feat: system pronouns (#429)

This commit is contained in:
Jake Fulmine 2022-03-23 19:20:16 +01:00 committed by GitHub
parent 062835e0c5
commit 7efe6f1f97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 99 additions and 2 deletions

View File

@ -8,6 +8,7 @@ public partial class CommandTree
public static Command SystemDesc = new Command("system description", "system [system] description [description]", "Changes your system's description"); 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 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 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 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 SystemAvatar = new Command("system icon", "system [system] icon [url|@mention]", "Changes your system's icon");
public static Command SystemBannerImage = new Command("system banner", "system [system] banner [url]", "Set the system's banner image"); public static Command SystemBannerImage = new Command("system banner", "system [system] banner [url]", "Set the system's banner image");

View File

@ -213,6 +213,8 @@ public partial class CommandTree
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemServerTag, m => m.ServerTag(ctx, target)); await ctx.CheckSystem(target).Execute<SystemEdit>(SystemServerTag, m => m.ServerTag(ctx, target));
else if (ctx.Match("description", "desc", "bio")) else if (ctx.Match("description", "desc", "bio"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemDesc, m => m.Description(ctx, target)); await ctx.CheckSystem(target).Execute<SystemEdit>(SystemDesc, m => m.Description(ctx, target));
else if (ctx.Match("pronouns", "prns"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemPronouns, m => m.Pronouns(ctx, target));
else if (ctx.Match("color", "colour")) else if (ctx.Match("color", "colour"))
await ctx.CheckSystem(target).Execute<SystemEdit>(SystemColor, m => m.Color(ctx, target)); await ctx.CheckSystem(target).Execute<SystemEdit>(SystemColor, m => m.Color(ctx, target));
else if (ctx.Match("banner", "splash", "cover")) else if (ctx.Match("banner", "splash", "cover"))

View File

@ -339,6 +339,58 @@ public class SystemEdit
await Set(); await Set();
} }
public async Task Pronouns(Context ctx, PKSystem target)
{
ctx.CheckSystemPrivacy(target.Id, target.PronounPrivacy);
var isOwnSystem = ctx.System.Id == target.Id;
var noPronounsSetMessage = "This system does not have pronouns set.";
if (isOwnSystem)
noPronounsSetMessage += " To set some, type `pk;system pronouns <pronouns>`";
if (ctx.MatchRaw())
{
if (target.Pronouns == null)
await ctx.Reply(noPronounsSetMessage);
else
await ctx.Reply($"```\n{target.Pronouns}\n```");
return;
}
if (!ctx.HasNext(false))
{
if (target.Pronouns == null)
await ctx.Reply(noPronounsSetMessage);
else
await ctx.Reply($"{(isOwnSystem ? "Your" : "This system's")} current pronouns are **{target.Pronouns}**.\nTo print the pronouns with formatting, type `pk;system pronouns -raw`."
+ (isOwnSystem ? " To clear them, type `pk;system pronouns -clear`."
: "" ));
return;
}
ctx.CheckSystem().CheckOwnSystem(target);
if (await ctx.MatchClear("your system's pronouns"))
{
await ctx.Repository.UpdateSystem(target.Id, new SystemPatch { Pronouns = null });
await ctx.Reply($"{Emojis.Success} System pronouns cleared.");
}
else
{
var newPronouns = ctx.RemainderOrNull(false).NormalizeLineEndSpacing();
if (newPronouns != null)
if (newPronouns.Length > Limits.MaxPronounsLength)
throw Errors.StringTooLongError("Pronouns", newPronouns.Length, Limits.MaxPronounsLength);
await ctx.Repository.UpdateSystem(target.Id, new SystemPatch { Pronouns = newPronouns });
await ctx.Reply(
$"{Emojis.Success} System pronouns changed.");
}
}
public async Task Avatar(Context ctx, PKSystem target) public async Task Avatar(Context ctx, PKSystem target)
{ {
async Task ClearIcon() async Task ClearIcon()
@ -525,6 +577,7 @@ public class SystemEdit
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.Title("Current privacy settings for your system") .Title("Current privacy settings for your system")
.Field(new Embed.Field("Description", target.DescriptionPrivacy.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())) .Field(new Embed.Field("Member list", target.MemberListPrivacy.Explanation()))
.Field(new Embed.Field("Group list", target.GroupListPrivacy.Explanation())) .Field(new Embed.Field("Group list", target.GroupListPrivacy.Explanation()))
.Field(new Embed.Field("Current fronter(s)", target.FrontPrivacy.Explanation())) .Field(new Embed.Field("Current fronter(s)", target.FrontPrivacy.Explanation()))
@ -548,6 +601,7 @@ public class SystemEdit
var subjectStr = subject switch var subjectStr = subject switch
{ {
SystemPrivacySubject.Description => "description", SystemPrivacySubject.Description => "description",
SystemPrivacySubject.Pronouns => "pronouns",
SystemPrivacySubject.Front => "front", SystemPrivacySubject.Front => "front",
SystemPrivacySubject.FrontHistory => "front history", SystemPrivacySubject.FrontHistory => "front history",
SystemPrivacySubject.MemberList => "member list", SystemPrivacySubject.MemberList => "member list",

View File

@ -103,6 +103,9 @@ public class EmbedService
"*(tag is disabled in this server)*")); "*(tag is disabled in this server)*"));
} }
if (system.PronounPrivacy.CanAccess(ctx) && system.Pronouns != null)
eb.Field(new Embed.Field("Pronouns", system.Pronouns, true));
if (!system.Color.EmptyOrNull()) eb.Field(new Embed.Field("Color", $"#{system.Color}", true)); if (!system.Color.EmptyOrNull()) eb.Field(new Embed.Field("Color", $"#{system.Color}", true));
eb.Field(new Embed.Field("Linked accounts", string.Join("\n", users).Truncate(1000), true)); eb.Field(new Embed.Field("Linked accounts", string.Join("\n", users).Truncate(1000), true));

View File

@ -0,0 +1,7 @@
-- schema version 28
-- system pronouns
alter table systems add column pronouns text;
alter table systems add column pronoun_privacy integer check (pronoun_privacy in (1, 2)) not null default 1;
update info set schema_version = 28;

View File

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

View File

@ -39,6 +39,7 @@ public class PKSystem
public string Name { get; } public string Name { get; }
public string Description { get; } public string Description { get; }
public string Tag { get; } public string Tag { get; }
public string Pronouns { get; }
public string AvatarUrl { get; } public string AvatarUrl { get; }
public string BannerImage { get; } public string BannerImage { get; }
public string Color { get; } public string Color { get; }
@ -51,6 +52,7 @@ public class PKSystem
public PrivacyLevel FrontPrivacy { get; } public PrivacyLevel FrontPrivacy { get; }
public PrivacyLevel FrontHistoryPrivacy { get; } public PrivacyLevel FrontHistoryPrivacy { get; }
public PrivacyLevel GroupListPrivacy { get; } public PrivacyLevel GroupListPrivacy { get; }
public PrivacyLevel PronounPrivacy { get; }
} }
public static class PKSystemExt public static class PKSystemExt
@ -68,6 +70,9 @@ public static class PKSystemExt
o.Add("name", system.Name); o.Add("name", system.Name);
o.Add("description", system.DescriptionFor(ctx)); o.Add("description", system.DescriptionFor(ctx));
o.Add("tag", system.Tag); o.Add("tag", system.Tag);
if (v == APIVersion.V2)
o.Add("pronouns", system.PronounPrivacy.Get(ctx, system.Pronouns));
o.Add("avatar_url", system.AvatarUrl.TryGetCleanCdnUrl()); o.Add("avatar_url", system.AvatarUrl.TryGetCleanCdnUrl());
o.Add("banner", system.DescriptionPrivacy.Get(ctx, system.BannerImage).TryGetCleanCdnUrl()); o.Add("banner", system.DescriptionPrivacy.Get(ctx, system.BannerImage).TryGetCleanCdnUrl());
o.Add("color", system.Color); o.Add("color", system.Color);
@ -103,6 +108,7 @@ public static class PKSystemExt
var p = new JObject(); var p = new JObject();
p.Add("description_privacy", system.DescriptionPrivacy.ToJsonString()); p.Add("description_privacy", system.DescriptionPrivacy.ToJsonString());
p.Add("pronoun_privacy", system.PronounPrivacy.ToJsonString());
p.Add("member_list_privacy", system.MemberListPrivacy.ToJsonString()); p.Add("member_list_privacy", system.MemberListPrivacy.ToJsonString());
p.Add("group_list_privacy", system.GroupListPrivacy.ToJsonString()); p.Add("group_list_privacy", system.GroupListPrivacy.ToJsonString());
p.Add("front_privacy", system.FrontPrivacy.ToJsonString()); p.Add("front_privacy", system.FrontPrivacy.ToJsonString());

View File

@ -13,6 +13,7 @@ public class SystemPatch: PatchObject
public Partial<string?> Hid { get; set; } public Partial<string?> Hid { get; set; }
public Partial<string?> Description { get; set; } public Partial<string?> Description { get; set; }
public Partial<string?> Tag { get; set; } public Partial<string?> Tag { get; set; }
public Partial<string?> Pronouns { get; set; }
public Partial<string?> AvatarUrl { get; set; } public Partial<string?> AvatarUrl { get; set; }
public Partial<string?> BannerImage { get; set; } public Partial<string?> BannerImage { get; set; }
public Partial<string?> Color { get; set; } public Partial<string?> Color { get; set; }
@ -24,12 +25,14 @@ public class SystemPatch: PatchObject
public Partial<PrivacyLevel> GroupListPrivacy { get; set; } public Partial<PrivacyLevel> GroupListPrivacy { get; set; }
public Partial<PrivacyLevel> FrontPrivacy { get; set; } public Partial<PrivacyLevel> FrontPrivacy { get; set; }
public Partial<PrivacyLevel> FrontHistoryPrivacy { get; set; } public Partial<PrivacyLevel> FrontHistoryPrivacy { get; set; }
public Partial<PrivacyLevel> PronounPrivacy { get; set; }
public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper
.With("name", Name) .With("name", Name)
.With("hid", Hid) .With("hid", Hid)
.With("description", Description) .With("description", Description)
.With("tag", Tag) .With("tag", Tag)
.With("pronouns", Pronouns)
.With("avatar_url", AvatarUrl) .With("avatar_url", AvatarUrl)
.With("banner_image", BannerImage) .With("banner_image", BannerImage)
.With("color", Color) .With("color", Color)
@ -41,6 +44,7 @@ public class SystemPatch: PatchObject
.With("group_list_privacy", GroupListPrivacy) .With("group_list_privacy", GroupListPrivacy)
.With("front_privacy", FrontPrivacy) .With("front_privacy", FrontPrivacy)
.With("front_history_privacy", FrontHistoryPrivacy) .With("front_history_privacy", FrontHistoryPrivacy)
.With("pronoun_privacy", PronounPrivacy)
); );
public new void AssertIsValid() public new void AssertIsValid()
@ -51,6 +55,8 @@ public class SystemPatch: PatchObject
AssertValid(Description.Value, "description", Limits.MaxDescriptionLength); AssertValid(Description.Value, "description", Limits.MaxDescriptionLength);
if (Tag.Value != null) if (Tag.Value != null)
AssertValid(Tag.Value, "tag", Limits.MaxSystemTagLength); AssertValid(Tag.Value, "tag", Limits.MaxSystemTagLength);
if (Pronouns.Value != null)
AssertValid(Pronouns.Value, "pronouns", Limits.MaxPronounsLength);
if (AvatarUrl.Value != null) if (AvatarUrl.Value != null)
AssertValid(AvatarUrl.Value, "avatar_url", Limits.MaxUriLength, AssertValid(AvatarUrl.Value, "avatar_url", Limits.MaxUriLength,
s => MiscUtils.TryMatchUri(s, out var avatarUri)); s => MiscUtils.TryMatchUri(s, out var avatarUri));
@ -69,6 +75,7 @@ public class SystemPatch: PatchObject
if (o.ContainsKey("name")) patch.Name = o.Value<string>("name").NullIfEmpty(); if (o.ContainsKey("name")) patch.Name = o.Value<string>("name").NullIfEmpty();
if (o.ContainsKey("description")) patch.Description = o.Value<string>("description").NullIfEmpty(); if (o.ContainsKey("description")) patch.Description = o.Value<string>("description").NullIfEmpty();
if (o.ContainsKey("tag")) patch.Tag = o.Value<string>("tag").NullIfEmpty(); if (o.ContainsKey("tag")) patch.Tag = o.Value<string>("tag").NullIfEmpty();
if (o.ContainsKey("pronouns")) patch.Pronouns = o.Value<string>("pronouns").NullIfEmpty();
if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value<string>("avatar_url").NullIfEmpty(); if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value<string>("avatar_url").NullIfEmpty();
if (o.ContainsKey("banner")) patch.BannerImage = o.Value<string>("banner").NullIfEmpty(); if (o.ContainsKey("banner")) patch.BannerImage = o.Value<string>("banner").NullIfEmpty();
if (o.ContainsKey("color")) patch.Color = o.Value<string>("color").NullIfEmpty(); if (o.ContainsKey("color")) patch.Color = o.Value<string>("color").NullIfEmpty();
@ -96,6 +103,9 @@ public class SystemPatch: PatchObject
if (privacy.ContainsKey("description_privacy")) if (privacy.ContainsKey("description_privacy"))
patch.DescriptionPrivacy = patch.ParsePrivacy(privacy, "description_privacy"); patch.DescriptionPrivacy = patch.ParsePrivacy(privacy, "description_privacy");
if (privacy.ContainsKey("pronoun_privacy"))
patch.PronounPrivacy = patch.ParsePrivacy(privacy, "pronoun_privacy");
if (privacy.ContainsKey("member_list_privacy")) if (privacy.ContainsKey("member_list_privacy"))
patch.MemberListPrivacy = patch.ParsePrivacy(privacy, "member_list_privacy"); patch.MemberListPrivacy = patch.ParsePrivacy(privacy, "member_list_privacy");
@ -128,6 +138,8 @@ public class SystemPatch: PatchObject
o.Add("description", Description.Value); o.Add("description", Description.Value);
if (Tag.IsPresent) if (Tag.IsPresent)
o.Add("tag", Tag.Value); o.Add("tag", Tag.Value);
if (Pronouns.IsPresent)
o.Add("pronouns", Pronouns.Value);
if (AvatarUrl.IsPresent) if (AvatarUrl.IsPresent)
o.Add("avatar_url", AvatarUrl.Value); o.Add("avatar_url", AvatarUrl.Value);
if (BannerImage.IsPresent) if (BannerImage.IsPresent)
@ -137,6 +149,7 @@ public class SystemPatch: PatchObject
if ( if (
DescriptionPrivacy.IsPresent DescriptionPrivacy.IsPresent
|| PronounPrivacy.IsPresent
|| MemberListPrivacy.IsPresent || MemberListPrivacy.IsPresent
|| GroupListPrivacy.IsPresent || GroupListPrivacy.IsPresent
|| FrontPrivacy.IsPresent || FrontPrivacy.IsPresent
@ -148,6 +161,9 @@ public class SystemPatch: PatchObject
if (DescriptionPrivacy.IsPresent) if (DescriptionPrivacy.IsPresent)
p.Add("description_privacy", DescriptionPrivacy.Value.ToJsonString()); p.Add("description_privacy", DescriptionPrivacy.Value.ToJsonString());
if (PronounPrivacy.IsPresent)
p.Add("pronoun_privacy", PronounPrivacy.Value.ToJsonString());
if (MemberListPrivacy.IsPresent) if (MemberListPrivacy.IsPresent)
p.Add("member_list_privacy", MemberListPrivacy.Value.ToJsonString()); p.Add("member_list_privacy", MemberListPrivacy.Value.ToJsonString());

View File

@ -3,6 +3,7 @@ namespace PluralKit.Core;
public enum SystemPrivacySubject public enum SystemPrivacySubject
{ {
Description, Description,
Pronouns,
MemberList, MemberList,
GroupList, GroupList,
Front, Front,
@ -17,6 +18,7 @@ public static class SystemPrivacyUtils
_ = subject switch _ = subject switch
{ {
SystemPrivacySubject.Description => system.DescriptionPrivacy = level, SystemPrivacySubject.Description => system.DescriptionPrivacy = level,
SystemPrivacySubject.Pronouns => system.PronounPrivacy = level,
SystemPrivacySubject.Front => system.FrontPrivacy = level, SystemPrivacySubject.Front => system.FrontPrivacy = level,
SystemPrivacySubject.FrontHistory => system.FrontHistoryPrivacy = level, SystemPrivacySubject.FrontHistory => system.FrontHistoryPrivacy = level,
SystemPrivacySubject.MemberList => system.MemberListPrivacy = level, SystemPrivacySubject.MemberList => system.MemberListPrivacy = level,
@ -44,6 +46,10 @@ public static class SystemPrivacyUtils
case "info": case "info":
subject = SystemPrivacySubject.Description; subject = SystemPrivacySubject.Description;
break; break;
case "pronouns":
case "prns":
subject = SystemPrivacySubject.Pronouns;
break;
case "members": case "members":
case "memberlist": case "memberlist":
case "list": case "list":

View File

@ -24,13 +24,14 @@ Every PluralKit entity has two IDs: a short (5-character) ID and a longer UUID.
|name|string|100-character limit| |name|string|100-character limit|
|description|?string|1000-character limit| |description|?string|1000-character limit|
|tag|string|| |tag|string||
|pronouns|?string|100-character limit|
|avatar_url|?string|256-character limit, must be a publicly-accessible URL| |avatar_url|?string|256-character limit, must be a publicly-accessible URL|
|banner|?string|256-character limit, must be a publicly-accessible URL| |banner|?string|256-character limit, must be a publicly-accessible URL|
|color|string|6-character hex code, no `#` at the beginning| |color|string|6-character hex code, no `#` at the beginning|
|created|datetime|| |created|datetime||
|privacy|?system privacy object|| |privacy|?system privacy object||
* System privacy keys: `description_privacy`, `member_list_privacy`, `group_list_privacy`, `front_privacy`, `front_history_privacy` * System privacy keys: `description_privacy`, `pronoun_privacy`, `member_list_privacy`, `group_list_privacy`, `front_privacy`, `front_history_privacy`
### Member model ### Member model

View File

@ -43,6 +43,7 @@ Some arguments indicate the use of specific Discord features. These include:
- `pk;system [system] privacy <subject> <public|private>` - Changes your systems privacy settings. - `pk;system [system] privacy <subject> <public|private>` - Changes your systems privacy settings.
- `pk;system [system] tag [tag]` - Changes the system tag of your system. - `pk;system [system] tag [tag]` - Changes the system tag of your system.
- `pk;system [system] servertag [tag|-enable|-disable]` - Changes your system's tag in the current server, or disables it for the current server. - `pk;system [system] servertag [tag|-enable|-disable]` - Changes your system's tag in the current server, or disables it for the current server.
- `pk;system [system] pronouns [pronouns]` - Changes the pronouns of your system.
- `pk;system proxy [server id] [on|off]` - Toggles message proxying for a specific server. - `pk;system proxy [server id] [on|off]` - Toggles message proxying for a specific server.
- `pk;system [system] delete` - Deletes your system. - `pk;system [system] delete` - Deletes your system.
- `pk;system [system] fronter` - Shows the current fronter of a system. - `pk;system [system] fronter` - Shows the current fronter of a system.