From 479e0a59b55c684793d6b77dc9813a44600aa0f1 Mon Sep 17 00:00:00 2001 From: dusk Date: Wed, 8 Oct 2025 03:26:40 +0000 Subject: [PATCH] remove rest of the parsing in csharp bot --- .../CommandMeta/CommandParseErrors.cs | 29 ++--- PluralKit.Bot/CommandMeta/CommandTree.cs | 66 ++++++------ .../Context/ContextArgumentsExt.cs | 100 ------------------ .../CommandSystem/Context/ContextAvatarExt.cs | 4 - .../Context/ContextEntityArgumentsExt.cs | 22 ---- .../Context/ContextPrivacyExt.cs | 51 --------- PluralKit.Bot/CommandSystem/Parameters.cs | 2 +- PluralKit.Bot/Commands/Admin.cs | 40 +++---- PluralKit.Bot/Commands/Api.cs | 34 +++--- PluralKit.Bot/Commands/Config.cs | 4 +- PluralKit.Bot/Commands/Fun.cs | 26 ++--- PluralKit.Bot/Commands/GroupMember.cs | 8 +- PluralKit.Bot/Commands/Groups.cs | 27 ++--- PluralKit.Bot/Commands/ImportExport.cs | 6 +- .../Commands/Lists/ContextListExt.cs | 6 +- PluralKit.Bot/Commands/Member.cs | 4 +- PluralKit.Bot/Commands/MemberAvatar.cs | 16 +-- PluralKit.Bot/Commands/MemberEdit.cs | 4 +- PluralKit.Bot/Commands/MemberProxy.cs | 18 ++-- PluralKit.Bot/Commands/Message.cs | 4 +- PluralKit.Bot/Commands/Random.cs | 4 +- PluralKit.Bot/Commands/ServerConfig.cs | 4 +- PluralKit.Bot/Commands/Switch.cs | 26 ++--- PluralKit.Bot/Commands/SystemFront.cs | 4 +- PluralKit.Bot/Commands/SystemLink.cs | 4 +- PluralKit.Bot/Services/EmbedService.cs | 8 +- PluralKit.Bot/Utils/ContextUtils.cs | 8 +- crates/command_definitions/src/admin.rs | 10 ++ crates/command_definitions/src/group.rs | 11 +- .../command_definitions/src/import_export.rs | 3 +- crates/command_definitions/src/member.rs | 1 + .../command_definitions/src/server_config.rs | 1 + crates/command_definitions/src/switch.rs | 2 +- crates/command_definitions/src/system.rs | 92 +++++++++------- crates/commands/src/main.rs | 2 +- 35 files changed, 242 insertions(+), 409 deletions(-) delete mode 100644 PluralKit.Bot/CommandSystem/Context/ContextPrivacyExt.cs diff --git a/PluralKit.Bot/CommandMeta/CommandParseErrors.cs b/PluralKit.Bot/CommandMeta/CommandParseErrors.cs index fb415b95..5b54df32 100644 --- a/PluralKit.Bot/CommandMeta/CommandParseErrors.cs +++ b/PluralKit.Bot/CommandMeta/CommandParseErrors.cs @@ -7,28 +7,13 @@ public partial class CommandTree private async Task PrintCommandList(Context ctx, string subject, string commands) { await ctx.Reply( - $"Here is a list of commands related to {subject}:", - embed: new Embed() - { - Description = $"{commands}\nFor a full list of possible commands, see .", - Color = DiscordUtils.Blue, - } + components: [ + new MessageComponent() + { + Type = ComponentType.Text, + Content = $"Here is a list of commands related to {subject}:\n{commands}\nFor a full list of possible commands, see .", + } + ] ); } - - private async Task CreateSystemNotFoundError(Context ctx) - { - var input = ctx.PopArgument(); - if (input.TryParseMention(out var id)) - { - // Try to resolve the user ID to find the associated account, - // so we can print their username. - var user = await ctx.Rest.GetUser(id); - if (user != null) - return $"Account **{user.Username}#{user.Discriminator}** does not have a system registered."; - return $"Account with ID `{id}` not found."; - } - - return $"System with ID {input.AsCode()} not found."; - } } \ No newline at end of file diff --git a/PluralKit.Bot/CommandMeta/CommandTree.cs b/PluralKit.Bot/CommandMeta/CommandTree.cs index e8c3eaa5..72a43288 100644 --- a/PluralKit.Bot/CommandMeta/CommandTree.cs +++ b/PluralKit.Bot/CommandMeta/CommandTree.cs @@ -22,13 +22,13 @@ public partial class CommandTree Commands.MemberNew(var param, _) => ctx.Execute(MemberNew, m => m.NewMember(ctx, param.name)), Commands.MemberSoulscream(var param, _) => ctx.Execute(MemberInfo, m => m.Soulscream(ctx, param.target)), Commands.MemberAvatarShow(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ShowAvatar(ctx, param.target, flags.GetReplyFormat())), - Commands.MemberAvatarClear(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ClearAvatar(ctx, param.target)), + Commands.MemberAvatarClear(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ClearAvatar(ctx, param.target, flags.yes)), Commands.MemberAvatarUpdate(var param, _) => ctx.Execute(MemberAvatar, m => m.ChangeAvatar(ctx, param.target, param.avatar)), Commands.MemberWebhookAvatarShow(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ShowWebhookAvatar(ctx, param.target, flags.GetReplyFormat())), - Commands.MemberWebhookAvatarClear(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ClearWebhookAvatar(ctx, param.target)), + Commands.MemberWebhookAvatarClear(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ClearWebhookAvatar(ctx, param.target, flags.yes)), Commands.MemberWebhookAvatarUpdate(var param, _) => ctx.Execute(MemberAvatar, m => m.ChangeWebhookAvatar(ctx, param.target, param.avatar)), Commands.MemberServerAvatarShow(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ShowServerAvatar(ctx, param.target, flags.GetReplyFormat())), - Commands.MemberServerAvatarClear(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ClearServerAvatar(ctx, param.target)), + Commands.MemberServerAvatarClear(var param, var flags) => ctx.Execute(MemberAvatar, m => m.ClearServerAvatar(ctx, param.target, flags.yes)), Commands.MemberServerAvatarUpdate(var param, _) => ctx.Execute(MemberAvatar, m => m.ChangeServerAvatar(ctx, param.target, param.avatar)), Commands.MemberPronounsShow(var param, var flags) => ctx.Execute(MemberPronouns, m => m.ShowPronouns(ctx, param.target, flags.GetReplyFormat())), Commands.MemberPronounsClear(var param, var flags) => ctx.Execute(MemberPronouns, m => m.ClearPronouns(ctx, param.target, flags.yes)), @@ -37,7 +37,7 @@ public partial class CommandTree Commands.MemberDescClear(var param, var flags) => ctx.Execute(MemberDesc, m => m.ClearDescription(ctx, param.target, flags.yes)), Commands.MemberDescUpdate(var param, _) => ctx.Execute(MemberDesc, m => m.ChangeDescription(ctx, param.target, param.description)), Commands.MemberNameShow(var param, var flags) => ctx.Execute(MemberInfo, m => m.ShowName(ctx, param.target, flags.GetReplyFormat())), - Commands.MemberNameUpdate(var param, _) => ctx.Execute(MemberInfo, m => m.ChangeName(ctx, param.target, param.name)), + Commands.MemberNameUpdate(var param, var flags) => ctx.Execute(MemberInfo, m => m.ChangeName(ctx, param.target, param.name, flags.yes)), Commands.MemberBannerShow(var param, var flags) => ctx.Execute(MemberBannerImage, m => m.ShowBannerImage(ctx, param.target, flags.GetReplyFormat())), Commands.MemberBannerClear(var param, var flags) => ctx.Execute(MemberBannerImage, m => m.ClearBannerImage(ctx, param.target, flags.yes)), Commands.MemberBannerUpdate(var param, _) => ctx.Execute(MemberBannerImage, m => m.ChangeBannerImage(ctx, param.target, param.banner)), @@ -59,7 +59,7 @@ public partial class CommandTree Commands.MemberServerKeepproxyUpdate(var param, _) => ctx.Execute(MemberServerKeepProxy, m => m.ChangeServerKeepProxy(ctx, param.target, param.value)), Commands.MemberServerKeepproxyClear(var param, var flags) => ctx.Execute(MemberServerKeepProxy, m => m.ClearServerKeepProxy(ctx, param.target, flags.yes)), Commands.MemberProxyShow(var param, _) => ctx.Execute(MemberProxy, m => m.ShowProxy(ctx, param.target)), - Commands.MemberProxyClear(var param, var flags) => ctx.Execute(MemberProxy, m => m.ClearProxy(ctx, param.target)), + Commands.MemberProxyClear(var param, var flags) => ctx.Execute(MemberProxy, m => m.ClearProxy(ctx, param.target, flags.yes)), Commands.MemberProxyAdd(var param, _) => ctx.Execute(MemberProxy, m => m.AddProxy(ctx, param.target, param.tag)), Commands.MemberProxyRemove(var param, _) => ctx.Execute(MemberProxy, m => m.RemoveProxy(ctx, param.target, param.tag)), Commands.MemberProxySet(var param, _) => ctx.Execute(MemberProxy, m => m.SetProxy(ctx, param.target, param.tags)), @@ -205,7 +205,7 @@ public partial class CommandTree Commands.SwitchDo(var param, _) => ctx.Execute(Switch, m => m.SwitchDo(ctx, param.targets)), Commands.SwitchMove(var param, _) => ctx.Execute(SwitchMove, m => m.SwitchMove(ctx, param.@string)), Commands.SwitchEdit(var param, var flags) => ctx.Execute(SwitchEdit, m => m.SwitchEdit(ctx, param.targets, false, flags.first, flags.remove, flags.append, flags.prepend)), - Commands.SwitchEditOut(_, _) => ctx.Execute(SwitchEditOut, m => m.SwitchEditOut(ctx)), + Commands.SwitchEditOut(_, var flags) => ctx.Execute(SwitchEditOut, m => m.SwitchEditOut(ctx, flags.yes)), Commands.SwitchDelete(var param, var flags) => ctx.Execute(SwitchDelete, m => m.SwitchDelete(ctx, flags.all)), Commands.SwitchCopy(var param, var flags) => ctx.Execute(SwitchCopy, m => m.SwitchEdit(ctx, param.targets, true, flags.first, flags.remove, flags.append, flags.prepend)), Commands.SystemFronter(var param, var flags) => ctx.Execute(SystemFronter, m => m.Fronter(ctx, param.target)), @@ -213,7 +213,9 @@ public partial class CommandTree Commands.SystemFronterPercent(var param, var flags) => ctx.Execute(SystemFrontPercent, m => m.FrontPercent(ctx, param.target, flags.duration, flags.fronters_only, flags.flat)), Commands.SystemDisplayId(var param, _) => ctx.Execute(SystemId, m => m.DisplayId(ctx, param.target)), Commands.SystemDisplayIdSelf => ctx.Execute(SystemId, m => m.DisplayId(ctx, ctx.System)), - Commands.SystemWebhook => ctx.Execute(null, m => m.SystemWebhook(ctx)), + Commands.SystemWebhookShow => ctx.Execute(null, m => m.GetSystemWebhook(ctx)), + Commands.SystemWebhookClear(_, var flags) => ctx.Execute(null, m => m.ClearSystemWebhook(ctx, flags.yes)), + Commands.SystemWebhookSet(var param, _) => ctx.Execute(null, m => m.SetSystemWebhook(ctx, param.url)), Commands.RandomSelf(_, var flags) => flags.group ? ctx.Execute(GroupRandom, m => m.Group(ctx, ctx.System, flags.all, flags.show_embed)) @@ -224,21 +226,21 @@ public partial class CommandTree : ctx.Execute(MemberRandom, m => m.Member(ctx, param.target, flags.all, flags.show_embed)), Commands.GroupRandomMember(var param, var flags) => ctx.Execute(GroupMemberRandom, m => m.GroupMember(ctx, param.target, flags)), Commands.SystemLink(var param, _) => ctx.Execute(Link, m => m.LinkSystem(ctx, param.account)), - Commands.SystemUnlink(var param, _) => ctx.Execute(Unlink, m => m.UnlinkAccount(ctx, param.account)), + Commands.SystemUnlink(var param, var flags) => ctx.Execute(Unlink, m => m.UnlinkAccount(ctx, param.account, flags.yes)), Commands.SystemMembersListSelf(var param, var flags) => ctx.Execute(SystemList, m => m.MemberList(ctx, ctx.System, null, flags)), Commands.SystemMembersSearchSelf(var param, var flags) => ctx.Execute(SystemFind, m => m.MemberList(ctx, ctx.System, param.query, flags)), Commands.SystemMembersList(var param, var flags) => ctx.Execute(SystemList, m => m.MemberList(ctx, param.target, null, flags)), Commands.SystemMembersSearch(var param, var flags) => ctx.Execute(SystemFind, m => m.MemberList(ctx, param.target, param.query, flags)), - Commands.MemberListGroups(var param, var flags) => ctx.Execute(MemberGroups, m => m.ListMemberGroups(ctx, param.target, null, flags)), - Commands.MemberSearchGroups(var param, var flags) => ctx.Execute(MemberGroups, m => m.ListMemberGroups(ctx, param.target, param.query, flags)), + Commands.MemberListGroups(var param, var flags) => ctx.Execute(MemberGroups, m => m.ListMemberGroups(ctx, param.target, null, flags, flags.all)), + Commands.MemberSearchGroups(var param, var flags) => ctx.Execute(MemberGroups, m => m.ListMemberGroups(ctx, param.target, param.query, flags, flags.all)), Commands.GroupListMembers(var param, var flags) => ctx.Execute(GroupMemberList, m => m.ListGroupMembers(ctx, param.target, null, flags)), Commands.GroupSearchMembers(var param, var flags) => ctx.Execute(GroupMemberList, m => m.ListGroupMembers(ctx, param.target, param.query, flags)), - Commands.SystemListGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, param.target, null, flags)), - Commands.SystemSearchGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, param.target, param.query, flags)), - Commands.GroupListGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, ctx.System, null, flags)), - Commands.GroupSearchGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, ctx.System, param.query, flags)), + Commands.SystemListGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, param.target, null, flags, flags.all)), + Commands.SystemSearchGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, param.target, param.query, flags, flags.all)), + Commands.GroupListGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, ctx.System, null, flags, flags.all)), + Commands.GroupSearchGroups(var param, var flags) => ctx.Execute(GroupList, g => g.ListSystemGroups(ctx, ctx.System, param.query, flags, flags.all)), Commands.GroupNew(var param, _) => ctx.Execute(GroupNew, g => g.CreateGroup(ctx, param.name)), - Commands.GroupInfo(var param, _) => ctx.Execute(GroupInfo, g => g.ShowGroupCard(ctx, param.target)), + Commands.GroupInfo(var param, var flags) => ctx.Execute(GroupInfo, g => g.ShowGroupCard(ctx, param.target, flags.show_embed, flags.all)), Commands.GroupShowName(var param, var flags) => ctx.Execute(GroupRename, g => g.ShowGroupDisplayName(ctx, param.target, flags.GetReplyFormat())), Commands.GroupClearName(var param, var flags) => ctx.Execute(GroupRename, g => g.RenameGroup(ctx, param.target, null)), Commands.GroupRename(var param, _) => ctx.Execute(GroupRename, g => g.RenameGroup(ctx, param.target, param.name)), @@ -249,16 +251,16 @@ public partial class CommandTree Commands.GroupClearDescription(var param, var flags) => ctx.Execute(GroupDesc, g => g.ClearGroupDescription(ctx, param.target)), Commands.GroupChangeDescription(var param, _) => ctx.Execute(GroupDesc, g => g.ChangeGroupDescription(ctx, param.target, param.description)), Commands.GroupShowIcon(var param, var flags) => ctx.Execute(GroupIcon, g => g.ShowGroupIcon(ctx, param.target, flags.GetReplyFormat())), - Commands.GroupClearIcon(var param, var flags) => ctx.Execute(GroupIcon, g => g.ClearGroupIcon(ctx, param.target)), + Commands.GroupClearIcon(var param, var flags) => ctx.Execute(GroupIcon, g => g.ClearGroupIcon(ctx, param.target, flags.yes)), Commands.GroupChangeIcon(var param, _) => ctx.Execute(GroupIcon, g => g.ChangeGroupIcon(ctx, param.target, param.icon)), Commands.GroupShowBanner(var param, var flags) => ctx.Execute(GroupBannerImage, g => g.ShowGroupBanner(ctx, param.target, flags.GetReplyFormat())), - Commands.GroupClearBanner(var param, var flags) => ctx.Execute(GroupBannerImage, g => g.ClearGroupBanner(ctx, param.target)), + Commands.GroupClearBanner(var param, var flags) => ctx.Execute(GroupBannerImage, g => g.ClearGroupBanner(ctx, param.target, flags.yes)), Commands.GroupChangeBanner(var param, _) => ctx.Execute(GroupBannerImage, g => g.ChangeGroupBanner(ctx, param.target, param.banner)), Commands.GroupShowColor(var param, var flags) => ctx.Execute(GroupColor, g => g.ShowGroupColor(ctx, param.target, flags.GetReplyFormat())), Commands.GroupClearColor(var param, var flags) => ctx.Execute(GroupColor, g => g.ClearGroupColor(ctx, param.target)), Commands.GroupChangeColor(var param, _) => ctx.Execute(GroupColor, g => g.ChangeGroupColor(ctx, param.target, param.color)), - Commands.GroupAddMember(var param, var flags) => ctx.Execute(GroupAdd, g => g.AddRemoveMembers(ctx, param.target, param.targets, Groups.AddRemoveOperation.Add, flags.all)), - Commands.GroupRemoveMember(var param, var flags) => ctx.Execute(GroupRemove, g => g.AddRemoveMembers(ctx, param.target, param.targets, Groups.AddRemoveOperation.Remove, flags.all)), + Commands.GroupAddMember(var param, var flags) => ctx.Execute(GroupAdd, g => g.AddRemoveMembers(ctx, param.target, param.targets, Groups.AddRemoveOperation.Add, flags.all, flags.yes)), + Commands.GroupRemoveMember(var param, var flags) => ctx.Execute(GroupRemove, g => g.AddRemoveMembers(ctx, param.target, param.targets, Groups.AddRemoveOperation.Remove, flags.all, flags.yes)), Commands.GroupShowPrivacy(var param, _) => ctx.Execute(GroupPrivacy, g => g.ShowGroupPrivacy(ctx, param.target)), Commands.GroupChangePrivacyAll(var param, _) => ctx.Execute(GroupPrivacy, g => g.SetAllGroupPrivacy(ctx, param.target, param.level)), Commands.GroupChangePrivacy(var param, _) => ctx.Execute(GroupPrivacy, g => g.SetGroupPrivacy(ctx, param.target, param.privacy, param.level)), @@ -282,12 +284,12 @@ public partial class CommandTree Commands.MessageDelete(var param, var flags) => ctx.Execute(Message, m => m.GetMessage(ctx, param.target.MessageId, flags.GetReplyFormat(), true, false)), Commands.MessageEdit(var param, var flags) => ctx.Execute(MessageEdit, m => m.EditMessage(ctx, param.target.MessageId, param.new_content, flags.regex, flags.mutate_space, flags.append, flags.prepend, flags.clear_embeds, flags.clear_attachments)), Commands.MessageReproxy(var param, _) => ctx.Execute(MessageReproxy, m => m.ReproxyMessage(ctx, param.msg.MessageId, param.member)), - Commands.Import(var param, _) => ctx.Execute(Import, m => m.Import(ctx, param.url)), + Commands.Import(var param, var flags) => ctx.Execute(Import, m => m.Import(ctx, param.url, flags.yes)), Commands.Export(_, _) => ctx.Execute(Export, m => m.Export(ctx)), Commands.ServerConfigShow => ctx.Execute(null, m => m.ShowConfig(ctx)), Commands.ServerConfigLogChannelShow => ctx.Execute(null, m => m.ShowLogChannel(ctx)), Commands.ServerConfigLogChannelSet(var param, _) => ctx.Execute(null, m => m.SetLogChannel(ctx, param.channel)), - Commands.ServerConfigLogChannelClear => ctx.Execute(null, m => m.ClearLogChannel(ctx)), + Commands.ServerConfigLogChannelClear(_, var flags) => ctx.Execute(null, m => m.ClearLogChannel(ctx, flags.yes)), Commands.ServerConfigLogCleanupShow => ctx.Execute(null, m => m.ShowLogCleanup(ctx)), Commands.ServerConfigLogCleanupSet(var param, _) => ctx.Execute(null, m => m.SetLogCleanup(ctx, param.toggle)), Commands.ServerConfigLogBlacklistShow => ctx.Execute(null, m => m.ShowLogBlacklist(ctx)), @@ -302,27 +304,27 @@ public partial class CommandTree Commands.ServerConfigRequireSystemTagSet(var param, _) => ctx.Execute(null, m => m.SetRequireSystemTag(ctx, param.toggle)), Commands.ServerConfigSuppressNotificationsShow => ctx.Execute(null, m => m.ShowSuppressNotifications(ctx)), Commands.ServerConfigSuppressNotificationsSet(var param, _) => ctx.Execute(null, m => m.SetSuppressNotifications(ctx, param.toggle)), - Commands.AdminUpdateSystemId(var param, _) => ctx.Execute(null, m => m.UpdateSystemId(ctx, param.target, param.new_hid)), - Commands.AdminUpdateMemberId(var param, _) => ctx.Execute(null, m => m.UpdateMemberId(ctx, param.target, param.new_hid)), - Commands.AdminUpdateGroupId(var param, _) => ctx.Execute(null, m => m.UpdateGroupId(ctx, param.target, param.new_hid)), - Commands.AdminRerollSystemId(var param, _) => ctx.Execute(null, m => m.RerollSystemId(ctx, param.target)), - Commands.AdminRerollMemberId(var param, _) => ctx.Execute(null, m => m.RerollMemberId(ctx, param.target)), - Commands.AdminRerollGroupId(var param, _) => ctx.Execute(null, m => m.RerollGroupId(ctx, param.target)), - Commands.AdminSystemMemberLimit(var param, _) => ctx.Execute(null, m => m.SystemMemberLimit(ctx, param.target, param.limit)), - Commands.AdminSystemGroupLimit(var param, _) => ctx.Execute(null, m => m.SystemGroupLimit(ctx, param.target, param.limit)), - Commands.AdminSystemRecover(var param, var flags) => ctx.Execute(null, m => m.SystemRecover(ctx, param.token, param.account, flags.reroll_token)), + Commands.AdminUpdateSystemId(var param, var flags) => ctx.Execute(null, m => m.UpdateSystemId(ctx, param.target, param.new_hid, flags.yes)), + Commands.AdminUpdateMemberId(var param, var flags) => ctx.Execute(null, m => m.UpdateMemberId(ctx, param.target, param.new_hid, flags.yes)), + Commands.AdminUpdateGroupId(var param, var flags) => ctx.Execute(null, m => m.UpdateGroupId(ctx, param.target, param.new_hid, flags.yes)), + Commands.AdminRerollSystemId(var param, var flags) => ctx.Execute(null, m => m.RerollSystemId(ctx, param.target, flags.yes)), + Commands.AdminRerollMemberId(var param, var flags) => ctx.Execute(null, m => m.RerollMemberId(ctx, param.target, flags.yes)), + Commands.AdminRerollGroupId(var param, var flags) => ctx.Execute(null, m => m.RerollGroupId(ctx, param.target, flags.yes)), + Commands.AdminSystemMemberLimit(var param, var flags) => ctx.Execute(null, m => m.SystemMemberLimit(ctx, param.target, param.limit, flags.yes)), + Commands.AdminSystemGroupLimit(var param, var flags) => ctx.Execute(null, m => m.SystemGroupLimit(ctx, param.target, param.limit, flags.yes)), + Commands.AdminSystemRecover(var param, var flags) => ctx.Execute(null, m => m.SystemRecover(ctx, param.token, param.account, flags.reroll_token, flags.yes)), Commands.AdminSystemDelete(var param, _) => ctx.Execute(null, m => m.SystemDelete(ctx, param.target)), Commands.AdminSendMessage(var param, _) => ctx.Execute(null, m => m.SendAdminMessage(ctx, param.account, param.content)), Commands.AdminAbuselogCreate(var param, var flags) => ctx.Execute(null, m => m.AbuseLogCreate(ctx, param.account, flags.deny_boy_usage, param.description)), Commands.AdminAbuselogShowAccount(var param, _) => ctx.Execute(null, m => m.AbuseLogShow(ctx, param.account, null)), Commands.AdminAbuselogFlagDenyAccount(var param, _) => ctx.Execute(null, m => m.AbuseLogFlagDeny(ctx, param.account, null, param.value)), - Commands.AdminAbuselogDescriptionAccount(var param, var flags) => ctx.Execute(null, m => m.AbuseLogDescription(ctx, param.account, null, param.desc, flags.clear)), + Commands.AdminAbuselogDescriptionAccount(var param, var flags) => ctx.Execute(null, m => m.AbuseLogDescription(ctx, param.account, null, param.desc, flags.clear, flags.yes)), Commands.AdminAbuselogAddUserAccount(var param, _) => ctx.Execute(null, m => m.AbuseLogAddUser(ctx, param.account, null, ctx.Author)), Commands.AdminAbuselogRemoveUserAccount(var param, _) => ctx.Execute(null, m => m.AbuseLogRemoveUser(ctx, param.account, null, ctx.Author)), Commands.AdminAbuselogDeleteAccount(var param, _) => ctx.Execute(null, m => m.AbuseLogDelete(ctx, param.account, null)), Commands.AdminAbuselogShowLogId(var param, _) => ctx.Execute(null, m => m.AbuseLogShow(ctx, null, param.log_id)), Commands.AdminAbuselogFlagDenyLogId(var param, _) => ctx.Execute(null, m => m.AbuseLogFlagDeny(ctx, null, param.log_id, param.value)), - Commands.AdminAbuselogDescriptionLogId(var param, var flags) => ctx.Execute(null, m => m.AbuseLogDescription(ctx, null, param.log_id, param.desc, flags.clear)), + Commands.AdminAbuselogDescriptionLogId(var param, var flags) => ctx.Execute(null, m => m.AbuseLogDescription(ctx, null, param.log_id, param.desc, flags.clear, flags.yes)), Commands.AdminAbuselogAddUserLogId(var param, _) => ctx.Execute(null, m => m.AbuseLogAddUser(ctx, null, param.log_id, ctx.Author)), Commands.AdminAbuselogRemoveUserLogId(var param, _) => ctx.Execute(null, m => m.AbuseLogRemoveUser(ctx, null, param.log_id, ctx.Author)), Commands.AdminAbuselogDeleteLogId(var param, _) => ctx.Execute(null, m => m.AbuseLogDelete(ctx, null, param.log_id)), diff --git a/PluralKit.Bot/CommandSystem/Context/ContextArgumentsExt.cs b/PluralKit.Bot/CommandSystem/Context/ContextArgumentsExt.cs index 48006cbb..730b4e8d 100644 --- a/PluralKit.Bot/CommandSystem/Context/ContextArgumentsExt.cs +++ b/PluralKit.Bot/CommandSystem/Context/ContextArgumentsExt.cs @@ -2,110 +2,10 @@ using System.Text.RegularExpressions; using Myriad.Types; -using PluralKit.Core; - namespace PluralKit.Bot; public static class ContextArgumentsExt { - public static string PopArgument(this Context ctx) => throw new PKError("todo: PopArgument"); - - public static string PeekArgument(this Context ctx) => throw new PKError("todo: PeekArgument"); - - public static string RemainderOrNull(this Context ctx, bool skipFlags = true) => throw new PKError("todo: RemainderOrNull"); - - public static bool HasNext(this Context ctx, bool skipFlags = true) => throw new PKError("todo: HasNext"); - - public static string FullCommand(this Context ctx) => throw new PKError("todo: FullCommand"); - - /// - /// Checks if the next parameter is equal to one of the given keywords and pops it from the stack. Case-insensitive. - /// - public static bool Match(this Context ctx, ref string used, params string[] potentialMatches) - { - var arg = ctx.PeekArgument(); - foreach (var match in potentialMatches) - if (arg.Equals(match, StringComparison.InvariantCultureIgnoreCase)) - { - used = ctx.PopArgument(); - return true; - } - - return false; - } - - /// - /// Checks if the next parameter is equal to one of the given keywords. Case-insensitive. - /// - public static bool Match(this Context ctx, params string[] potentialMatches) - { - string used = null; // Unused and unreturned, we just yeet it - return ctx.Match(ref used, potentialMatches); - } - - /// - /// Checks if the next parameter (starting from `ptr`) is equal to one of the given keywords, and leaves it on the stack. Case-insensitive. - /// - public static bool PeekMatch(this Context ctx, ref int ptr, string[] potentialMatches) - { - throw new PKError("todo: PeekMatch"); - } - - /// - /// Matches the next *n* parameters against each parameter consecutively. - ///
- /// Note that this is handled differently than single-parameter Match: - /// each method parameter is an array of potential matches for the *n*th command string parameter. - ///
- public static bool MatchMultiple(this Context ctx, params string[][] potentialParametersMatches) - { - throw new PKError("todo: MatchMultiple"); - } - - public static bool MatchFlag(this Context ctx, params string[] potentialMatches) - { - // Flags are *ALWAYS PARSED LOWERCASE*. This means we skip out on a "ToLower" call here. - // Can assume the caller array only contains lowercase *and* the set below only contains lowercase - throw new NotImplementedException(); - } - - public static bool MatchClear(this Context ctx) - => ctx.Match("clear", "reset", "default") || ctx.MatchFlag("c", "clear"); - - public static ReplyFormat MatchFormat(this Context ctx) - { - if (ctx.Match("r", "raw") || ctx.MatchFlag("r", "raw")) return ReplyFormat.Raw; - if (ctx.Match("pt", "plaintext") || ctx.MatchFlag("pt", "plaintext")) return ReplyFormat.Plaintext; - return ReplyFormat.Standard; - } - - public static ReplyFormat PeekMatchFormat(this Context ctx) - { - throw new PKError("todo: PeekMatchFormat"); - } - - public static bool MatchToggle(this Context ctx, bool? defaultValue = null) - { - var value = ctx.MatchToggleOrNull(defaultValue); - if (value == null) throw new PKError("You must pass either \"on\" or \"off\" to this command."); - return value.Value; - } - - public static bool? MatchToggleOrNull(this Context ctx, bool? defaultValue = null) - { - if (defaultValue != null && ctx.MatchClear()) - return defaultValue.Value; - - var yesToggles = new[] { "yes", "on", "enable", "enabled", "true" }; - var noToggles = new[] { "no", "off", "disable", "disabled", "false" }; - - if (ctx.Match(yesToggles) || ctx.MatchFlag(yesToggles)) - return true; - else if (ctx.Match(noToggles) || ctx.MatchFlag(noToggles)) - return false; - else return null; - } - public static (ulong? messageId, ulong? channelId) GetRepliedTo(this Context ctx) { if (ctx.Message.Type == Message.MessageType.Reply && ctx.Message.MessageReference?.MessageId != null) diff --git a/PluralKit.Bot/CommandSystem/Context/ContextAvatarExt.cs b/PluralKit.Bot/CommandSystem/Context/ContextAvatarExt.cs index 0c99c94f..21d24c4f 100644 --- a/PluralKit.Bot/CommandSystem/Context/ContextAvatarExt.cs +++ b/PluralKit.Bot/CommandSystem/Context/ContextAvatarExt.cs @@ -48,10 +48,6 @@ public static class ContextAvatarExt // ToString URL-decodes, which breaks URLs to spaces; AbsoluteUri doesn't return new ParsedImage { Url = uri.AbsoluteUri, Source = AvatarSource.Url }; } - public static async Task MatchImage(this Context ctx) - { - throw new NotImplementedException(); - } } public struct ParsedImage diff --git a/PluralKit.Bot/CommandSystem/Context/ContextEntityArgumentsExt.cs b/PluralKit.Bot/CommandSystem/Context/ContextEntityArgumentsExt.cs index 627c1185..5c429c96 100644 --- a/PluralKit.Bot/CommandSystem/Context/ContextEntityArgumentsExt.cs +++ b/PluralKit.Bot/CommandSystem/Context/ContextEntityArgumentsExt.cs @@ -1,9 +1,6 @@ -using System.Text.RegularExpressions; - using Myriad.Extensions; using Myriad.Types; -using PluralKit.Bot.Utils; using PluralKit.Core; namespace PluralKit.Bot; @@ -120,23 +117,4 @@ public static class ContextEntityArgumentsExt return $"{entity} with ID or name \"{input}\" not found."; return $"{entity} with name \"{input}\" not found. Note that a {entity.ToLower()} ID is 5 or 6 characters long."; } - - public static async Task MatchChannel(this Context ctx) - { - if (!MentionUtils.TryParseChannel(ctx.PeekArgument(), out var id)) - return null; - - // todo: match channels in other guilds - var channel = await ctx.Cache.TryGetChannel(ctx.Guild!.Id, id); - if (channel == null) - channel = await ctx.Rest.GetChannelOrNull(id); - if (channel == null) - return null; - - if (!DiscordUtils.IsValidGuildChannel(channel)) - return null; - - ctx.PopArgument(); - return channel; - } } \ No newline at end of file diff --git a/PluralKit.Bot/CommandSystem/Context/ContextPrivacyExt.cs b/PluralKit.Bot/CommandSystem/Context/ContextPrivacyExt.cs deleted file mode 100644 index 2f120f8a..00000000 --- a/PluralKit.Bot/CommandSystem/Context/ContextPrivacyExt.cs +++ /dev/null @@ -1,51 +0,0 @@ -using PluralKit.Core; - -namespace PluralKit.Bot; - -public static class ContextPrivacyExt -{ - public static PrivacyLevel PopPrivacyLevel(this Context ctx) - { - if (ctx.Match("public", "pub", "show", "shown", "visible", "unhide", "unhidden")) - return PrivacyLevel.Public; - - if (ctx.Match("private", "priv", "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().AsCode()} (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().AsCode()} (must be `description`, `members`, `front`, `fronthistory`, `groups`, 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().AsCode()} (must be `name`, `description`, `avatar`, `birthday`, `pronouns`, `proxy`, `metadata`, `visibility`, or `all`)."); - - ctx.PopArgument(); - return subject; - } - - public static GroupPrivacySubject PopGroupPrivacySubject(this Context ctx) - { - if (!GroupPrivacyUtils.TryParseGroupPrivacy(ctx.PeekArgument(), out var subject)) - throw new PKSyntaxError( - $"Invalid privacy subject {ctx.PopArgument().AsCode()} (must be `name`, `description`, `icon`, `metadata`, `visibility`, or `all`)."); - - ctx.PopArgument(); - return subject; - } -} \ No newline at end of file diff --git a/PluralKit.Bot/CommandSystem/Parameters.cs b/PluralKit.Bot/CommandSystem/Parameters.cs index 1add6fe2..0278f661 100644 --- a/PluralKit.Bot/CommandSystem/Parameters.cs +++ b/PluralKit.Bot/CommandSystem/Parameters.cs @@ -72,7 +72,7 @@ public class Parameters private async Task ResolveFfiParam(Context ctx, uniffi.commands.Parameter ffi_param) { - var byId = HasFlag("id", "by-id"); + var byId = HasFlag("id", "by-id"); // this is added as a hidden flag to all command definitions switch (ffi_param) { case uniffi.commands.Parameter.MemberRef memberRef: diff --git a/PluralKit.Bot/Commands/Admin.cs b/PluralKit.Bot/Commands/Admin.cs index e65e6bc1..7726466b 100644 --- a/PluralKit.Bot/Commands/Admin.cs +++ b/PluralKit.Bot/Commands/Admin.cs @@ -111,7 +111,7 @@ public class Admin return eb.Build(); } - public async Task UpdateSystemId(Context ctx, PKSystem target, string newHid) + public async Task UpdateSystemId(Context ctx, PKSystem target, string newHid, bool confirmYes) { ctx.AssertBotAdmin(); @@ -121,14 +121,14 @@ public class Admin await ctx.Reply(null, await CreateEmbed(ctx, target)); - if (!await ctx.PromptYesNo($"Change system ID of `{target.Hid}` to `{newHid}`?", "Change")) + if (!await ctx.PromptYesNo($"Change system ID of `{target.Hid}` to `{newHid}`?", "Change", flagValue: confirmYes)) throw new PKError("ID change cancelled."); await ctx.Repository.UpdateSystem(target.Id, new SystemPatch { Hid = newHid }); await ctx.Reply($"{Emojis.Success} System ID updated (`{target.Hid}` -> `{newHid}`)."); } - public async Task UpdateMemberId(Context ctx, PKMember target, string newHid) + public async Task UpdateMemberId(Context ctx, PKMember target, string newHid, bool confirmYes) { ctx.AssertBotAdmin(); @@ -141,7 +141,7 @@ public class Admin if (!await ctx.PromptYesNo( $"Change member ID of **{target.NameFor(LookupContext.ByNonOwner)}** (`{target.Hid}`) to `{newHid}`?", - "Change" + "Change", flagValue: confirmYes )) throw new PKError("ID change cancelled."); @@ -149,7 +149,7 @@ public class Admin await ctx.Reply($"{Emojis.Success} Member ID updated (`{target.Hid}` -> `{newHid}`)."); } - public async Task UpdateGroupId(Context ctx, PKGroup target, string newHid) + public async Task UpdateGroupId(Context ctx, PKGroup target, string newHid, bool confirmYes) { ctx.AssertBotAdmin(); @@ -161,7 +161,7 @@ public class Admin await ctx.Reply(null, await CreateEmbed(ctx, system)); if (!await ctx.PromptYesNo($"Change group ID of **{target.Name}** (`{target.Hid}`) to `{newHid}`?", - "Change" + "Change", flagValue: confirmYes )) throw new PKError("ID change cancelled."); @@ -169,13 +169,13 @@ public class Admin await ctx.Reply($"{Emojis.Success} Group ID updated (`{target.Hid}` -> `{newHid}`)."); } - public async Task RerollSystemId(Context ctx, PKSystem target) + public async Task RerollSystemId(Context ctx, PKSystem target, bool confirmYes) { ctx.AssertBotAdmin(); await ctx.Reply(null, await CreateEmbed(ctx, target)); - if (!await ctx.PromptYesNo($"Reroll system ID `{target.Hid}`?", "Reroll")) + if (!await ctx.PromptYesNo($"Reroll system ID `{target.Hid}`?", "Reroll", flagValue: confirmYes)) throw new PKError("ID change cancelled."); var query = new Query("systems").AsUpdate(new @@ -188,7 +188,7 @@ public class Admin await ctx.Reply($"{Emojis.Success} System ID updated (`{target.Hid}` -> `{newHid}`)."); } - public async Task RerollMemberId(Context ctx, PKMember target) + public async Task RerollMemberId(Context ctx, PKMember target, bool confirmYes) { ctx.AssertBotAdmin(); @@ -197,7 +197,7 @@ public class Admin if (!await ctx.PromptYesNo( $"Reroll member ID for **{target.NameFor(LookupContext.ByNonOwner)}** (`{target.Hid}`)?", - "Reroll" + "Reroll", flagValue: confirmYes )) throw new PKError("ID change cancelled."); @@ -211,7 +211,7 @@ public class Admin await ctx.Reply($"{Emojis.Success} Member ID updated (`{target.Hid}` -> `{newHid}`)."); } - public async Task RerollGroupId(Context ctx, PKGroup target) + public async Task RerollGroupId(Context ctx, PKGroup target, bool confirmYes) { ctx.AssertBotAdmin(); @@ -219,7 +219,7 @@ public class Admin await ctx.Reply(null, await CreateEmbed(ctx, system)); if (!await ctx.PromptYesNo($"Reroll group ID for **{target.Name}** (`{target.Hid}`)?", - "Change" + "Change", flagValue: confirmYes )) throw new PKError("ID change cancelled."); @@ -233,7 +233,7 @@ public class Admin await ctx.Reply($"{Emojis.Success} Group ID updated (`{target.Hid}` -> `{newHid}`)."); } - public async Task SystemMemberLimit(Context ctx, PKSystem target, int? newLimit) + public async Task SystemMemberLimit(Context ctx, PKSystem target, int? newLimit, bool confirmYes) { ctx.AssertBotAdmin(); @@ -247,14 +247,14 @@ public class Admin } await ctx.Reply(null, await CreateEmbed(ctx, target)); - if (!await ctx.PromptYesNo($"Update member limit from **{currentLimit}** to **{newLimit}**?", "Update")) + if (!await ctx.PromptYesNo($"Update member limit from **{currentLimit}** to **{newLimit}**?", "Update", flagValue: confirmYes)) throw new PKError("Member limit change cancelled."); await ctx.Repository.UpdateSystemConfig(target.Id, new SystemConfigPatch { MemberLimitOverride = newLimit }); await ctx.Reply($"{Emojis.Success} Member limit updated."); } - public async Task SystemGroupLimit(Context ctx, PKSystem target, int? newLimit) + public async Task SystemGroupLimit(Context ctx, PKSystem target, int? newLimit, bool confirmYes) { ctx.AssertBotAdmin(); @@ -268,14 +268,14 @@ public class Admin } await ctx.Reply(null, await CreateEmbed(ctx, target)); - if (!await ctx.PromptYesNo($"Update group limit from **{currentLimit}** to **{newLimit}**?", "Update")) + if (!await ctx.PromptYesNo($"Update group limit from **{currentLimit}** to **{newLimit}**?", "Update", flagValue: confirmYes)) throw new PKError("Group limit change cancelled."); await ctx.Repository.UpdateSystemConfig(target.Id, new SystemConfigPatch { GroupLimitOverride = newLimit }); await ctx.Reply($"{Emojis.Success} Group limit updated."); } - public async Task SystemRecover(Context ctx, string systemToken, User account, bool rerollToken) + public async Task SystemRecover(Context ctx, string systemToken, User account, bool rerollToken, bool confirmYes) { ctx.AssertBotAdmin(); @@ -294,7 +294,7 @@ public class Admin var system = await ctx.Repository.GetSystem(systemId.Value!); await ctx.Reply(null, await CreateEmbed(ctx, system)); - if (!await ctx.PromptYesNo($"Associate account {account.NameAndMention()} with system `{system.Hid}`?", "Recover account")) + if (!await ctx.PromptYesNo($"Associate account {account.NameAndMention()} with system `{system.Hid}`?", "Recover account", flagValue: confirmYes)) throw new PKError("System recovery cancelled."); await ctx.Repository.AddAccount(system.Id, account.Id); @@ -402,7 +402,7 @@ public class Admin } } - public async Task AbuseLogDescription(Context ctx, User? account, string? id, string? description, bool clear) + public async Task AbuseLogDescription(Context ctx, User? account, string? id, string? description, bool clear, bool confirmClear) { ctx.AssertBotAdmin(); @@ -410,7 +410,7 @@ public class Admin if (abuseLog == null) return; - if (clear && await ctx.ConfirmClear("this abuse log description")) + if (clear && await ctx.ConfirmClear("this abuse log description", confirmClear)) { await ctx.Repository.UpdateAbuseLog(abuseLog.Id, new AbuseLogPatch { Description = null }); await ctx.Reply($"{Emojis.Success} Abuse log description cleared."); diff --git a/PluralKit.Bot/Commands/Api.cs b/PluralKit.Bot/Commands/Api.cs index 626bcd4a..380e8cf1 100644 --- a/PluralKit.Bot/Commands/Api.cs +++ b/PluralKit.Bot/Commands/Api.cs @@ -115,28 +115,32 @@ public class Api } } - public async Task SystemWebhook(Context ctx) + public async Task GetSystemWebhook(Context ctx) { ctx.CheckSystem().CheckDMContext(); - if (!ctx.HasNext(false)) - { - if (ctx.System.WebhookUrl == null) - await ctx.Reply($"Your system does not have a webhook URL set. Set one with `{ctx.DefaultPrefix}system webhook `!"); - else - await ctx.Reply($"Your system's webhook URL is <{ctx.System.WebhookUrl}>."); + if (ctx.System.WebhookUrl == null) + await ctx.Reply($"Your system does not have a webhook URL set. Set one with `{ctx.DefaultPrefix}system webhook `!"); + else + await ctx.Reply($"Your system's webhook URL is <{ctx.System.WebhookUrl}>."); + } + + public async Task ClearSystemWebhook(Context ctx, bool confirmYes) + { + ctx.CheckSystem().CheckDMContext(); + + if (!await ctx.ConfirmClear("your system's webhook URL", confirmYes)) return; - } - if (ctx.MatchClear() && await ctx.ConfirmClear("your system's webhook URL")) - { - await ctx.Repository.UpdateSystem(ctx.System.Id, new SystemPatch { WebhookUrl = null, WebhookToken = null }); + await ctx.Repository.UpdateSystem(ctx.System.Id, new SystemPatch { WebhookUrl = null, WebhookToken = null }); - await ctx.Reply($"{Emojis.Success} System webhook URL removed."); - return; - } + await ctx.Reply($"{Emojis.Success} System webhook URL removed."); + } + + public async Task SetSystemWebhook(Context ctx, string newUrl) + { + ctx.CheckSystem().CheckDMContext(); - var newUrl = ctx.RemainderOrNull(); if (!await DispatchExt.ValidateUri(newUrl)) throw new PKError($"The URL {newUrl.AsCode()} is invalid or I cannot access it. Are you sure this is a valid, publicly accessible URL?"); diff --git a/PluralKit.Bot/Commands/Config.cs b/PluralKit.Bot/Commands/Config.cs index ff34e3d8..9d8b175c 100644 --- a/PluralKit.Bot/Commands/Config.cs +++ b/PluralKit.Bot/Commands/Config.cs @@ -290,7 +290,7 @@ public class Config await ctx.Reply($"{Emojis.Success} System time zone cleared (set to UTC)."); } - public async Task EditSystemTimezone(Context ctx, string zoneStr) + public async Task EditSystemTimezone(Context ctx, string zoneStr, bool confirmYes = false) { if (ctx.System == null) throw Errors.NoSystemError(ctx.DefaultPrefix); @@ -299,7 +299,7 @@ public class Config var currentTime = SystemClock.Instance.GetCurrentInstant().InZone(zone); var msg = $"This will change the system time zone to **{zone.Id}**. The current time is **{currentTime.FormatZoned()}**. Is this correct?"; - if (!await ctx.PromptYesNo(msg, "Change Timezone")) throw Errors.TimezoneChangeCancelled; + if (!await ctx.PromptYesNo(msg, "Change Timezone", flagValue: confirmYes)) throw Errors.TimezoneChangeCancelled; await ctx.Repository.UpdateSystemConfig(ctx.System.Id, new() { UiTz = zone.Id }); diff --git a/PluralKit.Bot/Commands/Fun.cs b/PluralKit.Bot/Commands/Fun.cs index 9763f186..609fffd5 100644 --- a/PluralKit.Bot/Commands/Fun.cs +++ b/PluralKit.Bot/Commands/Fun.cs @@ -37,20 +37,16 @@ public class Fun public Task Meow(Context ctx) => ctx.Reply("*mrrp :3*"); - public Task Error(Context ctx) - { - if (ctx.Match("message")) - return ctx.Reply("> **Error code:** `50f3c7b439d111ecab2023a5431fffbd`", new EmbedBuilder() - .Color(0xE74C3C) - .Title("Internal error occurred") - .Description( - "For support, please send the error code above in **#bug-reports-and-errors** on **[the support server *(click to join)*](https://discord.gg/PczBt78)** with a description of what you were doing at the time.") - .Footer(new Embed.EmbedFooter("50f3c7b439d111ecab2023a5431fffbd")) - .Timestamp(SystemClock.Instance.GetCurrentInstant().ToDateTimeOffset().ToString("O")) - .Build() - ); + public Task ErrorMessage(Context ctx) => ctx.Reply("> **Error code:** `50f3c7b439d111ecab2023a5431fffbd`", new EmbedBuilder() + .Color(0xE74C3C) + .Title("Internal error occurred") + .Description( + "For support, please send the error code above in **#bug-reports-and-errors** on **[the support server *(click to join)*](https://discord.gg/PczBt78)** with a description of what you were doing at the time.") + .Footer(new Embed.EmbedFooter("50f3c7b439d111ecab2023a5431fffbd")) + .Timestamp(SystemClock.Instance.GetCurrentInstant().ToDateTimeOffset().ToString("O")) + .Build() + ); - return ctx.Reply( - $"{Emojis.Error} Unknown command {"error".AsCode()}. For a list of possible commands, see ."); - } + public Task Error(Context ctx) => ctx.Reply( + $"{Emojis.Error} Unknown command {"error".AsCode()}. For a list of possible commands, see ."); } \ No newline at end of file diff --git a/PluralKit.Bot/Commands/GroupMember.cs b/PluralKit.Bot/Commands/GroupMember.cs index 69a9b269..a53bdd37 100644 --- a/PluralKit.Bot/Commands/GroupMember.cs +++ b/PluralKit.Bot/Commands/GroupMember.cs @@ -51,7 +51,7 @@ public class GroupMember groups.Count - toAction.Count)); } - public async Task ListMemberGroups(Context ctx, PKMember target, string? query, IHasListOptions flags) + public async Task ListMemberGroups(Context ctx, PKMember target, string? query, IHasListOptions flags, bool all) { var targetSystem = await ctx.Repository.GetSystem(target.System); var opts = flags.GetListOptions(ctx, target.System); @@ -80,10 +80,10 @@ public class GroupMember title.Append($" matching **{opts.Search.Truncate(100)}**"); await ctx.RenderGroupList(ctx.LookupContextFor(target.System), target.System, title.ToString(), - target.Color, opts); + target.Color, opts, all); } - public async Task AddRemoveMembers(Context ctx, PKGroup target, List _members, Groups.AddRemoveOperation op, bool all) + public async Task AddRemoveMembers(Context ctx, PKGroup target, List _members, Groups.AddRemoveOperation op, bool all, bool confirmYes) { ctx.CheckOwnGroup(target); @@ -126,7 +126,7 @@ public class GroupMember .Where(m => existingMembersInGroup.Contains(m.Value)) .ToList(); - if (all && !await ctx.PromptYesNo($"Are you sure you want to remove all members from group {target.Reference(ctx)}?", "Empty Group")) throw Errors.GenericCancelled(); + if (all && !await ctx.PromptYesNo($"Are you sure you want to remove all members from group {target.Reference(ctx)}?", "Empty Group", flagValue: confirmYes)) throw Errors.GenericCancelled(); await ctx.Repository.RemoveMembersFromGroup(target.Id, toAction); } diff --git a/PluralKit.Bot/Commands/Groups.cs b/PluralKit.Bot/Commands/Groups.cs index a405f527..aa2d67b9 100644 --- a/PluralKit.Bot/Commands/Groups.cs +++ b/PluralKit.Bot/Commands/Groups.cs @@ -32,7 +32,7 @@ public class Groups _avatarHosting = avatarHosting; } - public async Task CreateGroup(Context ctx, string groupName) + public async Task CreateGroup(Context ctx, string groupName, bool confirmYes = false) { ctx.CheckSystem(); @@ -53,7 +53,7 @@ public class Groups { var msg = $"{Emojis.Warn} You already have a group in your system with the name \"{existingGroup.Name}\" (with ID `{existingGroup.DisplayHid(ctx.Config)}`). Do you want to create another group with the same name?"; - if (!await ctx.PromptYesNo(msg, "Create")) + if (!await ctx.PromptYesNo(msg, "Create", flagValue: confirmYes)) throw new PKError("Group creation cancelled."); } @@ -98,7 +98,7 @@ public class Groups await ctx.Reply(replyStr, eb.Build()); } - public async Task RenameGroup(Context ctx, PKGroup target, string newName) + public async Task RenameGroup(Context ctx, PKGroup target, string? newName, bool confirmYes = false) { ctx.CheckOwnGroup(target); @@ -113,7 +113,7 @@ public class Groups { var msg = $"{Emojis.Warn} You already have a group in your system with the name \"{existingGroup.Name}\" (with ID `{existingGroup.DisplayHid(ctx.Config)}`). Do you want to rename this group to that name too?"; - if (!await ctx.PromptYesNo(msg, "Rename")) + if (!await ctx.PromptYesNo(msg, "Rename", flagValue: confirmYes)) throw new PKError("Group rename cancelled."); } @@ -320,10 +320,10 @@ public class Groups await ctx.Reply(embed: ebS.Build()); } - public async Task ClearGroupIcon(Context ctx, PKGroup target) + public async Task ClearGroupIcon(Context ctx, PKGroup target, bool confirmYes) { ctx.CheckOwnGroup(target); - await ctx.ConfirmClear("this group's icon"); + await ctx.ConfirmClear("this group's icon", confirmYes); await ctx.Repository.UpdateGroup(target.Id, new GroupPatch { Icon = null }); await ctx.Reply($"{Emojis.Success} Group icon cleared."); @@ -400,10 +400,10 @@ public class Groups await ctx.Reply(embed: ebS.Build()); } - public async Task ClearGroupBanner(Context ctx, PKGroup target) + public async Task ClearGroupBanner(Context ctx, PKGroup target, bool confirmYes) { ctx.CheckOwnGroup(target); - await ctx.ConfirmClear("this group's banner image"); + await ctx.ConfirmClear("this group's banner image", confirmYes); await ctx.Repository.UpdateGroup(target.Id, new GroupPatch { BannerImage = null }); await ctx.Reply($"{Emojis.Success} Group banner image cleared."); @@ -506,7 +506,7 @@ public class Groups files: [MiscUtils.GenerateColorPreview(color)]); } - public async Task ListSystemGroups(Context ctx, PKSystem system, string? query, IHasListOptions flags) + public async Task ListSystemGroups(Context ctx, PKSystem system, string? query, IHasListOptions flags, bool all) { if (system == null) { @@ -528,7 +528,8 @@ public class Groups system.Id, GetEmbedTitle(ctx, system, opts), system.Color, - opts + opts, + all ); } @@ -547,16 +548,16 @@ public class Groups return title.ToString(); } - public async Task ShowGroupCard(Context ctx, PKGroup target, bool showEmbed = false) + public async Task ShowGroupCard(Context ctx, PKGroup target, bool showEmbed, bool all) { var system = await GetGroupSystem(ctx, target); if (showEmbed) { - await ctx.Reply(text: EmbedService.LEGACY_EMBED_WARNING, embed: await _embeds.CreateGroupEmbed(ctx, system, target)); + await ctx.Reply(text: EmbedService.LEGACY_EMBED_WARNING, embed: await _embeds.CreateGroupEmbed(ctx, system, target, all)); return; } - await ctx.Reply(components: await _embeds.CreateGroupMessageComponents(ctx, system, target)); + await ctx.Reply(components: await _embeds.CreateGroupMessageComponents(ctx, system, target, all)); } public async Task ShowGroupPrivacy(Context ctx, PKGroup target) diff --git a/PluralKit.Bot/Commands/ImportExport.cs b/PluralKit.Bot/Commands/ImportExport.cs index dbecc3f7..76118afe 100644 --- a/PluralKit.Bot/Commands/ImportExport.cs +++ b/PluralKit.Bot/Commands/ImportExport.cs @@ -31,7 +31,7 @@ public class ImportExport _dmCache = dmCache; } - public async Task Import(Context ctx, string? inputUrl) + public async Task Import(Context ctx, string? inputUrl, bool confirmYes) { inputUrl = inputUrl ?? ctx.Message.Attachments.FirstOrDefault()?.Url; if (inputUrl == null) throw Errors.NoImportFilePassed; @@ -77,7 +77,7 @@ public class ImportExport async Task ConfirmImport(string message) { var msg = $"{message}\n\nDo you want to proceed with the import?"; - if (!await ctx.PromptYesNo(msg, "Proceed")) + if (!await ctx.PromptYesNo(msg, "Proceed", flagValue: confirmYes)) throw Errors.ImportCancelled; } @@ -86,7 +86,7 @@ public class ImportExport && data.Value("accounts").Contains(ctx.Author.Id.ToString())) { var msg = $"{Emojis.Warn} You seem to importing a system profile belonging to another account. Are you sure you want to proceed?"; - if (!await ctx.PromptYesNo(msg, "Import")) throw Errors.ImportCancelled; + if (!await ctx.PromptYesNo(msg, "Import", flagValue: confirmYes)) throw Errors.ImportCancelled; } var result = await _dataFiles.ImportSystem(ctx.Author.Id, ctx.System, data, ConfirmImport); diff --git a/PluralKit.Bot/Commands/Lists/ContextListExt.cs b/PluralKit.Bot/Commands/Lists/ContextListExt.cs index 875a1862..bdd1b034 100644 --- a/PluralKit.Bot/Commands/Lists/ContextListExt.cs +++ b/PluralKit.Bot/Commands/Lists/ContextListExt.cs @@ -130,7 +130,7 @@ public static class ContextListExt } public static async Task RenderGroupList(this Context ctx, LookupContext lookupCtx, - SystemId system, string embedTitle, string color, ListOptions opts) + SystemId system, string embedTitle, string color, ListOptions opts, bool all) { // We take an IDatabase instead of a IPKConnection so we don't keep the handle open for the entire runtime // We wanna release it as soon as the member list is actually *fetched*, instead of potentially minutes later (paginate timeout) @@ -204,7 +204,7 @@ public static class ContextListExt { if (g.ListPrivacy == PrivacyLevel.Public || lookupCtx == LookupContext.ByOwner) { - if (ctx.MatchFlag("all", "a")) + if (all) { ret += $"({"member".ToQuantity(g.TotalMemberCount)})"; } @@ -242,7 +242,7 @@ public static class ContextListExt if (g.ListPrivacy == PrivacyLevel.Public || lookupCtx == LookupContext.ByOwner) { - if (ctx.MatchFlag("all", "a") && ctx.DirectLookupContextFor(system) == LookupContext.ByOwner) + if (all && ctx.DirectLookupContextFor(system) == LookupContext.ByOwner) profile.Append($"\n**Member Count:** {g.TotalMemberCount}"); else profile.Append($"\n**Member Count:** {g.PublicMemberCount}"); diff --git a/PluralKit.Bot/Commands/Member.cs b/PluralKit.Bot/Commands/Member.cs index 45010f34..6d5ee812 100644 --- a/PluralKit.Bot/Commands/Member.cs +++ b/PluralKit.Bot/Commands/Member.cs @@ -28,7 +28,7 @@ public class Member _avatarHosting = avatarHosting; } - public async Task NewMember(Context ctx, string? memberName) + public async Task NewMember(Context ctx, string? memberName, bool confirmYes = false) { if (ctx.System == null) throw Errors.NoSystemError(ctx.DefaultPrefix); memberName = memberName ?? throw new PKSyntaxError("You must pass a member name."); @@ -42,7 +42,7 @@ public class Member if (existingMember != null) { var msg = $"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx)}\" (with ID `{existingMember.DisplayHid(ctx.Config)}`). Do you want to create another member with the same name?"; - if (!await ctx.PromptYesNo(msg, "Create")) throw new PKError("Member creation cancelled."); + if (!await ctx.PromptYesNo(msg, "Create", flagValue: confirmYes)) throw new PKError("Member creation cancelled."); } await using var conn = await ctx.Database.Obtain(); diff --git a/PluralKit.Bot/Commands/MemberAvatar.cs b/PluralKit.Bot/Commands/MemberAvatar.cs index 8c5289f8..81500a0e 100644 --- a/PluralKit.Bot/Commands/MemberAvatar.cs +++ b/PluralKit.Bot/Commands/MemberAvatar.cs @@ -17,10 +17,10 @@ public class MemberAvatar _avatarHosting = avatarHosting; } - private async Task AvatarClear(MemberAvatarLocation location, Context ctx, PKMember target, MemberGuildSettings? mgs) + private async Task AvatarClear(MemberAvatarLocation location, Context ctx, PKMember target, MemberGuildSettings? mgs, bool confirmYes) { ctx.CheckSystem().CheckOwnMember(target); - await ctx.ConfirmClear("this member's " + location.Name()); + await ctx.ConfirmClear("this member's " + location.Name(), confirmYes); await UpdateAvatar(location, ctx, target, null); if (location == MemberAvatarLocation.Server) @@ -149,10 +149,10 @@ public class MemberAvatar await AvatarShow(MemberAvatarLocation.Server, ctx, target, guildData, format); } - public async Task ClearServerAvatar(Context ctx, PKMember target) + public async Task ClearServerAvatar(Context ctx, PKMember target, bool confirmYes) { var guildData = await GetServerAvatarGuildData(ctx, target); - await AvatarClear(MemberAvatarLocation.Server, ctx, target, guildData); + await AvatarClear(MemberAvatarLocation.Server, ctx, target, guildData, confirmYes); } public async Task ChangeServerAvatar(Context ctx, PKMember target, ParsedImage avatar) @@ -167,10 +167,10 @@ public class MemberAvatar await AvatarShow(MemberAvatarLocation.Member, ctx, target, guildData, format); } - public async Task ClearAvatar(Context ctx, PKMember target) + public async Task ClearAvatar(Context ctx, PKMember target, bool confirmYes) { var guildData = await GetAvatarGuildData(ctx, target); - await AvatarClear(MemberAvatarLocation.Member, ctx, target, guildData); + await AvatarClear(MemberAvatarLocation.Member, ctx, target, guildData, confirmYes); } public async Task ChangeAvatar(Context ctx, PKMember target, ParsedImage avatar) @@ -185,10 +185,10 @@ public class MemberAvatar await AvatarShow(MemberAvatarLocation.MemberWebhook, ctx, target, guildData, format); } - public async Task ClearWebhookAvatar(Context ctx, PKMember target) + public async Task ClearWebhookAvatar(Context ctx, PKMember target, bool confirmYes) { var guildData = await GetWebhookAvatarGuildData(ctx, target); - await AvatarClear(MemberAvatarLocation.MemberWebhook, ctx, target, guildData); + await AvatarClear(MemberAvatarLocation.MemberWebhook, ctx, target, guildData, confirmYes); } public async Task ChangeWebhookAvatar(Context ctx, PKMember target, ParsedImage avatar) diff --git a/PluralKit.Bot/Commands/MemberEdit.cs b/PluralKit.Bot/Commands/MemberEdit.cs index 94b127d2..e4ccc6ea 100644 --- a/PluralKit.Bot/Commands/MemberEdit.cs +++ b/PluralKit.Bot/Commands/MemberEdit.cs @@ -44,7 +44,7 @@ public class MemberEdit } } - public async Task ChangeName(Context ctx, PKMember target, string newName) + public async Task ChangeName(Context ctx, PKMember target, string newName, bool confirmYes) { ctx.CheckSystem().CheckOwnMember(target); @@ -58,7 +58,7 @@ public class MemberEdit { var msg = $"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx)}\" (`{existingMember.DisplayHid(ctx.Config)}`). Do you want to rename this member to that name too?"; - if (!await ctx.PromptYesNo(msg, "Rename")) throw new PKError("Member renaming cancelled."); + if (!await ctx.PromptYesNo(msg, "Rename", flagValue: confirmYes)) throw new PKError("Member renaming cancelled."); } // Rename the member diff --git a/PluralKit.Bot/Commands/MemberProxy.cs b/PluralKit.Bot/Commands/MemberProxy.cs index d2b128d8..6e47dce0 100644 --- a/PluralKit.Bot/Commands/MemberProxy.cs +++ b/PluralKit.Bot/Commands/MemberProxy.cs @@ -14,7 +14,7 @@ public class MemberProxy await ctx.Reply($"This member's proxy tags are:\n{target.ProxyTagsString("\n")}"); } - public async Task ClearProxy(Context ctx, PKMember target) + public async Task ClearProxy(Context ctx, PKMember target, bool confirmYes = false) { ctx.CheckSystem().CheckOwnMember(target); @@ -22,7 +22,7 @@ public class MemberProxy if (target.ProxyTags.Count > 1) { var msg = $"{Emojis.Warn} You already have multiple proxy tags set: {target.ProxyTagsString()}\nDo you want to clear them all?"; - if (!await ctx.PromptYesNo(msg, "Clear")) + if (!await ctx.PromptYesNo(msg, "Clear", flagValue: confirmYes)) throw Errors.GenericCancelled(); } @@ -32,7 +32,7 @@ public class MemberProxy await ctx.Reply($"{Emojis.Success} Proxy tags cleared."); } - public async Task AddProxy(Context ctx, PKMember target, string proxyString) + public async Task AddProxy(Context ctx, PKMember target, string proxyString, bool confirmYes = false) { ctx.CheckSystem().CheckOwnMember(target); @@ -44,7 +44,7 @@ public class MemberProxy throw new PKError( $"Proxy tag too long ({tagToAdd.ProxyString.Length} > {Limits.MaxProxyTagLength} characters)."); - if (!await WarnOnConflict(ctx, target, tagToAdd)) + if (!await WarnOnConflict(ctx, target, tagToAdd, confirmYes)) throw Errors.GenericCancelled(); var newTags = target.ProxyTags.ToList(); @@ -72,7 +72,7 @@ public class MemberProxy await ctx.Reply($"{Emojis.Success} Removed proxy tags {tagToRemove.ProxyString.AsCode()}."); } - public async Task SetProxy(Context ctx, PKMember target, string proxyString) + public async Task SetProxy(Context ctx, PKMember target, string proxyString, bool confirmYes = false) { ctx.CheckSystem().CheckOwnMember(target); @@ -82,7 +82,7 @@ public class MemberProxy if (target.ProxyTags.Count > 1) { var msg = $"This member already has more than one proxy tag set: {target.ProxyTagsString()}\nDo you want to replace them?"; - if (!await ctx.PromptYesNo(msg, "Replace")) + if (!await ctx.PromptYesNo(msg, "Replace", flagValue: confirmYes)) throw Errors.GenericCancelled(); } @@ -90,7 +90,7 @@ public class MemberProxy throw new PKError( $"Proxy tag too long ({requestedTag.ProxyString.Length} > {Limits.MaxProxyTagLength} characters)."); - if (!await WarnOnConflict(ctx, target, requestedTag)) + if (!await WarnOnConflict(ctx, target, requestedTag, confirmYes)) throw Errors.GenericCancelled(); var newTags = new[] { requestedTag }; @@ -110,7 +110,7 @@ public class MemberProxy return new ProxyTag(prefixAndSuffix[0], prefixAndSuffix[1]); } - private async Task WarnOnConflict(Context ctx, PKMember target, ProxyTag newTag) + private async Task WarnOnConflict(Context ctx, PKMember target, ProxyTag newTag, bool confirmYes = false) { var query = "select * from (select *, (unnest(proxy_tags)).prefix as prefix, (unnest(proxy_tags)).suffix as suffix from members where system = @System) as _ where prefix is not distinct from @Prefix and suffix is not distinct from @Suffix and id != @Existing"; var conflicts = (await ctx.Database.Execute(conn => conn.QueryAsync(query, @@ -120,6 +120,6 @@ public class MemberProxy var conflictList = conflicts.Select(m => $"- **{m.NameFor(ctx)}**"); var msg = $"{Emojis.Warn} The following members have conflicting proxy tags:\n{string.Join('\n', conflictList)}\nDo you want to proceed anyway?"; - return await ctx.PromptYesNo(msg, "Proceed"); + return await ctx.PromptYesNo(msg, "Proceed", flagValue: confirmYes); } } \ No newline at end of file diff --git a/PluralKit.Bot/Commands/Message.cs b/PluralKit.Bot/Commands/Message.cs index 7bb1f681..6e25b67f 100644 --- a/PluralKit.Bot/Commands/Message.cs +++ b/PluralKit.Bot/Commands/Message.cs @@ -322,9 +322,7 @@ public class ProxiedMessage { if (messageId == null) { - if (!ctx.HasNext()) - throw new PKSyntaxError("You must pass a message ID or link."); - throw new PKSyntaxError($"Could not parse {ctx.PeekArgument().AsCode()} as a message ID or link."); + throw new PKSyntaxError("You must pass a message ID or link."); } var message = await ctx.Repository.GetFullMessage(messageId.Value); diff --git a/PluralKit.Bot/Commands/Random.cs b/PluralKit.Bot/Commands/Random.cs index 2356ce4a..d34c3e73 100644 --- a/PluralKit.Bot/Commands/Random.cs +++ b/PluralKit.Bot/Commands/Random.cs @@ -74,12 +74,12 @@ public class Random { await ctx.Reply( text: EmbedService.LEGACY_EMBED_WARNING, - embed: await _embeds.CreateGroupEmbed(ctx, target, groups.ToArray()[randInt])); + embed: await _embeds.CreateGroupEmbed(ctx, target, groups.ToArray()[randInt], all)); return; } await ctx.Reply( - components: await _embeds.CreateGroupMessageComponents(ctx, target, groups.ToArray()[randInt])); + components: await _embeds.CreateGroupMessageComponents(ctx, target, groups.ToArray()[randInt], all)); } public async Task GroupMember(Context ctx, PKGroup group, GroupRandomMemberFlags flags) diff --git a/PluralKit.Bot/Commands/ServerConfig.cs b/PluralKit.Bot/Commands/ServerConfig.cs index e7b24a3c..9ecc5170 100644 --- a/PluralKit.Bot/Commands/ServerConfig.cs +++ b/PluralKit.Bot/Commands/ServerConfig.cs @@ -144,11 +144,11 @@ public class ServerConfig await ctx.Reply($"{Emojis.Success} Proxy logging channel set to <#{channel.Id}>."); } - public async Task ClearLogChannel(Context ctx) + public async Task ClearLogChannel(Context ctx, bool confirmYes) { await ctx.CheckGuildContext().CheckAuthorPermission(PermissionSet.ManageGuild, "Manage Server"); - if (!await ctx.ConfirmClear("the server log channel")) + if (!await ctx.ConfirmClear("the server log channel", confirmYes)) return; await ctx.Repository.UpdateGuild(ctx.Guild.Id, new GuildPatch { LogChannel = null }); diff --git a/PluralKit.Bot/Commands/Switch.cs b/PluralKit.Bot/Commands/Switch.cs index 82c63e14..f566ef6a 100644 --- a/PluralKit.Bot/Commands/Switch.cs +++ b/PluralKit.Bot/Commands/Switch.cs @@ -57,14 +57,14 @@ public class Switch $"{Emojis.Success} Switch registered. Current fronters are now {string.Join(", ", members.Select(m => m.NameFor(ctx)))}."); } - public async Task SwitchMove(Context ctx, string timeToMove) + public async Task SwitchMove(Context ctx, string str, bool confirmYes = false) { ctx.CheckSystem(); var tz = TzdbDateTimeZoneSource.Default.ForId(ctx.Config?.UiTz ?? "UTC"); - var result = DateUtils.ParseDateTime(timeToMove, true, tz); - if (result == null) throw Errors.InvalidDateTime(timeToMove); + var result = DateUtils.ParseDateTime(str, true, tz); + if (result == null) throw Errors.InvalidDateTime(str); var time = result.Value; @@ -95,14 +95,14 @@ public class Switch // yeet var msg = $"{Emojis.Warn} This will move the latest switch ({lastSwitchMemberStr}) from ({lastSwitchDeltaStr} ago) to ({newSwitchDeltaStr} ago). Is this OK?"; - if (!await ctx.PromptYesNo(msg, "Move Switch")) throw Errors.SwitchMoveCancelled; + if (!await ctx.PromptYesNo(msg, "Move Switch", flagValue: confirmYes)) throw Errors.SwitchMoveCancelled; // aaaand *now* we do the move await ctx.Repository.MoveSwitch(lastTwoSwitches[0].Id, time.ToInstant()); await ctx.Reply($"{Emojis.Success} Switch moved to ({newSwitchDeltaStr} ago)."); } - public async Task SwitchEdit(Context ctx, List? newMembers, bool newSwitch = false, bool first = false, bool remove = false, bool append = false, bool prepend = false) + public async Task SwitchEdit(Context ctx, List? newMembers, bool newSwitch = false, bool first = false, bool remove = false, bool append = false, bool prepend = false, bool confirmYes = false) { ctx.CheckSystem(); @@ -131,7 +131,7 @@ public class Switch await DoSwitchCommand(ctx, newMembers); } else - await DoEditCommand(ctx, newMembers); + await DoEditCommand(ctx, newMembers, confirmYes); } public List PrependToSwitch(List members, List currentSwitchMembers) @@ -167,13 +167,13 @@ public class Switch return members; } - public async Task SwitchEditOut(Context ctx) + public async Task SwitchEditOut(Context ctx, bool confirmYes) { ctx.CheckSystem(); - await DoEditCommand(ctx, []); + await DoEditCommand(ctx, [], confirmYes); } - public async Task DoEditCommand(Context ctx, ICollection? members) + public async Task DoEditCommand(Context ctx, ICollection? members, bool confirmYes) { if (members == null) members = new List(); @@ -203,7 +203,7 @@ public class Switch msg = $"{Emojis.Warn} This will turn the latest switch ({lastSwitchMemberStr}, {lastSwitchDeltaStr} ago) into a switch-out. Is this okay?"; else msg = $"{Emojis.Warn} This will change the latest switch ({lastSwitchMemberStr}, {lastSwitchDeltaStr} ago) to {newSwitchMemberStr}. Is this okay?"; - if (!await ctx.PromptYesNo(msg, "Edit")) throw Errors.SwitchEditCancelled; + if (!await ctx.PromptYesNo(msg, "Edit", flagValue: confirmYes)) throw Errors.SwitchEditCancelled; // Actually edit the switch await ctx.Repository.EditSwitch(conn, lastSwitch.Id, members.Select(m => m.Id).ToList()); @@ -217,7 +217,7 @@ public class Switch await ctx.Reply($"{Emojis.Success} Switch edited. Current fronters are now {newSwitchMemberStr}."); } - public async Task SwitchDelete(Context ctx, bool all) + public async Task SwitchDelete(Context ctx, bool all = false, bool confirmYes = false) { ctx.CheckSystem(); @@ -226,7 +226,7 @@ public class Switch // Subcommand: "delete all" var purgeMsg = $"{Emojis.Warn} This will delete *all registered switches* in your system. Are you sure you want to proceed?"; - if (!await ctx.PromptYesNo(purgeMsg, "Clear Switches")) + if (!await ctx.PromptYesNo(purgeMsg, "Clear Switches", flagValue: confirmYes)) throw Errors.GenericCancelled(); await ctx.Repository.DeleteAllSwitches(ctx.System.Id); await ctx.Reply($"{Emojis.Success} Cleared system switches!"); @@ -258,7 +258,7 @@ public class Switch msg = $"{Emojis.Warn} This will delete the latest switch ({lastSwitchMemberStr}, {lastSwitchDeltaStr} ago). The next latest switch is {secondSwitchMemberStr} ({secondSwitchDeltaStr} ago). Is this okay?"; } - if (!await ctx.PromptYesNo(msg, "Delete Switch")) throw Errors.SwitchDeleteCancelled; + if (!await ctx.PromptYesNo(msg, "Delete Switch", flagValue: confirmYes)) throw Errors.SwitchDeleteCancelled; await ctx.Repository.DeleteSwitch(lastTwoSwitches[0].Id); await ctx.Reply($"{Emojis.Success} Switch deleted."); diff --git a/PluralKit.Bot/Commands/SystemFront.cs b/PluralKit.Bot/Commands/SystemFront.cs index 6d9cf049..330a9f77 100644 --- a/PluralKit.Bot/Commands/SystemFront.cs +++ b/PluralKit.Bot/Commands/SystemFront.cs @@ -26,7 +26,7 @@ public class SystemFront await ctx.Reply(embed: await _embeds.CreateFronterEmbed(sw, ctx.Zone, ctx.LookupContextFor(system.Id))); } - public async Task FrontHistory(Context ctx, PKSystem system, bool clear = false) + public async Task FrontHistory(Context ctx, PKSystem system, bool showMemberId, bool clear = false) { if (clear) { @@ -55,8 +55,6 @@ public class SystemFront embedTitle = $"Front history of {guildSettings.DisplayName} (`{system.Hid}`)"; } - var showMemberId = ctx.MatchFlag("with-id", "wid"); - await ctx.Paginate( sws, totalSwitches, diff --git a/PluralKit.Bot/Commands/SystemLink.cs b/PluralKit.Bot/Commands/SystemLink.cs index 38a0cc47..ef5f89af 100644 --- a/PluralKit.Bot/Commands/SystemLink.cs +++ b/PluralKit.Bot/Commands/SystemLink.cs @@ -25,7 +25,7 @@ public class SystemLink await ctx.Reply($"{Emojis.Success} Account linked to system."); } - public async Task UnlinkAccount(Context ctx, string idRaw) + public async Task UnlinkAccount(Context ctx, string idRaw, bool confirmYes) { ctx.CheckSystem(); @@ -38,7 +38,7 @@ public class SystemLink if (accountIds.Count == 1) throw Errors.UnlinkingLastAccount(ctx.DefaultPrefix); var msg = $"Are you sure you want to unlink <@{id}> from your system?"; - if (!await ctx.PromptYesNo(msg, "Unlink")) throw Errors.MemberUnlinkCancelled; + if (!await ctx.PromptYesNo(msg, "Unlink", flagValue: confirmYes)) throw Errors.MemberUnlinkCancelled; await ctx.Repository.RemoveAccount(ctx.System.Id, id); await ctx.Reply($"{Emojis.Success} Account unlinked."); diff --git a/PluralKit.Bot/Services/EmbedService.cs b/PluralKit.Bot/Services/EmbedService.cs index 4cf5158f..620d7229 100644 --- a/PluralKit.Bot/Services/EmbedService.cs +++ b/PluralKit.Bot/Services/EmbedService.cs @@ -560,7 +560,7 @@ public class EmbedService return eb.Build(); } - public async Task CreateGroupMessageComponents(Context ctx, PKSystem system, PKGroup target) + public async Task CreateGroupMessageComponents(Context ctx, PKSystem system, PKGroup target, bool all) { var pctx = ctx.LookupContextFor(system.Id); var name = target.NameFor(ctx); @@ -568,7 +568,7 @@ public class EmbedService var systemName = (ctx.Guild != null && systemGuildSettings?.DisplayName != null) ? systemGuildSettings?.DisplayName! : system.NameFor(ctx); var countctx = LookupContext.ByNonOwner; - if (ctx.MatchFlag("a", "all")) + if (all) { if (system.Id == ctx.System?.Id) countctx = LookupContext.ByOwner; @@ -673,12 +673,12 @@ public class EmbedService ]; } - public async Task CreateGroupEmbed(Context ctx, PKSystem system, PKGroup target) + public async Task CreateGroupEmbed(Context ctx, PKSystem system, PKGroup target, bool all) { var pctx = ctx.LookupContextFor(system.Id); var countctx = LookupContext.ByNonOwner; - if (ctx.MatchFlag("a", "all")) + if (all) { if (system.Id == ctx.System?.Id) countctx = LookupContext.ByOwner; diff --git a/PluralKit.Bot/Utils/ContextUtils.cs b/PluralKit.Bot/Utils/ContextUtils.cs index 4b0a4f5b..f40785d2 100644 --- a/PluralKit.Bot/Utils/ContextUtils.cs +++ b/PluralKit.Bot/Utils/ContextUtils.cs @@ -16,17 +16,17 @@ namespace PluralKit.Bot; public static class ContextUtils { - public static async Task ConfirmClear(this Context ctx, string toClear, bool? confirmYes = null) + public static async Task ConfirmClear(this Context ctx, string toClear, bool confirmYes) { - if (!await ctx.PromptYesNo($"{Emojis.Warn} Are you sure you want to clear {toClear}?", "Clear", null, true, confirmYes)) + if (!await ctx.PromptYesNo($"{Emojis.Warn} Are you sure you want to clear {toClear}?", "Clear", flagValue: confirmYes)) throw Errors.GenericCancelled(); return true; } public static async Task PromptYesNo(this Context ctx, string msgString, string acceptButton, - User user = null, bool matchFlag = true, bool? flagValue = null) + User user = null, bool matchFlag = true, bool flagValue = false) { - if (matchFlag && (flagValue ?? ctx.MatchFlag("y", "yes"))) return true; + if (matchFlag && flagValue) return true; var prompt = new YesNoPrompt(ctx) { diff --git a/crates/command_definitions/src/admin.rs b/crates/command_definitions/src/admin.rs index 56f4dd71..a7817d4a 100644 --- a/crates/command_definitions/src/admin.rs +++ b/crates/command_definitions/src/admin.rs @@ -16,6 +16,7 @@ pub fn cmds() -> impl Iterator { .help("Sets the deny flag on an abuse log entry"), command!(abuselog, ("description", ["desc"]), log_param, Optional(("desc", OpaqueStringRemainder)) => format!("admin_abuselog_description_{}", log_param.name())) .flag(("clear", ["c"])) + .flag(("yes", ["y"])) .help("Sets the description of an abuse log entry"), command!(abuselog, ("adduser", ["au"]), log_param => format!("admin_abuselog_add_user_{}", log_param.name())) .help("Adds a user to an abuse log entry"), @@ -36,22 +37,31 @@ pub fn cmds() -> impl Iterator { [ command!(admin, ("updatesystemid", ["usid"]), SystemRef, ("new_hid", OpaqueString) => "admin_update_system_id") + .flag(("yes", ["y"])) .help("Updates a system's ID"), command!(admin, ("updatememberid", ["umid"]), MemberRef, ("new_hid", OpaqueString) => "admin_update_member_id") + .flag(("yes", ["y"])) .help("Updates a member's ID"), command!(admin, ("updategroupid", ["ugid"]), GroupRef, ("new_hid", OpaqueString) => "admin_update_group_id") + .flag(("yes", ["y"])) .help("Updates a group's ID"), command!(admin, ("rerollsystemid", ["rsid"]), SystemRef => "admin_reroll_system_id") + .flag(("yes", ["y"])) .help("Rerolls a system's ID"), command!(admin, ("rerollmemberid", ["rmid"]), MemberRef => "admin_reroll_member_id") + .flag(("yes", ["y"])) .help("Rerolls a member's ID"), command!(admin, ("rerollgroupid", ["rgid"]), GroupRef => "admin_reroll_group_id") + .flag(("yes", ["y"])) .help("Rerolls a group's ID"), command!(admin, ("updatememberlimit", ["uml"]), SystemRef, Optional(("limit", OpaqueInt)) => "admin_system_member_limit") + .flag(("yes", ["y"])) .help("Updates a system's member limit"), command!(admin, ("updategrouplimit", ["ugl"]), SystemRef, Optional(("limit", OpaqueInt)) => "admin_system_group_limit") + .flag(("yes", ["y"])) .help("Updates a system's group limit"), command!(admin, ("systemrecover", ["sr"]), ("token", OpaqueString), ("account", UserRef) => "admin_system_recover") + .flag(("yes", ["y"])) .flag(("reroll-token", ["rt"])) .help("Recovers a system"), command!(admin, ("systemdelete", ["sd"]), SystemRef => "admin_system_delete") diff --git a/crates/command_definitions/src/group.rs b/crates/command_definitions/src/group.rs index fec62ccf..e0fdf2fb 100644 --- a/crates/command_definitions/src/group.rs +++ b/crates/command_definitions/src/group.rs @@ -21,9 +21,10 @@ pub fn cmds() -> impl Iterator { [command!(group_new, ("name", OpaqueString) => "group_new").help("Creates a new group")] .into_iter(); - let group_info_cmd = - [command!(group_target => "group_info").help("Shows information about a group")] - .into_iter(); + let group_info_cmd = [command!(group_target => "group_info") + .flag(("all", ["a"])) + .help("Shows information about a group")] + .into_iter(); let group_name = tokens!( group_target, @@ -159,9 +160,9 @@ pub fn cmds() -> impl Iterator { let group_modify_members_cmd = [ command!(group_target, "add", Optional(MemberRefs) => "group_add_member") - .flag(("all", ["a"])), + .flag(("all", ["a"])).flag(("yes", ["y"])), command!(group_target, ("remove", ["delete", "del", "rem"]), Optional(MemberRefs) => "group_remove_member") - .flag(("all", ["a"])), + .flag(("all", ["a"])).flag(("yes", ["y"])), ] .into_iter(); diff --git a/crates/command_definitions/src/import_export.rs b/crates/command_definitions/src/import_export.rs index 49b66f11..16c27a06 100644 --- a/crates/command_definitions/src/import_export.rs +++ b/crates/command_definitions/src/import_export.rs @@ -2,7 +2,8 @@ use super::*; pub fn cmds() -> impl Iterator { [ - command!("import", Optional(("url", OpaqueStringRemainder)) => "import"), + command!("import", Optional(("url", OpaqueStringRemainder)) => "import") + .flag(("yes", ["y"])), command!("export" => "export"), ] .into_iter() diff --git a/crates/command_definitions/src/member.rs b/crates/command_definitions/src/member.rs index f6acb28e..8da757b5 100644 --- a/crates/command_definitions/src/member.rs +++ b/crates/command_definitions/src/member.rs @@ -49,6 +49,7 @@ pub fn cmds() -> impl Iterator { [ command!(member_name => "member_name_show").help("Shows a member's name"), command!(member_name, ("name", OpaqueStringRemainder) => "member_name_update") + .flag(("yes", ["y"])) .help("Changes a member's name"), ] .into_iter() diff --git a/crates/command_definitions/src/server_config.rs b/crates/command_definitions/src/server_config.rs index 7119d528..c0cdfa0b 100644 --- a/crates/command_definitions/src/server_config.rs +++ b/crates/command_definitions/src/server_config.rs @@ -51,6 +51,7 @@ pub fn cmds() -> impl Iterator { command!(log_channel, ("channel", ChannelRef) => "server_config_log_channel_set") .help("Sets the log channel"), command!(log_channel, ("clear", ["c"]) => "server_config_log_channel_clear") + .flag(("yes", ["y"])) .help("Clears the log channel"), ] .into_iter(); diff --git a/crates/command_definitions/src/switch.rs b/crates/command_definitions/src/switch.rs index 14ef6a0d..3b51849a 100644 --- a/crates/command_definitions/src/switch.rs +++ b/crates/command_definitions/src/switch.rs @@ -20,7 +20,7 @@ pub fn cmds() -> impl Iterator { command!(switch, out => "switch_out"), command!(switch, r#move, OpaqueString => "switch_move"), // TODO: datetime parsing command!(switch, delete => "switch_delete").flag(("all", ["clear", "c"])), - command!(switch, edit, out => "switch_edit_out"), + command!(switch, edit, out => "switch_edit_out").flag(("yes", ["y"])), command!(switch, edit, Optional(MemberRefs) => "switch_edit").flags(edit_flags), command!(switch, copy, Optional(MemberRefs) => "switch_copy").flags(edit_flags), command!(switch, ("commands", ["help"]) => "switch_commands"), diff --git a/crates/command_definitions/src/system.rs b/crates/command_definitions/src/system.rs index 4e12ceb9..7abe106f 100644 --- a/crates/command_definitions/src/system.rs +++ b/crates/command_definitions/src/system.rs @@ -28,25 +28,33 @@ pub fn edit() -> impl Iterator { ] .into_iter(); - let system_webhook_cmd = [command!(system, ("webhook", ["hook"]) => "system_webhook") - .help("Creates a webhook for your system")] + let system_webhook = tokens!(system, ("webhook", ["hook"])); + let system_webhook_cmd = [ + command!(system_webhook => "system_webhook_show").help("Shows your system's webhook URL"), + command!(system_webhook, ("clear", ["c"]) => "system_webhook_clear") + .flag(("yes", ["y"])) + .help("Clears your system's webhook URL"), + command!(system_webhook, ("url", OpaqueString) => "system_webhook_set") + .help("Sets your system's webhook URL"), + ] .into_iter(); - let system_info_cmd = [ - command!(system => "system_info_self").help("Shows information about your system"), - command!(system_target, ("info", ["show", "view"]) => "system_info") - .help("Shows information about your system"), - ] - .into_iter() - .map(|cmd| { + let add_info_flags = |cmd: Command| { cmd.flag(("public", ["pub"])) .flag(("private", ["priv"])) .flag(("all", ["a"])) - }); + }; + let system_info_cmd_self = std::iter::once(add_info_flags( + command!(system => "system_info_self").help("Shows information about your system"), + )); + let system_info_cmd = std::iter::once(add_info_flags( + command!(system_target, ("info", ["show", "view"]) => "system_info") + .help("Shows information about your system"), + )); let system_name = tokens!(system_target, "name"); let system_name_cmd = - [command!(system_name => "system_show_name").help("Shows the systems name")].into_iter(); + std::iter::once(command!(system_name => "system_show_name").help("Shows the systems name")); let system_name_self = tokens!(system, "name"); let system_name_self_cmd = [ @@ -60,9 +68,10 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_server_name = tokens!(system_target, ("servername", ["sn", "guildname"])); - let system_server_name_cmd = [command!(system_server_name => "system_show_server_name") - .help("Shows the system's server name")] - .into_iter(); + let system_server_name_cmd = std::iter::once( + command!(system_server_name => "system_show_server_name") + .help("Shows the system's server name"), + ); let system_server_name_self = tokens!(system, ("servername", ["sn", "guildname"])); let system_server_name_self_cmd = [ @@ -77,9 +86,10 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_description = tokens!(system_target, ("description", ["desc", "d"])); - let system_description_cmd = [command!(system_description => "system_show_description") - .help("Shows the system's description")] - .into_iter(); + let system_description_cmd = std::iter::once( + command!(system_description => "system_show_description") + .help("Shows the system's description"), + ); let system_description_self = tokens!(system, ("description", ["desc", "d"])); let system_description_self_cmd = [ @@ -93,9 +103,9 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_color = tokens!(system_target, ("color", ["colour"])); - let system_color_cmd = - [command!(system_color => "system_show_color").help("Shows the system's color")] - .into_iter(); + let system_color_cmd = std::iter::once( + command!(system_color => "system_show_color").help("Shows the system's color"), + ); let system_color_self = tokens!(system, ("color", ["colour"])); let system_color_self_cmd = [ @@ -110,7 +120,7 @@ pub fn edit() -> impl Iterator { let system_tag = tokens!(system_target, ("tag", ["suffix"])); let system_tag_cmd = - [command!(system_tag => "system_show_tag").help("Shows the system's tag")].into_iter(); + std::iter::once(command!(system_tag => "system_show_tag").help("Shows the system's tag")); let system_tag_self = tokens!(system, ("tag", ["suffix"])); let system_tag_self_cmd = [ @@ -124,9 +134,10 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_server_tag = tokens!(system_target, ("servertag", ["st", "guildtag"])); - let system_server_tag_cmd = [command!(system_server_tag => "system_show_server_tag") - .help("Shows the system's server tag")] - .into_iter(); + let system_server_tag_cmd = std::iter::once( + command!(system_server_tag => "system_show_server_tag") + .help("Shows the system's server tag"), + ); let system_server_tag_self = tokens!(system, ("servertag", ["st", "guildtag"])); let system_server_tag_self_cmd = [ @@ -141,9 +152,9 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_pronouns = tokens!(system_target, ("pronouns", ["prns"])); - let system_pronouns_cmd = - [command!(system_pronouns => "system_show_pronouns").help("Shows the system's pronouns")] - .into_iter(); + let system_pronouns_cmd = std::iter::once( + command!(system_pronouns => "system_show_pronouns").help("Shows the system's pronouns"), + ); let system_pronouns_self = tokens!(system, ("pronouns", ["prns"])); let system_pronouns_self_cmd = [ @@ -158,9 +169,9 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_avatar = tokens!(system_target, ("avatar", ["pfp"])); - let system_avatar_cmd = - [command!(system_avatar => "system_show_avatar").help("Shows the system's avatar")] - .into_iter(); + let system_avatar_cmd = std::iter::once( + command!(system_avatar => "system_show_avatar").help("Shows the system's avatar"), + ); let system_avatar_self = tokens!(system, ("avatar", ["pfp"])); let system_avatar_self_cmd = [ @@ -175,11 +186,10 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_server_avatar = tokens!(system_target, ("serveravatar", ["spfp"])); - let system_server_avatar_cmd = [ + let system_server_avatar_cmd = std::iter::once( command!(system_server_avatar => "system_show_server_avatar") .help("Shows the system's server avatar"), - ] - .into_iter(); + ); let system_server_avatar_self = tokens!(system, ("serveravatar", ["spfp"])); let system_server_avatar_self_cmd = [ @@ -194,9 +204,9 @@ pub fn edit() -> impl Iterator { .into_iter(); let system_banner = tokens!(system_target, ("banner", ["cover"])); - let system_banner_cmd = - [command!(system_banner => "system_show_banner").help("Shows the system's banner")] - .into_iter(); + let system_banner_cmd = std::iter::once( + command!(system_banner => "system_show_banner").help("Shows the system's banner"), + ); let system_banner_self = tokens!(system, ("banner", ["cover"])); let system_banner_self_cmd = [ @@ -253,7 +263,7 @@ pub fn edit() -> impl Iterator { let system_link = [ command!("link", ("account", UserRef) => "system_link"), - command!("unlink", ("account", OpaqueString) => "system_unlink"), + command!("unlink", ("account", OpaqueString) => "system_unlink").flag(("yes", ["y"])), ] .into_iter(); @@ -286,10 +296,12 @@ pub fn edit() -> impl Iterator { .map(add_list_flags); let system_display_id_self_cmd = - [command!(system, "id" => "system_display_id_self")].into_iter(); - let system_display_id_cmd = [command!(system_target, "id" => "system_display_id")].into_iter(); + std::iter::once(command!(system, "id" => "system_display_id_self")); + let system_display_id_cmd = + std::iter::once(command!(system_target, "id" => "system_display_id")); - system_new_cmd + system_info_cmd_self + .chain(system_new_cmd) .chain(system_webhook_cmd) .chain(system_name_self_cmd) .chain(system_server_name_self_cmd) diff --git a/crates/commands/src/main.rs b/crates/commands/src/main.rs index 325fc469..8784b5c2 100644 --- a/crates/commands/src/main.rs +++ b/crates/commands/src/main.rs @@ -4,7 +4,7 @@ use command_parser::Tree; use commands::COMMAND_TREE; fn main() { - parse(); + related(); } fn related() {