feat(bot): add system guild icon & guild name (#554)

This commit is contained in:
rladenson 2023-07-19 12:48:04 +12:00 committed by Iris System
parent d12cd481f6
commit 3045c5e307
22 changed files with 337 additions and 28 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");
@ -20,7 +22,7 @@ public partial class CommandTree
public static Command SystemFrontHistory = new Command("system fronthistory", "system [system] fronthistory", "Shows a system's front history");
public static Command SystemFrontPercent = new Command("system frontpercent", "system [system] frontpercent [timespan]", "Shows a system's front breakdown");
public static Command SystemId = new Command("system id", "system [system] id", "Prints your system's id.");
public static Command SystemPrivacy = new Command("system privacy", "system [system] privacy <description|members|fronter|fronthistory|all> <public|private>", "Changes your system's privacy settings");
public static Command SystemPrivacy = new Command("system privacy", "system [system] privacy <name|avatar|description|members|fronter|fronthistory|all> <public|private>", "Changes your system's privacy settings");
public static Command ConfigTimezone = new Command("config timezone", "config timezone [timezone]", "Changes your system's time zone");
public static Command ConfigPing = new Command("config ping", "config ping [on|off]", "Changes your system's ping preferences");
public static Command ConfigAutoproxyAccount = new Command("config autoproxy account", "config autoproxy account [on|off]", "Toggles autoproxy globally for the current account");
@ -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

@ -131,10 +131,23 @@ public class GroupMember
opts.GroupFilter = target.Id;
var title = new StringBuilder($"Members of {target.DisplayName ?? target.Name} (`{target.Hid}`) in ");
if (targetSystem.Name != null)
title.Append($"{targetSystem.Name} (`{targetSystem.Hid}`)");
if (ctx.Guild != null)
{
var guildSettings = await ctx.Repository.GetSystemGuild(ctx.Guild.Id, targetSystem.Id);
if (guildSettings.DisplayName != null)
title.Append($"{guildSettings.DisplayName} (`{targetSystem.Hid}`)");
else if (targetSystem.NameFor(ctx) != null)
title.Append($"{targetSystem.NameFor(ctx)} (`{targetSystem.Hid}`)");
else
title.Append($"`{targetSystem.Hid}`");
}
else
title.Append($"`{targetSystem.Hid}`");
{
if (targetSystem.NameFor(ctx) != null)
title.Append($"{targetSystem.NameFor(ctx)} (`{targetSystem.Hid}`)");
else
title.Append($"`{targetSystem.Hid}`");
}
if (opts.Search != null)
title.Append($" matching **{opts.Search.Truncate(100)}**");

View file

@ -28,6 +28,7 @@ public class SystemEdit
public async Task Name(Context ctx, PKSystem target)
{
ctx.CheckSystemPrivacy(target.Id, target.NamePrivacy);
var isOwnSystem = target.Id == ctx.System?.Id;
var noNameSetMessage = $"{(isOwnSystem ? "Your" : "This")} system does not have a name set.";
@ -76,6 +77,60 @@ public class SystemEdit
}
}
public async Task ServerName(Context ctx, PKSystem target)
{
ctx.CheckGuildContext();
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 +526,80 @@ 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.");
}
}
ctx.CheckGuildContext();
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);
@ -630,6 +759,8 @@ public class SystemEdit
{
var eb = new EmbedBuilder()
.Title("Current privacy settings for your system")
.Field(new Embed.Field("Name", target.NamePrivacy.Explanation()))
.Field(new Embed.Field("Avatar", target.AvatarPrivacy.Explanation()))
.Field(new Embed.Field("Description", target.DescriptionPrivacy.Explanation()))
.Field(new Embed.Field("Pronouns", target.PronounPrivacy.Explanation()))
.Field(new Embed.Field("Member list", target.MemberListPrivacy.Explanation()))
@ -637,7 +768,7 @@ public class SystemEdit
.Field(new Embed.Field("Current fronter(s)", target.FrontPrivacy.Explanation()))
.Field(new Embed.Field("Front/switch history", target.FrontHistoryPrivacy.Explanation()))
.Description(
"To edit privacy settings, use the command:\n`pk;system privacy <subject> <level>`\n\n- `subject` is one of `description`, `list`, `front`, `fronthistory`, `groups`, or `all` \n- `level` is either `public` or `private`.");
"To edit privacy settings, use the command:\n`pk;system privacy <subject> <level>`\n\n- `subject` is one of `name`, `avatar`, `description`, `list`, `front`, `fronthistory`, `groups`, or `all` \n- `level` is either `public` or `private`.");
return ctx.Reply(embed: eb.Build());
}
@ -654,6 +785,8 @@ public class SystemEdit
var subjectStr = subject switch
{
SystemPrivacySubject.Name => "name",
SystemPrivacySubject.Avatar => "avatar",
SystemPrivacySubject.Description => "description",
SystemPrivacySubject.Pronouns => "pronouns",
SystemPrivacySubject.Front => "front",

View file

@ -44,10 +44,17 @@ public class SystemFront
.Scan(new FrontHistoryEntry(null, null),
(lastEntry, newSwitch) => new FrontHistoryEntry(lastEntry.ThisSwitch?.Timestamp, newSwitch));
var embedTitle = system.Name != null
? $"Front history of {system.Name} (`{system.Hid}`)"
var embedTitle = system.NameFor(ctx) != null
? $"Front history of {system.NameFor(ctx)} (`{system.Hid}`)"
: $"Front history of `{system.Hid}`";
if (ctx.Guild != null)
{
var guildSettings = await ctx.Repository.GetSystemGuild(ctx.Guild.Id, system.Id);
if (guildSettings.DisplayName != null)
embedTitle = $"Front history of {guildSettings.DisplayName} (`{system.Hid}`)";
}
var showMemberId = ctx.MatchFlag("with-id", "wid");
await ctx.Paginate(
@ -127,10 +134,13 @@ public class SystemFront
if (rangeStart.Value.ToInstant() > now) throw Errors.FrontPercentTimeInFuture;
var title = new StringBuilder("Frontpercent of ");
var guildSettings = await ctx.Repository.GetSystemGuild(ctx.Guild.Id, system.Id);
if (group != null)
title.Append($"{group.NameFor(ctx)} (`{group.Hid}`)");
else if (system.Name != null)
title.Append($"{system.Name} (`{system.Hid}`)");
else if (guildSettings.DisplayName != null)
title.Append($"{guildSettings.DisplayName} (`{system.Hid}`)");
else if (system.NameFor(ctx) != null)
title.Append($"{system.NameFor(ctx)} (`{system.Hid}`)");
else
title.Append($"`{system.Hid}`");

View file

@ -21,18 +21,21 @@ public class SystemList
await ctx.RenderMemberList(
ctx.LookupContextFor(target.Id),
target.Id,
GetEmbedTitle(target, opts),
await GetEmbedTitle(target, opts, ctx),
target.Color,
opts
);
}
private string GetEmbedTitle(PKSystem target, ListOptions opts)
private async Task<string> GetEmbedTitle(PKSystem target, ListOptions opts, Context ctx)
{
var title = new StringBuilder("Members of ");
if (target.Name != null)
title.Append($"{target.Name} (`{target.Hid}`)");
var systemGuildSettings = ctx.Guild != null ? await ctx.Repository.GetSystemGuild(ctx.Guild.Id, target.Id) : null;
if (systemGuildSettings != null && systemGuildSettings.DisplayName != null)
title.Append($"{systemGuildSettings.DisplayName} (`{target.Hid}`)");
else if (target.NameFor(ctx) != null)
title.Append($"{target.NameFor(ctx)} (`{target.Hid}`)");
else
title.Append($"`{target.Hid}`");

View file

@ -68,13 +68,16 @@ public class EmbedService
}
var eb = new EmbedBuilder()
.Title(system.Name)
.Thumbnail(new Embed.EmbedThumbnail(system.AvatarUrl.TryGetCleanCdnUrl()))
.Title(system.NameFor(ctx))
.Footer(new Embed.EmbedFooter(
$"System ID: {system.Hid} | Created on {system.Created.FormatZoned(cctx.Zone)}"))
.Color(color)
.Url($"https://dash.pluralkit.me/profile/s/{system.Hid}");
var avatar = system.AvatarFor(ctx);
if (avatar != null)
eb.Thumbnail(new Embed.EmbedThumbnail(avatar));
if (system.DescriptionPrivacy.CanAccess(ctx))
eb.Image(new Embed.EmbedImage(system.BannerImage));
@ -106,6 +109,21 @@ public class EmbedService
if (!guildSettings.TagEnabled)
eb.Field(new Embed.Field($"Tag (in server '{cctx.Guild.Name}')",
"*(tag is disabled in this server)*"));
if (guildSettings.DisplayName != null)
eb.Title(guildSettings.DisplayName);
var guildAvatar = guildSettings.AvatarUrl.TryGetCleanCdnUrl();
if (guildAvatar != null)
{
eb.Thumbnail(new Embed.EmbedThumbnail(guildAvatar));
var sysDesc = "*(this system has a server-specific avatar set";
if (avatar != null)
sysDesc += $"; [click here]({system.AvatarUrl.TryGetCleanCdnUrl()}) to see their global avatar)*";
else
sysDesc += ")*";
eb.Description(sysDesc);
}
}
if (system.PronounPrivacy.CanAccess(ctx) && system.Pronouns != null)
@ -162,7 +180,13 @@ public class EmbedService
// string FormatTimestamp(Instant timestamp) => DateTimeFormats.ZonedDateTimeFormat.Format(timestamp.InZone(system.Zone));
var name = member.NameFor(ctx);
if (system.Name != null) name = $"{name} ({system.Name})";
var systemGuildSettings = guild != null ? await _repo.GetSystemGuild(guild.Id, system.Id) : null;
if (systemGuildSettings != null && systemGuildSettings.DisplayName != null)
name = $"{name} ({systemGuildSettings.DisplayName})";
else if (system.NameFor(ctx) != null)
name = $"{name} ({system.NameFor(ctx)})";
else
name = $"{name}";
uint color;
try
@ -256,8 +280,13 @@ public class EmbedService
var memberCount = await _repo.GetGroupMemberCount(target.Id, countctx == LookupContext.ByOwner ? null : PrivacyLevel.Public);
var nameField = target.NamePrivacy.Get(pctx, target.Name, target.DisplayName ?? target.Name);
if (system.Name != null)
var nameField = target.NameFor(ctx);
var systemGuildSettings = ctx.Guild != null ? await _repo.GetSystemGuild(ctx.Guild.Id, system.Id) : null;
if (systemGuildSettings != null && systemGuildSettings.DisplayName != null)
nameField = $"{nameField} ({systemGuildSettings.DisplayName})";
else if (system.NameFor(ctx) != null)
nameField = $"{nameField} ({system.NameFor(ctx)})";
else
nameField = $"{nameField} ({system.Name})";
uint color;
@ -395,7 +424,7 @@ public class EmbedService
.Field(new Embed.Field("System",
msg.System == null
? "*(deleted or unknown system)*"
: msg.System.Name != null ? $"{msg.System.Name} (`{msg.System.Hid}`)" : $"`{msg.System.Hid}`"
: msg.System.NameFor(ctx) != null ? $"{msg.System.NameFor(ctx)} (`{msg.System.Hid}`)" : $"`{msg.System.Hid}`"
, true))
.Field(new Embed.Field("Member",
msg.Member == null

View file

@ -12,6 +12,9 @@ public static class ModelUtils
public static string NameFor(this PKGroup group, Context ctx) =>
group.NameFor(ctx.LookupContextFor(group.System));
public static string NameFor(this PKSystem system, Context ctx) =>
system.NameFor(ctx.LookupContextFor(system.Id));
public static string AvatarFor(this PKMember member, Context ctx) =>
member.AvatarFor(ctx.LookupContextFor(member.System)).TryGetCleanCdnUrl();