From cee6189c26cc34d357eba22f8b946e426af92fbe Mon Sep 17 00:00:00 2001 From: andrew-09 Date: Sun, 3 Nov 2024 13:10:25 -0800 Subject: [PATCH 1/6] Pin answer context command working --- .../togetherjava/tjbot/features/Features.java | 2 + .../tjbot/features/help/PinAnswerCommand.java | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.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 893adbc00f..0606d34389 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/Features.java @@ -32,6 +32,7 @@ import org.togetherjava.tjbot.features.help.HelpThreadLifecycleListener; import org.togetherjava.tjbot.features.help.HelpThreadMetadataPurger; import org.togetherjava.tjbot.features.help.MarkHelpThreadCloseInDBRoutine; +import org.togetherjava.tjbot.features.help.PinAnswerCommand; import org.togetherjava.tjbot.features.help.PinnedNotificationRemover; import org.togetherjava.tjbot.features.javamail.RSSHandlerRoutine; import org.togetherjava.tjbot.features.jshell.JShellCommand; @@ -160,6 +161,7 @@ public static Collection createFeatures(JDA jda, Database database, Con // Message context commands features.add(new TransferQuestionCommand(config, chatGptService)); + features.add(new PinAnswerCommand()); // User context commands diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java new file mode 100644 index 0000000000..af4d836414 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java @@ -0,0 +1,73 @@ +package org.togetherjava.tjbot.features.help; + +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; +import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.build.Commands; + +import org.togetherjava.tjbot.features.BotCommandAdapter; +import org.togetherjava.tjbot.features.CommandVisibility; +import org.togetherjava.tjbot.features.MessageContextCommand; + +public final class PinAnswerCommand extends BotCommandAdapter implements MessageContextCommand { + private static final String COMMAND_NAME = "pin-answer"; + private static final int MAX_PINNED_ANSWERS = 10; + private int count = 0; + + public PinAnswerCommand() { + super(Commands.message(COMMAND_NAME), CommandVisibility.GUILD); + } + + @Override + public void onMessageContext(MessageContextInteractionEvent event) { + Message originalMessage = event.getTarget(); + User commandInvoker = event.getUser(); + + if (!(originalMessage.getChannel() instanceof ThreadChannel threadChannel)) { + replyNotInThread(event); + return; + } + + if (!isThreadCreator(commandInvoker, threadChannel)) { + replyNotThreadCreator(event); + return; + } + + if (count >= MAX_PINNED_ANSWERS) { + replyMaxPinsReached(event); + return; + } + + pinMessage(event, originalMessage); + } + + private boolean isThreadCreator(User user, ThreadChannel thread) { + return user.getIdLong() == thread.getOwnerIdLong(); + } + + private void pinMessage(MessageContextInteractionEvent event, Message message) { + message.pin().queue(success -> { + count++; + event.reply("Answer pinned successfully! Pinned answers: " + count) + .setEphemeral(true) + .queue(); + }, failure -> event.reply("Failed to pin the answer.").setEphemeral(true).queue()); + } + + private void replyNotInThread(MessageContextInteractionEvent event) { + event.reply("This message is not in a thread.").setEphemeral(true).queue(); + } + + private void replyNotThreadCreator(MessageContextInteractionEvent event) { + event.reply("You are not the thread creator and cannot pin answers here.") + .setEphemeral(true) + .queue(); + } + + private void replyMaxPinsReached(MessageContextInteractionEvent event) { + event.reply("Maximum pinned answers (" + MAX_PINNED_ANSWERS + ") reached.") + .setEphemeral(true) + .queue(); + } +} From 6c01ced4e716526f49cf1e3109fb499be95a8876 Mon Sep 17 00:00:00 2001 From: andrew-09 Date: Fri, 8 Nov 2024 11:47:48 -0800 Subject: [PATCH 2/6] Clearer replies for users. Better way of getting the # of pinned messages in thread. Added additional check to see if in the 'questions' channel along with config parameter in PinAnswerCommand --- .../togetherjava/tjbot/features/Features.java | 2 +- .../tjbot/features/help/PinAnswerCommand.java | 50 ++++++++++++------- 2 files changed, 33 insertions(+), 19 deletions(-) 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 0606d34389..a7b4e01360 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/Features.java @@ -161,7 +161,7 @@ public static Collection createFeatures(JDA jda, Database database, Con // Message context commands features.add(new TransferQuestionCommand(config, chatGptService)); - features.add(new PinAnswerCommand()); + features.add(new PinAnswerCommand(config)); // User context commands diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java index af4d836414..62d856c8d4 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java @@ -2,10 +2,13 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel; import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; import net.dv8tion.jda.api.interactions.commands.build.Commands; +import org.togetherjava.tjbot.config.Config; +import org.togetherjava.tjbot.config.HelpSystemConfig; import org.togetherjava.tjbot.features.BotCommandAdapter; import org.togetherjava.tjbot.features.CommandVisibility; import org.togetherjava.tjbot.features.MessageContextCommand; @@ -13,10 +16,12 @@ public final class PinAnswerCommand extends BotCommandAdapter implements MessageContextCommand { private static final String COMMAND_NAME = "pin-answer"; private static final int MAX_PINNED_ANSWERS = 10; - private int count = 0; + private final String helpForumPattern; - public PinAnswerCommand() { + public PinAnswerCommand(Config config) { super(Commands.message(COMMAND_NAME), CommandVisibility.GUILD); + HelpSystemConfig helpConfig = config.getHelpSystem(); + helpForumPattern = helpConfig.getHelpForumPattern(); } @Override @@ -29,44 +34,53 @@ public void onMessageContext(MessageContextInteractionEvent event) { return; } - if (!isThreadCreator(commandInvoker, threadChannel)) { - replyNotThreadCreator(event); + if (!(threadChannel.getParentChannel() instanceof ForumChannel forumChannel) + || !forumChannel.getName().equalsIgnoreCase(helpForumPattern)) { + replyNotInQuestionsChannel(event); return; } - if (count >= MAX_PINNED_ANSWERS) { - replyMaxPinsReached(event); + if (!threadOwner(commandInvoker, threadChannel)) { + replyNotThreadCreator(event); return; } - pinMessage(event, originalMessage); + threadChannel.retrievePinnedMessages().queue(pinnedMessages -> { + if (pinnedMessages.size() >= MAX_PINNED_ANSWERS) { + replyMaxPinsReached(event); + } else { + pinMessage(event, originalMessage); + } + }); } - private boolean isThreadCreator(User user, ThreadChannel thread) { + private boolean threadOwner(User user, ThreadChannel thread) { return user.getIdLong() == thread.getOwnerIdLong(); } private void pinMessage(MessageContextInteractionEvent event, Message message) { - message.pin().queue(success -> { - count++; - event.reply("Answer pinned successfully! Pinned answers: " + count) - .setEphemeral(true) - .queue(); - }, failure -> event.reply("Failed to pin the answer.").setEphemeral(true).queue()); + message.pin() + .queue(success -> event.reply("Answer pinned successfully!").setEphemeral(true).queue(), + failure -> event.reply("Failed to pin the answer.").setEphemeral(true).queue()); } private void replyNotInThread(MessageContextInteractionEvent event) { - event.reply("This message is not in a thread.").setEphemeral(true).queue(); + event.reply("This command can only be used in threads").setEphemeral(true).queue(); } - private void replyNotThreadCreator(MessageContextInteractionEvent event) { - event.reply("You are not the thread creator and cannot pin answers here.") + private void replyNotInQuestionsChannel(MessageContextInteractionEvent event) { + event.reply("Answers can only be pinned in the questions channel") .setEphemeral(true) .queue(); } + private void replyNotThreadCreator(MessageContextInteractionEvent event) { + event.reply("Only thread owners can use this command").setEphemeral(true).queue(); + } + private void replyMaxPinsReached(MessageContextInteractionEvent event) { - event.reply("Maximum pinned answers (" + MAX_PINNED_ANSWERS + ") reached.") + event.reply("You've reached a maximum pinned limit (" + MAX_PINNED_ANSWERS + + ") for threads, if you wish to pin more messages please remove a few existing pinned messages") .setEphemeral(true) .queue(); } From 5b40a1f349d8d990d127851b25df7c2f69e9e223 Mon Sep 17 00:00:00 2001 From: andrew-09 Date: Fri, 8 Nov 2024 13:25:03 -0800 Subject: [PATCH 3/6] Remove unnecessary method and use replyNotInThread instead --- .../tjbot/features/help/PinAnswerCommand.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java index 62d856c8d4..332a6d044c 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java @@ -36,12 +36,12 @@ public void onMessageContext(MessageContextInteractionEvent event) { if (!(threadChannel.getParentChannel() instanceof ForumChannel forumChannel) || !forumChannel.getName().equalsIgnoreCase(helpForumPattern)) { - replyNotInQuestionsChannel(event); + replyNotInThread(event); return; } if (!threadOwner(commandInvoker, threadChannel)) { - replyNotThreadCreator(event); + replyNotThreadOwner(event); return; } @@ -68,13 +68,7 @@ private void replyNotInThread(MessageContextInteractionEvent event) { event.reply("This command can only be used in threads").setEphemeral(true).queue(); } - private void replyNotInQuestionsChannel(MessageContextInteractionEvent event) { - event.reply("Answers can only be pinned in the questions channel") - .setEphemeral(true) - .queue(); - } - - private void replyNotThreadCreator(MessageContextInteractionEvent event) { + private void replyNotThreadOwner(MessageContextInteractionEvent event) { event.reply("Only thread owners can use this command").setEphemeral(true).queue(); } From 66d28abf64934fa3de2a14660200423cfa43883d Mon Sep 17 00:00:00 2001 From: andrew-09 Date: Sat, 9 Nov 2024 11:41:50 -0800 Subject: [PATCH 4/6] Use matches intead of equals, merge if statements and remove unnecessary failure case. Update a reply for more clarity for users --- .../tjbot/features/help/PinAnswerCommand.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java index 332a6d044c..bfb49b73b4 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java @@ -29,16 +29,13 @@ public void onMessageContext(MessageContextInteractionEvent event) { Message originalMessage = event.getTarget(); User commandInvoker = event.getUser(); - if (!(originalMessage.getChannel() instanceof ThreadChannel threadChannel)) { + if (!(originalMessage.getChannel() instanceof ThreadChannel threadChannel) + || !(threadChannel.getParentChannel() instanceof ForumChannel forumChannel) + || !forumChannel.getName().matches(helpForumPattern)) { replyNotInThread(event); return; } - if (!(threadChannel.getParentChannel() instanceof ForumChannel forumChannel) - || !forumChannel.getName().equalsIgnoreCase(helpForumPattern)) { - replyNotInThread(event); - return; - } if (!threadOwner(commandInvoker, threadChannel)) { replyNotThreadOwner(event); @@ -60,12 +57,15 @@ private boolean threadOwner(User user, ThreadChannel thread) { private void pinMessage(MessageContextInteractionEvent event, Message message) { message.pin() - .queue(success -> event.reply("Answer pinned successfully!").setEphemeral(true).queue(), - failure -> event.reply("Failed to pin the answer.").setEphemeral(true).queue()); + .queue(success -> event.reply("Answer pinned successfully!") + .setEphemeral(true) + .queue()); } private void replyNotInThread(MessageContextInteractionEvent event) { - event.reply("This command can only be used in threads").setEphemeral(true).queue(); + event.reply("This command can only be used in threads in the questions channel") + .setEphemeral(true) + .queue(); } private void replyNotThreadOwner(MessageContextInteractionEvent event) { From 15500a4a3f740730295ae60761f89774f0b741f4 Mon Sep 17 00:00:00 2001 From: andrew-09 Date: Sat, 9 Nov 2024 11:42:41 -0800 Subject: [PATCH 5/6] newline undo --- .../org/togetherjava/tjbot/features/help/PinAnswerCommand.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java index bfb49b73b4..a01dccb62c 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java @@ -36,7 +36,6 @@ public void onMessageContext(MessageContextInteractionEvent event) { return; } - if (!threadOwner(commandInvoker, threadChannel)) { replyNotThreadOwner(event); return; From 8759346f5c3fba400f0e9a27d9ac70c549730e7b Mon Sep 17 00:00:00 2001 From: andrew-09 Date: Sat, 9 Nov 2024 11:44:13 -0800 Subject: [PATCH 6/6] More intuitive function name . Change replynotinthread to replynotinquestionsthread --- .../togetherjava/tjbot/features/help/PinAnswerCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java index a01dccb62c..be7096f163 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/PinAnswerCommand.java @@ -32,7 +32,7 @@ public void onMessageContext(MessageContextInteractionEvent event) { if (!(originalMessage.getChannel() instanceof ThreadChannel threadChannel) || !(threadChannel.getParentChannel() instanceof ForumChannel forumChannel) || !forumChannel.getName().matches(helpForumPattern)) { - replyNotInThread(event); + replyNotInQuestionsThread(event); return; } @@ -61,7 +61,7 @@ private void pinMessage(MessageContextInteractionEvent event, Message message) { .queue()); } - private void replyNotInThread(MessageContextInteractionEvent event) { + private void replyNotInQuestionsThread(MessageContextInteractionEvent event) { event.reply("This command can only be used in threads in the questions channel") .setEphemeral(true) .queue();