Use "smart references" for member commands

This commit is contained in:
Ske 2020-08-25 22:33:04 +02:00
parent d21eb7b477
commit 2794919728
4 changed files with 58 additions and 36 deletions

View File

@ -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;
}
}
}

View File

@ -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());
}

View File

@ -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)

View File

@ -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;
}
}
}