feat(bot): basic webhook username templating

This commit is contained in:
libglfw 2024-10-22 03:05:32 -04:00 committed by Iris System
parent 87196e3297
commit 614131265b
16 changed files with 78 additions and 14 deletions

View file

@ -30,6 +30,7 @@ public partial class CommandTree
public static Command ConfigShowPrivate = new Command("config show private", "config show private [on|off]", "Sets whether private information is shown to linked accounts by default"); public static Command ConfigShowPrivate = new Command("config show private", "config show private [on|off]", "Sets whether private information is shown to linked accounts by default");
public static Command ConfigMemberDefaultPrivacy = new("config private member", "config private member [on|off]", "Sets whether member privacy is automatically set to private when creating a new member"); public static Command ConfigMemberDefaultPrivacy = new("config private member", "config private member [on|off]", "Sets whether member privacy is automatically set to private when creating a new member");
public static Command ConfigGroupDefaultPrivacy = new("config private group", "config private group [on|off]", "Sets whether group privacy is automatically set to private when creating a new group"); public static Command ConfigGroupDefaultPrivacy = new("config private group", "config private group [on|off]", "Sets whether group privacy is automatically set to private when creating a new group");
public static Command ConfigNameFormat = new Command("config nameformat", "config nameformat [format]", "Changes your system's username formatting");
public static Command AutoproxySet = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for the current server"); public static Command AutoproxySet = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for the current server");
public static Command AutoproxyOff = new Command("autoproxy off", "autoproxy off", "Disables autoproxying for your system in the current server"); public static Command AutoproxyOff = new Command("autoproxy off", "autoproxy off", "Disables autoproxying for your system in the current server");
public static Command AutoproxyFront = new Command("autoproxy front", "autoproxy front", "Sets your system's autoproxy in this server to proxy the first member currently registered as front"); public static Command AutoproxyFront = new Command("autoproxy front", "autoproxy front", "Sets your system's autoproxy in this server to proxy the first member currently registered as front");
@ -145,7 +146,7 @@ public partial class CommandTree
public static Command[] ConfigCommands = public static Command[] ConfigCommands =
{ {
ConfigAutoproxyAccount, ConfigAutoproxyTimeout, ConfigTimezone, ConfigPing, ConfigAutoproxyAccount, ConfigAutoproxyTimeout, ConfigTimezone, ConfigPing,
ConfigMemberDefaultPrivacy, ConfigGroupDefaultPrivacy, ConfigShowPrivate ConfigMemberDefaultPrivacy, ConfigGroupDefaultPrivacy, ConfigShowPrivate, ConfigNameFormat
}; };
public static Command[] AutoproxyCommands = public static Command[] AutoproxyCommands =

View file

@ -594,6 +594,8 @@ public partial class CommandTree
return ctx.Execute<Config>(null, m => m.HidDisplayCaps(ctx)); return ctx.Execute<Config>(null, m => m.HidDisplayCaps(ctx));
if (ctx.MatchMultiple(new[] { "pad" }, new[] { "id", "ids" }) || ctx.MatchMultiple(new[] { "id" }, new[] { "pad", "padding" }) || ctx.Match("idpad", "padid", "padids")) if (ctx.MatchMultiple(new[] { "pad" }, new[] { "id", "ids" }) || ctx.MatchMultiple(new[] { "id" }, new[] { "pad", "padding" }) || ctx.Match("idpad", "padid", "padids"))
return ctx.Execute<Config>(null, m => m.HidListPadding(ctx)); return ctx.Execute<Config>(null, m => m.HidListPadding(ctx));
if (ctx.MatchMultiple(new[] { "name" }, new[] { "format" }) || ctx.Match("nf"))
return ctx.Execute<Config>(null, m => m.NameFormat(ctx));
if (ctx.MatchMultiple(new[] { "member", "group" }, new[] { "limit" }) || ctx.Match("limit")) if (ctx.MatchMultiple(new[] { "member", "group" }, new[] { "limit" }) || ctx.Match("limit"))
return ctx.Execute<Config>(null, m => m.LimitUpdate(ctx)); return ctx.Execute<Config>(null, m => m.LimitUpdate(ctx));
if (ctx.MatchMultiple(new[] { "proxy" }, new[] { "switch" }) || ctx.Match("proxyswitch", "ps")) if (ctx.MatchMultiple(new[] { "proxy" }, new[] { "switch" }) || ctx.Match("proxyswitch", "ps"))

View file

@ -130,6 +130,13 @@ public class Config
"disabled" "disabled"
)); ));
items.Add(new(
"Name Format",
"Format string used to display a member's name https://pluralkit.me/guide/#setting-a-custom-name-format",
ctx.Config.NameFormat,
ProxyMember.DefaultFormat
));
await ctx.Paginate<PaginatedConfigItem>( await ctx.Paginate<PaginatedConfigItem>(
items.ToAsyncEnumerable(), items.ToAsyncEnumerable(),
items.Count, items.Count,
@ -558,6 +565,19 @@ public class Config
await ctx.Reply($"Logging a switch every time a proxy tag is used is now {EnabledDisabled(newVal)}."); await ctx.Reply($"Logging a switch every time a proxy tag is used is now {EnabledDisabled(newVal)}.");
} }
public async Task NameFormat(Context ctx)
{
if (!ctx.HasNext())
{
await ctx.Reply($"Member names are currently formatted as `{ctx.Config.NameFormat ?? ProxyMember.DefaultFormat}`");
return;
}
var formatString = ctx.RemainderOrNull();
await ctx.Repository.UpdateSystemConfig(ctx.System.Id, new() { NameFormat = formatString });
await ctx.Reply($"Member names are now formatted as `{formatString}`");
}
public Task LimitUpdate(Context ctx) public Task LimitUpdate(Context ctx)
{ {
throw new PKError("You cannot update your own member or group limits. If you need a limit update, please join the " + throw new PKError("You cannot update your own member or group limits. If you need a limit update, please join the " +

View file

@ -162,7 +162,7 @@ public static class Errors
$"The webhook's name, {name.AsCode()}, is shorter than two characters, and thus cannot be proxied. Please change the member name or use a longer system tag."); $"The webhook's name, {name.AsCode()}, is shorter than two characters, and thus cannot be proxied. Please change the member name or use a longer system tag.");
public static PKError ProxyNameTooLong(string name) => new( public static PKError ProxyNameTooLong(string name) => new(
$"The webhook's name, {name.AsCode()}, is too long ({name.Length} > {Limits.MaxProxyNameLength} characters), and thus cannot be proxied. Please change the member name, display name or server display name, or use a shorter system tag."); $"The webhook's name, {name.AsCode()}, is too long ({name.Length} > {Limits.MaxProxyNameLength} characters), and thus cannot be proxied. Please change the member name, display name, server display name, system tag, or use a shorter name format");
public static PKError ProxyTagAlreadyExists(ProxyTag tagToAdd, PKMember member) => new( public static PKError ProxyTagAlreadyExists(ProxyTag tagToAdd, PKMember member) => new(
$"That member already has the proxy tag {tagToAdd.ProxyString.AsCode()}. The member currently has these tags: {member.ProxyTagsString()}"); $"That member already has the proxy tag {tagToAdd.ProxyString.AsCode()}. The member currently has these tags: {member.ProxyTagsString()}");

View file

@ -25,6 +25,7 @@ public class MessageContext
public string? SystemTag { get; } public string? SystemTag { get; }
public string? SystemGuildTag { get; } public string? SystemGuildTag { get; }
public bool TagEnabled { get; } public bool TagEnabled { get; }
public string? NameFormat { get; }
public string? SystemAvatar { get; } public string? SystemAvatar { get; }
public string? SystemGuildAvatar { get; } public string? SystemGuildAvatar { get; }
public bool AllowAutoproxy { get; } public bool AllowAutoproxy { get; }

View file

@ -31,17 +31,23 @@ public class ProxyMember
public bool AllowAutoproxy { get; } public bool AllowAutoproxy { get; }
public string? Color { get; } public string? Color { get; }
// If not set, this formatting will be applied to the proxy name
public static string DefaultFormat = "{name} {tag}";
public static string FormatTag(string template, string tag, string name) => StringUtils.SafeFormat(template, new[] {
("{tag}", tag),
("{name}", name)
});
public string ProxyName(MessageContext ctx) public string ProxyName(MessageContext ctx)
{ {
// TODO: if tag is null it should still format but only if it appears in the formatting.
var memberName = ServerName ?? DisplayName ?? Name; var memberName = ServerName ?? DisplayName ?? Name;
if (!ctx.TagEnabled) var tag = ctx.SystemGuildTag ?? ctx.SystemTag;
if (!ctx.TagEnabled || tag == null)
return memberName; return memberName;
if (ctx.SystemGuildTag != null) return FormatTag(ctx.NameFormat ?? DefaultFormat, tag, memberName);
return $"{memberName} {ctx.SystemGuildTag}";
if (ctx.SystemTag != null)
return $"{memberName} {ctx.SystemTag}";
return memberName;
} }
public string? ProxyAvatar(MessageContext ctx) => ServerAvatar ?? WebhookAvatar ?? Avatar ?? ctx.SystemGuildAvatar ?? ctx.SystemAvatar; public string? ProxyAvatar(MessageContext ctx) => ServerAvatar ?? WebhookAvatar ?? Avatar ?? ctx.SystemGuildAvatar ?? ctx.SystemAvatar;

View file

@ -1,4 +1,4 @@
create function message_context(account_id bigint, guild_id bigint, channel_id bigint, thread_id bigint) create function message_context(account_id bigint, guild_id bigint, channel_id bigint, thread_id bigint)
returns table ( returns table (
allow_autoproxy bool, allow_autoproxy bool,
@ -10,6 +10,7 @@
case_sensitive_proxy_tags bool, case_sensitive_proxy_tags bool,
proxy_error_message_enabled bool, proxy_error_message_enabled bool,
proxy_switch bool, proxy_switch bool,
name_format text,
tag_enabled bool, tag_enabled bool,
proxy_enabled bool, proxy_enabled bool,
@ -42,6 +43,7 @@ as $$
system_config.case_sensitive_proxy_tags as case_sensitive_proxy_tags, system_config.case_sensitive_proxy_tags as case_sensitive_proxy_tags,
system_config.proxy_error_message_enabled as proxy_error_message_enabled, system_config.proxy_error_message_enabled as proxy_error_message_enabled,
system_config.proxy_switch as proxy_switch, system_config.proxy_switch as proxy_switch,
system_config.name_format as name_format,
-- system_guild table -- system_guild table
coalesce(system_guild.tag_enabled, true) as tag_enabled, coalesce(system_guild.tag_enabled, true) as tag_enabled,

View file

@ -0,0 +1,6 @@
-- database version 47
-- add config setting for supplying a custom tag format in names
alter table system_config add column name_format text;
update info set schema_version = 47;

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 = 46; private const int TargetSchemaVersion = 47;
private readonly ILogger _logger; private readonly ILogger _logger;
public DatabaseMigrator(ILogger logger) public DatabaseMigrator(ILogger logger)

View file

@ -21,6 +21,7 @@ public class SystemConfigPatch: PatchObject
public Partial<bool> ProxyErrorMessageEnabled { get; set; } public Partial<bool> ProxyErrorMessageEnabled { get; set; }
public Partial<bool> HidDisplaySplit { get; set; } public Partial<bool> HidDisplaySplit { get; set; }
public Partial<bool> HidDisplayCaps { get; set; } public Partial<bool> HidDisplayCaps { get; set; }
public Partial<string?> NameFormat { get; set; }
public Partial<SystemConfig.HidPadFormat> HidListPadding { get; set; } public Partial<SystemConfig.HidPadFormat> HidListPadding { get; set; }
public Partial<bool> ProxySwitch { get; set; } public Partial<bool> ProxySwitch { get; set; }
@ -40,6 +41,7 @@ public class SystemConfigPatch: PatchObject
.With("hid_display_caps", HidDisplayCaps) .With("hid_display_caps", HidDisplayCaps)
.With("hid_list_padding", HidListPadding) .With("hid_list_padding", HidListPadding)
.With("proxy_switch", ProxySwitch) .With("proxy_switch", ProxySwitch)
.With("name_format", NameFormat)
); );
public new void AssertIsValid() public new void AssertIsValid()
@ -107,6 +109,9 @@ public class SystemConfigPatch: PatchObject
if (ProxySwitch.IsPresent) if (ProxySwitch.IsPresent)
o.Add("proxy_switch", ProxySwitch.Value); o.Add("proxy_switch", ProxySwitch.Value);
if (NameFormat.IsPresent)
o.Add("name_format", NameFormat.Value);
return o; return o;
} }
@ -147,6 +152,9 @@ public class SystemConfigPatch: PatchObject
if (o.ContainsKey("proxy_switch")) if (o.ContainsKey("proxy_switch"))
patch.ProxySwitch = o.Value<bool>("proxy_switch"); patch.ProxySwitch = o.Value<bool>("proxy_switch");
if (o.ContainsKey("name_format"))
patch.NameFormat = o.Value<string>("name_format");
return patch; return patch;
} }
} }

View file

@ -25,6 +25,7 @@ public class SystemConfig
public bool HidDisplayCaps { get; } public bool HidDisplayCaps { get; }
public HidPadFormat HidListPadding { get; } public HidPadFormat HidListPadding { get; }
public bool ProxySwitch { get; } public bool ProxySwitch { get; }
public string NameFormat { get; }
public enum HidPadFormat public enum HidPadFormat
{ {
@ -54,6 +55,7 @@ public static class SystemConfigExt
o.Add("hid_display_caps", cfg.HidDisplayCaps); o.Add("hid_display_caps", cfg.HidDisplayCaps);
o.Add("hid_list_padding", cfg.HidListPadding.ToUserString()); o.Add("hid_list_padding", cfg.HidListPadding.ToUserString());
o.Add("proxy_switch", cfg.ProxySwitch); o.Add("proxy_switch", cfg.ProxySwitch);
o.Add("name_format", cfg.NameFormat);
o.Add("description_templates", JArray.FromObject(cfg.DescriptionTemplates)); o.Add("description_templates", JArray.FromObject(cfg.DescriptionTemplates));

View file

@ -86,4 +86,10 @@ public static class StringUtils
return output; return output;
} }
// Lightweight formatting that intentionally is very basic to not have silly things like in-template for loops like other templating engines seem to have
// Currently doesn't handle escapes which might cause problems
public static string SafeFormat(string template, (string pattern, string arg)[] args) =>
args
.Aggregate(template, (acc, x) => acc.Replace(x.pattern, x.arg));
} }

View file

@ -739,8 +739,8 @@
}, },
"Sentry": { "Sentry": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.11.1", "resolved": "4.12.1",
"contentHash": "T/NLfs6MMkUSYsPEDajB9ad0124T18I0uUod5MNOev3iwjvcnIEQBrStEX2olbIxzqfvGXzQ/QFqTfA2ElLPlA==" "contentHash": "OLf7885OKHWLaTLTyw884mwOT4XKCWj2Hz5Wuz/TJemJqXwCIdIljkJBIoeHviRUPvtB7ulDgeYXf/Z7ScToSA=="
}, },
"Serilog": { "Serilog": {
"type": "Transitive", "type": "Transitive",
@ -1809,7 +1809,7 @@
"Humanizer.Core": "[2.8.26, )", "Humanizer.Core": "[2.8.26, )",
"Myriad": "[1.0.0, )", "Myriad": "[1.0.0, )",
"PluralKit.Core": "[1.0.0, )", "PluralKit.Core": "[1.0.0, )",
"Sentry": "[3.11.1, )", "Sentry": "[4.12.1, )",
"SixLabors.ImageSharp": "[3.1.5, )" "SixLabors.ImageSharp": "[3.1.5, )"
} }
}, },

View file

@ -149,6 +149,7 @@ You can have a space after `pk;`, e.g. `pk;system` and `pk; system` will do the
- `pk;config capitalize IDs [on|off]` - Toggles whether to display IDs as capital letters, to ease readability. - `pk;config capitalize IDs [on|off]` - Toggles whether to display IDs as capital letters, to ease readability.
- `pk;config pad IDs [left|right|off]` - Toggles whether to pad (add a space) 5-character IDs in lists. - `pk;config pad IDs [left|right|off]` - Toggles whether to pad (add a space) 5-character IDs in lists.
- `pk;config proxy switch [on|off]` - Toggles whether to log a switch whenever you proxy as a different member. - `pk;config proxy switch [on|off]` - Toggles whether to log a switch whenever you proxy as a different member.
- `pk;config name format [format]` - Changes your system's username formatting.
## Server owner commands ## Server owner commands
*(all commands here require Manage Server permission)* *(all commands here require Manage Server permission)*

View file

@ -387,6 +387,14 @@ Now, oth of the following will work without needing to add multiple versions of
John: Hello! John: Hello!
JOHN: Hello! JOHN: Hello!
### Setting a custom name format
The default proxy username formatting is "{name} {tag}", but you can customize this value in config:
pk;config nameformat {tag} {name}
pk;config nameformat {name}@{tag}
## Interacting with proxied messages ## Interacting with proxied messages
### Your own messages ### Your own messages

View file

@ -6,6 +6,7 @@ pkgs.mkShellNoCC {
gcc gcc
protobuf protobuf
dotnet-sdk_6 dotnet-sdk_6
omnisharp-roslyn
go go
nodejs yarn nodejs yarn
]; ];