From 11ced26d73f9784b3217cfc22cbcfe36f1ab3edd Mon Sep 17 00:00:00 2001 From: twonirwana Date: Sat, 7 Sep 2024 09:44:25 +0200 Subject: [PATCH 1/4] user install --- README.adoc | 5 ++--- bot/build.gradle.kts | 4 ---- .../channelConfig/ChannelConfigCommand.java | 8 +++----- .../command/directRoll/AliasRollCommand.java | 2 ++ .../command/directRoll/DirectRollCommand.java | 2 ++ .../command/directRoll/ValidationCommand.java | 2 ++ .../discord/bot/command/help/HelpCommand.java | 3 +++ .../discord/bot/command/ClearCommandTest.snap | 5 ++++- .../bot/command/FetchCommandMockTest.snap | 5 ++++- .../channelConfig/ChannelConfigTest.snap | 4 ++++ .../customDice/CustomDiceCommandTest.snap | 3 +++ .../CustomParameterCommandTest.snap | 3 +++ .../directRoll/AliasRollCommandTest.snap | 4 ++++ .../directRoll/DirectRollCommandTest.snap | 4 ++++ .../directRoll/HiddenRollCommandTest.snap | 3 +++ .../directRoll/ValidationCommandTest.snap | 4 ++++ .../bot/command/help/HelpCommandTest.snap | 6 +++++- .../command/help/QuickstartCommandTest.snap | 3 +++ .../bot/command/help/WelcomeCommandTest.snap | 3 +++ .../sumCustomSet/SumCustomSetCommandTest.snap | 3 +++ build.gradle.kts | 4 ---- discord-connector/api/build.gradle.kts | 4 ---- .../api/slash/CommandDefinition.java | 10 +++++++++- .../api/slash/CommandIntegrationType.java | 10 ++++++++++ discord-connector/build.gradle.kts | 3 --- discord-connector/jda/build.gradle.kts | 10 ++++------ .../jda/ApplicationCommandConverter.java | 15 ++++++++++++++ .../discord/connector/jda/JdaClient.java | 20 ++++++++++++++----- .../connector/jda/SlashEventAdapterImpl.java | 3 ++- settings.gradle.kts | 9 ++++++++- 30 files changed, 124 insertions(+), 40 deletions(-) create mode 100644 discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandIntegrationType.java diff --git a/README.adoc b/README.adoc index ad0ef0a8..37014e03 100644 --- a/README.adoc +++ b/README.adoc @@ -4,7 +4,7 @@ https://www.gnu.org/licenses/agpl-3.0[image:https://img.shields.io/badge/License-AGPL_v3-blue.svg[License: AGPL v3]] https://codecov.io/gh/twonirwana/DiscordDiceBot[image:https://codecov.io/gh/twonirwana/DiscordDiceBot/branch/main/graph/badge.svg?token=OLH7L312D7[codecov]] image:https://img.shields.io/github/actions/workflow/status/twonirwana/DiscordDiceBot/codeCov.yml?branch=main[GitHub Workflow Status] image:https://img.shields.io/discord/898657305883725834[link="https://discord.gg/e43BsqKpFr"] -image:https://dcbadge.limes.pink/api/shield/812381127943782502?bot=true&style=flat&theme=clean-inverted[link="https://discord.com/api/oauth2/authorize?client_id=812381127943782502&permissions=274878023680&scope=applications.commands%20bot"] +image:https://dcbadge.limes.pink/api/shield/812381127943782502?bot=true&style=flat&theme=clean-inverted[link="https://discord.com/oauth2/authorize?client_id=812381127943782502"] This bot is for rolling dice in discord. The bot needs to be configured with a slash command in a channel and then provides a message with buttons. @@ -15,8 +15,7 @@ The bot supports Discord thread (the button message must be added after the thre It can provide images of the dice roll results and it is possible to configure channel or user specific aliases. image:image/example.webp[image] - -*Add to Discord channel by following this link*: https://discord.com/api/oauth2/authorize?client_id=812381127943782502&permissions=274878023680&scope=applications.commands%20bot[*Bot invite link*] +*Add to Discord channel by following this link*: https://discord.com/oauth2/authorize?client_id=812381127943782502[*Bot invite link*] *Discord Server for trying the bot, questions and feature suggestions*: https://discord.gg/e43BsqKpFr[Button Dice Roller Discord Server] diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index a71bdf35..47a38748 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -3,10 +3,6 @@ plugins { id("jacoco") } -repositories { - mavenCentral() -} - dependencies { implementation(project(":discord-connector")) implementation("io.github.twonirwana:dice-evaluator:v0.9.1") diff --git a/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java b/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java index cfbfd498..3cd7a490 100644 --- a/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java +++ b/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java @@ -14,10 +14,7 @@ import de.janno.discord.bot.persistance.Mapper; import de.janno.discord.bot.persistance.PersistenceManager; import de.janno.discord.connector.api.*; -import de.janno.discord.connector.api.slash.CommandDefinition; -import de.janno.discord.connector.api.slash.CommandDefinitionOption; -import de.janno.discord.connector.api.slash.CommandDefinitionOptionChoice; -import de.janno.discord.connector.api.slash.CommandInteractionOption; +import de.janno.discord.connector.api.slash.*; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono; @@ -159,7 +156,7 @@ public class ChannelConfigCommand implements SlashCommand { .descriptionLocales(I18n.allNoneEnglishMessagesDescriptions("channel_config.option.value.description")) .required(true) .build()) - .option(SCOPE_OPTION) + .option(SCOPE_OPTION)//todo only user scope for userApp install or maybe extra command? .option(ALIAS_TYPE_OPTION) .build(); private final PersistenceManager persistenceManager; @@ -200,6 +197,7 @@ public static List parseStringToMultiAliasList(String aliasesString) { .nameLocales(I18n.allNoneEnglishMessagesNames("channel_config.name")) .description(I18n.getMessage("channel_config.description", Locale.ENGLISH)) .descriptionLocales(I18n.allNoneEnglishMessagesDescriptions("channel_config.description")) + .integrationTypes(CommandIntegrationType.ALL) .option(CommandDefinitionOption.builder() .name(SAVE_DIRECT_ROLL_CONFIG_OPTION_NAME) .nameLocales(I18n.allNoneEnglishMessagesNames("channel_config.option.save_direct_roll_config.name")) diff --git a/bot/src/main/java/de/janno/discord/bot/command/directRoll/AliasRollCommand.java b/bot/src/main/java/de/janno/discord/bot/command/directRoll/AliasRollCommand.java index 56989c82..5e94a349 100644 --- a/bot/src/main/java/de/janno/discord/bot/command/directRoll/AliasRollCommand.java +++ b/bot/src/main/java/de/janno/discord/bot/command/directRoll/AliasRollCommand.java @@ -12,6 +12,7 @@ import de.janno.discord.connector.api.message.EmbedOrMessageDefinition; import de.janno.discord.connector.api.slash.CommandDefinition; import de.janno.discord.connector.api.slash.CommandDefinitionOption; +import de.janno.discord.connector.api.slash.CommandIntegrationType; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -65,6 +66,7 @@ public AliasRollCommand(PersistenceManager persistenceManager, CachingDiceEvalua .nameLocales(I18n.allNoneEnglishMessagesNames("a.name")) .description(I18n.getMessage("a.description", Locale.ENGLISH)) .descriptionLocales(I18n.allNoneEnglishMessagesDescriptions("a.description")) + .integrationTypes(CommandIntegrationType.ALL) .option(CommandDefinitionOption.builder() .name(expressionOptionName) .nameLocales(I18n.allNoneEnglishMessagesNames("a.expression.name")) diff --git a/bot/src/main/java/de/janno/discord/bot/command/directRoll/DirectRollCommand.java b/bot/src/main/java/de/janno/discord/bot/command/directRoll/DirectRollCommand.java index da5e2b32..98a00935 100644 --- a/bot/src/main/java/de/janno/discord/bot/command/directRoll/DirectRollCommand.java +++ b/bot/src/main/java/de/janno/discord/bot/command/directRoll/DirectRollCommand.java @@ -24,6 +24,7 @@ import de.janno.discord.connector.api.message.EmbedOrMessageDefinition; import de.janno.discord.connector.api.slash.CommandDefinition; import de.janno.discord.connector.api.slash.CommandDefinitionOption; +import de.janno.discord.connector.api.slash.CommandIntegrationType; import de.janno.discord.connector.api.slash.CommandInteractionOption; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -71,6 +72,7 @@ public DirectRollCommand(PersistenceManager persistenceManager, CachingDiceEvalu .nameLocales(I18n.allNoneEnglishMessagesNames("r.name")) .description(I18n.getMessage("r.description", Locale.ENGLISH)) .descriptionLocales(I18n.allNoneEnglishMessagesDescriptions("r.description")) + .integrationTypes(CommandIntegrationType.ALL) .option(CommandDefinitionOption.builder() .name(expressionOptionName) .nameLocales(I18n.allNoneEnglishMessagesNames("r.expression.name")) diff --git a/bot/src/main/java/de/janno/discord/bot/command/directRoll/ValidationCommand.java b/bot/src/main/java/de/janno/discord/bot/command/directRoll/ValidationCommand.java index baef5a77..6dac629c 100644 --- a/bot/src/main/java/de/janno/discord/bot/command/directRoll/ValidationCommand.java +++ b/bot/src/main/java/de/janno/discord/bot/command/directRoll/ValidationCommand.java @@ -11,6 +11,7 @@ import de.janno.discord.connector.api.message.EmbedOrMessageDefinition; import de.janno.discord.connector.api.slash.CommandDefinition; import de.janno.discord.connector.api.slash.CommandDefinitionOption; +import de.janno.discord.connector.api.slash.CommandIntegrationType; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -63,6 +64,7 @@ private AutoCompleteAnswer getValidAutoCompleteMessage(@NonNull String typedExpr .nameLocales(I18n.allNoneEnglishMessagesNames("validation.name")) .description(I18n.getMessage("validation.description", Locale.ENGLISH)) .descriptionLocales(I18n.allNoneEnglishMessagesDescriptions("validation.description")) + .integrationTypes(CommandIntegrationType.ALL) .option(CommandDefinitionOption.builder() .name(expressionOptionName) .nameLocales(I18n.allNoneEnglishMessagesNames("validation.expression.name")) diff --git a/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java b/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java index bf6aebd7..76f342ad 100644 --- a/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java +++ b/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java @@ -6,6 +6,7 @@ import de.janno.discord.connector.api.SlashEventAdaptor; import de.janno.discord.connector.api.message.EmbedOrMessageDefinition; import de.janno.discord.connector.api.slash.CommandDefinition; +import de.janno.discord.connector.api.slash.CommandIntegrationType; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono; @@ -26,6 +27,7 @@ public class HelpCommand implements SlashCommand { return CommandDefinition.builder() .name(getCommandId()) .nameLocales(I18n.allNoneEnglishMessagesNames("help.name")) + .integrationTypes(CommandIntegrationType.ALL) .description(I18n.getMessage("help.description", Locale.ENGLISH)) .descriptionLocales(I18n.allNoneEnglishMessagesDescriptions("help.description")) .build(); @@ -34,6 +36,7 @@ public class HelpCommand implements SlashCommand { @Override public @NonNull Mono handleSlashCommandEvent(@NonNull SlashEventAdaptor event, @NonNull Supplier uuidSupplier, @NonNull Locale userLocale) { BotMetrics.incrementSlashStartMetricCounter(getCommandId()); + //todo other text or command for user install return event.replyWithEmbedOrMessageDefinition(EmbedOrMessageDefinition.builder() .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.quickstart.field.name", userLocale), I18n.getMessage("help.quickstart.field.value", userLocale), false)) .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.command.field.name", userLocale), I18n.getMessage("help.command.field.value", userLocale), false)) diff --git a/bot/src/test/java/de/janno/discord/bot/command/ClearCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/ClearCommandTest.snap index 83ac0b97..5ff552e3 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/ClearCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/ClearCommandTest.snap @@ -17,7 +17,10 @@ de.janno.discord.bot.command.ClearCommandTest.getCommandDefinition=[ "description": "Supprime tous les messages des boutons et les données sauvegardées du bot pour ce canal." } ], - "options": [ ] + "options": [ ], + "integrationTypes": [ + "GUILD_INSTALL" + ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/FetchCommandMockTest.snap b/bot/src/test/java/de/janno/discord/bot/command/FetchCommandMockTest.snap index 1c20decc..dc7ee722 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/FetchCommandMockTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/FetchCommandMockTest.snap @@ -54,7 +54,10 @@ de.janno.discord.bot.command.FetchCommandMockTest.getCommandDefinition=[ "description": "Déplace le dernier message du lancer de dés vers l'avant" } ], - "options": [ ] + "options": [ ], + "integrationTypes": [ + "GUILD_INSTALL" + ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/channelConfig/ChannelConfigTest.snap b/bot/src/test/java/de/janno/discord/bot/command/channelConfig/ChannelConfigTest.snap index 65323d29..ca20c7b8 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/channelConfig/ChannelConfigTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/channelConfig/ChannelConfigTest.snap @@ -716,6 +716,10 @@ de.janno.discord.bot.command.channelConfig.ChannelConfigTest.getCommandDefinitio ], "autoComplete": false } + ], + "integrationTypes": [ + "GUILD_INSTALL", + "USER_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/customDice/CustomDiceCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/customDice/CustomDiceCommandTest.snap index bf79cfda..e614564d 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/customDice/CustomDiceCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/customDice/CustomDiceCommandTest.snap @@ -415,6 +415,9 @@ de.janno.discord.bot.command.customDice.CustomDiceCommandTest.getCommandDefiniti "options": [ ], "autoComplete": false } + ], + "integrationTypes": [ + "GUILD_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/customParameter/CustomParameterCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/customParameter/CustomParameterCommandTest.snap index 15c9f02b..15c784f1 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/customParameter/CustomParameterCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/customParameter/CustomParameterCommandTest.snap @@ -415,6 +415,9 @@ de.janno.discord.bot.command.customParameter.CustomParameterCommandTest.getComma "options": [ ], "autoComplete": false } + ], + "integrationTypes": [ + "GUILD_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/directRoll/AliasRollCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/directRoll/AliasRollCommandTest.snap index 0921fac1..e5077ee9 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/directRoll/AliasRollCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/directRoll/AliasRollCommandTest.snap @@ -42,6 +42,10 @@ de.janno.discord.bot.command.directRoll.AliasRollCommandTest.getCommandDefinitio "options": [ ], "autoComplete": true } + ], + "integrationTypes": [ + "GUILD_INSTALL", + "USER_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/directRoll/DirectRollCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/directRoll/DirectRollCommandTest.snap index cf4db7ed..a48f22ac 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/directRoll/DirectRollCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/directRoll/DirectRollCommandTest.snap @@ -42,6 +42,10 @@ de.janno.discord.bot.command.directRoll.DirectRollCommandTest.getCommandDefiniti "options": [ ], "autoComplete": false } + ], + "integrationTypes": [ + "GUILD_INSTALL", + "USER_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/directRoll/HiddenRollCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/directRoll/HiddenRollCommandTest.snap index 2d3fd85f..d0d9a7e0 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/directRoll/HiddenRollCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/directRoll/HiddenRollCommandTest.snap @@ -42,6 +42,9 @@ de.janno.discord.bot.command.directRoll.HiddenRollCommandTest.getCommandDefiniti "options": [ ], "autoComplete": false } + ], + "integrationTypes": [ + "GUILD_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/directRoll/ValidationCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/directRoll/ValidationCommandTest.snap index c90eb937..13cf2f51 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/directRoll/ValidationCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/directRoll/ValidationCommandTest.snap @@ -42,6 +42,10 @@ de.janno.discord.bot.command.directRoll.ValidationCommandTest.getCommandDefiniti "options": [ ], "autoComplete": true } + ], + "integrationTypes": [ + "GUILD_INSTALL", + "USER_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap index 98a0b4df..b8356436 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap @@ -17,7 +17,11 @@ de.janno.discord.bot.command.help.HelpCommandTest.getCommandDefinition=[ "description": "Aide aux commandes et liens pour plus d'informations" } ], - "options": [ ] + "options": [ ], + "integrationTypes": [ + "GUILD_INSTALL", + "USER_INSTALL" + ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/help/QuickstartCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/help/QuickstartCommandTest.snap index 05383ac3..af1cbf89 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/help/QuickstartCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/help/QuickstartCommandTest.snap @@ -386,6 +386,9 @@ de.janno.discord.bot.command.help.QuickstartCommandTest.getCommandDefinition=[ "options": [ ], "autoComplete": true } + ], + "integrationTypes": [ + "GUILD_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/help/WelcomeCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/help/WelcomeCommandTest.snap index a7a2c1c5..c663bb44 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/help/WelcomeCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/help/WelcomeCommandTest.snap @@ -176,6 +176,9 @@ de.janno.discord.bot.command.help.WelcomeCommandTest.getCommandDefinition=[ "options": [ ], "autoComplete": false } + ], + "integrationTypes": [ + "GUILD_INSTALL" ] } ] diff --git a/bot/src/test/java/de/janno/discord/bot/command/sumCustomSet/SumCustomSetCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/sumCustomSet/SumCustomSetCommandTest.snap index cf356d8b..54b35e77 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/sumCustomSet/SumCustomSetCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/sumCustomSet/SumCustomSetCommandTest.snap @@ -697,6 +697,9 @@ de.janno.discord.bot.command.sumCustomSet.SumCustomSetCommandTest.getCommandDefi "options": [ ], "autoComplete": false } + ], + "integrationTypes": [ + "GUILD_INSTALL" ] } ] diff --git a/build.gradle.kts b/build.gradle.kts index a04c3aa4..b0411882 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,10 +10,6 @@ apply(plugin = "java") apply(plugin = "com.github.johnrengelman.shadow") apply(plugin = "jacoco") -repositories { - mavenCentral() - maven { setUrl("https://jitpack.io") } -} dependencies { implementation(project(":bot")) diff --git a/discord-connector/api/build.gradle.kts b/discord-connector/api/build.gradle.kts index aa6aaf18..3322592d 100644 --- a/discord-connector/api/build.gradle.kts +++ b/discord-connector/api/build.gradle.kts @@ -2,10 +2,6 @@ plugins { id("java") } -repositories { - mavenCentral() -} - dependencies { implementation(libs.reactor.core) implementation(libs.guava) diff --git a/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java b/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java index e29d46f3..85a06c32 100644 --- a/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java +++ b/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java @@ -29,13 +29,21 @@ public class CommandDefinition { Set descriptionLocales; @Singular List options; + @Singular + Set integrationTypes; - public CommandDefinition(@NonNull String name, @NonNull String description, Set nameLocales, Set descriptionLocales, List options) { + public CommandDefinition(@NonNull String name, + @NonNull String description, + Set nameLocales, + Set descriptionLocales, + List options, + Set integrationTypes) { this.name = name; this.description = description; this.nameLocales = nameLocales; this.descriptionLocales = descriptionLocales; this.options = options; + this.integrationTypes = (integrationTypes == null || integrationTypes.isEmpty()) ? Set.of(CommandIntegrationType.GUILD_INSTALL) : integrationTypes; //https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming Preconditions.checkArgument(NAME_PATTERN.matcher(name).matches(), "Invalid command name: %s", name); diff --git a/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandIntegrationType.java b/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandIntegrationType.java new file mode 100644 index 00000000..f2780db1 --- /dev/null +++ b/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandIntegrationType.java @@ -0,0 +1,10 @@ +package de.janno.discord.connector.api.slash; + +import java.util.Set; + +public enum CommandIntegrationType { + GUILD_INSTALL, + USER_INSTALL; + + public static Set ALL = Set.of(CommandIntegrationType.values()); +} diff --git a/discord-connector/build.gradle.kts b/discord-connector/build.gradle.kts index 21c1cd30..af1bb942 100644 --- a/discord-connector/build.gradle.kts +++ b/discord-connector/build.gradle.kts @@ -2,9 +2,6 @@ plugins { id("java-library") } -repositories { - mavenCentral() -} dependencies { api(project(":discord-connector:api")) diff --git a/discord-connector/jda/build.gradle.kts b/discord-connector/jda/build.gradle.kts index 7b474dc8..4e8e515d 100644 --- a/discord-connector/jda/build.gradle.kts +++ b/discord-connector/jda/build.gradle.kts @@ -2,16 +2,14 @@ plugins { id("java") } -repositories { - mavenCentral() -} - dependencies { implementation(project(":discord-connector:api")) - implementation("net.dv8tion:JDA:5.1.0") { + //todo update on jda release of user install + /* implementation("net.dv8tion:JDA:5.1.0") { exclude(module = "opus-java") - } + }*/ + implementation("com.github.freya022:JDA:f94446dd24") implementation(libs.reactor.core) implementation(libs.logback.classic) implementation(libs.log4j.to.slf4j) diff --git a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java index c28b8310..b5de876a 100644 --- a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java +++ b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java @@ -2,6 +2,7 @@ import de.janno.discord.connector.api.slash.*; import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.IntegrationType; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; @@ -31,9 +32,22 @@ public static CommandDefinition slashCommand2CommandDefinition(Command slashComm .nameLocales(discordLocale2LocaleName(slashCommand.getNameLocalizations())) .descriptionLocales(discordLocale2LocaleDescription(slashCommand.getDescriptionLocalizations())) .options(optionList) + .integrationTypes(integrationTypes2CommandIntegrationTypes(slashCommand.getIntegrationTypes())) .build(); } + private static Set commandIntegrationTypes2IntegrationTypes(Set commandIntegrationTypes) { + return commandIntegrationTypes.stream() + .map(i -> IntegrationType.valueOf(i.name())) + .collect(Collectors.toSet()); + } + + private static Set integrationTypes2CommandIntegrationTypes(Set integrationTypes) { + return integrationTypes.stream() + .map(i -> CommandIntegrationType.valueOf(i.name())) + .collect(Collectors.toSet()); + } + private static CommandDefinitionOption subcommandGroup2CommandDefinitionOption(Command.SubcommandGroup subcommandGroup) { return CommandDefinitionOption.builder() .type(CommandDefinitionOption.Type.SUB_COMMAND_GROUP) @@ -86,6 +100,7 @@ public static CommandData commandDefinition2CommandData(CommandDefinition comman return new CommandDataImpl(commandDefinition.getName(), commandDefinition.getDescription()) .setNameLocalizations(localeName2DiscordLocaleMap(commandDefinition.getNameLocales())) .setDescriptionLocalizations(localeDescription2DiscordLocaleMap(commandDefinition.getDescriptionLocales())) + .setIntegrationTypes(commandIntegrationTypes2IntegrationTypes(commandDefinition.getIntegrationTypes())) .addSubcommands(commandDefinition.getOptions().stream() .filter(c -> c.getType() == CommandDefinitionOption.Type.SUB_COMMAND) .map(ApplicationCommandConverter::commandDefinitionOption2SubcommandData) diff --git a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java index 4ca11839..c80cc09e 100644 --- a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java +++ b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java @@ -22,6 +22,7 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.events.session.ReadyEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.interactions.Interaction; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder; import net.dv8tion.jda.api.sharding.ShardManager; @@ -42,6 +43,8 @@ @Slf4j public class JdaClient { + private final static String WITHOUT_GUILD = "without_guild"; + public JdaClient(@NonNull List slashCommands, @NonNull List componentInteractEventHandlers, @NonNull Function welcomeMessageDefinition, @@ -135,7 +138,7 @@ public void onCommandAutoCompleteInteraction(@NonNull CommandAutoCompleteInterac Requester requester = new Requester(event.getInteraction().getUser().getName(), event.getChannel().getName(), - Optional.ofNullable(event.getInteraction().getGuild()).map(Guild::getName).orElse(""), + getGuildName(event.getInteraction()), event.getJDA().getShardInfo().getShardString(), userLocale); if (matchingHandler.size() != 1) { @@ -171,10 +174,10 @@ public void onSlashCommandInteraction(@NonNull SlashCommandInteractionEvent even .toList(); Locale userLocale = LocaleConverter.toLocale(event.getInteraction().getUserLocale()); - + //todo metric with: event.getContext() Requester requester = new Requester(event.getInteraction().getUser().getName(), event.getChannel().getName(), - Optional.ofNullable(event.getInteraction().getGuild()).map(Guild::getName).orElse(""), + getGuildName(event.getInteraction()), event.getJDA().getShardInfo().getShardString(), userLocale); if (matchingHandler.size() != 1) { @@ -206,10 +209,10 @@ public void onButtonInteraction(@NonNull ButtonInteractionEvent event) { .filter(command -> command.matchingComponentCustomId(event.getInteraction().getComponentId())) .toList(); Locale userLocale = LocaleConverter.toLocale(event.getInteraction().getUserLocale()); - + //todo metric interaction.getContext() Requester requester = new Requester(event.getInteraction().getUser().getName(), event.getChannel().getName(), - Optional.ofNullable(event.getInteraction().getGuild()).map(Guild::getName).orElse(""), + getGuildName(event.getInteraction()), event.getJDA().getShardInfo().getShardString(), userLocale); if (matchingHandler.size() != 1) { @@ -275,6 +278,13 @@ private static boolean hasPermission(GuildMessageChannel channel, Permission per .orElse(false); } + private static String getGuildName(Interaction interaction) { + if (!interaction.hasFullGuild()) { + return WITHOUT_GUILD; + } + return Optional.ofNullable(interaction.getGuild()).map(Guild::getName).orElse(WITHOUT_GUILD); + } + private static void shutdown(JDA jda) { log.info("ShardId={}: start jda shutdown", jda.getShardInfo().getShardString()); final long shutdownWaitTimeSec = Config.getInt("shutdownWaitTimeSec", 10); diff --git a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java index d7c44475..bdd0679c 100644 --- a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java +++ b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java @@ -58,7 +58,8 @@ public Long getGuildId() { @Override public Optional checkPermissions(@NonNull Locale userLocale) { - return checkPermission(event.getMessageChannel(), event.getGuild(), false, userLocale); + Guild guild = event.hasFullGuild() ? event.getGuild() : null; + return checkPermission(event.getMessageChannel(), guild, false, userLocale); } @Override diff --git a/settings.gradle.kts b/settings.gradle.kts index 8529e042..48edd962 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,8 +4,15 @@ include("discord-connector:api") include("discord-connector:jda") include("bot") - dependencyResolutionManagement { + //todo only mavenCentral() when user install is in the jda release + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenCentral() + maven { + setUrl("https://jitpack.io") + } + } versionCatalogs { create("libs") { library("lombok", "org.projectlombok:lombok:1.18.34") From 571b6646f9b4699bf78012f9346b3344cb553d7d Mon Sep 17 00:00:00 2001 From: twonirwana Date: Sun, 15 Sep 2024 13:50:23 +0200 Subject: [PATCH 2/4] cleanup --- README.adoc | 5 ++++- .../channelConfig/ChannelConfigCommand.java | 2 +- .../discord/bot/command/help/HelpCommand.java | 8 ++++--- bot/src/main/resources/botMessages.properties | 6 ++++-- .../main/resources/botMessages_de.properties | 6 ++++-- .../main/resources/botMessages_fr.properties | 6 ++++-- .../resources/botMessages_pt_BR.properties | 6 ++++-- .../discord/bot/SlashEventAdaptorMock.java | 4 ++++ .../bot/command/help/HelpCommandTest.java | 21 ++++++++++++++----- .../bot/command/help/HelpCommandTest.snap | 14 +++++++++++++ .../connector/api/SlashEventAdaptor.java | 2 ++ .../api/slash/CommandDefinition.java | 12 +++++------ .../jda/ApplicationCommandConverter.java | 18 +++++++++++++++- .../discord/connector/jda/JdaClient.java | 9 ++++++-- .../discord/connector/jda/JdaMetrics.java | 5 +++++ .../connector/jda/SlashEventAdapterImpl.java | 7 ++++++- 16 files changed, 102 insertions(+), 29 deletions(-) diff --git a/README.adoc b/README.adoc index 37014e03..b1f8b944 100644 --- a/README.adoc +++ b/README.adoc @@ -9,11 +9,14 @@ image:https://dcbadge.limes.pink/api/shield/812381127943782502?bot=true&style=fl This bot is for rolling dice in discord. The bot needs to be configured with a slash command in a channel and then provides a message with buttons. Upon clicking on a button the bot will roll the stored dice expression for the button, post the result and move the message with the buttons to the bottom of the channel. -If the message is pined, then it will only be copied and not moved. This allows user to roll dice without typing commands and thereby improves usability, especially for touchscreen users. + +If the message is pined, then it will only be copied and not moved. The bot supports Discord thread (the button message must be added after the thread creation), forum, Text in Voice, direct messages, and it is possible to send the answer in a different channel. It can provide images of the dice roll results and it is possible to configure channel or user specific aliases. +The bot can be user installed, this allows a user to use the slash commands (but no buttons) in server where the bot is not installed + image:image/example.webp[image] *Add to Discord channel by following this link*: https://discord.com/oauth2/authorize?client_id=812381127943782502[*Bot invite link*] diff --git a/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java b/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java index 3cd7a490..14d51a8b 100644 --- a/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java +++ b/bot/src/main/java/de/janno/discord/bot/command/channelConfig/ChannelConfigCommand.java @@ -156,7 +156,7 @@ public class ChannelConfigCommand implements SlashCommand { .descriptionLocales(I18n.allNoneEnglishMessagesDescriptions("channel_config.option.value.description")) .required(true) .build()) - .option(SCOPE_OPTION)//todo only user scope for userApp install or maybe extra command? + .option(SCOPE_OPTION) .option(ALIAS_TYPE_OPTION) .build(); private final PersistenceManager persistenceManager; diff --git a/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java b/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java index 76f342ad..ada86fd2 100644 --- a/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java +++ b/bot/src/main/java/de/janno/discord/bot/command/help/HelpCommand.java @@ -36,10 +36,12 @@ public class HelpCommand implements SlashCommand { @Override public @NonNull Mono handleSlashCommandEvent(@NonNull SlashEventAdaptor event, @NonNull Supplier uuidSupplier, @NonNull Locale userLocale) { BotMetrics.incrementSlashStartMetricCounter(getCommandId()); - //todo other text or command for user install + + final String context = event.isUserInstallInteraction() ? "userInstall" : "guildInstall"; + return event.replyWithEmbedOrMessageDefinition(EmbedOrMessageDefinition.builder() - .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.quickstart.field.name", userLocale), I18n.getMessage("help.quickstart.field.value", userLocale), false)) - .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.command.field.name", userLocale), I18n.getMessage("help.command.field.value", userLocale), false)) + .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.quickstart.field.name", userLocale), I18n.getMessage("help.quickstart.field.value." + context, userLocale), false)) + .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.command.field.name", userLocale), I18n.getMessage("help.command.field.value." + context, userLocale), false)) .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.documentation.field.name", userLocale), I18n.getMessage("help.documentation.field.value", userLocale), false)) .field(new EmbedOrMessageDefinition.Field(I18n.getMessage("help.discord.server.field.name", userLocale), I18n.getMessage("help.discord.server.field.value", userLocale), false)) .build(), true); diff --git a/bot/src/main/resources/botMessages.properties b/bot/src/main/resources/botMessages.properties index b4c00131..d19573f2 100644 --- a/bot/src/main/resources/botMessages.properties +++ b/bot/src/main/resources/botMessages.properties @@ -12,8 +12,10 @@ help.discord.server.field.name=Discord Server for News, Help and Feature Request custom_dice.help.example.field.value=`/custom_dice start buttons:3d6;10d10;3d20` custom_parameter.help.example.field.value=`/custom_parameter start expression:{numberOfDice:1<=>10}d{sides:4/6/8/10/12/20/100}` sum_custom_set.help.example.field.value=`/sum_custom_set start buttons:+;d6;1;2;3;4;5;6;7;8;9;0` -help.quickstart.field.value=Write `/welcome start` or `/quickstart system` to use pre-made RPG commands -help.command.field.value=Add `help` after a command to get specific help for it, e.g. `/custom_dice help` +help.quickstart.field.value.guildInstall=Write `/welcome start` or `/quickstart system` to use pre-made RPG commands +help.command.field.value.guildInstall=Add `help` after a command to get specific help for it, e.g. `/custom_dice help` +help.quickstart.field.value.userInstall=Write `/r expression: d20` to roll a twenty sided die +help.command.field.value.userInstall=Add `help` after a command to get specific help for it, e.g. `/r expression: help` help.documentation.field.value=https://github.com/twonirwana/DiscordDiceBot help.discord.server.field.value=https://discord.gg/e43BsqKpFr r.help.example.value=`/r expression: 1d6@Damage` diff --git a/bot/src/main/resources/botMessages_de.properties b/bot/src/main/resources/botMessages_de.properties index e401358f..bc7544e4 100644 --- a/bot/src/main/resources/botMessages_de.properties +++ b/bot/src/main/resources/botMessages_de.properties @@ -12,8 +12,10 @@ help.discord.server.field.name=Discord Server für Hilfe und Neuigkeiten custom_dice.help.example.field.value=`/custom_dice start buttons:3d6;10d10;3d20` custom_parameter.help.example.field.value=`/custom_parameter start ausdruck:{numberOfDice:1<=>10}d{sides:4/6/8/10/12/20/100}` sum_custom_set.help.example.field.value=`/sum_custom_set start buttons:+;d6;1;2;3;4;5;6;7;8;9;0` -help.quickstart.field.value=Schreib `/welcome start` oder `/quickstart system` um vorgefertigte RPG Kommandos zu starten -help.command.field.value=Füge `help` nach einem Befehl um spezifische Hilfe zu bekommen, z.B. `/custom_dice help` +help.quickstart.field.value.guildInstall=Schreib `/welcome start` oder `/quickstart system` um vorgefertigte RPG Kommandos zu starten +help.command.field.value.guildInstall=Füge `help` nach einem Befehl um spezifische Hilfe zu bekommen, z.B. `/custom_dice help` +help.quickstart.field.value.userInstall=Schreib `/r expression: d20` um einen zwanzig Seitigen Würfel zu würfeln +help.command.field.value.userInstall=Füge `help` nach einem Befehl um spezifische Hilfe zu bekommen, z.B. `/r expression: help` #help.documentation.field.value=https://github.com/twonirwana/DiscordDiceBot #help.discord.server.field.value=https://discord.gg/e43BsqKpFr r.help.example.value=`/{0} ausdruck:1d6` diff --git a/bot/src/main/resources/botMessages_fr.properties b/bot/src/main/resources/botMessages_fr.properties index 95a9f7f6..b8dab92f 100644 --- a/bot/src/main/resources/botMessages_fr.properties +++ b/bot/src/main/resources/botMessages_fr.properties @@ -12,8 +12,10 @@ help.discord.server.field.name=Serveur Discord pour l'aide et les nouvelles custom_dice.help.example.field.value=`/custom_dice démarrer boutons:3d6;10d10;3d20` custom_parameter.help.example.field.value=`/custom_parameter démarrer expression:{numberOfDice:1<=>10}d{sides:4/6/8/10/12/20/100}` sum_custom_set.help.example.field.value=`/sum_custom_set démarrer boutons:+;d6;1;2;3;4;5;6;7;8;9;0` -help.quickstart.field.value=Ecrire `/welcome start` ou `/quickstart système` pour utiliser des commandes RPG pré-faites -help.command.field.value=Ajoutez `help` après une commande pour obtenir une aide spécifique, par exemple `/custom_dice help` +help.quickstart.field.value.guildInstall=Ecrire `/welcome start` ou `/quickstart système` pour utiliser des commandes RPG pré-faites +help.command.field.value.guildInstall=Ajoutez `help` après une commande pour obtenir une aide spécifique, par exemple `/custom_dice help` +help.quickstart.field.value.userInstall=Ecrire `/r expression : d20` pour lancer un dé à vingt faces +help.command.field.value.userInstall=Ajoutez `help` après une commande pour obtenir une aide spécifique, par exemple `/r expression: help` help.documentation.field.value=https://github.com/twonirwana/DiscordDiceBot help.discord.server.field.value=https://discord.gg/e43BsqKpFr r.help.example.value=`/{0} expression:1d6` diff --git a/bot/src/main/resources/botMessages_pt_BR.properties b/bot/src/main/resources/botMessages_pt_BR.properties index b759734a..d188666b 100644 --- a/bot/src/main/resources/botMessages_pt_BR.properties +++ b/bot/src/main/resources/botMessages_pt_BR.properties @@ -13,8 +13,10 @@ help.discord.server.field.name=Servidor do Discord Server para ajuda e notícias custom_dice.help.example.field.value=`/custom_dice iniciar botoes:3d6;10d10;3d20` custom_parameter.help.example.field.value=`/custom_parameter iniciar formula:{numberOfDice:1<=>10}d{sides:4/6/8/10/12/20/100}` sum_custom_set.help.example.field.value=`/sum_custom_set iniciar botoes:+;d6;1;2;3;4;5;6;7;8;9;0` -help.quickstart.field.value=Escreva `/welcome iniciar` ou `/quickstart sistema` para usar comando de RPG pré-configurados -help.command.field.value=Adicione `help`depois de um comando para ter ajuda espefícia para ele, ex.: `/custom_dice help` +help.quickstart.field.value.guildInstall=Escreva `/welcome iniciar` ou `/quickstart sistema` para usar comando de RPG pré-configurados +help.command.field..guildInstall=Adicione `help`depois de um comando para ter ajuda espefícia para ele, ex.: `/custom_dice help` +help.quickstart.field.value.userInstall=Escreva `/r expression: d20` para lançar um dado de vinte lados +help.command.field.value.userInstall=Adicione `help`depois de um comando para ter ajuda espefícia para ele, ex.: `/r expression: help` help.documentation.field.value=https://github.com/twonirwana/DiscordDiceBot help.discord.server.field.value=https://discord.gg/e43BsqKpFr r.help.example.value=`/{0} formula:1d6` diff --git a/bot/src/test/java/de/janno/discord/bot/SlashEventAdaptorMock.java b/bot/src/test/java/de/janno/discord/bot/SlashEventAdaptorMock.java index 050957fe..2ff401e8 100644 --- a/bot/src/test/java/de/janno/discord/bot/SlashEventAdaptorMock.java +++ b/bot/src/test/java/de/janno/discord/bot/SlashEventAdaptorMock.java @@ -8,6 +8,7 @@ import de.janno.discord.connector.api.slash.CommandInteractionOption; import lombok.Getter; import lombok.NonNull; +import lombok.Setter; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.ParallelFlux; @@ -26,6 +27,9 @@ public class SlashEventAdaptorMock implements SlashEventAdaptor { private final List allReplays = new ArrayList<>(); private final long userId; private final Locale userLocale; + @Getter + @Setter + private boolean userInstallInteraction = false; @Getter private Optional firstButtonEventMockOfLastButtonMessage = Optional.empty(); diff --git a/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.java b/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.java index e8664152..8818077b 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.java +++ b/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.java @@ -2,17 +2,16 @@ import au.com.origin.snapshots.Expect; import au.com.origin.snapshots.junit5.SnapshotExtension; -import de.janno.discord.connector.api.SlashEventAdaptor; +import de.janno.discord.bot.SlashEventAdaptorMock; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import java.util.List; import java.util.Locale; import java.util.UUID; -import static org.mockito.Mockito.*; - @ExtendWith(SnapshotExtension.class) class HelpCommandTest { @@ -32,10 +31,22 @@ public void getId() { @Test void handleSlashCommandEvent() { - SlashEventAdaptor slashEventAdaptor = mock(SlashEventAdaptor.class); - when(slashEventAdaptor.replyWithEmbedOrMessageDefinition(any(), anyBoolean())).thenReturn(Mono.empty()); + SlashEventAdaptorMock slashEventAdaptor = new SlashEventAdaptorMock(List.of()); Mono res = underTest.handleSlashCommandEvent(slashEventAdaptor, () -> UUID.fromString("00000000-0000-0000-0000-000000000000"), Locale.ENGLISH); StepVerifier.create(res).verifyComplete(); + + expect.toMatchSnapshot(slashEventAdaptor.getSortedActions()); + } + + @Test + void handleSlashCommandEvent_userInstall() { + SlashEventAdaptorMock slashEventAdaptor = new SlashEventAdaptorMock(List.of()); + slashEventAdaptor.setUserInstallInteraction(true); + + Mono res = underTest.handleSlashCommandEvent(slashEventAdaptor, () -> UUID.fromString("00000000-0000-0000-0000-000000000000"), Locale.ENGLISH); + StepVerifier.create(res).verifyComplete(); + + expect.toMatchSnapshot(slashEventAdaptor.getSortedActions()); } } \ No newline at end of file diff --git a/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap b/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap index b8356436..3701f3b9 100644 --- a/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap +++ b/bot/src/test/java/de/janno/discord/bot/command/help/HelpCommandTest.snap @@ -28,4 +28,18 @@ de.janno.discord.bot.command.help.HelpCommandTest.getCommandDefinition=[ de.janno.discord.bot.command.help.HelpCommandTest.getId=[ "help" +] + + +de.janno.discord.bot.command.help.HelpCommandTest.handleSlashCommandEvent=[ + [ + "replyWithEmbedOrMessageDefinition: EmbedOrMessageDefinition(title=null, descriptionOrContent=null, fields=[EmbedOrMessageDefinition.Field(name=Quickstart, value=Write `/welcome start` or `/quickstart system` to use pre-made RPG commands, inline=false), EmbedOrMessageDefinition.Field(name=Command help, value=Add `help` after a command to get specific help for it, e.g. `/custom_dice help`, inline=false), EmbedOrMessageDefinition.Field(name=Full documentation, value=https://github.com/twonirwana/DiscordDiceBot, inline=false), EmbedOrMessageDefinition.Field(name=Discord Server for News, Help and Feature Requests, value=https://discord.gg/e43BsqKpFr, inline=false)], componentRowDefinitions=[], hasImage=false, type=EMBED, userReference=false, sendToOtherChannelId=null)" + ] +] + + +de.janno.discord.bot.command.help.HelpCommandTest.handleSlashCommandEvent_userInstall=[ + [ + "replyWithEmbedOrMessageDefinition: EmbedOrMessageDefinition(title=null, descriptionOrContent=null, fields=[EmbedOrMessageDefinition.Field(name=Quickstart, value=Write `/r expression: d20` to roll a twenty sided die, inline=false), EmbedOrMessageDefinition.Field(name=Command help, value=Add `help` after a command to get specific help for it, e.g. `/r expression: help`, inline=false), EmbedOrMessageDefinition.Field(name=Full documentation, value=https://github.com/twonirwana/DiscordDiceBot, inline=false), EmbedOrMessageDefinition.Field(name=Discord Server for News, Help and Feature Requests, value=https://discord.gg/e43BsqKpFr, inline=false)], componentRowDefinitions=[], hasImage=false, type=EMBED, userReference=false, sendToOtherChannelId=null)" + ] ] \ No newline at end of file diff --git a/discord-connector/api/src/main/java/de/janno/discord/connector/api/SlashEventAdaptor.java b/discord-connector/api/src/main/java/de/janno/discord/connector/api/SlashEventAdaptor.java index a6f6dd25..1126e564 100644 --- a/discord-connector/api/src/main/java/de/janno/discord/connector/api/SlashEventAdaptor.java +++ b/discord-connector/api/src/main/java/de/janno/discord/connector/api/SlashEventAdaptor.java @@ -27,4 +27,6 @@ public interface SlashEventAdaptor extends DiscordAdapter { boolean isValidAnswerChannel(long channelId); long getUserId(); + + boolean isUserInstallInteraction(); } diff --git a/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java b/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java index 85a06c32..8fa1c464 100644 --- a/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java +++ b/discord-connector/api/src/main/java/de/janno/discord/connector/api/slash/CommandDefinition.java @@ -1,15 +1,13 @@ package de.janno.discord.connector.api.slash; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSortedSet; import lombok.Builder; import lombok.NonNull; import lombok.Singular; import lombok.Value; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -30,20 +28,20 @@ public class CommandDefinition { @Singular List options; @Singular - Set integrationTypes; + SortedSet integrationTypes; public CommandDefinition(@NonNull String name, @NonNull String description, Set nameLocales, Set descriptionLocales, List options, - Set integrationTypes) { + SortedSet integrationTypes) { this.name = name; this.description = description; this.nameLocales = nameLocales; this.descriptionLocales = descriptionLocales; this.options = options; - this.integrationTypes = (integrationTypes == null || integrationTypes.isEmpty()) ? Set.of(CommandIntegrationType.GUILD_INSTALL) : integrationTypes; + this.integrationTypes = (integrationTypes == null || integrationTypes.isEmpty()) ? ImmutableSortedSet.of(CommandIntegrationType.GUILD_INSTALL) : integrationTypes; //https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming Preconditions.checkArgument(NAME_PATTERN.matcher(name).matches(), "Invalid command name: %s", name); diff --git a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java index b5de876a..4f6bc1f9 100644 --- a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java +++ b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/ApplicationCommandConverter.java @@ -1,8 +1,11 @@ package de.janno.discord.connector.jda; +import com.google.common.collect.ImmutableSortedSet; import de.janno.discord.connector.api.slash.*; +import lombok.NonNull; import net.dv8tion.jda.api.interactions.DiscordLocale; import net.dv8tion.jda.api.interactions.IntegrationType; +import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; @@ -42,7 +45,7 @@ private static Set commandIntegrationTypes2IntegrationTypes(Set .collect(Collectors.toSet()); } - private static Set integrationTypes2CommandIntegrationTypes(Set integrationTypes) { + private static Set integrationTypes2CommandIntegrationTypes(Set integrationTypes) { return integrationTypes.stream() .map(i -> CommandIntegrationType.valueOf(i.name())) .collect(Collectors.toSet()); @@ -96,11 +99,24 @@ private static CommandDefinitionOption commandOption2CommandDefinitionOption(Com .build(); } + private static Set getInteractionContextTypeFromInteractionTypes(@NonNull Set interactionTypes) { + ImmutableSortedSet.Builder builder = new ImmutableSortedSet.Builder<>(Enum::compareTo); + builder.add(InteractionContextType.BOT_DM); + if (interactionTypes.contains(CommandIntegrationType.GUILD_INSTALL)) { + builder.add(InteractionContextType.GUILD); + } + if (interactionTypes.contains(CommandIntegrationType.USER_INSTALL)) { + builder.add(InteractionContextType.PRIVATE_CHANNEL); + } + return builder.build(); + } + public static CommandData commandDefinition2CommandData(CommandDefinition commandDefinition) { return new CommandDataImpl(commandDefinition.getName(), commandDefinition.getDescription()) .setNameLocalizations(localeName2DiscordLocaleMap(commandDefinition.getNameLocales())) .setDescriptionLocalizations(localeDescription2DiscordLocaleMap(commandDefinition.getDescriptionLocales())) .setIntegrationTypes(commandIntegrationTypes2IntegrationTypes(commandDefinition.getIntegrationTypes())) + .setContexts(getInteractionContextTypeFromInteractionTypes(commandDefinition.getIntegrationTypes())) .addSubcommands(commandDefinition.getOptions().stream() .filter(c -> c.getType() == CommandDefinitionOption.Type.SUB_COMMAND) .map(ApplicationCommandConverter::commandDefinitionOption2SubcommandData) diff --git a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java index c80cc09e..32e3b81f 100644 --- a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java +++ b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaClient.java @@ -174,7 +174,12 @@ public void onSlashCommandInteraction(@NonNull SlashCommandInteractionEvent even .toList(); Locale userLocale = LocaleConverter.toLocale(event.getInteraction().getUserLocale()); - //todo metric with: event.getContext() + + //no central slash handler, therefore we set the metric here + if (event.isUserInstalledInteractionOnly()) { + JdaMetrics.userInstallSlashCommand(); + } + Requester requester = new Requester(event.getInteraction().getUser().getName(), event.getChannel().getName(), getGuildName(event.getInteraction()), @@ -209,7 +214,7 @@ public void onButtonInteraction(@NonNull ButtonInteractionEvent event) { .filter(command -> command.matchingComponentCustomId(event.getInteraction().getComponentId())) .toList(); Locale userLocale = LocaleConverter.toLocale(event.getInteraction().getUserLocale()); - //todo metric interaction.getContext() + Requester requester = new Requester(event.getInteraction().getUser().getName(), event.getChannel().getName(), getGuildName(event.getInteraction()), diff --git a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaMetrics.java b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaMetrics.java index 067ed24c..9e03ae15 100644 --- a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaMetrics.java +++ b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/JdaMetrics.java @@ -20,6 +20,7 @@ public class JdaMetrics { private static final String METRIC_PREFIX = "dice."; private static final String METRIC_WELCOME_COUNTER_PREFIX = "welcomeCounter"; + private static final String METRIC_USER_INSTALL_PREFIX = "userInstall"; private static final String USER_LOCALE = "userLocale"; private static final String SHARD_ID = "shardId"; @@ -91,4 +92,8 @@ private static String lastTwoCharacters(String in) { } return in.substring(in.length() - 2).toUpperCase(); } + + public static void userInstallSlashCommand() { + globalRegistry.counter(METRIC_PREFIX + METRIC_USER_INSTALL_PREFIX).increment(); + } } diff --git a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java index bdd0679c..4bb6e4b9 100644 --- a/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java +++ b/discord-connector/jda/src/main/java/de/janno/discord/connector/jda/SlashEventAdapterImpl.java @@ -40,6 +40,7 @@ public class SlashEventAdapterImpl extends DiscordAdapterImpl implements SlashEv @NonNull private final String invokingGuildMemberName; + public SlashEventAdapterImpl(@NonNull SlashCommandInteractionEvent event, @NonNull Requester requester) { this.event = event; this.requester = requester; @@ -47,7 +48,6 @@ public SlashEventAdapterImpl(@NonNull SlashCommandInteractionEvent event, @NonNu this.commandString = String.format("`%s`", event.getCommandString()); this.guildId = Optional.ofNullable(event.getGuild()).map(Guild::getIdLong).orElse(null); this.invokingGuildMemberName = Optional.ofNullable(event.getMember()).map(Member::getEffectiveName).orElse(event.getUser().getName()); - } @Nullable @@ -143,6 +143,11 @@ public long getUserId() { return event.getUser().getIdLong(); } + @Override + public boolean isUserInstallInteraction() { + return event.isUserInstalledInteractionOnly(); + } + @Override protected @NonNull MessageChannel getMessageChannel() { return event.getMessageChannel(); From 95f82626fbfb6b77209f663744d92e36fbfc7d8b Mon Sep 17 00:00:00 2001 From: twonirwana Date: Sun, 15 Sep 2024 17:40:43 +0200 Subject: [PATCH 3/4] add test --- .../jda/ApplicationCommandConverterTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/discord-connector/jda/src/test/java/de/janno/discord/connector/jda/ApplicationCommandConverterTest.java b/discord-connector/jda/src/test/java/de/janno/discord/connector/jda/ApplicationCommandConverterTest.java index 43525b45..273be15f 100644 --- a/discord-connector/jda/src/test/java/de/janno/discord/connector/jda/ApplicationCommandConverterTest.java +++ b/discord-connector/jda/src/test/java/de/janno/discord/connector/jda/ApplicationCommandConverterTest.java @@ -2,6 +2,9 @@ import de.janno.discord.connector.api.slash.CommandDefinition; import de.janno.discord.connector.api.slash.CommandDefinitionOption; +import de.janno.discord.connector.api.slash.CommandIntegrationType; +import net.dv8tion.jda.api.interactions.IntegrationType; +import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; @@ -9,6 +12,8 @@ import net.dv8tion.jda.internal.interactions.CommandDataImpl; import org.junit.jupiter.api.Test; +import java.util.Set; + import static org.assertj.core.api.Assertions.assertThat; class ApplicationCommandConverterTest { @@ -27,6 +32,22 @@ void notEqual_differentName() { .isNotEqualTo(ApplicationCommandConverter.commandDefinition2CommandData(commandDefinition)); } + @Test + void setInteractionType() { + CommandDefinition commandDefinition = CommandDefinition.builder() + .name("a") + .description("description") + .integrationTypes(Set.of(CommandIntegrationType.GUILD_INSTALL, CommandIntegrationType.USER_INSTALL)) + .build(); + + CommandData res = ApplicationCommandConverter.commandDefinition2CommandData(commandDefinition); + + assertThat(res.getIntegrationTypes()) + .containsExactlyInAnyOrder(IntegrationType.GUILD_INSTALL, IntegrationType.USER_INSTALL); + assertThat(res.getContexts()) + .containsExactlyInAnyOrder(InteractionContextType.GUILD, InteractionContextType.BOT_DM, InteractionContextType.PRIVATE_CHANNEL); + } + @Test void notEqual_differentDescription() { CommandDefinition commandDefinition = CommandDefinition.builder() From bf6d7d4acee43513e969579a61b47d8da3c59ec1 Mon Sep 17 00:00:00 2001 From: twonirwana Date: Thu, 31 Oct 2024 16:09:25 +0100 Subject: [PATCH 4/4] update --- discord-connector/jda/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord-connector/jda/build.gradle.kts b/discord-connector/jda/build.gradle.kts index 4607968d..dd3568e2 100644 --- a/discord-connector/jda/build.gradle.kts +++ b/discord-connector/jda/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { /* implementation("net.dv8tion:JDA:5.1.2") { exclude(module = "opus-java") }*/ - implementation("com.github.freya022:JDA:f94446dd24") + implementation("com.github.freya022:JDA:f5840dab04") implementation(libs.reactor.core) implementation(libs.logback.classic) implementation(libs.log4j.to.slf4j)