diff --git a/pom.xml b/pom.xml index 161303b7..1a071ae7 100644 --- a/pom.xml +++ b/pom.xml @@ -106,5 +106,16 @@ annotations 24.0.1 + + + ch.qos.logback + logback-classic + 1.4.6 + + + ch.qos.logback + logback-core + 1.4.6 + diff --git a/src/examples/embeds.json b/src/examples/embeds.json index 3916ecfd..25d07091 100644 --- a/src/examples/embeds.json +++ b/src/examples/embeds.json @@ -1,7 +1,7 @@ { "insufficientPermissions": { "title": "Insufficient Permissions", - "description": "`{prefix}{label}` requires specific permissions to be executed", + "description": "`{name}` requires specific permissions to be executed", "color": "#ff0000", "fields": [ { @@ -10,21 +10,6 @@ } ] }, - "guildMuted": { - "title": "Insufficient Permissions", - "description": "This guild is muted!", - "color": "#ff0000" - }, - "channelMuted": { - "title": "Insufficient Permissions", - "description": "This channel is muted!", - "color": "#ff0000" - }, - "userMuted": { - "title": "Insufficient Permissions", - "description": "This channel is muted!", - "color": "#ff0000" - }, "typeAdaptingFailed": { "title": "Syntax Error", "description": "`{usage}`", diff --git a/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java b/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java index f9cc21ee..f8aabf22 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java +++ b/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java @@ -4,7 +4,7 @@ import com.github.kaktushose.jda.commands.dispatching.DispatcherSupervisor; import com.github.kaktushose.jda.commands.dispatching.RuntimeSupervisor; import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapterRegistry; -import com.github.kaktushose.jda.commands.dispatching.filter.FilterRegistry; +import com.github.kaktushose.jda.commands.dispatching.middleware.MiddlewareRegistry; import com.github.kaktushose.jda.commands.dispatching.validation.ValidatorRegistry; import com.github.kaktushose.jda.commands.reflect.ImplementationRegistry; import com.github.kaktushose.jda.commands.reflect.InteractionRegistry; @@ -30,7 +30,7 @@ public class JDACommands { private final JDAContext jdaContext; private final ImplementationRegistry implementationRegistry; private final DispatcherSupervisor dispatcherSupervisor; - private final FilterRegistry filterRegistry; + private final MiddlewareRegistry middlewareRegistry; private final TypeAdapterRegistry adapterRegistry; private final ValidatorRegistry validatorRegistry; private final DependencyInjector dependencyInjector; @@ -43,7 +43,7 @@ protected JDACommands() { jdaContext = null; implementationRegistry = null; runtimeSupervisor = null; - filterRegistry = null; + middlewareRegistry = null; adapterRegistry = null; validatorRegistry = null; dependencyInjector = null; @@ -63,12 +63,12 @@ private JDACommands(Object jda, Class clazz, LocalizationFunction function, S dependencyInjector = new DependencyInjector(); dependencyInjector.index(clazz, packages); - filterRegistry = new FilterRegistry(); + middlewareRegistry = new MiddlewareRegistry(); adapterRegistry = new TypeAdapterRegistry(); validatorRegistry = new ValidatorRegistry(); implementationRegistry = new ImplementationRegistry( dependencyInjector, - filterRegistry, + middlewareRegistry, adapterRegistry, validatorRegistry ); @@ -81,7 +81,7 @@ private JDACommands(Object jda, Class clazz, LocalizationFunction function, S interactionRegistry.index(clazz, packages); - updater = new SlashCommandUpdater(this); + updater = new SlashCommandUpdater(this, function); updater.updateAllCommands(); jdaContext.performTask(it -> it.addEventListener(dispatcherSupervisor)); @@ -225,12 +225,12 @@ public JDAContext getJdaContext() { } /** - * Gets the {@link FilterRegistry}. + * Gets the {@link MiddlewareRegistry}. * - * @return the {@link FilterRegistry} + * @return the {@link MiddlewareRegistry} */ - public FilterRegistry getFilterRegistry() { - return filterRegistry; + public MiddlewareRegistry getMiddlewareRegistry() { + return middlewareRegistry; } /** diff --git a/src/main/java/com/github/kaktushose/jda/commands/annotations/Component.java b/src/main/java/com/github/kaktushose/jda/commands/annotations/Implementation.java similarity index 70% rename from src/main/java/com/github/kaktushose/jda/commands/annotations/Component.java rename to src/main/java/com/github/kaktushose/jda/commands/annotations/Implementation.java index 5b9dec9f..6336c3f9 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/annotations/Component.java +++ b/src/main/java/com/github/kaktushose/jda/commands/annotations/Implementation.java @@ -1,7 +1,7 @@ package com.github.kaktushose.jda.commands.annotations; import com.github.kaktushose.jda.commands.annotations.constraints.Constraint; -import com.github.kaktushose.jda.commands.dispatching.filter.FilterRegistry.FilterPosition; +import com.github.kaktushose.jda.commands.dispatching.middleware.Priority; import com.github.kaktushose.jda.commands.reflect.ImplementationRegistry; import java.lang.annotation.*; @@ -16,16 +16,18 @@ */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -public @interface Component { +public @interface Implementation { /** - * Gets the {@link FilterPosition FilterPosition} to register the - * {@link com.github.kaktushose.jda.commands.dispatching.filter.Filter Filter} at. If the component is not a subtype - * of {@link com.github.kaktushose.jda.commands.dispatching.filter.Filter Filter}, this field can be ignored. + * Gets the {@link Priority} to register the + * {@link com.github.kaktushose.jda.commands.dispatching.middleware.Middleware Middleware} with. If this + * implementation is not a subtype + * of {@link com.github.kaktushose.jda.commands.dispatching.middleware.Middleware Middleware}, this field can be + * ignored. * - * @return the {@link FilterPosition FilterPosition} + * @return the {@link Priority} */ - FilterPosition position() default FilterPosition.UNKNOWN; + Priority priority() default Priority.NORMAL; /** * Gets the annotation the {@link com.github.kaktushose.jda.commands.dispatching.validation.Validator Validator} diff --git a/src/main/java/com/github/kaktushose/jda/commands/annotations/interactions/Cooldown.java b/src/main/java/com/github/kaktushose/jda/commands/annotations/interactions/Cooldown.java index 2ec0776f..db60c670 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/annotations/interactions/Cooldown.java +++ b/src/main/java/com/github/kaktushose/jda/commands/annotations/interactions/Cooldown.java @@ -1,5 +1,7 @@ package com.github.kaktushose.jda.commands.annotations.interactions; +import com.github.kaktushose.jda.commands.dispatching.middleware.impl.CooldownMiddleware; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -11,7 +13,7 @@ * * @author Kaktushose * @version 2.0.0 - * @see com.github.kaktushose.jda.commands.dispatching.filter.impl.CooldownFilter CooldownFilter + * @see CooldownMiddleware CooldownFilter * @since 1.0.0 */ @Target({ElementType.METHOD, ElementType.TYPE}) diff --git a/src/main/java/com/github/kaktushose/jda/commands/data/CommandTree.java b/src/main/java/com/github/kaktushose/jda/commands/data/CommandTree.java index aaff70ab..4a72c929 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/data/CommandTree.java +++ b/src/main/java/com/github/kaktushose/jda/commands/data/CommandTree.java @@ -2,6 +2,7 @@ import com.github.kaktushose.jda.commands.reflect.interactions.commands.SlashCommandDefinition; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import net.dv8tion.jda.api.interactions.commands.localization.LocalizationFunction; import java.util.Collection; import java.util.List; @@ -80,12 +81,12 @@ private String[] resolveLabel(String label) { * * @return a {@link List} of {@link SlashCommandData} */ - public List getCommands() { - return root.getCommandData(); + public List getCommands(LocalizationFunction localizationFunction) { + return root.getCommandData(localizationFunction); } /** - * Gets the sanitized labels of all {@link SlashCommandData} returned by {@link #getCommands()}. + * Gets the sanitized labels of all {@link SlashCommandData} returned by {@link #getCommands(LocalizationFunction)} ()}. * The labels will match the regex {@code ^[\w-]+$}. Furthermore, if the label consists of more than three spaces * any additional space will be replaced with {@code _} due to Discords limitations on SubcommandGroups. * diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/adapter/TypeAdapterRegistry.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/adapter/TypeAdapterRegistry.java index 67eb68a2..0e46a920 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/adapter/TypeAdapterRegistry.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/adapter/TypeAdapterRegistry.java @@ -140,7 +140,7 @@ public void adapt(@NotNull SlashCommandContext context) { ErrorMessageFactory messageFactory = context.getImplementationRegistry().getErrorMessageFactory(); log.debug("Type adapting arguments..."); - arguments.add(new CommandEvent(context)); + arguments.add(new CommandEvent(context)); for (int i = 0; i < command.getActualParameters().size(); i++) { ParameterDefinition parameter = command.getActualParameters().get(i); @@ -158,7 +158,7 @@ public void adapt(@NotNull SlashCommandContext context) { IllegalStateException exception = new IllegalStateException( "Command input doesn't match parameter length! Please report this error the the devs of jda-commands." ); - context.setCancelled(true).setErrorMessage(messageFactory.getCommandExecutionFailedMessage(context, exception)); + context.setCancelled(messageFactory.getCommandExecutionFailedMessage(context, exception)); throw exception; } @@ -184,7 +184,7 @@ public void adapt(@NotNull SlashCommandContext context) { Optional parsed = adapter.get().parse(raw, context); if (parsed.isEmpty()) { log.debug("Type adapting failed!"); - context.setCancelled(true).setErrorMessage(messageFactory.getTypeAdaptingFailedMessage(context)); + context.setCancelled(messageFactory.getTypeAdaptingFailedMessage(context)); break; } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/Filter.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/Filter.java deleted file mode 100644 index 31bee223..00000000 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/Filter.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.github.kaktushose.jda.commands.dispatching.filter; - -import com.github.kaktushose.jda.commands.dispatching.interactions.Context; -import org.jetbrains.annotations.NotNull; - -/** - * Generic top level interface for the filter chain. A filter performs filtering tasks on a {@link Context} - * before execution. A filter might modify the {@link Context} or even cancel the whole event. - * - * @author Kaktushose - * @version 2.0.0 - * @since 2.0.0 - */ -public interface Filter { - - /** - * Performs the filtering on a {@link Context} object. Use {@link Context#setCancelled(boolean)} to - * indicate that the {@link Context} didn't pass the filter. - * - * @param context the {@link Context} to filter - */ - void apply(@NotNull Context context); - -} diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/FilterRegistry.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/FilterRegistry.java deleted file mode 100644 index 9ecbb35d..00000000 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/FilterRegistry.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.github.kaktushose.jda.commands.dispatching.filter; - -import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapterRegistry; -import com.github.kaktushose.jda.commands.dispatching.filter.impl.*; -import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * Central registry for all {@link Filter Filters}. - * - * @author Kaktushose - * @version 2.0.0 - * @see Filter - * @since 2.0.0 - */ -public class FilterRegistry { - - private static final Logger log = LoggerFactory.getLogger(FilterRegistry.class); - private final Map> filters; - - /** - * Constructs a new FilterRegistry. This will register the following {@link Filter Filters} by default: - *
    - *
  • {@link ConstraintFilter}
  • - *
  • {@link CooldownFilter}
  • - *
  • {@link DirectMessageFilter}
  • - *
  • {@link PermissionsFilter}
  • - *
  • {@link UserMuteFilter}
  • - *
- */ - public FilterRegistry() { - this.filters = new EnumMap<>(FilterPosition.class); - - register(new UserMuteFilter(), FilterPosition.BEFORE_ROUTING); - register(new PermissionsFilter(), FilterPosition.BEFORE_ADAPTING); - register(new DirectMessageFilter(), FilterPosition.BEFORE_ADAPTING); - register(new CooldownFilter(), FilterPosition.BEFORE_ADAPTING); - register(new ConstraintFilter(), FilterPosition.BEFORE_EXECUTION); - } - - /** - * Register a {@link Filter} for a specific {@link FilterPosition FilterPosition}. One {@link Filter} can be - * registered multiple times, even for the same {@link FilterPosition FilterPosition}. - * - * @param filter the {@link Filter} to register - * @param position the {@link FilterPosition FilterPosition} at which the {@link Filter} gets registered - */ - public void register(@NotNull Filter filter, @NotNull FilterPosition position) { - filters.putIfAbsent(position, new HashSet<>()); - filters.get(position).add(filter); - log.debug("Registered filter {} for position {}", filter.getClass().getName(), position); - } - - /** - * Unregisters all occurrences of the given {@link Filter} regardless of the {@link FilterPosition FilterPosition}. - * - * @param filter the {@link Filter} to unregister - */ - public void unregister(@NotNull Class filter) { - filters.keySet().forEach(position -> unregister(filter, position)); - log.debug("Unregistered filter(s) {}", filter.getName()); - } - - /** - * Unregisters all occurrences of the given {@link Filter} with the given {@link FilterPosition}. - * - * @param filter the {@link Filter} to unregister - * @param position the {@link FilterPosition} to use - */ - public void unregister(Class filter, FilterPosition position) { - Set filterSet = filters.get(position); - if (filterSet != null) { - filterSet.removeIf(current -> current.getClass().isAssignableFrom(filter)); - } - } - - /** - * Retrieves all available {@link Filter Filters} regardless of their {@link FilterPosition FilterPosition}. - * - * @return all registered {@link Filter Filters} - */ - public Collection getAll() { - return filters.values() - .stream() - .flatMap(Set::stream) - .collect(Collectors.toUnmodifiableSet()); - } - - /** - * Retrieves all {@link Filter Filters} that are registered for the given {@link FilterPosition FilterPosition}. - * - * @param position the {@link FilterPosition} to retrieve the {@link Filter Filters} for - * @return all registered {@link Filter Filters} - */ - public Collection getAll(@NotNull FilterPosition position) { - return Collections.unmodifiableCollection(filters.get(position)); - } - - /** - * Enum describing different filter positions. - * - * @author Kaktushose - * @version 2.2.0 - * @see TypeAdapterRegistry - * @since 2.0.0 - */ - public enum FilterPosition { - - /** - * Filter will be executed before command routing. The command will not be present in the - * {@link SlashCommandContext}. - */ - BEFORE_ROUTING, - - /** - * Filter will be executed before type adapting. The command will be present in the - * {@link SlashCommandContext} but not the type adapted input. - */ - BEFORE_ADAPTING, - - /** - * Filter will be executed just before the command execution. - */ - BEFORE_EXECUTION, - - /** - * Filter will not be executed. - */ - UNKNOWN - } -} diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/package-info.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/package-info.java deleted file mode 100644 index 2bc023df..00000000 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Implementations of frequently needed filters. - */ -package com.github.kaktushose.jda.commands.dispatching.filter.impl; diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/package-info.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/package-info.java deleted file mode 100644 index 4e76eb2b..00000000 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Filtering system for commands. - */ -package com.github.kaktushose.jda.commands.dispatching.filter; diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/Context.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/Context.java index c725afb7..e4dcf295 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/Context.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/Context.java @@ -57,18 +57,6 @@ public MessageCreateData getErrorMessage() { return errorMessage; } - /** - * Set the {@link Message} to send if an error occurred. - * - * @param message the {@link Message} to send - * @return the current CommandContext instance - */ - @NotNull - public Context setErrorMessage(@NotNull MessageCreateData message) { - this.errorMessage = message; - return this; - } - /** * Gets the corresponding {@link ImplementationRegistry} instance. * @@ -105,7 +93,7 @@ public JDACommands getJdaCommands() { * Set the {@link JDACommands} instance. * * @param jdaCommands the {@link JDACommands} instance - * @return the current CommandContext instance + * @return the current Context instance */ @NotNull public Context setJdaCommands(@NotNull JDACommands jdaCommands) { @@ -123,21 +111,43 @@ public boolean isCancelled() { } /** - * Set whether the context should be cancelled. + * Sets this context as cancelled and uses the provided {@link MessageCreateData} as an error message. * - * @param cancelled whether the context should be cancelled - * @return the current CommandContext instance + * @param errorMessage the error message as {@link MessageCreateData} + * @return the current Context instance */ - @NotNull - public Context setCancelled(final boolean cancelled) { - this.cancelled = cancelled; + public Context setCancelled(MessageCreateData errorMessage) { + this.cancelled = true; + this.errorMessage = errorMessage; + return this; + } + + /** + * Undoes {@link #setCancelled(MessageCreateData)} and. + * + * @return the current Context instance + */ + public Context setUncancelled() { + this.cancelled = false; return this; } + /** + * Whether this context should send ephemeral replies. + * + * @return {@code true} if this context should send ephemeral replies + */ public boolean isEphemeral() { return ephemeral; } + + /** + * Sets whether this context should send ephemeral replies. + * + * @param ephemeral {@code true} if this context should send ephemeral replies + * @return the current Context instance + */ public Context setEphemeral(boolean ephemeral) { this.ephemeral = ephemeral; return this; @@ -162,10 +172,21 @@ public Context setRuntime(InteractionRuntime runtime) { return this; } + /** + * Gets the {@link GenericInteractionDefinition} this context got created from. + * + * @return the {@link GenericInteractionDefinition} + */ public GenericInteractionDefinition getInteractionDefinition() { return interactionDefinition; } + /** + * Sets the {@link GenericInteractionDefinition} + * + * @param interactionDefinition the {@link GenericInteractionDefinition} of this context + * @return the current Context instance + */ public Context setInteractionDefinition(GenericInteractionDefinition interactionDefinition) { this.interactionDefinition = interactionDefinition; return this; diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/GenericDispatcher.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/GenericDispatcher.java index 7cc87650..1df9cb36 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/GenericDispatcher.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/GenericDispatcher.java @@ -3,9 +3,13 @@ import com.github.kaktushose.jda.commands.JDACommands; import com.github.kaktushose.jda.commands.dispatching.RuntimeSupervisor; import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapterRegistry; -import com.github.kaktushose.jda.commands.dispatching.filter.FilterRegistry; +import com.github.kaktushose.jda.commands.dispatching.middleware.Middleware; +import com.github.kaktushose.jda.commands.dispatching.middleware.MiddlewareRegistry; +import com.github.kaktushose.jda.commands.dispatching.middleware.Priority; import com.github.kaktushose.jda.commands.reflect.ImplementationRegistry; import com.github.kaktushose.jda.commands.reflect.InteractionRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Abstract base class for event dispatchers. @@ -16,8 +20,10 @@ */ public abstract class GenericDispatcher { + private final static Logger log = LoggerFactory.getLogger(GenericDispatcher.class); + protected final JDACommands jdaCommands; - protected final FilterRegistry filterRegistry; + protected final MiddlewareRegistry middlewareRegistry; protected final ImplementationRegistry implementationRegistry; protected final InteractionRegistry interactionRegistry; protected final TypeAdapterRegistry adapterRegistry; @@ -30,13 +36,46 @@ public abstract class GenericDispatcher { */ public GenericDispatcher(JDACommands jdaCommands) { this.jdaCommands = jdaCommands; - filterRegistry = jdaCommands.getFilterRegistry(); + middlewareRegistry = jdaCommands.getMiddlewareRegistry(); implementationRegistry = jdaCommands.getImplementationRegistry(); interactionRegistry = jdaCommands.getInteractionRegistry(); adapterRegistry = jdaCommands.getAdapterRegistry(); runtimeSupervisor = jdaCommands.getRuntimeSupervisor(); } + protected void executeMiddlewares(Context context) { + log.debug("Executing middlewares..."); + + for (Middleware middleware : middlewareRegistry.getMiddlewares(Priority.PERMISSIONS)) { + log.debug("Executing middleware {}", middleware.getClass().getSimpleName()); + middleware.execute(context); + if (context.isCancelled()) { + return; + } + } + for (Middleware middleware : middlewareRegistry.getMiddlewares(Priority.HIGH)) { + log.debug("Executing middleware {}", middleware.getClass().getSimpleName()); + middleware.execute(context); + if (context.isCancelled()) { + return; + } + } + for (Middleware middleware : middlewareRegistry.getMiddlewares(Priority.NORMAL)) { + log.debug("Executing middleware {}", middleware.getClass().getSimpleName()); + middleware.execute(context); + if (context.isCancelled()) { + return; + } + } + for (Middleware middleware : middlewareRegistry.getMiddlewares(Priority.LOW)) { + log.debug("Executing middleware {}", middleware.getClass().getSimpleName()); + middleware.execute(context); + if (context.isCancelled()) { + return; + } + } + } + /** * Dispatches a {@link Context}. * diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/autocomplete/AutoCompleteDispatcher.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/autocomplete/AutoCompleteDispatcher.java index ff0cd44f..44b7df00 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/autocomplete/AutoCompleteDispatcher.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/autocomplete/AutoCompleteDispatcher.java @@ -3,6 +3,7 @@ import com.github.kaktushose.jda.commands.JDACommands; import com.github.kaktushose.jda.commands.dispatching.interactions.Context; import com.github.kaktushose.jda.commands.dispatching.interactions.GenericDispatcher; +import com.github.kaktushose.jda.commands.dispatching.reply.ReplyContext; import com.github.kaktushose.jda.commands.reflect.interactions.AutoCompleteDefinition; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import org.slf4j.Logger; @@ -43,8 +44,15 @@ public void onEvent(Context context) { } AutoCompleteDefinition autoComplete = optionalAutoComplete.get(); - log.debug("Input matches auto complete: {}", autoComplete.getId()); + context.setInteractionDefinition(autoComplete); + executeMiddlewares(context); + if (checkCancelled(context)) { + log.debug("Interaction execution cancelled by middleware"); + return; + } + + log.debug("Input matches auto complete: {}", autoComplete.getId()); log.info("Executing auto complete {} for user {}", autoComplete.getMethod().getName(), event.getMember()); try { autoComplete.getMethod().invoke(runtimeSupervisor.getOrCreateInstance(event, autoComplete), new AutoCompleteEvent(context)); @@ -52,4 +60,16 @@ public void onEvent(Context context) { throw new IllegalStateException("Auto complete execution failed!", exception); } } + + @SuppressWarnings("ConstantConditions") + private boolean checkCancelled(Context context) { + if (context.isCancelled()) { + ReplyContext replyContext = new ReplyContext(context); + replyContext.getBuilder().applyData(context.getErrorMessage()); + replyContext.queue(); + return true; + } + return false; + } + } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/commands/CommandDispatcher.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/commands/CommandDispatcher.java index 821d0575..117fcdee 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/commands/CommandDispatcher.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/commands/CommandDispatcher.java @@ -6,7 +6,6 @@ import com.github.kaktushose.jda.commands.dispatching.interactions.GenericDispatcher; import com.github.kaktushose.jda.commands.dispatching.reply.ReplyContext; import com.github.kaktushose.jda.commands.embeds.ErrorMessageFactory; -import com.github.kaktushose.jda.commands.reflect.interactions.commands.ContextCommandDefinition; import com.github.kaktushose.jda.commands.reflect.interactions.commands.GenericCommandDefinition; import com.github.kaktushose.jda.commands.reflect.interactions.commands.SlashCommandDefinition; import net.dv8tion.jda.api.events.interaction.command.GenericCommandInteractionEvent; @@ -53,7 +52,7 @@ public void onEvent(Context context) { if (optional.isEmpty()) { IllegalStateException exception = new IllegalStateException("No command found! Please report this error the the devs of jda-commands."); - context.setCancelled(true).setErrorMessage(messageFactory.getCommandExecutionFailedMessage(context, exception)); + context.setCancelled(messageFactory.getCommandExecutionFailedMessage(context, exception)); checkCancelled(context); throw exception; } @@ -86,11 +85,17 @@ public void onEvent(Context context) { arguments = slashContext.getArguments(); } else { arguments = new ArrayList<>() {{ - add(new CommandEvent(context)); + add(new CommandEvent(context)); add(((GenericContextInteractionEvent) event).getTarget()); }}; } + executeMiddlewares(context); + if (checkCancelled(context)) { + log.debug("Interaction execution cancelled by middleware"); + return; + } + log.info("Executing command {} for user {}", command.getMethod().getName(), context.getEvent().getMember()); try { RuntimeSupervisor.InteractionRuntime runtime = runtimeSupervisor.newRuntime(event, command); @@ -101,7 +106,7 @@ public void onEvent(Context context) { log.error("Command execution failed!", exception); // this unwraps the underlying error in case of an exception inside the command class Throwable throwable = exception instanceof InvocationTargetException ? exception.getCause() : exception; - context.setCancelled(true).setErrorMessage(messageFactory.getCommandExecutionFailedMessage(context, throwable)); + context.setCancelled(messageFactory.getCommandExecutionFailedMessage(context, throwable)); checkCancelled(context); } } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/components/ComponentDispatcher.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/components/ComponentDispatcher.java index afc3f9e2..d226fd3a 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/components/ComponentDispatcher.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/components/ComponentDispatcher.java @@ -67,33 +67,31 @@ public void onEvent(Context context) { IllegalStateException exception = new IllegalStateException( "No select menu found! Please report this error the the devs of jda-commands." ); - context.setCancelled(true).setErrorMessage(messageFactory.getCommandExecutionFailedMessage(context, exception)); + context.setCancelled(messageFactory.getCommandExecutionFailedMessage(context, exception)); checkCancelled(context); throw exception; } EphemeralInteractionDefinition component = optionalComponent.get(); context.setInteractionDefinition(component).setEphemeral(component.isEphemeral()); - log.debug("Input matches component: {}", component.getId()); - log.info("Executing select component {} for user {}", component.getMethod().getName(), event.getMember()); + executeMiddlewares(context); + if (checkCancelled(context)) { + log.debug("Interaction execution cancelled by middleware"); + return; + } + + log.debug("Input matches component: {}", component.getId()); + log.info("Executing component {} for user {}", component.getMethod().getName(), event.getMember()); context.setRuntime(runtime); try { Class clazz = component.getClass(); if (EntitySelectMenuDefinition.class.isAssignableFrom(clazz)) { - component.getMethod().invoke( - runtime.getInstance(), - new ComponentEvent(context), - ((EntitySelectInteractionEvent) event).getMentions() - ); + component.getMethod().invoke(runtime.getInstance(), new ComponentEvent(context), ((EntitySelectInteractionEvent) event).getMentions()); } else if (StringSelectMenuDefinition.class.isAssignableFrom(clazz)) { - component.getMethod().invoke( - runtime.getInstance(), - new ComponentEvent(context), - ((StringSelectInteractionEvent) event).getValues() - ); + component.getMethod().invoke(runtime.getInstance(), new ComponentEvent(context), ((StringSelectInteractionEvent) event).getValues()); } else if (ButtonDefinition.class.isAssignableFrom(clazz)) { - component.getMethod().invoke(runtime.getInstance(), new ComponentEvent(context)); + component.getMethod().invoke(runtime.getInstance(), new ComponentEvent(context)); } else { throw new IllegalStateException("Unknown component type! Please report this error the the devs of jda-commands."); } @@ -102,7 +100,7 @@ public void onEvent(Context context) { // this unwraps the underlying error in case of an exception inside the command class Throwable throwable = exception instanceof InvocationTargetException ? exception.getCause() : exception; - context.setCancelled(true).setErrorMessage(messageFactory.getCommandExecutionFailedMessage(context, throwable)); + context.setCancelled(messageFactory.getCommandExecutionFailedMessage(context, throwable)); checkCancelled(context); } } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/modals/ModalDispatcher.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/modals/ModalDispatcher.java index 035752e4..f040cc07 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/modals/ModalDispatcher.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/interactions/modals/ModalDispatcher.java @@ -54,13 +54,20 @@ public void onEvent(Context context) { IllegalStateException exception = new IllegalStateException( "No Modal found! Please report this error the the devs of jda-commands." ); - context.setCancelled(true).setErrorMessage(messageFactory.getCommandExecutionFailedMessage(context, exception)); + context.setCancelled(messageFactory.getCommandExecutionFailedMessage(context, exception)); checkCancelled(context); throw exception; } ModalDefinition modal = optionalModal.get(); context.setInteractionDefinition(modal).setEphemeral(modal.isEphemeral()); + + executeMiddlewares(context); + if (checkCancelled(context)) { + log.debug("Interaction execution cancelled by middleware"); + return; + } + log.debug("Input matches Modal: {}", modal.getId()); log.info("Executing Modal {} for user {}", modal.getMethod().getName(), event.getMember()); try { @@ -73,7 +80,7 @@ public void onEvent(Context context) { log.error("Modal execution failed!", exception); // this unwraps the underlying error in case of an exception inside the command class Throwable throwable = exception instanceof InvocationTargetException ? exception.getCause() : exception; - context.setCancelled(true).setErrorMessage(messageFactory.getCommandExecutionFailedMessage(context, throwable)); + context.setCancelled(messageFactory.getCommandExecutionFailedMessage(context, throwable)); checkCancelled(context); } } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/Middleware.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/Middleware.java new file mode 100644 index 00000000..fefc75ad --- /dev/null +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/Middleware.java @@ -0,0 +1,9 @@ +package com.github.kaktushose.jda.commands.dispatching.middleware; + +import com.github.kaktushose.jda.commands.dispatching.interactions.Context; + +public interface Middleware { + + void execute(Context context); + +} diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/MiddlewareRegistry.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/MiddlewareRegistry.java new file mode 100644 index 00000000..50a9ae66 --- /dev/null +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/MiddlewareRegistry.java @@ -0,0 +1,57 @@ +package com.github.kaktushose.jda.commands.dispatching.middleware; + +import com.github.kaktushose.jda.commands.dispatching.middleware.impl.ConstraintMiddleware; +import com.github.kaktushose.jda.commands.dispatching.middleware.impl.CooldownMiddleware; +import com.github.kaktushose.jda.commands.dispatching.middleware.impl.PermissionsMiddleware; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.stream.Collectors; + +public class MiddlewareRegistry { + + private static final Logger log = LoggerFactory.getLogger(MiddlewareRegistry.class); + private final Map> middlewares; + + public MiddlewareRegistry() { + middlewares = new HashMap<>(); + middlewares.put(Priority.LOW, new HashSet<>()); + middlewares.put(Priority.NORMAL, new HashSet<>()); + middlewares.put(Priority.HIGH, new HashSet<>()); + middlewares.put(Priority.PERMISSIONS, new HashSet<>()); + register(Priority.PERMISSIONS, new PermissionsMiddleware()); + register(Priority.NORMAL, new ConstraintMiddleware(), new CooldownMiddleware()); + } + + public MiddlewareRegistry register(Priority priority, Middleware... middlewares) { + register(priority, List.of(middlewares)); + return this; + } + + public MiddlewareRegistry register(Priority priority, Collection middlewares) { + this.middlewares.get(priority).addAll(middlewares); + log.debug("Registered middleware(s) {} with priority {}", middlewares, priority); + return this; + } + + public MiddlewareRegistry unregister(Priority priority, Middleware... middlewares) { + unregister(priority, List.of(middlewares)); + return this; + } + + public MiddlewareRegistry unregister(Priority priority, Collection middlewares) { + this.middlewares.get(priority).removeAll(middlewares); + log.debug("Unregistered middleware(s) {}", middlewares); + return this; + } + + public Set getMiddlewares() { + return middlewares.values().stream().flatMap(Collection::stream).collect(Collectors.toUnmodifiableSet()); + } + + public Set getMiddlewares(Priority priority) { + return Collections.unmodifiableSet(middlewares.get(priority)); + } + +} diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/Priority.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/Priority.java new file mode 100644 index 00000000..26ac0083 --- /dev/null +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/Priority.java @@ -0,0 +1,27 @@ +package com.github.kaktushose.jda.commands.dispatching.middleware; + +/** + * Enum to define with witch priority a {@link Middleware} should be executed. + * + * @author Kaktushose + * @version 4.0.0 + * @since 4.0.0 + */ +public enum Priority { + /** + * Lowest priority, will be executed at the end + */ + LOW, + /** + * Default priority. + */ + NORMAL, + /** + * Highest priority for custom implementation, will be executed right after internal middlewares. + */ + HIGH, + /** + * Middlewares with priority PERMISSIONS will always be executed first + */ + PERMISSIONS +} diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/ConstraintFilter.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/ConstraintMiddleware.java similarity index 69% rename from src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/ConstraintFilter.java rename to src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/ConstraintMiddleware.java index 22859584..0e91a0d0 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/ConstraintFilter.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/ConstraintMiddleware.java @@ -1,11 +1,12 @@ -package com.github.kaktushose.jda.commands.dispatching.filter.impl; +package com.github.kaktushose.jda.commands.dispatching.middleware.impl; -import com.github.kaktushose.jda.commands.dispatching.filter.Filter; import com.github.kaktushose.jda.commands.dispatching.interactions.Context; import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; +import com.github.kaktushose.jda.commands.dispatching.middleware.Middleware; import com.github.kaktushose.jda.commands.reflect.ConstraintDefinition; import com.github.kaktushose.jda.commands.reflect.ParameterDefinition; import com.github.kaktushose.jda.commands.reflect.interactions.commands.SlashCommandDefinition; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,17 +15,17 @@ import java.util.Objects; /** - * A {@link Filter} implementation that will check the parameter constraints a + * A {@link Middleware} implementation that will check the parameter constraints a * {@link SlashCommandDefinition} might have. * * @author Kaktushose - * @version 2.0.0 + * @version 4.0.0 * @see com.github.kaktushose.jda.commands.dispatching.validation.ValidatorRegistry ValidatorRegistry * @since 2.0.0 */ -public class ConstraintFilter implements Filter { +public class ConstraintMiddleware implements Middleware { - private static final Logger log = LoggerFactory.getLogger(ConstraintFilter.class); + private static final Logger log = LoggerFactory.getLogger(ConstraintMiddleware.class); /** * Checks if all parameters fulfill their constraints. Will cancel the {@link Context} if a parameter @@ -33,7 +34,10 @@ public class ConstraintFilter implements Filter { * @param ctx the {@link Context} to filter */ @Override - public void apply(@NotNull Context ctx) { + public void execute(@NotNull Context ctx) { + if (!SlashCommandInteractionEvent.class.isAssignableFrom(ctx.getEvent().getClass())) { + return; + } SlashCommandContext context = (SlashCommandContext) ctx; List arguments = context.getArguments(); List parameters = Objects.requireNonNull(context.getCommand()).getParameters(); @@ -48,12 +52,11 @@ public void apply(@NotNull Context ctx) { boolean validated = constraint.getValidator().validate(argument, constraint.getAnnotation(), context); if (!validated) { - context.setCancelled(true); -// context.setErrorMessage( -// context.getImplementationRegistry() -// .getErrorMessageFactory() -// .getConstraintFailedMessage(context, constraint) -// ); + context.setCancelled( + context.getImplementationRegistry() + .getErrorMessageFactory() + .getConstraintFailedMessage(context, constraint) + ); log.debug("Constraint failed!"); return; } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/CooldownFilter.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/CooldownMiddleware.java similarity index 80% rename from src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/CooldownFilter.java rename to src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/CooldownMiddleware.java index f0abb955..9a3739e3 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/CooldownFilter.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/CooldownMiddleware.java @@ -1,11 +1,12 @@ -package com.github.kaktushose.jda.commands.dispatching.filter.impl; +package com.github.kaktushose.jda.commands.dispatching.middleware.impl; import com.github.kaktushose.jda.commands.annotations.interactions.Cooldown; -import com.github.kaktushose.jda.commands.dispatching.filter.Filter; import com.github.kaktushose.jda.commands.dispatching.interactions.Context; import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; +import com.github.kaktushose.jda.commands.dispatching.middleware.Middleware; import com.github.kaktushose.jda.commands.reflect.CooldownDefinition; import com.github.kaktushose.jda.commands.reflect.interactions.commands.SlashCommandDefinition; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,7 +14,7 @@ import java.util.*; /** - * A {@link Filter} implementation that contains the business logic behind command cooldowns. + * A {@link Middleware} implementation that contains the business logic behind command cooldowns. * If the command isn't annotated with {@link Cooldown Cooldown} or more * formally if the {@link SlashCommandDefinition} doesn't hold a {@link CooldownDefinition} or the delay of the * {@link CooldownDefinition} amounts to {@code 0} this filter has no effect. @@ -23,12 +24,12 @@ * @see Cooldown * @since 2.0.0 */ -public class CooldownFilter implements Filter { +public class CooldownMiddleware implements Middleware { - private static final Logger log = LoggerFactory.getLogger(CooldownFilter.class); + private static final Logger log = LoggerFactory.getLogger(CooldownMiddleware.class); private final Map> activeCooldowns; - public CooldownFilter() { + public CooldownMiddleware() { activeCooldowns = new HashMap<>(); } @@ -39,7 +40,10 @@ public CooldownFilter() { * @param context the {@link Context} to filter */ @Override - public void apply(@NotNull Context context) { + public void execute(@NotNull Context context) { + if (!SlashCommandInteractionEvent.class.isAssignableFrom(context.getEvent().getClass())) { + return; + } SlashCommandDefinition command = ((SlashCommandContext) context).getCommand(); if (!command.hasCooldown()) { @@ -58,8 +62,7 @@ public void apply(@NotNull Context context) { if (remaining <= 0) { activeCooldowns.get(id).remove(entry); } else { - context.setCancelled(true); - context.setErrorMessage(context.getImplementationRegistry().getErrorMessageFactory().getCooldownMessage(context, remaining)); + context.setCancelled(context.getImplementationRegistry().getErrorMessageFactory().getCooldownMessage(context, remaining)); log.debug("Command has a remaining cooldown of {} ms!", remaining); return; } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/PermissionsFilter.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/PermissionsMiddleware.java similarity index 74% rename from src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/PermissionsFilter.java rename to src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/PermissionsMiddleware.java index 5a1489b8..e3b9c68f 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/filter/impl/PermissionsFilter.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/middleware/impl/PermissionsMiddleware.java @@ -1,9 +1,8 @@ -package com.github.kaktushose.jda.commands.dispatching.filter.impl; +package com.github.kaktushose.jda.commands.dispatching.middleware.impl; import com.github.kaktushose.jda.commands.annotations.interactions.Permissions; -import com.github.kaktushose.jda.commands.dispatching.filter.Filter; import com.github.kaktushose.jda.commands.dispatching.interactions.Context; -import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; +import com.github.kaktushose.jda.commands.dispatching.middleware.Middleware; import com.github.kaktushose.jda.commands.permissions.PermissionsProvider; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.User; @@ -13,7 +12,7 @@ import org.slf4j.LoggerFactory; /** - * A {@link Filter} implementation that will check permissions. + * A {@link Middleware} implementation that will check permissions. * The default implementation can only handle discord permissions. However, the {@link PermissionsProvider} can be * used for own implementations. * This filter will first check against {@link PermissionsProvider#hasPermission(User, Context)} with a @@ -27,9 +26,9 @@ * @see PermissionsProvider * @since 2.0.0 */ -public class PermissionsFilter implements Filter { +public class PermissionsMiddleware implements Middleware { - private static final Logger log = LoggerFactory.getLogger(PermissionsFilter.class); + private static final Logger log = LoggerFactory.getLogger(PermissionsMiddleware.class); /** * Checks if the {@link User} and respectively the {@link Member} has the permission to execute the command. @@ -37,22 +36,19 @@ public class PermissionsFilter implements Filter { * @param context the {@link Context} to filter */ @Override - public void apply(@NotNull Context context) { + public void execute(@NotNull Context context) { log.debug("Checking permissions..."); PermissionsProvider provider = context.getImplementationRegistry().getPermissionsProvider(); - GenericInteractionCreateEvent event = context.getEvent(); boolean hasPerms; - if (event.isFromGuild()) { + if (event.getMember() != null) { hasPerms = provider.hasPermission(event.getMember(), context); } else { hasPerms = provider.hasPermission(event.getUser(), context); } if (!hasPerms) { - context.setCancelled(true).setErrorMessage( - context.getImplementationRegistry().getErrorMessageFactory().getInsufficientPermissionsMessage((SlashCommandContext) context) - ); + context.setCancelled(context.getImplementationRegistry().getErrorMessageFactory().getInsufficientPermissionsMessage(context)); log.debug("Insufficient permissions!"); return; } diff --git a/src/main/java/com/github/kaktushose/jda/commands/dispatching/validation/ValidatorRegistry.java b/src/main/java/com/github/kaktushose/jda/commands/dispatching/validation/ValidatorRegistry.java index 8b1917bb..478f0a10 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/dispatching/validation/ValidatorRegistry.java +++ b/src/main/java/com/github/kaktushose/jda/commands/dispatching/validation/ValidatorRegistry.java @@ -1,7 +1,6 @@ package com.github.kaktushose.jda.commands.dispatching.validation; import com.github.kaktushose.jda.commands.annotations.constraints.*; -import com.github.kaktushose.jda.commands.dispatching.filter.Filter; import com.github.kaktushose.jda.commands.dispatching.validation.impl.*; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -27,7 +26,7 @@ public class ValidatorRegistry { private final Map, Validator> validators; /** - * Constructs a new ValidatorRegistry. This will register the following {@link Filter Filters} by default: + * Constructs a new ValidatorRegistry. This will register the following {@link Validator Validators} by default: *
    *
  • {@link MinimumValidator}
  • *
  • {@link MaximumValidator}
  • diff --git a/src/main/java/com/github/kaktushose/jda/commands/embeds/DefaultErrorMessageFactory.java b/src/main/java/com/github/kaktushose/jda/commands/embeds/DefaultErrorMessageFactory.java index 7a0737dd..343900c5 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/embeds/DefaultErrorMessageFactory.java +++ b/src/main/java/com/github/kaktushose/jda/commands/embeds/DefaultErrorMessageFactory.java @@ -4,6 +4,7 @@ import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent; import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; import com.github.kaktushose.jda.commands.reflect.ConstraintDefinition; +import com.github.kaktushose.jda.commands.reflect.interactions.GenericInteractionDefinition; import com.github.kaktushose.jda.commands.reflect.interactions.commands.SlashCommandDefinition; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; @@ -16,7 +17,6 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; /** * Implementation of {@link ErrorMessageFactory} with default embeds. @@ -28,8 +28,6 @@ */ public class DefaultErrorMessageFactory implements ErrorMessageFactory { - protected static final String PREFIX = Matcher.quoteReplacement("/"); - @Override public MessageCreateData getTypeAdaptingFailedMessage(@NotNull SlashCommandContext context) { StringBuilder sbExpected = new StringBuilder(); @@ -55,7 +53,7 @@ public MessageCreateData getTypeAdaptingFailedMessage(@NotNull SlashCommandConte MessageEmbed embed = new EmbedBuilder() .setColor(Color.ORANGE) .setTitle("Syntax Error") - .setDescription(String.format("%s%s", PREFIX, command.getName())) + .setDescription(command.getDisplayName()) .addField("Expected", String.format("`%s`", expected), false) .addField("Actual", String.format("`%s`", actual), false) .build(); @@ -64,43 +62,22 @@ public MessageCreateData getTypeAdaptingFailedMessage(@NotNull SlashCommandConte } @Override - public MessageCreateData getInsufficientPermissionsMessage(@NotNull SlashCommandContext context) { + public MessageCreateData getInsufficientPermissionsMessage(@NotNull Context context) { StringBuilder sbPermissions = new StringBuilder(); - SlashCommandDefinition command = context.getCommand(); - command.getPermissions().forEach(permission -> sbPermissions.append(permission).append(", ")); + GenericInteractionDefinition interaction = context.getInteractionDefinition(); + interaction.getPermissions().forEach(permission -> sbPermissions.append(permission).append(", ")); String permissions = sbPermissions.toString().isEmpty() ? "N/A" : sbPermissions.substring(0, sbPermissions.length() - 2); MessageEmbed embed = new EmbedBuilder() .setColor(Color.RED) .setTitle("Insufficient Permissions") - .setDescription(String.format("`%s%s` requires specific permissions to be executed", - PREFIX, - command.getName())) + .setDescription(String.format("`%s` requires specific permissions to be executed", + interaction.getDisplayName())) .addField("Permissions:", String.format("`%s`", permissions), false ).build(); return new MessageCreateBuilder().setEmbeds(embed).build(); } - @Override - public MessageCreateData getGuildMutedMessage(@NotNull Context context) { - return new MessageCreateBuilder().setEmbeds(new EmbedBuilder() - .setColor(Color.RED) - .setTitle("Insufficient Permissions") - .setDescription("This guild is muted!") - .build() - ).build(); - } - - @Override - public MessageCreateData getChannelMutedMessage(@NotNull Context context) { - return new MessageCreateBuilder().setEmbeds(new EmbedBuilder() - .setColor(Color.RED) - .setTitle("Insufficient Permissions") - .setDescription("This channel is muted!") - .build() - ).build(); - } - @Override public MessageCreateData getConstraintFailedMessage(@NotNull Context context, @NotNull ConstraintDefinition constraint) { return new MessageCreateBuilder().setEmbeds(new EmbedBuilder() diff --git a/src/main/java/com/github/kaktushose/jda/commands/embeds/ErrorMessageFactory.java b/src/main/java/com/github/kaktushose/jda/commands/embeds/ErrorMessageFactory.java index 6d060cfa..37a7b9e9 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/embeds/ErrorMessageFactory.java +++ b/src/main/java/com/github/kaktushose/jda/commands/embeds/ErrorMessageFactory.java @@ -28,26 +28,10 @@ public interface ErrorMessageFactory { /** * Gets a {@link MessageCreateData} to send when a user is missing permissions. * - * @param context the corresponding {@link SlashCommandContext} - * @return a {@link MessageCreateData} to send when a user is missing permissions - */ - MessageCreateData getInsufficientPermissionsMessage(@NotNull SlashCommandContext context); - - /** - * Gets a {@link MessageCreateData} to send when a {@link net.dv8tion.jda.api.entities.Guild Guild} is muted. - * * @param context the corresponding {@link Context} - * @return a {@link MessageCreateData} to send when a {@link net.dv8tion.jda.api.entities.Guild Guild} is muted - */ - MessageCreateData getGuildMutedMessage(@NotNull Context context); - - /** - * Gets a {@link MessageCreateData} to send when a {@link net.dv8tion.jda.api.entities.channel.concrete.TextChannel TextChannel} is muted. - * - * @param context the corresponding {@link Context} - * @return a {@link MessageCreateData} to send when a {@link net.dv8tion.jda.api.entities.channel.concrete.TextChannel TextChannel} is muted + * @return a {@link MessageCreateData} to send when a user is missing permissions */ - MessageCreateData getChannelMutedMessage(@NotNull Context context); + MessageCreateData getInsufficientPermissionsMessage(@NotNull Context context); /** * Gets a {@link MessageCreateData} to send when a parameter constraint fails. diff --git a/src/main/java/com/github/kaktushose/jda/commands/embeds/JsonErrorMessageFactory.java b/src/main/java/com/github/kaktushose/jda/commands/embeds/JsonErrorMessageFactory.java index c9123dba..a6f19ec2 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/embeds/JsonErrorMessageFactory.java +++ b/src/main/java/com/github/kaktushose/jda/commands/embeds/JsonErrorMessageFactory.java @@ -5,6 +5,7 @@ import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent; import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; import com.github.kaktushose.jda.commands.reflect.ConstraintDefinition; +import com.github.kaktushose.jda.commands.reflect.interactions.GenericInteractionDefinition; import com.github.kaktushose.jda.commands.reflect.interactions.commands.SlashCommandDefinition; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.jetbrains.annotations.NotNull; @@ -57,54 +58,29 @@ public MessageCreateData getTypeAdaptingFailedMessage(@NotNull SlashCommandConte String actual = sbActual.toString().isEmpty() ? " " : sbActual.substring(0, sbActual.length() - 2); return embedCache.getEmbed("typeAdaptingFailed") - .injectValue("usage", String.format("%s%s", PREFIX, command.getName())) + .injectValue("usage", command.getDisplayName()) .injectValue("expected", expected) .injectValue("actual", actual) .toMessageCreateData(); } @Override - public MessageCreateData getInsufficientPermissionsMessage(@NotNull SlashCommandContext context) { + public MessageCreateData getInsufficientPermissionsMessage(@NotNull Context context) { if (!embedCache.containsEmbed("insufficientPermissions")) { return super.getInsufficientPermissionsMessage(context); } - SlashCommandDefinition command = context.getCommand(); + GenericInteractionDefinition interaction = context.getInteractionDefinition(); StringBuilder sbPermissions = new StringBuilder(); - command.getPermissions().forEach(permission -> sbPermissions.append(permission).append(", ")); + interaction.getPermissions().forEach(permission -> sbPermissions.append(permission).append(", ")); String permissions = sbPermissions.toString().isEmpty() ? "N/A" : sbPermissions.substring(0, sbPermissions.length() - 2); return embedCache.getEmbed("insufficientPermissions") - .injectValue("prefix", PREFIX) - .injectValue("label", command.getName()) + .injectValue("name", interaction.getDisplayName()) .injectValue("permissions", permissions) .toMessageCreateData(); } - @Override - public MessageCreateData getGuildMutedMessage(@NotNull Context context) { - if (!embedCache.containsEmbed("guildMuted")) { - return super.getGuildMutedMessage(context); - } - return embedCache.getEmbed("guildMuted").toMessageCreateData(); - } - - @Override - public MessageCreateData getChannelMutedMessage(@NotNull Context context) { - if (!embedCache.containsEmbed("channelMuted")) { - return super.getChannelMutedMessage(context); - } - return embedCache.getEmbed("channelMuted").toMessageCreateData(); - } - - @Override - public MessageCreateData getUserMutedMessage(@NotNull Context context) { - if (!embedCache.containsEmbed("userMuted")) { - return super.getUserMutedMessage(context); - } - return embedCache.getEmbed("userMuted").toMessageCreateData(); - } - @Override public MessageCreateData getConstraintFailedMessage(@NotNull Context context, @NotNull ConstraintDefinition constraint) { if (!embedCache.containsEmbed("constraintFailed")) { diff --git a/src/main/java/com/github/kaktushose/jda/commands/permissions/DefaultPermissionsProvider.java b/src/main/java/com/github/kaktushose/jda/commands/permissions/DefaultPermissionsProvider.java index 1aad2d34..bdb665c1 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/permissions/DefaultPermissionsProvider.java +++ b/src/main/java/com/github/kaktushose/jda/commands/permissions/DefaultPermissionsProvider.java @@ -1,7 +1,6 @@ package com.github.kaktushose.jda.commands.permissions; import com.github.kaktushose.jda.commands.dispatching.interactions.Context; -import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.User; @@ -14,7 +13,6 @@ /** * Default implementation of {@link PermissionsProvider} with the following behaviour: *
      - *
    • {@link PermissionsProvider#isMuted(User, Context)} will always return {@code false}
    • *
    • {@link PermissionsProvider#hasPermission(User, Context)} will always return {@code true}
    • *
    • * {@link PermissionsProvider#hasPermission(Member, Context)} will check against the default Discord permissions. More @@ -32,21 +30,14 @@ public class DefaultPermissionsProvider implements PermissionsProvider { private static final Logger log = LoggerFactory.getLogger(DefaultPermissionsProvider.class); - @Override - public boolean isMuted(@NotNull User user, @NotNull Context context) { - return false; - } - @Override public boolean hasPermission(@NotNull User user, @NotNull Context context) { return true; } @Override - public boolean hasPermission(@NotNull Member member, @NotNull Context ctx) { - // TODO temporary fix until permissions for other events were figured out - SlashCommandContext context = (SlashCommandContext) ctx; - for (String s : context.getCommand().getPermissions()) { + public boolean hasPermission(@NotNull Member member, @NotNull Context context) { + for (String s : context.getInteractionDefinition().getPermissions()) { // not a discord perm, continue if (Arrays.stream(Permission.values()).noneMatch(p -> p.name().equalsIgnoreCase(s))) { continue; @@ -56,8 +47,6 @@ public boolean hasPermission(@NotNull Member member, @NotNull Context ctx) { return false; } } - return true; - } } diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/ImplementationRegistry.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/ImplementationRegistry.java index 22a9cf29..589895d7 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/ImplementationRegistry.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/ImplementationRegistry.java @@ -1,13 +1,14 @@ package com.github.kaktushose.jda.commands.reflect; -import com.github.kaktushose.jda.commands.annotations.Component; +import com.github.kaktushose.jda.commands.annotations.Implementation; import com.github.kaktushose.jda.commands.annotations.Inject; import com.github.kaktushose.jda.commands.annotations.constraints.Constraint; import com.github.kaktushose.jda.commands.dependency.DependencyInjector; import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapter; import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapterRegistry; -import com.github.kaktushose.jda.commands.dispatching.filter.Filter; -import com.github.kaktushose.jda.commands.dispatching.filter.FilterRegistry; +import com.github.kaktushose.jda.commands.dispatching.middleware.Middleware; +import com.github.kaktushose.jda.commands.dispatching.middleware.MiddlewareRegistry; +import com.github.kaktushose.jda.commands.dispatching.middleware.Priority; import com.github.kaktushose.jda.commands.dispatching.validation.Validator; import com.github.kaktushose.jda.commands.dispatching.validation.ValidatorRegistry; import com.github.kaktushose.jda.commands.embeds.DefaultErrorMessageFactory; @@ -45,7 +46,7 @@ * * @author Kaktushose * @version 4.0.0 - * @see Component + * @see Implementation * @since 2.0.0 */ public class ImplementationRegistry { @@ -53,7 +54,7 @@ public class ImplementationRegistry { private static final Logger log = LoggerFactory.getLogger(ImplementationRegistry.class); private static Reflections reflections; private final DependencyInjector dependencyInjector; - private final FilterRegistry filterRegistry; + private final MiddlewareRegistry middlewareRegistry; private final TypeAdapterRegistry typeAdapterRegistry; private final ValidatorRegistry validatorRegistry; private PermissionsProvider permissionsProvider; @@ -64,12 +65,12 @@ public class ImplementationRegistry { * Constructs a new ImplementationRegistry. * * @param dependencyInjector the corresponding {@link DependencyInjector} - * @param filterRegistry the corresponding {@link FilterRegistry} + * @param middlewareRegistry the corresponding {@link MiddlewareRegistry} * @param typeAdapterRegistry the corresponding {@link TypeAdapterRegistry} * @param validatorRegistry the corresponding {@link ValidatorRegistry} */ public ImplementationRegistry(DependencyInjector dependencyInjector, - FilterRegistry filterRegistry, + MiddlewareRegistry middlewareRegistry, TypeAdapterRegistry typeAdapterRegistry, ValidatorRegistry validatorRegistry) { permissionsProvider = new DefaultPermissionsProvider(); @@ -77,7 +78,7 @@ public ImplementationRegistry(DependencyInjector dependencyInjector, guildScopeProvider = new DefaultGuildScopeProvider(); this.dependencyInjector = dependencyInjector; - this.filterRegistry = filterRegistry; + this.middlewareRegistry = middlewareRegistry; this.typeAdapterRegistry = typeAdapterRegistry; this.validatorRegistry = validatorRegistry; } @@ -106,7 +107,7 @@ public void index(@NotNull Class clazz, @NotNull String... packages) { findImplementation(ErrorMessageFactory.class).ifPresent(this::setErrorMessageFactory); findImplementation(GuildScopeProvider.class).ifPresent(this::setGuildScopeProvider); - findFilters().forEach(filterRegistry::register); + findMiddlewares().forEach(middlewareRegistry::register); findAdapters().forEach(typeAdapterRegistry::register); findValidators().forEach(validatorRegistry::register); } @@ -170,7 +171,7 @@ public void setGuildScopeProvider(GuildScopeProvider guildScopeProvider) { private Optional findImplementation(Class type) { T instance = null; for (Class clazz : reflections.getSubTypesOf(type)) { - if (!clazz.isAnnotationPresent(Component.class)) { + if (!clazz.isAnnotationPresent(Implementation.class)) { continue; } @@ -196,16 +197,16 @@ private Optional findImplementation(Class type) { return Optional.ofNullable(instance); } - private Map findFilters() { - Map result = new HashMap<>(); - for (Class clazz : reflections.getSubTypesOf(Filter.class)) { - if (!clazz.isAnnotationPresent(Component.class)) { + private Map> findMiddlewares() { + Map> result = new HashMap<>(); + for (Class clazz : reflections.getSubTypesOf(Middleware.class)) { + if (!clazz.isAnnotationPresent(Implementation.class)) { continue; } - log.debug("Found {}", clazz.getName()); + log.debug("Found middleware {}", clazz.getName()); - Filter instance; + Middleware instance; try { instance = clazz.getConstructor().newInstance(); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | @@ -214,13 +215,10 @@ private Map findFilters() { continue; } - FilterRegistry.FilterPosition position = clazz.getAnnotation(Component.class).position(); - if (position == FilterRegistry.FilterPosition.UNKNOWN) { - log.error("Invalid filter position {}!", position); - continue; - } + Priority priority = clazz.getAnnotation(Implementation.class).priority(); - result.put(instance, position); + result.putIfAbsent(priority, new HashSet<>()); + result.get(priority).add(instance); } return result; } @@ -229,7 +227,7 @@ private Map findFilters() { private Map, TypeAdapter> findAdapters() { Map, TypeAdapter> result = new HashMap<>(); for (Class clazz : reflections.getSubTypesOf(TypeAdapter.class)) { - if (!clazz.isAnnotationPresent(Component.class)) { + if (!clazz.isAnnotationPresent(Implementation.class)) { continue; } @@ -272,7 +270,7 @@ private Map, TypeAdapter> findAdapters() { private Map, Validator> findValidators() { Map, Validator> result = new HashMap<>(); for (Class clazz : reflections.getSubTypesOf(Validator.class)) { - if (!clazz.isAnnotationPresent(Component.class)) { + if (!clazz.isAnnotationPresent(Implementation.class)) { continue; } @@ -287,7 +285,7 @@ private Map, Validator> findValidators() { continue; } - Class annotation = clazz.getAnnotation(Component.class).annotation(); + Class annotation = clazz.getAnnotation(Implementation.class).annotation(); if (Constraint.class.isAssignableFrom(annotation)) { log.error("Invalid annotation type {}!", Constraint.class); continue; diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/InteractionControllerDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/InteractionControllerDefinition.java index bc10c926..ebcf7a4f 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/InteractionControllerDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/InteractionControllerDefinition.java @@ -83,11 +83,11 @@ public static Optional build(@NotNull Class } dependencyInjector.registerDependencies(interactionClass, fields); - Set permissions = new HashSet<>(); + final Set permissions = new HashSet<>(); // index controller level permissions if (interactionClass.isAnnotationPresent(Permissions.class)) { Permissions permission = interactionClass.getAnnotation(Permissions.class); - permissions = Arrays.stream(permission.value()).collect(Collectors.toSet()); + permissions.addAll(Arrays.stream(permission.value()).collect(Collectors.toSet())); } // get controller level cooldown and use it if no command level cooldown is present @@ -139,6 +139,7 @@ public static Optional build(@NotNull Class if (interaction.ephemeral()) { button.setEphemeral(true); } + button.getPermissions().addAll(permissions); buttons.add(button); }); } @@ -147,6 +148,7 @@ public static Optional build(@NotNull Class if (interaction.ephemeral()) { menu.setEphemeral(true); } + menu.getPermissions().addAll(permissions); selectMenus.add(menu); }); } @@ -155,6 +157,7 @@ public static Optional build(@NotNull Class if (interaction.ephemeral()) { menu.setEphemeral(true); } + menu.getPermissions().addAll(permissions); selectMenus.add(menu); }); } @@ -165,6 +168,7 @@ public static Optional build(@NotNull Class if (interaction.ephemeral()) { modal.setEphemeral(true); } + modal.getPermissions().addAll(permissions); modals.add(modal); }); } diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/AutoCompleteDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/AutoCompleteDefinition.java index 10368af9..de65bfa5 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/AutoCompleteDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/AutoCompleteDefinition.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; import java.lang.reflect.Method; +import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -23,7 +24,7 @@ public class AutoCompleteDefinition extends GenericInteractionDefinition { private Set commands; protected AutoCompleteDefinition(Method method, Set commands) { - super(method); + super(method, new HashSet<>()); this.commands = commands; } diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/EphemeralInteractionDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/EphemeralInteractionDefinition.java index d1ade2a0..58bbc763 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/EphemeralInteractionDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/EphemeralInteractionDefinition.java @@ -1,6 +1,7 @@ package com.github.kaktushose.jda.commands.reflect.interactions; import java.lang.reflect.Method; +import java.util.Set; /** * Represents interactions that can be replied to with an ephemeral text message. @@ -13,8 +14,8 @@ public abstract class EphemeralInteractionDefinition extends GenericInteractionD protected boolean ephemeral; - protected EphemeralInteractionDefinition(Method method, boolean ephemeral) { - super(method); + protected EphemeralInteractionDefinition(Method method, Set permissions, boolean ephemeral) { + super(method, permissions); this.ephemeral = ephemeral; } diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/GenericInteractionDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/GenericInteractionDefinition.java index 3a9ec84d..a5b01287 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/GenericInteractionDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/GenericInteractionDefinition.java @@ -6,6 +6,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Set; /** * Abstract base class for all interaction definitions. @@ -20,10 +21,12 @@ public abstract class GenericInteractionDefinition { protected final String id; protected final Method method; + protected Set permissions; - protected GenericInteractionDefinition(Method method) { + protected GenericInteractionDefinition(Method method, Set permissions) { this.id = String.format("%s.%s", method.getDeclaringClass().getSimpleName(), method.getName()); this.method = method; + this.permissions = permissions; } /** @@ -46,6 +49,24 @@ public Method getMethod() { return method; } + /** + * Gets a set of permission Strings. + * + * @return set of permission Strings + */ + public Set getPermissions() { + return permissions; + } + + /** + * Returns the display name of this interaction. By default, returns the method name + * + * @return the name of this interaction + */ + public String getDisplayName() { + return method.getName(); + } + /** * Gets a new instance of the method defining class * diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/ModalDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/ModalDefinition.java index 45f33f1a..3dcafb78 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/ModalDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/ModalDefinition.java @@ -2,6 +2,7 @@ import com.github.kaktushose.jda.commands.annotations.interactions.Interaction; import com.github.kaktushose.jda.commands.annotations.interactions.Modal; +import com.github.kaktushose.jda.commands.annotations.interactions.Permissions; import com.github.kaktushose.jda.commands.dispatching.interactions.Context; import com.github.kaktushose.jda.commands.dispatching.interactions.commands.SlashCommandContext; import com.github.kaktushose.jda.commands.dispatching.interactions.modals.ModalEvent; @@ -11,9 +12,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Parameter; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; /** * Representation of a Modal. @@ -28,8 +27,8 @@ public class ModalDefinition extends EphemeralInteractionDefinition { private final String title; private final List textInputs; - protected ModalDefinition(Method method, boolean ephemeral, String title, List textInputs) { - super(method, ephemeral); + protected ModalDefinition(Method method, Set permissions, boolean ephemeral, String title, List textInputs) { + super(method, permissions, ephemeral); this.title = title; this.textInputs = textInputs; } @@ -76,9 +75,15 @@ public static Optional build(@NotNull Method method) { return Optional.empty(); } + Set permissions = new HashSet<>(); + if (method.isAnnotationPresent(Permissions.class)) { + Permissions permission = method.getAnnotation(Permissions.class); + permissions = new HashSet<>(Arrays.asList(permission.value())); + } + Modal modal = method.getAnnotation(Modal.class); - return Optional.of(new ModalDefinition(method, modal.ephemeral(), modal.value(), textInputs)); + return Optional.of(new ModalDefinition(method, permissions, modal.ephemeral(), modal.value(), textInputs)); } /** @@ -113,6 +118,11 @@ public List getTextInputs() { return textInputs; } + @Override + public String getDisplayName() { + return title; + } + /** * Gets the runtime id. The runtime id is composed of the static interaction id and the * snowflake id of the interaction event that created the runtime. @@ -125,4 +135,15 @@ public String getRuntimeId(Context context) { return String.format("%s.%s", getId(), context.getRuntime().getInstanceId()); } + @Override + public String toString() { + return "ModalDefinition{" + + "title='" + title + '\'' + + ", textInputs=" + textInputs + + ", ephemeral=" + ephemeral + + ", id='" + id + '\'' + + ", method=" + method + + ", permissions=" + permissions + + '}'; + } } diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/commands/GenericCommandDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/commands/GenericCommandDefinition.java index 74424629..fd8eecf9 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/commands/GenericCommandDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/commands/GenericCommandDefinition.java @@ -23,7 +23,6 @@ public abstract class GenericCommandDefinition extends EphemeralInteractionDefinition implements Comparable { protected final String name; - protected final Set permissions; protected final boolean isGuildOnly; protected final boolean isNSFW; protected final Command.Type commandType; @@ -41,9 +40,8 @@ protected GenericCommandDefinition(Method method, Set enabledPermissions, SlashCommand.CommandScope scope, LocalizationFunction localizationFunction) { - super(method, ephemeral); + super(method, permissions, ephemeral); this.name = name; - this.permissions = permissions; this.isGuildOnly = isGuildOnly; this.isNSFW = isNSFW; this.commandType = commandType; @@ -69,12 +67,12 @@ public String getName() { } /** - * Gets a set of permission Strings. + * Gets the command name. * - * @return set of permission Strings + * @return the command name */ - public Set getPermissions() { - return permissions; + public String getDisplayName() { + return String.format("/%s", name); } /** diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/ButtonDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/ButtonDefinition.java index f87d686f..1de75256 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/ButtonDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/ButtonDefinition.java @@ -2,13 +2,17 @@ import com.github.kaktushose.jda.commands.annotations.interactions.Button; import com.github.kaktushose.jda.commands.annotations.interactions.Interaction; +import com.github.kaktushose.jda.commands.annotations.interactions.Permissions; import com.github.kaktushose.jda.commands.dispatching.interactions.components.ComponentEvent; import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; /** * Representation of a {@link net.dv8tion.jda.api.interactions.components.buttons.Button Button}. @@ -26,12 +30,13 @@ public class ButtonDefinition extends GenericComponentDefinition { private final ButtonStyle style; protected ButtonDefinition(Method method, + Set permissions, boolean ephemeral, String label, Emoji emoji, String link, ButtonStyle style) { - super(method, ephemeral); + super(method, permissions, ephemeral); this.label = label; this.emoji = emoji; this.link = link; @@ -67,6 +72,12 @@ public static Optional build(@NotNull Method method) { Button button = method.getAnnotation(Button.class); + Set permissions = new HashSet<>(); + if (method.isAnnotationPresent(Permissions.class)) { + Permissions permission = method.getAnnotation(Permissions.class); + permissions = new HashSet<>(Arrays.asList(permission.value())); + } + Emoji emoji; String emojiString = button.emoji(); if (emojiString.isEmpty()) { @@ -77,6 +88,7 @@ public static Optional build(@NotNull Method method) { return Optional.of(new ButtonDefinition( method, + permissions, button.ephemeral(), button.value(), emoji, @@ -141,6 +153,11 @@ public ButtonStyle getStyle() { return style; } + @Override + public String getDisplayName() { + return getLabel().orElse(id); + } + @Override public String toString() { return "ButtonDefinition{" + @@ -149,6 +166,7 @@ public String toString() { ", link='" + link + '\'' + ", style=" + style + ", ephemeral=" + ephemeral + + ", permissions=" + permissions + ", id='" + id + '\'' + ", method=" + method + '}'; diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/GenericComponentDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/GenericComponentDefinition.java index 80e58e76..63b62818 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/GenericComponentDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/GenericComponentDefinition.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; import java.lang.reflect.Method; +import java.util.Set; /** * Marker class for component definitions. @@ -18,8 +19,8 @@ */ public abstract class GenericComponentDefinition extends EphemeralInteractionDefinition { - protected GenericComponentDefinition(Method method, boolean ephemeral) { - super(method, ephemeral); + protected GenericComponentDefinition(Method method, Set permissions, boolean ephemeral) { + super(method, permissions, ephemeral); } /** diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/EntitySelectMenuDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/EntitySelectMenuDefinition.java index 648ab2d6..bd0e0b2d 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/EntitySelectMenuDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/EntitySelectMenuDefinition.java @@ -2,6 +2,7 @@ import com.github.kaktushose.jda.commands.annotations.interactions.EntitySelectMenu; import com.github.kaktushose.jda.commands.annotations.interactions.Interaction; +import com.github.kaktushose.jda.commands.annotations.interactions.Permissions; import com.github.kaktushose.jda.commands.dispatching.interactions.components.ComponentEvent; import net.dv8tion.jda.api.entities.channel.ChannelType; import net.dv8tion.jda.api.interactions.components.selections.EntitySelectMenu.DefaultValue; @@ -9,10 +10,7 @@ import org.jetbrains.annotations.NotNull; import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; /** * Representation of a {@link net.dv8tion.jda.api.interactions.components.selections.EntitySelectMenu EntitySelectMenu}. @@ -29,6 +27,7 @@ public class EntitySelectMenuDefinition extends GenericSelectMenuDefinition channelTypes; protected EntitySelectMenuDefinition(Method method, + Set permissions, boolean ephemeral, Set selectTargets, Set defaultValues, @@ -36,7 +35,7 @@ protected EntitySelectMenuDefinition(Method method, String placeholder, int minValue, int maxValue) { - super(method, ephemeral, placeholder, minValue, maxValue); + super(method, permissions, ephemeral, placeholder, minValue, maxValue); this.selectTargets = selectTargets; this.defaultValues = defaultValues; this.channelTypes = channelTypes; @@ -73,6 +72,12 @@ public static Optional build(@NotNull Method method) return Optional.empty(); } + Set permissions = new HashSet<>(); + if (method.isAnnotationPresent(Permissions.class)) { + Permissions permission = method.getAnnotation(Permissions.class); + permissions = new HashSet<>(Arrays.asList(permission.value())); + } + EntitySelectMenu selectMenu = method.getAnnotation(EntitySelectMenu.class); Set defaultValueSet = new HashSet<>(); @@ -91,6 +96,7 @@ public static Optional build(@NotNull Method method) return Optional.of(new EntitySelectMenuDefinition( method, + permissions, selectMenu.ephemeral(), Set.of(selectMenu.value()), defaultValueSet, @@ -181,6 +187,7 @@ public String toString() { ", placeholder='" + placeholder + '\'' + ", minValue=" + minValue + ", maxValue=" + maxValue + + ", permissions=" + permissions + ", ephemeral=" + ephemeral + ", id='" + id + '\'' + ", method=" + method + diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/GenericSelectMenuDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/GenericSelectMenuDefinition.java index a777a009..70480b83 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/GenericSelectMenuDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/GenericSelectMenuDefinition.java @@ -4,6 +4,7 @@ import net.dv8tion.jda.api.interactions.components.selections.SelectMenu; import java.lang.reflect.Method; +import java.util.Set; /** * Abstract base class for select menus. @@ -20,8 +21,8 @@ public abstract class GenericSelectMenuDefinition extends protected final int minValue; protected final int maxValue; - protected GenericSelectMenuDefinition(Method method, boolean ephemeral, String placeholder, int minValue, int maxValue) { - super(method, ephemeral); + protected GenericSelectMenuDefinition(Method method, Set permissions, boolean ephemeral, String placeholder, int minValue, int maxValue) { + super(method, permissions, ephemeral); this.placeholder = placeholder; this.minValue = minValue; this.maxValue = maxValue; @@ -62,4 +63,9 @@ public int getMinValue() { public int getMaxValue() { return maxValue; } + + @Override + public String getDisplayName() { + return placeholder.isEmpty() ? "Select Menu" : placeholder; + } } diff --git a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/StringSelectMenuDefinition.java b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/StringSelectMenuDefinition.java index e5516b2d..a2f01ca7 100644 --- a/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/StringSelectMenuDefinition.java +++ b/src/main/java/com/github/kaktushose/jda/commands/reflect/interactions/components/menus/StringSelectMenuDefinition.java @@ -1,16 +1,14 @@ package com.github.kaktushose.jda.commands.reflect.interactions.components.menus; import com.github.kaktushose.jda.commands.annotations.interactions.Interaction; +import com.github.kaktushose.jda.commands.annotations.interactions.Permissions; import com.github.kaktushose.jda.commands.annotations.interactions.SelectOption; import com.github.kaktushose.jda.commands.annotations.interactions.StringSelectMenu; import com.github.kaktushose.jda.commands.dispatching.interactions.components.ComponentEvent; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; /** @@ -26,12 +24,13 @@ public class StringSelectMenuDefinition extends GenericSelectMenuDefinition selectOptions; protected StringSelectMenuDefinition(Method method, + Set permissions, boolean ephemeral, Set selectOptions, String placeholder, int minValue, int maxValue) { - super(method, ephemeral, placeholder, minValue, maxValue); + super(method, permissions, ephemeral, placeholder, minValue, maxValue); this.selectOptions = selectOptions; } @@ -66,6 +65,12 @@ public static Optional build(@NotNull Method method) return Optional.empty(); } + Set permissions = new HashSet<>(); + if (method.isAnnotationPresent(Permissions.class)) { + Permissions permission = method.getAnnotation(Permissions.class); + permissions = new HashSet<>(Arrays.asList(permission.value())); + } + StringSelectMenu selectMenu = method.getAnnotation(StringSelectMenu.class); Set selectOptions = new HashSet<>(); @@ -75,6 +80,7 @@ public static Optional build(@NotNull Method method) return Optional.of(new StringSelectMenuDefinition( method, + permissions, selectMenu.ephemeral(), selectOptions, selectMenu.value(), @@ -114,6 +120,7 @@ public String toString() { ", minValue=" + minValue + ", maxValue=" + maxValue + ", ephemeral=" + ephemeral + + ", permissions=" + permissions + ", id='" + id + '\'' + ", method=" + method + '}'; diff --git a/src/test/java/adapting/mock/JDACommandsMock.java b/src/test/java/adapting/mock/JDACommandsMock.java index 8502d225..ea48963e 100644 --- a/src/test/java/adapting/mock/JDACommandsMock.java +++ b/src/test/java/adapting/mock/JDACommandsMock.java @@ -3,7 +3,7 @@ import com.github.kaktushose.jda.commands.JDACommands; import com.github.kaktushose.jda.commands.dependency.DependencyInjector; import com.github.kaktushose.jda.commands.dispatching.adapter.TypeAdapterRegistry; -import com.github.kaktushose.jda.commands.dispatching.filter.FilterRegistry; +import com.github.kaktushose.jda.commands.dispatching.middleware.MiddlewareRegistry; import com.github.kaktushose.jda.commands.dispatching.validation.ValidatorRegistry; import com.github.kaktushose.jda.commands.reflect.ImplementationRegistry; @@ -14,6 +14,6 @@ public JDACommandsMock() { @Override public ImplementationRegistry getImplementationRegistry() { - return new ImplementationRegistry(new DependencyInjector(), new FilterRegistry(), new TypeAdapterRegistry(), new ValidatorRegistry()); + return new ImplementationRegistry(new DependencyInjector(), new MiddlewareRegistry(), new TypeAdapterRegistry(), new ValidatorRegistry()); } }