From 336c3d0bd8fe832b7ccc76e0453a0b5a708698dd Mon Sep 17 00:00:00 2001
From: Sheldan <5037282+Sheldan@users.noreply.github.com>
Date: Fri, 31 May 2024 00:54:32 +0200
Subject: [PATCH] [AB-xxx] adding modmail support for ban appeals refactoring
modmail to use user objects instead of member in various places
---
.../modmail/modmail-impl/pom.xml | 6 +
.../abstracto/modmail/command/AnonReply.java | 8 +-
.../abstracto/modmail/command/Close.java | 8 +-
.../abstracto/modmail/command/Contact.java | 30 +-
.../modmail/command/DenyModmailAppeal.java | 121 ++++++++
.../abstracto/modmail/command/Reply.java | 9 +-
.../ModMailInitialButtonListener.java | 14 +-
.../ModMailMessageDeletedListener.java | 7 +-
.../ModMailMessageEditedListener.java | 29 +-
.../listener/ModMailMessageListener.java | 3 -
.../service/ModMailRoleServiceBean.java | 3 -
.../service/ModMailThreadServiceBean.java | 228 ++++++++------
.../migrations/1.5.37/collection.xml | 6 +
.../migrations/1.5.37/seedData/command.xml | 16 +
.../migrations/1.5.37/seedData/data.xml | 6 +
.../migrations/modMail-changeLog.xml | 1 +
.../main/resources/modmail-config.properties | 9 +-
.../ModMailMessageDeletedListenerTest.java | 141 ---------
.../ModMailMessageEditedListenerTest.java | 283 ------------------
.../modmail/config/ModMailFeatureConfig.java | 17 +-
.../abstracto/modmail/config/ModMailMode.java | 5 +-
.../modmail/model/ClosingContext.java | 1 -
.../template/ContactNotificationModel.java | 4 +-
.../template/ModMailModeratorReplyModel.java | 7 +-
.../template/ModMailNotificationModel.java | 8 +-
.../model/template/ModMailThreaderHeader.java | 10 +-
.../model/template/ModMailUserReplyModel.java | 6 +-
.../modmail/service/ModMailThreadService.java | 15 +-
.../models/template/display/UserDisplay.java | 3 +
29 files changed, 386 insertions(+), 618 deletions(-)
create mode 100644 abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/DenyModmailAppeal.java
create mode 100644 abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/collection.xml
create mode 100644 abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/command.xml
create mode 100644 abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/data.xml
delete mode 100644 abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListenerTest.java
delete mode 100644 abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListenerTest.java
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml b/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml
index e43fb1c6d..5aeee0e0f 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml
@@ -38,6 +38,12 @@
${project.version}
+
+ dev.sheldan.abstracto.modules
+ moderation-int
+ ${project.version}
+
+
dev.sheldan.abstracto.core
metrics-int
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/AnonReply.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/AnonReply.java
index f0c711f1f..1c8c7d3bd 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/AnonReply.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/AnonReply.java
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
-import dev.sheldan.abstracto.core.service.MemberService;
+import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.exception.ModMailThreadClosedException;
@@ -40,7 +40,7 @@ public class AnonReply extends AbstractConditionableCommand {
private ModMailThreadManagementService modMailThreadManagementService;
@Autowired
- private MemberService memberService;
+ private UserService userService;
@Override
public CompletableFuture executeAsync(CommandContext commandContext) {
@@ -52,8 +52,8 @@ public class AnonReply extends AbstractConditionableCommand {
throw new ModMailThreadClosedException();
}
Long threadId = modMailThread.getId();
- return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
- modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), true, member)
+ return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
+ modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), true, user, commandContext.getGuild())
).thenApply(aVoid -> CommandResult.fromSuccess());
}
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Close.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Close.java
index a67b52ab2..74d0ae38a 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Close.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Close.java
@@ -81,7 +81,6 @@ public class Close extends AbstractConditionableCommand {
.builder()
.closingMember(commandContext.getAuthor())
.notifyUser(true)
- .channel(commandContext.getChannel())
.log(true)
.note(note)
.build();
@@ -112,19 +111,18 @@ public class Close extends AbstractConditionableCommand {
ClosingContext context = ClosingContext
.builder()
.closingMember(event.getMember())
- .channel(event.getChannel())
.notifyUser(!silently)
.log(log)
.note(note)
.build();
return interactionService.replyEmbed(CLOSE_RESPONSE, event)
- .thenCompose(interactionHook -> self.closeThread(context))
+ .thenCompose(interactionHook -> self.closeThread(context, event.getChannelIdLong()))
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Transactional
- public CompletableFuture closeThread(ClosingContext closingContext) {
- ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(closingContext.getChannel().getIdLong());
+ public CompletableFuture closeThread(ClosingContext closingContext, Long channelId) {
+ ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(channelId);
if(ModMailThreadState.CLOSED.equals(modMailThread.getState()) || ModMailThreadState.CLOSING.equals(modMailThread.getState())) {
throw new ModMailThreadClosedException();
}
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Contact.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Contact.java
index e95b77889..f71f91cf0 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Contact.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Contact.java
@@ -25,6 +25,7 @@ import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementS
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook;
@@ -44,7 +45,7 @@ import java.util.concurrent.CompletableFuture;
@Slf4j
public class Contact extends AbstractConditionableCommand {
- private static final String CONTACT_PARAMETER = "contact";
+ private static final String COMMAND_NAME = "contact";
private static final String USER_PARMETER = "user";
private static final String MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE = "modmail_thread_already_exists";
private static final String CONTACT_RESPONSE = "contact_response";
@@ -87,24 +88,21 @@ public class Contact extends AbstractConditionableCommand {
List> futures = channelService.sendEmbedTemplateInTextChannelList(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
} else {
- return modMailThreadService.createModMailThreadForUser(targetUser, null, false, commandContext.getUndoActions())
- .thenCompose(unused -> modMailThreadService.sendContactNotification(targetUser, unused, commandContext.getChannel()))
+ return modMailThreadService.createModMailThreadForUser(targetUser.getUser(), targetUser.getGuild(), null, false, commandContext.getUndoActions())
+ .thenCompose(unused -> modMailThreadService.sendContactNotification(targetUser.getUser(), unused, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
}
@Override
public CompletableFuture executeSlash(SlashCommandInteractionEvent event) {
- Member member = slashCommandParameterService.getCommandOption(USER_PARMETER, event, Member.class);
- if(!member.getGuild().equals(event.getGuild())) {
- throw new EntityGuildMismatchException();
- }
- AUserInAServer user = userManagementService.loadOrCreateUser(member);
+ User user = slashCommandParameterService.getCommandOption(USER_PARMETER, event, User.class);
+ AUserInAServer userInAServer = userManagementService.loadOrCreateUser(user.getIdLong(), event.getGuild().getIdLong());
// if this AUserInAServer already has an open thread, we should instead post a message
// containing a link to the channel, instead of opening a new one
- if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
- log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", event.getMember().getId(), event.getGuild().getId(), user.getUserReference().getId());
- ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
+ if(modMailThreadManagementService.hasOpenModMailThreadForUser(userInAServer)) {
+ log.info("Modmail thread for userInAServer {} in server {} already exists. Notifying userInAServer {}.", event.getMember().getId(), event.getGuild().getId(), userInAServer.getUserReference().getId());
+ ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(userInAServer);
ModMailThreadExistsModel model = ModMailThreadExistsModel
.builder()
.existingModMailThread(existingThread)
@@ -114,9 +112,9 @@ public class Contact extends AbstractConditionableCommand {
.thenApply(interactionHook -> CommandResult.fromSuccess());
} else {
CompletableFuture response = interactionService.replyEmbed(CONTACT_RESPONSE, event);
- CompletableFuture threadFuture = modMailThreadService.createModMailThreadForUser(member, null, false, new ArrayList<>());
+ CompletableFuture threadFuture = modMailThreadService.createModMailThreadForUser(user, event.getGuild(), null, false, new ArrayList<>());
return CompletableFuture.allOf(response, threadFuture)
- .thenCompose(unused -> modMailThreadService.sendContactNotification(member, threadFuture.join(), response.join()))
+ .thenCompose(unused -> modMailThreadService.sendContactNotification(user, threadFuture.join(), response.join()))
.thenApply(o -> CommandResult.fromSuccess());
}
}
@@ -126,7 +124,7 @@ public class Contact extends AbstractConditionableCommand {
Parameter responseText = Parameter
.builder()
.name(USER_PARMETER)
- .type(Member.class)
+ .type(User.class)
.templated(true)
.build();
List parameters = Arrays.asList(responseText);
@@ -139,11 +137,11 @@ public class Contact extends AbstractConditionableCommand {
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
- .commandName(CONTACT_PARAMETER)
+ .commandName(COMMAND_NAME)
.build();
return CommandConfiguration.builder()
- .name(CONTACT_PARAMETER)
+ .name(COMMAND_NAME)
.module(ModMailModuleDefinition.MODMAIL)
.parameters(parameters)
.slashCommandConfig(slashCommandConfig)
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/DenyModmailAppeal.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/DenyModmailAppeal.java
new file mode 100644
index 000000000..7b1189a5b
--- /dev/null
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/DenyModmailAppeal.java
@@ -0,0 +1,121 @@
+package dev.sheldan.abstracto.modmail.command;
+
+import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
+import dev.sheldan.abstracto.core.command.condition.CommandCondition;
+import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
+import dev.sheldan.abstracto.core.command.config.HelpInfo;
+import dev.sheldan.abstracto.core.command.config.Parameter;
+import dev.sheldan.abstracto.core.command.execution.CommandResult;
+import dev.sheldan.abstracto.core.config.FeatureDefinition;
+import dev.sheldan.abstracto.core.config.FeatureMode;
+import dev.sheldan.abstracto.core.interaction.InteractionService;
+import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
+import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
+import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
+import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
+import dev.sheldan.abstracto.modmail.config.ModMailMode;
+import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
+import dev.sheldan.abstracto.modmail.exception.ModMailThreadClosedException;
+import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
+import dev.sheldan.abstracto.modmail.model.database.ModMailThreadState;
+import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
+import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
+import lombok.extern.slf4j.Slf4j;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.InteractionHook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+@Component
+@Slf4j
+public class DenyModmailAppeal extends AbstractConditionableCommand {
+
+ private static final String COMMAND_NAME = "denyappeal";
+ private static final String FULL_COMMAND_NAME = "denyModmailAppeal";
+ private static final String REASON_PARAMETER = "reason";
+
+ private static final String RESPONSE_TEMPLATE = "denyModmailAppeal_response";
+
+ @Autowired
+ private ModMailContextCondition requiresModMailCondition;
+
+ @Autowired
+ private ModMailThreadManagementService modMailThreadManagementService;
+
+ @Autowired
+ private ModMailThreadService modMailThreadService;
+
+ @Autowired
+ private SlashCommandParameterService slashCommandParameterService;
+
+ @Autowired
+ private InteractionService interactionService;
+
+ @Override
+ public CompletableFuture executeSlash(SlashCommandInteractionEvent event) {
+ ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(event.getChannel().getIdLong());
+ if(ModMailThreadState.CLOSED.equals(modMailThread.getState()) || ModMailThreadState.CLOSING.equals(modMailThread.getState())) {
+ throw new ModMailThreadClosedException();
+ }
+ String reason = slashCommandParameterService.getCommandOption(REASON_PARAMETER, event, String.class);
+ CompletableFuture response = interactionService.replyEmbed(RESPONSE_TEMPLATE, event);
+ CompletableFuture threadFuture = modMailThreadService.rejectAppeal(modMailThread, reason, event.getMember());
+ return CompletableFuture.allOf(response, threadFuture)
+ .thenApply(unused -> CommandResult.fromSuccess());
+ }
+
+ @Override
+ public FeatureDefinition getFeature() {
+ return ModMailFeatureDefinition.MOD_MAIL;
+ }
+
+ @Override
+ public CommandConfiguration getConfiguration() {
+ Parameter responseText = Parameter
+ .builder()
+ .name(REASON_PARAMETER)
+ .type(String.class)
+ .templated(true)
+ .build();
+
+ List parameters = Arrays.asList(responseText);
+ HelpInfo helpInfo = HelpInfo
+ .builder()
+ .templated(true)
+ .build();
+
+ SlashCommandConfig slashCommandConfig = SlashCommandConfig
+ .builder()
+ .enabled(true)
+ .rootCommandName(ModMailSlashCommandNames.MODMAIL)
+ .commandName(COMMAND_NAME)
+ .build();
+
+ return CommandConfiguration.builder()
+ .name(FULL_COMMAND_NAME)
+ .module(ModMailModuleDefinition.MODMAIL)
+ .parameters(parameters)
+ .slashCommandConfig(slashCommandConfig)
+ .help(helpInfo)
+ .slashCommandOnly(true)
+ .supportsEmbedException(true)
+ .templated(true)
+ .build();
+ }
+
+ @Override
+ public List getConditions() {
+ List conditions = super.getConditions();
+ conditions.add(requiresModMailCondition);
+ return conditions;
+ }
+
+ @Override
+ public List getFeatureModeLimitations() {
+ return List.of(ModMailMode.MOD_MAIL_APPEALS);
+ }
+}
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Reply.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Reply.java
index c536b070b..fee6523ff 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Reply.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/command/Reply.java
@@ -9,6 +9,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.MemberService;
+import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.exception.ModMailThreadClosedException;
@@ -39,7 +40,7 @@ public class Reply extends AbstractConditionableCommand {
private ModMailThreadManagementService modMailThreadManagementService;
@Autowired
- private MemberService memberService;
+ private UserService userService;
@Override
public CompletableFuture executeAsync(CommandContext commandContext) {
@@ -50,8 +51,8 @@ public class Reply extends AbstractConditionableCommand {
throw new ModMailThreadClosedException();
}
Long threadId = modMailThread.getId();
- return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
- modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), false, member)
+ return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
+ modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), false, user, commandContext.getGuild())
).thenApply(aVoid -> CommandResult.fromSuccess());
}
@@ -65,7 +66,7 @@ public class Reply extends AbstractConditionableCommand {
.optional(true)
.templated(true)
.build();
- List parameters = Arrays.asList(responseText);
+ List parameters = List.of(responseText);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("reply")
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailInitialButtonListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailInitialButtonListener.java
index 42d255ec8..d401e5532 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailInitialButtonListener.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailInitialButtonListener.java
@@ -14,6 +14,7 @@ import dev.sheldan.abstracto.modmail.model.dto.ServiceChoicesPayload;
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
import lombok.extern.slf4j.Slf4j;
+import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@@ -25,7 +26,7 @@ import java.util.ArrayList;
public class ModMailInitialButtonListener implements ButtonClickedListener {
@Autowired
- private MemberService memberService;
+ private GuildService guildService;
@Autowired
private ModMailThreadService modMailThreadService;
@@ -51,20 +52,19 @@ public class ModMailInitialButtonListener implements ButtonClickedListener {
Long userId = choices.getUserId();
log.debug("Executing action for creationg a modmail thread in server {} for user {}.", chosenServer.getServerId(), userId);
ArrayList undoActions = new ArrayList<>();
- memberService.getMemberInServerAsync(chosenServer.getServerId(), userId)
- .thenCompose(member -> channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId())
+ Guild guild = guildService.getGuildById(chosenServer.getServerId());
+ channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId())
.thenCompose(originalMessage -> {
try {
- return modMailThreadService.createModMailThreadForUser(member, originalMessage, true, undoActions);
+ return modMailThreadService.createModMailThreadForUser(model.getEvent().getUser(), guild, originalMessage, true, undoActions);
} catch (Exception ex) {
log.error("Failed to setup thread correctly", ex);
undoActionService.performActions(undoActions);
return null;
}
})
- .thenAccept(unused -> self.cleanup(model)))
- .exceptionally(throwable -> {
- log.error("Failed to setup thread correctly", throwable);
+ .thenAccept(unused -> self.cleanup(model)).exceptionally(throwable -> {
+ log.warn("Failed to setup modmail thread.");
undoActionService.performActions(undoActions);
return null;
});
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListener.java
index 9ef2690a9..d68ded485 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListener.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListener.java
@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.listener.MessageDeletedModel;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.core.service.MessageService;
+import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
@@ -33,7 +34,7 @@ public class ModMailMessageDeletedListener implements AsyncMessageDeletedListene
private ModMailMessageDeletedListener self;
@Autowired
- private MemberService memberService;
+ private UserService userService;
@Override
public DefaultListenerResult execute(MessageDeletedModel model) {
@@ -47,8 +48,8 @@ public class ModMailMessageDeletedListener implements AsyncMessageDeletedListene
Long channelId = thread.getChannel().getId();
Long serverId = thread.getServer().getId();
log.info("Deleting message for mod mail thread {} in channel {} in server {}.", thread.getId(), channelId, serverId);
- memberService.getMemberInServerAsync(model.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId()).thenAccept(member -> {
- CompletableFuture dmDeletePromise = messageService.deleteMessageInChannelWithUser(member.getUser(), dmMessageId);
+ userService.retrieveUserForId(modMailMessage.getThreadReference().getUser().getUserReference().getId()).thenAccept(user -> {
+ CompletableFuture dmDeletePromise = messageService.deleteMessageInChannelWithUser(user, dmMessageId);
CompletableFuture channelDeletePromise;
if(hasMessageInChannel) {
channelDeletePromise = messageService.deleteMessageInChannelInServer(serverId, channelId, channelMessage);
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListener.java
index 37d77d564..4249c4151 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListener.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListener.java
@@ -10,9 +10,11 @@ import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.listener.MessageUpdatedModel;
+import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.core.service.MessageService;
+import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
import dev.sheldan.abstracto.modmail.model.template.ModMailModeratorReplyModel;
@@ -24,6 +26,7 @@ import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@@ -45,9 +48,6 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
@Autowired
private CommandService commandService;
- @Autowired
- private MemberService memberService;
-
@Autowired
private TemplateService templateService;
@@ -66,6 +66,12 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
@Autowired
private ModMailThreadService modMailThreadService;
+ @Autowired
+ private MemberService memberService;
+
+ @Autowired
+ private UserService userService;
+
@Override
public DefaultListenerResult execute(MessageUpdatedModel model) {
CachedMessage messageBefore = model.getBefore();
@@ -85,7 +91,7 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
log.info("Edit did not contain the original command to retrieve the parameters for. Resulting to {}.", DEFAULT_COMMAND_FOR_MODMAIL_EDIT);
}
CompletableFuture parameterParseFuture = commandService.getParametersForCommand(commandName, message);
- CompletableFuture loadTargetUser = memberService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId());
+ CompletableFuture loadTargetUser = userService.retrieveUserForId(modMailMessage.getThreadReference().getUser().getUserReference().getId());
CompletableFuture loadEditingUser = memberService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getAuthor().getUserReference().getId());
CompletableFuture.allOf(parameterParseFuture, loadTargetUser, loadEditingUser).thenAccept(unused ->
self.updateMessageInThread(message, parameterParseFuture.join(), loadTargetUser.join(), loadEditingUser.join())
@@ -100,15 +106,10 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
}
@Transactional
- public void updateMessageInThread(Message loadedMessage, Parameters parameters, Member targetMember, Member editingUser) {
+ public void updateMessageInThread(Message loadedMessage, Parameters parameters, User user, Member editingUser) {
String newText = (String) parameters.getParameters().get(0);
Optional messageOptional = modMailMessageManagementService.getByMessageIdOptional(loadedMessage.getIdLong());
messageOptional.ifPresent(modMailMessage -> {
- FullUserInServer fullThreadUser = FullUserInServer
- .builder()
- .aUserInAServer(modMailMessage.getThreadReference().getUser())
- .member(targetMember)
- .build();
List imageUrls = loadedMessage
.getAttachments()
.stream()
@@ -128,7 +129,7 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
.attachedImageUrls(imageUrls)
.remainingAttachments(otherAttachments)
.anonymous(modMailMessage.getAnonymous())
- .threadUser(fullThreadUser);
+ .userDisplay(UserDisplay.fromUser(user));
if(modMailMessage.getAnonymous()) {
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailMessage.getThreadReference().getServer()));
} else {
@@ -143,13 +144,13 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
log.debug("Editing message {} in mod mail channel {} for thread {} in server {} as well.", modMailMessage.getCreatedMessageInChannel(), channel.getId(), threadId, serverId);
channelService.editMessageInAChannel(messageToSend, channel, modMailMessage.getCreatedMessageInChannel());
}
- log.debug("Editing message {} in DM channel with user {} for thread {} in server {}.", modMailMessage.getCreatedMessageInDM(), targetMember.getUser().getIdLong(), threadId, serverId);
- messageService.editMessageInDMChannel(targetMember.getUser(), messageToSend, modMailMessage.getCreatedMessageInDM());
+ log.debug("Editing message {} in DM channel with user {} for thread {} in server {}.", modMailMessage.getCreatedMessageInDM(), user.getIdLong(), threadId, serverId);
+ messageService.editMessageInDMChannel(user, messageToSend, modMailMessage.getCreatedMessageInDM());
});
if(!messageOptional.isPresent()) {
log.warn("Message {} of user {} in channel {} for server {} for thread about user {} could not be found in the mod mail messages when updating the text.",
- loadedMessage.getIdLong(), editingUser.getIdLong(), loadedMessage.getChannel().getIdLong(), loadedMessage.getGuild().getIdLong(), targetMember.getIdLong());
+ loadedMessage.getIdLong(), editingUser.getIdLong(), loadedMessage.getChannel().getIdLong(), loadedMessage.getGuild().getIdLong(), user.getIdLong());
}
}
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java
index b0b826765..abfc3036c 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java
@@ -36,9 +36,6 @@ public class ModMailMessageListener implements PrivateMessageReceivedListener {
@Autowired
private UserManagementService userManagementService;
- @Autowired
- private UserInServerManagementService userInServerManagementService;
-
@Override
@Transactional
public void execute(Message message) {
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java
index 77c5df592..feadf74b0 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java
@@ -19,9 +19,6 @@ public class ModMailRoleServiceBean implements ModMailRoleService {
@Autowired
private CommandService commandService;
- @Autowired
- private FeatureManagementService featureManagementService;
-
@Override
public void addRoleToModMailRoles(ARole role) {
log.info("Adding role {} to modmail roles in server {}.", role.getId(), role.getServer().getId());
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java
index 8f5a8ae77..b4660b28f 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java
@@ -8,10 +8,7 @@ import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
import dev.sheldan.abstracto.core.metric.service.MetricService;
import dev.sheldan.abstracto.core.metric.service.MetricTag;
-import dev.sheldan.abstracto.core.models.FeatureValidationResult;
-import dev.sheldan.abstracto.core.models.FullGuild;
-import dev.sheldan.abstracto.core.models.FullUserInServer;
-import dev.sheldan.abstracto.core.models.UndoActionInstance;
+import dev.sheldan.abstracto.core.models.*;
import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import dev.sheldan.abstracto.core.service.*;
@@ -20,6 +17,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.core.utils.FutureUtils;
+import dev.sheldan.abstracto.moderation.service.BanService;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureConfig;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailMode;
@@ -52,6 +50,7 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
+import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@@ -112,6 +111,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Autowired
private GuildService guildService;
+ @Autowired
+ private BanService banService;
+
@Autowired
private MessageService messageService;
@@ -188,22 +190,21 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
public static final String MODMAIL_INITIAL_ORIGIN = "modmailInitial";
@Override
- public CompletableFuture createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List undoActions) {
- Long serverId = member.getGuild().getIdLong();
- User user = member.getUser();
- AServer server = serverManagementService.loadServer(member.getGuild().getIdLong());
+ public CompletableFuture createModMailThreadForUser(User user, Guild guild, Message initialMessage, boolean userInitiated, List undoActions) {
+ Long serverId = guild.getIdLong();
+ AServer server = serverManagementService.loadServer(serverId);
metricService.incrementCounter(MODMAIL_THREAD_CREATED_COUNTER);
ModMailChannelNameModel model = ModMailChannelNameModel
.builder()
.serverId(serverId)
- .userId(member.getIdLong())
+ .userId(user.getIdLong())
.randomText(RandomStringUtils.randomAlphanumeric(25))
.uuid(UUID.randomUUID().toString())
.currentDate(Instant.now())
.build();
String channelName = templateService.renderTemplate(TEXT_CHANNEL_NAME_TEMPLATE_KEY, model, serverId);
if (featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, serverId, ModMailMode.THREAD_CONTAINER)) {
- MessageToSend notificationMessageToSend = getModmailNotificationMessageToSend(member, null, serverId, false);
+ MessageToSend notificationMessageToSend = getModmailNotificationMessageToSend(user, null, serverId, false);
Optional modmailContainerOptional = postTargetService.getPostTargetChannel(ModMailPostTargets.MOD_MAIL_CONTAINER, serverId);
if(modmailContainerOptional.isEmpty()) {
throw new AbstractoRunTimeException("Modmail thread container not setup.");
@@ -219,7 +220,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.thenCompose(unused -> channelService.createThreadWithStarterMessage(textChannel, channelName, notificationMessage.get(0).join().getIdLong()))
.thenCompose(threadChannel -> {
undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, threadChannel.getIdLong()));
- return self.performModMailThreadSetup(member, initialMessage, threadChannel, userInitiated, undoActions)
+ return self.performModMailThreadSetup(user, initialMessage, threadChannel, userInitiated, undoActions)
.thenCompose(unused -> CompletableFuture.completedFuture(threadChannel));
});
} else {
@@ -228,7 +229,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
CompletableFuture textChannelFuture = channelService.createTextChannel(channelName, server, categoryId);
return textChannelFuture.thenCompose(channel -> {
undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, channel.getIdLong()));
- return self.performModMailThreadSetup(member, initialMessage, channel, userInitiated, undoActions)
+ return self.performModMailThreadSetup(user, initialMessage, channel, userInitiated, undoActions)
.thenCompose(unused -> CompletableFuture.completedFuture(channel));
});
}
@@ -236,21 +237,21 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Transactional
@Override
- public CompletableFuture sendContactNotification(Member member, MessageChannel messageChannel, MessageChannel feedBackChannel) {
+ public CompletableFuture sendContactNotification(User user, MessageChannel messageChannel, MessageChannel feedBackChannel) {
ContactNotificationModel model = ContactNotificationModel
.builder()
.createdChannel(messageChannel)
- .targetMember(member)
+ .userDisplay(UserDisplay.fromUser(user))
.build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannelList(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, feedBackChannel));
}
@Override
- public CompletableFuture sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook) {
+ public CompletableFuture sendContactNotification(User user, MessageChannel createdMessageChannel, InteractionHook interactionHook) {
ContactNotificationModel model = ContactNotificationModel
.builder()
.createdChannel(createdMessageChannel)
- .targetMember(member)
+ .userDisplay(UserDisplay.fromUser(user))
.build();
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, interactionHook));
}
@@ -258,7 +259,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
/**
* This method is responsible for creating the instance in the database, sending the header in the newly created text channel and forwarding the initial message
* by the user (if any), after this is complete, this method executes the method to perform the mod mail notification.
- * @param member The {@link Member} for which a {@link ModMailThread} is being created
+ * @param user The {@link User} for which a {@link ModMailThread} is being created
* @param initialMessage The {@link Message} which was sent by the user to open a thread, this is null, if the thread was opened via a command
* @param channel The created {@link TextChannel} in which the mod mail thread is dealt with
* @param userInitiated Whether the thread was initiated by a member
@@ -266,33 +267,33 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @return A {@link CompletableFuture future} which completes when the setup is done
*/
@Transactional
- public CompletableFuture performModMailThreadSetup(Member member, Message initialMessage, GuildMessageChannel channel, boolean userInitiated, List undoActions) {
- log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), member.getId(), channel.getGuild().getId(), userInitiated);
- CompletableFuture headerFuture = sendModMailHeader(channel, member);
+ public CompletableFuture performModMailThreadSetup(User user, Message initialMessage, GuildMessageChannel channel, boolean userInitiated, List undoActions) {
+ log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), user.getId(), channel.getGuild().getId(), userInitiated);
+ CompletableFuture headerFuture = sendModMailHeader(channel, user);
CompletableFuture userReplyMessage;
if(initialMessage != null){
- log.info("Sending initial message {} of user {} to modmail thread {}.", initialMessage.getId(), member.getId(), channel.getId());
- userReplyMessage = self.sendUserReply(channel, 0L, initialMessage, member, false);
+ log.info("Sending initial message {} of user {} to modmail thread {}.", initialMessage.getId(), user.getId(), channel.getId());
+ userReplyMessage = self.sendUserReply(channel, 0L, initialMessage, false);
} else {
log.info("No initial message to send.");
userReplyMessage = CompletableFuture.completedFuture(null);
}
CompletableFuture notificationFuture;
if (userInitiated) {
- notificationFuture = self.sendModMailNotification(member, channel);
+ notificationFuture = self.sendModMailNotification(user, channel);
} else {
notificationFuture = CompletableFuture.completedFuture(null);
}
return CompletableFuture.allOf(headerFuture, notificationFuture, userReplyMessage).thenAccept(aVoid -> {
undoActions.clear();
- self.setupModMailThreadInDB(initialMessage, channel, member, userReplyMessage.join());
+ self.setupModMailThreadInDB(initialMessage, channel, user, userReplyMessage.join());
});
}
@Transactional
- public void setupModMailThreadInDB(Message initialMessage, GuildMessageChannel channel, Member member, Message sendMessage) {
+ public void setupModMailThreadInDB(Message initialMessage, GuildMessageChannel channel, User user, Message sendMessage) {
log.info("Persisting info about modmail thread {} in database.", channel.getIdLong());
- AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
+ AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(channel.getGuild().getIdLong(), user.getIdLong());
ModMailThread thread = createThreadObject(channel, aUserInAServer);
if(initialMessage != null) {
log.debug("Adding initial message {} to modmail thread in channel {}.", initialMessage.getId(), channel.getId());
@@ -302,19 +303,19 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
/**
* Sends the message containing the pings to notify the staff members to handle the opened {@link ModMailThread}
- * @param member The {@link FullUserInServer} which opened the thread
+ * @param user The {@link FullUserInServer} which opened the thread
* @param channel The created {@link GuildMessageChannel} in which the mod mail thread is dealt with
* @return A {@link CompletableFuture future} which completes when the notification has been sent
*/
@Transactional
- public CompletableFuture sendModMailNotification(Member member, GuildMessageChannel channel) {
- Long serverId = member.getGuild().getIdLong();
- MessageToSend messageToSend = getModmailNotificationMessageToSend(member, channel, serverId, true);
+ public CompletableFuture sendModMailNotification(User user, GuildMessageChannel channel) {
+ Long serverId = channel.getGuild().getIdLong();
+ MessageToSend messageToSend = getModmailNotificationMessageToSend(user, channel, serverId, true);
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_PING, serverId));
}
- private MessageToSend getModmailNotificationMessageToSend(Member member, GuildMessageChannel channel, Long serverId, boolean pingRole) {
- log.info("Sending modmail notification for new modmail thread about user {} in server {}.", member.getId(), serverId);
+ private MessageToSend getModmailNotificationMessageToSend(User user, GuildMessageChannel channel, Long serverId, boolean pingRole) {
+ log.info("Sending modmail notification for new modmail thread about user {} in server {}.", user.getId(), serverId);
AServer server = serverManagementService.loadServer(serverId);
List rolesToPing;
if(pingRole) {
@@ -322,10 +323,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
} else {
rolesToPing = new ArrayList<>();
}
- log.debug("Pinging {} roles to notify about modmail thread about user {} in server {}.", rolesToPing.size(), member.getId(), serverId);
+ log.debug("Pinging {} roles to notify about modmail thread about user {} in server {}.", rolesToPing.size(), user.getId(), serverId);
ModMailNotificationModel modMailNotificationModel = ModMailNotificationModel
.builder()
- .member(member)
+ .userDisplay(UserDisplay.fromUser(user))
.roles(rolesToPing)
.channel(channel)
.build();
@@ -370,24 +371,57 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
if(!servers.isEmpty()) {
log.info("There are {} shared servers between user and the bot.", servers.size());
List availableGuilds = new ArrayList<>();
+ Set alreadyConsideredServers = new HashSet<>();
for (AServer server : servers) {
// only take the servers in which mod mail is actually enabled, would not make much sense to make the
// other servers available
- if (featureFlagService.isFeatureEnabled(modMailFeatureConfig, server)) {
- FullGuild guild = FullGuild
- .builder()
- .guild(guildService.getGuildById(server.getId()))
- .server(server)
- .build();
+ boolean possibleForModmail = featureFlagService.isFeatureEnabled(modMailFeatureConfig, server);
+ if (possibleForModmail) {
+ Guild guild = guildService.getGuildById(server.getId());
ServerChoice serverChoice = ServerChoice
.builder()
- .serverId(guild.getGuild().getIdLong())
- .serverName(guild.getGuild().getName())
+ .serverId(guild.getIdLong())
+ .serverName(guild.getName())
+ .build();
+ availableGuilds.add(serverChoice);
+ }
+ alreadyConsideredServers.add(server.getId());
+ }
+
+ List restOfKnownServers = serverManagementService.getAllServers()
+ .stream()
+ .filter(server -> alreadyConsideredServers.contains(server.getId()))
+ .toList();
+ for (AServer server : restOfKnownServers) {
+ boolean possibleForModmail = false;
+ Long actualServerId = 0L;
+ Long potentialMainServer = configService.getLongValue(ModMailFeatureConfig.MOD_MAIL_APPEAL_SERVER, server.getId()); // what _other_ server is the appeal server
+ if(potentialMainServer != 0) {
+ if(featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, potentialMainServer, ModMailMode.MOD_MAIL_APPEALS)) {
+ Long configuredAppealServerId = configService.getLongValue(ModMailFeatureConfig.MOD_MAIL_APPEAL_SERVER, potentialMainServer);
+ if(configuredAppealServerId != 0 && configuredAppealServerId.equals(server.getId())) { // if the other server has set the current server as the appeal config
+ Guild otherGuild = guildService.getGuildById(potentialMainServer);
+ if(otherGuild != null) { // check if we are part of that server
+ possibleForModmail = true;
+ actualServerId = potentialMainServer;
+ log.info("Server {} was available, because it is using server {} as a mod mail appeal server.", server.getId(), otherGuild.getIdLong());
+ }
+ }
+ } else {
+ log.info("Server {} has set the appeal server {}, but that server does not have mod mail appeals enabled.", server.getId(), potentialMainServer);
+ }
+ }
+ if(possibleForModmail) {
+ Guild guild = guildService.getGuildById(actualServerId);
+ ServerChoice serverChoice = ServerChoice
+ .builder()
+ .serverId(guild.getIdLong())
+ .serverName(guild.getName())
.build();
availableGuilds.add(serverChoice);
}
}
- log.info("There were {} shared servers found which have modmail enabled.", availableGuilds.size());
+ log.info("There were {} available servers found.", availableGuilds.size());
// if more than 1 server is available, show a choice dialog
ArrayList undoActions = new ArrayList<>();
if(availableGuilds.size() > 1) {
@@ -415,20 +449,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
} else if(availableGuilds.size() == 1) {
// if exactly one server is available, open the thread directly
Long chosenServerId = availableGuilds.get(0).getServerId();
+ Guild guild = guildService.getGuildById(chosenServerId);
log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", initialMessage.getAuthor().getId(), chosenServerId);
- memberService.getMemberInServerAsync(chosenServerId, initialMessage.getAuthor().getIdLong()).thenCompose(member -> {
- try {
- return self.createModMailThreadForUser(member, initialMessage, true, undoActions).thenApply(messageChannel -> null);
- } catch (Exception exception) {
- CompletableFuture future = new CompletableFuture<>();
- future.completeExceptionally(exception);
- return future;
- }
- }).exceptionally(throwable -> {
- log.error("Failed to setup thread correctly", throwable);
- undoActionService.performActions(undoActions);
- return null;
- });
+ createModMailThreadForUser(initialMessage.getAuthor(), guild , initialMessage, true, undoActions)
+ .thenAccept(messageChannel -> {
+ log.info("Setup modmail thread for user {} in guild {}.", initialMessage.getAuthor().getIdLong(), guild.getIdLong());
+ }).exceptionally(throwable -> {
+ log.error("Failed to setup modmail channel in guild {} for user {}.", guild.getIdLong(), initialMessage.getAuthor().getIdLong(), throwable);
+ return null;
+ });
} else {
log.info("No server available to open a modmail thread in.");
// in case there is no server available, send an error message
@@ -451,18 +480,17 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* Method used to send the header of a newly created mod mail thread. This message contains information about
* the user which the thread is about
* @param channel The {@link GuildMessageChannel} in which the mod mail thread is present in
- * @param member The {@link Member} which the {@link ModMailThread} is about
+ * @param user The {@link User} which the {@link ModMailThread} is about
*/
- private CompletableFuture sendModMailHeader(GuildMessageChannel channel, Member member) {
+ private CompletableFuture sendModMailHeader(GuildMessageChannel channel, User user) {
log.debug("Sending modmail thread header for tread in channel {} on server {}.", channel.getIdLong(), channel.getGuild().getId());
- AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
+ AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(channel.getGuild().getIdLong(), user.getIdLong());
ModMailThread latestThread = modMailThreadManagementService.getLatestModMailThread(aUserInAServer);
List oldThreads = modMailThreadManagementService.getModMailThreadForUser(aUserInAServer);
ModMailThreaderHeader header = ModMailThreaderHeader
.builder()
- .member(member)
+ .userDisplay(UserDisplay.fromUser(user))
.latestModMailThread(latestThread)
- .memberJoinDate(member.getTimeJoined().toInstant())
.pastModMailThreadCount((long)oldThreads.size())
.build();
List> messages = channelService.sendEmbedTemplateInTextChannelList("modmail_thread_header", header, channel);
@@ -476,18 +504,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Long modmailThreadId = modMailThread.getId();
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_RECEIVED);
log.debug("Relaying message {} to modmail thread {} for user {} to server {}.", messageFromUser.getId(), modMailThread.getId(), messageFromUser.getAuthor().getIdLong(), modMailThread.getServer().getId());
- return memberService.getMemberInServerAsync(modMailThread.getServer().getId(), messageFromUser.getAuthor().getIdLong()).thenCompose(member ->
- self.relayMessage(messageFromUser, serverId, channelId, modmailThreadId, member)
- );
-
- }
-
- @Transactional
- public CompletableFuture relayMessage(Message messageFromUser, Long serverId, Long channelId, Long modmailThreadId, Member member) {
Optional textChannelFromServer = channelService.getMessageChannelFromServerOptional(serverId, channelId);
if(textChannelFromServer.isPresent()) {
GuildMessageChannel guildMessageChannel = textChannelFromServer.get();
- return self.sendUserReply(guildMessageChannel, modmailThreadId, messageFromUser, member, true);
+ return self.sendUserReply(guildMessageChannel, modmailThreadId, messageFromUser, true);
} else {
log.warn("Closing mod mail thread {}, because it seems the channel {} in server {} got deleted.", modmailThreadId, channelId, serverId);
// in this case there was no text channel on the server associated with the mod mail thread
@@ -505,11 +525,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @param messageChannel The {@link GuildMessageChannel} in which the {@link ModMailThread} is being handled
* @param modMailThreadId The id of the modmail thread to which the received {@link Message} is a reply to, can be null, if it is null, its the initial message
* @param messageFromUser The received message from the user
- * @param member The {@link Member} instance from the user the thread is about. It is used as author
* @param modMailThreadExists Whether the modmail thread already exists and is persisted.
* @return A {@link CompletableFuture} which resolves when the postprocessing of the message is completed (adding read notification, and storing messageIDs)
*/
- public CompletableFuture sendUserReply(GuildMessageChannel messageChannel, Long modMailThreadId, Message messageFromUser, Member member, boolean modMailThreadExists) {
+ public CompletableFuture sendUserReply(GuildMessageChannel messageChannel, Long modMailThreadId, Message messageFromUser, boolean modMailThreadExists) {
List> subscriberMemberFutures = new ArrayList<>();
if(modMailThreadExists) {
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
@@ -550,7 +569,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
ModMailUserReplyModel modMailUserReplyModel = ModMailUserReplyModel
.builder()
.postedMessage(messageFromUser)
- .member(member)
+ .userDisplay(UserDisplay.fromUser(messageFromUser.getAuthor()))
.attachedImageUrls(imageUrls)
.remainingAttachments(otherAttachments)
.subscribers(subscribers)
@@ -604,21 +623,16 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
@Transactional
- public CompletableFuture 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());
+ public CompletableFuture loadExecutingMemberAndRelay(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, User user, Guild guild) {
+ log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), user.getId(), modmailThreadId, guild.getId());
return memberService.getMemberInServerAsync(replyCommandMessage.getGuild().getIdLong(), replyCommandMessage.getAuthor().getIdLong())
- .thenCompose(executingMember -> self.relayMessageToDm(modmailThreadId, text, replyCommandMessage, anonymous, targetMember, executingMember));
+ .thenCompose(executingMember -> self.relayMessageToDm(modmailThreadId, text, replyCommandMessage, anonymous, user, executingMember));
}
@Transactional
- public CompletableFuture relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, Member targetMember, Member executingMember) {
+ public CompletableFuture relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, User user, Member executingMember) {
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_SENT);
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
- FullUserInServer fullThreadUser = FullUserInServer
- .builder()
- .aUserInAServer(modMailThread.getUser())
- .member(targetMember)
- .build();
List imageUrls = replyCommandMessage
.getAttachments()
.stream()
@@ -638,7 +652,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.remainingAttachments(otherAttachments)
.attachedImageUrls(imageUrls)
.anonymous(anonymous)
- .threadUser(fullThreadUser);
+ .userDisplay(UserDisplay.fromUser(user));
if(anonymous) {
log.debug("Message is sent anonymous.");
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailThread.getServer()));
@@ -647,7 +661,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate(MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel, modMailThread.getServer().getId());
- CompletableFuture future = messageService.sendMessageToSendToUser(targetMember.getUser(), messageToSend);
+ CompletableFuture future = messageService.sendMessageToSendToUser(user, messageToSend);
CompletableFuture sameThreadMessageFuture;
if(featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, modMailThread.getServer(), ModMailMode.SEPARATE_MESSAGE)) {
sameThreadMessageFuture = channelService.sendMessageEmbedToSendToAChannel(messageToSend, modMailThread.getChannel()).get(0);
@@ -679,24 +693,24 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
log.info("Archiving thread {} for modmail thread closing.", modMailThread.getChannel().getId());
return loadUserAndSendClosingHeader(modMailThread, closingConfig)
.thenCompose(unused -> channelService.archiveThreadChannel(threadChannel))
- .thenCompose(unused -> memberService.getMemberInServerAsync(serverId, userId))
- .thenAccept(member -> self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions));
+ .thenCompose(unused -> userService.retrieveUserForId(userId))
+ .thenCompose(user -> self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), user, undoActions));
} else {
if(closingConfig.getLog()) {
if(!modMailMessages.isEmpty()) {
return modMailMessageService.loadModMailMessages(modMailMessages)
- .thenAccept(loadedModmailThreadMessages -> self.logMessagesToModMailLog(closingConfig, modMailThreadId, undoActions, loadedModmailThreadMessages, serverId, userId));
+ .thenCompose(loadedModmailThreadMessages -> self.logMessagesToModMailLog(closingConfig, modMailThreadId, undoActions, loadedModmailThreadMessages, serverId, userId));
} else {
log.info("Modmail thread {} in server {} has no messages. Only logging header.", modMailThreadId, serverId);
return loadUserAndSendClosingHeader(modMailThread, closingConfig)
- .thenAccept(unused -> memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
- self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions)
+ .thenCompose(unused -> userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
+ self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), user, undoActions)
));
}
} else {
log.debug("Not logging modmail thread {}.", modMailThreadId);
- return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
- self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions)
+ return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
+ self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), user, undoActions)
);
}
}
@@ -736,8 +750,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
undoActions.add(UndoActionInstance.getMessageDeleteAction(message.getGuild().getIdLong(), message.getChannel().getIdLong(), message.getIdLong()));
}
});
- return memberService.getMemberInServerAsync(serverId, userId).thenCompose(member ->
- self.afterSuccessfulLog(modMailThreadId, closingContext.getNotifyUser(), member, undoActions)
+ return userService.retrieveUserForId(userId).thenCompose(user ->
+ self.afterSuccessfulLog(modMailThreadId, closingContext.getNotifyUser(), user, undoActions)
).exceptionally(throwable -> {
log.warn("Failed to retrieve member for closing the modmail thread. Closing without member information.", throwable);
self.afterSuccessfulLog(modMailThreadId, false, null, undoActions);
@@ -756,12 +770,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @param modMailThreadId The ID of the {@link ModMailThread} which is being closed.
* @param notifyUser Whether the user should be notified
* @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions
- * @param modMailThreaduser The {@link Member member} for which the {@link ModMailThread thread} was for
+ * @param modMailThreaduser The {@link User member} for which the {@link ModMailThread thread} was for
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
* @return A {@link CompletableFuture future} which completes after the messages have been logged
*/
@Transactional
- public CompletableFuture afterSuccessfulLog(Long modMailThreadId, Boolean notifyUser, Member modMailThreaduser, List undoActions) {
+ public CompletableFuture afterSuccessfulLog(Long modMailThreadId, Boolean notifyUser, User modMailThreaduser, List undoActions) {
log.debug("Mod mail logging for thread {} has completed. Starting post logging activities.", modMailThreadId);
Optional modMailThreadOpt = modMailThreadManagementService.getByIdOptional(modMailThreadId);
if(modMailThreadOpt.isPresent()) {
@@ -771,7 +785,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
HashMap closingMessage = new HashMap<>();
String defaultValue = templateService.renderSimpleTemplate("modmail_closing_user_message_description");
closingMessage.put("closingMessage", configService.getStringValue(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY, modMailThread.getServer().getId(), defaultValue));
- return messageService.sendEmbedToUser(modMailThreaduser.getUser(), "modmail_closing_user_message", closingMessage).thenAccept(message ->
+ return messageService.sendEmbedToUser(modMailThreaduser, "modmail_closing_user_message", closingMessage).thenCompose(message ->
self.deleteChannelAndClose(modMailThreadId, undoActions)
).exceptionally(throwable -> {
self.deleteChannelAndClose(modMailThreadId, undoActions);
@@ -1002,6 +1016,28 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
}
+ @Transactional
+ public CompletableFuture banUserFromAppealServer(Long mainServerId, Long userId, String reason) {
+ Long configuredAppealServerId = configService.getLongValue(ModMailFeatureConfig.MOD_MAIL_APPEAL_SERVER, mainServerId);
+ Guild appealGuild = guildService.getGuildById(configuredAppealServerId);
+ return banService.banUser(appealGuild, ServerUser.fromId(configuredAppealServerId, userId), Duration.ZERO, reason);
+ }
+
+ @Override
+ public CompletableFuture rejectAppeal(ModMailThread modMailThread, String reason, Member memberPerforming) {
+ ClosingContext context = ClosingContext
+ .builder()
+ .closingMember(memberPerforming)
+ .notifyUser(true)
+ .log(true)
+ .note(reason)
+ .build();
+ Long mainServerId = modMailThread.getServer().getId();
+ Long userToBanId = modMailThread.getUser().getUserReference().getId();
+ return closeModMailThread(modMailThread, context, new ArrayList<>())
+ .thenCompose((nul) -> self.banUserFromAppealServer(mainServerId, userToBanId , reason));
+ }
+
@PostConstruct
public void postConstruct() {
metricService.registerCounter(MODMAIL_THREAD_CREATED_COUNTER, "Mod mail threads created");
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/collection.xml b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/collection.xml
new file mode 100644
index 000000000..1bbc30fef
--- /dev/null
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/collection.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/command.xml b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/command.xml
new file mode 100644
index 000000000..ddced2699
--- /dev/null
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/command.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/data.xml b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/data.xml
new file mode 100644
index 000000000..e18fc4181
--- /dev/null
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/1.5.37/seedData/data.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/modMail-changeLog.xml b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/modMail-changeLog.xml
index 8aee5ff15..7148dbca8 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/modMail-changeLog.xml
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/migrations/modMail-changeLog.xml
@@ -3,4 +3,5 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
+
\ No newline at end of file
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/modmail-config.properties b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/modmail-config.properties
index 657a9c230..ba76cda53 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/modmail-config.properties
+++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/modmail-config.properties
@@ -21,4 +21,11 @@ abstracto.featureModes.threadContainer.enabled=false
abstracto.featureModes.threadMessage.featureName=modmail
abstracto.featureModes.threadMessage.mode=threadMessage
-abstracto.featureModes.threadMessage.enabled=true
\ No newline at end of file
+abstracto.featureModes.threadMessage.enabled=true
+
+abstracto.featureModes.modMailAppeals.featureName=modmail
+abstracto.featureModes.modMailAppeals.mode=modMailAppeals
+abstracto.featureModes.modMailAppeals.enabled=false
+
+abstracto.systemConfigs.modMailAppealServer.name=modMailAppealServer
+abstracto.systemConfigs.modMailAppealServer.longValue=0
\ No newline at end of file
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListenerTest.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListenerTest.java
deleted file mode 100644
index cdc1b7b73..000000000
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageDeletedListenerTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package dev.sheldan.abstracto.modmail.listener;
-
-import dev.sheldan.abstracto.core.models.cache.CachedMessage;
-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.models.listener.MessageDeletedModel;
-import dev.sheldan.abstracto.core.service.MemberService;
-import dev.sheldan.abstracto.core.service.MessageService;
-import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
-import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
-import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService;
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.User;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ModMailMessageDeletedListenerTest {
-
- @InjectMocks
- private ModMailMessageDeletedListener testUnit;
-
- @Mock
- private ModMailMessageManagementService modMailMessageManagementService;
-
- @Mock
- private MessageService messageService;
-
- @Mock
- private ModMailMessageDeletedListener self;
-
- @Mock
- private MemberService memberService;
-
- @Mock
- private CachedMessage deletedMessage;
-
- @Mock
- private ModMailMessage modMailMessage;
-
- @Mock
- private Member targetMember;
-
- @Mock
- private User targetUser;
-
- @Mock
- private AServer server;
-
- @Mock
- private AChannel channel;
-
- @Mock
- private MessageDeletedModel model;
-
- private static final Long DELETED_MESSAGE_ID = 4L;
- private static final Long CREATED_MESSAGE_ID_1 = 3L;
- private static final Long CREATED_MESSAGE_ID_2 = 5L;
- private static final Long USER_ID = 5L;
- private static final Long SERVER_ID = 6L;
- private static final Long CHANNEL_ID = 9L;
-
- @Test
- public void testDeleteOutSideOfThread() {
- when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.empty());
- when(model.getCachedMessage()).thenReturn(deletedMessage);
- testUnit.execute(model);
- verify(memberService, times(0)).getMemberInServerAsync(anyLong(), anyLong());
- }
-
- @Test
- public void testDeleteNonDuplicatedMessage() {
- when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- AUserInAServer targetUsInAServer = Mockito.mock(AUserInAServer.class);
- when(thread.getUser()).thenReturn(targetUsInAServer);
- when(thread.getChannel()).thenReturn(channel);
- when(thread.getServer()).thenReturn(server);
- AUser targetAUser = Mockito.mock(AUser.class);
- when(targetUsInAServer.getUserReference()).thenReturn(targetAUser);
- when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
- when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID_2);
- when(targetAUser.getId()).thenReturn(USER_ID);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- when(targetMember.getUser()).thenReturn(targetUser);
- when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
- when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null));
- when(model.getCachedMessage()).thenReturn(deletedMessage);
- when(model.getServerId()).thenReturn(SERVER_ID);
- testUnit.execute(model);
- verify(messageService, times(0)).deleteMessageInChannelInServer(eq(SERVER_ID), anyLong(), any());
- verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID);
- }
-
- @Test
- public void testDeleteDuplicatedMessage() {
- when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- AUserInAServer targetUsInAServer = Mockito.mock(AUserInAServer.class);
- when(thread.getUser()).thenReturn(targetUsInAServer);
- when(thread.getChannel()).thenReturn(channel);
- when(thread.getServer()).thenReturn(server);
- when(server.getId()).thenReturn(SERVER_ID);
- when(channel.getId()).thenReturn(CHANNEL_ID);
- AUser targetAUser = Mockito.mock(AUser.class);
- when(targetUsInAServer.getUserReference()).thenReturn(targetAUser);
- when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID_1);
- when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID_2);
- when(targetAUser.getId()).thenReturn(USER_ID);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- when(targetMember.getUser()).thenReturn(targetUser);
- when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
- when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null));
- when(messageService.deleteMessageInChannelInServer(SERVER_ID, CHANNEL_ID, CREATED_MESSAGE_ID_1)).thenReturn(CompletableFuture.completedFuture(null));
- when(model.getServerId()).thenReturn(SERVER_ID);
- when(model.getCachedMessage()).thenReturn(deletedMessage);
- testUnit.execute(model);
- verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID);
- }
-
- @Test
- public void removeMessageFromThread() {
- when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- testUnit.removeMessageFromThread(DELETED_MESSAGE_ID);
- verify(modMailMessageManagementService, times(1)).deleteMessageFromThread(modMailMessage);
- }
-}
\ No newline at end of file
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListenerTest.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListenerTest.java
deleted file mode 100644
index 9de139e9a..000000000
--- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/test/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageEditedListenerTest.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package dev.sheldan.abstracto.modmail.listener;
-
-import dev.sheldan.abstracto.core.command.config.Parameters;
-import dev.sheldan.abstracto.core.command.service.CommandRegistry;
-import dev.sheldan.abstracto.core.command.service.CommandService;
-import dev.sheldan.abstracto.core.models.cache.CachedMessage;
-import dev.sheldan.abstracto.core.models.database.AChannel;
-import dev.sheldan.abstracto.core.models.database.AUser;
-import dev.sheldan.abstracto.core.models.database.AUserInAServer;
-import dev.sheldan.abstracto.core.models.listener.MessageUpdatedModel;
-import dev.sheldan.abstracto.core.service.ChannelService;
-import dev.sheldan.abstracto.core.service.MemberService;
-import dev.sheldan.abstracto.core.service.MessageService;
-import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
-import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
-import dev.sheldan.abstracto.modmail.model.template.ModMailModeratorReplyModel;
-import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
-import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
-import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService;
-import dev.sheldan.abstracto.core.templating.model.MessageToSend;
-import dev.sheldan.abstracto.core.templating.service.TemplateService;
-import net.dv8tion.jda.api.entities.Guild;
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.User;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.*;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-
-import static dev.sheldan.abstracto.modmail.listener.ModMailMessageEditedListener.DEFAULT_COMMAND_FOR_MODMAIL_EDIT;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ModMailMessageEditedListenerTest {
-
- @InjectMocks
- private ModMailMessageEditedListener testUnit;
-
- @Mock
- private ModMailThreadService modMailThreadService;
-
- @Mock
- private ModMailMessageManagementService modMailMessageManagementService;
-
- @Mock
- private CommandRegistry commandRegistry;
-
- @Mock
- private CommandService commandService;
-
- @Mock
- private MemberService memberService;
-
- @Mock
- private TemplateService templateService;
-
- @Mock
- private ChannelService channelService;
-
- @Mock
- private MessageService messageService;
-
- @Mock
- private ModMailMessageEditedListener self;
-
- @Mock
- private CachedMessage messageBefore;
-
- @Mock
- private Message messageAfter;
-
- @Mock
- private Message loadedMessage;
-
- @Mock
- private ModMailMessage modMailMessage;
-
- @Mock
- private Parameters parsedParameters;
-
- @Mock
- private Member targetMember;
-
- @Mock
- private User targetUser;
-
- @Mock
- private MessageToSend messageToSend;
-
- @Mock
- private Member authorMember;
-
- @Mock
- private Guild guild;
-
- @Captor
- private ArgumentCaptor replyModelArgumentCaptor;
-
- @Mock
- private MessageUpdatedModel model;
-
- private static final Long CHANNEL_ID = 5L;
- private static final Long MESSAGE_ID = 6L;
- private static final Long CREATED_MESSAGE_ID = 10L;
- private static final String NEW_COMMAND_PART = "editedText";
- private static final String NEW_PARAM = "param";
- private static final String NEW_CONTENT = NEW_COMMAND_PART + " " + NEW_PARAM;
- private static final Long SERVER_ID = 4L;
- private static final Long USER_ID = 3L;
- private static final Long AUTHOR_USER_ID = 9L;
-
-
- @Test
- public void testEditOutsideModMailThread() {
- when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(false);
- when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
- when(model.getAfter()).thenReturn(messageAfter);
- when(model.getBefore()).thenReturn(messageBefore);
- testUnit.execute(model);
- verify(modMailMessageManagementService, times(0)).getByMessageIdOptional(anyLong());
- }
-
-
- @Test
- public void testEditMessageWithCorrectCommand() {
- when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
- when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
- when(model.getBefore()).thenReturn(messageBefore);
- when(model.getAfter()).thenReturn(messageAfter);
- when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.empty());
- when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
- when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
- when(messageBefore.getServerId()).thenReturn(SERVER_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- AUserInAServer targetUsInAServer = Mockito.mock(AUserInAServer.class);
- when(thread.getUser()).thenReturn(targetUsInAServer);
- AUser targetUser = Mockito.mock(AUser.class);
- when(targetUsInAServer.getUserReference()).thenReturn(targetUser);
- when(targetUser.getId()).thenReturn(USER_ID);
- AUserInAServer authorUserInAServer = Mockito.mock(AUserInAServer.class);
- when(modMailMessage.getAuthor()).thenReturn(authorUserInAServer);
- AUser authorUser = Mockito.mock(AUser.class);
- when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
- when(authorUserInAServer.getUserReference()).thenReturn(authorUser);
- when(messageAfter.getContentStripped()).thenReturn(NEW_CONTENT);
- when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART);
- when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(true);
- when(commandService.getParametersForCommand(NEW_COMMAND_PART, messageAfter)).thenReturn(CompletableFuture.completedFuture(parsedParameters));
- when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
- when(memberService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
- when(model.getAfter()).thenReturn(messageAfter);
- when(model.getBefore()).thenReturn(messageBefore);
- testUnit.execute(model);
- verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
- }
-
- @Test
- public void testEditMessageWithInCorrectCommand() {
- when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
- when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
- when(messageBefore.getServerId()).thenReturn(SERVER_ID);
- when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
- when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- AUserInAServer aUserInAServer = Mockito.mock(AUserInAServer.class);
- when(thread.getUser()).thenReturn(aUserInAServer);
- AUser user = Mockito.mock(AUser.class);
- when(aUserInAServer.getUserReference()).thenReturn(user);
- when(user.getId()).thenReturn(USER_ID);
- AUserInAServer authorUserInAServer = Mockito.mock(AUserInAServer.class);
- when(modMailMessage.getAuthor()).thenReturn(authorUserInAServer);
- AUser authorUser = Mockito.mock(AUser.class);
- when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
- when(authorUserInAServer.getUserReference()).thenReturn(authorUser);
- when(messageAfter.getContentStripped()).thenReturn(NEW_CONTENT);
- when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART);
- when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(false);
- when(commandService.getParametersForCommand(DEFAULT_COMMAND_FOR_MODMAIL_EDIT, messageAfter)).thenReturn(CompletableFuture.completedFuture(parsedParameters));
- when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
- when(memberService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
- when(model.getAfter()).thenReturn(messageAfter);
- when(model.getBefore()).thenReturn(messageBefore);
- testUnit.execute(model);
- verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
- }
-
- @Test
- public void testUpdateAnonymousMessageInThreadNotSentToModMailThreadChannel() {
- when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- when(modMailMessage.getAnonymous()).thenReturn(true);
- when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
- when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- when(targetMember.getUser()).thenReturn(targetUser);
- when(authorMember.getGuild()).thenReturn(guild);
- when(guild.getIdLong()).thenReturn(SERVER_ID);
- when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
- when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
- testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
- verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong());
- verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
- Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
- }
-
- @Test
- public void testUpdateAnonymousMessageInThreadAlsoSendToModMailThreadChannel() {
- when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- when(modMailMessage.getAnonymous()).thenReturn(true);
- when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
- when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- when(targetMember.getUser()).thenReturn(targetUser);
- when(authorMember.getGuild()).thenReturn(guild);
- when(guild.getIdLong()).thenReturn(SERVER_ID);
- AChannel channel = Mockito.mock(AChannel.class);
- when(thread.getChannel()).thenReturn(channel);
- when(channel.getId()).thenReturn(CHANNEL_ID);
- when(guild.getIdLong()).thenReturn(SERVER_ID);
- when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
- when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
- testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
- verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID));
- verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
- Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
- }
-
- @Test
- public void testUpdateMessageInThreadNotDuplicated() {
- when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- when(modMailMessage.getAnonymous()).thenReturn(false);
- when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
- when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- when(targetMember.getUser()).thenReturn(targetUser);
- when(authorMember.getGuild()).thenReturn(guild);
- when(guild.getIdLong()).thenReturn(SERVER_ID);
- when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
- when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
- testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
- verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong());
- verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
- Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous());
- }
-
- @Test
- public void testUpdateMessageInThreadDuplicated() {
- when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
- when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
- when(modMailMessage.getAnonymous()).thenReturn(false);
- when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
- when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
- ModMailThread thread = Mockito.mock(ModMailThread.class);
- when(modMailMessage.getThreadReference()).thenReturn(thread);
- when(targetMember.getUser()).thenReturn(targetUser);
- when(authorMember.getGuild()).thenReturn(guild);
- when(guild.getIdLong()).thenReturn(SERVER_ID);
- AChannel channel = Mockito.mock(AChannel.class);
- when(thread.getChannel()).thenReturn(channel);
- when(channel.getId()).thenReturn(CHANNEL_ID);
- when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
- when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
- testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
- verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID));
- verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
- Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous());
- }
-}
\ No newline at end of file
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeatureConfig.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeatureConfig.java
index e980d8e02..e66d6742a 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeatureConfig.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeatureConfig.java
@@ -21,6 +21,7 @@ import java.util.List;
public class ModMailFeatureConfig implements FeatureConfig {
public static final String MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY = "modMailClosingText";
+ public static final String MOD_MAIL_APPEAL_SERVER = "modMailAppealServer";
@Autowired
private ModMailFeatureValidator modMailFeatureValidator;
@@ -34,27 +35,33 @@ public class ModMailFeatureConfig implements FeatureConfig {
@Override
public List getRequiredPostTargets() {
- return Arrays.asList(ModMailPostTargets.MOD_MAIL_PING, ModMailPostTargets.MOD_MAIL_LOG, ModMailPostTargets.MOD_MAIL_CONTAINER);
+ return List.of(ModMailPostTargets.MOD_MAIL_PING,
+ ModMailPostTargets.MOD_MAIL_LOG,
+ ModMailPostTargets.MOD_MAIL_CONTAINER);
}
@Override
public List getAdditionalFeatureValidators() {
- return Arrays.asList(modMailFeatureValidator);
+ return List.of(modMailFeatureValidator);
}
@Override
public List getRequiredEmotes() {
- return Arrays.asList("readReaction");
+ return List.of("readReaction");
}
@Override
public List getAvailableModes() {
- return Arrays.asList(ModMailMode.LOGGING, ModMailMode.SEPARATE_MESSAGE, ModMailMode.THREAD_CONTAINER);
+ return List.of(ModMailMode.LOGGING,
+ ModMailMode.SEPARATE_MESSAGE,
+ ModMailMode.THREAD_CONTAINER,
+ ModMailMode.MOD_MAIL_APPEALS
+ );
}
@Override
public List getRequiredSystemConfigKeys() {
- return Arrays.asList(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY);
+ return List.of(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY, MOD_MAIL_APPEAL_SERVER);
}
@Override
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java
index 048bf10fc..4d70cdea0 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java
@@ -9,7 +9,10 @@ import lombok.Getter;
*/
@Getter
public enum ModMailMode implements FeatureMode {
- LOGGING("log"), SEPARATE_MESSAGE("threadMessage"), THREAD_CONTAINER("threadContainer");
+ LOGGING("log"),
+ SEPARATE_MESSAGE("threadMessage"),
+ THREAD_CONTAINER("threadContainer"),
+ MOD_MAIL_APPEALS("modMailAppeals");
private final String key;
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/ClosingContext.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/ClosingContext.java
index 2f49f775e..96111aa86 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/ClosingContext.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/ClosingContext.java
@@ -13,6 +13,5 @@ public class ClosingContext {
private Boolean notifyUser;
private Boolean log;
private Member closingMember;
- private Channel channel;
private String note;
}
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ContactNotificationModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ContactNotificationModel.java
index 6d1ce22cb..51b228269 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ContactNotificationModel.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ContactNotificationModel.java
@@ -1,15 +1,15 @@
package dev.sheldan.abstracto.modmail.model.template;
+import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
-import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
@Getter
@Setter
@Builder
public class ContactNotificationModel {
- private Member targetMember;
+ private UserDisplay userDisplay;
private MessageChannel createdChannel;
}
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailModeratorReplyModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailModeratorReplyModel.java
index 8a2e5763c..7205e0659 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailModeratorReplyModel.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailModeratorReplyModel.java
@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.modmail.model.template;
-import dev.sheldan.abstracto.core.models.FullUserInServer;
+import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import lombok.Builder;
import lombok.Getter;
@@ -18,10 +18,7 @@ import java.util.Map;
@Setter
@Builder
public class ModMailModeratorReplyModel {
- /**
- * A {@link FullUserInServer} reference representing the user the thread is about. The member attribute is null, if the user left the guild
- */
- private FullUserInServer threadUser;
+ private UserDisplay userDisplay;
/**
* The staff {@link Member} which replied to the thread, be it anonymously or normal.
*/
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailNotificationModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailNotificationModel.java
index 2948ca085..7e595efb1 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailNotificationModel.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailNotificationModel.java
@@ -1,13 +1,12 @@
package dev.sheldan.abstracto.modmail.model.template;
-import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.context.ServerContext;
+import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import dev.sheldan.abstracto.modmail.model.database.ModMailRole;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
-import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import java.util.List;
@@ -24,10 +23,7 @@ public class ModMailNotificationModel extends ServerContext {
* The created {@link ModMailThread} which was just created
*/
private ModMailThread modMailThread;
- /**
- * The {@link FullUserInServer} for which this thread is about
- */
- private Member member;
+ private UserDisplay userDisplay;
/**
* A list of roles which will be notified upon creation of the mod mail thread.
*/
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailThreaderHeader.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailThreaderHeader.java
index 4728987e2..605f2bade 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailThreaderHeader.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailThreaderHeader.java
@@ -1,12 +1,10 @@
package dev.sheldan.abstracto.modmail.model.template;
+import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
-import net.dv8tion.jda.api.entities.Member;
-
-import java.time.Instant;
/**
* This is the model used when a new mod mail thread is opened and a message containing some information about the user
@@ -16,16 +14,12 @@ import java.time.Instant;
@Setter
@Builder
public class ModMailThreaderHeader {
- /**
- * A {@link Member} instance to retrieve information from
- */
- private Member member;
+ private UserDisplay userDisplay;
/**
* The latest {@link ModMailThread}, before the current opened one. This is null if there is no closed mod mail thread
* for the user
*/
private ModMailThread latestModMailThread;
- private Instant memberJoinDate;
/**
* The amount of previous mod mail thread the user has.
*/
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailUserReplyModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailUserReplyModel.java
index 95aa67559..169db4b4e 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailUserReplyModel.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailUserReplyModel.java
@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.modmail.model.template;
+import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@@ -16,10 +17,7 @@ import java.util.Map;
@Setter
@Builder
public class ModMailUserReplyModel {
- /**
- * The {@link Member} from which the message is and whose mod mail thread it is
- */
- private Member member;
+ private UserDisplay userDisplay;
/**
* The {@link Message} which was posted, which contains all the possible information
*/
diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java
index 4fa881337..a684d8156 100644
--- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java
+++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java
@@ -22,16 +22,16 @@ public interface ModMailThreadService {
* Creates a new mod mail thread for the given user. including: the {@link net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel}
* in the appropriate {@link net.dv8tion.jda.api.entities.channel.concrete.Category} and calls the methods responsible for storing
* the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread}
- * @param member The {@link AUserInAServer} to create the mod mail thread for
+ * @param user The {@link User} to create the mod mail thread for
* @param initialMessage The initial message sparking this mod mail thread, null in case it was created by a command
* @param userInitiated Whether or not the mod mail thread was initiated by a user
* @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.
* @return A {@link CompletableFuture future} which completes when the modmail thread is set up
*/
- CompletableFuture createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List undoActions);
+ CompletableFuture createModMailThreadForUser(User user, Guild guild, Message initialMessage, boolean userInitiated, List undoActions);
- CompletableFuture sendContactNotification(Member member, MessageChannel createdMessageChannel, MessageChannel feedBackChannel);
- CompletableFuture sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook);
+ CompletableFuture sendContactNotification(User user, MessageChannel createdMessageChannel, MessageChannel feedBackChannel);
+ CompletableFuture sendContactNotification(User user, MessageChannel createdMessageChannel, InteractionHook interactionHook);
/**
* Changes the configuration value of the category used to create mod mail threads to the given ID.
@@ -68,10 +68,11 @@ 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 targetMember The {@link Member} the {@link ModMailThread} is about.
+ * @param targetUser The {@link User} the {@link ModMailThread} is about.
+ * @param guild The guild the reply is created in
* @return A {@link CompletableFuture future} which completes when the message has been relayed to the DM
*/
- CompletableFuture loadExecutingMemberAndRelay(Long threadId, String text, Message message, boolean anonymous, Member targetMember);
+ CompletableFuture loadExecutingMemberAndRelay(Long threadId, String text, Message message, boolean anonymous, User targetUser, Guild guild);
/**
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel} associated with the mod mail thread,
@@ -98,4 +99,6 @@ public interface ModMailThreadService {
boolean isModMailThread(AChannel channel);
boolean isModMailThread(Long channelId);
+
+ CompletableFuture rejectAppeal(ModMailThread modMailThread, String reason, Member memberPerforming);
}
diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/UserDisplay.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/UserDisplay.java
index 861848d6c..85c374981 100644
--- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/UserDisplay.java
+++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/UserDisplay.java
@@ -15,6 +15,8 @@ public class UserDisplay {
private String userMention;
private String discriminator;
private String name;
+ private String avatarUrl;
+ // TODO add avatar, only available from user
public static UserDisplay fromUser(User user) {
return UserDisplay
@@ -23,6 +25,7 @@ public class UserDisplay {
.name(user.getEffectiveName())
.discriminator(user.getDiscriminator())
.id(user.getIdLong())
+ .avatarUrl(user.getEffectiveAvatarUrl())
.build();
}