feat: started adding system guild avatar and system guild name, they can be set and used but are not shown in system cards.

This commit is contained in:
rladenson 2023-05-25 15:41:41 -04:00
parent 83af1f04a7
commit ef5bcc8b49
10 changed files with 172 additions and 4 deletions

View file

@ -5,12 +5,14 @@ public partial class CommandTree
public static Command SystemInfo = new Command("system", "system [system]", "Looks up information about a system");
public static Command SystemNew = new Command("system new", "system new [name]", "Creates a new system");
public static Command SystemRename = new Command("system name", "system [system] rename [name]", "Renames your system");
public static Command SystemServerName = new Command("system servername", "system [system] servername [name]", "Changes your system displayname for this server");
public static Command SystemDesc = new Command("system description", "system [system] description [description]", "Changes your system's description");
public static Command SystemColor = new Command("system color", "system [system] color [color]", "Changes your system's color");
public static Command SystemTag = new Command("system tag", "system [system] tag [tag]", "Changes your system's tag");
public static Command SystemPronouns = new Command("system pronouns", "system [system] pronouns [pronouns]", "Changes your system's pronouns");
public static Command SystemServerTag = new Command("system servertag", "system [system] servertag [tag|enable|disable]", "Changes your system's tag in the current server");
public static Command SystemAvatar = new Command("system icon", "system [system] icon [url|@mention]", "Changes your system's icon");
public static Command SystemServerAvatar = new Command("system serveravatar", "system [system] serveravatar [tag]", "Changes your system's icon in the current server");
public static Command SystemBannerImage = new Command("system banner", "system [system] banner [url]", "Set the system's banner image");
public static Command SystemDelete = new Command("system delete", "system [system] delete", "Deletes your system");
public static Command SystemProxy = new Command("system proxy", "system proxy [server id] [on|off]", "Enables or disables message proxying in a specific server");
@ -107,7 +109,7 @@ public partial class CommandTree
public static Command[] SystemCommands =
{
SystemInfo, SystemNew, SystemRename, SystemTag, SystemDesc, SystemAvatar, SystemBannerImage, SystemColor,
SystemInfo, SystemNew, SystemRename, SystemServerName, SystemTag, SystemDesc, SystemAvatar, SystemServerAvatar, SystemBannerImage, SystemColor,
SystemDelete, SystemList, SystemFronter, SystemFrontHistory, SystemFrontPercent, SystemPrivacy, SystemProxy
};

View file

@ -220,6 +220,9 @@ public partial class CommandTree
{
if (ctx.Match("name", "rename", "changename", "rn"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemRename, m => m.Name(ctx, target));
else if (ctx.Match("servername", "sn", "sname", "snick", "snickname", "servernick", "servernickname",
"serverdisplayname", "guildname", "guildnick", "guildnickname", "serverdn"))
await ctx.Execute<SystemEdit>(SystemServerName, m => m.ServerName(ctx, target));
else if (ctx.Match("tag", "t"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemTag, m => m.Tag(ctx, target));
else if (ctx.Match("servertag", "st", "stag", "deer"))
@ -234,6 +237,9 @@ public partial class CommandTree
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemBannerImage, m => m.BannerImage(ctx, target));
else if (ctx.Match("avatar", "picture", "icon", "image", "pic", "pfp"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemAvatar, m => m.Avatar(ctx, target));
else if (ctx.Match("serveravatar", "sa", "servericon", "serverimage", "serverpfp", "serverpic", "savatar", "spic",
"guildavatar", "guildpic", "guildicon", "sicon", "spfp"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemServerAvatar, m => m.ServerAvatar(ctx, target));
else if (ctx.Match("list", "l", "members", "ls"))
await ctx.CheckSystem(target).Execute<SystemList>(SystemList, m => m.MemberList(ctx, target));
else if (ctx.Match("find", "search", "query", "fd", "s"))
@ -319,7 +325,7 @@ public partial class CommandTree
else
await ctx.Execute<GroupMember>(MemberGroups, m => m.ListMemberGroups(ctx, target));
else if (ctx.Match("serveravatar", "sa", "servericon", "serverimage", "serverpfp", "serverpic", "savatar", "spic",
"guildavatar", "guildpic", "guildicon", "sicon"))
"guildavatar", "guildpic", "guildicon", "sicon", "spfp"))
await ctx.Execute<MemberAvatar>(MemberServerAvatar, m => m.ServerAvatar(ctx, target));
else if (ctx.Match("displayname", "dn", "dname", "nick", "nickname", "dispname"))
await ctx.Execute<MemberEdit>(MemberDisplayName, m => m.DisplayName(ctx, target));

View file

@ -76,6 +76,58 @@ public class SystemEdit
}
}
public async Task ServerName(Context ctx, PKSystem target)
{
var isOwnSystem = target.Id == ctx.System?.Id;
var noNameSetMessage = $"{(isOwnSystem ? "Your" : "This")} system does not have a name specific to this server.";
if (isOwnSystem)
noNameSetMessage += " Type `pk;system servername <name>` to set one.";
var settings = await ctx.Repository.GetSystemGuild(ctx.Guild.Id, target.Id);
if (ctx.MatchRaw())
{
if (settings.DisplayName != null)
await ctx.Reply($"```\n{settings.DisplayName}\n```");
else
await ctx.Reply(noNameSetMessage);
return;
}
if (!ctx.HasNext(false))
{
if (settings.DisplayName != null)
await ctx.Reply(
$"{(isOwnSystem ? "Your" : "This")} system's name for this server is currently **{settings.DisplayName}**."
+ (isOwnSystem ? " Type `pk;system servername -clear` to clear it." : "")
+ $" Using {settings.DisplayName.Length}/{Limits.MaxSystemNameLength} characters.");
else
await ctx.Reply(noNameSetMessage);
return;
}
ctx.CheckSystem().CheckOwnSystem(target);
if (ctx.MatchClear() && await ctx.ConfirmClear("your system's name for this server"))
{
await ctx.Repository.UpdateSystemGuild(target.Id, ctx.Guild.Id, new SystemGuildPatch { DisplayName = null });
await ctx.Reply($"{Emojis.Success} System name for this server cleared.");
}
else
{
var newSystemGuildName = ctx.RemainderOrNull(false).NormalizeLineEndSpacing();
if (newSystemGuildName.Length > Limits.MaxSystemNameLength)
throw Errors.StringTooLongError("System name for this server", newSystemGuildName.Length, Limits.MaxSystemNameLength);
await ctx.Repository.UpdateSystemGuild(target.Id, ctx.Guild.Id, new SystemGuildPatch { DisplayName = newSystemGuildName });
await ctx.Reply($"{Emojis.Success} System name for this server changed (using {newSystemGuildName.Length}/{Limits.MaxSystemNameLength} characters).");
}
}
public async Task Description(Context ctx, PKSystem target)
{
ctx.CheckSystemPrivacy(target.Id, target.DescriptionPrivacy);
@ -471,6 +523,78 @@ public class SystemEdit
await ShowIcon();
}
public async Task ServerAvatar(Context ctx, PKSystem target)
{
async Task ClearIcon()
{
ctx.CheckOwnSystem(target);
await ctx.Repository.UpdateSystemGuild(target.Id, ctx.Guild.Id, new SystemGuildPatch { AvatarUrl = null });
await ctx.Reply($"{Emojis.Success} System server avatar cleared.");
}
async Task SetIcon(ParsedImage img)
{
ctx.CheckOwnSystem(target);
await AvatarUtils.VerifyAvatarOrThrow(_client, img.Url);
await ctx.Repository.UpdateSystemGuild(target.Id, ctx.Guild.Id, new SystemGuildPatch { AvatarUrl = img.Url });
var msg = img.Source switch
{
AvatarSource.User =>
$"{Emojis.Success} System icon for this server changed to {img.SourceUser?.Username}'s avatar! It will now be used for anything that uses system avatar in this server.\n{Emojis.Warn} If {img.SourceUser?.Username} changes their avatar, the system icon for this server will need to be re-set.",
AvatarSource.Url =>
$"{Emojis.Success} System icon for this server changed to the image at the given URL. It will now be used for anything that uses system avatar in this server.",
AvatarSource.Attachment =>
$"{Emojis.Success} System icon for this server changed to attached image. It will now be used for anything that uses system avatar in this server.\n{Emojis.Warn} If you delete the message containing the attachment, the system icon for this server will stop working.",
_ => throw new ArgumentOutOfRangeException()
};
// The attachment's already right there, no need to preview it.
var hasEmbed = img.Source != AvatarSource.Attachment;
await (hasEmbed
? ctx.Reply(msg, new EmbedBuilder().Image(new Embed.EmbedImage(img.Url)).Build())
: ctx.Reply(msg));
}
async Task ShowIcon()
{
var settings = await ctx.Repository.GetSystemGuild(ctx.Guild.Id, target.Id);
if ((settings.AvatarUrl?.Trim() ?? "").Length > 0)
{
var eb = new EmbedBuilder()
.Title("System server icon")
.Image(new Embed.EmbedImage(settings.AvatarUrl.TryGetCleanCdnUrl()));
if (target.Id == ctx.System?.Id)
eb.Description("To clear, use `pk;system servericon clear`.");
await ctx.Reply(embed: eb.Build());
}
else
{
throw new PKSyntaxError(
"This system does not have a icon specific to this server. Set one by attaching an image to this command, or by passing an image URL or @mention.");
}
}
if (target != null && target?.Id != ctx.System?.Id)
{
await ShowIcon();
return;
}
if (ctx.MatchClear() && await ctx.ConfirmClear("your system's icon for this server"))
await ClearIcon();
else if (await ctx.MatchImage() is { } img)
await SetIcon(img);
else
await ShowIcon();
}
public async Task BannerImage(Context ctx, PKSystem target)
{
ctx.CheckSystemPrivacy(target.Id, target.DescriptionPrivacy);

View file

@ -26,6 +26,7 @@ public class MessageContext
public string? SystemGuildTag { get; }
public bool TagEnabled { get; }
public string? SystemAvatar { get; }
public string? SystemGuildAvatar { get; }
public bool AllowAutoproxy { get; }
public int? LatchTimeout { get; }
public bool CaseSensitiveProxyTags { get; }

View file

@ -42,5 +42,5 @@ public class ProxyMember
return memberName;
}
public string? ProxyAvatar(MessageContext ctx) => ServerAvatar ?? WebhookAvatar ?? Avatar ?? ctx.SystemAvatar;
public string? ProxyAvatar(MessageContext ctx) => ServerAvatar ?? WebhookAvatar ?? Avatar ?? ctx.SystemGuildAvatar ?? ctx.SystemAvatar;
}

View file

@ -13,6 +13,7 @@ create function message_context(account_id bigint, guild_id bigint, channel_id b
system_guild_tag text,
tag_enabled bool,
system_avatar text,
system_guild_avatar text,
allow_autoproxy bool,
latch_timeout integer,
case_sensitive_proxy_tags bool,
@ -22,6 +23,7 @@ as $$
-- CTEs to query "static" (accessible only through args) data
with
system as (select systems.*, system_config.latch_timeout, system_guild.tag as guild_tag, system_guild.tag_enabled as tag_enabled,
system_guild.avatar_url as guild_avatar,
allow_autoproxy as account_autoproxy, system_config.case_sensitive_proxy_tags, system_config.proxy_error_message_enabled from accounts
left join systems on systems.id = accounts.system
left join system_config on system_config.system = accounts.system
@ -44,6 +46,7 @@ as $$
system.guild_tag as system_guild_tag,
coalesce(system.tag_enabled, true) as tag_enabled,
system.avatar_url as system_avatar,
system.guild_avatar as system_guild_avatar,
system.account_autoproxy as allow_autoproxy,
system.latch_timeout as latch_timeout,
system.case_sensitive_proxy_tags as case_sensitive_proxy_tags,

View file

@ -0,0 +1,7 @@
-- database version 35
-- add guild avatar and guild name to system guild settings
alter table system_guild add column avatar_url text;
alter table system_guild add column display_name text;
update info set schema_version = 35;

View file

@ -9,7 +9,7 @@ namespace PluralKit.Core;
internal class DatabaseMigrator
{
private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files
private const int TargetSchemaVersion = 34;
private const int TargetSchemaVersion = 36;
private readonly ILogger _logger;
public DatabaseMigrator(ILogger logger)

View file

@ -11,17 +11,26 @@ public class SystemGuildPatch: PatchObject
public Partial<bool> ProxyEnabled { get; set; }
public Partial<string?> Tag { get; set; }
public Partial<bool?> TagEnabled { get; set; }
public Partial<string?> AvatarUrl { get; set; } //TODO API
public Partial<string?> DisplayName { get; set; }
public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper
.With("proxy_enabled", ProxyEnabled)
.With("tag", Tag)
.With("tag_enabled", TagEnabled)
.With("avatar_url", AvatarUrl)
.With("display_name", DisplayName)
);
public new void AssertIsValid()
{
if (Tag.Value != null)
AssertValid(Tag.Value, "tag", Limits.MaxSystemTagLength);
if (AvatarUrl.Value != null)
AssertValid(AvatarUrl.Value, "avatar_url", Limits.MaxUriLength,
s => MiscUtils.TryMatchUri(s, out var avatarUri));
if (DisplayName.Value != null)
AssertValid(DisplayName.Value, "display_name", Limits.MaxMemberNameLength);
}
#nullable disable
@ -37,6 +46,12 @@ public class SystemGuildPatch: PatchObject
if (o.ContainsKey("tag_enabled") && o["tag_enabled"].Type != JTokenType.Null)
patch.TagEnabled = o.Value<bool>("tag_enabled");
if (o.ContainsKey("avatar_url"))
patch.AvatarUrl = o.Value<string>("avatar_url").NullIfEmpty();
if (o.ContainsKey("display_name"))
patch.DisplayName = o.Value<string>("display_name").NullIfEmpty();
return patch;
}
@ -56,6 +71,12 @@ public class SystemGuildPatch: PatchObject
if (TagEnabled.IsPresent)
o.Add("tag_enabled", TagEnabled.Value);
if (AvatarUrl.IsPresent)
o.Add("avatar_url", AvatarUrl.Value);
if (DisplayName.IsPresent)
o.Add("display_name", DisplayName.Value);
return o;
}
}

View file

@ -9,6 +9,8 @@ public class SystemGuildSettings
public bool ProxyEnabled { get; } = true;
public string? Tag { get; }
public bool TagEnabled { get; }
public string? AvatarUrl { get; }
public string? DisplayName { get; }
}
public static class SystemGuildExt
@ -20,6 +22,8 @@ public static class SystemGuildExt
o.Add("proxying_enabled", settings.ProxyEnabled);
o.Add("tag", settings.Tag);
o.Add("tag_enabled", settings.TagEnabled);
o.Add("avatar_url", settings.AvatarUrl);
o.Add("display_name", settings.DisplayName);
return o;
}