mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-24 22:43:37 +00:00
updated javadoc for experience tracking
added/changed some javadoc for mod mail some small interface changes changed a few methods to actually use the exists mechanic, instead of checking for null values added some templates instead of hard coded strings fixed some bugs related to mod mail
This commit is contained in:
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
|
||||
@@ -19,11 +19,15 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sends the reply from the staff member to the user, but marks the reply as anonymous. The original author is still
|
||||
* tracked internally.
|
||||
*/
|
||||
@Component
|
||||
public class AnonReply extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private RequiresModMailCondition requiresModMailCondition;
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadService modMailThreadService;
|
||||
@@ -34,6 +38,7 @@ public class AnonReply extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// text is optional, for example if only an attachment is sent
|
||||
String text = parameters.size() == 1 ? (String) parameters.get(0) : "";
|
||||
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
|
||||
modMailThreadService.relayMessageToDm(thread, text, commandContext.getMessage(), true, commandContext.getChannel());
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
|
||||
@@ -21,11 +21,16 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Closes the mod mail thread: logs the messages to the log post target, if the feature has the appropriate
|
||||
* {@link dev.sheldan.abstracto.core.config.FeatureMode}, deletes the {@link net.dv8tion.jda.api.entities.MessageChannel}.
|
||||
* This command takes an optional parameter, the note, which will be replaced with a default value, if not present
|
||||
*/
|
||||
@Component
|
||||
public class Close extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private RequiresModMailCondition requiresModMailCondition;
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
@@ -41,6 +46,7 @@ public class Close extends AbstractConditionableCommand {
|
||||
@Transactional
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// the default value of the note is configurable via template
|
||||
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object());
|
||||
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
|
||||
modMailThreadService.closeModMailThread(thread, commandContext.getChannel(), note, true);
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailMode;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
@@ -21,11 +21,16 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command closes a mod mail thread without logging the closing and the contents of the {@link ModMailThread}.
|
||||
* This command is only available if the server has the {@link dev.sheldan.abstracto.modmail.config.ModMailFeature}
|
||||
* in the 'LOGGING' mode, because else the normal close command behaves the same way.
|
||||
*/
|
||||
@Component
|
||||
public class CloseNoLog extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private RequiresModMailCondition requiresModMailCondition;
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
@@ -39,6 +44,7 @@ public class CloseNoLog extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
|
||||
// we dont have a note, therefore we cant pass any, the method handles this accordingly
|
||||
modMailThreadService.closeModMailThread(thread, commandContext.getChannel(), null, false, false);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
@@ -67,6 +73,9 @@ public class CloseNoLog extends AbstractConditionableCommand {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* This command is only available in the LOGGING mod mail feature mode
|
||||
*/
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(ModMailMode.LOGGING);
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
|
||||
@@ -20,11 +20,15 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command can be used to close the mod mail thread without sending a 'closing' message to the user.
|
||||
* This behaves the same way as the default close commmand otherwise
|
||||
*/
|
||||
@Component
|
||||
public class CloseSilently extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private RequiresModMailCondition requiresModMailCondition;
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
@@ -37,6 +41,7 @@ public class CloseSilently extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// default note text is configurable via template, because the note is optional
|
||||
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object());
|
||||
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
|
||||
modMailThreadService.closeModMailThread(thread, commandContext.getChannel(), note, false);
|
||||
|
||||
@@ -26,6 +26,10 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command is used to create a thread with a member directly. If a thread already exists, this will post a link to
|
||||
* the {@link net.dv8tion.jda.api.entities.MessageChannel}
|
||||
*/
|
||||
@Component
|
||||
public class Contact extends AbstractConditionableCommand {
|
||||
|
||||
@@ -38,9 +42,6 @@ public class Contact extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private UserInServerManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@@ -48,12 +49,13 @@ public class Contact extends AbstractConditionableCommand {
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
Member targetUser = (Member) commandContext.getParameters().getParameters().get(0);
|
||||
AUserInAServer user = userManagementService.loadUser(targetUser);
|
||||
ModMailThread existingThread = modMailThreadManagementService.getOpenModmailThreadForUser(user);
|
||||
if(existingThread != null) {
|
||||
// if this AUserInAServer already has an open thread, we should instead post a message
|
||||
// containing a link to the channel, instead of opening a new one
|
||||
if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
|
||||
ModMailThreadExistsModel model = (ModMailThreadExistsModel) ContextConverter.fromCommandContext(commandContext, ModMailThreadExistsModel.class);
|
||||
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
|
||||
model.setExistingModMailThread(existingThread);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_thread_already_exists", model);
|
||||
channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
|
||||
channelService.sendEmbedTemplateInChannel("modmail_thread_already_exists", model, commandContext.getChannel());
|
||||
} else {
|
||||
FullUser fullUser = FullUser
|
||||
.builder()
|
||||
|
||||
@@ -2,6 +2,8 @@ package dev.sheldan.abstracto.modmail.commands;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleInterface;
|
||||
import dev.sheldan.abstracto.templating.service.TemplateService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@@ -9,9 +11,13 @@ public class ModMailModuleInterface implements ModuleInterface {
|
||||
|
||||
public static final String MODMAIL = "modMail";
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Override
|
||||
public ModuleInfo getInfo() {
|
||||
return ModuleInfo.builder().name(MODMAIL).description("Commands to be used for modmail.").build();
|
||||
String description = templateService.renderSimpleTemplate("modmail_help_module_info");
|
||||
return ModuleInfo.builder().name(MODMAIL).description(description).build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command is used to remove a role from the roles to be notified when a new {@link dev.sheldan.abstracto.modmail.models.database.ModMailThread}
|
||||
* is opened. The method this command executes also automatically dis-allows all mod mail related {@link dev.sheldan.abstracto.core.command.Command}
|
||||
* for this role.
|
||||
*/
|
||||
@Component
|
||||
public class RemoveModMailRole extends AbstractConditionableCommand {
|
||||
|
||||
@@ -25,7 +30,7 @@ public class RemoveModMailRole extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
ARole role = (ARole) commandContext.getParameters().getParameters().get(0);
|
||||
modMailRoleService.removeRoleFromModMailRoles(role, commandContext.getUserInitiatedContext().getServer());
|
||||
modMailRoleService.removeRoleFromModMailRoles(role);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
|
||||
@@ -19,11 +19,14 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sends the reply from the staff member to the user, and shows the actual author in the created embed.
|
||||
*/
|
||||
@Component
|
||||
public class Reply extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private RequiresModMailCondition requiresModMailCondition;
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadService modMailThreadService;
|
||||
|
||||
@@ -15,6 +15,10 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command is used to change the category used to create new mod mail threads. This does not migrate the
|
||||
* existing mod mail threads.
|
||||
*/
|
||||
@Component
|
||||
public class SetModMailCategory extends AbstractConditionableCommand {
|
||||
|
||||
@@ -24,7 +28,7 @@ public class SetModMailCategory extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
Long categoryId = (Long) commandContext.getParameters().getParameters().get(0);
|
||||
modMailThreadService.setModMailCategoryTo(commandContext.getUserInitiatedContext().getServer(), categoryId);
|
||||
modMailThreadService.setModMailCategoryTo(commandContext.getGuild(), categoryId);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command is used to add roles to the roles being pinged when a new mod mail thread is opened.
|
||||
* The method this command uses automatically adds the mentioned roles to the roles which are allowed to execute
|
||||
* the mod mail related commands.
|
||||
*/
|
||||
@Component
|
||||
public class SetModMailRole extends AbstractConditionableCommand {
|
||||
|
||||
@@ -25,7 +30,7 @@ public class SetModMailRole extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
ARole role = (ARole) commandContext.getParameters().getParameters().get(0);
|
||||
modMailRoleService.addRoleToModMailRoles(role, commandContext.getUserInitiatedContext().getServer());
|
||||
modMailRoleService.addRoleToModMailRoles(role);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService;
|
||||
@@ -18,11 +18,16 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* This command subscribes the member executing this command to the {@link ModMailThread} in which the command was executed in.
|
||||
* In case the member is already subscribed an error message is displayed.
|
||||
*/
|
||||
@Component
|
||||
public class Subscribe extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private RequiresModMailCondition requiresModMailCondition;
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
|
||||
@@ -7,7 +7,7 @@ import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService;
|
||||
@@ -18,11 +18,16 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* This command un-subscribes the member executing this command from the {@link ModMailThread} in which the command was executed in.
|
||||
* In case the member is not subscribed an error message is displayed.
|
||||
*/
|
||||
@Component
|
||||
public class UnSubscribe extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private RequiresModMailCondition requiresModMailCondition;
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
|
||||
@@ -1,26 +1,35 @@
|
||||
package dev.sheldan.abstracto.modmail.commands.condition;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.Command;
|
||||
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
|
||||
import dev.sheldan.abstracto.core.command.condition.ConditionResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
|
||||
import dev.sheldan.abstracto.templating.service.TemplateService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This {@link dev.sheldan.abstracto.core.command.condition.CommandCondition} checks the channel it is executed in
|
||||
* and checks if the channel is a valid and open mod mail thread.
|
||||
*/
|
||||
@Component
|
||||
public class RequiresModMailCondition implements CommandCondition {
|
||||
public class RequiresModMailCondition implements ModMailContextCondition {
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Override
|
||||
public ConditionResult shouldExecute(CommandContext commandContext, Command command) {
|
||||
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
|
||||
if(thread != null) {
|
||||
return ConditionResult.builder().result(true).build();
|
||||
}
|
||||
return ConditionResult.builder().result(false).reason("Not in a mod mail thread.").build();
|
||||
String text = templateService.renderSimpleTemplate("modmail_not_in_modmail_thread");
|
||||
return ConditionResult.builder().result(false).reason(text).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import static dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean.MODMAIL_CLOSING_MESSAGE_TEXT;
|
||||
|
||||
/**
|
||||
* This listener is used to used to set the initial values of some server specific values, so we dont need to fall
|
||||
* back to the default values. The values might not be functional, for example mod mail category id, but their existence
|
||||
* makes things easier
|
||||
*/
|
||||
@Component
|
||||
public class ModMailConfigListener implements ServerConfigListener {
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean.MODMAIL_CLOSING_MESSAGE_TEXT;
|
||||
|
||||
/**
|
||||
* This listener is executed when the Spring context starts up and is used to set some default values related
|
||||
* to mod mail.
|
||||
*/
|
||||
@Component
|
||||
public class ModMailDefaultConfigListener {
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package dev.sheldan.abstracto.modmail.listener;
|
||||
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.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
@@ -14,6 +16,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This listener is the core mechanic behind mod mail, if the bot receives a message via DM, this listener is executed
|
||||
* and checks if the message should be forwarded to an existing mod mail thread, or if a new thread should be created/the
|
||||
* user should be prompted for a new mod mail thread.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ModMailMessageListener implements PrivateMessageReceivedListener {
|
||||
@@ -27,12 +36,17 @@ public class ModMailMessageListener implements PrivateMessageReceivedListener {
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void execute(Message message) {
|
||||
AUser user = userManagementService.loadUser(message.getAuthor().getIdLong());
|
||||
ModMailThread existingThread = modMailThreadManagementService.getOpenModmailThreadForUser(user);
|
||||
if(existingThread != null) {
|
||||
if(modMailThreadManagementService.hasOpenModMailThread(user)) {
|
||||
// there is only one open mod mail thread for a user at a time, so we can select the first one
|
||||
// we cannot use the AUserInAServer directly, because a message in a private channel does not have a Member
|
||||
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadsForUser(user).get(0);
|
||||
modMailThreadService.relayMessageToModMailThread(existingThread, message);
|
||||
} else {
|
||||
modMailThreadService.createModMailPrompt(user, message);
|
||||
|
||||
@@ -7,6 +7,9 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository to manage the stored {@link ModMailMessage} instances
|
||||
*/
|
||||
@Repository
|
||||
public interface ModMailMessageRepository extends JpaRepository<ModMailMessage, Long> {
|
||||
List<ModMailMessage> findByThreadReference(ModMailThread modMailThread);
|
||||
|
||||
@@ -8,6 +8,9 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository to manage the stored {@link ModMailRole} instances
|
||||
*/
|
||||
@Repository
|
||||
public interface ModMailRoleRepository extends JpaRepository<ModMailRole, Long> {
|
||||
boolean existsByServerAndRole(AServer server, ARole role);
|
||||
|
||||
@@ -8,6 +8,9 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository to manage the stored {@link ModMailThreadSubscriber} instances
|
||||
*/
|
||||
@Repository
|
||||
public interface ModMailSubscriberRepository extends JpaRepository<ModMailThreadSubscriber, Long> {
|
||||
List<ModMailThreadSubscriber> findByThreadReference(ModMailThread thread);
|
||||
|
||||
@@ -11,13 +11,18 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository to manage the stored {@link ModMailThread} instances
|
||||
*/
|
||||
@Repository
|
||||
public interface ModMailThreadRepository extends JpaRepository<ModMailThread, Long> {
|
||||
ModMailThread findByChannel(AChannel channel);
|
||||
List<ModMailThread> findByUser(AUserInAServer aUserInAServer);
|
||||
ModMailThread findTopByUserOrderByClosedDesc(AUserInAServer aUserInAServer);
|
||||
ModMailThread findByUser_UserReferenceAndStateNot(AUser user, ModMailThreadState state);
|
||||
List<ModMailThread> findByUser_UserReferenceAndStateNot(AUser user, ModMailThreadState state);
|
||||
boolean existsByUser_UserReferenceAndStateNot(AUser user, ModMailThreadState state);
|
||||
List<ModMailThread> findByServerAndState(AServer server, ModMailThreadState state);
|
||||
ModMailThread findByUserAndStateNot(AUserInAServer userInAServer, ModMailThreadState state);
|
||||
boolean existsByUserAndStateNot(AUserInAServer userInAServer, ModMailThreadState state);
|
||||
List<ModMailThread> findByUserAndState(AUserInAServer userInAServer, ModMailThreadState state);
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
if(modMailMessages.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// all message must be from the same thread
|
||||
ModMailThread thread = modMailMessages.get(0).getThreadReference();
|
||||
List<ServerChannelMessage> messageIds = new ArrayList<>();
|
||||
modMailMessages.forEach(modMailMessage -> {
|
||||
ServerChannelMessage.ServerChannelMessageBuilder serverChannelMessageBuilder = ServerChannelMessage
|
||||
.builder()
|
||||
.messageId(modMailMessage.getMessageId());
|
||||
// if its not from a private chat, we need to set the server and channel ID in order to fetch the data
|
||||
if(Boolean.FALSE.equals(modMailMessage.getDmChannel())) {
|
||||
serverChannelMessageBuilder
|
||||
.channelId(modMailMessage.getThreadReference().getChannel().getId())
|
||||
@@ -42,6 +44,10 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
messageIds.add(serverChannelMessageBuilder.build());
|
||||
});
|
||||
List<CompletableFuture<Message>> messageFutures = new ArrayList<>();
|
||||
// add the place holder futures, which are then resolved one by one
|
||||
// because we cannot directly fetch the messages, in case they are in a private channel
|
||||
// the opening of a private channel is a rest operation it itself, so we need
|
||||
// to create the promises here already, else the list is empty for example
|
||||
modMailMessages.forEach(modMailMessage -> messageFutures.add(new CompletableFuture<>()));
|
||||
Optional<TextChannel> textChannelFromServer = botService.getTextChannelFromServer(thread.getServer().getId(), thread.getChannel().getId());
|
||||
if(textChannelFromServer.isPresent()) {
|
||||
@@ -49,6 +55,8 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
botService.getInstance().openPrivateChannelById(thread.getUser().getUserReference().getId()).queue(privateChannel -> {
|
||||
Iterator<CompletableFuture<Message>> iterator = messageFutures.iterator();
|
||||
messageIds.forEach(serverChannelMessage -> {
|
||||
// TODO fix out of order promises
|
||||
// depending what the source of the message is, we need to fetch the message from the correct channel
|
||||
if(serverChannelMessage.getChannelId() == null){
|
||||
privateChannel.retrieveMessageById(serverChannelMessage.getMessageId()).queue(message -> iterator.next().complete(message), throwable -> {
|
||||
log.info("Failed to load message in private channel with user {}", thread.getUser().getUserReference().getId());
|
||||
|
||||
@@ -3,7 +3,6 @@ package dev.sheldan.abstracto.modmail.service;
|
||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
||||
import dev.sheldan.abstracto.core.models.database.ARole;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -22,16 +21,16 @@ public class ModMailRoleServiceBean implements ModMailRoleService {
|
||||
private FeatureManagementService featureManagementService;
|
||||
|
||||
@Override
|
||||
public void addRoleToModMailRoles(ARole role, AServer server) {
|
||||
if(!modMailRoleManagementService.isRoleAlreadyAssigned(role, server)) {
|
||||
modMailRoleManagementService.addRoleToModMailRoles(role, server);
|
||||
public void addRoleToModMailRoles(ARole role) {
|
||||
if(!modMailRoleManagementService.isRoleAlreadyAssigned(role, role.getServer())) {
|
||||
modMailRoleManagementService.addRoleToModMailRoles(role, role.getServer());
|
||||
}
|
||||
commandService.allowFeatureForRole(ModMailFeatures.MOD_MAIL, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRoleFromModMailRoles(ARole role, AServer server) {
|
||||
modMailRoleManagementService.removeRoleFromModMailRoles(role, server);
|
||||
public void removeRoleFromModMailRoles(ARole role) {
|
||||
modMailRoleManagementService.removeRoleFromModMailRoles(role, role.getServer());
|
||||
commandService.disAllowFeatureForRole(ModMailFeatures.MOD_MAIL, role);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ModMailSubscriptionServiceBean implements ModMailSubscriptionServic
|
||||
if(!modMailSubscriberManagementService.isSubscribedToThread(aUserInAServer, modMailThread)){
|
||||
modMailSubscriberManagementService.createSubscriber(aUserInAServer, modMailThread);
|
||||
} else {
|
||||
throw new AlreadySubscribedException("The user is already subscribed to the thread.");
|
||||
throw new AlreadySubscribedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ModMailSubscriptionServiceBean implements ModMailSubscriptionServic
|
||||
if(modMailSubscriberManagementService.isSubscribedToThread(aUserInAServer, modMailThread)){
|
||||
modMailSubscriberManagementService.removeSubscriber(aUserInAServer, modMailThread);
|
||||
} else {
|
||||
throw new NotSubscribedException("The user is not subscribed to the thread.");
|
||||
throw new NotSubscribedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package dev.sheldan.abstracto.modmail.service;
|
||||
|
||||
import com.jagrosh.jdautilities.commons.waiter.EventWaiter;
|
||||
import com.jagrosh.jdautilities.menu.ButtonMenu;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.exception.PostTargetNotFoundException;
|
||||
import dev.sheldan.abstracto.core.exception.UserInServerNotFoundException;
|
||||
import dev.sheldan.abstracto.core.models.FeatureValidationResult;
|
||||
import dev.sheldan.abstracto.core.models.FullGuild;
|
||||
import dev.sheldan.abstracto.core.models.FullUser;
|
||||
import dev.sheldan.abstracto.core.models.UndoActionInstance;
|
||||
@@ -13,6 +16,7 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerService;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import dev.sheldan.abstracto.modmail.config.*;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailCategoryIdException;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadNotFoundException;
|
||||
import dev.sheldan.abstracto.modmail.models.database.*;
|
||||
import dev.sheldan.abstracto.modmail.models.dto.ServerChoice;
|
||||
@@ -21,6 +25,7 @@ import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagement
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailSubscriberManagementService;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
|
||||
import dev.sheldan.abstracto.modmail.validator.ModMailFeatureValidator;
|
||||
import dev.sheldan.abstracto.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.templating.service.TemplateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -39,9 +44,19 @@ import java.util.concurrent.ExecutionException;
|
||||
@Slf4j
|
||||
public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
|
||||
/**
|
||||
* The config key to use for the closing text
|
||||
*/
|
||||
public static final String MODMAIL_CLOSING_MESSAGE_TEXT = "modMailClosingText";
|
||||
/**
|
||||
* The config key to use for the ID of the category to create {@link MessageChannel} in
|
||||
*/
|
||||
public static final String MODMAIL_CATEGORY = "modmailCategory";
|
||||
/**
|
||||
* The template key used for default mod mail exceptions
|
||||
*/
|
||||
public static final String MODMAIL_EXCEPTION_GENERIC_TEMPLATE = "modmail_exception_generic";
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
|
||||
@@ -99,10 +114,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
@Autowired
|
||||
private ModMailFeatureValidator modMailFeatureValidator;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadServiceBean self;
|
||||
|
||||
/**
|
||||
* The emoji used when the user can decide for a server to open a mod mail thread in.
|
||||
*/
|
||||
private List<String> NUMBER_EMOJI = Arrays.asList("\u0031\u20e3", "\u0032\u20e3", "\u0033\u20e3",
|
||||
"\u0034\u20e3", "\u0035\u20e3", "\u0036\u20e3",
|
||||
"\u0037\u20e3", "\u0038\u20e3", "\u0039\u20e3",
|
||||
@@ -111,21 +131,32 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
|
||||
@Override
|
||||
public void createModMailThreadForUser(FullUser aUserInAServer, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated) {
|
||||
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, aUserInAServer.getAUserInAServer().getServerReference().getId());
|
||||
Long serverId = aUserInAServer.getAUserInAServer().getServerReference().getId();
|
||||
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId);
|
||||
User user = aUserInAServer.getMember().getUser();
|
||||
CompletableFuture<TextChannel> textChannel = channelService.createTextChannel(user.getName() + user.getDiscriminator(), aUserInAServer.getAUserInAServer().getServerReference(), categoryId);
|
||||
CompletableFuture<TextChannel> textChannelFuture = channelService.createTextChannel(user.getName() + user.getDiscriminator(), aUserInAServer.getAUserInAServer().getServerReference(), categoryId);
|
||||
|
||||
textChannel.thenAccept(channel -> {
|
||||
Long userInServerId = aUserInAServer.getAUserInAServer().getUserInServerId();
|
||||
textChannelFuture.thenAccept(channel -> {
|
||||
List<UndoActionInstance> undoActions = new ArrayList<>();
|
||||
undoActions.add(UndoActionInstance.getChannelDeleteAction(aUserInAServer.getAUserInAServer().getServerReference().getId(), channel.getIdLong()));
|
||||
undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, channel.getIdLong()));
|
||||
self.performModMailThreadSetup(aUserInAServer, initialMessage, channel, userInitiated, undoActions);
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to create mod mail thread", throwable);
|
||||
sendModMailFailure("modmail_exception_failed_to_create_mod_mail_thread", aUserInAServer.getAUserInAServer(), null, feedBackChannel, throwable);
|
||||
sendModMailFailure("modmail_exception_failed_to_create_mod_mail_thread", userInServerId, null, feedBackChannel, throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* this method is responsible for creating the instance in the database, sending the header in the newly created text channel and forwarding the initial message
|
||||
* by the user (if any), after this is complete, this method executes the method to perform the mod mail notification.
|
||||
* @param aUserInAServer The {@link FullUser} for which a {@link ModMailThread} is being created
|
||||
* @param initialMessage The {@link Message} which was sent by the user to open a thread, this is null, if the thread was oepend via a command
|
||||
* @param channel The created {@link TextChannel} in which the mod mail thread is dealth with
|
||||
* @param userInitiated Whether or not the thread was initiated by a member
|
||||
* @param undoActions The list of actions to undo, in case an exception occurs
|
||||
*/
|
||||
@Transactional
|
||||
public void performModMailThreadSetup(FullUser aUserInAServer, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) {
|
||||
try {
|
||||
@@ -148,6 +179,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the message containing the pings to notify the staff members to handle the opened {@link ModMailThread}
|
||||
* @param aUserInAServer The {@link FullUser} which opened the thread
|
||||
* @param thread The {@link ModMailThread} instance which was created
|
||||
* @param undoActions The list of {@link UndoActionInstance} to perform, in case an exception occurs
|
||||
*/
|
||||
@Transactional
|
||||
public void sendModMailNotification(FullUser aUserInAServer, ModMailThread thread, List<UndoActionInstance> undoActions) {
|
||||
List<ModMailRole> rolesToPing = modMailRoleManagementService.getRolesForServer(thread.getServer());
|
||||
@@ -167,6 +204,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the instance of the {@link ModMailThread} in the database.
|
||||
* @param channel The {@link TextChannel} in which the {@link ModMailThread} is being done
|
||||
* @param user The {@link FullUser} which the thread is about
|
||||
* @return The created instance of {@link ModMailThread}
|
||||
*/
|
||||
public ModMailThread createThreadObject(TextChannel channel, FullUser user) {
|
||||
AChannel channel2 = channelManagementService.createChannel(channel.getIdLong(), AChannelType.TEXT, user.getAUserInAServer().getServerReference());
|
||||
log.info("Creating mod mail thread in channel {} with db channel {}", channel.getIdLong(), channel2.getId());
|
||||
@@ -174,28 +217,26 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOpenThread(AUserInAServer aUserInAServer) {
|
||||
return modMailThreadManagementService.getOpenModmailThreadForUser(aUserInAServer) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOpenThread(AUser user) {
|
||||
return modMailThreadManagementService.getOpenModmailThreadForUser(user) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModMailCategoryTo(AServer server, Long categoryId) {
|
||||
configService.setLongValue(MODMAIL_CATEGORY, server.getId(), categoryId);
|
||||
public void setModMailCategoryTo(Guild guild, Long categoryId) {
|
||||
FeatureValidationResult result = FeatureValidationResult.builder().build();
|
||||
modMailFeatureValidator.validateModMailCategory(result, guild, categoryId);
|
||||
if(result.getValidationResult()) {
|
||||
throw new ModMailCategoryIdException(categoryId);
|
||||
}
|
||||
configService.setLongValue(MODMAIL_CATEGORY, guild.getIdLong(), categoryId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createModMailPrompt(AUser user, Message initialMessage) {
|
||||
List<AUserInAServer> knownServers = userInServerManagementService.getUserInAllServers(user.getId());
|
||||
// do nothing if we dont know the user
|
||||
if(!knownServers.isEmpty()) {
|
||||
List<ServerChoice> availableGuilds = new ArrayList<>();
|
||||
HashMap<String, AUserInAServer> choices = new HashMap<>();
|
||||
for (int i = 0; i < knownServers.size(); i++) {
|
||||
AUserInAServer aUserInAServer = knownServers.get(i);
|
||||
// only take the servers in which mod mail is actually enabled, would not make much sense to make the
|
||||
// other servers available
|
||||
if(featureFlagService.isFeatureEnabled(modMailFeature, aUserInAServer.getServerReference())) {
|
||||
AServer serverReference = aUserInAServer.getServerReference();
|
||||
FullGuild guild = FullGuild
|
||||
@@ -203,12 +244,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
.guild(botService.getGuildByIdNullable(serverReference.getId()))
|
||||
.server(serverReference)
|
||||
.build();
|
||||
// TODO support more than this limited amount of servers
|
||||
String reactionEmote = NUMBER_EMOJI.get(i);
|
||||
ServerChoice serverChoice = ServerChoice.builder().guild(guild).reactionEmote(reactionEmote).build();
|
||||
choices.put(reactionEmote, aUserInAServer);
|
||||
availableGuilds.add(serverChoice);
|
||||
}
|
||||
}
|
||||
// if more than 1 server is available, show a choice dialog
|
||||
if(availableGuilds.size() > 1) {
|
||||
ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel
|
||||
.builder()
|
||||
@@ -227,14 +270,29 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
})
|
||||
.build();
|
||||
menu.display(initialMessage.getChannel());
|
||||
} else if(availableGuilds.size() == 1) {
|
||||
// if exactly one server is available, open the thread directly
|
||||
AUserInAServer chosenServer = choices.get(availableGuilds.get(0).getReactionEmote());
|
||||
Member memberInServer = botService.getMemberInServer(chosenServer);
|
||||
FullUser fullUser = FullUser.builder().member(memberInServer).aUserInAServer(chosenServer).build();
|
||||
self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true);
|
||||
} else {
|
||||
// in case there is no server available, send an error message
|
||||
channelService.sendEmbedTemplateInChannel("modmail_no_server_available", new Object(), initialMessage.getChannel());
|
||||
}
|
||||
|
||||
} else {
|
||||
log.warn("User which was not known in any of the servers tried to contact the bot. {}", user.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method used to send the header of a newly created mod mail thread. This message contains information about
|
||||
* the user which the thread is about
|
||||
* @param channel The {@link TextChannel} in which the mod mail thread is present in
|
||||
* @param aUserInAServer The {@link AUserInAServer} which the {@link ModMailThread} is about
|
||||
* @param undoActions The list of {@link UndoActionInstance} to execute in case an exception occurs
|
||||
*/
|
||||
private void sendModMailHeader(TextChannel channel, FullUser aUserInAServer, List<UndoActionInstance> undoActions) {
|
||||
ModMailThread latestThread = modMailThreadManagementService.getLatestModMailThread(aUserInAServer.getAUserInAServer());
|
||||
List<ModMailThread> oldThreads = modMailThreadManagementService.getModMailThreadForUser(aUserInAServer.getAUserInAServer());
|
||||
@@ -267,6 +325,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This message takes a received {@link Message} from a user, renders it to a new message to send and sends it to
|
||||
* the appropriate {@link ModMailThread} channel, the returned promise only returns if the message was dealt with on the user
|
||||
* side.
|
||||
* @param textChannel The {@link TextChannel} in which the {@link ModMailThread} is being handled
|
||||
* @param modMailThread The {@link ModMailThread} to which the received {@link Message} is a reply to
|
||||
* @param message The received message from the user
|
||||
* @return A {@link CompletableFuture} which resolves when the post processing of the message is completed (adding read notification, and storing messageIDs)
|
||||
*/
|
||||
public CompletableFuture<Void> sendUserReply(TextChannel textChannel, ModMailThread modMailThread, Message message) {
|
||||
Long modMailThreadId = modMailThread.getId();
|
||||
FullUser fullUser = FullUser
|
||||
@@ -300,6 +367,14 @@ 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 modMailThreadId The ID of the {@link ModMailThread} for which the message was directed to
|
||||
* @param message The actual {@link Message} instance received from the user.
|
||||
* @param completableFutures The list of {@link CompletableFuture} which were rendered from the sent message
|
||||
* and posted in the {@link ModMailThread} by Abstracto
|
||||
*/
|
||||
@Transactional
|
||||
public void postProcessSendMessages(Long modMailThreadId, Message message, List<CompletableFuture<Message>> completableFutures) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
|
||||
@@ -315,7 +390,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
self.saveMessageIds(messages, modMailThread, modMailThread.getUser(), false, false);
|
||||
// update the state of the thread
|
||||
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.USER_REPLIED);
|
||||
// add the reaction to show that the message has been processed
|
||||
messageService.addReactionToMessage("readReaction", modMailThread.getServer().getId(), message);
|
||||
});
|
||||
} else {
|
||||
@@ -336,9 +413,21 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the staff members in the thread about any exception occurring when executing a command in a {@link ModMailThread}.
|
||||
* This takes a custom template which is rendered and a generic model is provided.
|
||||
* @param template The key of the {@link dev.sheldan.abstracto.templating.model.database.Template} to use
|
||||
* @param userInServerId The ID of the user in the server which the {@link ModMailThread} is about
|
||||
* @param modMailTreadId The ID of the {@link ModMailThread} in which an exception occurred
|
||||
* @param channel The {@link MessageChannel} in to which the exception message should be sent to
|
||||
* @param throwable The instance of the {@link Throwable} which happened.
|
||||
* @throws UserInServerNotFoundException in case the {@link AUserInAServer} was not found by the ID
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} was not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
public void sendModMailFailure(String template, AUserInAServer aUserInAServer, Long modMailTreadId, MessageChannel channel, Throwable throwable) {
|
||||
public void sendModMailFailure(String template, Long userInServerId, Long modMailTreadId, MessageChannel channel, Throwable throwable) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailTreadId);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(userInServerId).orElseThrow(() -> new UserInServerNotFoundException(userInServerId));
|
||||
if(modMailThreadOpt.isPresent()) {
|
||||
ModMailThread modMailThread = modMailThreadOpt.get();
|
||||
try {
|
||||
@@ -363,10 +452,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser) {
|
||||
public void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser) {
|
||||
AFeatureMode aFeatureMode = featureModeService.getFeatureMode(ModMailFeatures.MOD_MAIL, modMailThread.getServer());
|
||||
boolean loggingMode = aFeatureMode.getMode().equalsIgnoreCase(ModMailMode.LOGGING.getKey());
|
||||
closeModMailThread(modMailThread, feedBack, note, notifyUser, loggingMode);
|
||||
closeModMailThread(modMailThread, feedBack, note, notifyUser, loggingMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -404,7 +493,19 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param feedBack The {@link MessageChannel} in which possible feedback about exceptions is sent to
|
||||
* @param note The note which was provided when closing the {@link ModMailThread}
|
||||
* @param notifyUser Whether or not to notify the user
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} which is being closed
|
||||
* @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions
|
||||
* @param messages The list of loaded {@link Message} to log
|
||||
* @param innerModMailThread An instance of {@link ModMailThread} which is getting closed
|
||||
*/
|
||||
private void logMessagesToModMailLog(MessageChannel feedBack, String note, Boolean notifyUser, Long modMailThreadId, List<UndoActionInstance> undoActions, List<CompletableFuture<Message>> messages, ModMailThread innerModMailThread) {
|
||||
Long userInServerId = innerModMailThread.getUser().getUserInServerId();
|
||||
try {
|
||||
CompletableFutureList<Message> list = self.logModMailThread(modMailThreadId, messages, note);
|
||||
list.getMainFuture().thenRun(() -> {
|
||||
@@ -422,19 +523,28 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
self.afterSuccessfulLog(modMailThreadId, feedBack, notifyUser, undoActions);
|
||||
});
|
||||
list.getMainFuture().exceptionally(innerThrowable -> {
|
||||
sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, innerModMailThread.getUser(), modMailThreadId, feedBack, innerThrowable);
|
||||
sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, userInServerId, modMailThreadId, feedBack, innerThrowable);
|
||||
log.error("Failed to log messages for mod mail thread {}.", modMailThreadId, innerThrowable);
|
||||
return null;
|
||||
});
|
||||
} catch (PostTargetNotFoundException po) {
|
||||
log.error("Failed to log mod mail messages", po);
|
||||
sendModMailFailure("modmail_exception_post_target_not_defined", innerModMailThread.getUser(), modMailThreadId, feedBack, po);
|
||||
sendModMailFailure("modmail_exception_post_target_not_defined", userInServerId, modMailThreadId, feedBack, po);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to log mod mail messages", e);
|
||||
sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, innerModMailThread.getUser(), modMailThreadId, feedBack, e);
|
||||
sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, userInServerId, modMailThreadId, feedBack, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This message is executed after the thread has been logged and notifies the user about the closed {@link ModMailThread}
|
||||
* which a configurable closing text. This method then calls the method to delete the channel.
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} which is being closed.
|
||||
* @param feedBack The {@link MessageChannel} in which exceptions should be sent to
|
||||
* @param notifyUser Whether or not the user should be notified
|
||||
* @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
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);
|
||||
@@ -463,7 +573,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to render closing user message", e);
|
||||
sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, modMailThread.getUser(), modMailThreadId, feedBack, e);
|
||||
Long userInServerId = modMailThread.getUser().getUserInServerId();
|
||||
sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, userInServerId, modMailThreadId, feedBack, e);
|
||||
}
|
||||
}, throwable -> {
|
||||
log.error("Failed to load private channel with user {}", user.getIdLong(), throwable);
|
||||
@@ -474,6 +585,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the actual {@link MessageChannel} in which the {@link ModMailThread} happened. This method then calls the
|
||||
* method to update the stats in the database
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} to delete the {@link MessageChannel} from
|
||||
* @param feedBack The {@link MessageChannel} in which exceptions should be sent to
|
||||
* @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
public void deleteChannelAndClose(Long modMailThreadId, MessageChannel feedBack, List<UndoActionInstance> undoActions) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
|
||||
@@ -495,7 +614,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
} catch (InsufficientPermissionException ex) {
|
||||
log.error(failureMessage, modMailThreadId, ex);
|
||||
undoActionService.performActions(undoActions);
|
||||
sendModMailFailure("modmail_exception_cannot_delete_channel", modMailThread.getUser(), modMailThreadId, feedBack, ex);
|
||||
sendModMailFailure("modmail_exception_cannot_delete_channel", modMailThread.getUser().getUserInServerId(), modMailThreadId, feedBack, ex);
|
||||
} catch (Exception ex) {
|
||||
log.error(failureMessage, modMailThreadId, ex);
|
||||
undoActionService.performActions(undoActions);
|
||||
@@ -506,13 +625,25 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the list of {@link CompletableFuture} which are returned from retrieving the {@link Message} to log,
|
||||
* and creates the models necessary to render the log entries. This message also sends the closing header in the
|
||||
* log concerning general information about the closed {@link ModMailThread}
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} to log the messages of
|
||||
* @param messages The list of {@link CompletableFuture} which contain the {@link Message} which could be loaded
|
||||
* @param note The note which was entered when closing the {@link ModMailThread}
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
* @return An instance of {@link CompletableFutureList}, which contains a main {@link CompletableFuture} which is resolved,
|
||||
* when all of the smaller {@link CompletableFuture} in it are resolved. We need this construct, because we need to access
|
||||
* the result values of the individual futures after they are done.
|
||||
*/
|
||||
@Transactional
|
||||
public CompletableFutureList<Message> logModMailThread(Long modMailThreadId, List<CompletableFuture<Message>> messages, String note) {
|
||||
log.info("Logging mod mail thread {}.", modMailThreadId);
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
|
||||
if(modMailThreadOpt.isPresent()) {
|
||||
ModMailThread modMailThread = modMailThreadOpt.get();
|
||||
List<ModMailLoggedMessage> loggedMessages = new ArrayList<>();
|
||||
List<ModMailLoggedMessageModel> loggedMessages = new ArrayList<>();
|
||||
messages.forEach(future -> {
|
||||
try {
|
||||
if(!future.isCompletedExceptionally()) {
|
||||
@@ -521,15 +652,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
ModMailMessage modmailMessage = modMailThread.getMessages()
|
||||
.stream()
|
||||
.filter(modMailMessage -> modMailMessage.getMessageId().equals(loadedMessage.getIdLong()))
|
||||
.findFirst().get();
|
||||
ModMailLoggedMessage modMailLoggedMessage =
|
||||
ModMailLoggedMessage
|
||||
.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."));
|
||||
ModMailLoggedMessageModel modMailLoggedMessageModel =
|
||||
ModMailLoggedMessageModel
|
||||
.builder()
|
||||
.message(loadedMessage)
|
||||
.modMailMessage(modmailMessage)
|
||||
.author(userInServerService.getFullUser(modmailMessage.getAuthor()))
|
||||
.build();
|
||||
loggedMessages.add(modMailLoggedMessage);
|
||||
loggedMessages.add(modMailLoggedMessageModel);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
@@ -562,6 +693,11 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ModMailThread} in the database to CLOSED.
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} to update the state of
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
public void closeModMailThreadInDb(Long modMailThreadId) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
|
||||
@@ -574,7 +710,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
public List<CompletableFuture<Message>> sendMessagesToPostTarget(ModMailThread modMailThread, List<ModMailLoggedMessage> loadedMessages) {
|
||||
/**
|
||||
* Renders the retrieved {@link Message} which are in {@link ModMailLoggedMessageModel} into {@link MessageToSend} and
|
||||
* sends this to the appropriate logging {@link PostTarget}
|
||||
* @param modMailThread The {@link ModMailThread} to which the loaded messages belong to
|
||||
* @param loadedMessages The list of {@link ModMailLoggedMessageModel} which can be rendered
|
||||
* @return A list of {@link CompletableFuture} which represent each of the messages being send to the {@link PostTarget}
|
||||
*/
|
||||
public List<CompletableFuture<Message>> sendMessagesToPostTarget(ModMailThread modMailThread, List<ModMailLoggedMessageModel> loadedMessages) {
|
||||
List<CompletableFuture<Message>> messageFutures = new ArrayList<>();
|
||||
loadedMessages.forEach(message -> {
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_logged_message", message);
|
||||
@@ -584,6 +727,17 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
return messageFutures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the reply which was done by a staff member to the private channel with the {@link Member} and calls the
|
||||
* method for saving the messages and updating the status
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} for which the reply was created for
|
||||
* @param text The text the reply should contain
|
||||
* @param message The original message which triggered the command to create the reply. This is necessary for attachments
|
||||
* @param privateChannel The instance of a {@link PrivateChannel} which was opened with the user and is used to send messages
|
||||
* @param anonymous Whether or not the reply should be anonymous
|
||||
* @param feedBack The {@link MessageChannel} in which exceptions should be sent to
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
public void sendReply(Long modMailThreadId, String text, Message message, PrivateChannel privateChannel, Boolean anonymous, MessageChannel feedBack) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
|
||||
@@ -591,7 +745,6 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
ModMailThread modMailThread = modMailThreadOpt.get();
|
||||
AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember());
|
||||
Member userInGuild = botService.getMemberInServer(modMailThread.getUser());
|
||||
Member moderatorMember = botService.getMemberInServer(moderator);
|
||||
FullUser fullThreadUser = FullUser
|
||||
.builder()
|
||||
.aUserInAServer(modMailThread.getUser())
|
||||
@@ -607,16 +760,18 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
if(anonymous) {
|
||||
modMailModeratorReplyModelBuilder.moderator(botService.getBotInGuild(modMailThread.getServer()));
|
||||
} else {
|
||||
Member moderatorMember = botService.getMemberInServer(moderator);
|
||||
modMailModeratorReplyModelBuilder.moderator(moderatorMember);
|
||||
}
|
||||
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_staff_message", modMailUserReplyModel);
|
||||
Long userInServerId = modMailThread.getUser().getUserInServerId();
|
||||
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, privateChannel);
|
||||
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid ->
|
||||
self.saveSendMessagesAndUpdateState(modMailThreadId, anonymous, moderator, completableFutures)
|
||||
).exceptionally(throwable -> {
|
||||
log.error("Failed to send message to user {}", modMailThread.getUser().getUserReference().getId());
|
||||
sendModMailFailure("modmail_exception_cannot_message_user", modMailThread.getUser(), modMailThread.getId(), feedBack, throwable);
|
||||
log.error("Failed to send message to user in server {}", userInServerId);
|
||||
sendModMailFailure("modmail_exception_cannot_message_user", userInServerId, modMailThread.getId(), feedBack, throwable);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
@@ -625,6 +780,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the promises which were created when sending the messages to the private channel and stores the message IDs
|
||||
* and updates the state of the {@link ModMailThread}.
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} for which the messages were sent for
|
||||
* @param anonymous Whether or not the messages were send anonymous
|
||||
* @param moderator The original {@link AUserInAServer} which authored the messages
|
||||
* @param completableFutures The list of {@link CompletableFuture} which contain the {@link Message} which were sent to the member
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
public void saveSendMessagesAndUpdateState(Long modMailThreadId, Boolean anonymous, AUserInAServer moderator, List<CompletableFuture<Message>> completableFutures) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
|
||||
@@ -649,6 +813,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the list of {@link Message} and attaches them to the given {@link ModMailThread} as {@link ModMailMessage} which should possibly
|
||||
* be logged at a later time
|
||||
* @param messages The list of {@link Message} to store the IDs of
|
||||
* @param modMailThread The {@link ModMailThread} which should have the messages attached
|
||||
* @param author The {@link AUserInAServer} who authored the {@link Message}
|
||||
* @param anonymous Whether or not the {@link Message} was anonymous
|
||||
* @param inDmChannel Whether or not the {@link Message} was sent in a private channel
|
||||
*/
|
||||
public void saveMessageIds(List<Message> messages, ModMailThread modMailThread, AUserInAServer author, Boolean anonymous, Boolean inDmChannel) {
|
||||
messages.forEach(message ->
|
||||
modMailMessageManagementService.addMessageToThread(modMailThread, message, author, anonymous, inDmChannel)
|
||||
|
||||
@@ -47,15 +47,25 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModMailThread getOpenModmailThreadForUser(AUserInAServer userInAServer) {
|
||||
public ModMailThread getOpenModMailThreadForUser(AUserInAServer userInAServer) {
|
||||
return modMailThreadRepository.findByUserAndStateNot(userInAServer, ModMailThreadState.CLOSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModMailThread getOpenModmailThreadForUser(AUser user) {
|
||||
public boolean hasOpenModMailThreadForUser(AUserInAServer userInAServer) {
|
||||
return modMailThreadRepository.existsByUserAndStateNot(userInAServer, ModMailThreadState.CLOSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModMailThread> getOpenModMailThreadsForUser(AUser user) {
|
||||
return modMailThreadRepository.findByUser_UserReferenceAndStateNot(user, ModMailThreadState.CLOSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOpenModMailThread(AUser user) {
|
||||
return modMailThreadRepository.existsByUser_UserReferenceAndStateNot(user, ModMailThreadState.CLOSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModMailThread> getModMailThreadForUser(AUserInAServer aUserInAServer) {
|
||||
return modMailThreadRepository.findByUser(aUserInAServer);
|
||||
@@ -66,6 +76,12 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
|
||||
return modMailThreadRepository.findTopByUserOrderByClosedDesc(aUserInAServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* The status of the created instance is INITIAL.
|
||||
* @param userInAServer The {@link AUserInAServer} for which the thread was created for
|
||||
* @param channel An instance of {@link AChannel} in which the conversation with the member is handled
|
||||
* @return the created {@link ModMailThread} instance
|
||||
*/
|
||||
@Override
|
||||
public ModMailThread createModMailThread(AUserInAServer userInAServer, AChannel channel) {
|
||||
ModMailThread thread = ModMailThread
|
||||
|
||||
@@ -3,6 +3,10 @@ package dev.sheldan.abstracto.modmail.setup;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.templating.Templatable;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the provided category used for creating mod mail thread is not valid.
|
||||
* (If it does not exist in the guild)
|
||||
*/
|
||||
public class InvalidCategoryException extends AbstractoRunTimeException implements Templatable {
|
||||
public InvalidCategoryException() {
|
||||
super("");
|
||||
|
||||
@@ -7,19 +7,34 @@ import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This delayed action is responsible for setting the system configuration of the mod mail category for a given server
|
||||
*/
|
||||
@Component
|
||||
public class ModMailCategoryDelayedAction implements DelayedAction {
|
||||
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
/**
|
||||
* Sets the config key of MODMAIL_CATEGORY to the given category ID contained in the {@link DelayedActionConfig}
|
||||
* @param delayedActionConfig An instance of {@link ModMailCategoryDelayedActionConfig} containing the ID
|
||||
* of the {@link net.dv8tion.jda.api.entities.Category} and the ID of the
|
||||
* {@link net.dv8tion.jda.api.entities.Guild} to change
|
||||
*/
|
||||
@Override
|
||||
public void execute(DelayedActionConfig delayedActionConfig) {
|
||||
ModMailCategoryDelayedActionConfig concrete = (ModMailCategoryDelayedActionConfig) delayedActionConfig;
|
||||
configService.setConfigValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, concrete.getServerId(), concrete.getValue());
|
||||
configService.setLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, concrete.getServerId(), concrete.getCategoryId());
|
||||
}
|
||||
|
||||
/**
|
||||
* This delayed action only reacts to delayed action configurations of typ {@link ModMailCategoryDelayedActionConfig}.
|
||||
* As this the instance bound to this {@link DelayedAction}
|
||||
* @param delayedActionConfig An instance of check whether or not this {@link DelayedAction} should be executed for this
|
||||
* {@link DelayedActionConfig}
|
||||
* @return Whether or not the passed {@link DelayedActionConfig} is going to be handled by this class.
|
||||
*/
|
||||
@Override
|
||||
public boolean handles(DelayedActionConfig delayedActionConfig) {
|
||||
return delayedActionConfig instanceof ModMailCategoryDelayedActionConfig;
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
package dev.sheldan.abstracto.modmail.setup;
|
||||
|
||||
import dev.sheldan.abstracto.core.interactive.DelayedActionConfig;
|
||||
import dev.sheldan.abstracto.core.models.database.AConfig;
|
||||
import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryActionModel;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Category;
|
||||
|
||||
/**
|
||||
* This represents both an instance of a {@link DelayedActionConfig} used to be executed in the
|
||||
* {@link dev.sheldan.abstracto.core.service.DelayedActionService} and, as all {@link DelayedActionConfig}, as a
|
||||
* model when all setup steps are presented, and the member executing the setup command needs to confirm the changes.
|
||||
* This model is responsible to contain the values needed to displayed the mod mail category changes.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailCategoryDelayedActionConfig implements DelayedActionConfig {
|
||||
private Long serverId;
|
||||
private AConfig value;
|
||||
private Long categoryId;
|
||||
private Category category;
|
||||
|
||||
@Override
|
||||
@@ -26,7 +31,7 @@ public class ModMailCategoryDelayedActionConfig implements DelayedActionConfig {
|
||||
return ModMailCategoryActionModel
|
||||
.builder()
|
||||
.category(this.category)
|
||||
.categoryId(value.getLongValue())
|
||||
.categoryId(categoryId)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import dev.sheldan.abstracto.core.interactive.*;
|
||||
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
|
||||
import dev.sheldan.abstracto.core.models.FeatureValidationResult;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AConfig;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.BotService;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
@@ -61,6 +60,19 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
|
||||
@Autowired
|
||||
private BotService botService;
|
||||
|
||||
/**
|
||||
* This setup method loads the existing mod mail category (if anything) and populates the model used to render the prompt.
|
||||
* This method will then render the prompt and wait for the users input, if the provided input was a valid
|
||||
* category ID in the current server, this method returns the proper result. If anything else is put in (except the input
|
||||
* triggering a cancellation) this this method will jump back to this step and prompt the user again.
|
||||
* @param user The {@link AServerChannelUserId} context required in order to execute the step. This is needed
|
||||
* to check if the returned message is from the same user and to see for which server
|
||||
* we need to change the mod mail category for
|
||||
* @param parameter This is a parameter which contains the previous message triggering the setup step.
|
||||
* This is necessary, because sometimes the {@link Message} executing the setup was also triggering
|
||||
* the first {@link SetupStep}, so, if we are aware of it, we can ignore it
|
||||
* @return A {@link CompletableFuture} containing the {@link SetupStepResult}. This might be cancelled or successful.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<SetupStepResult> execute(AServerChannelUserId user, SetupStepParameter parameter) {
|
||||
String messageTemplateKey = "setup_modmail_category_message";
|
||||
@@ -78,6 +90,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
|
||||
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId());
|
||||
|
||||
// very odd case, if the channel the command was executed in, was not found in the database.
|
||||
if(channel.isPresent()) {
|
||||
Runnable finalAction = getTimeoutRunnable(user.getGuildId(), user.getChannelId());
|
||||
Consumer<MessageReceivedEvent> configAction = (MessageReceivedEvent event) -> {
|
||||
@@ -85,21 +98,23 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
|
||||
|
||||
SetupStepResult result;
|
||||
Message message = event.getMessage();
|
||||
// this checks whether or not the user wanted to cancel the setup
|
||||
if(checkForExit(message)) {
|
||||
result = SetupStepResult.fromCancelled();
|
||||
} else {
|
||||
String messageContent = event.getMessage().getContentRaw();
|
||||
// directly parse the long from the message, for *now*, only the category ID is supported
|
||||
Long categoryId = Long.parseLong(messageContent);
|
||||
Guild guild = botService.getGuildByIdNullable(user.getGuildId());
|
||||
FeatureValidationResult featureValidationResult = FeatureValidationResult.builder().validationResult(true).build();
|
||||
// directly validate whether or not the given category ID is a valid value
|
||||
modMailFeatureValidator.validateModMailCategory(featureValidationResult, guild, categoryId);
|
||||
if(Boolean.FALSE.equals(featureValidationResult.getValidationResult())) {
|
||||
AConfig fakeValue = configService.getFakeConfigForValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, user.getGuildId(), messageContent);
|
||||
if(Boolean.TRUE.equals(featureValidationResult.getValidationResult())) {
|
||||
ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig
|
||||
.builder()
|
||||
.serverId(user.getGuildId())
|
||||
.category(guild.getCategoryById(categoryId))
|
||||
.value(fakeValue)
|
||||
.categoryId(categoryId)
|
||||
.build();
|
||||
List<DelayedActionConfig> delayedSteps = Arrays.asList(build);
|
||||
result = SetupStepResult
|
||||
@@ -108,6 +123,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
|
||||
.delayedActionConfigList(delayedSteps)
|
||||
.build();
|
||||
} else {
|
||||
// exceptions this exception is used to effectively fail the setup step
|
||||
throw new InvalidCategoryException();
|
||||
}
|
||||
|
||||
@@ -115,7 +131,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
|
||||
|
||||
future.complete(result);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to handle post target step.", e);
|
||||
log.error("Failed to handle mod mail category step.", e);
|
||||
future.completeExceptionally(new SetupStepException(e));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.service.BotService;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureValidatorService;
|
||||
import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryValidationError;
|
||||
import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryValidationErrorModel;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
|
||||
import net.dv8tion.jda.api.entities.Category;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
@@ -15,6 +15,11 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* This component is used to validate whether or not the mod mail feature has a mod mail category configured, which points to
|
||||
* a category on the server it is configured for. This and other {@link dev.sheldan.abstracto.core.service.FeatureValidator}
|
||||
* are used to fully validate the mod mail feature.
|
||||
*/
|
||||
@Component
|
||||
public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
|
||||
|
||||
@@ -27,6 +32,12 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
|
||||
@Autowired
|
||||
private FeatureValidatorService featureValidatorService;
|
||||
|
||||
/**
|
||||
* Checks if the mod mail category contains a value and whether or not this valid also points to a {@link Category}
|
||||
* @param featureConfig The instance of {@link FeatureConfig} of mod mail
|
||||
* @param server The {@link AServer} to check the config for
|
||||
* @param validationResult The current {@link FeatureValidationResult} used to accumulate the wrong values
|
||||
*/
|
||||
@Override
|
||||
public void featureIsSetup(FeatureConfig featureConfig, AServer server, FeatureValidationResult validationResult) {
|
||||
Optional<Guild> guildById = botService.getGuildById(server.getId());
|
||||
@@ -40,15 +51,21 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the category and checks if the given ID is a valid category in the given {@link Guild}
|
||||
* @param validationResult The object in which the result of the validation will be stored
|
||||
* @param guild The {@link Guild} to check for the category
|
||||
* @param modMailCategory The configured ID of the category
|
||||
*/
|
||||
public void validateModMailCategory(FeatureValidationResult validationResult, Guild guild, Long modMailCategory) {
|
||||
Category categoryById = guild.getCategoryById(modMailCategory);
|
||||
if(categoryById == null) {
|
||||
validationResult.setValidationResult(false);
|
||||
ModMailCategoryValidationError newError = ModMailCategoryValidationError
|
||||
ModMailCategoryValidationErrorModel newError = ModMailCategoryValidationErrorModel
|
||||
.builder()
|
||||
.currentCategoryId(modMailCategory)
|
||||
.build();
|
||||
validationResult.getValidationErrors().add(newError);
|
||||
validationResult.getValidationErrorModels().add(newError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<#assign categoryName><#if category?has_content>${category.name}<#else><#include "setup_modmail_category_message_no_category">></#if></#assign><#include "setup_modmail_category_message_display">
|
||||
<#assign categoryName><#if category?has_content>${category.name}<#else><#include "setup_modmail_category_message_no_category"></#if></#assign><#include "setup_modmail_category_message_display">
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.modmail.condition;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
|
||||
|
||||
/**
|
||||
* This condition represents the condition that the command can only be executed while the member
|
||||
* is within a mod mail channel.
|
||||
*/
|
||||
public interface ModMailContextCondition extends CommandCondition {
|
||||
}
|
||||
@@ -14,6 +14,9 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* General instance of {@link FeatureConfig} to establish the mod mail feature
|
||||
*/
|
||||
@Component
|
||||
public class ModMailFeature implements FeatureConfig {
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@ package dev.sheldan.abstracto.modmail.config;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* This enum defines the to {@link FeatureMode} mod mail has.
|
||||
* Either closed mod mail threads are logged, or they are not logged to the respective post target.
|
||||
*/
|
||||
@Getter
|
||||
public enum ModMailMode implements FeatureMode {
|
||||
LOGGING("log"), NO_LOG("nolog");
|
||||
|
||||
@@ -5,7 +5,14 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ModMailPostTargets implements PostTargetEnum {
|
||||
MOD_MAIL_PING("modmailPing"), MOD_MAIL_LOG("modmailLog");
|
||||
/**
|
||||
* The channel to be used for notifying the users about new mod mail threads
|
||||
*/
|
||||
MOD_MAIL_PING("modmailPing"),
|
||||
/**
|
||||
* The channel to be used to log the contents of closed mod mail threads
|
||||
*/
|
||||
MOD_MAIL_LOG("modmailLog");
|
||||
|
||||
private String key;
|
||||
|
||||
|
||||
@@ -3,9 +3,12 @@ package dev.sheldan.abstracto.modmail.exception;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.templating.Templatable;
|
||||
|
||||
/**
|
||||
* This exception is thrown then you try to subscribe to a mod mail thread, to which you are already subscribed to
|
||||
*/
|
||||
public class AlreadySubscribedException extends AbstractoRunTimeException implements Templatable {
|
||||
public AlreadySubscribedException(String message) {
|
||||
super(message);
|
||||
public AlreadySubscribedException() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.sheldan.abstracto.modmail.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.templating.Templatable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a {@link net.dv8tion.jda.api.entities.Member} tries to set the mod mail category
|
||||
* via a command, and the new value does not qualify as a valid {@link net.dv8tion.jda.api.entities.Category}
|
||||
* in the member executes the command in
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ModMailCategoryIdException extends AbstractoRunTimeException implements Templatable {
|
||||
private Long categoryId;
|
||||
|
||||
public ModMailCategoryIdException(Long categoryId) {
|
||||
super("");
|
||||
this.categoryId = categoryId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "modmail_category_not_setup";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
HashMap<String, Long> params = new HashMap<>();
|
||||
params.put("categoryId", this.categoryId);
|
||||
return params;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,10 @@ import dev.sheldan.abstracto.templating.Templatable;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This exception is raised, when for some reason the mod mail thread is not found in the database anymore, but the context which is executed stems from a mod mail thread.
|
||||
* For example if it is attempted to log a thread, without the thread existing in the database.
|
||||
*/
|
||||
public class ModMailThreadNotFoundException extends AbstractoRunTimeException implements Templatable {
|
||||
|
||||
private final Long modMailThreadId;
|
||||
|
||||
@@ -3,9 +3,12 @@ package dev.sheldan.abstracto.modmail.exception;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.templating.Templatable;
|
||||
|
||||
/**
|
||||
* This exception is thrown when you try to unsubscribe from a mod mail thread, to which you are not subscribed to
|
||||
*/
|
||||
public class NotSubscribedException extends AbstractoRunTimeException implements Templatable {
|
||||
public NotSubscribedException(String message) {
|
||||
super(message);
|
||||
public NotSubscribedException() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,11 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* A table used to store which messages need to be retrieved when logging a mod mail thread.
|
||||
* These messages are only the messages passed between the member and the staff handling the thread and include all messages by the user
|
||||
* and only the messages send via command (reply/anonreply)
|
||||
*/
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@@ -18,19 +23,34 @@ import java.time.Instant;
|
||||
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
public class ModMailMessage {
|
||||
|
||||
/**
|
||||
* The globally unique message ID which was send in the mod mail thread, either by a user of by the staff handling the thread
|
||||
*/
|
||||
@Id
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* The {@link AUserInAServer} which authored this message
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "modmail_message_author", nullable = false)
|
||||
private AUserInAServer author;
|
||||
|
||||
/**
|
||||
* The {@link ModMailThread} in whose context this message was sent and this message is related to
|
||||
*/
|
||||
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
|
||||
@JoinColumn(name = "threadReference", nullable = false)
|
||||
private ModMailThread threadReference;
|
||||
|
||||
/**
|
||||
* Whether or not this message was from the user or a staff member, for convenience
|
||||
*/
|
||||
private Boolean dmChannel;
|
||||
|
||||
/**
|
||||
* Staff only: Whether or not this message meant to be sent anonymous
|
||||
*/
|
||||
private Boolean anonymous;
|
||||
|
||||
@Column(name = "created")
|
||||
|
||||
@@ -8,6 +8,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* The table responsible to define which roles are the roles responsible for handling the mod mail threads.
|
||||
* These will get notified via a ping, when a new mod mail thread is created.
|
||||
*/
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@@ -19,14 +23,23 @@ import java.time.Instant;
|
||||
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
public class ModMailRole {
|
||||
|
||||
/**
|
||||
* Unique ID of the mod mail role
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long modMailRoleId;
|
||||
|
||||
/**
|
||||
* Which {@link AServer} this role is associated with, for convenience
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "modmail_role_server", nullable = false)
|
||||
private AServer server;
|
||||
|
||||
/**
|
||||
* The actual {@link ARole} which this mod mail role references
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "modmail_role", nullable = false)
|
||||
private ARole role;
|
||||
|
||||
@@ -9,6 +9,10 @@ import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The table responsible to associate certain channels to be mod mail thread channels. It also stores the current state of the thread (answered, initial)
|
||||
* ,who the associated user is, who has subscribed to the thread and the messages posted in the thread.
|
||||
*/
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@@ -24,14 +28,23 @@ public class ModMailThread {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* The member who opened the thread or who got contacted
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "modmail_user", nullable = false)
|
||||
private AUserInAServer user;
|
||||
|
||||
/**
|
||||
* The text channel in which this thread is dealt with
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "modmail_thread_channel", nullable = false)
|
||||
private AChannel channel;
|
||||
|
||||
/**
|
||||
* The server on which this mod mail thread is, for convenience
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "modmail_thread_server", nullable = false)
|
||||
private AServer server;
|
||||
@@ -55,6 +68,10 @@ public class ModMailThread {
|
||||
@Column
|
||||
private Instant closed;
|
||||
|
||||
/**
|
||||
* The messages which were officially posted in the context of the mod mail thread. Either via command (from the
|
||||
* staff side of view) or by messaging the bot (from the member view)
|
||||
*/
|
||||
@OneToMany(
|
||||
fetch = FetchType.LAZY,
|
||||
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
|
||||
@@ -64,6 +81,9 @@ public class ModMailThread {
|
||||
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
private List<ModMailMessage> messages = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The staff members who subscribed to be notified in case there is a new message in a mod mail thread.
|
||||
*/
|
||||
@OneToMany(
|
||||
fetch = FetchType.LAZY,
|
||||
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
|
||||
@@ -73,6 +93,9 @@ public class ModMailThread {
|
||||
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
private List<ModMailThreadSubscriber> subscribers = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The current state of the mod mail thread. Whether or not the last post was by staff or user.
|
||||
*/
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column
|
||||
private ModMailThreadState state;
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
package dev.sheldan.abstracto.modmail.models.database;
|
||||
|
||||
public enum ModMailThreadState {
|
||||
INITIAL, USER_REPLIED, MOD_REPLIED, CLOSED, CLOSING;
|
||||
/**
|
||||
* User opened the mod mail thread or staff contacted member, but did not post a message yet
|
||||
*/
|
||||
INITIAL,
|
||||
/**
|
||||
* User replied to mod mail thread
|
||||
*/
|
||||
USER_REPLIED,
|
||||
/**
|
||||
* Staff member responded to the mod mail thread
|
||||
*/
|
||||
MOD_REPLIED,
|
||||
/**
|
||||
* The thread was closed by a staff member and the channel was removed
|
||||
*/
|
||||
CLOSED, CLOSING;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* This able contains the staff users which subscribed to a certain mod mail thread and will get notified of new messages
|
||||
* in a mod mail thread
|
||||
*/
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@@ -22,10 +26,16 @@ public class ModMailThreadSubscriber {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long subscriberId;
|
||||
|
||||
/**
|
||||
* The staff member which is subscribed
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "modmail_message_subscriber", nullable = false)
|
||||
private AUserInAServer subscriber;
|
||||
|
||||
/**
|
||||
* The thread for which the member is subscribed to
|
||||
*/
|
||||
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
|
||||
@JoinColumn(name = "modMailThread", nullable = false)
|
||||
private ModMailThread threadReference;
|
||||
|
||||
@@ -5,10 +5,20 @@ import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Used when the user shares multiple servers with the bot and needs to determine for which server the user
|
||||
* wants to open a mod mail thread, this is done by reacting to the prompt with the proper emote.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ServerChoice {
|
||||
/**
|
||||
* The possible guild to open a mod mail thread for
|
||||
*/
|
||||
private FullGuild guild;
|
||||
/**
|
||||
* The unicode emote used in the prompt to identify this choice
|
||||
*/
|
||||
private String reactionEmote;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Category;
|
||||
|
||||
/**
|
||||
* This model is used when confirming the setup up the mod mail configuration for the category in which the channels should be created
|
||||
* This model contains the actual JDA category object where the channels will be created in, and the id of said
|
||||
* category
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
package dev.sheldan.abstracto.modmail.models.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ValidationError;
|
||||
import dev.sheldan.abstracto.core.models.ValidationErrorModel;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This model is used when the category for creating mod mail threads is not properly setup
|
||||
* and when the feature is enabled via command. This will be rendered as a simple additional line of validation errors
|
||||
* after the command finished
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailCategoryValidationError implements ValidationError {
|
||||
public class ModMailCategoryValidationErrorModel implements ValidationErrorModel {
|
||||
private Long currentCategoryId;
|
||||
|
||||
@Override
|
||||
@@ -7,13 +7,27 @@ import lombok.Setter;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* This model is used when rendering the message before logging the messages in a closed {@link ModMailThread} and contains
|
||||
* general information about why the thread was closed and the thread itself.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailClosingHeaderModel {
|
||||
/**
|
||||
* The note used to close the thread, might be the default value
|
||||
*/
|
||||
private String note;
|
||||
/**
|
||||
* The {@link ModMailThread} which was closed
|
||||
*/
|
||||
private ModMailThread closedThread;
|
||||
|
||||
/**
|
||||
* The duration between the creation and closed date of a {@link ModMailThread}
|
||||
* @return
|
||||
*/
|
||||
public Duration getDuration() {
|
||||
return Duration.between(closedThread.getCreated(), closedThread.getClosed());
|
||||
}
|
||||
|
||||
@@ -6,11 +6,25 @@ import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* This model is used to render any exception happening when executing a command within a {@link ModMailThread}
|
||||
* and this command failing in any capacity. This model is used to render multiple templates (for differnet kinds of
|
||||
* exceptions), all of which might use the information or not.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailExceptionModel {
|
||||
/**
|
||||
* The {@link ModMailThread} in which the exception occurred
|
||||
*/
|
||||
private ModMailThread modMailThread;
|
||||
/**
|
||||
* A user associated with this exception, depends on the exact behaviour of the exception.
|
||||
*/
|
||||
private FullUser user;
|
||||
/**
|
||||
* The exception which was thrown
|
||||
*/
|
||||
private Throwable throwable;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package dev.sheldan.abstracto.modmail.models.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.FullUser;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailLoggedMessage {
|
||||
private Message message;
|
||||
private ModMailMessage modMailMessage;
|
||||
private FullUser author;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package dev.sheldan.abstracto.modmail.models.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.FullUser;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
/**
|
||||
* This model is used to render a message from a mod mail thread when closing the thread and logging the thread to the logging post target
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailLoggedMessageModel {
|
||||
/**
|
||||
* The {@link Message} instance which was posted
|
||||
*/
|
||||
private Message message;
|
||||
/**
|
||||
* The reference to the {@link ModMailMessage} stored in the database
|
||||
*/
|
||||
private ModMailMessage modMailMessage;
|
||||
|
||||
/**
|
||||
* A reference to the {@link FullUser} which is the author. The member part is null, if the member left the guild.
|
||||
*/
|
||||
private FullUser author;
|
||||
|
||||
|
||||
}
|
||||
@@ -8,14 +8,36 @@ import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
/**
|
||||
* Model used to render the response by staff members to the DM channel with the user
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailModeratorReplyModel {
|
||||
/**
|
||||
* A {@link FullUser} reference representing the user the thread is about. The member attribute is null, if the user left the guild
|
||||
*/
|
||||
private FullUser threadUser;
|
||||
/**
|
||||
* The staff {@link Member} which replied to the thread, be it anonymously or normal.
|
||||
*/
|
||||
private Member moderator;
|
||||
/**
|
||||
* The text which was used to reply. This is necessary, because the reply is triggered via a command, so
|
||||
* we would need re-parse the {@link Message} in order to find the value to display
|
||||
*/
|
||||
private String text;
|
||||
/**
|
||||
* The {@link Message} which contained the command to reply to the user. This is needed for attachments.
|
||||
*/
|
||||
private Message postedMessage;
|
||||
/**
|
||||
* Whether or not the reply should be shown anonymous
|
||||
*/
|
||||
private Boolean anonymous;
|
||||
/**
|
||||
* The {@link ModMailThread} to reply to
|
||||
*/
|
||||
private ModMailThread modMailThread;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,24 @@ import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The model used to notify staff members about a newly created mod mail thread. This model contains a dynamic amount of roles which are pinged
|
||||
* upon creation of a mod mail thread
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@SuperBuilder
|
||||
public class ModMailNotificationModel extends ServerContext {
|
||||
/**
|
||||
* The created {@link ModMailThread} which was just created
|
||||
*/
|
||||
private ModMailThread modMailThread;
|
||||
/**
|
||||
* The {@link FullUser} for which this thread is about
|
||||
*/
|
||||
private FullUser threadUser;
|
||||
/**
|
||||
* A list of roles which will be notified upon creation of the mod mail thread.
|
||||
*/
|
||||
private List<ModMailRole> roles;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,17 @@ import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Container model used to define all the possible {@link ServerChoice} which are presented when the initial message is
|
||||
* sent to the bot
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailServerChooserModel {
|
||||
/**
|
||||
* A list of {@link ServerChoice} which contains the common servers of the user and the bot, but only those
|
||||
* in which the mod mail feature is currently enabled
|
||||
*/
|
||||
private List<ServerChoice> commonGuilds;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* This model is used to notify a staff member that there is already a mod mail thread open for the user
|
||||
* and provide a link to the channel associated with the user.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@SuperBuilder
|
||||
|
||||
@@ -6,11 +6,25 @@ import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* This is the model used when a new mod mail thread is opened and a message containing some information about the user
|
||||
* is displayed for the user handling the mod mail thread.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailThreaderHeader {
|
||||
/**
|
||||
* A {@link FullUser} instance to retrieve information from
|
||||
*/
|
||||
private FullUser threadUser;
|
||||
/**
|
||||
* The latest {@link ModMailThread}, before the current opened one. This is null if there is no closed mod mail thread
|
||||
* for the user
|
||||
*/
|
||||
private ModMailThread latestModMailThread;
|
||||
/**
|
||||
* The amount of previous mod mail thread the user has.
|
||||
*/
|
||||
private Long pastModMailThreadCount;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,28 @@ import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Model used to render the response by the user to the mod mail thread channel.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailUserReplyModel {
|
||||
/**
|
||||
* The {@link FullUser} from which the message is and whose mod mail thread it is
|
||||
*/
|
||||
private FullUser threadUser;
|
||||
/**
|
||||
* The {@link Message} which was posted, which contains all the possible information
|
||||
*/
|
||||
private Message postedMessage;
|
||||
/**
|
||||
* The {@link ModMailThread} for which the {@link Message} was a reply for
|
||||
*/
|
||||
private ModMailThread modMailThread;
|
||||
/**
|
||||
* List of {@link FullUser} which are registered as subscribers for a particular mod mail thread and will be pinged
|
||||
* when the user sends a new message
|
||||
*/
|
||||
private List<FullUser> subscribers;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Category;
|
||||
|
||||
/**
|
||||
* Model which is used when setting up the mod mail feature. The category property will be used when there is already a category
|
||||
* defined to be used for mod mail threads and it is still a valid category.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
|
||||
@@ -6,6 +6,14 @@ import net.dv8tion.jda.api.entities.Message;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Service to handle the messages of a {@link dev.sheldan.abstracto.modmail.models.database.ModMailThread}
|
||||
*/
|
||||
public interface ModMailMessageService {
|
||||
/**
|
||||
* Loads the given mod mail messages in the form of {@link Message} from Discord and returns the created promises, some of which might fail, if the message was already deleted
|
||||
* @param modMailMessages The list of {@link ModMailMessage} to load
|
||||
* @return A list of futures which contain the individual results of actively loading the {@link Message}
|
||||
*/
|
||||
List<CompletableFuture<Message>> loadModMailMessages(List<ModMailMessage> modMailMessages);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
package dev.sheldan.abstracto.modmail.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.ARole;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
|
||||
/**
|
||||
* Service for managing {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole}, this includes crating and removing them
|
||||
*/
|
||||
public interface ModMailRoleService {
|
||||
void addRoleToModMailRoles(ARole role, AServer server);
|
||||
void removeRoleFromModMailRoles(ARole role, AServer server);
|
||||
/**
|
||||
* Adds a given {@link ARole} to the list of {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole} of the given server.
|
||||
* This method also allows the given role to execute the mod mail related commands. (Which causes the commands to automatically be restricted)
|
||||
* @param role The {@link ARole} to change to a {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole}
|
||||
*
|
||||
*/
|
||||
void addRoleToModMailRoles(ARole role);
|
||||
|
||||
/**
|
||||
* Removes the given {@link ARole} from the list of {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole} of the server.
|
||||
* This automatically dis-allows the mod mail related commands for the given role.
|
||||
* @param role The {@link ARole} to remove from the list of mod mail roles
|
||||
*
|
||||
*/
|
||||
void removeRoleFromModMailRoles(ARole role);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,23 @@ package dev.sheldan.abstracto.modmail.service;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
|
||||
|
||||
/**
|
||||
* Service used to add subscriptions to threads and remove them as well.
|
||||
*/
|
||||
public interface ModMailSubscriptionService {
|
||||
/**
|
||||
* Subscribes the {@link AUserInAServer} to the given {@link ModMailThread}.
|
||||
* @param aUserInAServer The {@link AUserInAServer} to subscribe
|
||||
* @param modMailThread The {@link ModMailThread} to subscribe the user to
|
||||
* @throws dev.sheldan.abstracto.modmail.exception.AlreadySubscribedException in case the user is already subscribed
|
||||
*/
|
||||
void subscribeToThread(AUserInAServer aUserInAServer, ModMailThread modMailThread);
|
||||
|
||||
/**
|
||||
* Un-subscribes the {@link AUserInAServer} from the given {@link ModMailThread}
|
||||
* @param aUserInAServer The {@link AUserInAServer} to un-subscribe
|
||||
* @param modMailThread The {@link ModMailThread} to un-subscribe the user from
|
||||
* @throws dev.sheldan.abstracto.modmail.exception.NotSubscribedException in case the user is not subscribed to the thread
|
||||
*/
|
||||
void unsubscribeFromThread(AUserInAServer aUserInAServer, ModMailThread modMailThread);
|
||||
}
|
||||
|
||||
@@ -6,17 +6,85 @@ 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.modmail.models.database.ModMailThread;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
|
||||
/**
|
||||
* Service used to handle the mod mail life cycle, including creation, updating, sending/receiving messages and logging the mod mail thread
|
||||
*/
|
||||
public interface ModMailThreadService {
|
||||
/**
|
||||
* Creates a new mod mail thread for the given user. including: the {@link net.dv8tion.jda.api.entities.TextChannel}
|
||||
* in the appropriate {@link net.dv8tion.jda.api.entities.Category} and calls the methods responsible for storing
|
||||
* the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread}
|
||||
* @param userInAServer The {@link AUserInAServer} to create the mod mail thread for
|
||||
* @param initialMessage The initial message sparking this mod mail thread, null in case it was created by a command
|
||||
* @param feedBackChannel The {@link MessageChannel} in which feedback about exceptions should be posted to
|
||||
* @param userInitiated Whether or not the mod mail thread was initiated by a user
|
||||
*/
|
||||
void createModMailThreadForUser(FullUser userInAServer, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated);
|
||||
boolean hasOpenThread(AUserInAServer aUserInAServer);
|
||||
boolean hasOpenThread(AUser user);
|
||||
void setModMailCategoryTo(AServer server, Long categoryId);
|
||||
|
||||
/**
|
||||
* Changes the configuration value of the category used to create mod mail threads to the given ID.
|
||||
* @param guild The {@link Guild} to change the category value for
|
||||
* @param categoryId The ID of the category to use
|
||||
*/
|
||||
void setModMailCategoryTo(Guild guild, Long categoryId);
|
||||
|
||||
/**
|
||||
* Creates a prompt message, where the user initiating the mod mail thread has to chose for which server
|
||||
* the user wants to create a mod mail thread for. The message will be displayed in the same channel
|
||||
* as the original message was displayed in. Only servers in which the mod mail feature is enabled, will be counted
|
||||
* and if there are no servers available an error message will be displayed.
|
||||
* @param user The {@link AUser} who wants to open a mod mail thread
|
||||
* @param initialMessage The {@link Message} which was send by the user to open a mod mail thread with.
|
||||
*/
|
||||
void createModMailPrompt(AUser user, Message initialMessage);
|
||||
|
||||
/**
|
||||
* Forwards the given {@link Message} send by the user to the appropriate text channel of the given {@link ModMailThread}.
|
||||
* In case there was no channel found, this will cause a message to be shown to the user and the existing mod mail thread will be closed.
|
||||
* This is the case, if the mod mail thread was still open in the database, but no text channel was found anymore.
|
||||
* @param modMailThread The {@link ModMailThread} on which the user answered
|
||||
* @param message The {@link Message} object which was sent by the user to answer with
|
||||
*/
|
||||
void relayMessageToModMailThread(ModMailThread modMailThread, Message message);
|
||||
|
||||
/**
|
||||
* Forwards a message send by a moderator to the direct message channel opened with the user. If the message is
|
||||
* marked as anonymous, the bot will take the place of the author, in other case the author is shown in the embed.
|
||||
* @param modMailThread The {@link ModMailThread} to which the reply was sent to
|
||||
* @param text The parsed text of the reply
|
||||
* @param message The pure {@link Message} containing the command which caused the reply
|
||||
* @param anonymous Whether or nor the message should be send anonymous
|
||||
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
|
||||
*/
|
||||
void relayMessageToDm(ModMailThread modMailThread, String text, Message message, boolean anonymous, MessageChannel feedBack);
|
||||
|
||||
/**
|
||||
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread,
|
||||
* and depending on the {@link dev.sheldan.abstracto.core.config.FeatureMode} of mod mail logs the content of the thread into the appropriate
|
||||
* post target. This also takes an optional note, which will be displayed in the first message of the logging. This method changes the state of the
|
||||
* {@link ModMailThread} to CLOSED and notifies the user about closing.
|
||||
* @param modMailThread The {@link ModMailThread} which is being closed.
|
||||
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
|
||||
* @param note The text of the note used for the header message of the logged mod mail thread.
|
||||
* @param notifyUser Whether or not the user should be notified
|
||||
*/
|
||||
void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser);
|
||||
|
||||
/**
|
||||
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread,
|
||||
* and logs the content of the thread into the appropriate post target. This also takes an optional note, which will
|
||||
* be displayed in the first message of the logging. This method changes the state of the {@link ModMailThread} to
|
||||
* CLOSED and notifies the user about closing.
|
||||
* @param modMailThread The {@link ModMailThread} which is being closed.
|
||||
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
|
||||
* @param note The text of the note used for the header message of the logged mod mail thread, this is only required when actually
|
||||
* logging the mod mail thread
|
||||
* @param notifyUser Whether or not the user should be notified
|
||||
* @param logThread Whether or not the thread should be logged to the appropriate post target
|
||||
*/
|
||||
void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser, boolean logThread);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,25 @@ import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Management service to handle the creation and retrieval of {@link ModMailMessage} instances from the database
|
||||
*/
|
||||
public interface ModMailMessageManagementService {
|
||||
/**
|
||||
* Creates an instance of {@link ModMailMessage}, attaches it to the given {@link ModMailThread} and returns the created instance
|
||||
* @param modMailThread The {@link ModMailThread} the message should be attached to
|
||||
* @param message The {@link Message} which should be attached to the {@link ModMailThread}
|
||||
* @param author The {@link AUserInAServer} who authored the {@link Message} originally
|
||||
* @param anonymous Whether or not the message was sent anonymous (only possible by staff members)
|
||||
* @param dmChannel Whether or not the message originated from the user, and therefore in an direct message channel
|
||||
* @return
|
||||
*/
|
||||
ModMailMessage addMessageToThread(ModMailThread modMailThread, Message message, AUserInAServer author, Boolean anonymous, Boolean dmChannel);
|
||||
|
||||
/**
|
||||
* Retrieves all messages which were sent in a {@link ModMailThread}
|
||||
* @param modMailThread The {@link ModMailThread} to retrieve the messages for
|
||||
* @return A list of {@link ModMailMessage} which were sent in the given thread
|
||||
*/
|
||||
List<ModMailMessage> getMessagesOfThread(ModMailThread modMailThread);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,40 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailRole;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Management service bean responsible to create, remove, retrieve and check mod mail roles which are used to determine
|
||||
* which roles are getting pinged when a new mod mail thread is created.
|
||||
*/
|
||||
public interface ModMailRoleManagementService {
|
||||
/**
|
||||
* Adds the given {@link ARole} to the mod mail roles of the {@link AServer}. This method does not check if the role
|
||||
* is already present.
|
||||
* @param role The {@link ARole} to add to the mod mail roles
|
||||
* @param server The {@link AServer} to which the given {@link ARole} should be added to the mod mail roles
|
||||
*/
|
||||
void addRoleToModMailRoles(ARole role, AServer server);
|
||||
|
||||
/**
|
||||
* Removes the given {@link ARole} from the mod mail roles of the given {@link AServer}. Does nothing if the
|
||||
* role is not used as a mod mail role on the server
|
||||
* @param role The {@link ARole} to remove from the mod mail roles
|
||||
* @param server The {@link AServer} from which the role should be removed from the mod mail roles
|
||||
*/
|
||||
void removeRoleFromModMailRoles(ARole role, AServer server);
|
||||
|
||||
/**
|
||||
* Retrieves all roles which should be pinged when a new mod mail thread is created by a user and returns the list
|
||||
* of {@link ModMailRole} for the given {@link AServer}.
|
||||
* @param server The {@link AServer} for which to retrieve the mod mail roles for
|
||||
* @return The list of found {@link ModMailRole} for the given {@link AServer}
|
||||
*/
|
||||
List<ModMailRole> getRolesForServer(AServer server);
|
||||
|
||||
/**
|
||||
* Checks whether or not the given {@link ARole} has already been assigned as a {@link ModMailRole} in the given {@link AServer}
|
||||
* @param role The {@link ARole} to check for
|
||||
* @param server The {@link AServer} to check in
|
||||
* @return Whether or not the given {@link ARole} is used as a {@link ModMailRole} in the given {@link AServer}
|
||||
*/
|
||||
boolean isRoleAlreadyAssigned(ARole role, AServer server);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,38 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailThreadSubscriber;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Management service used to retrieve/create/remove instances of {@link ModMailThreadSubscriber}
|
||||
*/
|
||||
public interface ModMailSubscriberManagementService {
|
||||
/**
|
||||
* Retrieves all the {@link ModMailThreadSubscriber} of the given {@link ModMailThread}
|
||||
* @param modMailThread The {@link ModMailThread} to retrieve the subscribers of
|
||||
* @return The list of {@link ModMailThreadSubscriber} which are currently configured for the given {@link ModMailThread}
|
||||
*/
|
||||
List<ModMailThreadSubscriber> getSubscribersForThread(ModMailThread modMailThread);
|
||||
|
||||
/**
|
||||
* This method checks if a {@link AUserInAServer} is stored as a {@link ModMailThreadSubscriber} for the given
|
||||
* {@link ModMailThread}
|
||||
* @param aUserInAServer The {@link AUserInAServer} to check for
|
||||
* @param modMailThread The {@link ModMailThread} to check in
|
||||
* @return Whether or not the given {@link AUserInAServer} is a subscriber of the mod mail thread
|
||||
*/
|
||||
boolean isSubscribedToThread(AUserInAServer aUserInAServer, ModMailThread modMailThread);
|
||||
|
||||
/**
|
||||
* Creates a {@link ModMailThreadSubscriber} with the given parameters and returns the created instance
|
||||
* @param aUserInAServer The {@link AUserInAServer} to subscribe to a thread
|
||||
* @param modMailThread The {@link ModMailThread} to which the user should be subscribed to
|
||||
* @return The created instance of {@link ModMailThreadSubscriber}
|
||||
*/
|
||||
ModMailThreadSubscriber createSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread);
|
||||
|
||||
/**
|
||||
* Removes the instance of the {@link ModMailThreadSubscriber}, effectively un-subscribing the user from the thread
|
||||
* @param aUserInAServer The {@link AUserInAServer} to un-subscribe
|
||||
* @param modMailThread The {@link ModMailThread} to unsubscribe from
|
||||
*/
|
||||
void removeSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.modmail.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.ChannelNotFoundException;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
@@ -9,16 +10,100 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Management service to create/retrieve/modify instances of {@link ModMailThread}
|
||||
*/
|
||||
|
||||
public interface ModMailThreadManagementService {
|
||||
|
||||
/**
|
||||
* Retrieves a {@link ModMailThread} found in the {@link net.dv8tion.jda.api.entities.MessageChannel} given by the ID of the channel
|
||||
* @param channelId The id of the channel to retrieve the {@link ModMailThread} for
|
||||
* @throws ChannelNotFoundException if an appropriate {@link AChannel} was not found
|
||||
* @return The instance of {@link ModMailThread} if it exists, null if none was found
|
||||
*/
|
||||
ModMailThread getByChannelId(Long channelId);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link ModMailThread} by the given ID in an optional, if it exists, and an {@literal Optional#empty()} otherwise
|
||||
* @param modMailThreadId The ID of the mod mail to search for
|
||||
* @return An {@link Optional} containing the mod mail thread or empty
|
||||
*/
|
||||
Optional<ModMailThread> getById(Long modMailThreadId);
|
||||
|
||||
/**
|
||||
* Retrieves a {@link ModMailThread} found in the {@link net.dv8tion.jda.api.entities.MessageChannel} given by the
|
||||
* {@link AChannel} object
|
||||
* @param channel The {@link AChannel} object to search a mod mail thread for
|
||||
* @return The found mod mail thread, or null if none was found
|
||||
*/
|
||||
ModMailThread getByChannel(AChannel channel);
|
||||
|
||||
/**
|
||||
* Searches for mod mail threads with the appropriate staten which concern the given {@link AUserInAServer}
|
||||
* @param userInAServer The {@link AUserInAServer} to search mod mail threads for
|
||||
* @param state The {@link ModMailThreadState} to be used as a criteria
|
||||
* @return A list of {@link ModMailThread} which were found by the given criteria
|
||||
*/
|
||||
List<ModMailThread> getThreadByUserAndState(AUserInAServer userInAServer, ModMailThreadState state);
|
||||
ModMailThread getOpenModmailThreadForUser(AUserInAServer userInAServer);
|
||||
ModMailThread getOpenModmailThreadForUser(AUser user);
|
||||
|
||||
/**
|
||||
* Retrieves the *only* open mod mail thread for the given {@link AUserInAServer}, and null if none is in the state open
|
||||
* @param userInAServer The {@link AUserInAServer} to search an open {@link ModMailThread} for
|
||||
* @return The found open {@link ModMailThread}, or null if none is found
|
||||
*/
|
||||
ModMailThread getOpenModMailThreadForUser(AUserInAServer userInAServer);
|
||||
|
||||
/**
|
||||
* Returns whether or not the {@link AUserInAServer} has a {@link ModMailThread} in a state which is not CLOSED
|
||||
* @param userInAServer The {@link AUserInAServer} to check for
|
||||
* @return Boolean whether or not the {@link AUserInAServer} has an open thread
|
||||
*/
|
||||
boolean hasOpenModMailThreadForUser(AUserInAServer userInAServer);
|
||||
|
||||
/**
|
||||
* Retrieves all the open {@link ModMailThread} for the {@link AUser}, which means over all the known guilds
|
||||
* @param user The {@link AUser} for which the open mod mail threads should be retrieved
|
||||
* @return A list of {@link ModMailThread} which contains all the current threads which are not CLOSED
|
||||
*/
|
||||
List<ModMailThread> getOpenModMailThreadsForUser(AUser user);
|
||||
|
||||
/**
|
||||
* Returns whether or not the {@link AUser} has a {@link ModMailThread} in a state which is not CLOSED
|
||||
* @param user The {@link AUser} to check for open mod mail treads
|
||||
* @return Boolean whether or not the {@link AUser} has an open thread
|
||||
*/
|
||||
boolean hasOpenModMailThread(AUser user);
|
||||
|
||||
/**
|
||||
* Retrieves all the open {@link ModMailThread} for the {@link AUserInAServer}, which means only in one guild, this
|
||||
* should be at most one
|
||||
* @param aUserInAServer The {@link AUserInAServer} to retrieve the mod mail threads for
|
||||
* @return A list of {@link ModMailThread} which contains all the current mod mail threads for the member, should be at most one
|
||||
*/
|
||||
List<ModMailThread> getModMailThreadForUser(AUserInAServer aUserInAServer);
|
||||
|
||||
/**
|
||||
* Retrieves the *latest* {@link ModMailThread} of the {@link AUserInAServer}, which means, the latest thread which is in the state
|
||||
* CLOSED, null other wise.
|
||||
* @param aUserInAServer The {@link AUserInAServer} to retrieve the latest thread for
|
||||
* @return If a thread in state CLOSED exists, the latest one, null other wise
|
||||
*/
|
||||
ModMailThread getLatestModMailThread(AUserInAServer aUserInAServer);
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link ModMailThread} with the appropriate parameters and returns the created instance.
|
||||
* @param userInAServer The {@link AUserInAServer} for which the thread was created for
|
||||
* @param channel An instance of {@link AChannel} in which the conversation with the member is handled
|
||||
* @return The created instance of {@link ModMailThread}
|
||||
*/
|
||||
ModMailThread createModMailThread(AUserInAServer userInAServer, AChannel channel);
|
||||
|
||||
/**
|
||||
* Updates the {@link ModMailThread} with the new state and saves the instance.
|
||||
* @param modMailThread The {@link ModMailThread} to change the state for
|
||||
* @param newState The new {@link ModMailThreadState} to change the thread to
|
||||
*/
|
||||
void setModMailThreadState(ModMailThread modMailThread, ModMailThreadState newState);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,5 +2,8 @@ package dev.sheldan.abstracto.modmail.setup;
|
||||
|
||||
import dev.sheldan.abstracto.core.interactive.SetupStep;
|
||||
|
||||
/**
|
||||
* Setup step responsible to setup the required {@link java.util.Locale.Category} for mod mail
|
||||
*/
|
||||
public interface ModMailCategorySetup extends SetupStep {
|
||||
}
|
||||
|
||||
@@ -4,6 +4,15 @@ import dev.sheldan.abstracto.core.models.FeatureValidationResult;
|
||||
import dev.sheldan.abstracto.core.service.FeatureValidator;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
|
||||
/**
|
||||
* Validator service which validates, whether or not the configured mod mail category is actually a valid category.
|
||||
*/
|
||||
public interface ModMailFeatureValidator extends FeatureValidator {
|
||||
/**
|
||||
* Validates the category and checks if the given ID is a valid category in the given {@link Guild}
|
||||
* @param validationResult The object in which the result of the validation will be stored
|
||||
* @param guild The {@link Guild} to check for the category
|
||||
* @param modMailCategory The configured ID of the category
|
||||
*/
|
||||
void validateModMailCategory(FeatureValidationResult validationResult, Guild guild, Long modMailCategory);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user