added undo logic to mod mail logging

added some more logging when closing the mod mail thread
This commit is contained in:
Sheldan
2020-05-09 01:10:46 +02:00
parent 379db1ff73
commit 0e7add826b
4 changed files with 99 additions and 26 deletions

View File

@@ -11,6 +11,7 @@ import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerService; import dev.sheldan.abstracto.core.service.management.UserInServerService;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.modmail.config.ModMailFeature; import dev.sheldan.abstracto.modmail.config.ModMailFeature;
import dev.sheldan.abstracto.modmail.models.database.*; import dev.sheldan.abstracto.modmail.models.database.*;
import dev.sheldan.abstracto.modmail.models.dto.ServerChoice; import dev.sheldan.abstracto.modmail.models.dto.ServerChoice;
@@ -107,7 +108,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
textChannel.thenAccept(channel -> { textChannel.thenAccept(channel -> {
List<UndoActionInstance> undoActions = new ArrayList<>(); List<UndoActionInstance> undoActions = new ArrayList<>();
undoActions.add(UndoActionInstance.getChannelDeleteAction(channel.getIdLong(), aUserInAServer.getAUserInAServer().getServerReference().getId())); undoActions.add(UndoActionInstance.getChannelDeleteAction(aUserInAServer.getAUserInAServer().getServerReference().getId(), channel.getIdLong()));
self.performModMailThreadSetup(aUserInAServer, channel, userInitiated, undoActions); self.performModMailThreadSetup(aUserInAServer, channel, userInitiated, undoActions);
}).exceptionally(throwable -> { }).exceptionally(throwable -> {
log.error("Failed to create mod mail thread", throwable); log.error("Failed to create mod mail thread", throwable);
@@ -331,8 +332,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override @Override
public synchronized void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, Boolean notifyUser) { public synchronized void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, Boolean notifyUser) {
log.info("Starting closing procedure for thread {}", modMailThread.getId());
List<ModMailMessage> modMailMessages = modMailThread.getMessages(); List<ModMailMessage> modMailMessages = modMailThread.getMessages();
List<CompletableFuture<Message>> messages = modMailMessageService.loadModMailMessages(modMailMessages); List<CompletableFuture<Message>> messages = modMailMessageService.loadModMailMessages(modMailMessages);
log.trace("Loading {} mod mail thread messages.", messages.size());
Long modMailThreadId = modMailThread.getId(); Long modMailThreadId = modMailThread.getId();
for (int i = 0; i < messages.size(); i++) { for (int i = 0; i < messages.size(); i++) {
CompletableFuture<Message> messageCompletableFuture = messages.get(i); CompletableFuture<Message> messageCompletableFuture = messages.get(i);
@@ -343,13 +346,25 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}); });
} }
CompletableFuture.allOf(messages.toArray(new CompletableFuture[0])).whenComplete((avoid, throwable) -> { CompletableFuture.allOf(messages.toArray(new CompletableFuture[0])).whenComplete((avoid, throwable) -> {
log.trace("Loaded {} mod mail thread messages", messages.size());
if(throwable != null) { if(throwable != null) {
log.warn("Failed to load some mod mail messages for mod mail thread {}. Still trying to post the ones we got.", modMailThreadId, throwable); log.warn("Failed to load some mod mail messages for mod mail thread {}. Still trying to post the ones we got.", modMailThreadId, throwable);
} }
try { try {
self.logModMailThread(modMailThreadId, messages, note).thenRun(() -> { List<UndoActionInstance> undoActions = new ArrayList<>();
self.afterSuccessfulLog(modMailThreadId, feedBack, notifyUser); CompletableFutureList<Message> list = self.logModMailThread(modMailThreadId, messages, note);
}).exceptionally(innerThrowable -> { list.getMainFuture().thenRun(() -> {
list.getFutures().forEach(messageCompletableFuture -> {
try {
Message message = messageCompletableFuture.get();
undoActions.add(UndoActionInstance.getMessageDeleteAction(message.getGuild().getIdLong(), message.getChannel().getIdLong(), message.getIdLong()));
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post logging messages.", e);
}
});
self.afterSuccessfulLog(modMailThreadId, feedBack, notifyUser, undoActions);
});
list.getMainFuture().exceptionally(innerThrowable -> {
sendModMailFailure("modmail_exception_generic", modMailThread.getUser(), modMailThreadId, feedBack, innerThrowable); sendModMailFailure("modmail_exception_generic", modMailThread.getUser(), modMailThreadId, feedBack, innerThrowable);
log.error("Failed to log messages for mod mail thread {}.", modMailThreadId, innerThrowable); log.error("Failed to log messages for mod mail thread {}.", modMailThreadId, innerThrowable);
return null; return null;
@@ -367,44 +382,64 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
} }
@Transactional @Transactional
public void afterSuccessfulLog(Long modMailThreadId, MessageChannel feedBack, Boolean notifyUser) { public void afterSuccessfulLog(Long modMailThreadId, MessageChannel feedBack, Boolean notifyUser, List<UndoActionInstance> undoActions) {
log.trace("Mod mail logging for thread {} has completed. Starting post logging activities.", modMailThreadId);
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId); ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
User user = botService.getMemberInServer(modMailThread.getUser()).getUser(); User user = botService.getMemberInServer(modMailThread.getUser()).getUser();
user.openPrivateChannel().queue(privateChannel -> { user.openPrivateChannel().queue(privateChannel -> {
try { try {
List<CompletableFuture<Message>> messageFutures = new ArrayList<>(); List<CompletableFuture<Message>> messageFutures = new ArrayList<>();
if(notifyUser){ if(notifyUser){
log.trace("Notifying user {}", user.getIdLong());
messageFutures.addAll(channelService.sendTemplateInChannel("modmail_closing_user_message", new Object(), privateChannel)); messageFutures.addAll(channelService.sendTemplateInChannel("modmail_closing_user_message", new Object(), privateChannel));
} else { } else {
log.trace("*Not* notifying user {}", user.getIdLong());
messageFutures.add(CompletableFuture.completedFuture(null)); messageFutures.add(CompletableFuture.completedFuture(null));
} }
CompletableFuture.allOf(messageFutures.toArray(new CompletableFuture[0])).whenComplete((result, throwable) -> { CompletableFuture.allOf(messageFutures.toArray(new CompletableFuture[0])).whenComplete((result, throwable) -> {
if(throwable != null) { if(throwable != null) {
log.warn("Failed to send closing message to user {} after closing mod mail thread {}", user.getIdLong(), modMailThread.getId(), throwable); log.warn("Failed to send closing message to user {} after closing mod mail thread {}", user.getIdLong(), modMailThread.getId(), throwable);
} }
try { self.deleteChannelAndClose(modMailThreadId, feedBack, undoActions);
channelService.deleteTextChannel(modMailThread.getChannel()).thenRun(() -> {
self.closeModMailThreadInDb(modMailThreadId);
}).exceptionally(throwable2 -> {
log.error("Failed to delete text channel containing mod mail thread {}", modMailThread.getId(), throwable2);
return null;
});
} catch (InsufficientPermissionException ex){
log.error("Failed to delete text channel containing mod mail thread {}", modMailThread.getId(), ex);
sendModMailFailure("modmail_exception_cannot_delete_channel", modMailThread.getUser(), modMailThreadId, feedBack, ex);
} catch (Exception ex) {
log.error("Failed to delete text channel containing mod mail thread {}", modMailThread.getId(), ex);
}
}); });
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to render closing user message", e); log.error("Failed to render closing user message", e);
sendModMailFailure("modmail_exception_generic", modMailThread.getUser(), modMailThreadId, feedBack, e); sendModMailFailure("modmail_exception_generic", modMailThread.getUser(), modMailThreadId, feedBack, e);
} }
}, throwable -> log.error("Failed to load private channel with user {}", user.getIdLong(), throwable)); }, throwable -> {
log.error("Failed to load private channel with user {}", user.getIdLong(), throwable);
undoActionService.performActions(undoActions);
});
} }
@Transactional @Transactional
public CompletableFuture<Void> logModMailThread(Long modMailThreadId, List<CompletableFuture<Message>> messages, String note) { public void deleteChannelAndClose(Long modMailThreadId, MessageChannel feedBack, List<UndoActionInstance> undoActions) {
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
try {
channelService.deleteTextChannel(modMailThread.getChannel()).thenRun(() -> {
try {
self.closeModMailThreadInDb(modMailThreadId);
} catch (Exception e) {
undoActionService.performActions(undoActions);
}
}).exceptionally(throwable2 -> {
undoActionService.performActions(undoActions);
log.error("Failed to delete text channel containing mod mail thread {}", modMailThread.getId(), throwable2);
return null;
});
} catch (InsufficientPermissionException ex) {
log.error("Failed to delete text channel containing mod mail thread {}", modMailThreadId, ex);
undoActionService.performActions(undoActions);
sendModMailFailure("modmail_exception_cannot_delete_channel", modMailThread.getUser(), modMailThreadId, feedBack, ex);
} catch (Exception ex) {
log.error("Failed to delete text channel containing mod mail thread {}", modMailThreadId, ex);
undoActionService.performActions(undoActions);
}
}
@Transactional
public CompletableFutureList<Message> logModMailThread(Long modMailThreadId, List<CompletableFuture<Message>> messages, String note) {
log.info("Logging mod mail thread {}.", modMailThreadId);
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId); ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
List<ModMailLoggedMessage> loggedMessages = new ArrayList<>(); List<ModMailLoggedMessage> loggedMessages = new ArrayList<>();
messages.forEach(future -> { messages.forEach(future -> {
@@ -437,17 +472,23 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.closedThread(modMailThread) .closedThread(modMailThread)
.note(note) .note(note)
.build(); .build();
log.trace("Sending close header and individual mod mail messages to mod mail log target.");
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_header", headerModel); MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_header", headerModel);
List<CompletableFuture<Message>> closeHeaderFutures = postTargetService.sendEmbedInPostTarget(messageToSend, MODMAIL_LOG_POSTTARGET, modMailThread.getServer().getId()); List<CompletableFuture<Message>> closeHeaderFutures = postTargetService.sendEmbedInPostTarget(messageToSend, MODMAIL_LOG_POSTTARGET, modMailThread.getServer().getId());
completableFutures.addAll(closeHeaderFutures); completableFutures.addAll(closeHeaderFutures);
completableFutures.addAll(self.sendMessagesToPostTarget(modMailThread, loggedMessages)); completableFutures.addAll(self.sendMessagesToPostTarget(modMailThread, loggedMessages));
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])); CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]));
return CompletableFutureList
.<Message>builder()
.mainFuture(voidCompletableFuture)
.futures(completableFutures)
.build();
} }
@Transactional @Transactional
public void closeModMailThreadInDb(Long modMailThreadId) { public void closeModMailThreadInDb(Long modMailThreadId) {
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId); ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
log.info("Setting thread {} to closed.", modMailThread.getId()); log.info("Setting thread {} to closed in db.", modMailThread.getId());
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.CLOSED); modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.CLOSED);
} }

View File

@@ -23,13 +23,21 @@ public class UndoActionServiceBean implements UndoActionService {
public void performActions(List<UndoActionInstance> actionsToPerform) { public void performActions(List<UndoActionInstance> actionsToPerform) {
actionsToPerform.forEach(undoActionInstance -> { actionsToPerform.forEach(undoActionInstance -> {
UndoAction action = undoActionInstance.getAction(); UndoAction action = undoActionInstance.getAction();
List<Long> ids = undoActionInstance.getIds();
switch (action) { switch (action) {
case DELETE_CHANNEL: case DELETE_CHANNEL:
if(undoActionInstance.getIds().size() != 2) { if(ids.size() != 2) {
throw new UndoActionException("Not the correct amount of ides provided for the channel deletion undo action"); log.error("Not the correct amount of ids provided for the channel deletion undo action.");
break;
} }
deleteChannel(undoActionInstance.getIds().get(0), undoActionInstance.getIds().get(1)); deleteChannel(ids.get(0), ids.get(1));
break; break;
case DELETE_MESSAGE:
if(ids.size() != 3) {
log.error("Not the correct amount of ids provided for the message deletion undo action.");
break;
}
botService.deleteMessage(ids.get(0), ids.get(1), ids.get(2));
} }
}); });
} }

View File

@@ -14,11 +14,19 @@ public class UndoActionInstance {
private List<Long> ids; private List<Long> ids;
private UndoAction action; private UndoAction action;
public static UndoActionInstance getChannelDeleteAction(Long channelId, Long serverId) { public static UndoActionInstance getChannelDeleteAction(Long serverId, Long channelId) {
return UndoActionInstance return UndoActionInstance
.builder() .builder()
.action(UndoAction.DELETE_CHANNEL) .action(UndoAction.DELETE_CHANNEL)
.ids(Arrays.asList(serverId, channelId)) .ids(Arrays.asList(serverId, channelId))
.build(); .build();
} }
public static UndoActionInstance getMessageDeleteAction(Long serverId, Long channelId, Long messageId) {
return UndoActionInstance
.builder()
.action(UndoAction.DELETE_MESSAGE)
.ids(Arrays.asList(serverId, channelId, messageId))
.build();
}
} }

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.core.utils;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Getter
@Setter
@Builder
public class CompletableFutureList<T> {
private CompletableFuture<Void> mainFuture;
private List<CompletableFuture<T>> futures;
}