-
-
Notifications
You must be signed in to change notification settings - Fork 91
Transfer Feature reopen #905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
1c0a76d
reverting back to old version before merge
ankitsmt211 e163ed1
adding transfer feature
ankitsmt211 60b63b2
add improved tag search
ankitsmt211 b9da163
spotless fix
ankitsmt211 cc1682d
UX improvements
ankitsmt211 e6c746a
UX - requested changes
ankitsmt211 e95053d
add UX requested changes and refactor
ankitsmt211 9a4ae68
refactor variable names and improved forum post with mention at top
ankitsmt211 95901a7
add variables for more clarity and minor fix
ankitsmt211 5df4783
add variable for clarity and fix thrown exception
ankitsmt211 fe0f639
remove hard coded java tag
ankitsmt211 14f15f1
refactor variable names for modal component
ankitsmt211 342cb56
refactor variable for more clarity
ankitsmt211 b015165
refactor modal components and variables
ankitsmt211 e4d64f4
refactor dm OP message
ankitsmt211 4f02c4b
handle non-text channel triggers gracefully
ankitsmt211 f02a750
remove last commit and refactor modal components
ankitsmt211 5ee5d9e
requested changes
ankitsmt211 bcef492
add jdoc for params and refactor variables
ankitsmt211 1c45749
requested changes
ankitsmt211 e7e0301
remove unnecessary log
ankitsmt211 4172c96
sonar fix
ankitsmt211 e2e25fd
refactor method name
ankitsmt211 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
220 changes: 220 additions & 0 deletions
220
...ion/src/main/java/org/togetherjava/tjbot/features/moderation/TransferQuestionCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
package org.togetherjava.tjbot.features.moderation; | ||
|
||
import net.dv8tion.jda.api.EmbedBuilder; | ||
import net.dv8tion.jda.api.JDA; | ||
import net.dv8tion.jda.api.entities.Guild; | ||
import net.dv8tion.jda.api.entities.Message; | ||
import net.dv8tion.jda.api.entities.MessageEmbed; | ||
import net.dv8tion.jda.api.entities.User; | ||
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel; | ||
import net.dv8tion.jda.api.entities.channel.forums.ForumTag; | ||
import net.dv8tion.jda.api.entities.channel.forums.ForumTagSnowflake; | ||
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; | ||
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent; | ||
import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; | ||
import net.dv8tion.jda.api.interactions.commands.build.Commands; | ||
import net.dv8tion.jda.api.interactions.components.Modal; | ||
import net.dv8tion.jda.api.interactions.components.text.TextInput; | ||
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle; | ||
import net.dv8tion.jda.api.requests.RestAction; | ||
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; | ||
import net.dv8tion.jda.api.utils.messages.MessageCreateData; | ||
|
||
import org.togetherjava.tjbot.config.Config; | ||
import org.togetherjava.tjbot.features.BotCommandAdapter; | ||
import org.togetherjava.tjbot.features.CommandVisibility; | ||
import org.togetherjava.tjbot.features.MessageContextCommand; | ||
import org.togetherjava.tjbot.features.utils.StringDistances; | ||
|
||
import java.awt.Color; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.function.Predicate; | ||
import java.util.function.Supplier; | ||
import java.util.regex.Pattern; | ||
|
||
public final class TransferQuestionCommand extends BotCommandAdapter | ||
implements MessageContextCommand { | ||
private static final String COMMAND_NAME = "transfer-question"; | ||
private static final String MODAL_TITLE_ID = "transferID"; | ||
private static final String MODAL_INPUT_ID = "transferQuestion"; | ||
private static final String MODAL_TAG = "tags"; | ||
private static final int TITLE_GUESS_MAX_LENGTH = 50; | ||
private static final Pattern TITLE_GUESS_COMPACT_REMOVAL_PATTERN = Pattern.compile("\\W"); | ||
private static final int TITLE_GUESS_COMPACT_LENGTH_MIN = 2; | ||
private static final int TITLE_GUESS_COMPACT_LENGTH_MAX = 30; | ||
private static final Color EMBED_COLOR = new Color(50, 164, 168); | ||
private final Predicate<String> isHelpForumName; | ||
private final List<String> tags; | ||
|
||
|
||
/** | ||
* Creates a new instance. | ||
* | ||
* @param config to get the helper forum and tags | ||
*/ | ||
public TransferQuestionCommand(Config config) { | ||
Taz03 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
super(Commands.message(COMMAND_NAME), CommandVisibility.GUILD); | ||
|
||
isHelpForumName = | ||
Pattern.compile(config.getHelpSystem().getHelpForumPattern()).asMatchPredicate(); | ||
|
||
tags = config.getHelpSystem().getCategories(); | ||
} | ||
|
||
@Override | ||
public void onMessageContext(MessageContextInteractionEvent event) { | ||
String originalMessage = event.getTarget().getContentRaw(); | ||
String originalMessageId = event.getTarget().getId(); | ||
String originalChannelId = event.getChannel().getId(); | ||
String authorId = event.getTarget().getAuthor().getId(); | ||
String mostCommonTag = tags.get(0); | ||
|
||
TextInput modalTitle = TextInput.create(MODAL_TITLE_ID, "Title", TextInputStyle.SHORT) | ||
.setMaxLength(70) | ||
.setMinLength(4) | ||
.setPlaceholder("Describe the question in short") | ||
.setValue(createTitle(originalMessage)) | ||
.build(); | ||
|
||
TextInput modalInput = | ||
TextInput.create(MODAL_INPUT_ID, "Question", TextInputStyle.PARAGRAPH) | ||
.setValue(originalMessage) | ||
.setRequiredRange(3, 2000) | ||
.setPlaceholder("Contents of the question") | ||
.build(); | ||
|
||
TextInput modalTag = TextInput.create(MODAL_TAG, "Most fitting tag", TextInputStyle.SHORT) | ||
.setValue(mostCommonTag) | ||
.setPlaceholder("Suitable tag for the question") | ||
.build(); | ||
|
||
String modalComponentId = | ||
generateComponentId(authorId, originalMessageId, originalChannelId); | ||
Modal transferModal = Modal.create(modalComponentId, "Transfer this question") | ||
.addActionRow(modalTitle) | ||
.addActionRow(modalInput) | ||
.addActionRow(modalTag) | ||
.build(); | ||
|
||
event.replyModal(transferModal).queue(); | ||
} | ||
|
||
@Override | ||
public void onModalSubmitted(ModalInteractionEvent event, List<String> args) { | ||
event.deferEdit().queue(); | ||
|
||
String authorId = args.get(0); | ||
Zabuzard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
String messageId = args.get(1); | ||
String channelId = args.get(2); | ||
|
||
event.getJDA() | ||
.retrieveUserById(authorId) | ||
.flatMap(fetchedUser -> createForumPost(event, fetchedUser)) | ||
.flatMap(createdforumPost -> dmUser(event.getChannel(), createdforumPost, | ||
event.getGuild())) | ||
.flatMap(dmSent -> deleteOriginalMessage(event.getJDA(), channelId, messageId)) | ||
.queue(); | ||
} | ||
|
||
private static String createTitle(String message) { | ||
if (message.length() >= TITLE_GUESS_MAX_LENGTH) { | ||
int lastWordEnd = message.lastIndexOf(' ', TITLE_GUESS_MAX_LENGTH); | ||
|
||
if (lastWordEnd == -1) { | ||
lastWordEnd = TITLE_GUESS_MAX_LENGTH; | ||
} | ||
|
||
message = message.substring(0, lastWordEnd); | ||
} | ||
|
||
return isTitleValid(message) ? message : "Untitled"; | ||
} | ||
|
||
private static boolean isTitleValid(CharSequence title) { | ||
String titleCompact = TITLE_GUESS_COMPACT_REMOVAL_PATTERN.matcher(title).replaceAll(""); | ||
|
||
return titleCompact.length() >= TITLE_GUESS_COMPACT_LENGTH_MIN | ||
&& titleCompact.length() <= TITLE_GUESS_COMPACT_LENGTH_MAX; | ||
} | ||
|
||
private RestAction<ForumPost> createForumPost(ModalInteractionEvent event, User originalUser) { | ||
|
||
String originalMessage = event.getValue(MODAL_INPUT_ID).getAsString(); | ||
|
||
MessageEmbed embedForPost = makeEmbedForPost(originalUser, originalMessage); | ||
|
||
MessageCreateData forumMessage = new MessageCreateBuilder() | ||
.addContent("%s has a question:".formatted(originalUser.getAsMention())) | ||
.setEmbeds(embedForPost) | ||
.build(); | ||
|
||
String forumTitle = event.getValue(MODAL_TITLE_ID).getAsString(); | ||
String transferQuestionTag = event.getValue(MODAL_TAG).getAsString(); | ||
|
||
ForumChannel questionsForum = getHelperForum(event.getJDA()); | ||
String mostCommonTag = tags.get(0); | ||
|
||
String queryTag = | ||
StringDistances.closestMatch(transferQuestionTag, tags).orElse(mostCommonTag); | ||
|
||
ForumTag tag = getTagOrDefault(questionsForum.getAvailableTagsByName(queryTag, true), | ||
() -> questionsForum.getAvailableTagsByName(mostCommonTag, true).get(0)); | ||
|
||
return questionsForum.createForumPost(forumTitle, forumMessage) | ||
.setTags(ForumTagSnowflake.fromId(tag.getId())) | ||
.map(createdPost -> new ForumPost(originalUser, createdPost.getMessage())); | ||
} | ||
|
||
private RestAction<Message> dmUser(MessageChannelUnion sourceChannel, ForumPost forumPost, | ||
Guild guild) { | ||
|
||
String messageTemplate = | ||
""" | ||
Hello%s 👋 You have asked a question in the wrong channel%s. Not a big deal, but none of the experts who could help you are reading your question there 🙁 | ||
|
||
Your question has been automatically transferred to %s, please continue there, thank you 👍 | ||
"""; | ||
|
||
String messageForDm = messageTemplate.formatted("", " on" + " " + guild.getName(), | ||
forumPost.message.getJumpUrl()); | ||
|
||
String messageOnDmFailure = messageTemplate.formatted(" " + forumPost.author.getAsMention(), | ||
"", forumPost.message.getJumpUrl()); | ||
|
||
return forumPost.author.openPrivateChannel() | ||
.flatMap(channel -> channel.sendMessage(messageForDm)) | ||
.onErrorFlatMap(error -> sourceChannel.sendMessage(messageOnDmFailure)); | ||
} | ||
|
||
private RestAction<Void> deleteOriginalMessage(JDA jda, String channelId, String messageId) { | ||
return jda.getTextChannelById(channelId).deleteMessageById(messageId); | ||
} | ||
|
||
private ForumChannel getHelperForum(JDA jda) { | ||
Optional<ForumChannel> forumChannelOptional = jda.getForumChannels() | ||
.stream() | ||
.filter(forumChannel -> isHelpForumName.test(forumChannel.getName())) | ||
.findFirst(); | ||
|
||
return forumChannelOptional.orElseThrow(() -> new IllegalStateException( | ||
"Did not find the helper-forum while trying to transfer a question. Make sure the config is setup properly.")); | ||
} | ||
|
||
private static ForumTag getTagOrDefault(List<ForumTag> tagsFoundOnForum, | ||
Supplier<ForumTag> defaultTag) { | ||
return tagsFoundOnForum.isEmpty() ? defaultTag.get() : tagsFoundOnForum.get(0); | ||
} | ||
|
||
private MessageEmbed makeEmbedForPost(User originalUser, String originalMessage) { | ||
return new EmbedBuilder() | ||
.setAuthor(originalUser.getName(), originalUser.getAvatarUrl(), | ||
originalUser.getAvatar().getUrl()) | ||
.setDescription(originalMessage) | ||
.setColor(EMBED_COLOR) | ||
.build(); | ||
} | ||
|
||
private record ForumPost(User author, Message message) { | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.