From 4ff1dc182b6e6581a78e872b45a57bc763ffd793 Mon Sep 17 00:00:00 2001 From: Tijs Date: Mon, 3 Oct 2022 22:50:15 +0200 Subject: [PATCH 01/12] Bugfix In BotCommandAdapter the Interactor's name was used without prefix, but to forward from the button the prefix is needed. --- .../tjbot/commands/BotCommandAdapter.java | 5 +++-- .../togetherjava/tjbot/commands/system/BotCore.java | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java index c03d0b82ca..f7cf697420 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java @@ -130,7 +130,8 @@ protected final String generateComponentId(String... args) { */ @SuppressWarnings({"OverloadedVarargsMethod", "WeakerAccess"}) protected final String generateComponentId(Lifespan lifespan, String... args) { - return componentIdGenerator.generate(new ComponentId(getName(), Arrays.asList(args)), - lifespan); + return componentIdGenerator + .generate(new ComponentId(UserInteractorPrefix.getPrefixedNameFromInstance(this), + Arrays.asList(args)), lifespan); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java index 8cc95de6f1..cc481b3ce0 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java @@ -104,12 +104,12 @@ public BotCore(JDA jda, Database database, Config config) { componentIdParser = uuid -> componentIdStore.get(UUID.fromString(uuid)); Collection interactors = getInteractors(); - interactors.forEach(slashCommand -> slashCommand - .acceptComponentIdGenerator(((componentId, lifespan) -> { - UUID uuid = UUID.randomUUID(); - componentIdStore.putOrThrow(uuid, componentId, lifespan); - return uuid.toString(); - }))); + interactors.forEach( + interactor -> interactor.acceptComponentIdGenerator(((componentId, lifespan) -> { + UUID uuid = UUID.randomUUID(); + componentIdStore.putOrThrow(uuid, componentId, lifespan); + return uuid.toString(); + }))); if (logger.isInfoEnabled()) { logger.info("Available user interactors: {}", interactors); From 53ed3f0c7f8404cc85fd068958dbdacd9d34ab23 Mon Sep 17 00:00:00 2001 From: illuminator3 Date: Mon, 3 Oct 2022 23:01:37 +0200 Subject: [PATCH 02/12] for tijs --- .../tjbot/commands/tags/TagCommand.java | 9 +++- .../tjbot/commands/tags/TagManageCommand.java | 4 +- .../tjbot/commands/tags/TagSystem.java | 41 +++++++++++++++---- .../tjbot/commands/tags/TagSystemTest.java | 4 +- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java index 2e00048a18..312e988f17 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java @@ -2,6 +2,7 @@ import net.dv8tion.jda.api.EmbedBuilder; 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.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; @@ -9,6 +10,7 @@ import org.togetherjava.tjbot.commands.SlashCommandAdapter; import java.time.Instant; +import java.util.List; import java.util.Objects; /** @@ -46,7 +48,7 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); OptionMapping replyToUserOption = event.getOption(REPLY_TO_USER_OPTION); - if (tagSystem.handleIsUnknownTag(id, event)) { + if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId)) { return; } @@ -62,4 +64,9 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { } message.queue(); } + + @Override + public void onButtonClick(ButtonInteractionEvent event, List args) { + System.out.println(event.getComponentId()); + } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java index f496ed104a..31e844b201 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java @@ -151,7 +151,7 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { private void rawTag(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); - if (tagSystem.handleIsUnknownTag(id, event)) { + if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId)) { return; } @@ -316,7 +316,7 @@ private Optional getTagContent(Subcommand subcommand, String id) { private boolean isWrongTagStatusAndHandle(TagStatus requiredTagStatus, String id, IReplyCallback event) { if (requiredTagStatus == TagStatus.EXISTS) { - return tagSystem.handleIsUnknownTag(id, event); + return tagSystem.handleIsUnknownTag(id, event, super::generateComponentId); } else if (requiredTagStatus == TagStatus.NOT_EXISTS) { if (tagSystem.hasTag(id)) { event.reply("The tag with id '%s' already exists.".formatted(id)) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java index 8a34131be9..a2e44ae21b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java @@ -2,16 +2,18 @@ import net.dv8tion.jda.api.entities.Emoji; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; +import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; +import org.apache.commons.collections4.ListUtils; import org.togetherjava.tjbot.commands.utils.StringDistances; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.db.generated.tables.Tags; import org.togetherjava.tjbot.db.generated.tables.records.TagsRecord; import java.awt.Color; -import java.util.Optional; -import java.util.Set; +import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -19,6 +21,17 @@ * underlying database. */ public final class TagSystem { + /** + * The amount of candidates that are suggested as buttons in the message that tells the user + * that the tag they tried accessing doesn't exist + */ + private static final int CANDIDATE_SUGGESTIONS_PER_USAGE = 5; + + /** + * todo document + */ + protected static final String TAG_SUGGESTION_INDICATOR = "tag suggestion"; + /** * The ambient color to use for tag system related messages. */ @@ -57,17 +70,31 @@ static Button createDeleteButton(String componentId) { * @param event the event to send messages with * @return whether the given tag is unknown to the system */ - boolean handleIsUnknownTag(String id, IReplyCallback event) { + boolean handleIsUnknownTag(String id, IReplyCallback event, Function componentIdGenerator) { if (hasTag(id)) { return false; } - String suggestionText = StringDistances.closestMatch(id, getAllIds()) - .map(", did you perhaps mean '%s'?"::formatted) - .orElse("."); - event.reply("Could not find any tag with id '%s'%s".formatted(id, suggestionText)) + List candidates = getAllIds().stream() + .sorted(Comparator + .comparingInt(candidate -> StringDistances.editDistance(id, candidate))) + .limit(CANDIDATE_SUGGESTIONS_PER_USAGE) + .toList(); + List rows = new ArrayList<>(); + List> partition = ListUtils.partition(candidates, 5); + + for (List part : partition) { + rows.add(ActionRow + .of(part.stream().map(i -> Button.secondary(componentIdGenerator.apply(new String[] { TAG_SUGGESTION_INDICATOR, i }), i)).toList())); + } + + event + .reply("Could not find any tag with id '%s', did you perhaps mean any of the following?" + .formatted(id)) .setEphemeral(true) + .addActionRows(rows) .queue(); + return true; } diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java index 9c441b023d..1adb779ba2 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java @@ -52,10 +52,10 @@ void handleIsUnknownTag() { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(new TagCommand(system)).build(); - assertFalse(system.handleIsUnknownTag("known", event)); + assertFalse(system.handleIsUnknownTag("known", event, a -> null)); verify(event, never()).reply(anyString()); - assertTrue(system.handleIsUnknownTag("unknown", event)); + assertTrue(system.handleIsUnknownTag("unknown", event, a -> null)); verify(event).reply(anyString()); } From a2c7a63135374a295096ff469f7e50dd71a2250d Mon Sep 17 00:00:00 2001 From: Tijs Date: Mon, 3 Oct 2022 23:38:39 +0200 Subject: [PATCH 03/12] Fixed tests not working --- .../tjbot/commands/SlashCommandAdapterTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/SlashCommandAdapterTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/SlashCommandAdapterTest.java index bc5b18ed7d..7a0bf4f3da 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/SlashCommandAdapterTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/SlashCommandAdapterTest.java @@ -10,6 +10,8 @@ final class SlashCommandAdapterTest { private static final String NAME = "foo"; + private static final String PREFIXED_NAME = + UserInteractorPrefix.SLASH_COMMAND.getPrefix() + NAME; private static final String DESCRIPTION = "Foo command"; private static final CommandVisibility VISIBILITY = CommandVisibility.GUILD; private static final int UNIQUE_ID_ITERATIONS = 20; @@ -71,7 +73,7 @@ void generateComponentId() { String[] elements = {"foo", "bar", "baz"}; String[] componentIdText = adapter.generateComponentId(elements).split(";"); assertEquals(3, componentIdText.length); - assertEquals(NAME, componentIdText[0]); + assertEquals(PREFIXED_NAME, componentIdText[0]); assertEquals(Integer.toString(elements.length), componentIdText[1]); assertEquals(Lifespan.REGULAR.toString(), componentIdText[2]); @@ -79,7 +81,7 @@ void generateComponentId() { for (Lifespan lifespan : Lifespan.values()) { componentIdText = adapter.generateComponentId(lifespan, elements).split(";"); assertEquals(3, componentIdText.length); - assertEquals(NAME, componentIdText[0]); + assertEquals(PREFIXED_NAME, componentIdText[0]); assertEquals(Integer.toString(elements.length), componentIdText[1]); assertEquals(lifespan.toString(), componentIdText[2]); } From 4632190d415a5c09a6cab5e6fc3fbb74c307bb08 Mon Sep 17 00:00:00 2001 From: illuminator3 Date: Tue, 4 Oct 2022 00:00:45 +0200 Subject: [PATCH 04/12] yes --- .../tjbot/commands/tags/TagCommand.java | 45 +++++++++++++------ .../tjbot/commands/tags/TagManageCommand.java | 4 +- .../tjbot/commands/tags/TagSystem.java | 17 +++++-- .../tjbot/commands/tags/TagSystemTest.java | 4 +- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java index 312e988f17..40d51525b1 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java @@ -1,17 +1,21 @@ package org.togetherjava.tjbot.commands.tags; import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.IMentionable; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +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.requests.restaction.interactions.ReplyCallbackAction; import org.togetherjava.tjbot.commands.CommandVisibility; import org.togetherjava.tjbot.commands.SlashCommandAdapter; +import javax.annotation.Nullable; import java.time.Instant; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * Implements the {@code /tag} command which lets the bot respond content of a tag that has been @@ -48,25 +52,40 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); OptionMapping replyToUserOption = event.getOption(REPLY_TO_USER_OPTION); - if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId)) { + if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId, + replyToUserOption)) { return; } - ReplyCallbackAction message = event - .replyEmbeds(new EmbedBuilder().setDescription(tagSystem.getTag(id).orElseThrow()) - .setFooter(event.getUser().getName() + " • used " + event.getCommandString()) - .setTimestamp(Instant.now()) - .setColor(TagSystem.AMBIENT_COLOR) - .build()); - - if (replyToUserOption != null) { - message = message.setContent(replyToUserOption.getAsUser().getAsMention()); - } - message.queue(); + sendTagReply(event, event.getUser().getName(), id, Optional.of(event.getCommandString()), + Optional.ofNullable(replyToUserOption) + .map(OptionMapping::getAsUser) + .map(IMentionable::getAsMention)); } @Override public void onButtonClick(ButtonInteractionEvent event, List args) { - System.out.println(event.getComponentId()); + if (!TagSystem.TAG_SUGGESTION_INDICATOR.equals(args.get(0))) { + return; + } + + sendTagReply(event, event.getUser().getName(), args.get(1), Optional.empty(), + Optional.ofNullable(args.get(2))); + } + + /** + * Sends the reply for a successfull /tag use (i.e. the given tag exists) + */ + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + private void sendTagReply(IReplyCallback callback, String userName, String tag, + Optional commandString, Optional replyToUser) { + callback + .replyEmbeds(new EmbedBuilder().setDescription(tagSystem.getTag(tag).orElseThrow()) + .setFooter(userName + commandString.map(s -> " • used " + s).orElse("")) + .setTimestamp(Instant.now()) + .setColor(TagSystem.AMBIENT_COLOR) + .build()) + .setContent(replyToUser.orElse("")) + .queue(); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java index 31e844b201..d5ed2d116d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java @@ -151,7 +151,7 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { private void rawTag(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); - if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId)) { + if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId, null)) { return; } @@ -316,7 +316,7 @@ private Optional getTagContent(Subcommand subcommand, String id) { private boolean isWrongTagStatusAndHandle(TagStatus requiredTagStatus, String id, IReplyCallback event) { if (requiredTagStatus == TagStatus.EXISTS) { - return tagSystem.handleIsUnknownTag(id, event, super::generateComponentId); + return tagSystem.handleIsUnknownTag(id, event, super::generateComponentId, null); } else if (requiredTagStatus == TagStatus.NOT_EXISTS) { if (tagSystem.hasTag(id)) { event.reply("The tag with id '%s' already exists.".formatted(id)) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java index a2e44ae21b..7702907c8b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java @@ -2,6 +2,7 @@ import net.dv8tion.jda.api.entities.Emoji; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; @@ -11,6 +12,7 @@ import org.togetherjava.tjbot.db.generated.tables.Tags; import org.togetherjava.tjbot.db.generated.tables.records.TagsRecord; +import javax.annotation.Nullable; import java.awt.Color; import java.util.*; import java.util.function.Function; @@ -70,7 +72,9 @@ static Button createDeleteButton(String componentId) { * @param event the event to send messages with * @return whether the given tag is unknown to the system */ - boolean handleIsUnknownTag(String id, IReplyCallback event, Function componentIdGenerator) { + boolean handleIsUnknownTag(String id, IReplyCallback event, + Function componentIdGenerator, + @Nullable OptionMapping userToReplyTo) { if (hasTag(id)) { return false; } @@ -84,8 +88,15 @@ boolean handleIsUnknownTag(String id, IReplyCallback event, Function> partition = ListUtils.partition(candidates, 5); for (List part : partition) { - rows.add(ActionRow - .of(part.stream().map(i -> Button.secondary(componentIdGenerator.apply(new String[] { TAG_SUGGESTION_INDICATOR, i }), i)).toList())); + rows.add( + ActionRow + .of(part.stream() + .map(i -> Button.secondary(componentIdGenerator.apply(new String[] { + TAG_SUGGESTION_INDICATOR, i, + userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention() + : null}), + i)) + .toList())); } event diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java index 1adb779ba2..8b75a8e94a 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java @@ -52,10 +52,10 @@ void handleIsUnknownTag() { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(new TagCommand(system)).build(); - assertFalse(system.handleIsUnknownTag("known", event, a -> null)); + assertFalse(system.handleIsUnknownTag("known", event, a -> null, null)); verify(event, never()).reply(anyString()); - assertTrue(system.handleIsUnknownTag("unknown", event, a -> null)); + assertTrue(system.handleIsUnknownTag("unknown", event, a -> null, null)); verify(event).reply(anyString()); } From f45bf2e3f83df763bfaa9196108504a43cb468fd Mon Sep 17 00:00:00 2001 From: illuminator3 Date: Tue, 4 Oct 2022 00:08:37 +0200 Subject: [PATCH 05/12] why don't you just fix the imports for me sonar --- .../java/org/togetherjava/tjbot/commands/tags/TagCommand.java | 2 -- .../java/org/togetherjava/tjbot/commands/tags/TagSystem.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java index 40d51525b1..69c26b3dc9 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java @@ -7,11 +7,9 @@ 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.requests.restaction.interactions.ReplyCallbackAction; import org.togetherjava.tjbot.commands.CommandVisibility; import org.togetherjava.tjbot.commands.SlashCommandAdapter; -import javax.annotation.Nullable; import java.time.Instant; import java.util.List; import java.util.Objects; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java index 7702907c8b..2d8c3be254 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java @@ -32,7 +32,7 @@ public final class TagSystem { /** * todo document */ - protected static final String TAG_SUGGESTION_INDICATOR = "tag suggestion"; + static final String TAG_SUGGESTION_INDICATOR = "tag suggestion"; /** * The ambient color to use for tag system related messages. From c6885a24dd01c52f8d206ae7848dfddfe7fb118c Mon Sep 17 00:00:00 2001 From: illuminator3 Date: Tue, 4 Oct 2022 12:52:38 +0200 Subject: [PATCH 06/12] fix tests --- .../org/togetherjava/tjbot/commands/tags/TagSystem.java | 4 ++-- .../togetherjava/tjbot/commands/tags/TagCommandTest.java | 7 ++++++- .../togetherjava/tjbot/commands/tags/TagSystemTest.java | 4 ++-- .../test/java/org/togetherjava/tjbot/jda/JdaTester.java | 3 +++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java index 2d8c3be254..721bec2119 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java @@ -100,8 +100,8 @@ boolean handleIsUnknownTag(String id, IReplyCallback event, } event - .reply("Could not find any tag with id '%s', did you perhaps mean any of the following?" - .formatted(id)) + .reply("Could not find any tag with id '%s'%s" + .formatted(id, candidates.isEmpty() ? "." : ", did you perhaps mean any of the following?")) .setEphemeral(true) .addActionRows(rows) .queue(); diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java index eced581e77..02b129e518 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java @@ -7,6 +7,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.togetherjava.tjbot.commands.SlashCommand; +import org.togetherjava.tjbot.commands.componentids.ComponentId; +import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; +import org.togetherjava.tjbot.commands.componentids.Lifespan; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.db.generated.tables.Tags; import org.togetherjava.tjbot.jda.JdaTester; @@ -27,6 +30,8 @@ void setUp() { system = spy(new TagSystem(database)); jdaTester = new JdaTester(); command = new TagCommand(system); + + command.acceptComponentIdGenerator((componentId, lifespan) -> "foo"); } private SlashCommandInteractionEvent triggerSlashCommand(String id, @@ -65,7 +70,7 @@ void canNotFindTagSuggestDifferentTag() { // THEN responds that the tag could not be found and instead suggests using the other tag verify(event) - .reply("Could not find any tag with id 'second', did you perhaps mean 'first'?"); + .reply("Could not find any tag with id 'second', did you perhaps mean any of the following?"); } @Test diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java index 8b75a8e94a..852d32cd89 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java @@ -52,10 +52,10 @@ void handleIsUnknownTag() { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(new TagCommand(system)).build(); - assertFalse(system.handleIsUnknownTag("known", event, a -> null, null)); + assertFalse(system.handleIsUnknownTag("known", event, a -> "foo", null)); verify(event, never()).reply(anyString()); - assertTrue(system.handleIsUnknownTag("unknown", event, a -> null, null)); + assertTrue(system.handleIsUnknownTag("unknown", event, a -> "foo", null)); verify(event).reply(anyString()); } diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java index 381d102578..cd3e664c56 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java @@ -10,6 +10,7 @@ import net.dv8tion.jda.api.exceptions.ErrorResponseException; import net.dv8tion.jda.api.interactions.InteractionHook; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; +import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.ItemComponent; import net.dv8tion.jda.api.requests.ErrorResponse; import net.dv8tion.jda.api.requests.Response; @@ -151,6 +152,8 @@ public JdaTester() { when(replyAction.addActionRow(anyCollection())).thenReturn(replyAction); when(replyAction.addActionRow(ArgumentMatchers.any())) .thenReturn(replyAction); + when(replyAction.addActionRows(anyCollection())).thenReturn(replyAction); + when(replyAction.addActionRows(ArgumentMatchers.any())).thenReturn(replyAction); when(replyAction.setContent(anyString())).thenReturn(replyAction); when(replyAction.addFile(any(byte[].class), any(String.class), any(AttachmentOption.class))) .thenReturn(replyAction); From 1217a4e3fb41285e8587cbfba74b56d5f62c6f39 Mon Sep 17 00:00:00 2001 From: illuminator3 Date: Tue, 4 Oct 2022 13:44:34 +0200 Subject: [PATCH 07/12] fix compilation & requested changes --- .../tjbot/commands/tags/TagSystem.java | 26 ++++++++----------- .../org/togetherjava/tjbot/jda/JdaTester.java | 4 +-- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java index 8cb7d0a513..bfb2da0bec 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java @@ -6,6 +6,7 @@ import net.dv8tion.jda.api.interactions.components.ActionRow; 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.interactions.ReplyCallbackAction; import org.apache.commons.collections4.ListUtils; import org.togetherjava.tjbot.commands.utils.StringDistances; import org.togetherjava.tjbot.db.Database; @@ -24,10 +25,9 @@ */ public final class TagSystem { /** - * The amount of candidates that are suggested as buttons in the message that tells the user - * that the tag they tried accessing doesn't exist + * The amount of tags suggested when the user types an incorrect tag name. */ - private static final int CANDIDATE_SUGGESTIONS_PER_USAGE = 5; + private static final int TAG_SUGGESTIONS_AMOUNT = 5; /** * todo document @@ -81,29 +81,25 @@ boolean handleIsUnknownTag(String id, IReplyCallback event, List candidates = getAllIds().stream() .sorted(Comparator .comparingInt(candidate -> StringDistances.editDistance(id, candidate))) - .limit(CANDIDATE_SUGGESTIONS_PER_USAGE) + .limit(TAG_SUGGESTIONS_AMOUNT) .toList(); - List rows = new ArrayList<>(); List> partition = ListUtils.partition(candidates, 5); + ReplyCallbackAction action = event + .reply("Could not find any tag with id '%s'%s" + .formatted(id, candidates.isEmpty() ? "." : ", did you perhaps mean any of the following?")) + .setEphemeral(true); for (List part : partition) { - rows.add( - ActionRow - .of(part.stream() + action.addActionRow( + part.stream() .map(i -> Button.secondary(componentIdGenerator.apply(new String[] { TAG_SUGGESTION_INDICATOR, i, userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention() : null}), i)) - .toList())); + .toList()); } - event - .reply("Could not find any tag with id '%s'%s" - .formatted(id, candidates.isEmpty() ? "." : ", did you perhaps mean any of the following?")) - .setEphemeral(true) - .addActionRows(rows) - .queue(); return true; } diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java index 63c577558b..fd93187593 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java @@ -167,8 +167,6 @@ public JdaTester() { when(replyAction.addActionRow(anyCollection())).thenReturn(replyAction); when(replyAction.addActionRow(ArgumentMatchers.any())) .thenReturn(replyAction); - when(replyAction.addActionRows(anyCollection())).thenReturn(replyAction); - when(replyAction.addActionRows(ArgumentMatchers.any())).thenReturn(replyAction); when(replyAction.setContent(anyString())).thenReturn(replyAction); when(replyAction.addFiles(anyCollection())).thenReturn(replyAction); when(replyAction.addFiles(any(FileUpload.class))).thenReturn(replyAction); @@ -574,7 +572,7 @@ public MessageReceivedEvent createMessageReceiveEvent(MessageCreateData message, * strings or files. *

* An example would be - * + * *

      * {
      *     @code

From f0ac7224c8bf6836bc1a6a37c646a577f8c5a0f8 Mon Sep 17 00:00:00 2001
From: illuminator3 
Date: Tue, 4 Oct 2022 17:51:09 +0200
Subject: [PATCH 08/12] stuff

---
 .../tjbot/commands/BotCommandAdapter.java     |  8 ++++
 .../tjbot/commands/tags/TagCommand.java       | 26 +++++-------
 .../tjbot/commands/tags/TagManageCommand.java |  4 +-
 .../tjbot/commands/tags/TagSystem.java        | 42 ++++++++++---------
 .../tjbot/commands/tags/TagCommandTest.java   |  4 +-
 .../tjbot/commands/tags/TagSystemTest.java    |  6 ++-
 6 files changed, 49 insertions(+), 41 deletions(-)

diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
index 3a5e5af1f3..c9595686b7 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
@@ -134,4 +134,12 @@ protected final String generateComponentId(Lifespan lifespan, String... args) {
             .generate(new ComponentId(UserInteractorPrefix.getPrefixedNameFromInstance(this),
                     Arrays.asList(args)), lifespan);
     }
+
+    /**
+     * @return the component id generator used by {@link #generateComponentId(String...)} and
+     *         {@link #generateComponentId(Lifespan, String...)}
+     */
+    protected final ComponentIdGenerator getComponentIdGenerator() {
+        return componentIdGenerator;
+    }
 }
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
index 69c26b3dc9..0096b98a59 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
@@ -10,6 +10,7 @@
 import org.togetherjava.tjbot.commands.CommandVisibility;
 import org.togetherjava.tjbot.commands.SlashCommandAdapter;
 
+import javax.annotation.Nullable;
 import java.time.Instant;
 import java.util.List;
 import java.util.Objects;
@@ -50,40 +51,35 @@ public void onSlashCommand(SlashCommandInteractionEvent event) {
         String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString();
         OptionMapping replyToUserOption = event.getOption(REPLY_TO_USER_OPTION);
 
-        if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId,
+        if (tagSystem.handleIsUnknownTag(id, event, super.getComponentIdGenerator(),
                 replyToUserOption)) {
             return;
         }
 
-        sendTagReply(event, event.getUser().getName(), id, Optional.of(event.getCommandString()),
-                Optional.ofNullable(replyToUserOption)
-                    .map(OptionMapping::getAsUser)
-                    .map(IMentionable::getAsMention));
+        sendTagReply(event, event.getUser().getName(), id, event.getCommandString(),
+                replyToUserOption == null ? null : replyToUserOption.getAsUser().getAsMention());
     }
 
     @Override
     public void onButtonClick(ButtonInteractionEvent event, List args) {
-        if (!TagSystem.TAG_SUGGESTION_INDICATOR.equals(args.get(0))) {
-            return;
-        }
-
-        sendTagReply(event, event.getUser().getName(), args.get(1), Optional.empty(),
-                Optional.ofNullable(args.get(2)));
+        sendTagReply(event, event.getUser().getName(), args.get(0), null, args.get(1));
     }
 
     /**
      * Sends the reply for a successfull /tag use (i.e. the given tag exists)
      */
-    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     private void sendTagReply(IReplyCallback callback, String userName, String tag,
-            Optional commandString, Optional replyToUser) {
+            @Nullable String commandString, @Nullable String replyToUser) {
+        Optional commandStringOpt = Optional.ofNullable(commandString);
+        Optional replyToUserOpt = Optional.ofNullable(replyToUser);
+
         callback
             .replyEmbeds(new EmbedBuilder().setDescription(tagSystem.getTag(tag).orElseThrow())
-                .setFooter(userName + commandString.map(s -> " • used " + s).orElse(""))
+                .setFooter(userName + commandStringOpt.map(s -> " • used " + s).orElse(""))
                 .setTimestamp(Instant.now())
                 .setColor(TagSystem.AMBIENT_COLOR)
                 .build())
-            .setContent(replyToUser.orElse(""))
+            .setContent(replyToUserOpt.orElse(""))
             .queue();
     }
 }
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java
index 24ed014bab..e507f49c50 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java
@@ -152,7 +152,7 @@ public void onSlashCommand(SlashCommandInteractionEvent event) {
 
     private void rawTag(SlashCommandInteractionEvent event) {
         String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString();
-        if (tagSystem.handleIsUnknownTag(id, event, super::generateComponentId, null)) {
+        if (tagSystem.handleIsUnknownTag(id, event, super.getComponentIdGenerator(), null)) {
             return;
         }
 
@@ -317,7 +317,7 @@ private Optional getTagContent(Subcommand subcommand, String id) {
     private boolean isWrongTagStatusAndHandle(TagStatus requiredTagStatus, String id,
             IReplyCallback event) {
         if (requiredTagStatus == TagStatus.EXISTS) {
-            return tagSystem.handleIsUnknownTag(id, event, super::generateComponentId, null);
+            return tagSystem.handleIsUnknownTag(id, event, super.getComponentIdGenerator(), null);
         } else if (requiredTagStatus == TagStatus.NOT_EXISTS) {
             if (tagSystem.hasTag(id)) {
                 event.reply("The tag with id '%s' already exists.".formatted(id))
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
index bfb2da0bec..62987a737d 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
@@ -8,6 +8,10 @@
 import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
 import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
 import org.apache.commons.collections4.ListUtils;
+import org.togetherjava.tjbot.commands.UserInteractorPrefix;
+import org.togetherjava.tjbot.commands.componentids.ComponentId;
+import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator;
+import org.togetherjava.tjbot.commands.componentids.Lifespan;
 import org.togetherjava.tjbot.commands.utils.StringDistances;
 import org.togetherjava.tjbot.db.Database;
 import org.togetherjava.tjbot.db.generated.tables.Tags;
@@ -29,11 +33,6 @@ public final class TagSystem {
      */
     private static final int TAG_SUGGESTIONS_AMOUNT = 5;
 
-    /**
-     * todo document
-     */
-    static final String TAG_SUGGESTION_INDICATOR = "tag suggestion";
-
     /**
      * The ambient color to use for tag system related messages.
      */
@@ -69,11 +68,13 @@ static Button createDeleteButton(String componentId) {
      *
      * @param id the id of the tag to check
      * @param event the event to send messages with
+     * @param componentIdGenerator the component id generator to generate the button ids with
+     * @param userToReplyTo the user that was originally meant to be replied to when the tag command
+     *        was invoked
      * @return whether the given tag is unknown to the system
      */
     boolean handleIsUnknownTag(String id, IReplyCallback event,
-            Function componentIdGenerator,
-            @Nullable OptionMapping userToReplyTo) {
+            ComponentIdGenerator componentIdGenerator, @Nullable OptionMapping userToReplyTo) {
         if (hasTag(id)) {
             return false;
         }
@@ -84,23 +85,24 @@ boolean handleIsUnknownTag(String id, IReplyCallback event,
             .limit(TAG_SUGGESTIONS_AMOUNT)
             .toList();
         List> partition = ListUtils.partition(candidates, 5);
-        ReplyCallbackAction action = event
-                .reply("Could not find any tag with id '%s'%s"
-                        .formatted(id, candidates.isEmpty() ? "." : ", did you perhaps mean any of the following?"))
-                .setEphemeral(true);
+        ReplyCallbackAction action =
+                event
+                    .reply("Could not find any tag with id '%s'%s".formatted(id,
+                            candidates.isEmpty() ? "."
+                                    : ", did you perhaps mean any of the following?"))
+                    .setEphemeral(true);
 
         for (List part : partition) {
-            action.addActionRow(
-                        part.stream()
-                            .map(i -> Button.secondary(componentIdGenerator.apply(new String[] {
-                                    TAG_SUGGESTION_INDICATOR, i,
-                                    userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention()
-                                            : null}),
-                                    i))
-                            .toList());
+            action.addActionRow(part.stream()
+                .map(i -> Button.secondary(componentIdGenerator.generate(new ComponentId(
+                        UserInteractorPrefix.getPrefixedNameFromClass(TagCommand.class, "tag"),
+                        Arrays.asList(i,
+                                userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention()
+                                        : null)),
+                        Lifespan.REGULAR), i))
+                .toList());
         }
 
-
         return true;
     }
 
diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java
index 02b129e518..62ee40ea96 100644
--- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java
+++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java
@@ -69,8 +69,8 @@ void canNotFindTagSuggestDifferentTag() {
         SlashCommandInteractionEvent event = triggerSlashCommand("second", null);
 
         // THEN responds that the tag could not be found and instead suggests using the other tag
-        verify(event)
-            .reply("Could not find any tag with id 'second', did you perhaps mean any of the following?");
+        verify(event).reply(
+                "Could not find any tag with id 'second', did you perhaps mean any of the following?");
     }
 
     @Test
diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java
index 852d32cd89..cd4a370ff0 100644
--- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java
+++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagSystemTest.java
@@ -52,10 +52,12 @@ void handleIsUnknownTag() {
         SlashCommandInteractionEvent event =
                 jdaTester.createSlashCommandInteractionEvent(new TagCommand(system)).build();
 
-        assertFalse(system.handleIsUnknownTag("known", event, a -> "foo", null));
+        assertFalse(
+                system.handleIsUnknownTag("known", event, (componentId, lifespan) -> "foo", null));
         verify(event, never()).reply(anyString());
 
-        assertTrue(system.handleIsUnknownTag("unknown", event, a -> "foo", null));
+        assertTrue(system.handleIsUnknownTag("unknown", event, (componentId, lifespan) -> "foo",
+                null));
         verify(event).reply(anyString());
     }
 

From 0e6e8fce988a8e0de14c5095b874e017da8dee9b Mon Sep 17 00:00:00 2001
From: illuminator3 
Date: Tue, 4 Oct 2022 17:52:59 +0200
Subject: [PATCH 09/12] remove unused import

---
 .../src/test/java/org/togetherjava/tjbot/jda/JdaTester.java      | 1 -
 1 file changed, 1 deletion(-)

diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java
index fd93187593..1acfebfb2c 100644
--- a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java
+++ b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java
@@ -15,7 +15,6 @@
 import net.dv8tion.jda.api.exceptions.ErrorResponseException;
 import net.dv8tion.jda.api.interactions.InteractionHook;
 import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
-import net.dv8tion.jda.api.interactions.components.ActionRow;
 import net.dv8tion.jda.api.interactions.components.ItemComponent;
 import net.dv8tion.jda.api.interactions.components.LayoutComponent;
 import net.dv8tion.jda.api.requests.ErrorResponse;

From 9cfdc39ddeb62924ecd508759222c3325442f3b5 Mon Sep 17 00:00:00 2001
From: illuminator3 
Date: Tue, 4 Oct 2022 18:02:26 +0200
Subject: [PATCH 10/12] fix imports

---
 .../org/togetherjava/tjbot/commands/tags/TagCommand.java     | 1 -
 .../java/org/togetherjava/tjbot/commands/tags/TagSystem.java | 5 ++---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
index 0096b98a59..f9a6a14808 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
@@ -1,7 +1,6 @@
 package org.togetherjava.tjbot.commands.tags;
 
 import net.dv8tion.jda.api.EmbedBuilder;
-import net.dv8tion.jda.api.entities.IMentionable;
 import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
 import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
 import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
index 62987a737d..6ca24430ae 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
@@ -3,7 +3,6 @@
 import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
 import net.dv8tion.jda.api.interactions.commands.OptionMapping;
-import net.dv8tion.jda.api.interactions.components.ActionRow;
 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.interactions.ReplyCallbackAction;
@@ -18,9 +17,9 @@
 import org.togetherjava.tjbot.db.generated.tables.records.TagsRecord;
 
 import javax.annotation.Nullable;
-import java.awt.Color;
+import java.awt.*;
+import java.util.List;
 import java.util.*;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**

From e137e057066fab72d60e64e55a083c00ff1c78a3 Mon Sep 17 00:00:00 2001
From: illuminator3 
Date: Wed, 5 Oct 2022 18:29:00 +0200
Subject: [PATCH 11/12] requested changes

---
 .../tjbot/commands/BotCommandAdapter.java     | 10 ++--
 .../tjbot/commands/tags/TagCommand.java       | 18 +++----
 .../tjbot/commands/tags/TagManageCommand.java |  4 +-
 .../tjbot/commands/tags/TagSystem.java        | 47 +++++++++++--------
 4 files changed, 46 insertions(+), 33 deletions(-)

diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
index c9595686b7..d11f0369ad 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java
@@ -6,6 +6,7 @@
 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.Nullable;
 import org.togetherjava.tjbot.commands.componentids.ComponentId;
 import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator;
 import org.togetherjava.tjbot.commands.componentids.Lifespan;
@@ -136,10 +137,13 @@ protected final String generateComponentId(Lifespan lifespan, String... args) {
     }
 
     /**
-     * @return the component id generator used by {@link #generateComponentId(String...)} and
-     *         {@link #generateComponentId(Lifespan, String...)}
+     * Gets the generator used to create component IDs.
+     * 

+ * In general, prefer using {@link #generateComponentId(Lifespan, String...)} and {@link #generateComponentId(String...)} instead of interacting with the generator directly. + * + * @return the generator */ - protected final ComponentIdGenerator getComponentIdGenerator() { + protected final @Nullable ComponentIdGenerator getComponentIdGenerator() { return componentIdGenerator; } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java index f9a6a14808..a8f08c5e2e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java @@ -25,6 +25,7 @@ public final class TagCommand extends SlashCommandAdapter { private final TagSystem tagSystem; + static final String COMMAND_NAME = "tag"; static final String ID_OPTION = "id"; static final String REPLY_TO_USER_OPTION = "reply-to"; @@ -34,7 +35,7 @@ public final class TagCommand extends SlashCommandAdapter { * @param tagSystem the system providing the actual tag data */ public TagCommand(TagSystem tagSystem) { - super("tag", "Display a tags content", CommandVisibility.GUILD); + super(COMMAND_NAME, "Display a tags content", CommandVisibility.GUILD); this.tagSystem = tagSystem; @@ -50,7 +51,7 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); OptionMapping replyToUserOption = event.getOption(REPLY_TO_USER_OPTION); - if (tagSystem.handleIsUnknownTag(id, event, super.getComponentIdGenerator(), + if (tagSystem.handleIsUnknownTag(id, event, Objects.requireNonNull(getComponentIdGenerator()), replyToUserOption)) { return; } @@ -65,20 +66,19 @@ public void onButtonClick(ButtonInteractionEvent event, List args) { } /** - * Sends the reply for a successfull /tag use (i.e. the given tag exists) + * Sends the reply for a successfull /tag use (i.e. the given tag exists). */ - private void sendTagReply(IReplyCallback callback, String userName, String tag, - @Nullable String commandString, @Nullable String replyToUser) { + private void sendTagReply(IReplyCallback event, String invokerUserName, String tag, + @Nullable String commandString, @Nullable String replyTargetUser) { Optional commandStringOpt = Optional.ofNullable(commandString); - Optional replyToUserOpt = Optional.ofNullable(replyToUser); - callback + event .replyEmbeds(new EmbedBuilder().setDescription(tagSystem.getTag(tag).orElseThrow()) - .setFooter(userName + commandStringOpt.map(s -> " • used " + s).orElse("")) + .setFooter(invokerUserName + commandStringOpt.map(s -> " • used " + s).orElse("")) .setTimestamp(Instant.now()) .setColor(TagSystem.AMBIENT_COLOR) .build()) - .setContent(replyToUserOpt.orElse("")) + .setContent(replyTargetUser) .queue(); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java index e507f49c50..8bf1383930 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java @@ -152,7 +152,7 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { private void rawTag(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); - if (tagSystem.handleIsUnknownTag(id, event, super.getComponentIdGenerator(), null)) { + if (tagSystem.handleIsUnknownTag(id, event, Objects.requireNonNull(getComponentIdGenerator()), null)) { return; } @@ -317,7 +317,7 @@ private Optional getTagContent(Subcommand subcommand, String id) { private boolean isWrongTagStatusAndHandle(TagStatus requiredTagStatus, String id, IReplyCallback event) { if (requiredTagStatus == TagStatus.EXISTS) { - return tagSystem.handleIsUnknownTag(id, event, super.getComponentIdGenerator(), null); + return tagSystem.handleIsUnknownTag(id, event, Objects.requireNonNull(getComponentIdGenerator()), null); } else if (requiredTagStatus == TagStatus.NOT_EXISTS) { if (tagSystem.hasTag(id)) { event.reply("The tag with id '%s' already exists.".formatted(id)) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java index 6ca24430ae..205477d309 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * The core of the tag system. Provides methods to read and create tags, directly tied to the @@ -67,44 +68,52 @@ static Button createDeleteButton(String componentId) { * * @param id the id of the tag to check * @param event the event to send messages with - * @param componentIdGenerator the component id generator to generate the button ids with - * @param userToReplyTo the user that was originally meant to be replied to when the tag command + * @param componentIdGenerator used to generate buttons with tag suggestions + * @param replyTargetUser the user that was originally meant to be replied to when the tag command * was invoked * @return whether the given tag is unknown to the system */ boolean handleIsUnknownTag(String id, IReplyCallback event, - ComponentIdGenerator componentIdGenerator, @Nullable OptionMapping userToReplyTo) { + ComponentIdGenerator componentIdGenerator, @Nullable OptionMapping replyTargetUser) { if (hasTag(id)) { return false; } - List candidates = getAllIds().stream() - .sorted(Comparator - .comparingInt(candidate -> StringDistances.editDistance(id, candidate))) - .limit(TAG_SUGGESTIONS_AMOUNT) - .toList(); - List> partition = ListUtils.partition(candidates, 5); + Queue closestMatches = new PriorityQueue<>(Comparator + .comparingInt(candidate -> StringDistances.editDistance(id, candidate))); + + closestMatches.addAll(getAllIds()); + + List suggestions = Stream.generate(closestMatches::poll).limit(TAG_SUGGESTIONS_AMOUNT).toList(); ReplyCallbackAction action = event .reply("Could not find any tag with id '%s'%s".formatted(id, - candidates.isEmpty() ? "." + suggestions.isEmpty() ? "." : ", did you perhaps mean any of the following?")) .setEphemeral(true); + List> batches = ListUtils.partition(suggestions, 5); - for (List part : partition) { - action.addActionRow(part.stream() - .map(i -> Button.secondary(componentIdGenerator.generate(new ComponentId( - UserInteractorPrefix.getPrefixedNameFromClass(TagCommand.class, "tag"), - Arrays.asList(i, - userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention() - : null)), - Lifespan.REGULAR), i)) - .toList()); + for (List batch : batches) { + action.addActionRow(batch.stream() + .map(suggestion -> createSuggestionButton(suggestion, componentIdGenerator, replyTargetUser)) + .toList()); } return true; } + /** + * Creates a button for a suggestion for {@link #handleIsUnknownTag(String, IReplyCallback, ComponentIdGenerator, OptionMapping)}. + */ + private Button createSuggestionButton(String suggestion, ComponentIdGenerator componentIdGenerator, @Nullable OptionMapping userToReplyTo) { + return Button.secondary(componentIdGenerator.generate(new ComponentId( + UserInteractorPrefix.getPrefixedNameFromClass(TagCommand.class, TagCommand.COMMAND_NAME), + Arrays.asList(suggestion, + userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention() + : null)), + Lifespan.REGULAR), suggestion); + } + /** * Checks if the given tag is known to the tag system. * From 94d1353c83dcd3baa147e744cb8799c407fb93ea Mon Sep 17 00:00:00 2001 From: illuminator3 Date: Wed, 5 Oct 2022 18:39:10 +0200 Subject: [PATCH 12/12] spotless --- .../tjbot/commands/BotCommandAdapter.java | 3 +- .../tjbot/commands/tags/TagCommand.java | 4 +-- .../tjbot/commands/tags/TagManageCommand.java | 6 ++-- .../tjbot/commands/tags/TagSystem.java | 30 +++++++++++-------- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java index d11f0369ad..066f652539 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/BotCommandAdapter.java @@ -139,7 +139,8 @@ protected final String generateComponentId(Lifespan lifespan, String... args) { /** * Gets the generator used to create component IDs. *

- * In general, prefer using {@link #generateComponentId(Lifespan, String...)} and {@link #generateComponentId(String...)} instead of interacting with the generator directly. + * In general, prefer using {@link #generateComponentId(Lifespan, String...)} and + * {@link #generateComponentId(String...)} instead of interacting with the generator directly. * * @return the generator */ diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java index a8f08c5e2e..51d934ab28 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java @@ -51,8 +51,8 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); OptionMapping replyToUserOption = event.getOption(REPLY_TO_USER_OPTION); - if (tagSystem.handleIsUnknownTag(id, event, Objects.requireNonNull(getComponentIdGenerator()), - replyToUserOption)) { + if (tagSystem.handleIsUnknownTag(id, event, + Objects.requireNonNull(getComponentIdGenerator()), replyToUserOption)) { return; } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java index 8bf1383930..9b5a06345d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java @@ -152,7 +152,8 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { private void rawTag(SlashCommandInteractionEvent event) { String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString(); - if (tagSystem.handleIsUnknownTag(id, event, Objects.requireNonNull(getComponentIdGenerator()), null)) { + if (tagSystem.handleIsUnknownTag(id, event, + Objects.requireNonNull(getComponentIdGenerator()), null)) { return; } @@ -317,7 +318,8 @@ private Optional getTagContent(Subcommand subcommand, String id) { private boolean isWrongTagStatusAndHandle(TagStatus requiredTagStatus, String id, IReplyCallback event) { if (requiredTagStatus == TagStatus.EXISTS) { - return tagSystem.handleIsUnknownTag(id, event, Objects.requireNonNull(getComponentIdGenerator()), null); + return tagSystem.handleIsUnknownTag(id, event, + Objects.requireNonNull(getComponentIdGenerator()), null); } else if (requiredTagStatus == TagStatus.NOT_EXISTS) { if (tagSystem.hasTag(id)) { event.reply("The tag with id '%s' already exists.".formatted(id)) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java index 205477d309..bfaaa3aa91 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java @@ -69,8 +69,8 @@ static Button createDeleteButton(String componentId) { * @param id the id of the tag to check * @param event the event to send messages with * @param componentIdGenerator used to generate buttons with tag suggestions - * @param replyTargetUser the user that was originally meant to be replied to when the tag command - * was invoked + * @param replyTargetUser the user that was originally meant to be replied to when the tag + * command was invoked * @return whether the given tag is unknown to the system */ boolean handleIsUnknownTag(String id, IReplyCallback event, @@ -79,12 +79,13 @@ boolean handleIsUnknownTag(String id, IReplyCallback event, return false; } - Queue closestMatches = new PriorityQueue<>(Comparator - .comparingInt(candidate -> StringDistances.editDistance(id, candidate))); + Queue closestMatches = new PriorityQueue<>( + Comparator.comparingInt(candidate -> StringDistances.editDistance(id, candidate))); closestMatches.addAll(getAllIds()); - List suggestions = Stream.generate(closestMatches::poll).limit(TAG_SUGGESTIONS_AMOUNT).toList(); + List suggestions = + Stream.generate(closestMatches::poll).limit(TAG_SUGGESTIONS_AMOUNT).toList(); ReplyCallbackAction action = event .reply("Could not find any tag with id '%s'%s".formatted(id, @@ -95,22 +96,25 @@ boolean handleIsUnknownTag(String id, IReplyCallback event, for (List batch : batches) { action.addActionRow(batch.stream() - .map(suggestion -> createSuggestionButton(suggestion, componentIdGenerator, replyTargetUser)) - .toList()); + .map(suggestion -> createSuggestionButton(suggestion, componentIdGenerator, + replyTargetUser)) + .toList()); } return true; } /** - * Creates a button for a suggestion for {@link #handleIsUnknownTag(String, IReplyCallback, ComponentIdGenerator, OptionMapping)}. + * Creates a button for a suggestion for + * {@link #handleIsUnknownTag(String, IReplyCallback, ComponentIdGenerator, OptionMapping)}. */ - private Button createSuggestionButton(String suggestion, ComponentIdGenerator componentIdGenerator, @Nullable OptionMapping userToReplyTo) { + private Button createSuggestionButton(String suggestion, + ComponentIdGenerator componentIdGenerator, @Nullable OptionMapping userToReplyTo) { return Button.secondary(componentIdGenerator.generate(new ComponentId( - UserInteractorPrefix.getPrefixedNameFromClass(TagCommand.class, TagCommand.COMMAND_NAME), - Arrays.asList(suggestion, - userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention() - : null)), + UserInteractorPrefix.getPrefixedNameFromClass(TagCommand.class, + TagCommand.COMMAND_NAME), + Arrays.asList(suggestion, + userToReplyTo != null ? userToReplyTo.getAsUser().getAsMention() : null)), Lifespan.REGULAR), suggestion); }