feat(bot): add new guild settings command

This commit is contained in:
Iris System 2024-11-10 15:46:36 +13:00
parent f0436332c0
commit 0473bd8f01
15 changed files with 179 additions and 15 deletions

View file

@ -105,10 +105,12 @@ public partial class CommandTree
public static Command LogEnable = new Command("log enable", "log enable all|<channel> [channel 2] [channel 3...]", "Enables message logging in certain channels");
public static Command LogDisable = new Command("log disable", "log disable all|<channel> [channel 2] [channel 3...]", "Disables message logging in certain channels");
public static Command LogShow = new Command("log show", "log show", "Displays the current list of channels where logging is disabled");
public static Command LogClean = new Command("logclean", "logclean [on|off]", "Toggles whether to clean up other bots' log channels");
public static Command BlacklistShow = new Command("blacklist show", "blacklist show", "Displays the current proxy blacklist");
public static Command BlacklistAdd = new Command("blacklist add", "blacklist add all|<channel> [channel 2] [channel 3...]", "Adds certain channels to the proxy blacklist");
public static Command BlacklistRemove = new Command("blacklist remove", "blacklist remove all|<channel> [channel 2] [channel 3...]", "Removes certain channels from the proxy blacklist");
public static Command ServerConfigLogClean = new Command("serverconfig logclean", "serverconfig logclean [on|off]", "Toggles whether to clean up other bots' log channels");
public static Command ServerConfigInvalidCommandResponse = new Command("serverconfig invalidcommanderror", "serverconfig invalidcommanderror [on|off]", "Sets whether to show an error message when an unknown command is sent");
public static Command ServerConfigRequireSystemTag = new Command("serverconfig requiretag", "serverconfig requiretag [on|off]", "Sets whether server users are required to have a system tag on proxied messages");
public static Command Invite = new Command("invite", "invite", "Gets a link to invite PluralKit to other servers");
public static Command PermCheck = new Command("permcheck", "permcheck <guild>", "Checks whether a server's permission setup is correct");
public static Command Admin = new Command("admin", "admin", "Super secret admin commands (sshhhh)");
@ -151,6 +153,11 @@ public partial class CommandTree
ConfigProxySwitch, ConfigNameFormat
};
public static Command[] ServerConfigCommands =
{
ServerConfigLogClean, ServerConfigInvalidCommandResponse, ServerConfigRequireSystemTag
};
public static Command[] AutoproxyCommands =
{
AutoproxyOff, AutoproxyFront, AutoproxyLatch, AutoproxyMember

View file

@ -20,6 +20,8 @@ public partial class CommandTree
return HandleAutoproxyCommand(ctx);
if (ctx.Match("config", "cfg", "configure"))
return HandleConfigCommand(ctx);
if (ctx.Match("serverconfig", "guildconfig", "scfg"))
return HandleServerConfigCommand(ctx);
if (ctx.Match("list", "find", "members", "search", "query", "l", "f", "fd", "ls"))
return ctx.Execute<SystemList>(SystemList, m => m.MemberList(ctx, ctx.System));
if (ctx.Match("link"))
@ -65,7 +67,7 @@ public partial class CommandTree
return PrintCommandList(ctx, "message logging", LogCommands);
else return PrintCommandExpectedError(ctx, LogCommands);
if (ctx.Match("logclean"))
return ctx.Execute<ServerConfig>(LogClean, m => m.SetLogCleanup(ctx));
return ctx.Execute<ServerConfig>(ServerConfigLogClean, m => m.SetLogCleanup(ctx), true);
if (ctx.Match("blacklist", "bl"))
if (ctx.Match("enable", "on", "add", "deny"))
return ctx.Execute<ServerConfig>(BlacklistAdd, m => m.SetBlacklisted(ctx, true));
@ -108,6 +110,10 @@ public partial class CommandTree
if (ctx.Match("dashboard", "dash"))
return ctx.Execute<Help>(Dashboard, m => m.Dashboard(ctx));
// don't send an "invalid command" response if the guild has those turned off
if (ctx.GuildConfig != null && ctx.GuildConfig!.InvalidCommandResponseEnabled != true)
return Task.CompletedTask;
// remove compiler warning
return ctx.Reply(
$"{Emojis.Error} Unknown command {ctx.PeekArgument().AsCode()}. For a list of possible commands, see <https://pluralkit.me/commands>.");
@ -534,6 +540,11 @@ public partial class CommandTree
case "cfg":
await PrintCommandList(ctx, "settings", ConfigCommands);
break;
case "serverconfig":
case "guildconfig":
case "scfg":
await PrintCommandList(ctx, "server settings", ServerConfigCommands);
break;
case "autoproxy":
case "ap":
await PrintCommandList(ctx, "autoproxy", AutoproxyCommands);
@ -604,4 +615,20 @@ public partial class CommandTree
// todo: maybe add the list of configuration keys here?
return ctx.Reply($"{Emojis.Error} Could not find a setting with that name. Please see `pk;commands config` for the list of possible config settings.");
}
private Task HandleServerConfigCommand(Context ctx)
{
if (!ctx.HasNext())
return ctx.Execute<ServerConfig>(null, m => m.ShowConfig(ctx));
if (ctx.MatchMultiple(new[] { "log" }, new[] { "cleanup", "clean" }) || ctx.Match("logclean"))
return ctx.Execute<ServerConfig>(null, m => m.SetLogCleanup(ctx));
if (ctx.MatchMultiple(new[] { "invalid", "unknown" }, new[] { "command" }, new[] { "error", "response" }) || ctx.Match("invalidcommanderror", "unknowncommanderror"))
return ctx.Execute<ServerConfig>(null, m => m.InvalidCommandResponse(ctx));
if (ctx.MatchMultiple(new[] { "require", "enforce" }, new[] { "tag", "systemtag" }) || ctx.Match("requiretag", "enforcetag"))
return ctx.Execute<ServerConfig>(null, m => m.RequireSystemTag(ctx));
// todo: maybe add the list of configuration keys here?
return ctx.Reply($"{Emojis.Error} Could not find a setting with that name. Please see `pk;commands serverconfig` for the list of possible config settings.");
}
}

View file

@ -29,11 +29,13 @@ public class Context
private Command? _currentCommand;
public Context(ILifetimeScope provider, int shardId, Guild? guild, Channel channel, MessageCreateEvent message,
int commandParseOffset, PKSystem senderSystem, SystemConfig config)
int commandParseOffset, PKSystem senderSystem, SystemConfig config,
GuildConfig? guildConfig)
{
Message = (Message)message;
ShardId = shardId;
Guild = guild;
GuildConfig = guildConfig;
Channel = channel;
System = senderSystem;
Config = config;
@ -59,6 +61,7 @@ public class Context
public readonly Message Message;
public readonly Guild Guild;
public readonly GuildConfig? GuildConfig;
public readonly int ShardId;
public readonly Cluster Cluster;

View file

@ -18,6 +18,70 @@ public class ServerConfig
_cache = cache;
}
private record PaginatedConfigItem(string Key, string Description, string? CurrentValue, string DefaultValue);
private string EnabledDisabled(bool value) => value ? "enabled" : "disabled";
public async Task ShowConfig(Context ctx)
{
await ctx.CheckGuildContext().CheckAuthorPermission(PermissionSet.ManageGuild, "Manage Server");
var items = new List<PaginatedConfigItem>();
// TODO: move log channel / blacklist into here
items.Add(new(
"log cleanup",
"Whether to clean up other bots' log channels",
EnabledDisabled(ctx.GuildConfig!.LogCleanupEnabled),
"disabled"
));
items.Add(new(
"invalid command error",
"Whether to show an error message when an unknown command is sent",
EnabledDisabled(ctx.GuildConfig!.InvalidCommandResponseEnabled),
"enabled"
));
items.Add(new(
"require tag",
"Whether server users are required to have a system tag on proxied messages",
EnabledDisabled(ctx.GuildConfig!.RequireSystemTag),
"disabled"
));
await ctx.Paginate<PaginatedConfigItem>(
items.ToAsyncEnumerable(),
items.Count,
10,
"Current settings for this server",
null,
(eb, l) =>
{
var description = new StringBuilder();
foreach (var item in l)
{
description.Append(item.Key.AsCode());
description.Append($" **({item.CurrentValue ?? item.DefaultValue})**");
if (item.CurrentValue != null && item.CurrentValue != item.DefaultValue)
description.Append("\ud83d\udd39");
description.AppendLine();
description.Append(item.Description);
description.AppendLine();
description.AppendLine();
}
eb.Description(description.ToString());
// using *large* blue diamond here since it's easier to see in the small footer
eb.Footer(new("\U0001f537 means this setting was changed. Type `pk;serverconfig <setting name> clear` to reset it to the default."));
return Task.CompletedTask;
}
);
}
public async Task SetLogChannel(Context ctx)
{
await ctx.CheckGuildContext().CheckAuthorPermission(PermissionSet.ManageGuild, "Manage Server");
@ -246,20 +310,16 @@ public class ServerConfig
}
await ctx.CheckGuildContext().CheckAuthorPermission(PermissionSet.ManageGuild, "Manage Server");
var guild = await ctx.Repository.GetGuild(ctx.Guild.Id);
bool? newValue = ctx.MatchToggleOrNull();
if (newValue == null)
{
var guildCfg = await ctx.Repository.GetGuild(ctx.Guild.Id);
if (guildCfg.LogCleanupEnabled)
if (ctx.GuildConfig!.LogCleanupEnabled)
eb.Description(
"Log cleanup is currently **on** for this server. To disable it, type `pk;logclean off`.");
"Log cleanup is currently **on** for this server. To disable it, type `pk;serverconfig logclean off`.");
else
eb.Description(
"Log cleanup is currently **off** for this server. To enable it, type `pk;logclean on`.");
"Log cleanup is currently **off** for this server. To enable it, type `pk;serverconfig logclean on`.");
await ctx.Reply(embed: eb.Build());
return;
}
@ -272,4 +332,36 @@ public class ServerConfig
else
await ctx.Reply($"{Emojis.Success} Log cleanup has been **disabled** for this server.");
}
public async Task InvalidCommandResponse(Context ctx)
{
await ctx.CheckGuildContext().CheckAuthorPermission(PermissionSet.ManageGuild, "Manage Server");
if (!ctx.HasNext())
{
var msg = $"Error responses for unknown/invalid commands are currently **{EnabledDisabled(ctx.GuildConfig!.InvalidCommandResponseEnabled)}**.";
await ctx.Reply(msg);
return;
}
var newVal = ctx.MatchToggle(false);
await ctx.Repository.UpdateGuild(ctx.Guild.Id, new() { InvalidCommandResponseEnabled = newVal });
await ctx.Reply($"Error responses for unknown/invalid commands are now {EnabledDisabled(newVal)}.");
}
public async Task RequireSystemTag(Context ctx)
{
await ctx.CheckGuildContext().CheckAuthorPermission(PermissionSet.ManageGuild, "Manage Server");
if (!ctx.HasNext())
{
var msg = $"System tags are currently **{(ctx.GuildConfig!.RequireSystemTag ? "required" : "not required")}** for PluralKit users in this server.";
await ctx.Reply(msg);
return;
}
var newVal = ctx.MatchToggle(false);
await ctx.Repository.UpdateGuild(ctx.Guild.Id, new() { RequireSystemTag = newVal });
await ctx.Reply($"System tags are now **{(newVal ? "required" : "not required")}** for PluralKit users in this server.");
}
}

View file

@ -129,7 +129,9 @@ public class MessageCreated: IEventHandler<MessageCreateEvent>
{
var system = await _repo.GetSystemByAccount(evt.Author.Id);
var config = system != null ? await _repo.GetSystemConfig(system.Id) : null;
await _tree.ExecuteCommand(new Context(_services, shardId, guild, channel, evt, cmdStart, system, config));
var guildConfig = guild != null ? await _repo.GetGuild(guild.Id) : null;
await _tree.ExecuteCommand(new Context(_services, shardId, guild, channel, evt, cmdStart, system, config, guildConfig));
}
catch (PKError)
{

View file

@ -123,6 +123,15 @@ public class ProxyService
return "PluralKit cannot proxy messages over 2000 characters in length.";
}
if (ctx.RequireSystemTag)
{
var tag = ctx.SystemGuildTag ?? ctx.SystemTag;
if (tag == null)
return "This server requires PluralKit users to have a system tag, but you do not have one set.";
if (!ctx.TagEnabled)
return "This server requires PluralKit users to have a system tag, but your system tag is disabled in this server.";
}
var guild = await _cache.GetGuild(channel.GuildId.Value);
var fileSizeLimit = guild.FileSizeLimit();
var bytesThreshold = fileSizeLimit * 1024 * 1024;