[AB-196] adding confirmation requirement to various commands

refactoring command received handler in order to re-use when confirmation has been given
removing reaction from showSuggestion and remind command
adding log message for message deleted message, in case the member left
all commands from now on must work without the member field from the message, as this is not available when retrieving the message
This commit is contained in:
Sheldan
2021-09-10 21:40:54 +02:00
parent da1a71ecdc
commit 16e6caa1f0
51 changed files with 615 additions and 109 deletions

View File

@@ -50,6 +50,7 @@ public class DeleteAssignableRolePlace extends AbstractConditionableCommand {
.templated(true)
.causesReaction(true)
.async(true)
.requiresConfirmation(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -66,6 +66,7 @@ public class SetExpRole extends AbstractConditionableCommand {
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.requiresConfirmation(true)
.parameters(parameters)
.help(helpInfo)
.build();

View File

@@ -52,6 +52,7 @@ public class SyncRoles extends AbstractConditionableCommand {
.module(ExperienceModuleDefinition.EXPERIENCE)
.templated(true)
.async(true)
.requiresConfirmation(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -67,6 +67,7 @@ public class UnSetExpRole extends AbstractConditionableCommand {
.templated(true)
.async(true)
.causesReaction(true)
.requiresConfirmation(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -51,6 +51,7 @@ public class RemoveTrackedInviteLinks extends AbstractConditionableCommand {
.module(InviteFilterModerationModuleDefinition.MODERATION)
.templated(true)
.async(true)
.requiresConfirmation(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -65,7 +65,10 @@ public class MessageDeleteLogListener implements AsyncMessageDeletedListener {
CachedMessage message = model.getCachedMessage();
memberService.getMemberInServerAsync(model.getServerId(), message.getAuthor().getAuthorId()).thenAccept(member ->
self.executeListener(message, member)
);
).exceptionally(throwable -> {
log.warn("Could not retrieve member {} for message deleted event in guild {}.", message.getAuthor().getAuthorId(), model.getServerId(), throwable);
return null;
});
return DefaultListenerResult.PROCESSED;
}

View File

@@ -44,6 +44,7 @@ public class DecayAllWarnings extends AbstractConditionableCommand {
.module(ModerationModuleDefinition.MODERATION)
.templated(true)
.async(true)
.requiresConfirmation(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -43,6 +43,7 @@ public class DecayWarnings extends AbstractConditionableCommand {
.name("decayWarnings")
.module(ModerationModuleDefinition.MODERATION)
.templated(true)
.requiresConfirmation(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)

View File

@@ -54,7 +54,7 @@ public class AnonReply extends AbstractConditionableCommand {
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
Long threadId = thread.getId();
return memberService.getMemberInServerAsync(thread.getUser()).thenCompose(member ->
modMailThreadService.relayMessageToDm(threadId, text, commandContext.getMessage(), true, commandContext.getChannel(), commandContext.getUndoActions(), member)
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), true, member)
).thenApply(aVoid -> CommandResult.fromSuccess());
}

View File

@@ -52,7 +52,7 @@ public class Reply extends AbstractConditionableCommand {
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
Long threadId = thread.getId();
return memberService.getMemberInServerAsync(thread.getUser()).thenCompose(member ->
modMailThreadService.relayMessageToDm(threadId, text, commandContext.getMessage(), false, commandContext.getChannel(), commandContext.getUndoActions(), member)
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), false, member)
).thenApply(aVoid -> CommandResult.fromSuccess());
}

View File

@@ -553,8 +553,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
@Transactional
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions, Member targetMember) {
public CompletableFuture<Void> loadExecutingMemberAndRelay(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, Member targetMember) {
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), targetMember.getId(), modmailThreadId, targetMember.getGuild().getId());
return memberService.getMemberInServerAsync(replyCommandMessage.getGuild().getIdLong(), replyCommandMessage.getAuthor().getIdLong())
.thenCompose(executingMember -> self.relayMessageToDm(modmailThreadId, text, replyCommandMessage, anonymous, targetMember, executingMember));
}
@Transactional
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, Member targetMember, Member executingMember) {
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_SENT);
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
FullUserInServer fullThreadUser = FullUserInServer
@@ -573,7 +579,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
log.debug("Message is sent anonymous.");
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailThread.getServer()));
} else {
modMailModeratorReplyModelBuilder.moderator(replyCommandMessage.getMember());
modMailModeratorReplyModelBuilder.moderator(executingMember);
}
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate(MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel, modMailThread.getServer().getId());

View File

@@ -67,12 +67,10 @@ public interface ModMailThreadService {
* @param text The parsed text of the reply
* @param message The pure {@link Message} containing the command which caused the reply
* @param anonymous Whether or nor the message should be send anonymous
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
* @param undoActions A list of {@link dev.sheldan.abstracto.core.models.UndoAction actions} to be undone in case the operation fails. This list will be filled in the method.
* @param targetMember The {@link Member} the {@link ModMailThread} is about.
* @return A {@link CompletableFuture future} which completes when the message has been relayed to the DM
*/
CompletableFuture<Void> relayMessageToDm(Long threadId, String text, Message message, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions, Member targetMember);
CompletableFuture<Void> loadExecutingMemberAndRelay(Long threadId, String text, Message message, boolean anonymous, Member targetMember);
/**
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread,

View File

@@ -70,7 +70,7 @@ public class Remind extends AbstractConditionableCommand {
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();

View File

@@ -109,7 +109,10 @@ public class RemindServiceBean implements ReminderService {
} else {
HashMap<Object, Object> parameters = new HashMap<>();
parameters.put("reminderId", reminder.getId().toString());
JobParameters jobParameters = JobParameters.builder().parameters(parameters).build();
JobParameters jobParameters = JobParameters
.builder()
.parameters(parameters)
.build();
String triggerKey = schedulerService.executeJobWithParametersOnce("reminderJob", "utility", jobParameters, Date.from(reminder.getTargetDate()));
log.info("Starting scheduled job with trigger {} to execute reminder {}.", triggerKey, reminder.getId());
reminder.setJobTriggerKey(triggerKey);

View File

@@ -50,6 +50,7 @@ public class PurgeImagePosts extends AbstractConditionableCommand {
.module(RepostDetectionModuleDefinition.REPOST_DETECTION)
.templated(true)
.async(false)
.requiresConfirmation(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -50,6 +50,7 @@ public class PurgeReposts extends AbstractConditionableCommand {
.module(RepostDetectionModuleDefinition.REPOST_DETECTION)
.templated(true)
.async(false)
.requiresConfirmation(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -51,6 +51,7 @@ public class DeleteTrackedEmote extends AbstractConditionableCommand {
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.requiresConfirmation(true)
.parameters(parameters)
.help(helpInfo)
.build();

View File

@@ -60,6 +60,7 @@ public class PurgeEmoteStats extends AbstractConditionableCommand {
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.supportsEmbedException(true)
.requiresConfirmation(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -41,6 +41,7 @@ public class ResetEmoteStats extends AbstractConditionableCommand {
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.supportsEmbedException(true)
.requiresConfirmation(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -58,7 +58,7 @@ public class ShowSuggestion extends AbstractConditionableCommand {
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();

View File

@@ -114,7 +114,13 @@ public class SuggestionServiceBean implements SuggestionService {
@Override
public CompletableFuture<Void> createSuggestionMessage(Message commandMessage, String text) {
Member suggester = commandMessage.getMember();
// it is done that way, because we cannot always be sure, that the message containsn the member
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
.thenCompose(suggester -> self.createMessageWithSuggester(commandMessage, text, suggester));
}
@Transactional
public CompletableFuture<Void> createMessageWithSuggester(Message commandMessage, String text, Member suggester) {
Long serverId = suggester.getGuild().getIdLong();
AServer server = serverManagementService.loadServer(serverId);
AUserInAServer userSuggester = userInServerManagementService.loadOrCreateUser(suggester);
@@ -126,7 +132,7 @@ public class SuggestionServiceBean implements SuggestionService {
.state(SuggestionState.NEW)
.serverId(serverId)
.message(commandMessage)
.member(commandMessage.getMember())
.member(suggester)
.suggesterUser(userSuggester)
.useButtons(useButtons)
.suggester(suggester.getUser())
@@ -210,22 +216,24 @@ public class SuggestionServiceBean implements SuggestionService {
@Override
public CompletableFuture<Void> acceptSuggestion(Long suggestionId, Message commandMessage, String text) {
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
.thenCompose(member -> self.setSuggestionToFinalState(member, suggestionId, commandMessage, text, SuggestionState.ACCEPTED));
}
@Transactional
public CompletableFuture<Void> setSuggestionToFinalState(Member executingMember, Long suggestionId, Message commandMessage, String text, SuggestionState state) {
Long serverId = commandMessage.getGuild().getIdLong();
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED);
suggestionManagementService.setSuggestionState(suggestion, state);
cancelSuggestionReminder(suggestion);
log.info("Accepting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
return updateSuggestion(commandMessage.getMember(), text, suggestion);
log.info("Setting suggestion {} in server {} to state {}", suggestionId, suggestion.getServer().getId(), state);
return updateSuggestion(executingMember, text, suggestion);
}
@Override
public CompletableFuture<Void> vetoSuggestion(Long suggestionId, Message commandMessage, String text) {
Long serverId = commandMessage.getGuild().getIdLong();
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.VETOED);
cancelSuggestionReminder(suggestion);
log.info("Vetoing suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
return updateSuggestion(commandMessage.getMember(), text, suggestion);
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
.thenCompose(member -> self.setSuggestionToFinalState(member, suggestionId, commandMessage, text, SuggestionState.VETOED));
}
private CompletableFuture<Void> updateSuggestion(Member memberExecutingCommand, String reason, Suggestion suggestion) {
@@ -293,12 +301,8 @@ public class SuggestionServiceBean implements SuggestionService {
@Override
public CompletableFuture<Void> rejectSuggestion(Long suggestionId, Message commandMessage, String text) {
Long serverId = commandMessage.getGuild().getIdLong();
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.REJECTED);
cancelSuggestionReminder(suggestion);
log.info("Rejecting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
return updateSuggestion(commandMessage.getMember(), text, suggestion);
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
.thenCompose(member -> self.setSuggestionToFinalState(member, suggestionId, commandMessage, text, SuggestionState.REJECTED));
}
@Override

View File

@@ -1,11 +1,7 @@
package dev.sheldan.abstracto.suggestion.service;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.exception.ChannelNotInGuildException;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
@@ -16,10 +12,8 @@ import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureMode;
import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget;
import dev.sheldan.abstracto.suggestion.exception.SuggestionNotFoundException;
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
import dev.sheldan.abstracto.suggestion.model.template.SuggestionUpdateModel;
import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService;
import net.dv8tion.jda.api.entities.*;
import org.junit.Test;
@@ -113,17 +107,12 @@ public class SuggestionServiceBeanTest {
public void testCreateSuggestionMessage() {
String suggestionText = "text";
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_CREATION_TEMPLATE), any(SuggestionLog.class), eq(SERVER_ID))).thenReturn(messageToSend);
Message suggestionMessage = Mockito.mock(Message.class);
when(counterService.getNextCounterValue(server, SuggestionServiceBean.SUGGESTION_COUNTER_KEY)).thenReturn(SUGGESTION_ID);
List<CompletableFuture<Message>> postingFutures = Arrays.asList(CompletableFuture.completedFuture(suggestionMessage));
when(postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, SERVER_ID)).thenReturn(postingFutures);
when(message.getMember()).thenReturn(member);
when(member.getGuild()).thenReturn(guild);
when(member.getIdLong()).thenReturn(SUGGESTER_ID);
when(message.getAuthor()).thenReturn(suggesterUser);
when(message.getGuild()).thenReturn(guild);
when(suggesterUser.getIdLong()).thenReturn(SUGGESTER_ID);
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(member));
testUnit.createSuggestionMessage(message, suggestionText);
verify(self).createMessageWithSuggester(message, suggestionText, member);
}
@Test
@@ -139,20 +128,26 @@ public class SuggestionServiceBeanTest {
}
@Test(expected = SuggestionNotFoundException.class)
@Test
public void testAcceptNotExistingSuggestion() {
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenThrow(new SuggestionNotFoundException(SUGGESTION_ID));
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(message.getGuild()).thenReturn(guild);
when(message.getAuthor()).thenReturn(suggesterUser);
when(suggesterUser.getIdLong()).thenReturn(SUGGESTER_ID);
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(member));
testUnit.acceptSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
verify(self).setSuggestionToFinalState(member, SUGGESTION_ID, message, CLOSING_TEXT, SuggestionState.ACCEPTED);
}
@Test(expected = SuggestionNotFoundException.class)
@Test
public void testRejectNotExistingSuggestion() {
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenThrow(new SuggestionNotFoundException(SUGGESTION_ID));
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(message.getGuild()).thenReturn(guild);
when(message.getAuthor()).thenReturn(suggesterUser);
when(suggesterUser.getIdLong()).thenReturn(SUGGESTER_ID);
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(member));
testUnit.rejectSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
verify(self).setSuggestionToFinalState(member, SUGGESTION_ID, message, CLOSING_TEXT, SuggestionState.REJECTED);
}
}