feat: better parameters handling, implement multi-token matching

This commit is contained in:
dusk 2025-01-07 23:15:18 +09:00
parent b29c51f103
commit 482c923507
No known key found for this signature in database
14 changed files with 521 additions and 251 deletions

View file

@ -26,11 +26,9 @@ public class Context
private readonly IMetrics _metrics;
private readonly CommandMessageService _commandMessageService;
private Command? _currentCommand;
public Context(ILifetimeScope provider, int shardId, Guild? guild, Channel channel, MessageCreateEvent message,
int commandParseOffset, PKSystem senderSystem, SystemConfig config,
GuildConfig? guildConfig, string[] prefixes)
GuildConfig? guildConfig, string[] prefixes, Parameters parameters)
{
Message = (Message)message;
ShardId = shardId;
@ -50,6 +48,7 @@ public class Context
DefaultPrefix = prefixes[0];
Rest = provider.Resolve<DiscordApiClient>();
Cluster = provider.Resolve<Cluster>();
Parameters = parameters;
}
public readonly IDiscordCache Cache;
@ -75,6 +74,7 @@ public class Context
public readonly string CommandPrefix;
public readonly string DefaultPrefix;
public readonly Parameters Parameters;
internal readonly IDatabase Database;
internal readonly ModelRepository Repository;
@ -111,8 +111,6 @@ public class Context
public async Task Execute<T>(Command? commandDef, Func<T, Task> handler, bool deprecated = false)
{
_currentCommand = commandDef;
if (deprecated && commandDef != null)
{
await Reply($"{Emojis.Warn} Server configuration has moved to `{DefaultPrefix}serverconfig`. The command you are trying to run is now `{DefaultPrefix}{commandDef.Key}`.");
@ -153,8 +151,8 @@ public class Context
public LookupContext LookupContextFor(SystemId systemId)
{
var hasPrivateOverride = this.MatchFlag("private", "priv");
var hasPublicOverride = this.MatchFlag("public", "pub");
var hasPrivateOverride = Parameters.HasFlag("private", "priv");
var hasPublicOverride = Parameters.HasFlag("public", "pub");
if (hasPrivateOverride && hasPublicOverride)
throw new PKError("Cannot match both public and private flags at the same time.");

View file

@ -59,7 +59,7 @@ public static class ContextEntityArgumentsExt
return null;
}
public static async Task<PKMember> ParseMember(this Context ctx, Parameters parameters, string input, SystemId? restrictToSystem = null)
public static async Task<PKMember> ParseMember(this Context ctx, string input, bool byId, SystemId? restrictToSystem = null)
{
// Member references can have one of three forms, depending on
// whether you're in a system or not:
@ -69,7 +69,7 @@ public static class ContextEntityArgumentsExt
// Skip name / display name matching if the user does not have a system
// or if they specifically request by-HID matching
if (ctx.System != null && !parameters.HasFlag("id", "by-id"))
if (ctx.System != null && !byId)
{
// First, try finding by member name in system
if (await ctx.Repository.GetMemberByName(ctx.System.Id, input) is PKMember memberByName)
@ -169,9 +169,9 @@ public static class ContextEntityArgumentsExt
return group;
}
public static string CreateNotFoundError(this Context ctx, Parameters parameters, string entity, string input)
public static string CreateNotFoundError(this Context ctx, string entity, string input, bool byId = false)
{
var isIDOnlyQuery = ctx.System == null || parameters.HasFlag("id", "by-id");
var isIDOnlyQuery = ctx.System == null || byId;
var inputIsHid = HidUtils.ParseHid(input) != null;
if (isIDOnlyQuery)

View file

@ -0,0 +1,64 @@
using PluralKit.Core;
namespace PluralKit.Bot;
public static class ContextParametersExt
{
public static async Task<string?> ParamResolveOpaque(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter(
ctx, param_name,
param => (param as Parameter.Opaque)?.value
);
}
public static async Task<PKMember?> ParamResolveMember(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter(
ctx, param_name,
param => (param as Parameter.MemberRef)?.member
);
}
public static async Task<PKSystem?> ParamResolveSystem(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter(
ctx, param_name,
param => (param as Parameter.SystemRef)?.system
);
}
public static async Task<MemberPrivacySubject?> ParamResolveMemberPrivacyTarget(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter(
ctx, param_name,
param => (param as Parameter.MemberPrivacyTarget)?.target
);
}
public static async Task<string?> ParamResolvePrivacyLevel(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter(
ctx, param_name,
param => (param as Parameter.PrivacyLevel)?.level
);
}
public static async Task<bool?> ParamResolveToggle(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter(
ctx, param_name,
param => (param as Parameter.Toggle)?.value
);
}
// this can never really be false (either it's present and is true or it's not present)
// but we keep it nullable for consistency with the other methods
public static async Task<bool?> ParamResolveReset(this Context ctx, string param_name)
{
return await ctx.Parameters.ResolveParameter<bool?>(
ctx, param_name,
param => param is Parameter.Reset
);
}
}