From 28d173c118071eb4f592f937f91e0cee295faa18 Mon Sep 17 00:00:00 2001 From: Daniel Tischner Date: Tue, 7 Feb 2023 09:38:50 +0100 Subject: [PATCH] Educate about /foo when ?!.foo (#759) * React to message commands (!close, .close, ?close) * matching * advice content follows next * Added actual advice * javadoc, got rid of the massive Pattern.compile(".*") duplication * unit tests * Improved regex * Test was unstable on CI/CD * dot after smiley looks odd --- .../togetherjava/tjbot/features/Features.java | 6 +- .../features/MessageReceiverAdapter.java | 7 ++ .../features/basic/SlashCommandEducator.java | 71 ++++++++++++++++++ .../code/CodeMessageAutoDetection.java | 2 - .../features/code/CodeMessageHandler.java | 3 - .../FileSharingMessageListener.java | 2 - .../BlacklistedAttachmentListener.java | 4 +- .../features/moderation/scam/ScamBlocker.java | 2 - .../tophelper/TopHelpersMessageListener.java | 2 - .../resources/slashCommandPopupAdvice.png | Bin 0 -> 50963 bytes .../basic/SlashCommandEducatorTest.java | 70 +++++++++++++++++ .../features/reminder/RemindRoutineTest.java | 2 +- .../org/togetherjava/tjbot/jda/JdaTester.java | 2 + 13 files changed, 154 insertions(+), 19 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/features/basic/SlashCommandEducator.java create mode 100644 application/src/main/resources/slashCommandPopupAdvice.png create mode 100644 application/src/test/java/org/togetherjava/tjbot/features/basic/SlashCommandEducatorTest.java diff --git a/application/src/main/java/org/togetherjava/tjbot/features/Features.java b/application/src/main/java/org/togetherjava/tjbot/features/Features.java index 0485904ab3..b1acf61111 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/Features.java @@ -4,10 +4,7 @@ import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.db.Database; -import org.togetherjava.tjbot.features.basic.PingCommand; -import org.togetherjava.tjbot.features.basic.RoleSelectCommand; -import org.togetherjava.tjbot.features.basic.SuggestionsUpDownVoter; -import org.togetherjava.tjbot.features.basic.VcActivityCommand; +import org.togetherjava.tjbot.features.basic.*; import org.togetherjava.tjbot.features.bookmarks.*; import org.togetherjava.tjbot.features.code.CodeMessageAutoDetection; import org.togetherjava.tjbot.features.code.CodeMessageHandler; @@ -104,6 +101,7 @@ public static Collection createFeatures(JDA jda, Database database, Con features.add(codeMessageHandler); features.add(new CodeMessageAutoDetection(config, codeMessageHandler)); features.add(new CodeMessageManualDetection(codeMessageHandler)); + features.add(new SlashCommandEducator()); // Event receivers features.add(new RejoinModerationRoleListener(actionsStore, config)); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/MessageReceiverAdapter.java b/application/src/main/java/org/togetherjava/tjbot/features/MessageReceiverAdapter.java index 350a78d8a0..05280c97ab 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/MessageReceiverAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/MessageReceiverAdapter.java @@ -18,6 +18,13 @@ public abstract class MessageReceiverAdapter implements MessageReceiver { private final Pattern channelNamePattern; + /** + * Creates an instance of a message receiver, listening to messages of all channels. + */ + protected MessageReceiverAdapter() { + this(Pattern.compile(".*")); + } + /** * Creates an instance of a message receiver with the given pattern. * diff --git a/application/src/main/java/org/togetherjava/tjbot/features/basic/SlashCommandEducator.java b/application/src/main/java/org/togetherjava/tjbot/features/basic/SlashCommandEducator.java new file mode 100644 index 0000000000..a9d8056e1a --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/features/basic/SlashCommandEducator.java @@ -0,0 +1,71 @@ +package org.togetherjava.tjbot.features.basic; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.requests.restaction.MessageCreateAction; +import net.dv8tion.jda.api.utils.FileUpload; + +import org.togetherjava.tjbot.features.MessageReceiverAdapter; +import org.togetherjava.tjbot.features.help.HelpSystemHelper; + +import java.io.InputStream; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +/** + * Listens to messages that are likely supposed to be message commands, such as {@code !foo} and + * then educates the user about using slash commands, such as {@code /foo} instead. + */ +public final class SlashCommandEducator extends MessageReceiverAdapter { + private static final String SLASH_COMMAND_POPUP_ADVICE_PATH = "slashCommandPopupAdvice.png"; + private static final Predicate IS_MESSAGE_COMMAND = Pattern.compile(""" + [.!?] #Start of message command + [a-zA-Z]{2,15} #Name of message command, e.g. 'close' + .* #Rest of the message + """, Pattern.COMMENTS).asMatchPredicate(); + + @Override + public void onMessageReceived(MessageReceivedEvent event) { + if (event.getAuthor().isBot() || event.isWebhookMessage()) { + return; + } + + String content = event.getMessage().getContentRaw(); + if (IS_MESSAGE_COMMAND.test(content)) { + sendAdvice(event.getMessage()); + } + } + + private void sendAdvice(Message message) { + String content = + """ + Looks like you attempted to use a command? Please note that we only use **slash-commands** on this server 🙂 + + Try starting your message with a forward-slash `/` and Discord should open a popup showing you all available commands. + A command might then look like `/foo` 👍"""; + + createReply(message, content, SLASH_COMMAND_POPUP_ADVICE_PATH).queue(); + } + + private static MessageCreateAction createReply(Message messageToReplyTo, String content, + String imagePath) { + boolean useImage = true; + InputStream imageData = HelpSystemHelper.class.getResourceAsStream("/" + imagePath); + if (imageData == null) { + useImage = false; + } + + MessageEmbed embed = new EmbedBuilder().setDescription(content) + .setImage(useImage ? "attachment://" + imagePath : null) + .build(); + + MessageCreateAction action = messageToReplyTo.replyEmbeds(embed); + if (useImage) { + action = action.addFiles(FileUpload.fromData(imageData, imagePath)); + } + + return action; + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageAutoDetection.java b/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageAutoDetection.java index 9e53b0321a..2a95879449 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageAutoDetection.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageAutoDetection.java @@ -34,8 +34,6 @@ public final class CodeMessageAutoDetection extends MessageReceiverAdapter { * @param codeMessageHandler to register detected code messages at for further handling */ public CodeMessageAutoDetection(Config config, CodeMessageHandler codeMessageHandler) { - super(Pattern.compile(".*")); - this.codeMessageHandler = codeMessageHandler; isHelpForumName = diff --git a/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java b/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java index 1d809e66cf..21ddf289df 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java @@ -29,7 +29,6 @@ import java.awt.Color; import java.util.*; import java.util.function.Function; -import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -66,8 +65,6 @@ public final class CodeMessageHandler extends MessageReceiverAdapter implements * Creates a new instance. */ public CodeMessageHandler() { - super(Pattern.compile(".*")); - componentIdInteractor = new ComponentIdInteractor(getInteractionType(), getName()); List codeActions = List.of(new FormatCodeCommand()); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/features/filesharing/FileSharingMessageListener.java index 5ef727b40d..01ae063b97 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/filesharing/FileSharingMessageListener.java @@ -73,8 +73,6 @@ public class FileSharingMessageListener extends MessageReceiverAdapter implement * @see org.togetherjava.tjbot.features.Features */ public FileSharingMessageListener(Config config) { - super(Pattern.compile(".*")); - gistApiKey = config.getGistApiKey(); isHelpForumName = Pattern.compile(config.getHelpSystem().getHelpForumPattern()).asMatchPredicate(); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java index 1c5d9df5d8..db1060aefb 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java @@ -15,11 +15,10 @@ import org.togetherjava.tjbot.features.moderation.modmail.ModMailCommand; import org.togetherjava.tjbot.features.utils.MessageUtils; -import java.awt.*; +import java.awt.Color; import java.util.List; import java.util.Locale; import java.util.function.UnaryOperator; -import java.util.regex.Pattern; /** * Reacts to blacklisted attachments being posted, upon which they are deleted. @@ -35,7 +34,6 @@ public final class BlacklistedAttachmentListener extends MessageReceiverAdapter * @param modAuditLogWriter to inform the mods about the suspicious attachment */ public BlacklistedAttachmentListener(Config config, ModAuditLogWriter modAuditLogWriter) { - super(Pattern.compile(".*")); this.modAuditLogWriter = modAuditLogWriter; blacklistedFileExtensions = config.getBlacklistedFileExtensions(); } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java index af69d40dac..c7beafb704 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java @@ -74,8 +74,6 @@ public final class ScamBlocker extends MessageReceiverAdapter implements UserInt */ public ScamBlocker(ModerationActionsStore actionsStore, ScamHistoryStore scamHistoryStore, Config config) { - super(Pattern.compile(".*")); - this.actionsStore = actionsStore; this.scamHistoryStore = scamHistoryStore; this.config = config; diff --git a/application/src/main/java/org/togetherjava/tjbot/features/tophelper/TopHelpersMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/features/tophelper/TopHelpersMessageListener.java index f32086e880..9d98014aa4 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/tophelper/TopHelpersMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/tophelper/TopHelpersMessageListener.java @@ -38,8 +38,6 @@ public final class TopHelpersMessageListener extends MessageReceiverAdapter { * @param config the config to use for this */ public TopHelpersMessageListener(Database database, Config config) { - super(Pattern.compile(".*")); - this.database = database; isHelpForumName = diff --git a/application/src/main/resources/slashCommandPopupAdvice.png b/application/src/main/resources/slashCommandPopupAdvice.png new file mode 100644 index 0000000000000000000000000000000000000000..6284b8566e9ef48f8051ac31ee544ff1adee3a0b GIT binary patch literal 50963 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 X(lv!zyk{@~@JmucPP|6cAmIN1w7{*W literal 0 HcmV?d00001 diff --git a/application/src/test/java/org/togetherjava/tjbot/features/basic/SlashCommandEducatorTest.java b/application/src/test/java/org/togetherjava/tjbot/features/basic/SlashCommandEducatorTest.java new file mode 100644 index 0000000000..6e118a5c76 --- /dev/null +++ b/application/src/test/java/org/togetherjava/tjbot/features/basic/SlashCommandEducatorTest.java @@ -0,0 +1,70 @@ +package org.togetherjava.tjbot.features.basic; + +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import org.togetherjava.tjbot.features.MessageReceiver; +import org.togetherjava.tjbot.jda.JdaTester; + +import java.util.List; +import java.util.stream.Stream; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +final class SlashCommandEducatorTest { + private JdaTester jdaTester; + private MessageReceiver messageReceiver; + + @BeforeEach + void setUp() { + jdaTester = new JdaTester(); + messageReceiver = new SlashCommandEducator(); + } + + private MessageReceivedEvent sendMessage(String content) { + MessageCreateData message = new MessageCreateBuilder().setContent(content).build(); + MessageReceivedEvent event = + jdaTester.createMessageReceiveEvent(message, List.of(), ChannelType.TEXT); + + messageReceiver.onMessageReceived(event); + + return event; + } + + @ParameterizedTest + @MethodSource("provideMessageCommands") + void sendsAdviceOnMessageCommand(String message) { + // GIVEN a message containing a message command + // WHEN the message is sent + MessageReceivedEvent event = sendMessage(message); + + // THEN the system replies to it with an advice + verify(event.getMessage(), times(1)).replyEmbeds(any(MessageEmbed.class)); + } + + @ParameterizedTest + @MethodSource("provideOtherMessages") + void ignoresOtherMessages(String message) { + // GIVEN a message that is not a message command + // WHEN the message is sent + MessageReceivedEvent event = sendMessage(message); + + // THEN the system ignores the message and does not reply to it + verify(event.getMessage(), never()).replyEmbeds(any(MessageEmbed.class)); + } + + private static Stream provideMessageCommands() { + return Stream.of("!foo", ".foo", "?foo", ".test", "!whatever", "!this is a test"); + } + + private static Stream provideOtherMessages() { + return Stream.of(" a ", "foo", "#foo", "/foo", "!!!", "?!?!?", "?", ".,-", "!f", "! foo"); + } +} diff --git a/application/src/test/java/org/togetherjava/tjbot/features/reminder/RemindRoutineTest.java b/application/src/test/java/org/togetherjava/tjbot/features/reminder/RemindRoutineTest.java index f11f4c398f..f4469c3e89 100644 --- a/application/src/test/java/org/togetherjava/tjbot/features/reminder/RemindRoutineTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/features/reminder/RemindRoutineTest.java @@ -184,6 +184,6 @@ void reminderIsNotSendIfNotPending() { private static void assertSimilar(Instant expected, Instant actual) { // NOTE For some reason, the instant ends up in the database slightly wrong already (about // half a second), seems to be an issue with jOOQ - assertEquals(expected.toEpochMilli(), actual.toEpochMilli(), TimeUnit.SECONDS.toMillis(1)); + assertEquals(expected.toEpochMilli(), actual.toEpochMilli(), TimeUnit.SECONDS.toMillis(2)); } } 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 b5d68f6ea2..a634c93165 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java @@ -216,6 +216,8 @@ public JdaTester() { doNothing().when(messageCreateAction).queue(); when(messageCreateAction.setContent(any())).thenReturn(messageCreateAction); when(messageCreateAction.addContent(any())).thenReturn(messageCreateAction); + when(messageCreateAction.addFiles(any(FileUpload.class))).thenReturn(messageCreateAction); + when(messageCreateAction.addFiles(anyCollection())).thenReturn(messageCreateAction); CacheRestAction privateChannelAction = createSucceededActionMock(privateChannel, CacheRestAction.class);