From 96e31a19ec1f058758da3461e20509646c01fed1 Mon Sep 17 00:00:00 2001 From: anthorob Date: Wed, 18 Dec 2024 11:44:23 -0500 Subject: [PATCH] fix: add missing checks for command usage --- .../core/command/CommandProcessor.java | 85 ++++++++++++------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java b/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java index 58b26b0..96ec623 100644 --- a/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java +++ b/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java @@ -61,7 +61,7 @@ public class CommandProcessor { } try { - logger.info("Context ID: {}", context.getId()); + logger.info("{} ID: {}", context.getClass().getSimpleName(), context.getId()); logger.info("Executing command {} on guild {}", command.getCommandName(), context.getGuild() == null ? "PrivateMessage" : context.getGuild().getId()); configureSentry(command); @@ -110,46 +110,68 @@ public class CommandProcessor { } private boolean checkUsage(CommandOptions commandOptions) { + List groups = commandOptions.getSubcommandGroups(); + List subcommands = commandOptions.getSubcommands(); + List options = commandOptions.getOptions(); String[] possibleCommands = Arrays.stream(context.getFullCommand().split(" ")).skip(1).toArray(String[]::new); if (possibleCommands.length == 0) { - if (!commandOptions.getSubcommandGroups().isEmpty()) { - context.reply(String.format("Invalid usage for command: missing subcommand.\n" + - "Use **/help %s** for information on how to use this command", context.getCommand().getCommandName())); + if (!groups.isEmpty()) { + // missing subcommand group + context.reply(invalidUsage("missing subcommand group")); return false; } - if (!commandOptions.getSubcommands().isEmpty()) { - context.reply(String.format("Invalid usage for command: missing subcommand.\n" + - "Use **/help %s** for information on how to use this command", context.getCommand().getCommandName())); + if (!subcommands.isEmpty()) { + // missing subcommand + context.reply(invalidUsage("missing subcommand")); return false; } - return checkOptions(possibleCommands, 0, commandOptions.getOptions()); + return checkOptions(possibleCommands, 0, options); } - SubcommandGroupData group = commandOptions.getSubcommandGroups().stream().filter(data -> data.getName().equals(possibleCommands[0])).findFirst().orElse(null); - if (group != null) { - if (possibleCommands.length < 2) { - context.reply(String.format("Invalid usage for command: missing subcommand.\n" + - "Use **/help %s** for information on how to use this command", context.getCommand().getCommandName())); - return false; // missing subcommand + SubcommandGroupData group = groups.stream().filter(data -> data.getName().equals(possibleCommands[0])).findFirst().orElse(null); + if (group == null) { + SubcommandData subcommand = subcommands.stream().filter(data -> data.getName().equals(possibleCommands[0])).findFirst().orElse(null); + if (subcommand == null) { + if (!groups.isEmpty()) { + // no group found but one is expected + context.reply(invalidUsage("unknown subcommand group")); + return false; + } + + if (!subcommands.isEmpty()) { + // no subcommand found but one is expected + context.reply(invalidUsage("unknown subcommand")); + return false; + } + + // no group found, no subcommand found, command with options only + return checkOptions(possibleCommands, 0, options); } - SubcommandData subcommand = group.getSubcommands().stream().filter(data -> data.getName().equals(possibleCommands[1])).findFirst().orElse(null); - if (subcommand != null) { - context.setSubcommandGroup(group); - context.setSubcommand(subcommand); - return checkOptions(possibleCommands, 2, subcommand.getOptions()); - } - } - - SubcommandData subcommand = commandOptions.getSubcommands().stream().filter(data -> data.getName().equals(possibleCommands[0])).findFirst().orElse(null); - if (subcommand != null) { + // no group found, subcommand found context.setSubcommand(subcommand); return checkOptions(possibleCommands, 1, subcommand.getOptions()); } - return checkOptions(possibleCommands, 0, commandOptions.getOptions()); + if (possibleCommands.length < 2) { + // missing subcommand for group + context.reply(invalidUsage("missing subcommand for command group")); + return false; + } + + SubcommandData subcommand = group.getSubcommands().stream().filter(data -> data.getName().equals(possibleCommands[1])).findFirst().orElse(null); + if (subcommand == null) { + // group found, no subcommand found + context.reply(invalidUsage("unknown subcommand in command group")); + return false; + } + + // group found, subcommand found + context.setSubcommandGroup(group); + context.setSubcommand(subcommand); + return checkOptions(possibleCommands, 2, subcommand.getOptions()); } private boolean checkOptions(String[] args, int skip, List options) { @@ -163,8 +185,7 @@ public class CommandProcessor { int optional = options.stream().filter(not(OptionData::isRequired)).toList().size(); if (arguments.size() < required) { - context.reply(String.format("Invalid usage for command: missing one or more required arguments\n" + - "Use **/help %s** for information on how to use this command", context.getCommand().getCommandName())); + context.reply(invalidUsage("missing one or more required arguments")); return false; } @@ -180,8 +201,7 @@ public class CommandProcessor { } if (arguments.size() > required + optional) { - context.reply(String.format("Invalid usage for command: too many arguments\n" + - "Use **/help %s** for information on how to use this command", context.getCommand().getCommandName())); + context.reply(invalidUsage("too many arguments")); return false; } @@ -195,7 +215,7 @@ public class CommandProcessor { } if (context instanceof SlashCommandContext) { - return true; // no further check since slash perms are handled by guild settings + return true; // no further checks since slash perms are handled by guild settings on discord } if (command.canBeExecutedBy(context.getGuildUser())) { @@ -205,6 +225,11 @@ public class CommandProcessor { return command.needAdmin() && UserFunction.isAdmin(context.getGuildUser()); } + private String invalidUsage(String message) { + return String.format("Invalid usage for command: %s\n" + + "Use **/help %s** for information on how to use this command", message, context.getCommand().getCommandName()); + } + private void configureSentry(Command command) { Sentry.configureScope(scope -> { scope.setTag("command", command.getCommandName());