mirror of
https://github.com/NoiTheCat/BirthdayBot.git
synced 2024-11-21 13:54:36 +00:00
Add certain command overrides, matching existing options available via text commands
This commit is contained in:
parent
d27663a20a
commit
42399e423c
3 changed files with 185 additions and 6 deletions
|
@ -39,11 +39,14 @@ internal class RegistrationCommands : BotApplicationCommand {
|
||||||
public override CommandResponder? GetHandlerFor(string commandName) => commandName switch {
|
public override CommandResponder? GetHandlerFor(string commandName) => commandName switch {
|
||||||
"set-birthday" => CmdSetBirthday,
|
"set-birthday" => CmdSetBirthday,
|
||||||
"set-timezone" => CmdSetTimezone,
|
"set-timezone" => CmdSetTimezone,
|
||||||
"remove-timezone" => CmdDelTimezone,
|
"remove-timezone" => CmdDelTz,
|
||||||
"remove-birthday" => CmdRemove,
|
"remove-birthday" => CmdDelBd,
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Note that the following subcommands have largely been copied to RegistrationOverrideCommands.
|
||||||
|
// Any changes made here should be reflected there, if appropriate.
|
||||||
|
|
||||||
private static async Task CmdSetBirthday(ShardInstance instance, GuildConfiguration gconf, SocketSlashCommand arg) {
|
private static async Task CmdSetBirthday(ShardInstance instance, GuildConfiguration gconf, SocketSlashCommand arg) {
|
||||||
int inmonth, inday;
|
int inmonth, inday;
|
||||||
try {
|
try {
|
||||||
|
@ -91,7 +94,7 @@ internal class RegistrationCommands : BotApplicationCommand {
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task CmdDelTimezone(ShardInstance instance, GuildConfiguration gconf, SocketSlashCommand arg) {
|
private static async Task CmdDelTz(ShardInstance instance, GuildConfiguration gconf, SocketSlashCommand arg) {
|
||||||
var u = await GuildUserConfiguration.LoadAsync(gconf.GuildId, arg.User.Id).ConfigureAwait(false);
|
var u = await GuildUserConfiguration.LoadAsync(gconf.GuildId, arg.User.Id).ConfigureAwait(false);
|
||||||
if (!u.IsKnown) {
|
if (!u.IsKnown) {
|
||||||
await arg.RespondAsync(":white_check_mark: " + MsgNoData);
|
await arg.RespondAsync(":white_check_mark: " + MsgNoData);
|
||||||
|
@ -103,7 +106,7 @@ internal class RegistrationCommands : BotApplicationCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task CmdRemove(ShardInstance instance, GuildConfiguration gconf, SocketSlashCommand arg) {
|
private static async Task CmdDelBd(ShardInstance instance, GuildConfiguration gconf, SocketSlashCommand arg) {
|
||||||
var u = await GuildUserConfiguration.LoadAsync(gconf.GuildId, arg.User.Id).ConfigureAwait(false);
|
var u = await GuildUserConfiguration.LoadAsync(gconf.GuildId, arg.User.Id).ConfigureAwait(false);
|
||||||
if (u.IsKnown) {
|
if (u.IsKnown) {
|
||||||
await u.DeleteAsync().ConfigureAwait(false);
|
await u.DeleteAsync().ConfigureAwait(false);
|
||||||
|
|
174
ApplicationCommands/RegistrationOverrideCommands.cs
Normal file
174
ApplicationCommands/RegistrationOverrideCommands.cs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
using BirthdayBot.Data;
|
||||||
|
|
||||||
|
namespace BirthdayBot.ApplicationCommands;
|
||||||
|
|
||||||
|
internal class RegistrationOverrideCommands : BotApplicationCommand {
|
||||||
|
private delegate Task SubCommandHandler(GuildConfiguration gconf, SocketSlashCommand arg, Dictionary<string, object> subparam);
|
||||||
|
|
||||||
|
#region Help strings
|
||||||
|
public const string HelpOverride = "Run certain commands on behalf of other users.";
|
||||||
|
|
||||||
|
const string HelpOptTarget = "The user whose data to modify.";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public override IEnumerable<ApplicationCommandProperties> GetCommands() => new ApplicationCommandProperties[] {
|
||||||
|
new SlashCommandBuilder()
|
||||||
|
.WithName("override")
|
||||||
|
.WithDescription(HelpPfxModOnly + HelpOverride)
|
||||||
|
.AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("set-birthday")
|
||||||
|
.WithDescription(HelpPfxModOnly + "Sets or updates a user's birthday on their behalf.")
|
||||||
|
.WithType(ApplicationCommandOptionType.SubCommand)
|
||||||
|
.AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("target")
|
||||||
|
.WithType(ApplicationCommandOptionType.User)
|
||||||
|
.WithDescription("The target user whose birthday to modify.")
|
||||||
|
.WithRequired(true)
|
||||||
|
).AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("date")
|
||||||
|
.WithType(ApplicationCommandOptionType.String)
|
||||||
|
.WithDescription(RegistrationCommands.HelpOptDate)
|
||||||
|
.WithRequired(true)
|
||||||
|
)
|
||||||
|
).AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("set-timezone")
|
||||||
|
.WithDescription(HelpPfxModOnly + "Sets or updates a user's time zone on their behalf.")
|
||||||
|
.WithType(ApplicationCommandOptionType.SubCommand)
|
||||||
|
.AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("target")
|
||||||
|
.WithType(ApplicationCommandOptionType.User)
|
||||||
|
.WithDescription(HelpOptTarget)
|
||||||
|
.WithRequired(true)
|
||||||
|
).AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("zone")
|
||||||
|
.WithType(ApplicationCommandOptionType.String)
|
||||||
|
.WithDescription(RegistrationCommands.HelpOptZone)
|
||||||
|
.WithRequired(true)
|
||||||
|
)
|
||||||
|
).AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("remove-timezone")
|
||||||
|
.WithDescription(HelpPfxModOnly + "Removes a user's time zone on their behalf.")
|
||||||
|
.WithType(ApplicationCommandOptionType.SubCommand)
|
||||||
|
.AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("target")
|
||||||
|
.WithType(ApplicationCommandOptionType.User)
|
||||||
|
.WithDescription(HelpOptTarget)
|
||||||
|
.WithRequired(true)
|
||||||
|
)
|
||||||
|
).AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("remove-birthday")
|
||||||
|
.WithDescription(HelpPfxModOnly + "Removes a user's data from the bot on their behalf.")
|
||||||
|
.WithType(ApplicationCommandOptionType.SubCommand)
|
||||||
|
.AddOption(new SlashCommandOptionBuilder()
|
||||||
|
.WithName("target")
|
||||||
|
.WithType(ApplicationCommandOptionType.User)
|
||||||
|
.WithDescription(HelpOptTarget)
|
||||||
|
.WithRequired(true)
|
||||||
|
)
|
||||||
|
).Build()
|
||||||
|
};
|
||||||
|
public override CommandResponder? GetHandlerFor(string commandName) => commandName switch {
|
||||||
|
"override" => CmdOverride,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Personally, this confuses me. So here are some notes:
|
||||||
|
* arg.Data.Options contains the SubCommand and only the SubCommand. Its name is the subcommand's name.
|
||||||
|
* arg.Data.Options.Options then contains the options. "target" and others, all within the same collection.
|
||||||
|
*/
|
||||||
|
private Task CmdOverride(ShardInstance instance, GuildConfiguration gconf, SocketSlashCommand arg) {
|
||||||
|
SubCommandHandler? subh = arg.Data.Options.First().Name switch {
|
||||||
|
"set-birthday" => SubCmdSetBd,
|
||||||
|
"set-timezone" => SubCmdSetTz,
|
||||||
|
"remove-timezone" => SubCmdDelTz,
|
||||||
|
"remove-birthday" => SubCmdDelBd,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (subh == null) {
|
||||||
|
instance.Log($"{nameof(RegistrationOverrideCommands)}", $"Encountered unknown subcommand {arg.Data.Name}");
|
||||||
|
return arg.RespondAsync(ShardInstance.UnknownCommandError, ephemeral: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var subparam = ((SocketSlashCommandDataOption)arg.Data.Options.First()).Options.ToDictionary(o => o.Name, o => o.Value);
|
||||||
|
return subh(gconf, arg, subparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that the following subcommands have largely been copied from RegistrationCommands.
|
||||||
|
// Any changes made there should be reflected here, if appropriate.
|
||||||
|
// TODO A common base class might be more appropriate...
|
||||||
|
|
||||||
|
private async Task SubCmdSetBd(GuildConfiguration gconf, SocketSlashCommand arg, Dictionary<string, object> subparam) {
|
||||||
|
var target = (SocketGuildUser)subparam["target"];
|
||||||
|
int inmonth, inday;
|
||||||
|
try {
|
||||||
|
(inmonth, inday) = ParseDate((string)subparam["date"]);
|
||||||
|
} catch (FormatException e) {
|
||||||
|
// Our parse method's FormatException has its message to send out to Discord.
|
||||||
|
arg.RespondAsync(e.Message).Wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool known;
|
||||||
|
try {
|
||||||
|
var user = await GuildUserConfiguration.LoadAsync(gconf.GuildId, target.Id).ConfigureAwait(false);
|
||||||
|
known = user.IsKnown;
|
||||||
|
await user.UpdateAsync(inmonth, inday, user.TimeZone).ConfigureAwait(false);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Program.Log("Error", ex.ToString());
|
||||||
|
arg.RespondAsync(ShardInstance.InternalError).Wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await arg.RespondAsync($":white_check_mark: {target}'s birthday has been " +
|
||||||
|
$"{ (known ? "updated to" : "recorded as") } **{inday:00}-{Common.MonthNames[inmonth]}**.").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SubCmdSetTz(GuildConfiguration gconf, SocketSlashCommand arg, Dictionary<string, object> subparam) {
|
||||||
|
var target = (SocketGuildUser)subparam["target"];
|
||||||
|
var user = await GuildUserConfiguration.LoadAsync(gconf.GuildId, target.Id).ConfigureAwait(false);
|
||||||
|
if (!user.IsKnown) {
|
||||||
|
await arg.RespondAsync(":x: The user must have a birthday set before you can use this command.",
|
||||||
|
ephemeral: true).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool hasZone = user.TimeZone != null;
|
||||||
|
|
||||||
|
string inZone;
|
||||||
|
try {
|
||||||
|
inZone = ParseTimeZone((string)subparam["zone"]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
arg.RespondAsync(e.Message).Wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await user.UpdateAsync(user.BirthMonth, user.BirthDay, inZone).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await arg.RespondAsync($":white_check_mark: {target}'s time zone has been { (hasZone ? "updated" : "set") } to **{inZone}**.")
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SubCmdDelTz(GuildConfiguration gconf, SocketSlashCommand arg, Dictionary<string, object> subparam) {
|
||||||
|
var target = (SocketGuildUser)subparam["target"];
|
||||||
|
var u = await GuildUserConfiguration.LoadAsync(gconf.GuildId, target.Id).ConfigureAwait(false);
|
||||||
|
if (!u.IsKnown) {
|
||||||
|
await arg.RespondAsync(":white_check_mark: User is not registered. Nothing to remove.");
|
||||||
|
} else if (u.TimeZone is null) {
|
||||||
|
await arg.RespondAsync(":white_check_mark: User does not have zone registered. Nothing to remove.");
|
||||||
|
} else {
|
||||||
|
await u.UpdateAsync(u.BirthMonth, u.BirthDay, null);
|
||||||
|
await arg.RespondAsync($":white_check_mark: {target}'s time zone information has been removed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SubCmdDelBd(GuildConfiguration gconf, SocketSlashCommand arg, Dictionary<string, object> subparam) {
|
||||||
|
var target = (SocketGuildUser)subparam["target"];
|
||||||
|
var u = await GuildUserConfiguration.LoadAsync(gconf.GuildId, target.Id).ConfigureAwait(false);
|
||||||
|
if (u.IsKnown) {
|
||||||
|
await u.DeleteAsync().ConfigureAwait(false);
|
||||||
|
await arg.RespondAsync($":white_check_mark: {target}'s birthday information has been removed.");
|
||||||
|
} else {
|
||||||
|
await arg.RespondAsync(":white_check_mark: User is not registered. Nothing to remove.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ class ShardInstance : IDisposable {
|
||||||
public Configuration Config => _manager.Config;
|
public Configuration Config => _manager.Config;
|
||||||
|
|
||||||
public const string InternalError = ":x: An unknown error occurred. If it persists, please notify the bot owner.";
|
public const string InternalError = ":x: An unknown error occurred. If it persists, please notify the bot owner.";
|
||||||
|
public const string UnknownCommandError = "Oops, that command isn't supposed to be there... Please try something else.";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prepares and configures the shard instances, but does not yet start its connection.
|
/// Prepares and configures the shard instances, but does not yet start its connection.
|
||||||
|
@ -132,10 +133,11 @@ class ShardInstance : IDisposable {
|
||||||
foreach (var g in DiscordClient.Guilds) {
|
foreach (var g in DiscordClient.Guilds) {
|
||||||
await g.DeleteApplicationCommandsAsync().ConfigureAwait(false);
|
await g.DeleteApplicationCommandsAsync().ConfigureAwait(false);
|
||||||
await g.BulkOverwriteApplicationCommandAsync(commands.ToArray()).ConfigureAwait(false);
|
await g.BulkOverwriteApplicationCommandAsync(commands.ToArray()).ConfigureAwait(false);
|
||||||
|
Log("Command registration", $"Sent bulk overrides for {commands.Count} commands.");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var gcmd in await DiscordClient.GetGlobalApplicationCommandsAsync()) {
|
foreach (var gcmd in await DiscordClient.GetGlobalApplicationCommandsAsync()) {
|
||||||
Program.Log("Command registration", $"Found global command /{gcmd.Name} and we're DEBUG - sending removal request");
|
Log("Command registration", $"Found global command /{gcmd.Name} and we're DEBUG - sending removal request");
|
||||||
await gcmd.DeleteAsync();
|
await gcmd.DeleteAsync();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -210,7 +212,7 @@ class ShardInstance : IDisposable {
|
||||||
|
|
||||||
if (handler == null) { // Handler not found
|
if (handler == null) { // Handler not found
|
||||||
Log("Command", logLine + " Unknown command.");
|
Log("Command", logLine + " Unknown command.");
|
||||||
await arg.RespondAsync("Oops, that command isn't supposed to be there... Please try something else.",
|
await arg.RespondAsync(UnknownCommandError,
|
||||||
ephemeral: true).ConfigureAwait(false);
|
ephemeral: true).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue