mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-04 04:56:49 +00:00
implement admin commands
This commit is contained in:
parent
5198f7d83b
commit
a268f75d32
15 changed files with 263 additions and 287 deletions
|
|
@ -8,6 +8,7 @@ public partial class CommandTree
|
|||
{
|
||||
return command switch
|
||||
{
|
||||
Commands.Dashboard => ctx.Execute<Help>(Dashboard, m => m.Dashboard(ctx)),
|
||||
Commands.Explain => ctx.Execute<Help>(Explain, m => m.Explain(ctx)),
|
||||
Commands.Help(_, var flags) => ctx.Execute<Help>(Help, m => m.HelpRoot(ctx, flags.show_embed)),
|
||||
Commands.HelpCommands => ctx.Reply(
|
||||
|
|
@ -244,9 +245,33 @@ public partial class CommandTree
|
|||
Commands.MessageAuthor(var param, var flags) => ctx.Execute<ProxiedMessage>(Message, m => m.GetMessage(ctx, param.target.MessageId, flags.GetReplyFormat(), false, true)),
|
||||
Commands.MessageDelete(var param, var flags) => ctx.Execute<ProxiedMessage>(Message, m => m.GetMessage(ctx, param.target.MessageId, flags.GetReplyFormat(), true, false)),
|
||||
Commands.MessageEdit(var param, var flags) => ctx.Execute<ProxiedMessage>(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<ProxiedMessage>(MessageReproxy, m => m.ReproxyMessage(ctx, param.target.MessageId)),
|
||||
Commands.MessageReproxy(var param, _) => ctx.Execute<ProxiedMessage>(MessageReproxy, m => m.ReproxyMessage(ctx, param.msg.MessageId, param.member)),
|
||||
Commands.Import(var param, _) => ctx.Execute<ImportExport>(Import, m => m.Import(ctx, param.url)),
|
||||
Commands.Export(_, _) => ctx.Execute<ImportExport>(Export, m => m.Export(ctx)),
|
||||
Commands.AdminUpdateSystemId(var param, _) => ctx.Execute<Admin>(null, m => m.UpdateSystemId(ctx, param.target, param.new_hid)),
|
||||
Commands.AdminUpdateMemberId(var param, _) => ctx.Execute<Admin>(null, m => m.UpdateMemberId(ctx, param.target, param.new_hid)),
|
||||
Commands.AdminUpdateGroupId(var param, _) => ctx.Execute<Admin>(null, m => m.UpdateGroupId(ctx, param.target, param.new_hid)),
|
||||
Commands.AdminRerollSystemId(var param, _) => ctx.Execute<Admin>(null, m => m.RerollSystemId(ctx, param.target)),
|
||||
Commands.AdminRerollMemberId(var param, _) => ctx.Execute<Admin>(null, m => m.RerollMemberId(ctx, param.target)),
|
||||
Commands.AdminRerollGroupId(var param, _) => ctx.Execute<Admin>(null, m => m.RerollGroupId(ctx, param.target)),
|
||||
Commands.AdminSystemMemberLimit(var param, _) => ctx.Execute<Admin>(null, m => m.SystemMemberLimit(ctx, param.target, param.limit)),
|
||||
Commands.AdminSystemGroupLimit(var param, _) => ctx.Execute<Admin>(null, m => m.SystemGroupLimit(ctx, param.target, param.limit)),
|
||||
Commands.AdminSystemRecover(var param, var flags) => ctx.Execute<Admin>(null, m => m.SystemRecover(ctx, param.token, param.account, flags.reroll_token)),
|
||||
Commands.AdminSystemDelete(var param, _) => ctx.Execute<Admin>(null, m => m.SystemDelete(ctx, param.target)),
|
||||
Commands.AdminSendMessage(var param, _) => ctx.Execute<Admin>(null, m => m.SendAdminMessage(ctx, param.account, param.content)),
|
||||
Commands.AdminAbuselogCreate(var param, var flags) => ctx.Execute<Admin>(null, m => m.AbuseLogCreate(ctx, param.account, flags.deny_boy_usage, param.description)),
|
||||
Commands.AdminAbuselogShowAccount(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogShow(ctx, param.account, null)),
|
||||
Commands.AdminAbuselogFlagDenyAccount(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogFlagDeny(ctx, param.account, null, param.value)),
|
||||
Commands.AdminAbuselogDescriptionAccount(var param, var flags) => ctx.Execute<Admin>(null, m => m.AbuseLogDescription(ctx, param.account, null, param.desc, flags.clear)),
|
||||
Commands.AdminAbuselogAddUserAccount(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogAddUser(ctx, param.account, null, ctx.Author)),
|
||||
Commands.AdminAbuselogRemoveUserAccount(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogRemoveUser(ctx, param.account, null, ctx.Author)),
|
||||
Commands.AdminAbuselogDeleteAccount(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogDelete(ctx, param.account, null)),
|
||||
Commands.AdminAbuselogShowLogId(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogShow(ctx, null, param.log_id)),
|
||||
Commands.AdminAbuselogFlagDenyLogId(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogFlagDeny(ctx, null, param.log_id, param.value)),
|
||||
Commands.AdminAbuselogDescriptionLogId(var param, var flags) => ctx.Execute<Admin>(null, m => m.AbuseLogDescription(ctx, null, param.log_id, param.desc, flags.clear)),
|
||||
Commands.AdminAbuselogAddUserLogId(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogAddUser(ctx, null, param.log_id, ctx.Author)),
|
||||
Commands.AdminAbuselogRemoveUserLogId(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogRemoveUser(ctx, null, param.log_id, ctx.Author)),
|
||||
Commands.AdminAbuselogDeleteLogId(var param, _) => ctx.Execute<Admin>(null, m => m.AbuseLogDelete(ctx, null, param.log_id)),
|
||||
_ =>
|
||||
// this should only ever occur when deving if commands are not implemented...
|
||||
ctx.Reply(
|
||||
|
|
@ -282,82 +307,6 @@ public partial class CommandTree
|
|||
return ctx.Reply($"{Emojis.Warn} Blacklist commands have moved to `{ctx.DefaultPrefix}serverconfig`.");
|
||||
if (ctx.Match("invite")) return ctx.Execute<Misc>(Invite, m => m.Invite(ctx));
|
||||
if (ctx.Match("stats", "status")) return ctx.Execute<Misc>(null, m => m.Stats(ctx));
|
||||
if (ctx.Match("admin"))
|
||||
return HandleAdminCommand(ctx);
|
||||
if (ctx.Match("dashboard", "dash"))
|
||||
return ctx.Execute<Help>(Dashboard, m => m.Dashboard(ctx));
|
||||
}
|
||||
|
||||
private async Task HandleAdminAbuseLogCommand(Context ctx)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
if (ctx.Match("n", "new", "create"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.AbuseLogCreate(ctx));
|
||||
else
|
||||
{
|
||||
AbuseLog? abuseLog = null!;
|
||||
var account = await ctx.MatchUser();
|
||||
if (account != null)
|
||||
{
|
||||
abuseLog = await ctx.Repository.GetAbuseLogByAccount(account.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
abuseLog = await ctx.Repository.GetAbuseLogByGuid(new Guid(ctx.PopArgument()));
|
||||
}
|
||||
|
||||
if (abuseLog == null)
|
||||
{
|
||||
await ctx.Reply($"{Emojis.Error} Could not find an existing abuse log entry for that query.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.HasNext())
|
||||
await ctx.Execute<Admin>(Admin, a => a.AbuseLogShow(ctx, abuseLog));
|
||||
else if (ctx.Match("au", "adduser"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.AbuseLogAddUser(ctx, abuseLog));
|
||||
else if (ctx.Match("ru", "removeuser"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.AbuseLogRemoveUser(ctx, abuseLog));
|
||||
else if (ctx.Match("desc", "description"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.AbuseLogDescription(ctx, abuseLog));
|
||||
else if (ctx.Match("deny", "deny-bot-usage"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.AbuseLogFlagDeny(ctx, abuseLog));
|
||||
else if (ctx.Match("yeet", "remove", "delete"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.AbuseLogDelete(ctx, abuseLog));
|
||||
else
|
||||
await ctx.Reply($"{Emojis.Error} Unknown subcommand {ctx.PeekArgument().AsCode()}.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleAdminCommand(Context ctx)
|
||||
{
|
||||
if (ctx.Match("usid", "updatesystemid"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.UpdateSystemId(ctx));
|
||||
else if (ctx.Match("umid", "updatememberid"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.UpdateMemberId(ctx));
|
||||
else if (ctx.Match("ugid", "updategroupid"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.UpdateGroupId(ctx));
|
||||
else if (ctx.Match("rsid", "rerollsystemid"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.RerollSystemId(ctx));
|
||||
else if (ctx.Match("rmid", "rerollmemberid"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.RerollMemberId(ctx));
|
||||
else if (ctx.Match("rgid", "rerollgroupid"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.RerollGroupId(ctx));
|
||||
else if (ctx.Match("uml", "updatememberlimit"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.SystemMemberLimit(ctx));
|
||||
else if (ctx.Match("ugl", "updategrouplimit"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.SystemGroupLimit(ctx));
|
||||
else if (ctx.Match("sr", "systemrecover"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.SystemRecover(ctx));
|
||||
else if (ctx.Match("sd", "systemdelete"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.SystemDelete(ctx));
|
||||
else if (ctx.Match("sendmsg", "sendmessage"))
|
||||
await ctx.Execute<Admin>(Admin, a => a.SendAdminMessage(ctx));
|
||||
else if (ctx.Match("al", "abuselog"))
|
||||
await HandleAdminAbuseLogCommand(ctx);
|
||||
else
|
||||
await ctx.Reply($"{Emojis.Error} Unknown command.");
|
||||
}
|
||||
|
||||
private async Task CommandHelpRoot(Context ctx)
|
||||
|
|
|
|||
|
|
@ -18,37 +18,6 @@ public static class ContextEntityArgumentsExt
|
|||
return null;
|
||||
}
|
||||
|
||||
public static async Task<User> MatchUser(this Context ctx)
|
||||
{
|
||||
var text = ctx.PeekArgument();
|
||||
if (text.TryParseMention(out var id))
|
||||
{
|
||||
var user = await ctx.Cache.GetOrFetchUser(ctx.Rest, id);
|
||||
if (user != null) ctx.PopArgument();
|
||||
return user;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool MatchUserRaw(this Context ctx, out ulong id)
|
||||
{
|
||||
id = 0;
|
||||
|
||||
var text = ctx.PeekArgument();
|
||||
if (text.TryParseMention(out var mentionId))
|
||||
id = mentionId;
|
||||
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
public static Task<PKSystem> PeekSystem(this Context ctx) => throw new NotImplementedException();
|
||||
|
||||
public static async Task<PKSystem> MatchSystem(this Context ctx)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static async Task<PKSystem> ParseSystem(this Context ctx, string input)
|
||||
{
|
||||
// System references can take three forms:
|
||||
|
|
@ -67,7 +36,7 @@ public static class ContextEntityArgumentsExt
|
|||
return null;
|
||||
}
|
||||
|
||||
public static async Task<PKMember> ParseMember(this Context ctx, string input, bool byId, SystemId? restrictToSystem = null)
|
||||
public static async Task<PKMember?> ParseMember(this Context ctx, string input, bool byId)
|
||||
{
|
||||
// Member references can have one of three forms, depending on
|
||||
// whether you're in a system or not:
|
||||
|
|
@ -100,53 +69,22 @@ public static class ContextEntityArgumentsExt
|
|||
|
||||
// If we are supposed to restrict it to a system anyway we can just do that
|
||||
PKMember memberByHid = null;
|
||||
if (restrictToSystem != null)
|
||||
{
|
||||
memberByHid = await ctx.Repository.GetMemberByHid(hid, restrictToSystem);
|
||||
if (memberByHid != null)
|
||||
return memberByHid;
|
||||
}
|
||||
// otherwise we try the querier's system and if that doesn't work we do global
|
||||
else
|
||||
{
|
||||
memberByHid = await ctx.Repository.GetMemberByHid(hid, ctx.System?.Id);
|
||||
if (memberByHid != null)
|
||||
return memberByHid;
|
||||
memberByHid = await ctx.Repository.GetMemberByHid(hid, ctx.System?.Id);
|
||||
if (memberByHid != null)
|
||||
return memberByHid;
|
||||
|
||||
// ff ctx.System was null then this would be a duplicate of above and we don't want to run it again
|
||||
if (ctx.System != null)
|
||||
{
|
||||
memberByHid = await ctx.Repository.GetMemberByHid(hid);
|
||||
if (memberByHid != null)
|
||||
return memberByHid;
|
||||
}
|
||||
// ff ctx.System was null then this would be a duplicate of above and we don't want to run it again
|
||||
if (ctx.System != null)
|
||||
{
|
||||
memberByHid = await ctx.Repository.GetMemberByHid(hid);
|
||||
if (memberByHid != null)
|
||||
return memberByHid;
|
||||
}
|
||||
|
||||
// We didn't find anything, so we return null.
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<PKMember> PeekMember(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to pop a member descriptor from the stack, returning it if present. If a member could not be
|
||||
/// resolved by the next word in the argument stack, does *not* touch the stack, and returns null.
|
||||
/// </summary>
|
||||
public static async Task<PKMember> MatchMember(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
// First, peek a member
|
||||
var member = await ctx.PeekMember(restrictToSystem);
|
||||
|
||||
// If the peek was successful, we've used up the next argument, so we pop that just to get rid of it.
|
||||
if (member != null) ctx.PopArgument();
|
||||
|
||||
// Finally, we return the member value.
|
||||
return member;
|
||||
}
|
||||
|
||||
public static async Task<PKGroup> ParseGroup(this Context ctx, string input, bool byId, SystemId? restrictToSystem = null)
|
||||
{
|
||||
if (ctx.System != null && !byId)
|
||||
|
|
@ -166,18 +104,6 @@ public static class ContextEntityArgumentsExt
|
|||
return null;
|
||||
}
|
||||
|
||||
public static async Task<PKGroup> PeekGroup(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static async Task<PKGroup> MatchGroup(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
var group = await ctx.PeekGroup(restrictToSystem);
|
||||
if (group != null) ctx.PopArgument();
|
||||
return group;
|
||||
}
|
||||
|
||||
public static string CreateNotFoundError(this Context ctx, string entity, string input, bool byId = false)
|
||||
{
|
||||
var isIDOnlyQuery = ctx.System == null || byId;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using PluralKit.Core;
|
||||
using Myriad.Types;
|
||||
|
||||
namespace PluralKit.Bot;
|
||||
|
||||
|
|
@ -12,6 +13,14 @@ public static class ContextParametersExt
|
|||
);
|
||||
}
|
||||
|
||||
public static async Task<int?> ParamResolveNumber(this Context ctx, string param_name)
|
||||
{
|
||||
return await ctx.Parameters.ResolveParameter(
|
||||
ctx, param_name,
|
||||
param => (param as Parameter.Number)?.value
|
||||
);
|
||||
}
|
||||
|
||||
public static async Task<PKMember?> ParamResolveMember(this Context ctx, string param_name)
|
||||
{
|
||||
return await ctx.Parameters.ResolveParameter(
|
||||
|
|
@ -52,6 +61,14 @@ public static class ContextParametersExt
|
|||
);
|
||||
}
|
||||
|
||||
public static async Task<User?> ParamResolveUser(this Context ctx, string param_name)
|
||||
{
|
||||
return await ctx.Parameters.ResolveParameter(
|
||||
ctx, param_name,
|
||||
param => (param as Parameter.UserRef)?.user
|
||||
);
|
||||
}
|
||||
|
||||
public static async Task<MemberPrivacySubject?> ParamResolveMemberPrivacyTarget(this Context ctx, string param_name)
|
||||
{
|
||||
return await ctx.Parameters.ResolveParameter(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Humanizer;
|
||||
using Myriad.Types;
|
||||
using Myriad.Extensions;
|
||||
using PluralKit.Core;
|
||||
using uniffi.commands;
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ public abstract record Parameter()
|
|||
public record GroupRef(PKGroup group): Parameter;
|
||||
public record GroupRefs(List<PKGroup> groups): Parameter;
|
||||
public record SystemRef(PKSystem system): Parameter;
|
||||
public record UserRef(User user): Parameter;
|
||||
public record MessageRef(Message.Reference message): Parameter;
|
||||
public record ChannelRef(Channel channel): Parameter;
|
||||
public record GuildRef(Guild guild): Parameter;
|
||||
|
|
@ -22,6 +24,7 @@ public abstract record Parameter()
|
|||
public record PrivacyLevel(Core.PrivacyLevel level): Parameter;
|
||||
public record Toggle(bool value): Parameter;
|
||||
public record Opaque(string value): Parameter;
|
||||
public record Number(int value): Parameter;
|
||||
public record Avatar(ParsedImage avatar): Parameter;
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +99,11 @@ public class Parameters
|
|||
await ctx.ParseSystem(systemRef.system)
|
||||
?? throw new PKError(ctx.CreateNotFoundError("System", systemRef.system))
|
||||
);
|
||||
case uniffi.commands.Parameter.UserRef(var userId):
|
||||
return new Parameter.UserRef(
|
||||
await ctx.Cache.GetOrFetchUser(ctx.Rest, userId)
|
||||
?? throw new PKError(ctx.CreateNotFoundError("User", userId.ToString()))
|
||||
);
|
||||
// todo(dusk): ideally generate enums for these from rust code in the cs glue
|
||||
case uniffi.commands.Parameter.MemberPrivacyTarget memberPrivacyTarget:
|
||||
// this should never really fail...
|
||||
|
|
@ -118,6 +126,8 @@ public class Parameters
|
|||
return new Parameter.Toggle(toggle.toggle);
|
||||
case uniffi.commands.Parameter.OpaqueString opaque:
|
||||
return new Parameter.Opaque(opaque.raw);
|
||||
case uniffi.commands.Parameter.OpaqueInt number:
|
||||
return new Parameter.Number(number.raw);
|
||||
case uniffi.commands.Parameter.Avatar avatar:
|
||||
return new Parameter.Avatar(await ctx.GetUserPfp(avatar.avatar) ?? ctx.ParseImage(avatar.avatar));
|
||||
case uniffi.commands.Parameter.MessageRef(var guildId, var channelId, var messageId):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
using Humanizer;
|
||||
using Dapper;
|
||||
using SqlKata;
|
||||
|
|
@ -113,18 +111,10 @@ public class Admin
|
|||
return eb.Build();
|
||||
}
|
||||
|
||||
public async Task UpdateSystemId(Context ctx)
|
||||
public async Task UpdateSystemId(Context ctx, PKSystem target, string newHid)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchSystem();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown system.");
|
||||
|
||||
var input = ctx.PopArgument();
|
||||
if (!input.TryParseHid(out var newHid))
|
||||
throw new PKError($"Invalid new system ID `{input}`.");
|
||||
|
||||
var existingSystem = await ctx.Repository.GetSystemByHid(newHid);
|
||||
if (existingSystem != null)
|
||||
throw new PKError($"Another system already exists with ID `{newHid}`.");
|
||||
|
|
@ -138,18 +128,10 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} System ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||
}
|
||||
|
||||
public async Task UpdateMemberId(Context ctx)
|
||||
public async Task UpdateMemberId(Context ctx, PKMember target, string newHid)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchMember();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown member.");
|
||||
|
||||
var input = ctx.PopArgument();
|
||||
if (!input.TryParseHid(out var newHid))
|
||||
throw new PKError($"Invalid new member ID `{input}`.");
|
||||
|
||||
var existingMember = await ctx.Repository.GetMemberByHid(newHid);
|
||||
if (existingMember != null)
|
||||
throw new PKError($"Another member already exists with ID `{newHid}`.");
|
||||
|
|
@ -167,18 +149,10 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} Member ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||
}
|
||||
|
||||
public async Task UpdateGroupId(Context ctx)
|
||||
public async Task UpdateGroupId(Context ctx, PKGroup target, string newHid)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchGroup();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown group.");
|
||||
|
||||
var input = ctx.PopArgument();
|
||||
if (!input.TryParseHid(out var newHid))
|
||||
throw new PKError($"Invalid new group ID `{input}`.");
|
||||
|
||||
var existingGroup = await ctx.Repository.GetGroupByHid(newHid);
|
||||
if (existingGroup != null)
|
||||
throw new PKError($"Another group already exists with ID `{newHid}`.");
|
||||
|
|
@ -195,14 +169,10 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} Group ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||
}
|
||||
|
||||
public async Task RerollSystemId(Context ctx)
|
||||
public async Task RerollSystemId(Context ctx, PKSystem target)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchSystem();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown system.");
|
||||
|
||||
await ctx.Reply(null, await CreateEmbed(ctx, target));
|
||||
|
||||
if (!await ctx.PromptYesNo($"Reroll system ID `{target.Hid}`?", "Reroll"))
|
||||
|
|
@ -218,14 +188,10 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} System ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||
}
|
||||
|
||||
public async Task RerollMemberId(Context ctx)
|
||||
public async Task RerollMemberId(Context ctx, PKMember target)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchMember();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown member.");
|
||||
|
||||
var system = await ctx.Repository.GetSystem(target.System);
|
||||
await ctx.Reply(null, await CreateEmbed(ctx, system));
|
||||
|
||||
|
|
@ -245,14 +211,10 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} Member ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||
}
|
||||
|
||||
public async Task RerollGroupId(Context ctx)
|
||||
public async Task RerollGroupId(Context ctx, PKGroup target)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchGroup();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown group.");
|
||||
|
||||
var system = await ctx.Repository.GetSystem(target.System);
|
||||
await ctx.Reply(null, await CreateEmbed(ctx, system));
|
||||
|
||||
|
|
@ -271,27 +233,19 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} Group ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||
}
|
||||
|
||||
public async Task SystemMemberLimit(Context ctx)
|
||||
public async Task SystemMemberLimit(Context ctx, PKSystem target, int? newLimit)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchSystem();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown system.");
|
||||
|
||||
var config = await ctx.Repository.GetSystemConfig(target.Id);
|
||||
|
||||
var currentLimit = config.MemberLimitOverride ?? Limits.MaxMemberCount;
|
||||
if (!ctx.HasNext())
|
||||
if (newLimit == null)
|
||||
{
|
||||
await ctx.Reply(null, await CreateEmbed(ctx, target));
|
||||
return;
|
||||
}
|
||||
|
||||
var newLimitStr = ctx.PopArgument().ToLower().Replace(",", null).Replace("k", "000");
|
||||
if (!int.TryParse(newLimitStr, out var newLimit))
|
||||
throw new PKError($"Couldn't parse `{newLimitStr}` as number.");
|
||||
|
||||
await ctx.Reply(null, await CreateEmbed(ctx, target));
|
||||
if (!await ctx.PromptYesNo($"Update member limit from **{currentLimit}** to **{newLimit}**?", "Update"))
|
||||
throw new PKError("Member limit change cancelled.");
|
||||
|
|
@ -300,27 +254,19 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} Member limit updated.");
|
||||
}
|
||||
|
||||
public async Task SystemGroupLimit(Context ctx)
|
||||
public async Task SystemGroupLimit(Context ctx, PKSystem target, int? newLimit)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchSystem();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown system.");
|
||||
|
||||
var config = await ctx.Repository.GetSystemConfig(target.Id);
|
||||
|
||||
var currentLimit = config.GroupLimitOverride ?? Limits.MaxGroupCount;
|
||||
if (!ctx.HasNext())
|
||||
if (newLimit == null)
|
||||
{
|
||||
await ctx.Reply(null, await CreateEmbed(ctx, target));
|
||||
return;
|
||||
}
|
||||
|
||||
var newLimitStr = ctx.PopArgument().ToLower().Replace(",", null).Replace("k", "000");
|
||||
if (!int.TryParse(newLimitStr, out var newLimit))
|
||||
throw new PKError($"Couldn't parse `{newLimitStr}` as number.");
|
||||
|
||||
await ctx.Reply(null, await CreateEmbed(ctx, target));
|
||||
if (!await ctx.PromptYesNo($"Update group limit from **{currentLimit}** to **{newLimit}**?", "Update"))
|
||||
throw new PKError("Group limit change cancelled.");
|
||||
|
|
@ -329,13 +275,10 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} Group limit updated.");
|
||||
}
|
||||
|
||||
public async Task SystemRecover(Context ctx)
|
||||
public async Task SystemRecover(Context ctx, string systemToken, User account, bool rerollToken)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var rerollToken = ctx.MatchFlag("rt", "reroll-token");
|
||||
|
||||
var systemToken = ctx.PopArgument();
|
||||
var systemId = await ctx.Database.Execute(conn => conn.QuerySingleOrDefaultAsync<SystemId?>(
|
||||
"select id from systems where token = @token",
|
||||
new { token = systemToken }
|
||||
|
|
@ -344,10 +287,6 @@ public class Admin
|
|||
if (systemId == null)
|
||||
throw new PKError("Could not retrieve a system with that token.");
|
||||
|
||||
var account = await ctx.MatchUser();
|
||||
if (account == null)
|
||||
throw new PKError("You must pass an account to associate the system with (either ID or @mention).");
|
||||
|
||||
var existingAccount = await ctx.Repository.GetSystemByAccount(account.Id);
|
||||
if (existingAccount != null)
|
||||
throw Errors.AccountInOtherSystem(existingAccount, ctx.Config, ctx.DefaultPrefix);
|
||||
|
|
@ -378,14 +317,10 @@ public class Admin
|
|||
});
|
||||
}
|
||||
|
||||
public async Task SystemDelete(Context ctx)
|
||||
public async Task SystemDelete(Context ctx, PKSystem target)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var target = await ctx.MatchSystem();
|
||||
if (target == null)
|
||||
throw new PKError("Unknown system.");
|
||||
|
||||
await ctx.Reply($"To delete the following system, reply with the system's UUID: `{target.Uuid.ToString()}`",
|
||||
await CreateEmbed(ctx, target));
|
||||
if (!await ctx.ConfirmWithReply(target.Uuid.ToString()))
|
||||
|
|
@ -396,18 +331,11 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} System deletion succesful.");
|
||||
}
|
||||
|
||||
public async Task AbuseLogCreate(Context ctx)
|
||||
public async Task AbuseLogCreate(Context ctx, User account, bool denyBotUsage, string? description)
|
||||
{
|
||||
var denyBotUsage = ctx.MatchFlag("deny", "deny-bot-usage");
|
||||
var account = await ctx.MatchUser();
|
||||
if (account == null)
|
||||
throw new PKError("You must pass an account to associate the abuse log with (either ID or @mention).");
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
string? desc = null!;
|
||||
if (ctx.HasNext(false))
|
||||
desc = ctx.RemainderOrNull(false).NormalizeLineEndSpacing();
|
||||
|
||||
var abuseLog = await ctx.Repository.CreateAbuseLog(desc, denyBotUsage);
|
||||
var abuseLog = await ctx.Repository.CreateAbuseLog(description, denyBotUsage);
|
||||
await ctx.Repository.AddAbuseLogAccount(abuseLog.Id, account.Id);
|
||||
|
||||
await ctx.Reply(
|
||||
|
|
@ -415,14 +343,49 @@ public class Admin
|
|||
await CreateAbuseLogEmbed(ctx, abuseLog));
|
||||
}
|
||||
|
||||
public async Task AbuseLogShow(Context ctx, AbuseLog abuseLog)
|
||||
public async Task<AbuseLog?> GetAbuseLog(Context ctx, User? account, string? id)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
AbuseLog? abuseLog = null!;
|
||||
if (account != null)
|
||||
{
|
||||
abuseLog = await ctx.Repository.GetAbuseLogByAccount(account.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
abuseLog = await ctx.Repository.GetAbuseLogByGuid(new Guid(id));
|
||||
}
|
||||
|
||||
if (abuseLog == null)
|
||||
{
|
||||
await ctx.Reply($"{Emojis.Error} Could not find an existing abuse log entry for that query.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return abuseLog;
|
||||
}
|
||||
|
||||
public async Task AbuseLogShow(Context ctx, User? account, string? id)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
AbuseLog? abuseLog = await GetAbuseLog(ctx, account, id);
|
||||
if (abuseLog == null)
|
||||
return;
|
||||
|
||||
await ctx.Reply(null, await CreateAbuseLogEmbed(ctx, abuseLog));
|
||||
}
|
||||
|
||||
public async Task AbuseLogFlagDeny(Context ctx, AbuseLog abuseLog)
|
||||
public async Task AbuseLogFlagDeny(Context ctx, User? account, string? id, bool? value)
|
||||
{
|
||||
if (!ctx.HasNext())
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
AbuseLog? abuseLog = await GetAbuseLog(ctx, account, id);
|
||||
if (abuseLog == null)
|
||||
return;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
await ctx.Reply(
|
||||
$"Bot usage is currently {(abuseLog.DenyBotUsage ? "denied" : "allowed")} "
|
||||
|
|
@ -430,27 +393,31 @@ public class Admin
|
|||
}
|
||||
else
|
||||
{
|
||||
var value = ctx.MatchToggle(true);
|
||||
if (abuseLog.DenyBotUsage != value)
|
||||
await ctx.Repository.UpdateAbuseLog(abuseLog.Id, new AbuseLogPatch { DenyBotUsage = value });
|
||||
await ctx.Repository.UpdateAbuseLog(abuseLog.Id, new AbuseLogPatch { DenyBotUsage = value.Value });
|
||||
|
||||
await ctx.Reply(
|
||||
$"Bot usage is now **{(value ? "denied" : "allowed")}** "
|
||||
$"Bot usage is now **{(value.Value ? "denied" : "allowed")}** "
|
||||
+ $"for accounts associated with abuse log `{abuseLog.Uuid}`.");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AbuseLogDescription(Context ctx, AbuseLog abuseLog)
|
||||
public async Task AbuseLogDescription(Context ctx, User? account, string? id, string? description, bool clear)
|
||||
{
|
||||
if (ctx.MatchClear() && await ctx.ConfirmClear("this abuse log description"))
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
AbuseLog? abuseLog = await GetAbuseLog(ctx, account, id);
|
||||
if (abuseLog == null)
|
||||
return;
|
||||
|
||||
if (clear && await ctx.ConfirmClear("this abuse log description"))
|
||||
{
|
||||
await ctx.Repository.UpdateAbuseLog(abuseLog.Id, new AbuseLogPatch { Description = null });
|
||||
await ctx.Reply($"{Emojis.Success} Abuse log description cleared.");
|
||||
}
|
||||
else if (ctx.HasNext())
|
||||
else if (description != null)
|
||||
{
|
||||
var desc = ctx.RemainderOrNull(false).NormalizeLineEndSpacing();
|
||||
await ctx.Repository.UpdateAbuseLog(abuseLog.Id, new AbuseLogPatch { Description = desc });
|
||||
await ctx.Repository.UpdateAbuseLog(abuseLog.Id, new AbuseLogPatch { Description = description });
|
||||
await ctx.Reply($"{Emojis.Success} Abuse log description updated.");
|
||||
}
|
||||
else
|
||||
|
|
@ -461,11 +428,13 @@ public class Admin
|
|||
}
|
||||
}
|
||||
|
||||
public async Task AbuseLogAddUser(Context ctx, AbuseLog abuseLog)
|
||||
public async Task AbuseLogAddUser(Context ctx, User? accountToFind, string? id, User account)
|
||||
{
|
||||
var account = await ctx.MatchUser();
|
||||
if (account == null)
|
||||
throw new PKError("You must pass an account to associate the abuse log with (either ID or @mention).");
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
AbuseLog? abuseLog = await GetAbuseLog(ctx, accountToFind, id);
|
||||
if (abuseLog == null)
|
||||
return;
|
||||
|
||||
await ctx.Repository.AddAbuseLogAccount(abuseLog.Id, account.Id);
|
||||
await ctx.Reply(
|
||||
|
|
@ -473,11 +442,13 @@ public class Admin
|
|||
await CreateAbuseLogEmbed(ctx, abuseLog));
|
||||
}
|
||||
|
||||
public async Task AbuseLogRemoveUser(Context ctx, AbuseLog abuseLog)
|
||||
public async Task AbuseLogRemoveUser(Context ctx, User? accountToFind, string? id, User account)
|
||||
{
|
||||
var account = await ctx.MatchUser();
|
||||
if (account == null)
|
||||
throw new PKError("You must pass an account to remove from the abuse log (either ID or @mention).");
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
AbuseLog? abuseLog = await GetAbuseLog(ctx, accountToFind, id);
|
||||
if (abuseLog == null)
|
||||
return;
|
||||
|
||||
await ctx.Repository.UpdateAccount(account.Id, new()
|
||||
{
|
||||
|
|
@ -489,8 +460,14 @@ public class Admin
|
|||
await CreateAbuseLogEmbed(ctx, abuseLog));
|
||||
}
|
||||
|
||||
public async Task AbuseLogDelete(Context ctx, AbuseLog abuseLog)
|
||||
public async Task AbuseLogDelete(Context ctx, User? account, string? id)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
AbuseLog? abuseLog = await GetAbuseLog(ctx, account, id);
|
||||
if (abuseLog == null)
|
||||
return;
|
||||
|
||||
if (!await ctx.PromptYesNo($"Really delete abuse log entry `{abuseLog.Uuid}`?", "Delete", matchFlag: false))
|
||||
{
|
||||
await ctx.Reply($"{Emojis.Error} Deletion cancelled.");
|
||||
|
|
@ -501,17 +478,10 @@ public class Admin
|
|||
await ctx.Reply($"{Emojis.Success} Successfully deleted abuse log entry.");
|
||||
}
|
||||
|
||||
public async Task SendAdminMessage(Context ctx)
|
||||
public async Task SendAdminMessage(Context ctx, User account, string content)
|
||||
{
|
||||
ctx.AssertBotAdmin();
|
||||
|
||||
var account = await ctx.MatchUser();
|
||||
if (account == null)
|
||||
throw new PKError("You must pass an account to send an admin message to (either ID or @mention).");
|
||||
if (!ctx.HasNext())
|
||||
throw new PKError("You must provide a message to send.");
|
||||
|
||||
var content = ctx.RemainderOrNull(false).NormalizeLineEndSpacing();
|
||||
var messageContent = $"## [Admin Message]\n\n{content}\n\nWe cannot read replies sent to this DM. If you wish to contact the staff team, please join the support server (<https://discord.gg/PczBt78>) or send us an email at <legal@pluralkit.me>.";
|
||||
|
||||
try
|
||||
|
|
|
|||
|
|
@ -58,16 +58,14 @@ public class ProxiedMessage
|
|||
_redisService = redisService;
|
||||
}
|
||||
|
||||
public async Task ReproxyMessage(Context ctx, ulong? messageId)
|
||||
public async Task ReproxyMessage(Context ctx, ulong? messageId, PKMember target)
|
||||
{
|
||||
var (msg, systemId) = await GetMessageToEdit(ctx, messageId, ReproxyTimeout, true);
|
||||
|
||||
if (ctx.System.Id != systemId)
|
||||
throw new PKError("Can't reproxy a message sent by a different system.");
|
||||
|
||||
// Get target member ID
|
||||
var target = await ctx.MatchMember(restrictToSystem: ctx.System.Id);
|
||||
if (target == null)
|
||||
if (target == null || target.System != ctx.System.Id)
|
||||
throw new PKError("Could not find a member to reproxy the message with.");
|
||||
|
||||
// Fetch members and get the ProxyMember for `target`
|
||||
|
|
|
|||
|
|
@ -1 +1,64 @@
|
|||
use super::*;
|
||||
|
||||
pub fn admin() -> &'static str {
|
||||
"admin"
|
||||
}
|
||||
|
||||
pub fn cmds() -> impl Iterator<Item = Command> {
|
||||
let admin = admin();
|
||||
|
||||
let abuselog = tokens!(admin, ("abuselog", ["al"]));
|
||||
let make_abuselog_cmds = |log_param: Parameter| {
|
||||
[
|
||||
command!(abuselog, ("show", ["s"]), log_param => format!("admin_abuselog_show_{}", log_param.name()))
|
||||
.help("Shows an abuse log entry"),
|
||||
command!(abuselog, ("flagdeny", ["fd"]), log_param, Optional(("value", Toggle)) => format!("admin_abuselog_flag_deny_{}", log_param.name()))
|
||||
.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"]))
|
||||
.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"),
|
||||
command!(abuselog, ("removeuser", ["ru"]), log_param => format!("admin_abuselog_remove_user_{}", log_param.name()))
|
||||
.help("Removes a user from an abuse log entry"),
|
||||
command!(abuselog, ("delete", ["d"]), log_param => format!("admin_abuselog_delete_{}", log_param.name()))
|
||||
.help("Deletes an abuse log entry"),
|
||||
].into_iter()
|
||||
};
|
||||
let abuselog_cmds = [
|
||||
command!(abuselog, ("create", ["c", "new"]), ("account", UserRef), Optional(("description", OpaqueStringRemainder)) => "admin_abuselog_create")
|
||||
.flag(("deny-boy-usage", ["deny"]))
|
||||
.help("Creates an abuse log entry")
|
||||
]
|
||||
.into_iter()
|
||||
.chain(make_abuselog_cmds(Skip(("account", UserRef)).into())) // falls through to log_id
|
||||
.chain(make_abuselog_cmds(("log_id", OpaqueString).into()));
|
||||
|
||||
[
|
||||
command!(admin, ("updatesystemid", ["usid"]), SystemRef, ("new_hid", OpaqueString) => "admin_update_system_id")
|
||||
.help("Updates a system's ID"),
|
||||
command!(admin, ("updatememberid", ["umid"]), MemberRef, ("new_hid", OpaqueString) => "admin_update_member_id")
|
||||
.help("Updates a member's ID"),
|
||||
command!(admin, ("updategroupid", ["ugid"]), GroupRef, ("new_hid", OpaqueString) => "admin_update_group_id")
|
||||
.help("Updates a group's ID"),
|
||||
command!(admin, ("rerollsystemid", ["rsid"]), SystemRef => "admin_reroll_system_id")
|
||||
.help("Rerolls a system's ID"),
|
||||
command!(admin, ("rerollmemberid", ["rmid"]), MemberRef => "admin_reroll_member_id")
|
||||
.help("Rerolls a member's ID"),
|
||||
command!(admin, ("rerollgroupid", ["rgid"]), GroupRef => "admin_reroll_group_id")
|
||||
.help("Rerolls a group's ID"),
|
||||
command!(admin, ("updatememberlimit", ["uml"]), SystemRef, Optional(("limit", OpaqueInt)) => "admin_system_member_limit")
|
||||
.help("Updates a system's member limit"),
|
||||
command!(admin, ("updategrouplimit", ["ugl"]), SystemRef, Optional(("limit", OpaqueInt)) => "admin_system_group_limit")
|
||||
.help("Updates a system's group limit"),
|
||||
command!(admin, ("systemrecover", ["sr"]), ("token", OpaqueString), ("account", UserRef) => "admin_system_recover")
|
||||
.flag(("reroll-token", ["rt"]))
|
||||
.help("Recovers a system"),
|
||||
command!(admin, ("systemdelete", ["sd"]), SystemRef => "admin_system_delete")
|
||||
.help("Deletes a system"),
|
||||
command!(admin, ("sendmessage", ["sendmsg"]), ("account", UserRef), ("content", OpaqueStringRemainder) => "admin_send_message")
|
||||
.help("Sends a message to a user"),
|
||||
]
|
||||
.into_iter()
|
||||
.chain(abuselog_cmds)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -5,9 +5,7 @@ pub fn cmds() -> impl Iterator<Item = Command> {
|
|||
[
|
||||
command!(("dashboard", ["dash"]) => "dashboard"),
|
||||
command!("explain" => "explain"),
|
||||
command!(help => "help")
|
||||
.flag(("foo", OpaqueString)) // todo: just for testing
|
||||
.help("Shows the help command"),
|
||||
command!(help => "help").help("Shows the help command"),
|
||||
command!(help, "commands" => "help_commands").help("help commands"),
|
||||
command!(help, "proxy" => "help_proxy").help("help proxy"),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ pub mod api;
|
|||
pub mod autoproxy;
|
||||
pub mod commands;
|
||||
pub mod config;
|
||||
pub mod dashboard;
|
||||
pub mod debug;
|
||||
pub mod fun;
|
||||
pub mod group;
|
||||
|
|
@ -40,10 +39,12 @@ pub fn all() -> impl Iterator<Item = Command> {
|
|||
.chain(debug::cmds())
|
||||
.chain(message::cmds())
|
||||
.chain(import_export::cmds())
|
||||
.chain(admin::cmds())
|
||||
.map(|cmd| {
|
||||
cmd.hidden_flag(("plaintext", ["pt"]))
|
||||
.hidden_flag(("raw", ["r"]))
|
||||
.hidden_flag(("show-embed", ["se"]))
|
||||
.hidden_flag(("by-id", ["id"]))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub fn cmds() -> impl Iterator<Item = Command> {
|
|||
.help("Deletes a proxied message"),
|
||||
apply_edit(command!(message, edit => "message_edit")),
|
||||
apply_edit(command!(edit => "message_edit")),
|
||||
command!(("reproxy", ["rp", "crimes", "crime"]), MessageRef => "message_reproxy")
|
||||
command!(("reproxy", ["rp", "crimes", "crime"]), ("msg", MessageRef), ("member", MemberRef) => "message_reproxy")
|
||||
.help("Reproxies a message with a different member"),
|
||||
]
|
||||
.into_iter()
|
||||
|
|
|
|||
|
|
@ -3,18 +3,21 @@ use std::{
|
|||
str::FromStr,
|
||||
};
|
||||
|
||||
use smol_str::SmolStr;
|
||||
use regex::Regex;
|
||||
use smol_str::{SmolStr, format_smolstr};
|
||||
|
||||
use crate::token::{Token, TokenMatchResult};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ParameterValue {
|
||||
OpaqueString(String),
|
||||
OpaqueInt(i32),
|
||||
MemberRef(String),
|
||||
MemberRefs(Vec<String>),
|
||||
GroupRef(String),
|
||||
GroupRefs(Vec<String>),
|
||||
SystemRef(String),
|
||||
UserRef(u64),
|
||||
MessageRef(Option<u64>, Option<u64>, u64),
|
||||
ChannelRef(u64),
|
||||
GuildRef(u64),
|
||||
|
|
@ -85,6 +88,10 @@ impl Parameter {
|
|||
ParameterKind::OpaqueString | ParameterKind::OpaqueStringRemainder => {
|
||||
Ok(ParameterValue::OpaqueString(input.into()))
|
||||
}
|
||||
ParameterKind::OpaqueInt => input
|
||||
.parse::<i32>()
|
||||
.map(|num| ParameterValue::OpaqueInt(num))
|
||||
.map_err(|err| format_smolstr!("invalid integer: {err}")),
|
||||
ParameterKind::GroupRef => Ok(ParameterValue::GroupRef(input.into())),
|
||||
ParameterKind::GroupRefs => Ok(ParameterValue::GroupRefs(
|
||||
input.split(' ').map(|s| s.trim().to_string()).collect(),
|
||||
|
|
@ -94,6 +101,22 @@ impl Parameter {
|
|||
input.split(' ').map(|s| s.trim().to_string()).collect(),
|
||||
)),
|
||||
ParameterKind::SystemRef => Ok(ParameterValue::SystemRef(input.into())),
|
||||
ParameterKind::UserRef => {
|
||||
if let Ok(user_id) = input.parse::<u64>() {
|
||||
return Ok(ParameterValue::UserRef(user_id));
|
||||
}
|
||||
|
||||
static RE: std::sync::LazyLock<Regex> =
|
||||
std::sync::LazyLock::new(|| Regex::new(r"<@!?(\\d{17,19})>").unwrap());
|
||||
if let Some(captures) = RE.captures(&input) {
|
||||
return captures[1]
|
||||
.parse::<u64>()
|
||||
.map(|id| ParameterValue::UserRef(id))
|
||||
.map_err(|_| SmolStr::new("invalid user ID"));
|
||||
}
|
||||
|
||||
Err(SmolStr::new("invalid user ID"))
|
||||
}
|
||||
ParameterKind::MemberPrivacyTarget => MemberPrivacyTargetKind::from_str(input)
|
||||
.map(|target| ParameterValue::MemberPrivacyTarget(target.as_ref().into())),
|
||||
ParameterKind::GroupPrivacyTarget => GroupPrivacyTargetKind::from_str(input)
|
||||
|
|
@ -166,6 +189,9 @@ impl Display for Parameter {
|
|||
ParameterKind::OpaqueString => {
|
||||
write!(f, "[{}]", self.name)
|
||||
}
|
||||
ParameterKind::OpaqueInt => {
|
||||
write!(f, "[{}]", self.name)
|
||||
}
|
||||
ParameterKind::OpaqueStringRemainder => {
|
||||
write!(f, "[{}]...", self.name)
|
||||
}
|
||||
|
|
@ -174,6 +200,7 @@ impl Display for Parameter {
|
|||
ParameterKind::GroupRef => write!(f, "<target group>"),
|
||||
ParameterKind::GroupRefs => write!(f, "<group 1> <group 2> <group 3>..."),
|
||||
ParameterKind::SystemRef => write!(f, "<target system>"),
|
||||
ParameterKind::UserRef => write!(f, "<target user>"),
|
||||
ParameterKind::MessageRef => write!(f, "<target message>"),
|
||||
ParameterKind::ChannelRef => write!(f, "<target channel>"),
|
||||
ParameterKind::GuildRef => write!(f, "<target guild>"),
|
||||
|
|
@ -246,12 +273,14 @@ impl<P: Into<Parameter>> From<Skip<P>> for Parameter {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ParameterKind {
|
||||
OpaqueString,
|
||||
OpaqueInt,
|
||||
OpaqueStringRemainder,
|
||||
MemberRef,
|
||||
MemberRefs,
|
||||
GroupRef,
|
||||
GroupRefs,
|
||||
SystemRef,
|
||||
UserRef,
|
||||
MessageRef,
|
||||
ChannelRef,
|
||||
GuildRef,
|
||||
|
|
@ -267,12 +296,14 @@ impl ParameterKind {
|
|||
pub(crate) fn default_name(&self) -> &str {
|
||||
match self {
|
||||
ParameterKind::OpaqueString => "string",
|
||||
ParameterKind::OpaqueInt => "number",
|
||||
ParameterKind::OpaqueStringRemainder => "string",
|
||||
ParameterKind::MemberRef => "target",
|
||||
ParameterKind::MemberRefs => "targets",
|
||||
ParameterKind::GroupRef => "target",
|
||||
ParameterKind::GroupRefs => "targets",
|
||||
ParameterKind::SystemRef => "target",
|
||||
ParameterKind::UserRef => "target",
|
||||
ParameterKind::MessageRef => "target",
|
||||
ParameterKind::ChannelRef => "target",
|
||||
ParameterKind::GuildRef => "target",
|
||||
|
|
|
|||
|
|
@ -260,11 +260,13 @@ fn command_callback_to_name(cb: &str) -> String {
|
|||
fn get_param_ty(kind: ParameterKind) -> &'static str {
|
||||
match kind {
|
||||
ParameterKind::OpaqueString | ParameterKind::OpaqueStringRemainder => "string",
|
||||
ParameterKind::OpaqueInt => "int",
|
||||
ParameterKind::MemberRef => "PKMember",
|
||||
ParameterKind::MemberRefs => "List<PKMember>",
|
||||
ParameterKind::GroupRef => "PKGroup",
|
||||
ParameterKind::GroupRefs => "List<PKGroup>",
|
||||
ParameterKind::SystemRef => "PKSystem",
|
||||
ParameterKind::UserRef => "User",
|
||||
ParameterKind::MemberPrivacyTarget => "MemberPrivacySubject",
|
||||
ParameterKind::GroupPrivacyTarget => "GroupPrivacySubject",
|
||||
ParameterKind::SystemPrivacyTarget => "SystemPrivacySubject",
|
||||
|
|
@ -280,11 +282,13 @@ fn get_param_ty(kind: ParameterKind) -> &'static str {
|
|||
fn get_param_param_ty(kind: ParameterKind) -> &'static str {
|
||||
match kind {
|
||||
ParameterKind::OpaqueString | ParameterKind::OpaqueStringRemainder => "Opaque",
|
||||
ParameterKind::OpaqueInt => "Number",
|
||||
ParameterKind::MemberRef => "Member",
|
||||
ParameterKind::MemberRefs => "Members",
|
||||
ParameterKind::GroupRef => "Group",
|
||||
ParameterKind::GroupRefs => "Groups",
|
||||
ParameterKind::SystemRef => "System",
|
||||
ParameterKind::UserRef => "User",
|
||||
ParameterKind::MemberPrivacyTarget => "MemberPrivacyTarget",
|
||||
ParameterKind::GroupPrivacyTarget => "GroupPrivacyTarget",
|
||||
ParameterKind::SystemPrivacyTarget => "SystemPrivacyTarget",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ interface Parameter {
|
|||
GroupRef(string group);
|
||||
GroupRefs(sequence<string> groups);
|
||||
SystemRef(string system);
|
||||
UserRef(u64 user_id);
|
||||
MessageRef(u64? guild_id, u64? channel_id, u64 message_id);
|
||||
ChannelRef(u64 channel_id);
|
||||
GuildRef(u64 guild_id);
|
||||
|
|
@ -21,6 +22,7 @@ interface Parameter {
|
|||
SystemPrivacyTarget(string target);
|
||||
PrivacyLevel(string level);
|
||||
OpaqueString(string raw);
|
||||
OpaqueInt(i32 raw);
|
||||
Toggle(boolean toggle);
|
||||
Avatar(string avatar);
|
||||
Null();
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ pub enum Parameter {
|
|||
SystemRef {
|
||||
system: String,
|
||||
},
|
||||
UserRef {
|
||||
user_id: u64,
|
||||
},
|
||||
MessageRef {
|
||||
guild_id: Option<u64>,
|
||||
channel_id: Option<u64>,
|
||||
|
|
@ -63,6 +66,9 @@ pub enum Parameter {
|
|||
OpaqueString {
|
||||
raw: String,
|
||||
},
|
||||
OpaqueInt {
|
||||
raw: i32,
|
||||
},
|
||||
Toggle {
|
||||
toggle: bool,
|
||||
},
|
||||
|
|
@ -80,11 +86,13 @@ impl From<ParameterValue> for Parameter {
|
|||
ParameterValue::GroupRef(group) => Self::GroupRef { group },
|
||||
ParameterValue::GroupRefs(groups) => Self::GroupRefs { groups },
|
||||
ParameterValue::SystemRef(system) => Self::SystemRef { system },
|
||||
ParameterValue::UserRef(user_id) => Self::UserRef { user_id },
|
||||
ParameterValue::MemberPrivacyTarget(target) => Self::MemberPrivacyTarget { target },
|
||||
ParameterValue::GroupPrivacyTarget(target) => Self::GroupPrivacyTarget { target },
|
||||
ParameterValue::SystemPrivacyTarget(target) => Self::SystemPrivacyTarget { target },
|
||||
ParameterValue::PrivacyLevel(level) => Self::PrivacyLevel { level },
|
||||
ParameterValue::OpaqueString(raw) => Self::OpaqueString { raw },
|
||||
ParameterValue::OpaqueInt(raw) => Self::OpaqueInt { raw },
|
||||
ParameterValue::Toggle(toggle) => Self::Toggle { toggle },
|
||||
ParameterValue::Avatar(avatar) => Self::Avatar { avatar },
|
||||
ParameterValue::MessageRef(guild_id, channel_id, message_id) => Self::MessageRef {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue