mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-04 04:56:49 +00:00
feat(bot): add system guild icon & guild name (#554)
This commit is contained in:
parent
d12cd481f6
commit
3045c5e307
22 changed files with 337 additions and 28 deletions
|
|
@ -27,7 +27,7 @@ public class SystemControllerV2: PKControllerBase
|
|||
if (system == null)
|
||||
throw Errors.SystemNotFound;
|
||||
|
||||
return Ok(APIJsonExt.EmbedJson(system.Name ?? $"System with ID `{system.Hid}`", "System"));
|
||||
return Ok(APIJsonExt.EmbedJson(system.NameFor(ContextFor(system)) ?? $"System with ID `{system.Hid}`", "System"));
|
||||
}
|
||||
|
||||
[HttpPatch("{systemRef}")]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)}**");
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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}`");
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`");
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
7
PluralKit.Core/Database/Migrations/35.sql
Normal file
7
PluralKit.Core/Database/Migrations/35.sql
Normal 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;
|
||||
7
PluralKit.Core/Database/Migrations/36.sql
Normal file
7
PluralKit.Core/Database/Migrations/36.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
-- database version 36
|
||||
-- add system avatar privacy and system name privacy
|
||||
|
||||
alter table systems add column name_privacy integer not null default 1;
|
||||
alter table systems add column avatar_privacy integer not null default 1;
|
||||
|
||||
update info set schema_version = 36;
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ public class PKSystem
|
|||
public string WebhookUrl { get; }
|
||||
public string WebhookToken { get; }
|
||||
public Instant Created { get; }
|
||||
public PrivacyLevel NamePrivacy { get; }
|
||||
public PrivacyLevel AvatarPrivacy { get; }
|
||||
public PrivacyLevel DescriptionPrivacy { get; }
|
||||
public PrivacyLevel MemberListPrivacy { get; }
|
||||
public PrivacyLevel FrontPrivacy { get; }
|
||||
|
|
@ -59,18 +61,24 @@ public static class PKSystemExt
|
|||
public static string DescriptionFor(this PKSystem system, LookupContext ctx) =>
|
||||
system.DescriptionPrivacy.Get(ctx, system.Description);
|
||||
|
||||
public static string NameFor(this PKSystem system, LookupContext ctx) =>
|
||||
system.NamePrivacy.Get(ctx, system.Name);
|
||||
|
||||
public static string AvatarFor(this PKSystem system, LookupContext ctx) =>
|
||||
system.AvatarPrivacy.Get(ctx, system.AvatarUrl.TryGetCleanCdnUrl());
|
||||
|
||||
public static JObject ToJson(this PKSystem system, LookupContext ctx)
|
||||
{
|
||||
var o = new JObject();
|
||||
o.Add("id", system.Hid);
|
||||
o.Add("uuid", system.Uuid.ToString());
|
||||
|
||||
o.Add("name", system.Name);
|
||||
o.Add("name", system.NameFor(ctx));
|
||||
o.Add("description", system.DescriptionFor(ctx));
|
||||
o.Add("tag", system.Tag);
|
||||
o.Add("pronouns", system.PronounPrivacy.Get(ctx, system.Pronouns));
|
||||
|
||||
o.Add("avatar_url", system.AvatarUrl.TryGetCleanCdnUrl());
|
||||
o.Add("avatar_url", system.AvatarFor(ctx));
|
||||
o.Add("banner", system.DescriptionPrivacy.Get(ctx, system.BannerImage).TryGetCleanCdnUrl());
|
||||
o.Add("color", system.Color);
|
||||
o.Add("created", system.Created.FormatExport());
|
||||
|
|
@ -83,6 +91,8 @@ public static class PKSystemExt
|
|||
|
||||
var p = new JObject();
|
||||
|
||||
p.Add("name_privacy", system.NamePrivacy.ToJsonString());
|
||||
p.Add("avatar_privacy", system.AvatarPrivacy.ToJsonString());
|
||||
p.Add("description_privacy", system.DescriptionPrivacy.ToJsonString());
|
||||
p.Add("pronoun_privacy", system.PronounPrivacy.ToJsonString());
|
||||
p.Add("member_list_privacy", system.MemberListPrivacy.ToJsonString());
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
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
|
||||
|
|
@ -38,6 +47,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ public class SystemPatch: PatchObject
|
|||
public Partial<string?> Token { get; set; }
|
||||
public Partial<string?> WebhookUrl { get; set; }
|
||||
public Partial<string?> WebhookToken { get; set; }
|
||||
public Partial<PrivacyLevel> NamePrivacy { get; set; }
|
||||
public Partial<PrivacyLevel> AvatarPrivacy { get; set; }
|
||||
public Partial<PrivacyLevel> DescriptionPrivacy { get; set; }
|
||||
public Partial<PrivacyLevel> MemberListPrivacy { get; set; }
|
||||
public Partial<PrivacyLevel> GroupListPrivacy { get; set; }
|
||||
|
|
@ -37,6 +39,8 @@ public class SystemPatch: PatchObject
|
|||
.With("token", Token)
|
||||
.With("webhook_url", WebhookUrl)
|
||||
.With("webhook_token", WebhookToken)
|
||||
.With("name_privacy", NamePrivacy)
|
||||
.With("avatar_privacy", AvatarPrivacy)
|
||||
.With("description_privacy", DescriptionPrivacy)
|
||||
.With("member_list_privacy", MemberListPrivacy)
|
||||
.With("group_list_privacy", GroupListPrivacy)
|
||||
|
|
@ -93,6 +97,12 @@ public class SystemPatch: PatchObject
|
|||
{
|
||||
var privacy = o.Value<JObject>("privacy");
|
||||
|
||||
if (privacy.ContainsKey("name_privacy"))
|
||||
patch.NamePrivacy = patch.ParsePrivacy(privacy, "name_privacy");
|
||||
|
||||
if (privacy.ContainsKey("avatar_privacy"))
|
||||
patch.AvatarPrivacy = patch.ParsePrivacy(privacy, "avatar_privacy");
|
||||
|
||||
if (privacy.ContainsKey("description_privacy"))
|
||||
patch.DescriptionPrivacy = patch.ParsePrivacy(privacy, "description_privacy");
|
||||
|
||||
|
|
@ -137,7 +147,9 @@ public class SystemPatch: PatchObject
|
|||
o.Add("color", Color.Value);
|
||||
|
||||
if (
|
||||
DescriptionPrivacy.IsPresent
|
||||
NamePrivacy.IsPresent
|
||||
|| AvatarPrivacy.IsPresent
|
||||
|| DescriptionPrivacy.IsPresent
|
||||
|| PronounPrivacy.IsPresent
|
||||
|| MemberListPrivacy.IsPresent
|
||||
|| GroupListPrivacy.IsPresent
|
||||
|
|
@ -147,6 +159,12 @@ public class SystemPatch: PatchObject
|
|||
{
|
||||
var p = new JObject();
|
||||
|
||||
if (NamePrivacy.IsPresent)
|
||||
p.Add("name_privacy", NamePrivacy.Value.ToJsonString());
|
||||
|
||||
if (AvatarPrivacy.IsPresent)
|
||||
p.Add("avatar_privacy", AvatarPrivacy.Value.ToJsonString());
|
||||
|
||||
if (DescriptionPrivacy.IsPresent)
|
||||
p.Add("description_privacy", DescriptionPrivacy.Value.ToJsonString());
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ namespace PluralKit.Core;
|
|||
|
||||
public enum SystemPrivacySubject
|
||||
{
|
||||
Name,
|
||||
Avatar,
|
||||
Description,
|
||||
Pronouns,
|
||||
MemberList,
|
||||
|
|
@ -17,6 +19,8 @@ public static class SystemPrivacyUtils
|
|||
// what do you mean switch expressions can't be statements >.>
|
||||
_ = subject switch
|
||||
{
|
||||
SystemPrivacySubject.Name => system.NamePrivacy = level,
|
||||
SystemPrivacySubject.Avatar => system.AvatarPrivacy = level,
|
||||
SystemPrivacySubject.Description => system.DescriptionPrivacy = level,
|
||||
SystemPrivacySubject.Pronouns => system.PronounPrivacy = level,
|
||||
SystemPrivacySubject.Front => system.FrontPrivacy = level,
|
||||
|
|
@ -40,6 +44,15 @@ public static class SystemPrivacyUtils
|
|||
{
|
||||
switch (input.ToLowerInvariant())
|
||||
{
|
||||
case "name":
|
||||
subject = SystemPrivacySubject.Name;
|
||||
break;
|
||||
case "avatar":
|
||||
case "pfp":
|
||||
case "pic":
|
||||
case "icon":
|
||||
subject = SystemPrivacySubject.Avatar;
|
||||
break;
|
||||
case "description":
|
||||
case "desc":
|
||||
case "text":
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,10 @@ You can have a space after `pk;`, e.g. `pk;system` and `pk; system` will do the
|
|||
- `pk;system [system]` - Shows information about a system.
|
||||
- `pk;system new [name]` - Creates a new system registered to your account.
|
||||
- `pk;system [system] rename [new name]` - Changes the name of your system.
|
||||
- `pk;system [system] servername [servername]` - Changes the name of your system in the current server.
|
||||
- `pk;system [system] description [description]` - Changes the description of your system.
|
||||
- `pk;system [system] avatar [avatar url|@mention|upload]` - Changes the avatar of your system.
|
||||
- `pk;system [system] serveravatar [avatar url|@mention|upload]` - Changes the avatar of your system in the current server.
|
||||
- `pk;system [system] banner [image url|upload]` - Changes your system's banner image.
|
||||
- `pk;system [system] color [color]` - Changes your system's color.
|
||||
- `pk;system [system] privacy` - Displays your system's current privacy settings.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,18 @@ To view information about *a different* system, there are a number of ways to do
|
|||
pk;system 466378653216014359
|
||||
pk;system abcde
|
||||
|
||||
### System renaming
|
||||
If you want to change the name of your system, you can use the `pk;system rename` command, like so:
|
||||
|
||||
pk;system rename New System Name
|
||||
|
||||
### System server names
|
||||
If you'd like to set a name for your system, but only for a specific server, you can set the system's *server display name*. This shows up in replacement of the server name in the server you set it in. For example:
|
||||
|
||||
pk;system servername Name For This Server
|
||||
|
||||
To clear your system servername for a server, simply run `pk;system servername clear` in in the server in question. The servername cannot be run in DMs, it only applies to servers.
|
||||
|
||||
### System description
|
||||
If you'd like to add a small blurb to your system information card, you can add a *system description*. To do so, use the `pk;system description` command, as follows:
|
||||
|
||||
|
|
@ -51,13 +63,21 @@ There's a 1000 character length limit on your system description - which is quit
|
|||
If you'd like to remove your system description, just type `pk;system description` without any further parameters.
|
||||
|
||||
### System avatars
|
||||
If you'd like your system to have an associated "system avatar", displayed on your system information card, you can add a system avatar. To do so, use the `pk;system avatar` command. You can either supply it with an direct URL to an image, or attach an image directly. For example.
|
||||
If you'd like your system to have an associated "system avatar", displayed on your system information card, you can add a system avatar. Your system avatar will also show up as the avatar on members who do not have their own when proxying. To do so, use the `pk;system avatar` command. You can either supply it with an direct URL to an image, or attach an image directly. For example.
|
||||
|
||||
pk;system avatar http://placebeard.it/512.jpg
|
||||
pk;system avatar [with attached image]
|
||||
|
||||
To clear your avatar, simply type `pk;system avatar` with no attachment or link.
|
||||
|
||||
### System server avatars
|
||||
If you'd like your system to have an avatar (as above), but only for a specific server, you can set the *system server avatar*. This will override the global system avatar, but only in the server you set it in. For example:
|
||||
|
||||
pk;system serveravatar http://placebeard.it/512.jpg
|
||||
pk;system serveravatar [with attached image]
|
||||
|
||||
To clear your system serveravatar for a server, simply type `pk;system serveravatar clear` with no attachment or link in the server in question. The serveravatar command cannot be run in DMs, it only functions in servers.
|
||||
|
||||
### System tags
|
||||
Your system tag is a little snippet of text that'll be added to the end of all proxied messages.
|
||||
For example, if you want to proxy a member named `James`, and your system tag is `| The Boys`, the final name displayed
|
||||
|
|
@ -645,6 +665,8 @@ At the moment, there are a few aspects of system privacy that can be configured.
|
|||
- Group list
|
||||
- Current fronter
|
||||
- Front history
|
||||
- System name
|
||||
- System avatar
|
||||
|
||||
Each of these can be set to **public** or **private**. When set to **public**, anyone who queries your system (by account or system ID, or through the API), will see this information. When set to **private**, the information will only be shown when *you yourself* query the information. The cards will still be displayed in the channel the commands are run in, so it's still your responsibility not to pull up information in servers where you don't want it displayed.
|
||||
|
||||
|
|
@ -659,6 +681,8 @@ To update your system privacy settings, use the following commands:
|
|||
* `groups`
|
||||
* `fronter`
|
||||
* `fronthistory`
|
||||
* `name`
|
||||
* `avatar`
|
||||
* `all` (to change all subjects at once)
|
||||
|
||||
* `level` is either `public` or `private`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue