From 9f523b3c5fdc065bc5b2e8ad6b0faf086e02e509 Mon Sep 17 00:00:00 2001 From: Ske Date: Wed, 8 Jul 2020 00:46:58 +0200 Subject: [PATCH] Refactor system/member privacy commands --- PluralKit.Bot/Commands/MemberEdit.cs | 124 +++++++----------- .../Commands/Privacy/ContextPrivacyExt.cs | 39 ++++++ PluralKit.Bot/Commands/SystemEdit.cs | 113 ++++++---------- .../Models/Privacy/LookupContext.cs | 9 ++ .../Privacy/MemberPrivacySubject.cs} | 56 ++++---- .../{Privacy.cs => Privacy/PrivacyExt.cs} | 25 ++-- PluralKit.Core/Models/Privacy/PrivacyLevel.cs | 8 ++ .../Models/Privacy/SystemPrivacySubject.cs | 71 ++++++++++ 8 files changed, 249 insertions(+), 196 deletions(-) create mode 100644 PluralKit.Bot/Commands/Privacy/ContextPrivacyExt.cs create mode 100644 PluralKit.Core/Models/Privacy/LookupContext.cs rename PluralKit.Core/{Utils/PrivacyUtils.cs => Models/Privacy/MemberPrivacySubject.cs} (59%) rename PluralKit.Core/Models/{Privacy.cs => Privacy/PrivacyExt.cs} (67%) create mode 100644 PluralKit.Core/Models/Privacy/PrivacyLevel.cs create mode 100644 PluralKit.Core/Models/Privacy/SystemPrivacySubject.cs diff --git a/PluralKit.Bot/Commands/MemberEdit.cs b/PluralKit.Bot/Commands/MemberEdit.cs index dbfa4bc1..9e67ad2a 100644 --- a/PluralKit.Bot/Commands/MemberEdit.cs +++ b/PluralKit.Bot/Commands/MemberEdit.cs @@ -372,29 +372,6 @@ namespace PluralKit.Bot await ctx.Reply($"{Emojis.Success} Member proxy tags will now not be included in the resulting message when proxying."); } - private DiscordEmbed CreatePrivacyEmbed(Context ctx, PKMember member) - { - string PrivacyLevelString(PrivacyLevel level) => level switch - { - PrivacyLevel.Private => "**Private** (visible only when queried by you)", - PrivacyLevel.Public => "**Public** (visible to everyone)", - _ => throw new ArgumentOutOfRangeException(nameof(level), level, null) - }; - - var eb = new DiscordEmbedBuilder() - .WithTitle($"Current privacy settings for {member.NameFor(ctx)}") - .AddField("Name (replaces name with display name if member has one)",PrivacyLevelString(member.NamePrivacy)) - .AddField("Description", PrivacyLevelString(member.DescriptionPrivacy)) - .AddField("Avatar", PrivacyLevelString(member.AvatarPrivacy)) - .AddField("Birthday", PrivacyLevelString(member.BirthdayPrivacy)) - .AddField("Pronouns", PrivacyLevelString(member.PronounPrivacy)) - // .AddField("Color", PrivacyLevelString(target.ColorPrivacy)) - .AddField("Meta (message count, last front, last message)", PrivacyLevelString(member.MetadataPrivacy)) - .AddField("Visibility", PrivacyLevelString(member.MemberVisibility)) - .WithDescription("To edit privacy settings, use the command:\n`pk;member privacy `\n\n- `subject` is one of `name`, `description`, `avatar`, `birthday`, `pronouns`, `created`, `messages`, `visibility`, or `all`\n- `level` is either `public` or `private`."); - return eb.Build(); - } - public async Task Privacy(Context ctx, PKMember target, PrivacyLevel? newValueFromCommand) { if (ctx.System == null) throw Errors.NoSystemError; @@ -403,7 +380,17 @@ namespace PluralKit.Bot // Display privacy settings if (!ctx.HasNext() && newValueFromCommand == null) { - await ctx.Reply(embed: CreatePrivacyEmbed(ctx, target)); + await ctx.Reply(embed: new DiscordEmbedBuilder() + .WithTitle($"Current privacy settings for {target.NameFor(ctx)}") + .AddField("Name (replaces name with display name if member has one)",target.NamePrivacy.Explanation()) + .AddField("Description", target.DescriptionPrivacy.Explanation()) + .AddField("Avatar", target.AvatarPrivacy.Explanation()) + .AddField("Birthday", target.BirthdayPrivacy.Explanation()) + .AddField("Pronouns", target.PronounPrivacy.Explanation()) + .AddField("Meta (message count, last front, last message)",target.MetadataPrivacy.Explanation()) + .AddField("Visibility", target.MemberVisibility.Explanation()) + .WithDescription("To edit privacy settings, use the command:\n`pk;member privacy `\n\n- `subject` is one of `name`, `description`, `avatar`, `birthday`, `pronouns`, `created`, `messages`, `visibility`, or `all`\n- `level` is either `public` or `private`.") + .Build()); return; } @@ -412,37 +399,33 @@ namespace PluralKit.Bot if (ctx.Guild != null) guildSettings = await _db.Execute(c => c.QueryOrInsertMemberGuildConfig(ctx.Guild.Id, target.Id)); - // Set Privacy Settings - PrivacyLevel PopPrivacyLevel(string subjectName) + async Task SetAll(PrivacyLevel level) { - if (ctx.Match("public", "show", "shown", "visible")) - return PrivacyLevel.Public; - - if (ctx.Match("private", "hide", "hidden")) - return PrivacyLevel.Private; - - if (!ctx.HasNext()) - throw new PKSyntaxError($"You must pass a privacy level for `{subjectName}` (`public` or `private`)"); - throw new PKSyntaxError($"Invalid privacy level `{ctx.PopArgument()}` (must be `public` or `private`)."); + await _db.Execute(c => c.UpdateMember(target.Id, new MemberPatch().WithAllPrivacy(level))); + + if (level == PrivacyLevel.Private) + await ctx.Reply($"{Emojis.Success} All {target.NameFor(ctx)}'s privacy settings have been set to **{level.LevelName()}**. Other accounts will now see nothing on the member card."); + else + await ctx.Reply($"{Emojis.Success} All {target.NameFor(ctx)}'s privacy settings have been set to **{level.LevelName()}**. Other accounts will now see everything on the member card."); } - - // See if we have a subject given - PrivacyLevel newLevel; - if (PrivacyUtils.TryParseMemberPrivacy(ctx.PeekArgument(), out var subject)) - { - // We peeked before, pop it now - ctx.PopArgument(); - - // Read the privacy level from args - newLevel = PopPrivacyLevel(subject.Name()); - - // Set the level on the given subject - var patch = new MemberPatch(); - patch.SetPrivacy(subject, newLevel); - await _db.Execute(conn => conn.UpdateMember(target.Id, patch)); - // Print response - var explanation = (subject, newLevel) switch + async Task SetLevel(MemberPrivacySubject subject, PrivacyLevel level) + { + await _db.Execute(c => c.UpdateMember(target.Id, new MemberPatch().WithPrivacy(subject, level))); + + var subjectName = subject switch + { + MemberPrivacySubject.Name => "name privacy", + MemberPrivacySubject.Description => "description privacy", + MemberPrivacySubject.Avatar => "avatar privacy", + MemberPrivacySubject.Pronouns => "pronoun privacy", + MemberPrivacySubject.Birthday => "birthday privacy", + MemberPrivacySubject.Metadata => "metadata privacy", + MemberPrivacySubject.Visibility => "visibility", + _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}") + }; + + var explanation = (subject, level) switch { (MemberPrivacySubject.Name, PrivacyLevel.Private) => "This member's name is now hidden from other systems, and will be replaced by the member's display name.", (MemberPrivacySubject.Description, PrivacyLevel.Private) => "This member's description is now hidden from other systems.", @@ -460,37 +443,24 @@ namespace PluralKit.Bot (MemberPrivacySubject.Metadata, PrivacyLevel.Public) => "This member's metadata (eg. created timestamp, message count, etc) is no longer hidden from other systems.", (MemberPrivacySubject.Visibility, PrivacyLevel.Public) => "This member is no longer hidden from member lists.", - _ => throw new InvalidOperationException($"Invalid subject/level tuple ({subject}, {newLevel})") + _ => throw new InvalidOperationException($"Invalid subject/level tuple ({subject}, {level})") }; - await ctx.Reply($"{Emojis.Success} {target.NameFor(ctx)}'s {subject.Name()} has been set to **{newLevel.LevelName()}**. {explanation}"); - } - else if (ctx.Match("all") || newValueFromCommand != null) - { - newLevel = newValueFromCommand ?? PopPrivacyLevel("all"); + await ctx.Reply($"{Emojis.Success} {target.NameFor(ctx)}'s **{subjectName}** has been set to **{level.LevelName()}**. {explanation}"); - var patch = new MemberPatch(); - patch.SetAllPrivacy(newLevel); - await _db.Execute(conn => conn.UpdateMember(target.Id, patch)); + // Name privacy only works given a display name + if (subject == MemberPrivacySubject.Name && level == PrivacyLevel.Private && target.DisplayName == null) + await ctx.Reply($"{Emojis.Warn} This member does not have a display name set, and name privacy **will not take effect**."); - if(newLevel == PrivacyLevel.Private) - await ctx.Reply($"All {target.NameFor(ctx)}'s privacy settings have been set to **{newLevel.LevelName()}**. Other accounts will now see nothing on the member card."); - else - await ctx.Reply($"All {target.NameFor(ctx)}'s privacy settings have been set to **{newLevel.LevelName()}**. Other accounts will now see everything on the member card."); + // Avatar privacy doesn't apply when proxying if no server avatar is set + if (subject == MemberPrivacySubject.Avatar && level == PrivacyLevel.Private && guildSettings?.AvatarUrl == null) + await ctx.Reply($"{Emojis.Warn} This member does not have a server avatar set, so *proxying* will **still show the member avatar**. If you want to hide your avatar when proxying here, set a server avatar: `pk;member {target.Hid} serveravatar`"); } + + if (ctx.Match("all") || newValueFromCommand != null) + await SetAll(newValueFromCommand ?? ctx.PopPrivacyLevel()); else - { - var subjectList = "`name`, `description`, `avatar`, `birthday`, `pronouns`, `metadata`, `visibility`, or `all`"; - throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument()}` (must be {subjectList})."); - } - - // Name privacy only works given a display name - if (subject == MemberPrivacySubject.Name && newLevel == PrivacyLevel.Private && target.DisplayName == null) - await ctx.Reply($"{Emojis.Warn} This member does not have a display name set, and name privacy **will not take effect**."); - // Avatar privacy doesn't apply when proxying if no server avatar is set - if (subject == MemberPrivacySubject.Avatar && newLevel == PrivacyLevel.Private && - guildSettings?.AvatarUrl == null) - await ctx.Reply($"{Emojis.Warn} This member does not have a server avatar set, so *proxying* will **still show the member avatar**. If you want to hide your avatar when proxying here, set a server avatar: `pk;member {target.Hid} serveravatar`"); + await SetLevel(ctx.PopMemberPrivacySubject(), ctx.PopPrivacyLevel()); } public async Task Delete(Context ctx, PKMember target) diff --git a/PluralKit.Bot/Commands/Privacy/ContextPrivacyExt.cs b/PluralKit.Bot/Commands/Privacy/ContextPrivacyExt.cs new file mode 100644 index 00000000..8b774d25 --- /dev/null +++ b/PluralKit.Bot/Commands/Privacy/ContextPrivacyExt.cs @@ -0,0 +1,39 @@ +using PluralKit.Core; + +namespace PluralKit.Bot +{ + public static class ContextPrivacyExt + { + public static PrivacyLevel PopPrivacyLevel(this Context ctx) + { + if (ctx.Match("public", "show", "shown", "visible")) + return PrivacyLevel.Public; + + if (ctx.Match("private", "hide", "hidden")) + return PrivacyLevel.Private; + + if (!ctx.HasNext()) + throw new PKSyntaxError("You must pass a privacy level (`public` or `private`)"); + + throw new PKSyntaxError($"Invalid privacy level `{ctx.PopArgument()}` (must be `public` or `private`)."); + } + + public static SystemPrivacySubject PopSystemPrivacySubject(this Context ctx) + { + if (!SystemPrivacyUtils.TryParseSystemPrivacy(ctx.PeekArgument(), out var subject)) + throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument()}` (must be `description`, `members`, `front`, `fronthistory`, or `all`)."); + + ctx.PopArgument(); + return subject; + } + + public static MemberPrivacySubject PopMemberPrivacySubject(this Context ctx) + { + if (!MemberPrivacyUtils.TryParseMemberPrivacy(ctx.PeekArgument(), out var subject)) + throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument()}` (must be `name`, `description`, `avatar`, `birthday`, `pronouns`, `metadata`, `visibility`, or `all)."); + + ctx.PopArgument(); + return subject; + } + } +} \ No newline at end of file diff --git a/PluralKit.Bot/Commands/SystemEdit.cs b/PluralKit.Bot/Commands/SystemEdit.cs index b4d579cb..da2f5e9d 100644 --- a/PluralKit.Bot/Commands/SystemEdit.cs +++ b/PluralKit.Bot/Commands/SystemEdit.cs @@ -13,6 +13,8 @@ using NodaTime.TimeZones; using PluralKit.Core; +using Sentry.Protocol; + namespace PluralKit.Bot { public class SystemEdit @@ -261,93 +263,62 @@ namespace PluralKit.Bot { ctx.CheckSystem(); - if (!ctx.HasNext()) + Task PrintEmbed() { - string PrivacyLevelString(PrivacyLevel level) => level switch - { - PrivacyLevel.Private => "**Private** (visible only when queried by you)", - PrivacyLevel.Public => "**Public** (visible to everyone)", - _ => throw new ArgumentOutOfRangeException(nameof(level), level, null) - }; - var eb = new DiscordEmbedBuilder() .WithTitle("Current privacy settings for your system") - .AddField("Description", PrivacyLevelString(ctx.System.DescriptionPrivacy)) - .AddField("Member list", PrivacyLevelString(ctx.System.MemberListPrivacy)) - .AddField("Current fronter(s)", PrivacyLevelString(ctx.System.FrontPrivacy)) - .AddField("Front/switch history", PrivacyLevelString(ctx.System.FrontHistoryPrivacy)) + .AddField("Description", ctx.System.DescriptionPrivacy.Explanation()) + .AddField("Member list", ctx.System.MemberListPrivacy.Explanation()) + .AddField("Current fronter(s)", ctx.System.FrontPrivacy.Explanation()) + .AddField("Front/switch history", ctx.System.FrontHistoryPrivacy.Explanation()) .WithDescription("To edit privacy settings, use the command:\n`pk;system privacy `\n\n- `subject` is one of `description`, `list`, `front`, `fronthistory`, or `all` \n- `level` is either `public` or `private`."); - await ctx.Reply(embed: eb.Build()); - return; + return ctx.Reply(embed: eb.Build()); } - - PrivacyLevel PopPrivacyLevel(string subject, out string levelStr, out string levelExplanation) + + async Task SetLevel(SystemPrivacySubject subject, PrivacyLevel level) { - if (ctx.Match("public", "show", "shown", "visible")) + await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, new SystemPatch().WithPrivacy(subject, level))); + + var levelExplanation = level switch { - levelStr = "public"; - levelExplanation = "be able to query"; - return PrivacyLevel.Public; - } + PrivacyLevel.Public => "be able to query", + PrivacyLevel.Private => "*not* be able to query", + _ => "" + }; - if (ctx.Match("private", "hide", "hidden")) + var subjectStr = subject switch { - levelStr = "private"; - levelExplanation = "*not* be able to query"; - return PrivacyLevel.Private; - } + SystemPrivacySubject.Description => "description", + SystemPrivacySubject.Front => "front", + SystemPrivacySubject.FrontHistory => "front history", + SystemPrivacySubject.MemberList => "member list", + _ => "" + }; - if (!ctx.HasNext()) - throw new PKSyntaxError($"You must pass a privacy level for `{subject}` (`public` or `private`)"); - throw new PKSyntaxError($"Invalid privacy level `{ctx.PopArgument()}` (must be `public` or `private`)."); + var msg = $"System {subjectStr} privacy has been set to **{level.LevelName()}**. Other accounts will now {levelExplanation} your system {subjectStr}."; + await ctx.Reply($"{Emojis.Success} {msg}"); } - string levelStr, levelExplanation, subjectStr; - var subjectList = "`description`, `members`, `front`, `fronthistory`, or `all`"; - - SystemPatch patch = new SystemPatch(); - if (ctx.Match("description", "desc", "text", "info")) + async Task SetAll(PrivacyLevel level) { - subjectStr = "description"; - patch.DescriptionPrivacy = PopPrivacyLevel("description", out levelStr, out levelExplanation); - } - else if (ctx.Match("members", "memberlist", "list", "mlist")) - { - subjectStr = "member list"; - patch.MemberListPrivacy = PopPrivacyLevel("members", out levelStr, out levelExplanation); - } - else if (ctx.Match("front", "fronter")) - { - subjectStr = "fronter(s)"; - patch.FrontPrivacy = PopPrivacyLevel("front", out levelStr, out levelExplanation); - } - else if (ctx.Match("switch", "switches", "fronthistory", "fh")) - { - subjectStr = "front history"; - patch.FrontHistoryPrivacy = PopPrivacyLevel("fronthistory", out levelStr, out levelExplanation); - } - else if (ctx.Match("all")){ - subjectStr = "all"; - PrivacyLevel level = PopPrivacyLevel("all", out levelStr, out levelExplanation); - patch.DescriptionPrivacy = level; - patch.MemberListPrivacy = level; - patch.FrontPrivacy = level; - patch.FrontHistoryPrivacy = level; + await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, new SystemPatch().WithAllPrivacy(level))); + var msg = level switch + { + PrivacyLevel.Private => $"All system privacy settings have been set to **{level.LevelName()}**. Other accounts will now not be able to view your member list, front history, or system description.", + PrivacyLevel.Public => $"All system privacy settings have been set to **{level.LevelName()}**. Other accounts will now be able to view everything.", + _ => "" + }; + + await ctx.Reply($"{Emojis.Success} {msg}"); } + + if (!ctx.HasNext()) + await PrintEmbed(); + else if (ctx.Match("all")) + await SetAll(ctx.PopPrivacyLevel()); else - throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument()}` (must be {subjectList})."); - - await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); - if(subjectStr == "all"){ - if(levelStr == "private") - await ctx.Reply($"All of your systems privacy settings have been set to **{levelStr}**. Other accounts will now see nothing on the member card."); - else - await ctx.Reply($"All of your systems privacy have been set to **{levelStr}**. Other accounts will now see everything on the member card."); - } - //Handle other subjects - else - await ctx.Reply($"System {subjectStr} privacy has been set to **{levelStr}**. Other accounts will now {levelExplanation} your system {subjectStr}."); + await SetLevel(ctx.PopSystemPrivacySubject(), ctx.PopPrivacyLevel()); } public async Task SystemPing(Context ctx) diff --git a/PluralKit.Core/Models/Privacy/LookupContext.cs b/PluralKit.Core/Models/Privacy/LookupContext.cs new file mode 100644 index 00000000..5ebdd323 --- /dev/null +++ b/PluralKit.Core/Models/Privacy/LookupContext.cs @@ -0,0 +1,9 @@ +namespace PluralKit.Core +{ + public enum LookupContext + { + ByOwner, + ByNonOwner, + API + } +} \ No newline at end of file diff --git a/PluralKit.Core/Utils/PrivacyUtils.cs b/PluralKit.Core/Models/Privacy/MemberPrivacySubject.cs similarity index 59% rename from PluralKit.Core/Utils/PrivacyUtils.cs rename to PluralKit.Core/Models/Privacy/MemberPrivacySubject.cs index 0c1b0a1e..a92819e2 100644 --- a/PluralKit.Core/Utils/PrivacyUtils.cs +++ b/PluralKit.Core/Models/Privacy/MemberPrivacySubject.cs @@ -2,7 +2,8 @@ namespace PluralKit.Core { - public enum MemberPrivacySubject { + public enum MemberPrivacySubject + { Visibility, Name, Description, @@ -11,48 +12,34 @@ namespace PluralKit.Core Pronouns, Metadata } - - public static class PrivacyUtils - { - public static string Name(this MemberPrivacySubject subject) => subject switch - { - MemberPrivacySubject.Name => "name", - MemberPrivacySubject.Description => "description", - MemberPrivacySubject.Avatar => "avatar", - MemberPrivacySubject.Pronouns => "pronouns", - MemberPrivacySubject.Birthday => "birthday", - MemberPrivacySubject.Metadata => "metadata", - MemberPrivacySubject.Visibility => "visibility", - _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}") - }; - public static void SetPrivacy(this MemberPatch member, MemberPrivacySubject subject, PrivacyLevel level) + public static class MemberPrivacyUtils + { + public static MemberPatch WithPrivacy(this MemberPatch member, MemberPrivacySubject subject, PrivacyLevel level) { // what do you mean switch expressions can't be statements >.> _ = subject switch { - MemberPrivacySubject.Name => member.NamePrivacy = Partial.Present(level), - MemberPrivacySubject.Description => member.DescriptionPrivacy = Partial.Present(level), - MemberPrivacySubject.Avatar => member.AvatarPrivacy = Partial.Present(level), - MemberPrivacySubject.Pronouns => member.PronounPrivacy = Partial.Present(level), - MemberPrivacySubject.Birthday => member.BirthdayPrivacy= Partial.Present(level), - MemberPrivacySubject.Metadata => member.MetadataPrivacy = Partial.Present(level), - MemberPrivacySubject.Visibility => member.Visibility = Partial.Present(level), + MemberPrivacySubject.Name => member.NamePrivacy = level, + MemberPrivacySubject.Description => member.DescriptionPrivacy = level, + MemberPrivacySubject.Avatar => member.AvatarPrivacy = level, + MemberPrivacySubject.Pronouns => member.PronounPrivacy = level, + MemberPrivacySubject.Birthday => member.BirthdayPrivacy = level, + MemberPrivacySubject.Metadata => member.MetadataPrivacy = level, + MemberPrivacySubject.Visibility => member.Visibility = level, _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}") }; + + return member; } - public static void SetAllPrivacy(this MemberPatch member, PrivacyLevel level) + public static MemberPatch WithAllPrivacy(this MemberPatch member, PrivacyLevel level) { - member.NamePrivacy = Partial.Present(level); - member.DescriptionPrivacy = Partial.Present(level); - member.AvatarPrivacy = Partial.Present(level); - member.PronounPrivacy = Partial.Present(level); - member.BirthdayPrivacy = Partial.Present(level); - member.MetadataPrivacy = Partial.Present(level); - member.Visibility = Partial.Present(level); + foreach (var subject in Enum.GetValues(typeof(MemberPrivacySubject))) + member.WithPrivacy((MemberPrivacySubject) subject, level); + return member; } - + public static bool TryParseMemberPrivacy(string input, out MemberPrivacySubject subject) { switch (input.ToLowerInvariant()) @@ -89,7 +76,7 @@ namespace PluralKit.Core subject = MemberPrivacySubject.Metadata; break; case "visibility": - case "hidden": + case "hidden": case "shown": case "visible": case "list": @@ -99,7 +86,8 @@ namespace PluralKit.Core subject = MemberPrivacySubject.Name; return false; } + return true; - } + } } } \ No newline at end of file diff --git a/PluralKit.Core/Models/Privacy.cs b/PluralKit.Core/Models/Privacy/PrivacyExt.cs similarity index 67% rename from PluralKit.Core/Models/Privacy.cs rename to PluralKit.Core/Models/Privacy/PrivacyExt.cs index dcd32e5e..548f963e 100644 --- a/PluralKit.Core/Models/Privacy.cs +++ b/PluralKit.Core/Models/Privacy/PrivacyExt.cs @@ -1,11 +1,7 @@ -namespace PluralKit.Core -{ - public enum PrivacyLevel - { - Public = 1, - Private = 2 - } +using System; +namespace PluralKit.Core +{ public static class PrivacyExt { public static bool CanAccess(this PrivacyLevel level, LookupContext ctx) => @@ -16,6 +12,14 @@ public static T Get(this PrivacyLevel level, LookupContext ctx, T input, T fallback = default) => level.CanAccess(ctx) ? input : fallback; + + public static string Explanation(this PrivacyLevel level) => + level switch + { + PrivacyLevel.Private => "**Private** (visible only when queried by you)", + PrivacyLevel.Public => "**Public** (visible to everyone)", + _ => throw new ArgumentOutOfRangeException(nameof(level), level, null) + }; public static bool TryGet(this PrivacyLevel level, LookupContext ctx, T input, out T output, T absentValue = default) { @@ -29,11 +33,4 @@ return true; } } - - public enum LookupContext - { - ByOwner, - ByNonOwner, - API - } } \ No newline at end of file diff --git a/PluralKit.Core/Models/Privacy/PrivacyLevel.cs b/PluralKit.Core/Models/Privacy/PrivacyLevel.cs new file mode 100644 index 00000000..8dad4658 --- /dev/null +++ b/PluralKit.Core/Models/Privacy/PrivacyLevel.cs @@ -0,0 +1,8 @@ +namespace PluralKit.Core +{ + public enum PrivacyLevel + { + Public = 1, + Private = 2 + } +} \ No newline at end of file diff --git a/PluralKit.Core/Models/Privacy/SystemPrivacySubject.cs b/PluralKit.Core/Models/Privacy/SystemPrivacySubject.cs new file mode 100644 index 00000000..1b426d69 --- /dev/null +++ b/PluralKit.Core/Models/Privacy/SystemPrivacySubject.cs @@ -0,0 +1,71 @@ +using System; + +namespace PluralKit.Core +{ + public enum SystemPrivacySubject + { + Description, + MemberList, + Front, + FrontHistory + } + + public static class SystemPrivacyUtils + { + public static SystemPatch WithPrivacy(this SystemPatch system, SystemPrivacySubject subject, PrivacyLevel level) + { + // what do you mean switch expressions can't be statements >.> + _ = subject switch + { + SystemPrivacySubject.Description => system.DescriptionPrivacy = level, + SystemPrivacySubject.Front => system.FrontPrivacy = level, + SystemPrivacySubject.FrontHistory => system.FrontHistoryPrivacy = level, + SystemPrivacySubject.MemberList => system.MemberListPrivacy = level, + _ => throw new ArgumentOutOfRangeException($"Unknown privacy subject {subject}") + }; + + return system; + } + + public static SystemPatch WithAllPrivacy(this SystemPatch system, PrivacyLevel level) + { + foreach (var subject in Enum.GetValues(typeof(SystemPrivacySubject))) + WithPrivacy(system, (SystemPrivacySubject) subject, level); + return system; + } + + public static bool TryParseSystemPrivacy(string input, out SystemPrivacySubject subject) + { + switch (input.ToLowerInvariant()) + { + case "description": + case "desc": + case "text": + case "info": + subject = SystemPrivacySubject.Description; + break; + case "members": + case "memberlist": + case "list": + case "mlist": + subject = SystemPrivacySubject.MemberList; + break; + case "fronter": + case "fronters": + case "front": + subject = SystemPrivacySubject.Front; + break; + case "switch": + case "switches": + case "fronthistory": + case "fh": + subject = SystemPrivacySubject.FrontHistory; + break; + default: + subject = default; + return false; + } + return true; + } + } +} \ No newline at end of file