[AB-365] introducing slash commands for a selection of commands

adding method for pinning a message
moving suggestion to correct deployment
This commit is contained in:
Sheldan
2022-05-17 00:39:06 +02:00
parent 1913bc930d
commit 1d6de3f1e8
286 changed files with 8021 additions and 3065 deletions

View File

@@ -5,22 +5,29 @@ import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.ClosingContext;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -34,7 +41,12 @@ import java.util.concurrent.CompletableFuture;
@Slf4j
public class Close extends AbstractConditionableCommand {
public static final String MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY = "modmail_close_default_note";
private static final String MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY = "modmail_close_default_note";
private static final String CLOSE_COMMAND = "close";
private static final String NOTE_PARAMETER = "note";
private static final String SILENTLY_PARAMETER = "silently";
private static final String LOG_PARAMETER = "log";
private static final String CLOSE_RESPONSE = "close_response";
@Autowired
private ModMailContextCondition requiresModMailCondition;
@@ -50,6 +62,15 @@ public class Close extends AbstractConditionableCommand {
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private Close self;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
@@ -61,6 +82,7 @@ public class Close extends AbstractConditionableCommand {
.builder()
.closingMember(commandContext.getAuthor())
.notifyUser(true)
.channel(commandContext.getChannel())
.log(true)
.note(note)
.build();
@@ -68,16 +90,96 @@ public class Close extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String note;
if(slashCommandParameterService.hasCommandOption(NOTE_PARAMETER, event)) {
note = slashCommandParameterService.getCommandOption(NOTE_PARAMETER, event, String.class);
} else {
note = templateService.renderTemplate(MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
}
Boolean silently;
if(slashCommandParameterService.hasCommandOption(SILENTLY_PARAMETER, event)) {
silently = slashCommandParameterService.getCommandOption(SILENTLY_PARAMETER, event, Boolean.class);
} else {
silently = false;
}
Boolean log;
if(slashCommandParameterService.hasCommandOption(LOG_PARAMETER, event)) {
log = slashCommandParameterService.getCommandOption(LOG_PARAMETER, event, Boolean.class);
} else {
log = false;
}
ClosingContext context = ClosingContext
.builder()
.closingMember(event.getMember())
.channel(event.getChannel())
.notifyUser(!silently)
.log(log)
.note(note)
.build();
return interactionService.replyEmbed(CLOSE_RESPONSE, event)
.thenCompose(interactionHook -> self.closeThread(context))
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Transactional
public CompletableFuture<Void> closeThread(ClosingContext closingContext) {
AChannel channel = channelManagementService.loadChannel(closingContext.getChannel());
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
return modMailThreadService.closeModMailThread(thread, closingContext, new ArrayList<>());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter note = Parameter.builder().name("note").type(String.class).remainder(true).optional(true).templated(true).build();
List<Parameter> parameters = Arrays.asList(note);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
Parameter noteParameter = Parameter
.builder()
.name(NOTE_PARAMETER)
.type(String.class)
.remainder(true)
.optional(true)
.templated(true)
.build();
Parameter silentlyParameter = Parameter
.builder()
.name(SILENTLY_PARAMETER)
.type(Boolean.class)
.remainder(true)
.slashCommandOnly(true)
.optional(true)
.templated(true)
.build();
Parameter logParameter = Parameter
.builder()
.name(LOG_PARAMETER)
.type(Boolean.class)
.remainder(true)
.slashCommandOnly(true)
.optional(true)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(noteParameter, silentlyParameter, logParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(CLOSE_COMMAND)
.build();
return CommandConfiguration.builder()
.name("close")
.name(CLOSE_COMMAND)
.module(ModMailModuleDefinition.MODMAIL)
.parameters(parameters)
.help(helpInfo)
.slashCommandConfig(slashCommandConfig)
.async(true)
.supportsEmbedException(true)
.templated(true)

View File

@@ -4,16 +4,19 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.model.template.ModMailThreadExistsModel;
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
@@ -21,9 +24,13 @@ import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementS
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -36,6 +43,11 @@ import java.util.concurrent.CompletableFuture;
@Slf4j
public class Contact extends AbstractConditionableCommand {
private static final String CONTACT_PARAMETER = "contact";
private static final String USER_PARMETER = "user";
private static final String MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE = "modmail_thread_already_exists";
private static final String CONTACT_RESPONSE = "contact_response";
@Autowired
private ModMailThreadService modMailThreadService;
@@ -48,6 +60,12 @@ public class Contact extends AbstractConditionableCommand {
@Autowired
private ChannelService channelService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
Member targetUser = (Member) commandContext.getParameters().getParameters().get(0);
@@ -59,26 +77,73 @@ public class Contact extends AbstractConditionableCommand {
// containing a link to the channel, instead of opening a new one
if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", commandContext.getAuthor().getId(), commandContext.getGuild().getId(), user.getUserReference().getId());
ModMailThreadExistsModel model = (ModMailThreadExistsModel) ContextConverter.fromCommandContext(commandContext, ModMailThreadExistsModel.class);
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
model.setExistingModMailThread(existingThread);
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList("modmail_thread_already_exists", model, commandContext.getChannel());
ModMailThreadExistsModel model = ModMailThreadExistsModel
.builder()
.existingModMailThread(existingThread)
.build();
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
} else {
return modMailThreadService.createModMailThreadForUser(targetUser, null, commandContext.getChannel(), false, commandContext.getUndoActions())
return modMailThreadService.createModMailThreadForUser(targetUser, null, false, commandContext.getUndoActions())
.thenCompose(unused -> modMailThreadService.sendContactNotification(targetUser, unused, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member member = slashCommandParameterService.getCommandOption(USER_PARMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
AUserInAServer user = userManagementService.loadOrCreateUser(member);
// if this AUserInAServer already has an open thread, we should instead post a message
// containing a link to the channel, instead of opening a new one
if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", event.getMember().getId(), event.getGuild().getId(), user.getUserReference().getId());
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
ModMailThreadExistsModel model = ModMailThreadExistsModel
.builder()
.existingModMailThread(existingThread)
.build();
return interactionService.replyEmbed(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} else {
CompletableFuture<InteractionHook> response = interactionService.replyEmbed(CONTACT_RESPONSE, event);
CompletableFuture<MessageChannel> threadFuture = modMailThreadService.createModMailThreadForUser(member, null, false, new ArrayList<>());
return CompletableFuture.allOf(response, threadFuture)
.thenCompose(unused -> modMailThreadService.sendContactNotification(member, threadFuture.join(), response.join()))
.thenApply(o -> CommandResult.fromSuccess());
}
}
@Override
public CommandConfiguration getConfiguration() {
Parameter responseText = Parameter.builder().name("user").type(Member.class).templated(true).build();
Parameter responseText = Parameter
.builder()
.name(USER_PARMETER)
.type(Member.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(responseText);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(CONTACT_PARAMETER)
.build();
return CommandConfiguration.builder()
.name("contact")
.name(CONTACT_PARAMETER)
.module(ModMailModuleDefinition.MODMAIL)
.parameters(parameters)
.slashCommandConfig(slashCommandConfig)
.async(true)
.help(helpInfo)
.supportsEmbedException(true)

View File

@@ -4,19 +4,24 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
@@ -26,6 +31,9 @@ import java.util.List;
@Component
public class Subscribe extends AbstractConditionableCommand {
private static final String SUBSCRIBE_COMMAND = "subscribe";
private static final String SUBSCRIBE_RESPONSE = "subscribe_response";
@Autowired
private ModMailContextCondition requiresModMailCondition;
@@ -38,6 +46,9 @@ public class Subscribe extends AbstractConditionableCommand {
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private InteractionService interactionService;
@Override
public CommandResult execute(CommandContext commandContext) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong());
@@ -45,11 +56,31 @@ public class Subscribe extends AbstractConditionableCommand {
return CommandResult.fromSuccess();
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(event.getChannel().getIdLong());
modMailSubscriptionService.subscribeToThread(userInServerManagementService.loadOrCreateUser(event.getMember()), modMailThread);
return interactionService.replyEmbed(SUBSCRIBE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(SUBSCRIBE_COMMAND)
.build();
return CommandConfiguration.builder()
.name("subscribe")
.name(SUBSCRIBE_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ModMailModuleDefinition.MODMAIL)
.help(helpInfo)
.supportsEmbedException(true)

View File

@@ -4,20 +4,25 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
@@ -27,6 +32,9 @@ import java.util.List;
@Component
public class UnSubscribe extends AbstractConditionableCommand {
private static final String UN_SUBSCRIBE_COMMAND = "unSubscribe";
private static final String UN_SUBSCRIBE_RESPONSE = "unSubscribe_response";
@Autowired
private ModMailContextCondition requiresModMailCondition;
@@ -39,6 +47,9 @@ public class UnSubscribe extends AbstractConditionableCommand {
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private InteractionService interactionService;
@Override
public CommandResult execute(CommandContext commandContext) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong());
@@ -47,11 +58,32 @@ public class UnSubscribe extends AbstractConditionableCommand {
return CommandResult.fromSuccess();
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(event.getChannel().getIdLong());
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
modMailSubscriptionService.unsubscribeFromThread(aUserInAServer, modMailThread);
return interactionService.replyEmbed(UN_SUBSCRIBE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(UN_SUBSCRIBE_COMMAND)
.build();
return CommandConfiguration.builder()
.name("unSubscribe")
.name(UN_SUBSCRIBE_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ModMailModuleDefinition.MODMAIL)
.help(helpInfo)
.supportsEmbedException(true)

View File

@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.condition.detail.NotInModMailThreadConditionDetail;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -24,9 +24,6 @@ public class RequiresModMailCondition implements ModMailContextCondition {
@Autowired
private ModMailThreadManagementService modMailThreadManagementService;
@Autowired
private TemplateService templateService;
@Autowired
private ChannelManagementService channelManagementService;
@@ -34,8 +31,36 @@ public class RequiresModMailCondition implements ModMailContextCondition {
public ConditionResult shouldExecute(CommandContext commandContext, Command command) {
Optional<ModMailThread> threadOptional = modMailThreadManagementService.getByChannelOptional(channelManagementService.loadChannel(commandContext.getChannel()));
if(threadOptional.isPresent()) {
return ConditionResult.builder().result(true).build();
return ConditionResult
.builder()
.result(true)
.build();
}
return ConditionResult.builder().result(false).conditionDetail(new NotInModMailThreadConditionDetail()).build();
return ConditionResult
.builder()
.result(false)
.conditionDetail(new NotInModMailThreadConditionDetail())
.build();
}
@Override
public ConditionResult shouldExecute(SlashCommandInteractionEvent slashCommandInteractionEvent, Command command) {
Optional<ModMailThread> threadOptional = modMailThreadManagementService.getByChannelOptional(channelManagementService.loadChannel(slashCommandInteractionEvent.getChannel()));
if(threadOptional.isPresent()) {
return ConditionResult
.builder()
.result(true)
.build();
}
return ConditionResult
.builder()
.result(false)
.conditionDetail(new NotInModMailThreadConditionDetail())
.build();
}
@Override
public boolean supportsSlashCommands() {
return true;
}
}

View File

@@ -33,9 +33,6 @@ public class ModMailInitialButtonListener implements ButtonClickedListener {
@Autowired
private UndoActionService undoActionService;
@Autowired
private MessageService messageService;
@Autowired
private ComponentPayloadManagementService componentPayloadService;
@@ -58,7 +55,7 @@ public class ModMailInitialButtonListener implements ButtonClickedListener {
.thenCompose(member -> channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId())
.thenCompose(originalMessage -> {
try {
return modMailThreadService.createModMailThreadForUser(member, originalMessage, model.getEvent().getChannel(), true, undoActions);
return modMailThreadService.createModMailThreadForUser(member, originalMessage, true, undoActions);
} catch (Exception ex) {
log.error("Failed to setup thread correctly", ex);
undoActionService.performActions(undoActions);

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.modmail.service;
import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
import dev.sheldan.abstracto.core.metric.service.MetricService;
import dev.sheldan.abstracto.core.metric.service.MetricTag;
@@ -39,6 +40,7 @@ import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.interactions.InteractionHook;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -149,6 +151,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Autowired
private ComponentPayloadService componentPayloadService;
@Autowired
private InteractionService interactionService;
public static final String MODMAIL_THREAD_METRIC = "modmail.threads";
public static final String MODMAIL_MESSAGE_METRIC = "modmail.messges";
public static final String ACTION = "action";
@@ -180,7 +185,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
public static final String MODMAIL_INITIAL_ORIGIN = "modmailInitial";
@Override
public CompletableFuture<Void> createModMailThreadForUser(Member member, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated, List<UndoActionInstance> undoActions) {
public CompletableFuture<MessageChannel> createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions) {
Long serverId = member.getGuild().getIdLong();
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId);
AServer server = serverManagementService.loadServer(member.getGuild().getIdLong());
@@ -199,20 +204,32 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
CompletableFuture<TextChannel> textChannelFuture = channelService.createTextChannel(channelName, server, categoryId);
return textChannelFuture.thenCompose(channel -> {
undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, channel.getIdLong()));
return self.performModMailThreadSetup(member, initialMessage, channel, userInitiated, undoActions, feedBackChannel);
return self.performModMailThreadSetup(member, initialMessage, channel, userInitiated, undoActions)
.thenCompose(unused -> CompletableFuture.completedFuture(channel));
});
}
@Transactional
public CompletableFuture<Void> sendContactNotification(Member member, TextChannel textChannel, MessageChannel feedBackChannel) {
@Override
public CompletableFuture<Void> sendContactNotification(Member member, MessageChannel messageChannel, MessageChannel feedBackChannel) {
ContactNotificationModel model = ContactNotificationModel
.builder()
.createdChannel(textChannel)
.createdChannel(messageChannel)
.targetMember(member)
.build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannelList(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, feedBackChannel));
}
@Override
public CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook) {
ContactNotificationModel model = ContactNotificationModel
.builder()
.createdChannel(createdMessageChannel)
.targetMember(member)
.build();
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, interactionHook));
}
/**
* 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.
@@ -224,7 +241,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @return A {@link CompletableFuture future} which completes when the setup is done
*/
@Transactional
public CompletableFuture<Void> performModMailThreadSetup(Member member, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions, MessageChannel feedBackChannel) {
public CompletableFuture<Void> performModMailThreadSetup(Member member, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) {
log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), member.getId(), channel.getGuild().getId(), userInitiated);
CompletableFuture<Void> headerFuture = sendModMailHeader(channel, member);
CompletableFuture<Message> userReplyMessage;
@@ -244,10 +261,6 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
return CompletableFuture.allOf(headerFuture, notificationFuture, userReplyMessage).thenAccept(aVoid -> {
undoActions.clear();
self.setupModMailThreadInDB(initialMessage, channel, member, userReplyMessage.join());
}).thenAccept(unused -> {
if(!userInitiated) {
self.sendContactNotification(member, channel, feedBackChannel);
}
});
}
@@ -368,7 +381,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", initialMessage.getAuthor().getId(), chosenServerId);
memberService.getMemberInServerAsync(chosenServerId, initialMessage.getAuthor().getIdLong()).thenCompose(member -> {
try {
return self.createModMailThreadForUser(member, initialMessage, initialMessage.getChannel(), true, undoActions);
return self.createModMailThreadForUser(member, initialMessage, true, undoActions).thenApply(messageChannel -> null);
} catch (Exception exception) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(exception);

View File

@@ -0,0 +1,5 @@
package dev.sheldan.abstracto.modmail.config;
public class ModMailSlashCommandNames {
public static final String MODMAIL = "modmail";
}

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.modmail.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Channel;
import net.dv8tion.jda.api.entities.Member;
@Getter
@@ -12,5 +13,6 @@ public class ClosingContext {
private Boolean notifyUser;
private Boolean log;
private Member closingMember;
private Channel channel;
private String note;
}

View File

@@ -4,12 +4,12 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.MessageChannel;
@Getter
@Setter
@Builder
public class ContactNotificationModel {
private Member targetMember;
private TextChannel createdChannel;
private MessageChannel createdChannel;
}

View File

@@ -1,11 +1,10 @@
package dev.sheldan.abstracto.modmail.model.template;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import dev.sheldan.abstracto.core.utils.ChannelUtils;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import lombok.Builder;
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
@@ -13,8 +12,8 @@ import lombok.experimental.SuperBuilder;
*/
@Getter
@Setter
@SuperBuilder
public class ModMailThreadExistsModel extends UserInitiatedServerContext {
@Builder
public class ModMailThreadExistsModel {
private ModMailThread existingModMailThread;
public String getThreadUrl() {

View File

@@ -7,10 +7,8 @@ import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.modmail.model.ClosingContext;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.interactions.InteractionHook;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -25,12 +23,14 @@ public interface ModMailThreadService {
* the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread}
* @param member The {@link AUserInAServer} to create the mod mail thread for
* @param 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
* @param undoActions A list of {@link dev.sheldan.abstracto.core.models.UndoAction actions} to be undone in case the operation fails. This list will be filled in the method.
* @return A {@link CompletableFuture future} which completes when the modmail thread is set up
*/
CompletableFuture<Void> createModMailThreadForUser(Member member, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated, List<UndoActionInstance> undoActions);
CompletableFuture<MessageChannel> createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions);
CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, MessageChannel feedBackChannel);
CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook);
/**
* Changes the configuration value of the category used to create mod mail threads to the given ID.