fixed using the correct parameter for reply and anon reply (not the whole message, so we dont need to parse out the actual reply again)

added optional note parameter for close
fixed state not being saved in database for mod mail thread
changed logging of mod mail to be templated, instead of replaying the messages
added reaction to indicate the user, that the message was processes by modmail
fixed future handling for user message replies (we blocked)
added header for initial information about the user when he opens a thread
fixed duration formater resulting in new lines
This commit is contained in:
Sheldan
2020-05-06 23:22:43 +02:00
parent ad1cbb54fd
commit feb9ce07ee
23 changed files with 191 additions and 58 deletions

View File

@@ -33,14 +33,16 @@ public class AnonReply extends AbstractConditionableCommand {
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String text = parameters.size() == 1 ? (String) parameters.get(0) : "";
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
modMailThreadService.relayMessageToDm(thread, commandContext.getMessage(), true, commandContext.getChannel());
modMailThreadService.relayMessageToDm(thread, text, commandContext.getMessage(), true, commandContext.getChannel());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter responseText = Parameter.builder().name("text").type(String.class).description("The text to reply with").build();
Parameter responseText = Parameter.builder().name("text").type(String.class).remainder(true).optional(true).description("The text to reply with").build();
List<Parameter> parameters = Arrays.asList(responseText);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()

View File

@@ -4,6 +4,7 @@ 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.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
@@ -16,7 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
@@ -35,18 +36,22 @@ public class Close extends AbstractConditionableCommand {
@Override
@Transactional
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String note = parameters.size() == 1 ? (String) parameters.get(0) : "no note";
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
modMailThreadService.closeModMailThread(thread, commandContext.getChannel());
modMailThreadService.closeModMailThread(thread, commandContext.getChannel(), note);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter note = Parameter.builder().name("note").type(String.class).remainder(true).optional(true).build();
List<Parameter> parameters = Arrays.asList(note);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("close")
.module(ModMailModuleInterface.MODMAIL)
.parameters(new ArrayList<>())
.parameters(parameters)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -33,14 +33,16 @@ public class Reply extends AbstractConditionableCommand {
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String text = parameters.size() == 1 ? (String) parameters.get(0) : "";
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
modMailThreadService.relayMessageToDm(thread, commandContext.getMessage(), false, commandContext.getChannel());
modMailThreadService.relayMessageToDm(thread, text, commandContext.getMessage(), false, commandContext.getChannel());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter responseText = Parameter.builder().name("text").type(String.class).description("The text to reply with").build();
Parameter responseText = Parameter.builder().name("text").type(String.class).remainder(true).optional(true).description("The text to reply with").build();
List<Parameter> parameters = Arrays.asList(responseText);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()

View File

@@ -4,12 +4,10 @@ import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.listener.PrivateMessageReceivedListener;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.service.management.UserManagementService;
import dev.sheldan.abstracto.modmail.config.ModMailFeature;
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
@@ -29,10 +27,6 @@ public class ModMailMessageListener implements PrivateMessageReceivedListener {
@Autowired
private UserManagementService userManagementService;
@Autowired
private TemplateService templateService;
@Override
@Transactional
public void execute(Message message) {

View File

@@ -8,13 +8,12 @@ import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerService;
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState;
import dev.sheldan.abstracto.modmail.models.dto.ServerChoice;
import dev.sheldan.abstracto.modmail.models.template.ModMailExceptionModel;
import dev.sheldan.abstracto.modmail.models.template.ModMailModeratorReplyModel;
import dev.sheldan.abstracto.modmail.models.template.ModMailServerChooserModel;
import dev.sheldan.abstracto.modmail.models.template.*;
import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import dev.sheldan.abstracto.templating.model.MessageToSend;
@@ -25,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -65,6 +65,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Autowired
private PostTargetService postTargetService;
@Autowired
private MessageService messageService;
@Autowired
private UserInServerService userInServerService;
@Autowired
private ModMailThreadServiceBean self;
@@ -185,6 +191,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_user_message", modMailUserReplyModel);
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, textChannel);
List<Message> messages = new ArrayList<>();
CompletableFuture.allOf(messages.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
self.postProcessSendMessages(modMailThread, message, completableFutures, messages);
});
}
@Transactional
public void postProcessSendMessages(ModMailThread modMailThread, Message message, List<CompletableFuture<Message>> completableFutures, List<Message> messages) {
completableFutures.forEach(messageCompletableFuture -> {
try {
Message messageToAdd = messageCompletableFuture.get();
@@ -193,15 +207,17 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
log.error("Error while executing future to retrieve reaction.", e);
}
self.saveMessageIds(messages, modMailThread, modMailThread.getUser(), false, false);
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.USER_REPLIED);
messageService.addReactionToMessage("readReaction", modMailThread.getServer().getId(), message);
});
}
@Override
public void relayMessageToDm(ModMailThread modMailThread, Message message, Boolean anonymous, MessageChannel feedBack) {
public void relayMessageToDm(ModMailThread modMailThread, String text, Message message, Boolean anonymous, MessageChannel feedBack) {
User userById = botService.getInstance().getUserById(modMailThread.getUser().getUserReference().getId());
if(userById != null) {
userById.openPrivateChannel().queue(privateChannel -> {
self.sendReply(modMailThread, message, privateChannel, anonymous, feedBack);
self.sendReply(modMailThread, text, message, privateChannel, anonymous, feedBack);
}, throwable -> {
log.warn("Failed to open private channel with user {}", userById.getIdLong());
});
@@ -228,8 +244,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
@Override
public void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack) {
List<ModMailMessage> modMailMessages = modMailMessageManagementService.getMessagesOfThread(modMailThread);
public void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note) {
List<ModMailMessage> modMailMessages = modMailThread.getMessages();
List<CompletableFuture<Message>> messages = modMailMessageService.loadModMailMessages(modMailMessages);
for (int i = 0; i < messages.size(); i++) {
@@ -241,31 +257,53 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
});
}
CompletableFuture.allOf(messages.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
handledRetrievedMessages(modMailThread, messages);
self.logModMailThread(modMailThread, messages, note, modMailMessages);
}).exceptionally(throwable -> {
log.warn("Failed to load some mod mail messages for mod mail thread {}. Still trying to post the ones we got.", modMailThread.getId(), throwable);
handledRetrievedMessages(modMailThread, messages);
self.logModMailThread(modMailThread, messages, note, modMailMessages);
return null;
});
}
private void handledRetrievedMessages(ModMailThread modMailThread, List<CompletableFuture<Message>> messages) {
List<Message> loadedMessages = new ArrayList<>();
@Transactional
public void logModMailThread(ModMailThread modMailThread, List<CompletableFuture<Message>> messages, String note, List<ModMailMessage> modMailMessages) {
List<ModMailLoggedMessage> loggedMessages = new ArrayList<>();
messages.forEach(future -> {
try {
if(!future.isCompletedExceptionally()) {
Message loadedMessage = future.get();
if(loadedMessage != null) {
loadedMessages.add(loadedMessage);
ModMailMessage modmailMessage = modMailMessages
.stream()
.filter(modMailMessage -> modMailMessage.getMessageId().equals(loadedMessage.getIdLong()))
.findFirst().get();
ModMailLoggedMessage modMailLoggedMessage =
ModMailLoggedMessage
.builder()
.message(loadedMessage)
.modMailMessage(modmailMessage)
.author(userInServerService.getFullUser(modmailMessage.getAuthor()))
.build();
loggedMessages.add(modMailLoggedMessage);
}
}
} catch (InterruptedException | ExecutionException e) {
log.error("Error while executing future to retrieve reaction.", e);
}
});
List<CompletableFuture<Message>> completableFutures = self.sendMessagesToPostTarget(modMailThread, loadedMessages);
List<CompletableFuture<Message>> completableFutures = new ArrayList<>();
modMailThread.setClosed(Instant.now());
ModMailClosingHeaderModel headerModel = ModMailClosingHeaderModel
.builder()
.closedThread(modMailThread)
.note(note)
.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_header", headerModel);
List<CompletableFuture<Message>> closeHeaderFutures = postTargetService.sendEmbedInPostTarget(messageToSend, MODMAIL_LOG_POSTTARGET, modMailThread.getServer().getId());
completableFutures.addAll(closeHeaderFutures);
completableFutures.addAll(self.sendMessagesToPostTarget(modMailThread, loggedMessages));
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
channelService.deleteTextChannel(modMailThread.getChannel()).thenAccept(o -> {
self.closeModMailThreadInDb(modMailThread);
@@ -279,17 +317,18 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
@Transactional
public List<CompletableFuture<Message>> sendMessagesToPostTarget(ModMailThread modMailThread, List<Message> loadedMessages) {
public List<CompletableFuture<Message>> sendMessagesToPostTarget(ModMailThread modMailThread, List<ModMailLoggedMessage> loadedMessages) {
List<CompletableFuture<Message>> messageFutures = new ArrayList<>();
loadedMessages.forEach(message -> {
CompletableFuture<Message> logFuture = postTargetService.sendMessageInPostTarget(message, MODMAIL_LOG_POSTTARGET, modMailThread.getServer().getId());
messageFutures.add(logFuture);
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_logged_message", message);
List<CompletableFuture<Message>> logFuture = postTargetService.sendEmbedInPostTarget(messageToSend, MODMAIL_LOG_POSTTARGET, modMailThread.getServer().getId());
messageFutures.addAll(logFuture);
});
return messageFutures;
}
@Transactional
public void sendReply(ModMailThread modMailThread, Message message, PrivateChannel privateChannel, Boolean anonymous, MessageChannel feedBack) {
public void sendReply(ModMailThread modMailThread, String text, Message message, PrivateChannel privateChannel, Boolean anonymous, MessageChannel feedBack) {
AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember());
Member userInGuild = botService.getMemberInServer(modMailThread.getUser());
FullUser moderatorUser = FullUser
@@ -304,6 +343,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.build();
ModMailModeratorReplyModel modMailUserReplyModel = ModMailModeratorReplyModel
.builder()
.text(text)
.modMailThread(modMailThread)
.postedMessage(message)
.threadUser(fullThreadUser)
@@ -322,6 +362,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
});
self.saveMessageIds(messages, modMailThread, moderator, anonymous, true);
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.MOD_REPLIED);
}).exceptionally(throwable -> {
log.error("Failed to send message to user {}", modMailThread.getUser().getUserReference().getId());
sendModMailFailure("modmail_exception_cannot_message_user", modMailThread, feedBack, throwable);

View File

@@ -71,5 +71,7 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
@Override
public void setModMailThreadState(ModMailThread modMailThread, ModMailThreadState newState) {
modMailThread.setState(newState);
modMailThread.setUpdated(Instant.now());
modMailThreadRepository.save(modMailThread);
}
}

View File

@@ -1 +1,3 @@
abstracto.postTargets.modmail=modmaillog
abstracto.postTargets.modmail=modmaillog
abstracto.emoteNames.readReaction=readReaction
abstracto.defaultEmotes.readReaction=\uD83D\uDC40

View File

@@ -0,0 +1,15 @@
{
"title": {
"title": "Modmail thread has been closed"
},
"color" : {
"r": 200,
"g": 0,
"b": 255
},
<#assign messageCount>${closedThread.messages?size}</#assign>
<#assign user>user</#assign>
<#assign startDate>${formatInstant(closedThread.created,"yyyy-MM-dd HH:mm:ss")}</#assign>
<#assign duration>${fmtDuration(duration)}</#assign>
"description": "<#include "close_closing_description">"
}

View File

@@ -0,0 +1,16 @@
{
"author": {
"name": "${author.member.effectiveName}",
"avatar": "${author.member.user.effectiveAvatarUrl}"
},
"color" : {
"r": 200,
"g": 0,
"b": 255
},
"description": "${message.embeds[0].description}"
<#if message.attachments?size gt 0>
,"imageUrl": "${message.embeds[0].image.proxyUrl}"
</#if>,
"timeStamp": "${message.timeCreated}"
}

View File

@@ -11,8 +11,8 @@
"g": 0,
"b": 255
},
<#if postedMessage.contentRaw?has_content>
"description": "${postedMessage.contentRaw}"
<#if text?has_content>
"description": "${text}"
</#if>
<#if postedMessage.attachments?size gt 0>
,"imageUrl": "${postedMessage.attachments[0].proxyUrl}"

View File

@@ -8,5 +8,5 @@
"g": 0,
"b": 255
},
"description": "<#include "reply_exception_cannot_send_message_to_use_en_US.ftl">"
"description": "<#include "reply_exception_cannot_send_message_to_use">"
}