mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-03-27 14:23:56 +00:00
[AB-96] adding ability to edit/delete modmail messages via editing/deleting the original message causing the message,
adding featuremode to modmail to define whether or not there is a separate message posted to the mod mail thread, to see it easier, renaming modmail related tables to singular, adding some necessary methods (caching) to all entities
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package dev.sheldan.abstracto.modmail.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.listener.MessageDeletedListener;
|
||||
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
|
||||
import dev.sheldan.abstracto.core.models.GuildChannelMember;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.service.BotService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ModMailMessageDeletedListener implements MessageDeletedListener {
|
||||
|
||||
@Autowired
|
||||
private ModMailMessageManagementService modMailMessageManagementService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Autowired
|
||||
private ModMailMessageDeletedListener self;
|
||||
|
||||
@Autowired
|
||||
private BotService botService;
|
||||
|
||||
@Override
|
||||
public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) {
|
||||
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageBefore.getMessageId());
|
||||
messageOptional.ifPresent(modMailMessage -> {
|
||||
ModMailThread thread = modMailMessage.getThreadReference();
|
||||
Long dmMessageId = modMailMessage.getCreatedMessageInDM();
|
||||
boolean hasMessageInChannel = modMailMessage.getCreatedMessageInChannel() != null;
|
||||
Long channelMessage = modMailMessage.getCreatedMessageInChannel();
|
||||
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);
|
||||
botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId()).thenAccept(member -> {
|
||||
CompletableFuture<Void> dmDeletePromise = messageService.deleteMessageInChannelWithUser(member.getUser(), dmMessageId);
|
||||
CompletableFuture<Void> channelDeletePromise;
|
||||
if(hasMessageInChannel) {
|
||||
channelDeletePromise = messageService.deleteMessageInChannelInServer(serverId, channelId, channelMessage);
|
||||
} else {
|
||||
channelDeletePromise = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
CompletableFuture.allOf(dmDeletePromise, channelDeletePromise).thenAccept(unused ->
|
||||
self.removeMessageFromThread(messageBefore.getMessageId())
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void removeMessageFromThread(Long messageId) {
|
||||
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageId);
|
||||
messageOptional.ifPresent(modMailMessage ->
|
||||
modMailMessageManagementService.deleteMessageFromThread(modMailMessage)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureEnum getFeature() {
|
||||
return ModMailFeatures.MOD_MAIL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
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.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.listener.MessageTextUpdatedListener;
|
||||
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.service.BotService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.models.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.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.templating.service.TemplateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ModMailMessageEditedListener implements MessageTextUpdatedListener {
|
||||
|
||||
public static final String DEFAULT_COMMAND_FOR_MODMAIL_EDIT = "reply";
|
||||
@Autowired
|
||||
private ModMailMessageManagementService modMailMessageManagementService;
|
||||
|
||||
@Autowired
|
||||
private CommandService commandService;
|
||||
|
||||
@Autowired
|
||||
private BotService botService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ModMailMessageEditedListener self;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Autowired
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadService modMailThreadService;
|
||||
|
||||
@Override
|
||||
public void execute(CachedMessage messageBefore, Message messageAfter) {
|
||||
if(!modMailThreadService.isModMailThread(messageBefore.getChannelId())) {
|
||||
return;
|
||||
}
|
||||
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageBefore.getMessageId());
|
||||
messageOptional.ifPresent(modMailMessage -> {
|
||||
log.info("Editing send message {} in channel {} in mod mail thread {} in server {}.", messageBefore.getMessageId(), messageBefore.getChannelId(), modMailMessage.getThreadReference().getId(), messageBefore.getServerId());
|
||||
String contentStripped = messageAfter.getContentRaw();
|
||||
String commandName = commandRegistry.getCommandName(contentStripped.substring(0, contentStripped.indexOf(" ")), messageBefore.getServerId());
|
||||
if(!commandService.doesCommandExist(commandName)) {
|
||||
commandName = DEFAULT_COMMAND_FOR_MODMAIL_EDIT;
|
||||
log.info("Edit did not contain the original command to retrieve the parameters for. Resulting to {}.", DEFAULT_COMMAND_FOR_MODMAIL_EDIT);
|
||||
}
|
||||
CompletableFuture<Parameters> parameterParseFuture = commandService.getParametersForCommand(commandName, messageAfter);
|
||||
CompletableFuture<Member> loadTargetUser = botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId());
|
||||
CompletableFuture<Member> loadEditingUser = botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getAuthor().getUserReference().getId());
|
||||
CompletableFuture.allOf(parameterParseFuture, loadTargetUser, loadEditingUser).thenAccept(unused ->
|
||||
self.updateMessageInThread(messageAfter, parameterParseFuture.join(), loadTargetUser.join(), loadEditingUser.join())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateMessageInThread(Message messageAfter, Parameters parameters, Member targetMember, Member editingUser) {
|
||||
String newText = (String) parameters.getParameters().get(0);
|
||||
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageAfter.getIdLong());
|
||||
messageOptional.ifPresent(modMailMessage -> {
|
||||
FullUserInServer fullThreadUser = FullUserInServer
|
||||
.builder()
|
||||
.aUserInAServer(modMailMessage.getThreadReference().getUser())
|
||||
.member(targetMember)
|
||||
.build();
|
||||
ModMailModeratorReplyModel.ModMailModeratorReplyModelBuilder modMailModeratorReplyModelBuilder = ModMailModeratorReplyModel
|
||||
.builder()
|
||||
.text(newText)
|
||||
.modMailThread(modMailMessage.getThreadReference())
|
||||
.postedMessage(messageAfter)
|
||||
.anonymous(modMailMessage.getAnonymous())
|
||||
.threadUser(fullThreadUser);
|
||||
if(modMailMessage.getAnonymous()) {
|
||||
modMailModeratorReplyModelBuilder.moderator(botService.getBotInGuild(modMailMessage.getThreadReference().getServer()));
|
||||
} else {
|
||||
modMailModeratorReplyModelBuilder.moderator(editingUser);
|
||||
}
|
||||
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel);
|
||||
Long threadId = modMailMessage.getThreadReference().getId();
|
||||
long serverId = editingUser.getGuild().getIdLong();
|
||||
if(modMailMessage.getCreatedMessageInChannel() != null) {
|
||||
AChannel channel = modMailMessage.getThreadReference().getChannel();
|
||||
log.trace("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.trace("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());
|
||||
});
|
||||
|
||||
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.",
|
||||
messageAfter.getIdLong(), editingUser.getIdLong(), messageAfter.getChannel().getIdLong(), messageAfter.getGuild().getIdLong(), targetMember.getIdLong());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureEnum getFeature() {
|
||||
return ModMailFeatures.MOD_MAIL;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.persistence.QueryHint;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Repository to manage the stored {@link ModMailMessage} instances
|
||||
@@ -16,4 +17,7 @@ import java.util.List;
|
||||
public interface ModMailMessageRepository extends JpaRepository<ModMailMessage, Long> {
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
List<ModMailMessage> findByThreadReference(ModMailThread modMailThread);
|
||||
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
Optional<ModMailMessage> findByMessageId(Long messageId);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.Optional;
|
||||
public interface ModMailThreadRepository extends JpaRepository<ModMailThread, Long> {
|
||||
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
ModMailThread findByChannel(AChannel channel);
|
||||
Optional<ModMailThread> findByChannel(AChannel channel);
|
||||
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
List<ModMailThread> findByUser(AUserInAServer aUserInAServer);
|
||||
|
||||
@@ -38,7 +38,6 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
modMailMessages.forEach(modMailMessage -> {
|
||||
ServerChannelMessageUser.ServerChannelMessageUserBuilder serverChannelMessageBuilder = ServerChannelMessageUser
|
||||
.builder()
|
||||
.messageId(modMailMessage.getMessageId())
|
||||
.userId(modMailMessage.getAuthor().getUserReference().getId())
|
||||
.serverId(thread.getServer().getId());
|
||||
// if its not from a private chat, we need to set channel ID in order to fetch the data
|
||||
@@ -46,6 +45,9 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
log.trace("Message {} was from DM.", modMailMessage.getMessageId());
|
||||
serverChannelMessageBuilder
|
||||
.channelId(modMailMessage.getThreadReference().getChannel().getId());
|
||||
serverChannelMessageBuilder.messageId(modMailMessage.getCreatedMessageInChannel());
|
||||
} else {
|
||||
serverChannelMessageBuilder.messageId(modMailMessage.getCreatedMessageInDM());
|
||||
}
|
||||
messageIds.add(serverChannelMessageBuilder.build());
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.modmail.config.*;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailCategoryIdException;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadChannelNotFound;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadNotFoundException;
|
||||
import dev.sheldan.abstracto.modmail.models.dto.LoadedModmailThreadMessageList;
|
||||
import dev.sheldan.abstracto.modmail.models.database.*;
|
||||
@@ -57,6 +58,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* The template key used for default mod mail exceptions
|
||||
*/
|
||||
public static final String MODMAIL_EXCEPTION_GENERIC_TEMPLATE = "modmail_exception_generic";
|
||||
public static final String MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY = "modmail_staff_message";
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
@@ -184,7 +186,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
ModMailThread thread = createThreadObject(channel, aUserInAServer);
|
||||
if(initialMessage != null) {
|
||||
log.trace("Adding initial message {} to modmail thread in channel {}.", initialMessage.getId(), channel.getId());
|
||||
modMailMessageManagementService.addMessageToThread(thread, sendMessage, aUserInAServer, false, false);
|
||||
modMailMessageManagementService.addMessageToThread(thread, null, sendMessage, initialMessage, aUserInAServer, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,22 +329,22 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> relayMessageToModMailThread(ModMailThread modMailThread, Message message, List<UndoActionInstance> undoActions) {
|
||||
public CompletableFuture<Message> relayMessageToModMailThread(ModMailThread modMailThread, Message messageFromUser, List<UndoActionInstance> undoActions) {
|
||||
Long serverId = modMailThread.getServer().getId();
|
||||
Long channelId = modMailThread.getChannel().getId();
|
||||
Long modmailThreadId = modMailThread.getId();
|
||||
log.trace("Relaying message {} to modmail thread {} for user {} to server {}.", message.getId(), modMailThread.getId(), message.getAuthor().getIdLong(), modMailThread.getServer().getId());
|
||||
return botService.getMemberInServerAsync(modMailThread.getServer().getId(), message.getAuthor().getIdLong()).thenCompose(member -> {
|
||||
log.trace("Relaying message {} to modmail thread {} for user {} to server {}.", messageFromUser.getId(), modMailThread.getId(), messageFromUser.getAuthor().getIdLong(), modMailThread.getServer().getId());
|
||||
return botService.getMemberInServerAsync(modMailThread.getServer().getId(), messageFromUser.getAuthor().getIdLong()).thenCompose(member -> {
|
||||
Optional<TextChannel> textChannelFromServer = botService.getTextChannelFromServerOptional(serverId, channelId);
|
||||
if(textChannelFromServer.isPresent()) {
|
||||
TextChannel textChannel = textChannelFromServer.get();
|
||||
return self.sendUserReply(textChannel, modmailThreadId, message, member, true);
|
||||
return self.sendUserReply(textChannel, modmailThreadId, messageFromUser, member, true);
|
||||
} else {
|
||||
log.warn("Closing modmail thread {}, because it seems the channel {} in server {} got deleted.", modmailThreadId, channelId, serverId);
|
||||
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
|
||||
// close the existing one, so the user can start a new one
|
||||
self.closeModMailThreadInDb(modmailThreadId);
|
||||
return message.getChannel().sendMessage(templateService.renderTemplate("modmail_failed_to_forward_message", new Object())).submit();
|
||||
return messageFromUser.getChannel().sendMessage(templateService.renderTemplate("modmail_failed_to_forward_message", new Object())).submit();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -354,12 +356,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* side.
|
||||
* @param textChannel The {@link TextChannel} 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 message The received message from the user
|
||||
* @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 or not the modmail thread already exists and is persisted.
|
||||
* @return A {@link CompletableFuture} which resolves when the post processing of the message is completed (adding read notification, and storing messageIDs)
|
||||
*/
|
||||
public CompletableFuture<Message> sendUserReply(TextChannel textChannel, Long modMailThreadId, Message message, Member member, boolean modMailThreadExists) {
|
||||
public CompletableFuture<Message> sendUserReply(TextChannel textChannel, Long modMailThreadId, Message messageFromUser, Member member, boolean modMailThreadExists) {
|
||||
List<CompletableFuture<Member>> subscriberMemberFutures = new ArrayList<>();
|
||||
if(modMailThreadExists) {
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
|
||||
@@ -378,7 +380,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
List<FullUserInServer> subscribers = new ArrayList<>();
|
||||
ModMailUserReplyModel modMailUserReplyModel = ModMailUserReplyModel
|
||||
.builder()
|
||||
.postedMessage(message)
|
||||
.postedMessage(messageFromUser)
|
||||
.member(member)
|
||||
.subscribers(subscribers)
|
||||
.build();
|
||||
@@ -387,11 +389,11 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]))
|
||||
.thenCompose(aVoid -> {
|
||||
log.trace("Adding read reaction to initial message for mod mail thread in channel {}.", textChannel.getGuild().getId());
|
||||
return messageService.addReactionToMessageWithFuture("readReaction", textChannel.getGuild().getIdLong(), message);
|
||||
return messageService.addReactionToMessageWithFuture("readReaction", textChannel.getGuild().getIdLong(), messageFromUser);
|
||||
})
|
||||
.thenApply(aVoid -> {
|
||||
if(modMailThreadExists) {
|
||||
self.postProcessSendMessages(textChannel, completableFutures.get(0).join());
|
||||
self.postProcessSendMessages(textChannel, completableFutures.get(0).join(), messageFromUser);
|
||||
}
|
||||
return completableFutures.get(0).join();
|
||||
});
|
||||
@@ -403,26 +405,28 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
/**
|
||||
* This message handles the post processing of the messages received by the user. This includes: saving the messageIDs
|
||||
* in the database, updating the state of the {@link ModMailThread} and adding the read reaction to the user message
|
||||
* @param message The actual {@link Message} instance received from the user.
|
||||
* @param textChannel The channel in which the message
|
||||
* @param messageInModMailThread The actual {@link Message} instance which was sent to the mod mail thread
|
||||
* @param messageFromUser The {@link Message} object which was sent from the user
|
||||
*/
|
||||
@Transactional
|
||||
public void postProcessSendMessages(TextChannel textChannel, Message message) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getByIdOptional(textChannel.getIdLong());
|
||||
public void postProcessSendMessages(TextChannel textChannel, Message messageInModMailThread, Message messageFromUser) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getByChannelIdOptional(textChannel.getIdLong());
|
||||
if(modMailThreadOpt.isPresent()) {
|
||||
ModMailThread modMailThread = modMailThreadOpt.get();
|
||||
log.trace("Adding message {} sent from user to modmail thread {} and setting status to {}.", message.getId(), modMailThread.getId(), ModMailThreadState.USER_REPLIED);
|
||||
modMailMessageManagementService.addMessageToThread(modMailThread, message, modMailThread.getUser(), false, false);
|
||||
log.trace("Adding created message {} based on messeage {} sent from user to modmail thread {} and setting status to {}.", messageInModMailThread.getId(), messageFromUser.getId(), modMailThread.getId(), ModMailThreadState.USER_REPLIED);
|
||||
modMailMessageManagementService.addMessageToThread(modMailThread, null, messageInModMailThread, messageFromUser, modMailThread.getUser(), false, false);
|
||||
// update the state of the thread
|
||||
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.USER_REPLIED);
|
||||
} else {
|
||||
throw new ModMailThreadNotFoundException(textChannel.getIdLong());
|
||||
throw new ModMailThreadChannelNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message message, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions, Member targetMember) {
|
||||
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", message.getId(), targetMember.getId(), modmailThreadId, targetMember.getGuild().getId());
|
||||
AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember());
|
||||
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions, Member targetMember) {
|
||||
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), targetMember.getId(), modmailThreadId, targetMember.getGuild().getId());
|
||||
AUserInAServer moderator = userInServerManagementService.loadUser(replyCommandMessage.getMember());
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
|
||||
FullUserInServer fullThreadUser = FullUserInServer
|
||||
.builder()
|
||||
@@ -433,7 +437,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
.builder()
|
||||
.text(text)
|
||||
.modMailThread(modMailThread)
|
||||
.postedMessage(message)
|
||||
.postedMessage(replyCommandMessage)
|
||||
.anonymous(anonymous)
|
||||
.threadUser(fullThreadUser);
|
||||
if(anonymous) {
|
||||
@@ -445,9 +449,16 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
modMailModeratorReplyModelBuilder.moderator(moderatorMember);
|
||||
}
|
||||
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
|
||||
CompletableFuture<Message> future = messageService.sendEmbedToUserWithMessage(targetMember.getUser(), "modmail_staff_message", modMailUserReplyModel);
|
||||
return future.thenAccept(sendMessage ->
|
||||
self.saveSendMessagesAndUpdateState(modmailThreadId, anonymous, moderator, sendMessage)
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel);
|
||||
CompletableFuture<Message> future = messageService.sendMessageToSendToUser(targetMember.getUser(), messageToSend);
|
||||
CompletableFuture<Message> sameThreadMessageFuture;
|
||||
if(featureModeService.featureModeActive(ModMailFeatures.MOD_MAIL, modMailThread.getServer(), ModMailMode.SEPARATE_MESSAGE)) {
|
||||
sameThreadMessageFuture = channelService.sendMessageToSendToAChannel(messageToSend, modMailThread.getChannel()).get(0);
|
||||
} else {
|
||||
sameThreadMessageFuture = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
return CompletableFuture.allOf(future, sameThreadMessageFuture).thenAccept(avoid ->
|
||||
self.saveSendMessagesAndUpdateState(modmailThreadId, anonymous, moderator, future.join(), replyCommandMessage, sameThreadMessageFuture.join())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -481,6 +492,17 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModMailThread(AChannel channel) {
|
||||
return modMailThreadManagementService.getByChannelOptional(channel).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModMailThread(Long channelId) {
|
||||
AChannel channel = channelManagementService.loadChannel(channelId);
|
||||
return modMailThreadManagementService.getByChannelOptional(channel).isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes the actively loaded futures, calls the method responsible for logging the messages, and calls the method
|
||||
* after the logging has been done.
|
||||
@@ -603,7 +625,13 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
log.info("Logging message {} in modmail thread {}.", loadedMessage.getId(), modMailThreadId);
|
||||
ModMailMessage modmailMessage = modMailThread.getMessages()
|
||||
.stream()
|
||||
.filter(modMailMessage -> modMailMessage.getMessageId().equals(loadedMessage.getIdLong()))
|
||||
.filter(modMailMessage -> {
|
||||
if(modMailMessage.getDmChannel()) {
|
||||
return modMailMessage.getCreatedMessageInDM().equals(loadedMessage.getIdLong());
|
||||
} else {
|
||||
return modMailMessage.getCreatedMessageInChannel().equals(loadedMessage.getIdLong());
|
||||
}
|
||||
})
|
||||
.findFirst().orElseThrow(() -> new AbstractoRunTimeException("Could not find desired message in list of messages in thread. This should not happen, as we just retrieved them from the same place."));
|
||||
Member author = futures.getMemberFuture().join();
|
||||
ModMailLoggedMessageModel modMailLoggedMessageModel =
|
||||
@@ -688,12 +716,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
public void saveSendMessagesAndUpdateState(Long modMailThreadId, Boolean anonymous, AUserInAServer moderator, Message message) {
|
||||
public void saveSendMessagesAndUpdateState(Long modMailThreadId, Boolean anonymous, AUserInAServer moderator, Message createdMessageInDM, Message replyCommandMessage, Message modMailThreadMessage) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getByIdOptional(modMailThreadId);
|
||||
if(modMailThreadOpt.isPresent()) {
|
||||
ModMailThread modMailThread = modMailThreadOpt.get();
|
||||
log.trace("Adding (anonymous: {}) message {} of moderator to modmail thread {} and setting state to {}.", anonymous, message.getId(), modMailThreadId, ModMailThreadState.MOD_REPLIED);
|
||||
modMailMessageManagementService.addMessageToThread(modMailThread, message, moderator, anonymous, true);
|
||||
log.trace("Adding (anonymous: {}) message {} of moderator to modmail thread {} and setting state to {}.", anonymous, createdMessageInDM.getId(), modMailThreadId, ModMailThreadState.MOD_REPLIED);
|
||||
modMailMessageManagementService.addMessageToThread(modMailThread, createdMessageInDM, modMailThreadMessage, replyCommandMessage, moderator, anonymous, true);
|
||||
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.MOD_REPLIED);
|
||||
} else {
|
||||
throw new ModMailThreadNotFoundException(modMailThreadId);
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@@ -19,17 +20,21 @@ public class ModMailMessageManagementServiceBean implements ModMailMessageManage
|
||||
private ModMailMessageRepository modMailMessageRepository;
|
||||
|
||||
@Override
|
||||
public ModMailMessage addMessageToThread(ModMailThread modMailThread, Message message, AUserInAServer author, Boolean anonymous, Boolean dmChannel) {
|
||||
public ModMailMessage addMessageToThread(ModMailThread modMailThread, Message createdMessageInDM, Message createdMessageInChannel, Message userPostedMessage, AUserInAServer author, Boolean anonymous, Boolean dmChannel) {
|
||||
Long dmId = createdMessageInDM != null ? createdMessageInDM.getIdLong() : null;
|
||||
Long channelMessageId = createdMessageInChannel != null ? createdMessageInChannel.getIdLong() : null;
|
||||
ModMailMessage modMailMessage = ModMailMessage
|
||||
.builder()
|
||||
.author(author)
|
||||
.messageId(message.getIdLong())
|
||||
.messageId(userPostedMessage.getIdLong())
|
||||
.createdMessageInDM(dmId)
|
||||
.createdMessageInChannel(channelMessageId)
|
||||
.dmChannel(dmChannel)
|
||||
.threadReference(modMailThread)
|
||||
.anonymous(anonymous)
|
||||
.build();
|
||||
log.info("Storing modmail thread message {} to modmail thread {} of user {} in server {}.",
|
||||
message.getId(), modMailThread.getId(), author.getUserReference().getId(), author.getServerReference().getId());
|
||||
log.info("Storing created message in DM {} with created message in channel {} caused by message {} to modmail thread {} of user {} in server {}.",
|
||||
dmId, channelMessageId, userPostedMessage.getId(), modMailThread.getId(), author.getUserReference().getId(), author.getServerReference().getId());
|
||||
|
||||
modMailMessageRepository.save(modMailMessage);
|
||||
return modMailMessage;
|
||||
@@ -39,4 +44,14 @@ public class ModMailMessageManagementServiceBean implements ModMailMessageManage
|
||||
public List<ModMailMessage> getMessagesOfThread(ModMailThread modMailThread) {
|
||||
return modMailMessageRepository.findByThreadReference(modMailThread);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModMailMessage> getByMessageIdOptional(Long messageId) {
|
||||
return modMailMessageRepository.findByMessageId(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMessageFromThread(ModMailMessage modMailMessage) {
|
||||
modMailMessageRepository.delete(modMailMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ 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.service.management.ChannelManagementService;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadChannelNotFound;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadNotFoundException;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState;
|
||||
@@ -44,9 +45,20 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
|
||||
|
||||
@Override
|
||||
public ModMailThread getByChannel(AChannel channel) {
|
||||
return modMailThreadRepository.findByChannel(channel).orElseThrow(ModMailThreadChannelNotFound::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModMailThread> getByChannelOptional(AChannel channel) {
|
||||
return modMailThreadRepository.findByChannel(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModMailThread> getByChannelIdOptional(Long channelId) {
|
||||
AChannel channel = channelManagementService.loadChannel(channelId);
|
||||
return getByChannelOptional(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModMailThread> getThreadByUserAndState(AUserInAServer userInAServer, ModMailThreadState state) {
|
||||
return modMailThreadRepository.findByUserAndState(userInAServer, state);
|
||||
|
||||
@@ -10,10 +10,16 @@
|
||||
<property name="today" value="(SELECT NOW())"/>
|
||||
<changeSet author="Sheldan" id="modmail_default_feature_mode-insertion">
|
||||
<insert tableName="default_feature_mode">
|
||||
<column name="enabled" value="false"/>
|
||||
<column name="enabled" value="true"/>
|
||||
<column name="mode" value="log"/>
|
||||
<column name="feature_id" valueComputed="${modmailFeature}" />
|
||||
<column name="created" valueComputed="${today}"/>
|
||||
</insert>
|
||||
<insert tableName="default_feature_mode">
|
||||
<column name="enabled" value="true"/>
|
||||
<column name="mode" value="threadMessage"/>
|
||||
<column name="feature_id" valueComputed="${modmailFeature}" />
|
||||
<column name="created" valueComputed="${today}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -6,10 +6,10 @@
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
|
||||
<changeSet author="Sheldan" id="modmail_messages-table">
|
||||
<createTable tableName="modmail_messages">
|
||||
<changeSet author="Sheldan" id="modmail_message-table">
|
||||
<createTable tableName="modmail_message">
|
||||
<column name="message_id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="modmail_messages_pkey"/>
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="modmail_message_pkey"/>
|
||||
</column>
|
||||
<column name="anonymous" type="BOOLEAN"/>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
@@ -22,10 +22,10 @@
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="Sheldan" id="modmail_messages-fk_modmail_message_thread">
|
||||
<addForeignKeyConstraint baseColumnNames="thread_reference" baseTableName="modmail_messages" constraintName="fk_modmail_message_thread" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="modmail_thread" validate="true"/>
|
||||
<changeSet author="Sheldan" id="modmail_message-fk_modmail_message_thread">
|
||||
<addForeignKeyConstraint baseColumnNames="thread_reference" baseTableName="modmail_message" constraintName="fk_modmail_message_thread" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="modmail_thread" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet author="Sheldan" id="modmail_messages-fk_modmail_message_author">
|
||||
<addForeignKeyConstraint baseColumnNames="modmail_message_author" baseTableName="modmail_messages" constraintName="fk_modmail_message_author" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
|
||||
<changeSet author="Sheldan" id="modmail_message-fk_modmail_message_author">
|
||||
<addForeignKeyConstraint baseColumnNames="modmail_message_author" baseTableName="modmail_message" constraintName="fk_modmail_message_author" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -6,10 +6,10 @@
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
|
||||
<changeSet author="Sheldan" id="modmail_roles-table">
|
||||
<createTable tableName="modmail_roles">
|
||||
<changeSet author="Sheldan" id="modmail_role-table">
|
||||
<createTable tableName="modmail_role">
|
||||
<column autoIncrement="true" name="mod_mail_role_id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="modmail_roles_pkey"/>
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="modmail_role_pkey"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
@@ -21,10 +21,10 @@
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="Sheldan" id="modmail_roles-fk_modmail_role_role">
|
||||
<addForeignKeyConstraint baseColumnNames="modmail_role" baseTableName="modmail_roles" constraintName="fk_modmail_role_role" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="role" validate="true"/>
|
||||
<changeSet author="Sheldan" id="modmail_role-fk_modmail_role_role">
|
||||
<addForeignKeyConstraint baseColumnNames="modmail_role" baseTableName="modmail_role" constraintName="fk_modmail_role_role" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="role" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet author="Sheldan" id="modmail_roles-fk_modmail_role_server">
|
||||
<addForeignKeyConstraint baseColumnNames="modmail_role_server" baseTableName="modmail_roles" constraintName="fk_modmail_role_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
|
||||
<changeSet author="Sheldan" id="modmail_role-fk_modmail_role_server">
|
||||
<addForeignKeyConstraint baseColumnNames="modmail_role_server" baseTableName="modmail_role" constraintName="fk_modmail_role_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -6,8 +6,8 @@
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
|
||||
<include file="modmail_threads.xml" relativeToChangelogFile="true"/>
|
||||
<include file="modmail_messages.xml" relativeToChangelogFile="true"/>
|
||||
<include file="modmail_thread.xml" relativeToChangelogFile="true"/>
|
||||
<include file="modmail_message.xml" relativeToChangelogFile="true"/>
|
||||
<include file="modmail_subscriber.xml" relativeToChangelogFile="true"/>
|
||||
<include file="modmail_roles.xml" relativeToChangelogFile="true"/>
|
||||
<include file="modmail_role.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,142 @@
|
||||
package dev.sheldan.abstracto.modmail.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
|
||||
import dev.sheldan.abstracto.core.models.GuildChannelMember;
|
||||
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.service.BotService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.models.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 BotService botService;
|
||||
|
||||
@Mock
|
||||
private CachedMessage deletedMessage;
|
||||
|
||||
@Mock
|
||||
private AServerAChannelAUser origin;
|
||||
|
||||
@Mock
|
||||
private GuildChannelMember jdaOrigin;
|
||||
|
||||
@Mock
|
||||
private ModMailMessage modMailMessage;
|
||||
|
||||
@Mock
|
||||
private Member targetMember;
|
||||
|
||||
@Mock
|
||||
private User targetUser;
|
||||
|
||||
@Mock
|
||||
private AServer server;
|
||||
|
||||
@Mock
|
||||
private AChannel channel;
|
||||
|
||||
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());
|
||||
testUnit.execute(deletedMessage, origin, jdaOrigin);
|
||||
verify(botService, times(0)).getMemberInServerAsync(anyLong(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteNonDuplicatedMessage() {
|
||||
when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
|
||||
when(deletedMessage.getServerId()).thenReturn(SERVER_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(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
|
||||
when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
testUnit.execute(deletedMessage, origin, jdaOrigin);
|
||||
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(deletedMessage.getServerId()).thenReturn(SERVER_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(botService.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));
|
||||
testUnit.execute(deletedMessage, origin, jdaOrigin);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
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.service.BotService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.models.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.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.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 BotService botService;
|
||||
|
||||
@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 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<ModMailModeratorReplyModel> replyModelArgumentCaptor;
|
||||
|
||||
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);
|
||||
testUnit.execute(messageBefore, messageAfter);
|
||||
verify(modMailMessageManagementService, times(0)).getByMessageIdOptional(anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditNotTrackedMessage() {
|
||||
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
|
||||
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
|
||||
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.empty());
|
||||
testUnit.execute(messageBefore, messageAfter);
|
||||
verify(commandRegistry, times(0)).getCommandName(anyString(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditMessageWithCorrectCommand() {
|
||||
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
|
||||
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.getContentRaw()).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(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
|
||||
when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
|
||||
testUnit.execute(messageBefore, messageAfter);
|
||||
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditMessageWithInCorrectCommand() {
|
||||
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
|
||||
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 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.getContentRaw()).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(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
|
||||
when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
|
||||
testUnit.execute(messageBefore, messageAfter);
|
||||
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAnonymousMessageInThreadNotDuplicated() {
|
||||
when(messageAfter.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())).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(messageAfter, 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 testUpdateAnonymousMessageInThreadDuplicated() {
|
||||
when(messageAfter.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(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
|
||||
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(messageAfter, 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(messageAfter.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())).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(messageAfter, 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(messageAfter.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())).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(messageAfter, 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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user