diff --git a/application/build.gradle b/application/build.gradle index 3ed6987a3f..50e97d9a39 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -32,7 +32,7 @@ jib { } container { mainClass = 'org.togetherjava.tjbot.BootstrapLauncher' - setCreationTime(java.time.Instant.now().toString()) + setCreationTime(Instant.now().toString()) } } @@ -45,7 +45,7 @@ shadowJar { dependencies { implementation project(':database') - implementation 'net.dv8tion:JDA:4.4.0_352' + implementation 'net.dv8tion:JDA:5.0.0-alpha.5' implementation 'org.apache.logging.log4j:log4j-core:2.16.0' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j18-impl:2.16.0' @@ -71,4 +71,4 @@ dependencies { application { mainClass = 'org.togetherjava.tjbot.BootstrapLauncher' -} +} \ No newline at end of file diff --git a/application/src/main/java/org/togetherjava/tjbot/Application.java b/application/src/main/java/org/togetherjava/tjbot/Application.java index 7383bebb8d..f821d18c31 100644 --- a/application/src/main/java/org/togetherjava/tjbot/Application.java +++ b/application/src/main/java/org/togetherjava/tjbot/Application.java @@ -20,7 +20,7 @@ * Main class of the application. Use {@link #main(String[])} to start an instance of it. *
* New commands can be created by implementing - * {@link net.dv8tion.jda.api.events.interaction.SlashCommandEvent} or extending + * {@link net.dv8tion.jda.api.events.interaction.SlashCommandInteractionEvent} or extending * {@link org.togetherjava.tjbot.commands.SlashCommandAdapter}. They can then be registered in * {@link Features}. */ diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommand.java new file mode 100644 index 0000000000..14f64817e6 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommand.java @@ -0,0 +1,162 @@ +package org.togetherjava.tjbot.commands; + +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import org.jetbrains.annotations.NotNull; +import org.togetherjava.tjbot.commands.componentids.ComponentId; +import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; +import org.togetherjava.tjbot.commands.componentids.Lifespan; + +import java.util.List; + +/** + * Represents a Discord command. + *
+ * All commands have to implement this interface. For convenience, there is a + * {@link BotCommandAdapter} available that implemented most methods already. A new command can then + * be registered by adding it to {@link Features}. + *
+ *
+ * Commands can either be visible globally in Discord or just to specific guilds. Some + * configurations can be made via {@link CommandData}, which is then to be returned by + * {@link #getData()} where the system will then pick it up from. + *
+ * After registration, the system will notify a command whenever one of its corresponding command + * method, buttons ({@link #onButtonClick(ButtonInteractionEvent, List)}) or menus + * ({@link #onSelectionMenu(SelectMenuInteractionEvent, List)}) have been triggered. + *
+ *
+ * Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}. + */ +public interface BotCommand extends Feature { + + /** + * Gets the name of the command. + *
+ * After registration of the command, the name must not change anymore. + * + * @return the name of the command + */ + @NotNull + String getName(); + + + /** + * Gets the type of this command. + *
+ * After registration of the command, the type must not change anymore. + * + * @return the type of the command + */ + @NotNull + Command.Type getType(); + + + /** + * Gets the visibility of this command. + *
+ * After registration of the command, the visibility must not change anymore. + * + * @return the visibility of the command + */ + @NotNull + CommandVisibility getVisibility(); + + /** + * Gets the command data belonging to this command. + *
+ * See {@link net.dv8tion.jda.api.interactions.commands.build.Commands} for details on how to + * create and configure instances of it. + *
+ *
+ * This method may be called multiple times, implementations must not create new data each time + * but instead configure it once beforehand. The core system will automatically call this method + * to register the command to Discord. + * + * @return the command data of this command + */ + @NotNull + CommandData getData(); + + + /** + * Buttons can be attached below messages, and all buttons should provide the styling Discord + * provides. This means, red only for destructive actions, green only for successful etc. For + * examples on how they look, see + * Discord's + * support article. + * + * Triggered by the core system when a button corresponding to this implementation (based on + * {@link #getData()}) has been clicked. + *
+ * This method may be called multi-threaded. In particular, there are no guarantees that it will + * be executed on the same thread repeatedly or on the same thread that other event methods have + * been called on. + *
+ * Details are available in the given event and the event also enables implementations to + * respond to it. + *
+ * This method will be called in a multi-threaded context and the event may not be hold valid
+ * forever.
+ *
+ * @param event the event that triggered this
+ * @param args the arguments transported with the button, see
+ * {@link #acceptComponentIdGenerator(ComponentIdGenerator)} for details on how these are
+ * created
+ */
+ void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List
+ * This method may be called multi-threaded. In particular, there are no guarantees that it will
+ * be executed on the same thread repeatedly or on the same thread that other event methods have
+ * been called on.
+ *
+ * Details are available in the given event and the event also enables implementations to
+ * respond to it.
+ *
+ * This method will be called in a multi-threaded context and the event may not be hold valid
+ * forever.
+ *
+ * @param event the event that triggered this
+ * @param args the arguments transported with the selection menu, see
+ * {@link #acceptComponentIdGenerator(ComponentIdGenerator)} for details on how these are
+ * created
+ */
+ void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, @NotNull List
+ * The component ID has to be a UUID-string (see {@link java.util.UUID}), which is associated to
+ * a specific database entry, containing meta information about the command being executed. Such
+ * a database entry can be created and a UUID be obtained by using
+ * {@link ComponentIdGenerator#generate(ComponentId, Lifespan)}, as provided by the instance
+ * given to this method during system setup. The required {@link ComponentId} instance accepts
+ * optional extra arguments, which, if provided, can be picked up during the corresponding event
+ * (see {@link #onButtonClick(ButtonInteractionEvent, List)},
+ * {@link #onSelectionMenu(SelectMenuInteractionEvent, List)}).
+ *
+ * Alternatively, if {@link BotCommandAdapter} has been extended, it also offers a handy
+ * {@link BotCommandAdapter#generateComponentId(String...)} method to ease the flow.
+ *
+ * See Component-IDs on
+ * our Wiki for more details and examples of how to use component IDs.
+ *
+ *
+ * @param generator the provided component id generator
+ */
+ void acceptComponentIdGenerator(@NotNull ComponentIdGenerator generator);
+}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
new file mode 100644
index 0000000000..5d7d7751ef
--- /dev/null
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
@@ -0,0 +1,140 @@
+package org.togetherjava.tjbot.commands;
+
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.Command;
+import net.dv8tion.jda.api.interactions.commands.build.CommandData;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.togetherjava.tjbot.commands.componentids.ComponentId;
+import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator;
+import org.togetherjava.tjbot.commands.componentids.Lifespan;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Adapter implementation of a {@link BotCommand}. The minimal setup only requires implementation of
+ * their respective command method. A new command can then be registered by adding it to
+ * {@link Features}.
+ *
+ * Further, {@link #onButtonClick(ButtonInteractionEvent, List)} and
+ * {@link #onSelectionMenu(SelectMenuInteractionEvent, List)} can be overridden if desired. The
+ * default implementation is empty, the adapter will not react to such events.
+ *
+ *
+ * The adapter manages some getters for you, you've to create the {@link CommandData} yourself. See
+ * {@link #BotCommandAdapter(CommandData, CommandVisibility)}} for more info on that. Minimal
+ * modifications can be done on the {@link CommandData} returned by {@link #getData()}.
+ *
+ *
+ * If implementations want to add buttons or selection menus, it is highly advised to use component
+ * IDs generated by {@link #generateComponentId(String...)}, which will automatically create IDs
+ * that are valid per {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}.
+ *
+ *
+ * Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}.
+ * Registration of commands can be done in {@link Features}.
+ */
+public abstract class BotCommandAdapter implements BotCommand {
+ private final String name;
+ private final Command.Type type;
+ private final CommandVisibility visibility;
+ private final CommandData data;
+ private ComponentIdGenerator componentIdGenerator;
+
+ /**
+ * Creates a new adapter with the given data.
+ *
+ * @param data the data for this command
+ * @param visibility the visibility of the command
+ */
+ protected BotCommandAdapter(@NotNull CommandData data, @NotNull CommandVisibility visibility) {
+ this.data = Objects.requireNonNull(data, "The data shouldn't be null");
+ this.visibility = Objects.requireNonNull(visibility, "The visibility shouldn't be null");
+
+ this.name = data.getName();
+ this.type = data.getType();
+ }
+
+ @Override
+ public final @NotNull String getName() {
+ return name;
+ }
+
+ @NotNull
+ @Override
+ public Command.Type getType() {
+ return type;
+ }
+
+ @Override
+ public final @NotNull CommandVisibility getVisibility() {
+ return visibility;
+ }
+
+ @Override
+ public @NotNull CommandData getData() {
+ return data;
+ }
+
+ @Override
+ @Contract(mutates = "this")
+ public final void acceptComponentIdGenerator(@NotNull ComponentIdGenerator generator) {
+ componentIdGenerator =
+ Objects.requireNonNull(generator, "The given generator cannot be null");
+ }
+
+ @SuppressWarnings("NoopMethodInAbstractClass")
+ @Override
+ public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List
+ * They can be used to create buttons or selection menus and transport additional data
+ * throughout the event (e.g. the user id who created the button dialog).
+ *
+ * IDs generated by this method have a regular lifespan, meaning that they might get evicted and
+ * expire after not being used for a long time. Use
+ * {@link #generateComponentId(Lifespan, String...)} to set other lifespans, if desired.
+ *
+ * @param args the extra arguments that should be part of the ID
+ * @return the generated component ID
+ */
+ @SuppressWarnings("OverloadedVarargsMethod")
+ protected final @NotNull String generateComponentId(@NotNull String... args) {
+ return generateComponentId(Lifespan.REGULAR, args);
+ }
+
+ /**
+ * Helper method to generate component IDs that are considered valid per
+ * {@link #acceptComponentIdGenerator(ComponentIdGenerator)}.
+ *
+ * They can be used to create buttons or selection menus and transport additional data
+ * throughout the event (e.g. the user id who created the button dialog).
+ *
+ * @param lifespan the lifespan of the component id, controls when an id that was not used for a
+ * long time might be evicted and expire
+ * @param args the extra arguments that should be part of the ID
+ * @return the generated component ID
+ */
+ @SuppressWarnings({"OverloadedVarargsMethod", "WeakerAccess"})
+ protected final @NotNull String generateComponentId(@NotNull Lifespan lifespan,
+ @NotNull String... args) {
+ return componentIdGenerator.generate(new ComponentId(getName(), Arrays.asList(args)),
+ lifespan);
+ }
+}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandVisibility.java b/application/src/main/java/org/togetherjava/tjbot/commands/CommandVisibility.java
similarity index 89%
rename from application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandVisibility.java
rename to application/src/main/java/org/togetherjava/tjbot/commands/CommandVisibility.java
index e0d184c764..f8a2284590 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandVisibility.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/CommandVisibility.java
@@ -3,7 +3,7 @@
/**
* Visibility of a slash command, i.e. in which context it can be used by users.
*/
-public enum SlashCommandVisibility {
+public enum CommandVisibility {
/**
* The command can be used within the context of a guild.
*/
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java
index 94c8e74a90..2edf3ccefd 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java
@@ -82,6 +82,10 @@ public enum Features {
features.add(new RoleSelectCommand());
features.add(new TopHelpersCommand(database));
+ // Message context commands
+
+ // User context commands
+
// Mixtures
features.add(new FreeCommand());
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/MessageContextCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/MessageContextCommand.java
new file mode 100644
index 0000000000..d53eb56b08
--- /dev/null
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageContextCommand.java
@@ -0,0 +1,63 @@
+package org.togetherjava.tjbot.commands;
+
+import net.dv8tion.jda.api.entities.Emoji;
+import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.build.CommandData;
+import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import org.jetbrains.annotations.NotNull;
+import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator;
+
+import java.util.List;
+
+/**
+ * A message context-command is a command, accessible when right-clicking on a message.
+ *
+ *
+ * Represents a Discord message context-command. Mostly decorating
+ * {@link net.dv8tion.jda.api.interactions.commands.Command}.
+ *
+ * All message context-commands have to implement this interface. For convenience, there is a
+ * {@link BotCommandAdapter} available that implemented most methods already. A new command can then
+ * be registered by adding it to {@link Features}.
+ *
+ *
+ * Context commands can either be visible globally in Discord or just to specific guilds. Minor
+ * adjustments can be made via {@link CommandData}, which is then to be returned by
+ * {@link #getData()} where the system will then pick it up from.
+ *
+ * After registration, the system will notify a command whenever one of its corresponding message
+ * context-commands ({@link #onMessageContext(MessageContextInteractionEvent)}), buttons
+ * ({@link #onButtonClick(ButtonInteractionEvent, List)}) or menus
+ * ({@link #onSelectionMenu(SelectMenuInteractionEvent, List)}) have been triggered.
+ *
+ *
+ * Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}.
+ */
+public interface MessageContextCommand extends BotCommand {
+
+ /**
+ * Triggered by the core system when a message context-command corresponding to this
+ * implementation (based on {@link #getData()}) has been triggered.
+ *
+ * This method may be called multithreaded. In particular, there are no guarantees that it will
+ * be executed on the same thread repeatedly or on the same thread that other event methods have
+ * been called on.
+ *
+ * Details are available in the given event and the event also enables implementations to
+ * respond to it.
+ *
+ * Buttons or menus have to be created with a component ID (see
+ * {@link ComponentInteraction#getComponentId()},
+ * {@link net.dv8tion.jda.api.interactions.components.buttons.Button#of(ButtonStyle, String, Emoji)})
+ * in a very specific format, otherwise the core system will fail to identify the command that
+ * corresponded to the button or menu click event and is unable to route it back.
+ *
+ * See {@link #acceptComponentIdGenerator(ComponentIdGenerator)} for more info.
+ *
+ * @param event the event that triggered this
+ */
+ void onMessageContext(@NotNull MessageContextInteractionEvent event);
+}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java
index e43284ee31..ee679a47f0 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java
@@ -1,7 +1,7 @@
package org.togetherjava.tjbot.commands;
-import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
-import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
import org.jetbrains.annotations.NotNull;
import java.util.regex.Pattern;
@@ -38,7 +38,7 @@ public interface MessageReceiver extends Feature {
* @param event the event that triggered this, containing information about the corresponding
* message that was sent and received
*/
- void onMessageReceived(@NotNull GuildMessageReceivedEvent event);
+ void onMessageReceived(@NotNull MessageReceivedEvent event);
/**
* Triggered by the core system whenever an existing message was edited in a text channel of a
@@ -47,5 +47,5 @@ public interface MessageReceiver extends Feature {
* @param event the event that triggered this, containing information about the corresponding
* message that was edited
*/
- void onMessageUpdated(@NotNull GuildMessageUpdateEvent event);
+ void onMessageUpdated(@NotNull MessageUpdateEvent event);
}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java
index 506d2aa6e7..3d13b3b3e9 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java
@@ -1,7 +1,7 @@
package org.togetherjava.tjbot.commands;
-import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
-import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
import org.jetbrains.annotations.NotNull;
import java.util.regex.Pattern;
@@ -10,8 +10,8 @@
* Adapter implementation of a {@link MessageReceiver}. A new receiver can then be registered by
* adding it to {@link Features}.
*
- * {@link #onMessageReceived(GuildMessageReceivedEvent)} and
- * {@link #onMessageUpdated(GuildMessageUpdateEvent)} can be overridden if desired. The default
+ * {@link #onMessageReceived(MessageReceivedEvent)} and
+ * {@link #onMessageUpdated(MessageUpdateEvent)} can be overridden if desired. The default
* implementation is empty, the adapter will not react to such events.
*/
public abstract class MessageReceiverAdapter implements MessageReceiver {
@@ -35,13 +35,13 @@ protected MessageReceiverAdapter(@NotNull Pattern channelNamePattern) {
@SuppressWarnings("NoopMethodInAbstractClass")
@Override
- public void onMessageReceived(@NotNull GuildMessageReceivedEvent event) {
+ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
// Adapter does not react by default, subclasses may change this behavior
}
@SuppressWarnings("NoopMethodInAbstractClass")
@Override
- public void onMessageUpdated(@NotNull GuildMessageUpdateEvent event) {
+ public void onMessageUpdated(@NotNull MessageUpdateEvent event) {
// Adapter does not react by default, subclasses may change this behavior
}
}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java
index a5a01c20e8..5a6daa4b64 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java
@@ -1,20 +1,28 @@
package org.togetherjava.tjbot.commands;
import net.dv8tion.jda.api.entities.Emoji;
-import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
-import net.dv8tion.jda.api.events.interaction.SelectionMenuEvent;
-import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
+import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
-import net.dv8tion.jda.api.interactions.components.ButtonStyle;
+import net.dv8tion.jda.api.interactions.commands.build.Commands;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import org.jetbrains.annotations.NotNull;
-import org.togetherjava.tjbot.commands.componentids.ComponentId;
import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator;
-import org.togetherjava.tjbot.commands.componentids.Lifespan;
import java.util.List;
/**
+ * A slash-command is a command in Discord, with slash (/) as the prefix. These commands offer
+ * enhanced functionality and superior UX over text-commands. An example slash-command is the
+ * `/thread` command, this allows you to create threads using your keyboard. Try it out yourself!
+ *
+ *
* Represents a Discord slash-command. Mostly decorating
* {@link net.dv8tion.jda.api.interactions.commands.Command}.
*
@@ -28,32 +36,19 @@
* is then to be returned by {@link #getData()} where the system will then pick it up from.
*
* After registration, the system will notify a command whenever one of its corresponding slash
- * commands ({@link #onSlashCommand(SlashCommandEvent)}), buttons
- * ({@link #onButtonClick(ButtonClickEvent, List)}) or menus
- * ({@link #onSelectionMenu(SelectionMenuEvent, List)}) have been triggered.
+ * commands ({@link #onSlashCommand(SlashCommandInteractionEvent)}), buttons
+ * ({@link #onButtonClick(ButtonInteractionEvent, List)}) or menus
+ * ({@link #onSelectionMenu(SelectMenuInteractionEvent, List)}) have been triggered.
*
*
* Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}.
*/
-public interface SlashCommand extends Feature {
-
- /**
- * Gets the name of the command.
- *
- * Requirements for this are documented in {@link CommandData#CommandData(String, String)}.
- *
- *
- * After registration of the command, the name must not change anymore.
- *
- * @return the name of the command
- */
- @NotNull
- String getName();
+public interface SlashCommand extends BotCommand {
/**
* Gets the description of the command.
*
- * Requirements for this are documented in {@link CommandData#CommandData(String, String)}.
+ * Requirements for this are documented in {@link Commands#slash(String, String)}.
*
*
* After registration of the command, the description must not change anymore.
@@ -63,23 +58,13 @@ public interface SlashCommand extends Feature {
@NotNull
String getDescription();
- /**
- * Gets the visibility of this command.
- *
- * After registration of the command, the visibility must not change anymore.
- *
- * @return the visibility of the command
- */
- @NotNull
- SlashCommandVisibility getVisibility();
-
/**
* Gets the command data belonging to this command.
*
* The data can be used to configure the settings for this command, i.e. adding options,
* subcommands, menus and more.
*
- * See {@link CommandData} for details on how to create and configure instances of it.
+ * See {@link SlashCommandData} for details on how to create and configure instances of it.
*
*
* This method may be called multiple times, implementations must not create new data each time
@@ -89,13 +74,13 @@ public interface SlashCommand extends Feature {
* @return the command data of this command
*/
@NotNull
- CommandData getData();
+ SlashCommandData getData();
/**
* Triggered by the core system when a slash command corresponding to this implementation (based
* on {@link #getData()}) has been triggered.
*
- * This method may be called multi-threaded. In particular, there are no guarantees that it will
+ * This method may be called multithreaded. In particular, there are no guarantees that it will
* be executed on the same thread repeatedly or on the same thread that other event methods have
* been called on.
*
@@ -104,80 +89,37 @@ public interface SlashCommand extends Feature {
*
* Buttons or menus have to be created with a component ID (see
* {@link ComponentInteraction#getComponentId()},
- * {@link net.dv8tion.jda.api.interactions.components.Button#of(ButtonStyle, String, Emoji)}) in
- * a very specific format, otherwise the core system will fail to identify the command that
+ * {@link net.dv8tion.jda.api.interactions.components.buttons.Button#of(ButtonStyle, String, Emoji)})
+ * in a very specific format, otherwise the core system will fail to identify the command that
* corresponded to the button or menu click event and is unable to route it back.
*
- * The component ID has to be a UUID-string (see {@link java.util.UUID}), which is associated to
- * a specific database entry, containing meta information about the command being executed. Such
- * a database entry can be created and a UUID be obtained by using
- * {@link ComponentIdGenerator#generate(ComponentId, Lifespan)}, as provided by the instance
- * given to {@link #acceptComponentIdGenerator(ComponentIdGenerator)} during system setup. The
- * required {@link ComponentId} instance accepts optional extra arguments, which, if provided,
- * can be picked up during the corresponding event (see
- * {@link #onButtonClick(ButtonClickEvent, List)},
- * {@link #onSelectionMenu(SelectionMenuEvent, List)}).
- *
- * Alternatively, if {@link SlashCommandAdapter} has been extended, it also offers a handy
- * {@link SlashCommandAdapter#generateComponentId(String...)} method to ease the flow.
- *
- * See Component-IDs on
- * our Wiki for more details and examples of how to use component IDs.
- *
- * This method will be called in a multi-threaded context and the event may not be hold valid
- * forever.
- *
- * @param event the event that triggered this
- */
- void onSlashCommand(@NotNull SlashCommandEvent event);
-
- /**
- * Triggered by the core system when a button corresponding to this implementation (based on
- * {@link #getData()}) has been clicked.
- *
- * This method may be called multi-threaded. In particular, there are no guarantees that it will
- * be executed on the same thread repeatedly or on the same thread that other event methods have
- * been called on.
- *
- * Details are available in the given event and the event also enables implementations to
- * respond to it.
- *
- * This method will be called in a multi-threaded context and the event may not be hold valid
- * forever.
+ * See {@link #acceptComponentIdGenerator(ComponentIdGenerator)} for more info on the ID's.
*
* @param event the event that triggered this
- * @param args the arguments transported with the button, see
- * {@link #onSlashCommand(SlashCommandEvent)} for details on how these are created
*/
- void onButtonClick(@NotNull ButtonClickEvent event, @NotNull List
- * This method may be called multi-threaded. In particular, there are no guarantees that it will
+ * Autocompletion is comparable, but not the same as slash-command choices. Choices allow you to
+ * set a static list of {@value OptionData#MAX_CHOICES} possible "choices" to the commmand.
+ * Autocomplete allows you to dynamically give the user a list of
+ * {@value OptionData#MAX_CHOICES} possible choices. These choices can be generated based on the
+ * input of the user, the functionality is comparable to Google's autocompletion when searching
+ * for something.
+ *
+ *
- * This method will be called in a multi-threaded context and the event may not be hold valid
- * forever.
+ * respond to it.
- * Further, {@link #onButtonClick(ButtonClickEvent, List)} and
- * {@link #onSelectionMenu(SelectionMenuEvent, List)} can be overridden if desired. The default
- * implementation is empty, the adapter will not react to such events.
+ * Further, {@link #onButtonClick(ButtonInteractionEvent, List)} and
+ * {@link #onSelectionMenu(SelectMenuInteractionEvent, List)} can be overridden if desired. The
+ * default implementation is empty, the adapter will not react to such events.
*
*
* The adapter manages all command related data itself, which can be provided during construction
- * (see {@link #SlashCommandAdapter(String, String, SlashCommandVisibility)}). In order to add
- * options, subcommands or similar command configurations, use {@link #getData()} and mutate the
- * returned data object (see {@link CommandData} for details on how to work with this class).
+ * (see {@link #SlashCommandAdapter(String, String, CommandVisibility)}). In order to add options,
+ * subcommands or similar command configurations, use {@link #getData()} and mutate the returned
+ * data object (see {@link CommandData} for details on how to work with this class).
*
*
* If implementations want to add buttons or selection menus, it is highly advised to use component
* IDs generated by {@link #generateComponentId(String...)}, which will automatically create IDs
- * that are valid per {@link SlashCommand#onSlashCommand(SlashCommandEvent)}.
+ * that are valid per {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}.
*
*
* Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}. A minimal
- * setup would consist of a class like
+ * setup would consist of a class like:
*
*
* and registration of an instance of that class in {@link Features}.
*/
-public abstract class SlashCommandAdapter implements SlashCommand {
- private final String name;
+public abstract class SlashCommandAdapter extends BotCommandAdapter implements SlashCommand {
private final String description;
- private final SlashCommandVisibility visibility;
- private final CommandData data;
- private ComponentIdGenerator componentIdGenerator;
+ private final SlashCommandData data;
/**
* Creates a new adapter with the given data.
*
* @param name the name of this command, requirements for this are documented in
- * {@link CommandData#CommandData(String, String)}
+ * {@link Commands#slash(String, String)}
* @param description the description of this command, requirements for this are documented in
- * {@link CommandData#CommandData(String, String)}
+ * {@link Commands#slash(String, String)}
* @param visibility the visibility of the command
*/
protected SlashCommandAdapter(@NotNull String name, @NotNull String description,
- SlashCommandVisibility visibility) {
- this.name = name;
+ @NotNull CommandVisibility visibility) {
+ super(Commands.slash(name, description), visibility);
this.description = description;
- this.visibility = visibility;
- data = new CommandData(name, description);
- }
-
- @Override
- public final @NotNull String getName() {
- return name;
+ this.data = (SlashCommandData) super.getData();
}
@Override
@@ -90,68 +79,15 @@ protected SlashCommandAdapter(@NotNull String name, @NotNull String description,
return description;
}
+ @NotNull
@Override
- public final @NotNull SlashCommandVisibility getVisibility() {
- return visibility;
- }
-
- @Override
- public final @NotNull CommandData getData() {
+ public final SlashCommandData getData() {
return data;
}
- @Override
- public final void acceptComponentIdGenerator(@NotNull ComponentIdGenerator generator) {
- componentIdGenerator = generator;
- }
-
- @SuppressWarnings("NoopMethodInAbstractClass")
- @Override
- public void onButtonClick(@NotNull ButtonClickEvent event, @NotNull List
- * They can be used to create buttons or selection menus and transport additional data
- * throughout the event (e.g. the user id who created the button dialog).
- *
- * IDs generated by this method have a regular lifespan, meaning that they might get evicted and
- * expire after not being used for a long time. Use
- * {@link #generateComponentId(Lifespan, String...)} to set other lifespans, if desired.
- *
- * @param args the extra arguments that should be part of the ID
- * @return the generated component ID
- */
- @SuppressWarnings("OverloadedVarargsMethod")
- protected final @NotNull String generateComponentId(@NotNull String... args) {
- return generateComponentId(Lifespan.REGULAR, args);
- }
-
- /**
- * Helper method to generate component IDs that are considered valid per
- * {@link SlashCommand#onSlashCommand(SlashCommandEvent)}.
- *
- * They can be used to create buttons or selection menus and transport additional data
- * throughout the event (e.g. the user id who created the button dialog).
- *
- * @param lifespan the lifespan of the component id, controls when an id that was not used for a
- * long time might be evicted and expire
- * @param args the extra arguments that should be part of the ID
- * @return the generated component ID
- */
- @SuppressWarnings({"OverloadedVarargsMethod", "WeakerAccess"})
- protected final @NotNull String generateComponentId(@NotNull Lifespan lifespan,
- @NotNull String... args) {
- return Objects.requireNonNull(componentIdGenerator)
- .generate(new ComponentId(getName(), Arrays.asList(args)), lifespan);
- }
}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/UserContextCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/UserContextCommand.java
new file mode 100644
index 0000000000..ee6026279b
--- /dev/null
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/UserContextCommand.java
@@ -0,0 +1,64 @@
+package org.togetherjava.tjbot.commands;
+
+import net.dv8tion.jda.api.entities.Emoji;
+import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.build.CommandData;
+import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import org.jetbrains.annotations.NotNull;
+import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator;
+
+import java.util.List;
+
+/**
+ * A user context-command is a command, accessible when right-clicking on a member in a guild. These
+ * commands aren't accessible within DM's.
+ *
+ *
+ * Represents a Discord user context-command. Mostly decorating
+ * {@link net.dv8tion.jda.api.interactions.commands.Command}.
+ *
+ * All user context-commands have to implement this interface. For convenience, there is a
+ * {@link BotCommandAdapter} available that implemented most methods already. A new command can then
+ * be registered by adding it to {@link Features}.
+ *
+ *
+ * Context commands can either be visible globally in Discord or just to specific guilds. Minor
+ * adjustments can be made via {@link CommandData}, which is then to be returned by
+ * {@link #getData()} where the system will then pick it up from.
+ *
+ * After registration, the system will notify a command whenever one of its corresponding user
+ * context-commands ({@link #onUserContext(UserContextInteractionEvent)}), buttons
+ * ({@link #onButtonClick(ButtonInteractionEvent, List)}) or menus
+ * ({@link #onSelectionMenu(SelectMenuInteractionEvent, List)}) have been triggered.
+ *
+ *
+ * Some example commands are available in {@link org.togetherjava.tjbot.commands.basic}.
+ */
+public interface UserContextCommand extends BotCommand {
+
+ /**
+ * Triggered by the core system when a user context-command corresponding to this implementation
+ * (based on {@link #getData()}) has been triggered.
+ *
+ * This method may be called multithreaded. In particular, there are no guarantees that it will
+ * be executed on the same thread repeatedly or on the same thread that other event methods have
+ * been called on.
+ *
+ * Details are available in the given event and the event also enables implementations to
+ * respond to it.
+ *
+ * Buttons or menus have to be created with a component ID (see
+ * {@link ComponentInteraction#getComponentId()},
+ * {@link net.dv8tion.jda.api.interactions.components.buttons.Button#of(ButtonStyle, String, Emoji)})
+ * in a very specific format, otherwise the core system will fail to identify the command that
+ * corresponded to the button or menu click event and is unable to route it back.
+ *
+ * See {@link #acceptComponentIdGenerator(ComponentIdGenerator)} for more info.
+ *
+ * @param event the event that triggered this
+ */
+ void onUserContext(@NotNull UserContextInteractionEvent event);
+}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java
index eec68480c3..260bf6bbbb 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java
@@ -1,9 +1,9 @@
package org.togetherjava.tjbot.commands.basic;
-import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.jetbrains.annotations.NotNull;
import org.togetherjava.tjbot.commands.SlashCommandAdapter;
-import org.togetherjava.tjbot.commands.SlashCommandVisibility;
+import org.togetherjava.tjbot.commands.CommandVisibility;
/**
* Implementation of an example command to illustrate how to respond to a user.
@@ -15,7 +15,7 @@ public final class PingCommand extends SlashCommandAdapter {
* Creates an instance of the ping pong command.
*/
public PingCommand() {
- super("ping", "Bot responds with 'Pong!'", SlashCommandVisibility.GUILD);
+ super("ping", "Bot responds with 'Pong!'", CommandVisibility.GUILD);
}
/**
@@ -24,7 +24,7 @@ public PingCommand() {
* @param event the corresponding event
*/
@Override
- public void onSlashCommand(@NotNull SlashCommandEvent event) {
+ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
event.reply("Pong!").queue();
}
}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java
index c7931e86ef..2d08f5725f 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java
@@ -4,24 +4,26 @@
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.*;
-import net.dv8tion.jda.api.events.interaction.SelectionMenuEvent;
-import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent;
import net.dv8tion.jda.api.interactions.Interaction;
+import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
+import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
+import net.dv8tion.jda.api.interactions.components.selections.SelectMenuInteraction;
import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
-import net.dv8tion.jda.api.interactions.components.selections.SelectionMenu;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.togetherjava.tjbot.commands.CommandVisibility;
import org.togetherjava.tjbot.commands.SlashCommandAdapter;
-import org.togetherjava.tjbot.commands.SlashCommandVisibility;
import org.togetherjava.tjbot.commands.componentids.Lifespan;
import java.awt.*;
@@ -63,7 +65,7 @@ public final class RoleSelectCommand extends SlashCommandAdapter {
*/
public RoleSelectCommand() {
super("role-select", "Sends a message where users can select their roles",
- SlashCommandVisibility.GUILD);
+ CommandVisibility.GUILD);
SubcommandData allRoles =
new SubcommandData(ALL_OPTION, "Lists all the rolls in the server for users")
@@ -89,7 +91,7 @@ private static SelectOption mapToSelectOption(@NotNull Role role) {
}
@Override
- public void onSlashCommand(@NotNull final SlashCommandEvent event) {
+ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) {
Member member = Objects.requireNonNull(event.getMember(), "Member is null");
if (!member.hasPermission(Permission.MANAGE_ROLES)) {
event.reply("You dont have the right permissions to use this command")
@@ -105,8 +107,8 @@ public void onSlashCommand(@NotNull final SlashCommandEvent event) {
return;
}
- SelectionMenu.Builder menu =
- SelectionMenu.create(generateComponentId(Lifespan.PERMANENT, member.getId()));
+ SelectMenu.Builder menu =
+ SelectMenu.create(generateComponentId(Lifespan.PERMANENT, member.getId()));
boolean isEphemeral = false;
if (CHOOSE_OPTION.equals(event.getSubcommandName())) {
@@ -139,13 +141,13 @@ public void onSlashCommand(@NotNull final SlashCommandEvent event) {
* Adds role options to a selection menu.
*
*
- * @param event the {@link SlashCommandEvent}
- * @param menu the menu to add options to {@link SelectionMenu.Builder}
+ * @param event the {@link SlashCommandInteractionEvent}
+ * @param menu the menu to add options to {@link SelectMenu.Builder}
* @param placeHolder the placeholder for the menu {@link String}
* @param minValues the minimum number of selections. nullable {@link Integer}
*/
private static void addMenuOptions(@NotNull final Interaction event,
- @NotNull final SelectionMenu.Builder menu, @NotNull final String placeHolder,
+ @NotNull final SelectMenu.Builder menu, @NotNull final String placeHolder,
@Nullable final Integer minValues) {
Guild guild = Objects.requireNonNull(event.getGuild(), "The given guild cannot be null");
@@ -188,7 +190,7 @@ private static void addMenuOptions(@NotNull final Interaction event,
}
@Override
- public void onSelectionMenu(@NotNull final SelectionMenuEvent event,
+ public void onSelectionMenu(@NotNull final SelectMenuInteractionEvent event,
@NotNull final List
- * See {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandEvent)} for
- * more context on how to use this.
+ * See
+ * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}
+ * for more context on how to use this.
*
* The interface {@link ComponentIdParser} is the counterpart to this, offering parsing back the
* payload from the ID.
@@ -25,8 +26,8 @@ public interface ComponentIdGenerator {
* interactions, such as button or selection menus.
*
* See {@link ComponentInteraction#getComponentId()} and
- * {@link net.dv8tion.jda.api.interactions.components.Button#of(ButtonStyle, String, Emoji)} for
- * details on where the generated ID can be used.
+ * {@link net.dv8tion.jda.api.interactions.components.buttons.Button#of(ButtonStyle, String, Emoji)}
+ * for details on where the generated ID can be used.
*
* @param componentId the component ID payload to persist and generate a valid ID for
* @param lifespan the lifespan of the generated and persisted component ID
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java
index a6188da8b9..aa7ede56e1 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java
@@ -1,9 +1,9 @@
package org.togetherjava.tjbot.commands.componentids;
import net.dv8tion.jda.api.entities.Emoji;
-import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
-import net.dv8tion.jda.api.interactions.components.ButtonStyle;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ComponentInteraction;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
@@ -14,8 +14,9 @@
* Component IDs are used during button or selection menu events. They can carry arbitrary data and
* are persisted by the system.
*
- * See {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandEvent)} for
- * more context on how to use this.
+ * See
+ * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}
+ * for more context on how to use this.
*
* The interface {@link ComponentIdGenerator} is the counterpart to this, offering generation of IDs
* from payload.
@@ -27,8 +28,8 @@ public interface ComponentIdParser {
* interactions, such as button or selection menus.
*
* See {@link ComponentInteraction#getComponentId()} and
- * {@link net.dv8tion.jda.api.interactions.components.Button#of(ButtonStyle, String, Emoji)} for
- * details on where the ID was originally transported with.
+ * {@link net.dv8tion.jda.api.interactions.components.buttons.Button#of(ButtonStyle, String, Emoji)}
+ * for details on where the ID was originally transported with.
*
* @param uuid the UUID to parse which represents the component ID
* @return the payload associated to the given UUID, if empty the component ID either never
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java
index 8aca4f38c3..ad4dcde67e 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java
@@ -4,7 +4,6 @@
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
-import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
import org.jetbrains.annotations.NotNull;
import org.jooq.Result;
import org.slf4j.Logger;
@@ -27,8 +26,8 @@
/**
* Thread-safe storage for component IDs. Can put, persist and get back component IDs based on
* UUIDs. Component IDs are used for button and selection menu commands, see
- * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandEvent)} for
- * details.
+ * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}
+ * for details.
*
* Use {@link #putOrThrow(UUID, ComponentId, Lifespan)} to put and persist a component ID; and
* {@link #get(UUID)} to get it back. Component IDs are persisted during application runs and can
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java
index 1353844d85..239d79060a 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java
@@ -2,7 +2,7 @@
* This package provides utilities to generate, persist and parse component IDs.
*
* See
- * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(net.dv8tion.jda.api.events.interaction.SlashCommandEvent)}
+ * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(net.dv8tion.jda.api.events.interaction.SlashCommandInteractionEvent)}
* for details on component IDs.
*
* The class {@link org.togetherjava.tjbot.commands.componentids.ComponentIdStore} is the central
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/free/ChannelMonitor.java b/application/src/main/java/org/togetherjava/tjbot/commands/free/ChannelMonitor.java
index af2619dfc9..33d3723db4 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/free/ChannelMonitor.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/free/ChannelMonitor.java
@@ -64,7 +64,7 @@ public void addChannelForStatus(@NotNull final TextChannel channel) {
* This method tests whether a guild id is configured for monitoring in the free command system.
* To add a guild for monitoring see {@link org.togetherjava.tjbot.config.FreeCommandConfig} or
* {@link #addChannelForStatus(TextChannel)}.
- *
+ *
* @param guildId the id of the guild to test.
* @return whether the guild is configured in the free command system or not.
*/
@@ -77,7 +77,7 @@ public boolean isMonitoringGuild(final long guildId) {
* system. To add a channel for monitoring see
* {@link org.togetherjava.tjbot.config.FreeCommandConfig} or
* {@link #addChannelToMonitor(long)}.
- *
+ *
* @param channelId the id of the channel to test.
* @return {@code true} if the channel is configured in the system, {@code false} otherwise.
*/
@@ -136,7 +136,7 @@ public boolean isChannelInactive(@NotNull final TextChannel channel) {
/**
* This method sets the channel's status to 'busy' see {@link ChannelStatus#setBusy(long)} for
* details.
- *
+ *
* @param channelId the id for the channel status to modify.
* @param userId the id of the user changing the status to busy.
* @throws IllegalArgumentException if the channel passed is not monitored. See
@@ -149,7 +149,7 @@ public void setChannelBusy(final long channelId, final long userId) {
/**
* This method sets the channel's status to 'free', see {@link ChannelStatus#setFree()} for
* details.
- *
+ *
* @param channelId the id for the channel status to modify.
* @throws IllegalArgumentException if the channel passed is not monitored. See
* {@link #addChannelToMonitor(long)}
@@ -171,7 +171,7 @@ public void setChannelFree(final long channelId) {
/**
* This method provides a stream of the id's for channels where statuses are displayed. This is
* streamed purely as a simple method of encapsulation.
- *
+ *
* @return a stream of channel id's
*/
public @NotNull Stream
* If this is called on from a channel that was not configured for monitoring (see
* {@link FreeCommandConfig}) the user will receive an ephemeral message stating such.
- *
+ *
* @param event the event that triggered this
* @throws IllegalStateException if this method is called for a Global Slash Command
*/
@Override
- public void onSlashCommand(@NotNull final SlashCommandEvent event) {
+ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) {
logger.debug("/free used by {} on channel {}", event.getUser().getAsTag(),
event.getChannel().getName());
if (!handleShouldBeProcessed(event)) {
@@ -154,7 +154,7 @@ public void onSlashCommand(@NotNull final SlashCommandEvent event) {
* @param event the event to test for validity.
* @return true if the event should be processed false otherwise.
*/
- private boolean handleShouldBeProcessed(@NotNull final SlashCommandEvent event) {
+ private boolean handleShouldBeProcessed(@NotNull final SlashCommandInteractionEvent event) {
if (!isReady) {
logger.debug(
"Slash command requested by {} in {}(channel: {}) before command is ready.",
@@ -240,7 +240,7 @@ private void checkBusyStatusAllChannels(@NotNull JDA jda) {
return guild;
}
- private @NotNull Guild requiresGuild(SlashCommandEvent event) {
+ private @NotNull Guild requiresGuild(SlashCommandInteractionEvent event) {
Guild guild = event.getGuild();
if (guild == null) {
throw new IllegalStateException(
@@ -289,26 +289,30 @@ private void checkBusyStatusAllChannels(@NotNull JDA jda) {
public void onEvent(@NotNull GenericEvent event) {
if (event instanceof ReadyEvent readyEvent) {
onReady(readyEvent);
- } else if (event instanceof GuildMessageReceivedEvent guildEvent) {
- if (guildEvent.isWebhookMessage() || guildEvent.getAuthor().isBot()) {
+ } else if (event instanceof MessageReceivedEvent messageEvent) {
+ if (!messageEvent.isFromGuild()) {
+ return;
+ }
+
+ if (messageEvent.isWebhookMessage() || messageEvent.getAuthor().isBot()) {
return;
}
- if (!channelMonitor.isMonitoringChannel(guildEvent.getChannel().getIdLong())) {
+ if (!channelMonitor.isMonitoringChannel(messageEvent.getChannel().getIdLong())) {
logger.debug(
"Channel is not being monitored, ignoring message received in {} from {}",
- guildEvent.getChannel().getName(), guildEvent.getAuthor());
+ messageEvent.getChannel().getName(), messageEvent.getAuthor());
return;
}
- if (channelMonitor.isChannelBusy(guildEvent.getChannel().getIdLong())) {
+ if (channelMonitor.isChannelBusy(messageEvent.getChannel().getIdLong())) {
logger.debug(
"Channel status is currently busy, ignoring message received in {} from {}",
- guildEvent.getChannel().getName(), guildEvent.getAuthor());
+ messageEvent.getChannel().getName(), messageEvent.getAuthor());
return;
}
- channelMonitor.setChannelBusy(guildEvent.getChannel().getIdLong(),
- guildEvent.getAuthor().getIdLong());
- displayStatus(channelMonitor.getStatusChannelFor(guildEvent.getGuild()));
- guildEvent.getMessage().reply(UserStrings.NEW_QUESTION.message()).queue();
+ channelMonitor.setChannelBusy(messageEvent.getChannel().getIdLong(),
+ messageEvent.getAuthor().getIdLong());
+ displayStatus(channelMonitor.getStatusChannelFor(messageEvent.getGuild()));
+ messageEvent.getMessage().reply(UserStrings.NEW_QUESTION.message()).queue();
}
}
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/free/FreeUtil.java b/application/src/main/java/org/togetherjava/tjbot/commands/free/FreeUtil.java
index 99a002c257..beec330198 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/free/FreeUtil.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/free/FreeUtil.java
@@ -2,7 +2,7 @@
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
-import net.dv8tion.jda.api.interactions.Interaction;
+import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
import net.dv8tion.jda.api.utils.TimeUtil;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
@@ -23,11 +23,12 @@ enum FreeUtil {
/**
* Helper method to easily send ephemeral messages to users.
- *
+ *
* @param interaction The event or hook that this message is responding to
* @param message The text to be display for the user to read.
*/
- public static void sendErrorMessage(@NotNull Interaction interaction, @NotNull String message) {
+ public static void sendErrorMessage(@NotNull IReplyCallback interaction,
+ @NotNull String message) {
interaction.reply(message).setEphemeral(true).queue();
}
@@ -89,7 +90,7 @@ public static void sendErrorMessage(@NotNull Interaction interaction, @NotNull S
* Method that calculates a time value a specific duration before now. The duration is
* configured in {@link FreeCommandConfig#INACTIVE_UNIT} and
* {@link FreeCommandConfig#INACTIVE_DURATION}.
- *
+ *
* @return the time value a set duration before now.
*/
public static @NotNull OffsetDateTime inactiveTimeLimit() {
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java
index 468fe7fda2..4ee7423852 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java
@@ -1,10 +1,10 @@
package org.togetherjava.tjbot.commands.mathcommands;
-import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
-import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionType;
-import net.dv8tion.jda.api.interactions.components.Button;
-import net.dv8tion.jda.api.interactions.components.ButtonStyle;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import org.jetbrains.annotations.NotNull;
import org.scilab.forge.jlatexmath.ParseException;
import org.scilab.forge.jlatexmath.TeXConstants;
@@ -12,7 +12,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.togetherjava.tjbot.commands.SlashCommandAdapter;
-import org.togetherjava.tjbot.commands.SlashCommandVisibility;
+import org.togetherjava.tjbot.commands.CommandVisibility;
import javax.imageio.ImageIO;
import java.awt.*;
@@ -46,13 +46,13 @@ public class TeXCommand extends SlashCommandAdapter {
public TeXCommand() {
super("tex",
"This command accepts a latex expression and generates an image corresponding to it.",
- SlashCommandVisibility.GUILD);
+ CommandVisibility.GUILD);
getData().addOption(OptionType.STRING, LATEX_OPTION,
"The latex which is rendered as an image", true);
}
@Override
- public void onSlashCommand(@NotNull final SlashCommandEvent event) {
+ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
String latex = Objects.requireNonNull(event.getOption(LATEX_OPTION)).getAsString();
String userID = (Objects.requireNonNull(event.getMember()).getId());
TeXFormula formula;
@@ -92,8 +92,9 @@ public void onSlashCommand(@NotNull final SlashCommandEvent event) {
.queue();
}
+
@Override
- public void onButtonClick(@NotNull final ButtonClickEvent event,
+ public void onButtonClick(@NotNull final ButtonInteractionEvent event,
@NotNull final List
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java
index 33613c797a..9fddc6705b 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java
@@ -4,18 +4,18 @@
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
-import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
-import net.dv8tion.jda.api.interactions.components.Button;
-import net.dv8tion.jda.api.interactions.components.ButtonStyle;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.togetherjava.tjbot.commands.SlashCommand;
+import org.togetherjava.tjbot.commands.BotCommand;
+import org.togetherjava.tjbot.commands.CommandVisibility;
import org.togetherjava.tjbot.commands.SlashCommandAdapter;
-import org.togetherjava.tjbot.commands.SlashCommandVisibility;
import org.togetherjava.tjbot.commands.utils.MessageUtils;
import java.util.ArrayList;
@@ -37,7 +37,7 @@
*/
public final class ReloadCommand extends SlashCommandAdapter {
private static final Logger logger = LoggerFactory.getLogger(ReloadCommand.class);
- private final SlashCommandProvider commandProvider;
+ private final BotCommandProvider commandProvider;
/**
* Creates the reload command, using the given provider as source of truth for the commands to
@@ -46,15 +46,15 @@ public final class ReloadCommand extends SlashCommandAdapter {
* @param commandProvider the provider of slash commands to reload when this command is
* triggered
*/
- public ReloadCommand(@NotNull SlashCommandProvider commandProvider) {
+ public ReloadCommand(@NotNull BotCommandProvider commandProvider) {
super("reload",
"Uploads all existing slash-commands to Discord so they are fully up-to-date.",
- SlashCommandVisibility.GUILD);
+ CommandVisibility.GUILD);
this.commandProvider = commandProvider;
}
@Override
- public void onSlashCommand(@NotNull SlashCommandEvent event) {
+ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
Member member = Objects.requireNonNull(event.getMember());
if (!member.hasPermission(Permission.MANAGE_SERVER)) {
@@ -76,7 +76,7 @@ public void onSlashCommand(@NotNull SlashCommandEvent event) {
}
@Override
- public void onButtonClick(@NotNull ButtonClickEvent event, @NotNull List
* An example test using this class might look like:
- *
+ *
*
* The method creates a builder that can be used to further adjust the event before creation,
* e.g. provide options.
@@ -113,11 +113,11 @@ public JdaTester() {
* @param command the command to create an event for
* @return a builder used to create a Mockito mocked slash command event
*/
- public @NotNull SlashCommandEventBuilder createSlashCommandEvent(
+ public @NotNull SlashCommandInteractionEventBuilder createSlashCommandEvent(
@NotNull SlashCommand command) {
- UnaryOperator
* Create instances of this class by using {@link JdaTester#createSlashCommandEvent(SlashCommand)}.
*
@@ -31,20 +31,20 @@
* cleared using {@link #clearOptions()}.
*
* Refer to the following examples: the command {@code ping} is build using
- *
+ *
*
+ * See {@link #acceptComponentIdGenerator(ComponentIdGenerator)} for more info on the ID's.
*
* @param event the event that triggered this
- * @param args the arguments transported with the selection menu, see
- * {@link #onSlashCommand(SlashCommandEvent)} for details on how these are created
- */
- void onSelectionMenu(@NotNull SelectionMenuEvent event, @NotNull List
* {
* @code
* public class PingCommand extends SlashCommandAdapter {
* public PingCommand() {
- * super("ping", "Responds with 'Pong!'", SlashCommandVisibility.GUILD);
+ * super("ping", "Responds with 'Pong!'", CommandVisibility.GUILD);
* }
*
* @Override
- * public void onSlashCommand(@NotNull SlashCommandEvent event) {
+ * public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
* event.reply("Pong!").queue();
* }
* }
@@ -55,34 +53,25 @@
*
* {
* @code
@@ -105,7 +105,7 @@ public JdaTester() {
/**
* Creates a Mockito mocked slash command event, which can be used for
- * {@link SlashCommand#onSlashCommand(SlashCommandEvent)}.
+ * {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)}.
*
* {@code
* // /ping
- * jdaTester.createSlashCommandEvent(command).build();
+ * jdaTester.createSlashCommandInteractionEvent(command).build();
*
* // /days start:10.01.2021 end:13.01.2021
- * jdaTester.createSlashCommandEvent(command)
+ * jdaTester.createSlashCommandInteractionEvent(command)
* .option("start", "10.01.2021")
* .option("end", "13.01.2021")
* .build();
*
* // /db put key:foo value:bar
- * jdaTester.createSlashCommandEvent(command)
+ * jdaTester.createSlashCommandInteractionEvent(command)
* .subcommand("put")
* .option("key", "foo")
* .option("value", "bar")
@@ -53,10 +53,10 @@
*
*/
@SuppressWarnings("ClassWithTooManyFields")
-public final class SlashCommandEventBuilder {
+public final class SlashCommandInteractionEventBuilder {
private static final ObjectMapper JSON = new ObjectMapper();
private final JDAImpl jda;
- private final UnaryOperator