Use "smart references" for member commands
This commit is contained in:
		| @@ -2,7 +2,6 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Text.RegularExpressions; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| using Dapper; | ||||
| @@ -52,10 +51,10 @@ namespace PluralKit.Bot | ||||
|              | ||||
|             var eb = new DiscordEmbedBuilder() | ||||
|                 .WithDescription($"Your new group, **{groupName}**, has been created, with the group ID **`{newGroup.Hid}`**.\nBelow are a couple of useful commands:") | ||||
|                 .AddField("View the group card", $"> pk;group **{GroupReference(newGroup)}**") | ||||
|                 .AddField("Add members to the group", $"> pk;group **{GroupReference(newGroup)}** add **MemberName**\n> pk;group **{GroupReference(newGroup)}** add **Member1** **Member2** **Member3** (and so on...)") | ||||
|                 .AddField("Set the description", $"> pk;group **{GroupReference(newGroup)}** description **This is my new group, and here is the description!**") | ||||
|                 .AddField("Set the group icon", $"> pk;group **{GroupReference(newGroup)}** icon\n*(with an image attached)*"); | ||||
|                 .AddField("View the group card", $"> pk;group **{newGroup.Reference()}**") | ||||
|                 .AddField("Add members to the group", $"> pk;group **{newGroup.Reference()}** add **MemberName**\n> pk;group **{newGroup.Reference()}** add **Member1** **Member2** **Member3** (and so on...)") | ||||
|                 .AddField("Set the description", $"> pk;group **{newGroup.Reference()}** description **This is my new group, and here is the description!**") | ||||
|                 .AddField("Set the group icon", $"> pk;group **{newGroup.Reference()}** icon\n*(with an image attached)*"); | ||||
|             await ctx.Reply($"{Emojis.Success} Group created!", eb.Build()); | ||||
|         } | ||||
|  | ||||
| @@ -102,7 +101,7 @@ namespace PluralKit.Bot | ||||
|                     .AddField("Display Name", target.DisplayName ?? "*(none)*"); | ||||
|                  | ||||
|                 if (ctx.System?.Id == target.System) | ||||
|                     eb.WithDescription($"To change display name, type `pk;group {GroupReference(target)} displayname <display name>`.\nTo clear it, type `pk;group {GroupReference(target)} displayname -clear`."); | ||||
|                     eb.WithDescription($"To change display name, type `pk;group {target.Reference()} displayname <display name>`.\nTo clear it, type `pk;group {target.Reference()} displayname -clear`."); | ||||
|                  | ||||
|                 await ctx.Reply(embed: eb.Build()); | ||||
|             } | ||||
| @@ -133,7 +132,7 @@ namespace PluralKit.Bot | ||||
|             { | ||||
|                 if (target.Description == null) | ||||
|                     if (ctx.System?.Id == target.System) | ||||
|                         await ctx.Reply($"This group does not have a description set. To set one, type `pk;group {GroupReference(target)} description <description>`."); | ||||
|                         await ctx.Reply($"This group does not have a description set. To set one, type `pk;group {target.Reference()} description <description>`."); | ||||
|                     else | ||||
|                         await ctx.Reply("This group does not have a description set."); | ||||
|                 else if (ctx.MatchFlag("r", "raw")) | ||||
| @@ -142,8 +141,8 @@ namespace PluralKit.Bot | ||||
|                     await ctx.Reply(embed: new DiscordEmbedBuilder() | ||||
|                         .WithTitle("Group description") | ||||
|                         .WithDescription(target.Description) | ||||
|                         .AddField("\u200B", $"To print the description with formatting, type `pk;group {GroupReference(target)} description -raw`."  | ||||
|                                     + (ctx.System?.Id == target.System ? $" To clear it, type `pk;group {GroupReference(target)} description -clear`." : "")) | ||||
|                         .AddField("\u200B", $"To print the description with formatting, type `pk;group {target.Reference()} description -raw`."  | ||||
|                                     + (ctx.System?.Id == target.System ? $" To clear it, type `pk;group {target.Reference()} description -clear`." : "")) | ||||
|                         .Build()); | ||||
|             } | ||||
|             else | ||||
| @@ -206,7 +205,7 @@ namespace PluralKit.Bot | ||||
|                      | ||||
|                     if (target.System == ctx.System?.Id) | ||||
|                     { | ||||
|                         eb.WithDescription($"To clear, use `pk;group {GroupReference(target)} icon -clear`."); | ||||
|                         eb.WithDescription($"To clear, use `pk;group {target.Reference()} icon -clear`."); | ||||
|                     } | ||||
|  | ||||
|                     await ctx.Reply(embed: eb.Build()); | ||||
| @@ -300,9 +299,9 @@ namespace PluralKit.Bot | ||||
|             { | ||||
|                 if (memberCount == 0 && pctx == LookupContext.ByOwner) | ||||
|                     // Only suggest the add command if this is actually the owner lol | ||||
|                     eb.AddField("Members (0)", $"Add one with `pk;group {GroupReference(target)} add <member>`!", true); | ||||
|                     eb.AddField("Members (0)", $"Add one with `pk;group {target.Reference()} add <member>`!", true); | ||||
|                 else | ||||
|                     eb.AddField($"Members ({memberCount})", $"(see `pk;group {GroupReference(target)} list`)", true); | ||||
|                     eb.AddField($"Members ({memberCount})", $"(see `pk;group {target.Reference()} list`)", true); | ||||
|             } | ||||
|  | ||||
|             if (target.DescriptionFor(pctx) is {} desc) | ||||
| @@ -416,7 +415,7 @@ namespace PluralKit.Bot | ||||
|                     .AddField("Icon", target.IconPrivacy.Explanation()) | ||||
|                     .AddField("Member list", target.ListPrivacy.Explanation()) | ||||
|                     .AddField("Visibility", target.Visibility.Explanation()) | ||||
|                     .WithDescription($"To edit privacy settings, use the command:\n> pk;group **{GroupReference(target)}** privacy **<subject>** **<level>**\n\n- `subject` is one of `description`, `icon`, `members`, `visibility`, or `all`\n- `level` is either `public` or `private`.") | ||||
|                     .WithDescription($"To edit privacy settings, use the command:\n> pk;group **{target.Reference()}** privacy **<subject>** **<level>**\n\n- `subject` is one of `description`, `icon`, `members`, `visibility`, or `all`\n- `level` is either `public` or `private`.") | ||||
|                     .Build());  | ||||
|                 return; | ||||
|             } | ||||
| @@ -488,12 +487,5 @@ namespace PluralKit.Bot | ||||
|                 return system; | ||||
|             return await conn.QuerySystem(target.System)!; | ||||
|         } | ||||
|  | ||||
|         private static string GroupReference(PKGroup group) | ||||
|         { | ||||
|             if (Regex.IsMatch(group.Name, "^[A-Za-z0-9\\-_]+$")) | ||||
|                 return group.Name; | ||||
|             return group.Hid; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -30,7 +30,7 @@ namespace PluralKit.Bot | ||||
|             else | ||||
|             { | ||||
|                 if (mgs?.AvatarUrl != null) | ||||
|                     await ctx.Reply($"{Emojis.Success} Member avatar cleared. Note that this member has a server-specific avatar set here, type `pk;member {target.Hid} serveravatar clear` if you wish to clear that too."); | ||||
|                     await ctx.Reply($"{Emojis.Success} Member avatar cleared. Note that this member has a server-specific avatar set here, type `pk;member {target.Reference()} serveravatar clear` if you wish to clear that too."); | ||||
|                 else  | ||||
|                     await ctx.Reply($"{Emojis.Success} Member avatar cleared."); | ||||
|             } | ||||
| @@ -50,7 +50,7 @@ namespace PluralKit.Bot | ||||
|                 } | ||||
|  | ||||
|                 if (location == AvatarLocation.Server) | ||||
|                     throw new PKError($"This member does not have a server avatar set. Type `pk;member {target.Hid} avatar` to see their global avatar."); | ||||
|                     throw new PKError($"This member does not have a server avatar set. Type `pk;member {target.Reference()} avatar` to see their global avatar."); | ||||
|             } | ||||
|              | ||||
|             var field = location == AvatarLocation.Server ? $"server avatar (for {ctx.Guild.Name})" : "avatar"; | ||||
| @@ -60,7 +60,7 @@ namespace PluralKit.Bot | ||||
|                 .WithTitle($"{target.NameFor(ctx)}'s {field}") | ||||
|                 .WithImageUrl(currentValue); | ||||
|             if (target.System == ctx.System?.Id) | ||||
|                 eb.WithDescription($"To clear, use `pk;member {target.Hid} {cmd} clear`."); | ||||
|                 eb.WithDescription($"To clear, use `pk;member {target.Reference()} {cmd} clear`."); | ||||
|             await ctx.Reply(embed: eb.Build()); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -78,7 +78,7 @@ namespace PluralKit.Bot | ||||
|                     throw Errors.LookupNotAllowed; | ||||
|                 if (target.Description == null) | ||||
|                     if (ctx.System?.Id == target.System) | ||||
|                         await ctx.Reply($"This member does not have a description set. To set one, type `pk;member {target.Hid} description <description>`."); | ||||
|                         await ctx.Reply($"This member does not have a description set. To set one, type `pk;member {target.Reference()} description <description>`."); | ||||
|                     else | ||||
|                         await ctx.Reply("This member does not have a description set."); | ||||
|                 else if (ctx.MatchFlag("r", "raw")) | ||||
| @@ -87,8 +87,8 @@ namespace PluralKit.Bot | ||||
|                     await ctx.Reply(embed: new DiscordEmbedBuilder() | ||||
|                         .WithTitle("Member description") | ||||
|                         .WithDescription(target.Description) | ||||
|                         .AddField("\u200B", $"To print the description with formatting, type `pk;member {target.Hid} description -raw`."  | ||||
|                                     + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Hid} description -clear`." : "")) | ||||
|                         .AddField("\u200B", $"To print the description with formatting, type `pk;member {target.Reference()} description -raw`."  | ||||
|                                     + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Reference()} description -clear`." : "")) | ||||
|                         .Build()); | ||||
|             } | ||||
|             else | ||||
| @@ -120,12 +120,12 @@ namespace PluralKit.Bot | ||||
|                     throw Errors.LookupNotAllowed; | ||||
|                 if (target.Pronouns == null) | ||||
|                     if (ctx.System?.Id == target.System) | ||||
|                         await ctx.Reply($"This member does not have pronouns set. To set some, type `pk;member {target.Hid} pronouns <pronouns>`."); | ||||
|                         await ctx.Reply($"This member does not have pronouns set. To set some, type `pk;member {target.Reference()} pronouns <pronouns>`."); | ||||
|                     else | ||||
|                         await ctx.Reply("This member does not have pronouns set."); | ||||
|                 else | ||||
|                     await ctx.Reply($"**{target.NameFor(ctx)}**'s pronouns are **{target.Pronouns}**." | ||||
|                         + (ctx.System?.Id == target.System ? $" To clear them, type `pk;member {target.Hid} pronouns -clear`." : "")); | ||||
|                         + (ctx.System?.Id == target.System ? $" To clear them, type `pk;member {target.Reference()} pronouns -clear`." : "")); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
| @@ -162,7 +162,7 @@ namespace PluralKit.Bot | ||||
|                 if (target.Color == null) | ||||
|                     if (ctx.System?.Id == target.System) | ||||
|                         await ctx.Reply( | ||||
|                             $"This member does not have a color set. To set one, type `pk;member {target.Hid} color <color>`."); | ||||
|                             $"This member does not have a color set. To set one, type `pk;member {target.Reference()} color <color>`."); | ||||
|                     else | ||||
|                         await ctx.Reply("This member does not have a color set."); | ||||
|                 else | ||||
| @@ -171,7 +171,7 @@ namespace PluralKit.Bot | ||||
|                         .WithColor(target.Color.ToDiscordColor().Value) | ||||
|                         .WithThumbnail($"https://fakeimg.pl/256x256/{target.Color}/?text=%20") | ||||
|                         .WithDescription($"This member's color is **#{target.Color}**." | ||||
|                                          + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Hid} color -clear`." : "")) | ||||
|                                          + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Reference()} color -clear`." : "")) | ||||
|                         .Build()); | ||||
|             } | ||||
|             else | ||||
| @@ -209,10 +209,10 @@ namespace PluralKit.Bot | ||||
|                  | ||||
|                 if (target.Birthday == null) | ||||
|                     await ctx.Reply("This member does not have a birthdate set." | ||||
|                         + (ctx.System?.Id == target.System ? $" To set one, type `pk;member {target.Hid} birthdate <birthdate>`." : "")); | ||||
|                         + (ctx.System?.Id == target.System ? $" To set one, type `pk;member {target.Reference()} birthdate <birthdate>`." : "")); | ||||
|                 else | ||||
|                     await ctx.Reply($"This member's birthdate is **{target.BirthdayString}**." | ||||
|                                     + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Hid} birthdate -clear`." : "")); | ||||
|                                     + (ctx.System?.Id == target.System ? $" To clear it, type `pk;member {target.Reference()} birthdate -clear`." : "")); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
| @@ -293,7 +293,7 @@ namespace PluralKit.Bot | ||||
|                 // No perms check, display name isn't covered by member privacy  | ||||
|                 var eb = await CreateMemberNameInfoEmbed(ctx, target); | ||||
|                 if (ctx.System?.Id == target.System) | ||||
|                     eb.WithDescription($"To change display name, type `pk;member {target.Hid} displayname <display name>`.\nTo clear it, type `pk;member {target.Hid} displayname -clear`."); | ||||
|                     eb.WithDescription($"To change display name, type `pk;member {target.Reference()} displayname <display name>`.\nTo clear it, type `pk;member {target.Reference()} displayname -clear`."); | ||||
|                 await ctx.Reply(embed: eb.Build()); | ||||
|             } | ||||
|             else | ||||
| @@ -330,7 +330,7 @@ namespace PluralKit.Bot | ||||
|                 // No perms check, server name isn't covered by member privacy  | ||||
|                 var eb = await CreateMemberNameInfoEmbed(ctx, target); | ||||
|                 if (ctx.System?.Id == target.System) | ||||
|                     eb.WithDescription($"To change server name, type `pk;member {target.Hid} servername <server name>`.\nTo clear it, type `pk;member {target.Hid} servername -clear`."); | ||||
|                     eb.WithDescription($"To change server name, type `pk;member {target.Reference()} servername <server name>`.\nTo clear it, type `pk;member {target.Reference()} servername -clear`."); | ||||
|                 await ctx.Reply(embed: eb.Build()); | ||||
|             } | ||||
|             else | ||||
| @@ -455,7 +455,7 @@ namespace PluralKit.Bot | ||||
|                  | ||||
|                 // 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`"); | ||||
|                     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.Reference()} serveravatar`"); | ||||
|             } | ||||
|  | ||||
|             if (ctx.Match("all") || newValueFromCommand != null) | ||||
|   | ||||
| @@ -1,4 +1,7 @@ | ||||
| using PluralKit.Core; | ||||
| using System.Linq; | ||||
| using System.Text.RegularExpressions; | ||||
|  | ||||
| using PluralKit.Core; | ||||
|  | ||||
| namespace PluralKit.Bot | ||||
| { | ||||
| @@ -12,5 +15,32 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         public static string DisplayName(this PKMember member) => | ||||
|             member.DisplayName ?? member.Name; | ||||
|  | ||||
|         public static string Reference(this PKMember member) => EntityReference(member.Hid, member.Name); | ||||
|         public static string Reference(this PKGroup group) => EntityReference(group.Hid, group.Name); | ||||
|  | ||||
|         private static string EntityReference(string hid, string name) | ||||
|         { | ||||
|             bool IsSimple(string s) => | ||||
|                 // No spaces, no symbols, allow single quote but not at the start | ||||
|                 Regex.IsMatch(s, "^[\\w\\d\\-_'?]+$") && !s.StartsWith("'"); | ||||
|              | ||||
|             // If it's very long (>25 chars), always use hid | ||||
|             if (name.Length >= 25) | ||||
|                 return hid; | ||||
|  | ||||
|             // If name is "simple" just use that | ||||
|             if (IsSimple(name))  | ||||
|                 return name; | ||||
|              | ||||
|             // If three or fewer "words" and they're all simple individually, quote them | ||||
|             var words = name.Split(' '); | ||||
|             if (words.Length <= 3 && words.All(w => w.Length > 0 && IsSimple(w))) | ||||
|                 // Words with double quotes are never "simple" so we're safe to naive-quote here | ||||
|                 return $"\"{name}\""; | ||||
|              | ||||
|             // Otherwise, just use hid | ||||
|             return hid; | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user