diff --git a/src/main/java/net/pingex/dcf/commands/AnnotatedCommand.java b/src/main/java/net/pingex/dcf/commands/AnnotatedCommand.java index 1191cd5..1e914ba 100644 --- a/src/main/java/net/pingex/dcf/commands/AnnotatedCommand.java +++ b/src/main/java/net/pingex/dcf/commands/AnnotatedCommand.java @@ -42,4 +42,9 @@ public @interface AnnotatedCommand * Default permission, ie. when the permissions provider doesn't return anything. */ DefaultPermission defaultPermission() default DefaultPermission.EVERYONE; + + /** + * Tells where the command should run, ie. PM or guild chat, or both + */ + CommandScope scope() default CommandScope.NOWHERE; } diff --git a/src/main/java/net/pingex/dcf/commands/Command.java b/src/main/java/net/pingex/dcf/commands/Command.java index cf12efe..d812ee6 100644 --- a/src/main/java/net/pingex/dcf/commands/Command.java +++ b/src/main/java/net/pingex/dcf/commands/Command.java @@ -42,6 +42,11 @@ public abstract class Command implements ICommandExecutor */ private DefaultPermission defaultPermission; + /** + * Tells where the command should run, ie. PM or guild chat, or both + */ + private CommandScope commandScope; + /** * Basic constructor. * @param name Name of the command @@ -50,8 +55,9 @@ public abstract class Command implements ICommandExecutor * @param isEnabled Is the command enabled ? * @param usage Command usage help * @param defaultPermission Default permission, ie. when the permissions provider doesn't return anything. + * @param commandScope Tells where the command should run, ie. PM or guild chat, or both */ - public Command(String name, List aliases, String description, boolean isEnabled, String usage, DefaultPermission defaultPermission) + public Command(String name, List aliases, String description, boolean isEnabled, String usage, DefaultPermission defaultPermission, CommandScope commandScope) { this.name = name; this.aliases = aliases; @@ -59,6 +65,7 @@ public abstract class Command implements ICommandExecutor this.isEnabled = isEnabled; this.usage = usage; this.defaultPermission = defaultPermission; + this.commandScope = commandScope; } /** @@ -71,6 +78,7 @@ public abstract class Command implements ICommandExecutor public static final boolean IS_ENABLED = true; public static final String USAGE = "No command usage provided."; public static final DefaultPermission DEFAULT_PERMISSION = DefaultPermission.EVERYONE; + public static final CommandScope COMMAND_SCOPE = CommandScope.NOWHERE; // NOWHERE is enforced as a default value to force devs to specify a real scope. } /** @@ -108,6 +116,11 @@ public abstract class Command implements ICommandExecutor */ private DefaultPermission defaultPermission = Defaults.DEFAULT_PERMISSION; + /** + * Tells where the command should run, ie. PM or guild chat, or both + */ + private CommandScope commandScope = Defaults.COMMAND_SCOPE; + public Builder(String name) { this.name = name; @@ -153,6 +166,12 @@ public abstract class Command implements ICommandExecutor return this; } + public Builder commandScope(CommandScope commandScope) + { + this.commandScope = commandScope; + return this; + } + /** * Build a new Command using a supplied executor. * @param toExecute The body of the command. @@ -160,7 +179,7 @@ public abstract class Command implements ICommandExecutor */ public Command build(ICommandExecutor toExecute) { - return new Command(name, aliases, description, isEnabled, usage, defaultPermission) + return new Command(name, aliases, description, isEnabled, usage, defaultPermission, commandScope) { @Override public void execute(MessageReceivedEvent event, List arguments) throws Throwable @@ -178,7 +197,7 @@ public abstract class Command implements ICommandExecutor */ public Command build(Method target, Object invokable) { - return new Command(name, aliases, description, isEnabled, usage, defaultPermission) + return new Command(name, aliases, description, isEnabled, usage, defaultPermission, commandScope) { @Override public void execute(MessageReceivedEvent event, List arguments) throws Throwable @@ -212,6 +231,7 @@ public abstract class Command implements ICommandExecutor .enabled(meta.isEnabled()) .usage(meta.usage()) .defaultPermission(meta.defaultPermission()) + .commandScope(meta.scope()) .build(target, invokable); } @@ -245,6 +265,11 @@ public abstract class Command implements ICommandExecutor return defaultPermission; } + public CommandScope getScope() + { + return commandScope; + } + public void setEnabled(boolean enabled) { isEnabled = enabled; diff --git a/src/main/java/net/pingex/dcf/commands/CommandHandler.java b/src/main/java/net/pingex/dcf/commands/CommandHandler.java index 154a203..103727a 100644 --- a/src/main/java/net/pingex/dcf/commands/CommandHandler.java +++ b/src/main/java/net/pingex/dcf/commands/CommandHandler.java @@ -75,6 +75,14 @@ public class CommandHandler return; } + // Scope check + if(!targetCommand.get().getScope().test(event.getMessage().getChannel())) + { + LOGGER.debug("User {} attempted to run a command outside of its intended scope.", event.getMessage().getAuthor().getID()); + DiscordInteractionsUtil.sendMessage(event.getMessage().getChannel(), "Cannot run this command outside of its intended scope. Valid scope is: " + targetCommand.get().getScope() + "."); + return; + } + // Authorize if(!PermissionsHandler.canRunCommand(event.getMessage(), targetCommand.get())) { diff --git a/src/main/java/net/pingex/dcf/commands/CommandScope.java b/src/main/java/net/pingex/dcf/commands/CommandScope.java new file mode 100644 index 0000000..885c776 --- /dev/null +++ b/src/main/java/net/pingex/dcf/commands/CommandScope.java @@ -0,0 +1,45 @@ +package net.pingex.dcf.commands; + +import sx.blah.discord.handle.obj.IChannel; + +import java.util.function.Predicate; + +/** + * CommandScope allows devs to tell where Commands should run. + * ie. PM, guild chat, etc + */ +public enum CommandScope +{ + /** + * Allows only in a guild chat + */ + GUILD_CHAT(iChannel -> !iChannel.isPrivate()), + + /** + * Only via PM with the bot + */ + PRIVATE_MESSAGE(IChannel::isPrivate), + + /** + * Allows unconditionally + */ + ANYWHERE(iChannel -> true), + + /** + * Denies unconditionally + * Default value + */ + NOWHERE(iChannel -> false); + + private Predicate channel; + + CommandScope(Predicate channel) + { + this.channel = channel; + } + + public boolean test(IChannel iChannel) + { + return channel.test(iChannel); + } +} diff --git a/src/main/java/net/pingex/dcf/commands/InternalCommands.java b/src/main/java/net/pingex/dcf/commands/InternalCommands.java index c84d6c6..45d68c1 100644 --- a/src/main/java/net/pingex/dcf/commands/InternalCommands.java +++ b/src/main/java/net/pingex/dcf/commands/InternalCommands.java @@ -32,6 +32,7 @@ public class InternalCommands implements IWithCommands private static final boolean IS_ENABLED = true; private static final String USAGE = "Page"; private static final DefaultPermission DEFAULT_PERMISSION = DefaultPermission.EVERYONE; + private static final CommandScope COMMAND_SCOPE = CommandScope.ANYWHERE; /** * How many commands should be displayed on each page @@ -42,7 +43,7 @@ public class InternalCommands implements IWithCommands private ListCommand() { - super(NAME, ALIASES, DESCRIPTION, IS_ENABLED, USAGE, DEFAULT_PERMISSION); + super(NAME, ALIASES, DESCRIPTION, IS_ENABLED, USAGE, DEFAULT_PERMISSION, COMMAND_SCOPE); } @Override @@ -113,12 +114,13 @@ public class InternalCommands implements IWithCommands private static final boolean IS_ENABLED = true; private static final String USAGE = "Command"; private static final DefaultPermission DEFAULT_PERMISSION = DefaultPermission.EVERYONE; + private static final CommandScope COMMAND_SCOPE = CommandScope.ANYWHERE; static final UsageCommand INSTANCE = new UsageCommand(); private UsageCommand() { - super(NAME, ALIASES, DESCRIPTION, IS_ENABLED, USAGE, DEFAULT_PERMISSION); + super(NAME, ALIASES, DESCRIPTION, IS_ENABLED, USAGE, DEFAULT_PERMISSION, COMMAND_SCOPE); } @Override