diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml b/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml new file mode 100644 index 000000000..63fc4ca07 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml @@ -0,0 +1,23 @@ + + + + dev.sheldan.abstracto.modules + utility + 1.0-SNAPSHOT + + 4.0.0 + + modmail-impl + + + + dev.sheldan.abstracto.modules + modmail-int + ${project.version} + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/AnonReply.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/AnonReply.java new file mode 100644 index 000000000..420ef6eb7 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/AnonReply.java @@ -0,0 +1,43 @@ +package dev.sheldan.abstracto.modmail.commands; + +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.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.config.ModMailFeatures; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class AnonReply extends AbstractConditionableCommand { + + @Autowired + private RequiresModMailCondition requiresModMailCondition; + + @Override + public CommandResult execute(CommandContext commandContext) { + return null; + } + + @Override + public CommandConfiguration getConfiguration() { + return null; + } + + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } + + @Override + public List getConditions() { + List conditions = super.getConditions(); + conditions.add(requiresModMailCondition); + return conditions; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Close.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Close.java new file mode 100644 index 000000000..acd34da6f --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Close.java @@ -0,0 +1,43 @@ +package dev.sheldan.abstracto.modmail.commands; + +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.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.config.ModMailFeatures; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class Close extends AbstractConditionableCommand { + + @Autowired + private RequiresModMailCondition requiresModMailCondition; + + @Override + public CommandResult execute(CommandContext commandContext) { + return null; + } + + @Override + public CommandConfiguration getConfiguration() { + return null; + } + + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } + + @Override + public List getConditions() { + List conditions = super.getConditions(); + conditions.add(requiresModMailCondition); + return conditions; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseSilently.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseSilently.java new file mode 100644 index 000000000..64a4d5d9d --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseSilently.java @@ -0,0 +1,43 @@ +package dev.sheldan.abstracto.modmail.commands; + +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.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.config.ModMailFeatures; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class CloseSilently extends AbstractConditionableCommand { + + @Autowired + private RequiresModMailCondition requiresModMailCondition; + + @Override + public CommandResult execute(CommandContext commandContext) { + return null; + } + + @Override + public CommandConfiguration getConfiguration() { + return null; + } + + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } + + @Override + public List getConditions() { + List conditions = super.getConditions(); + conditions.add(requiresModMailCondition); + return conditions; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Contact.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Contact.java new file mode 100644 index 000000000..2f9c0c005 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Contact.java @@ -0,0 +1,28 @@ +package dev.sheldan.abstracto.modmail.commands; + +import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; +import dev.sheldan.abstracto.core.command.config.CommandConfiguration; +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.config.ModMailFeatures; +import org.springframework.stereotype.Component; + +@Component +public class Contact extends AbstractConditionableCommand { + @Override + public CommandResult execute(CommandContext commandContext) { + return null; + } + + @Override + public CommandConfiguration getConfiguration() { + return null; + } + + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } + +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/ModMailModuleInterface.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/ModMailModuleInterface.java new file mode 100644 index 000000000..915fe0e18 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/ModMailModuleInterface.java @@ -0,0 +1,22 @@ +package dev.sheldan.abstracto.modmail.commands; + +import dev.sheldan.abstracto.core.command.config.ModuleInfo; +import dev.sheldan.abstracto.core.command.config.ModuleInterface; +import org.springframework.stereotype.Component; + +@Component +public class ModMailModuleInterface implements ModuleInterface { + + public static final String MODMAIL = "modMail"; + + @Override + public ModuleInfo getInfo() { + return ModuleInfo.builder().name(MODMAIL).description("Commands to be used for modmail.").build(); + } + + + @Override + public String getParentModule() { + return "default"; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Reply.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Reply.java new file mode 100644 index 000000000..46aa83832 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Reply.java @@ -0,0 +1,67 @@ +package dev.sheldan.abstracto.modmail.commands; + +import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; +import dev.sheldan.abstracto.core.command.condition.CommandCondition; +import dev.sheldan.abstracto.core.command.config.CommandConfiguration; +import dev.sheldan.abstracto.core.command.config.HelpInfo; +import dev.sheldan.abstracto.core.command.config.Parameter; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.config.ModMailFeatures; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.service.ModMailThreadService; +import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class Reply extends AbstractConditionableCommand { + + @Autowired + private RequiresModMailCondition requiresModMailCondition; + + @Autowired + private ModMailThreadService modMailThreadService; + + @Autowired + private ModMailThreadManagementService modMailThreadManagementService; + + @Override + public CommandResult execute(CommandContext commandContext) { + ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); + modMailThreadService.relayMessageToDm(thread, commandContext.getMessage()); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter responseText = Parameter.builder().name("text").type(String.class).description("The text to reply with").build(); + List parameters = Arrays.asList(responseText); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("reply") + .module(ModMailModuleInterface.MODMAIL) + .parameters(parameters) + .help(helpInfo) + .templated(true) + .causesReaction(true) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } + + @Override + public List getConditions() { + List conditions = super.getConditions(); + conditions.add(requiresModMailCondition); + return conditions; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailCategory.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailCategory.java new file mode 100644 index 000000000..f6b185326 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailCategory.java @@ -0,0 +1,52 @@ +package dev.sheldan.abstracto.modmail.commands; + +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.modmail.config.ModMailFeatures; +import dev.sheldan.abstracto.modmail.service.ModMailThreadService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class SetModMailCategory extends AbstractConditionableCommand { + + @Autowired + private ModMailThreadService modMailThreadService; + + @Override + public CommandResult execute(CommandContext commandContext) { + Long categoryId = (Long) commandContext.getParameters().getParameters().get(0); + modMailThreadService.setModMailCategoryTo(commandContext.getUserInitiatedContext().getServer(), categoryId); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter categoryId = Parameter.builder().name("categoryId").type(Long.class).description("The category id to be used for modmail.").build(); + List parameters = Arrays.asList(categoryId); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + List aliases = Arrays.asList("modMailCat"); + return CommandConfiguration.builder() + .name("setModMailCategory") + .module(ModMailModuleInterface.MODMAIL) + .aliases(aliases) + .parameters(parameters) + .help(helpInfo) + .templated(true) + .causesReaction(true) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/condition/RequiresModMailCondition.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/condition/RequiresModMailCondition.java new file mode 100644 index 000000000..e69fd2a31 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/condition/RequiresModMailCondition.java @@ -0,0 +1,26 @@ +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.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class RequiresModMailCondition implements CommandCondition { + + @Autowired + private ModMailThreadManagementService modMailThreadManagementService; + + @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(); + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeature.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeature.java new file mode 100644 index 000000000..5fc2b3239 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeature.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.modmail.config; + +import dev.sheldan.abstracto.core.config.FeatureConfig; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.stereotype.Component; + +@Component +public class ModMailFeature implements FeatureConfig { + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeatures.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeatures.java new file mode 100644 index 000000000..8f3e18a8e --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeatures.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.modmail.config; + +import dev.sheldan.abstracto.core.config.FeatureEnum; + +public enum ModMailFeatures implements FeatureEnum { + MODMAIL("modmail"); + + private String key; + + ModMailFeatures(String key) { + this.key = key; + } + + @Override + public String getKey() { + return this.key; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java new file mode 100644 index 000000000..efee69997 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java @@ -0,0 +1,52 @@ +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.service.management.UserManagementService; +import dev.sheldan.abstracto.modmail.config.ModMailFeature; +import dev.sheldan.abstracto.modmail.config.ModMailFeatures; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.service.ModMailThreadService; +import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; +import dev.sheldan.abstracto.templating.service.TemplateService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Slf4j +public class ModMailMessageListener implements PrivateMessageReceivedListener { + + @Autowired + private ModMailThreadService modMailThreadService; + + @Autowired + private ModMailThreadManagementService modMailThreadManagementService; + + @Autowired + private UserManagementService userManagementService; + + + @Autowired + private TemplateService templateService; + + @Override + @Transactional + public void execute(Message message) { + AUser user = userManagementService.loadUser(message.getAuthor().getIdLong()); + ModMailThread existingThread = modMailThreadManagementService.getOpenModmailThreadForUser(user); + if(existingThread != null) { + modMailThreadService.relayMessageToModMailThread(existingThread, message); + } else { + modMailThreadService.createModMailPrompt(user, message.getChannel()); + } + } + + @Override + public FeatureEnum getFeature() { + return ModMailFeatures.MODMAIL; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailMessageRepository.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailMessageRepository.java new file mode 100644 index 000000000..d572d05ec --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailMessageRepository.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.modmail.repository; + +import dev.sheldan.abstracto.modmail.models.database.ModMailMessage; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ModMailMessageRepository extends JpaRepository { +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailThreadRepository.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailThreadRepository.java new file mode 100644 index 000000000..0dc2403dc --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailThreadRepository.java @@ -0,0 +1,22 @@ +package dev.sheldan.abstracto.modmail.repository; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.models.database.AUser; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ModMailThreadRepository extends JpaRepository { + ModMailThread findByChannel(AChannel channel); + List findByUser(AUserInAServer aUserInAServer); + ModMailThread findByUser_UserReferenceAndStateNot(AUser user, ModMailThreadState state); + List findByServerAndState(AServer server, ModMailThreadState state); + ModMailThread findByUserAndStateNot(AUserInAServer userInAServer, ModMailThreadState state); + List findByUserAndState(AUserInAServer userInAServer, ModMailThreadState state); +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java new file mode 100644 index 000000000..a5296d4f1 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java @@ -0,0 +1,243 @@ +package dev.sheldan.abstracto.modmail.service; + +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import com.jagrosh.jdautilities.menu.ButtonMenu; +import dev.sheldan.abstracto.core.models.FullGuild; +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.core.models.cache.CachedReaction; +import dev.sheldan.abstracto.core.models.database.*; +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.ConfigService; +import dev.sheldan.abstracto.core.service.management.ChannelManagementService; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.models.dto.ServerChoice; +import dev.sheldan.abstracto.modmail.models.template.ModMailModeratorReplyModel; +import dev.sheldan.abstracto.modmail.models.template.ModMailServerChooserModel; +import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService; +import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; +import dev.sheldan.abstracto.templating.model.MessageToSend; +import dev.sheldan.abstracto.templating.service.TemplateService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@Component +@Slf4j +public class ModMailThreadServiceBean implements ModMailThreadService { + + public static final String MODMAIL_CATEGORY = "modmailCategory"; + @Autowired + private ModMailThreadManagementService modMailThreadManagementService; + + @Autowired + private ConfigService configService; + + @Autowired + private ChannelService channelService; + + @Autowired + private ChannelManagementService channelManagementService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private BotService botService; + + @Autowired + private TemplateService templateService; + + @Autowired + private ModMailMessageManagementService modMailMessageManagementService; + + @Autowired + private ModMailThreadServiceBean self; + + private List NUMBER_EMOJI = Arrays.asList("\u0031\u20e3", "\u0032\u20e3", "\u0033\u20e3", + "\u0034\u20e3", "\u0035\u20e3", "\u0036\u20e3", + "\u0037\u20e3", "\u0038\u20e3", "\u0039\u20e3", + "\u0040\u20e3"); + + + @Override + public void createModMailThreadForUser(FullUser aUserInAServer) { + Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, aUserInAServer.getAUserInAServer().getServerReference().getId()); + User user = aUserInAServer.getMember().getUser(); + CompletableFuture textChannel = channelService.createTextChannel(user.getName() + user.getDiscriminator(), aUserInAServer.getAUserInAServer().getServerReference(), categoryId); + + textChannel.thenAccept(channel -> { + self.createThreadObject(channel, aUserInAServer); + self.sendWelcomeMessage(channel, aUserInAServer); + }); + } + + @Transactional + public void 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()); + modMailThreadManagementService.createModMailThread(user.getAUserInAServer(), channel2); + } + + @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); + } + + @Override + public void createModMailPrompt(AUser user, MessageChannel channel) { + List knownServers = userInServerManagementService.getUserInAllServers(user.getId()); + if(knownServers.size() > 0) { + List availableGuilds = new ArrayList<>(); + HashMap choices = new HashMap<>(); + for (int i = 0; i < knownServers.size(); i++) { + AUserInAServer aUserInAServer = knownServers.get(i); + AServer serverReference = aUserInAServer.getServerReference(); + FullGuild guild = FullGuild + .builder() + .guild(botService.getGuildByIdNullable(serverReference.getId())) + .server(serverReference) + .build(); + String reactionEmote = NUMBER_EMOJI.get(i); + ServerChoice serverChoice = ServerChoice.builder().guild(guild).reactionEmote(reactionEmote).build(); + choices.put(reactionEmote, aUserInAServer); + availableGuilds.add(serverChoice); + } + ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel + .builder() + .commonGuilds(availableGuilds) + .build(); + + String text = templateService.renderTemplate("modmail_modal_server_choice", modMailServerChooserModel); + // todo dont instantiate directly + EventWaiter waiter = new EventWaiter(); + botService.getInstance().addEventListener(waiter); + ButtonMenu menu = new ButtonMenu.Builder() + .setChoices(choices.keySet().toArray(new String[0])) + .setEventWaiter(waiter) + .setDescription(text) + .setAction(reactionEmote -> { + AUserInAServer chosenServer = choices.get(reactionEmote.getEmoji()); + Member memberInServer = botService.getMemberInServer(chosenServer); + FullUser fullUser = FullUser.builder().member(memberInServer).aUserInAServer(chosenServer).build(); + self.createModMailThreadForUser(fullUser); + botService.getInstance().removeEventListener(waiter); + }) + .build(); + menu.display(channel); + } + } + + @Override + public void sendWelcomeMessage(TextChannel channel, FullUser aUserInAServer) { + String text = templateService.renderTemplate("modmail_welcome_message", new Object()); + channel.sendMessage(text).queue(); + } + + @Override + public void relayMessageToModMailThread(ModMailThread modMailThread, Message message) { + Optional textChannelFromServer = botService.getTextChannelFromServer(modMailThread.getServer().getId(), modMailThread.getChannel().getId()); + if(textChannelFromServer.isPresent()) { + TextChannel textChannel = textChannelFromServer.get(); + self.sendUserReply(textChannel, modMailThread, message); + } + } + + @Transactional + public void sendUserReply(TextChannel textChannel, ModMailThread modMailThread, Message message) { + FullUser fullUser = FullUser + .builder() + .aUserInAServer(modMailThread.getUser()) + .member(botService.getMemberInServer(modMailThread.getUser())) + .build(); + ModMailModeratorReplyModel modMailUserReplyModel = ModMailModeratorReplyModel + .builder() + .modMailThread(modMailThread) + .postedMessage(message) + .threadUser(fullUser) + .build(); + MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_moderator_message", modMailUserReplyModel); + List> completableFutures = channelService.sendMessageToEndInTextChannel(messageToSend, textChannel); + List messages = new ArrayList<>(); + completableFutures.forEach(messageCompletableFuture -> { + try { + Message messageToAdd = messageCompletableFuture.get(); + messages.add(messageToAdd); + } catch (InterruptedException | ExecutionException e) { + log.error("Error while executing future to retrieve reaction.", e); + } + self.saveMessageIds(messages, modMailThread, modMailThread.getUser(), false); + }); + } + + @Override + public void relayMessageToDm(ModMailThread modMailThread, Message message) { + User userById = botService.getInstance().getUserById(modMailThread.getUser().getUserReference().getId()); + if(userById != null) { + userById.openPrivateChannel().queue(privateChannel -> { + self.sendReply(modMailThread, message, privateChannel); + }); + } + } + + @Transactional + public void sendReply(ModMailThread modMailThread, Message message, PrivateChannel privateChannel) { + AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember()); + Member userInGuild = botService.getMemberInServer(modMailThread.getUser()); + FullUser moderatorUser = FullUser + .builder() + .aUserInAServer(moderator) + .member(message.getMember()) + .build(); + FullUser fullThreadUser = FullUser + .builder() + .aUserInAServer(modMailThread.getUser()) + .member(userInGuild) + .build(); + ModMailModeratorReplyModel modMailUserReplyModel = ModMailModeratorReplyModel + .builder() + .modMailThread(modMailThread) + .postedMessage(message) + .threadUser(fullThreadUser) + .moderator(moderatorUser) + .build(); + MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_staff_message", modMailUserReplyModel); + List> completableFutures = channelService.sendMessageToEndInTextChannel(messageToSend, privateChannel); + CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> { + List messages = new ArrayList<>(); + completableFutures.forEach(messageCompletableFuture -> { + try { + Message messageToAdd = messageCompletableFuture.get(); + messages.add(messageToAdd); + } catch (InterruptedException | ExecutionException e) { + log.error("Error while executing send message to reply to user.", e); + } + }); + self.saveMessageIds(messages, modMailThread, moderator, false); + }); + } + + @Transactional + public void saveMessageIds(List messages, ModMailThread modMailThread, AUserInAServer author, Boolean anonymous) { + messages.forEach(message -> { + modMailMessageManagementService.addMessageToThread(modMailThread, message, author, false); + }); + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementServiceBean.java new file mode 100644 index 000000000..8c26929de --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementServiceBean.java @@ -0,0 +1,30 @@ +package dev.sheldan.abstracto.modmail.service.management; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.modmail.models.database.ModMailMessage; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.repository.ModMailMessageRepository; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ModMailMessageManagementServiceBean implements ModMailMessageManagementService { + + @Autowired + private ModMailMessageRepository modMailMessageRepository; + + @Override + public ModMailMessage addMessageToThread(ModMailThread modMailThread, Message message, AUserInAServer author, Boolean anonymous) { + ModMailMessage modMailMessage = ModMailMessage + .builder() + .author(author) + .messageId(message.getIdLong()) + .threadReference(modMailThread) + .anonymous(anonymous) + .build(); + + modMailMessageRepository.save(modMailMessage); + return modMailMessage; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java new file mode 100644 index 000000000..a301a2b7a --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java @@ -0,0 +1,70 @@ +package dev.sheldan.abstracto.modmail.service.management; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AUser; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.service.management.ChannelManagementService; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState; +import dev.sheldan.abstracto.modmail.repository.ModMailThreadRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.List; + +@Component +public class ModMailThreadManagementServiceBean implements ModMailThreadManagementService { + + @Autowired + private ModMailThreadRepository modMailThreadRepository; + + @Autowired + private ChannelManagementService channelManagementService; + + @Override + public ModMailThread getByChannelId(Long channelId) { + AChannel channel = channelManagementService.loadChannel(channelId); + return getByChannel(channel); + } + + @Override + public ModMailThread getByChannel(AChannel channel) { + return modMailThreadRepository.findByChannel(channel); + } + + @Override + public List getThreadByUserAndState(AUserInAServer userInAServer, ModMailThreadState state) { + return modMailThreadRepository.findByUserAndState(userInAServer, state); + } + + @Override + public ModMailThread getOpenModmailThreadForUser(AUserInAServer userInAServer) { + return modMailThreadRepository.findByUserAndStateNot(userInAServer, ModMailThreadState.CLOSED); + } + + @Override + public ModMailThread getOpenModmailThreadForUser(AUser user) { + return modMailThreadRepository.findByUser_UserReferenceAndStateNot(user, ModMailThreadState.CLOSED); + } + + @Override + public List getModMailThreadForUser(AUserInAServer aUserInAServer) { + return modMailThreadRepository.findByUser(aUserInAServer); + } + + @Override + public void createModMailThread(AUserInAServer userInAServer, AChannel channel) { + ModMailThread thread = ModMailThread + .builder() + .channel(channel) + .created(Instant.now()) + .user(userInAServer) + .server(userInAServer.getServerReference()) + .state(ModMailThreadState.INITIAL) + .updated(Instant.now()) + .build(); + + modMailThreadRepository.save(thread); + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/serverChooser/modmail_modal_server_choice_en_US.ftl b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/serverChooser/modmail_modal_server_choice_en_US.ftl new file mode 100644 index 000000000..e40aba800 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/serverChooser/modmail_modal_server_choice_en_US.ftl @@ -0,0 +1,5 @@ +<#include "server_chooser_server_list_description"> + +<#list commonGuilds as guild> + ${guild.reactionEmote} ${guild.guild.guild.name} + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/threadContent/modmail_staff_message_embed_en_US.ftl b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/threadContent/modmail_staff_message_embed_en_US.ftl new file mode 100644 index 000000000..aeacafc66 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/threadContent/modmail_staff_message_embed_en_US.ftl @@ -0,0 +1,20 @@ +{ + "author": { + "name": "${threadUser.member.effectiveName}", + "avatar": "${threadUser.member.user.effectiveAvatarUrl}" + }, + "title": { + "title": "<#include "modmail_thread_staff_message_title">" + }, + "color" : { + "r": 200, + "g": 0, + "b": 255 + }, + <#if postedMessage.contentRaw?has_content> + "description": "${postedMessage.contentRaw}" + + <#if postedMessage.attachments?size gt 0> + ,"imageUrl": "${postedMessage.attachments[0].proxyUrl}" + +} \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/threadContent/modmail_user_message_embed_en_US.ftl b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/threadContent/modmail_user_message_embed_en_US.ftl new file mode 100644 index 000000000..a8bd51305 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/threadContent/modmail_user_message_embed_en_US.ftl @@ -0,0 +1,20 @@ +{ + "author": { + "name": "${threadUser.member.effectiveName}", + "avatar": "${threadUser.member.user.effectiveAvatarUrl}" + }, + "title": { + "title": "<#include "modmail_thread_user_message_title">" + }, + "color" : { + "r": 200, + "g": 0, + "b": 255 + }, + <#if postedMessage.contentRaw?has_content> + "description": "${postedMessage.contentRaw}" + + <#if postedMessage.attachments?size gt 0> + ,"imageUrl": "${postedMessage.attachments[0].proxyUrl}" + +} \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/welcomeMessage/modmail_welcome_message_en_US.ftl b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/welcomeMessage/modmail_welcome_message_en_US.ftl new file mode 100644 index 000000000..dd117fc58 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/welcomeMessage/modmail_welcome_message_en_US.ftl @@ -0,0 +1 @@ +You opened a mod mail thread on the server reply in this channel to send messages to a staff only channel. \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/pom.xml b/abstracto-application/abstracto-modules/modmail/modmail-int/pom.xml new file mode 100644 index 000000000..2779c72e8 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/pom.xml @@ -0,0 +1,22 @@ + + + + dev.sheldan.abstracto.modules + utility + 1.0-SNAPSHOT + + 4.0.0 + + modmail-int + + + + dev.sheldan.abstracto.templating + templating-interface + ${project.version} + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailMessage.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailMessage.java new file mode 100644 index 000000000..3c23a0d8a --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailMessage.java @@ -0,0 +1,32 @@ +package dev.sheldan.abstracto.modmail.models.database; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import lombok.*; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; + +@Builder +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "modmail_messages") +@Cacheable +@Getter +@Setter +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class ModMailMessage { + + @Id + private Long messageId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "modmail_message_author", nullable = false) + private AUserInAServer author; + + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @JoinColumn(name = "threadReference", nullable = false) + private ModMailThread threadReference; + + private Boolean anonymous; +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThread.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThread.java new file mode 100644 index 000000000..d5df152c4 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThread.java @@ -0,0 +1,62 @@ +package dev.sheldan.abstracto.modmail.models.database; + +import dev.sheldan.abstracto.core.models.database.*; +import lombok.*; +import net.dv8tion.jda.api.entities.ChannelType; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Builder +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "modmail_threads") +@Cacheable +@Getter +@Setter +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class ModMailThread { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "modmail_user", nullable = false) + private AUserInAServer user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "modmail_thread_channel", nullable = false) + private AChannel channel; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "modmail_thread_server", nullable = false) + private AServer server; + + @Column + private Instant created; + + @Column + private Instant updated; + + @Column + private Instant closed; + + @OneToMany( + fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + orphanRemoval = true) + @JoinColumn(name = "threadReference") + @Builder.Default + @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private List messages = new ArrayList<>(); + + @Enumerated(EnumType.STRING) + @Column + private ModMailThreadState state; + +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadState.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadState.java new file mode 100644 index 000000000..0b09e2ebb --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadState.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.modmail.models.database; + +public enum ModMailThreadState { + INITIAL, USER_REPLIED, MOD_REPLIED, CLOSED, CLOSING; + + public static ModMailThreadState getState(ModMailThreadState type) { + switch (type) { + case INITIAL: return ModMailThreadState.INITIAL; + case USER_REPLIED: return ModMailThreadState.USER_REPLIED; + case CLOSED: return ModMailThreadState.CLOSED; + case CLOSING: return ModMailThreadState.CLOSING; + default: + case MOD_REPLIED: return ModMailThreadState.MOD_REPLIED; + } + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/dto/ServerChoice.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/dto/ServerChoice.java new file mode 100644 index 000000000..278f68791 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/dto/ServerChoice.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.modmail.models.dto; + +import dev.sheldan.abstracto.core.models.FullGuild; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class ServerChoice { + private FullGuild guild; + private String reactionEmote; +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailModeratorReplyModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailModeratorReplyModel.java new file mode 100644 index 000000000..4df512247 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailModeratorReplyModel.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.modmail.models.template; + +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Message; + +@Getter +@Setter +@Builder +public class ModMailModeratorReplyModel { + private FullUser threadUser; + private FullUser moderator; + private Message postedMessage; + private ModMailThread modMailThread; +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailServerChooserModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailServerChooserModel.java new file mode 100644 index 000000000..9147b790b --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailServerChooserModel.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.modmail.models.template; + +import dev.sheldan.abstracto.modmail.models.dto.ServerChoice; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class ModMailServerChooserModel { + private List commonGuilds; +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailUserReplyModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailUserReplyModel.java new file mode 100644 index 000000000..3cc4b2477 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailUserReplyModel.java @@ -0,0 +1,17 @@ +package dev.sheldan.abstracto.modmail.models.template; + +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Message; + +@Getter +@Setter +@Builder +public class ModMailUserReplyModel { + private FullUser threadUser; + private Message postedMessage; + private ModMailThread modMailThread; +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java new file mode 100644 index 000000000..93080d5d8 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java @@ -0,0 +1,22 @@ +package dev.sheldan.abstracto.modmail.service; + + +import dev.sheldan.abstracto.core.models.FullUser; +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.Message; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.TextChannel; + +public interface ModMailThreadService { + void createModMailThreadForUser(FullUser userInAServer); + boolean hasOpenThread(AUserInAServer aUserInAServer); + boolean hasOpenThread(AUser user); + void setModMailCategoryTo(AServer server, Long categoryId); + void createModMailPrompt(AUser user, MessageChannel messageChannel); + void sendWelcomeMessage(TextChannel channel, FullUser aUserInAServer); + void relayMessageToModMailThread(ModMailThread modMailThread, Message message); + void relayMessageToDm(ModMailThread modMailThread, Message message); +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementService.java new file mode 100644 index 000000000..273ca69fa --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementService.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.modmail.service.management; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.modmail.models.database.ModMailMessage; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import net.dv8tion.jda.api.entities.Message; + +public interface ModMailMessageManagementService { + ModMailMessage addMessageToThread(ModMailThread modMailThread, Message message, AUserInAServer author, Boolean anonymous); +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementService.java new file mode 100644 index 000000000..1d614716e --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementService.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.modmail.service.management; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AUser; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState; +import net.dv8tion.jda.api.entities.TextChannel; + +import java.util.List; + +public interface ModMailThreadManagementService { + ModMailThread getByChannelId(Long channelId); + ModMailThread getByChannel(AChannel channel); + List getThreadByUserAndState(AUserInAServer userInAServer, ModMailThreadState state); + ModMailThread getOpenModmailThreadForUser(AUserInAServer userInAServer); + ModMailThread getOpenModmailThreadForUser(AUser user); + List getModMailThreadForUser(AUserInAServer aUserInAServer); + void createModMailThread(AUserInAServer userInAServer, AChannel channel); + +} diff --git a/abstracto-application/abstracto-modules/modmail/pom.xml b/abstracto-application/abstracto-modules/modmail/pom.xml new file mode 100644 index 000000000..4e26d118f --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/pom.xml @@ -0,0 +1,29 @@ + + + + dev.sheldan.abstracto + abstracto-modules + 1.0-SNAPSHOT + + 4.0.0 + + dev.sheldan.abstracto.modules + modmail + pom + + + modmail-int + modmail-impl + + + + + dev.sheldan.abstracto.core + core-interface + ${project.version} + compile + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/pom.xml b/abstracto-application/abstracto-modules/pom.xml index 4f75f0029..94bb2bd2f 100644 --- a/abstracto-application/abstracto-modules/pom.xml +++ b/abstracto-application/abstracto-modules/pom.xml @@ -15,6 +15,7 @@ moderation utility experience-tracking + modmail diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardPostDeletedListener.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardPostDeletedListener.java index 1d13d1840..eea1271c5 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardPostDeletedListener.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardPostDeletedListener.java @@ -24,7 +24,8 @@ public class StarboardPostDeletedListener implements MessageDeletedListener { Optional byStarboardPostId = starboardPostManagementService.findByStarboardPostId(messageBefore.getMessageId()); if(byStarboardPostId.isPresent()) { StarboardPost post = byStarboardPostId.get(); - log.info("Removing starboard post: message {}, channel {}, server {}, because the message was deleted", post.getPostMessageId(), post.getSourceChanel().getId(), post.getAuthor().getId()); + log.info("Removing starboard post: message {}, channel {}, server {}, because the message was deleted", + post.getPostMessageId(), post.getSourceChanel().getId(), post.getAuthor().getUserReference().getId()); starboardPostManagementService.setStarboardPostIgnored(messageBefore.getMessageId(), true); } } diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java index c856c7830..411c07f6d 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java @@ -25,7 +25,7 @@ public class StarboardPostManagementServiceBean implements StarboardPostManageme public StarboardPost createStarboardPost(CachedMessage starredMessage, AUserInAServer starredUser, AUserInAServer starringUser, AServerAChannelMessage starboardPost) { StarboardPost post = StarboardPost .builder() - .author(starredUser.getUserReference()) + .author(starredUser) .postMessageId(starredMessage.getMessageId()) .starboardMessageId(starboardPost.getMessageId()) .starboardChannel(starboardPost.getChannel()) diff --git a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/database/StarboardPost.java b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/database/StarboardPost.java index b3a90a361..fbd019a2f 100644 --- a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/database/StarboardPost.java +++ b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/database/StarboardPost.java @@ -1,7 +1,7 @@ package dev.sheldan.abstracto.utility.models.database; import dev.sheldan.abstracto.core.models.database.AChannel; -import dev.sheldan.abstracto.core.models.database.AUser; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; import lombok.*; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -27,7 +27,7 @@ public class StarboardPost { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "poster", nullable = false) - private AUser author; + private AUserInAServer author; @Column private Long starboardMessageId; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfigListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfigListener.java index 148dc4b39..d0371fd6f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfigListener.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfigListener.java @@ -26,9 +26,11 @@ public class CommandConfigListener implements ServerConfigListener { @Override public void updateServerConfig(AServer server) { commandList.forEach(command -> { - ACommand aCommand = commandManagementService.findCommandByName(command.getConfiguration().getName()); - if(!commandInServerManagementService.doesCommandExistInServer(aCommand, server)) { - commandInServerManagementService.crateCommandInServer(aCommand, server); + if(command.getConfiguration() != null) { + ACommand aCommand = commandManagementService.findCommandByName(command.getConfiguration().getName()); + if(!commandInServerManagementService.doesCommandExistInServer(aCommand, server)) { + commandInServerManagementService.crateCommandInServer(aCommand, server); + } } }); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandCreationListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandCreationListener.java index eadff86ac..306621729 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandCreationListener.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/config/CommandCreationListener.java @@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.command.service.CommandService; import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService; import dev.sheldan.abstracto.core.service.FeatureFlagService; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; @@ -13,6 +14,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; @Component +@Slf4j public class CommandCreationListener { @Autowired @@ -38,6 +40,10 @@ public class CommandCreationListener { } }); commandList.forEach(command -> { + if(command.getConfiguration() == null) { + log.warn("Command {} has null configuration.", command); + return; + } if(!commandService.doesCommandExist(command.getConfiguration().getName())) { commandService.createCommand(command.getConfiguration().getName(), command.getConfiguration().getModule(), command.getFeature()); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java index 81dc11803..d167b54dd 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java @@ -33,6 +33,9 @@ public class CommandManager implements CommandRegistry { public Command findCommandByParameters(String name, UnParsedCommandParameter unParsedCommandParameter) { Optional commandOptional = commands.stream().filter((Command o )-> { CommandConfiguration commandConfiguration = o.getConfiguration(); + if(commandConfiguration == null) { + return false; + } if(!commandNameMatches(name, commandConfiguration)) { return false; } @@ -88,7 +91,8 @@ public class CommandManager implements CommandRegistry { public List getAllCommandsFromModule(ModuleInterface moduleInterface) { List commandsFromModule = new ArrayList<>(); this.getAllCommands().forEach(command -> { - if(command.getConfiguration().getModule().equals(moduleInterface.getInfo().getName())){ + CommandConfiguration configuration = command.getConfiguration(); + if(configuration != null && configuration.getModule().equals(moduleInterface.getInfo().getName())){ commandsFromModule.add(command); } }); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandServiceBean.java index 97cef6b67..52768c10a 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandServiceBean.java @@ -11,10 +11,12 @@ import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.models.database.AFeature; import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.models.database.AServer; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class CommandServiceBean implements CommandService { @Autowired @@ -32,6 +34,10 @@ public class CommandServiceBean implements CommandService { @Override public ACommand createCommand(String name, String moduleName, FeatureEnum featureEnum) { AModule module = moduleManagementService.getOrCreate(moduleName); + if(featureEnum == null) { + log.warn("Command {} in module {} has no feature.", name, moduleName); + return null; + } AFeature feature = featureManagementService.getFeature(featureEnum.getKey()); return commandManagementService.createCommand(name, module, feature); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetNumber.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetFloat.java similarity index 95% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetNumber.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetFloat.java index d82c564f5..aa84a6926 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetNumber.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetFloat.java @@ -16,7 +16,7 @@ import java.util.Arrays; import java.util.List; @Component -public class SetNumber extends AbstractConditionableCommand { +public class SetFloat extends AbstractConditionableCommand { @Autowired private ConfigService configService; @@ -37,7 +37,7 @@ public class SetNumber extends AbstractConditionableCommand { List parameters = Arrays.asList(channelGroupName, channelToAdd); HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); return CommandConfiguration.builder() - .name("setNumber") + .name("setFloat") .module(ConfigModuleInterface.CONFIG) .parameters(parameters) .templated(true) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetLong.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetLong.java new file mode 100644 index 000000000..1f1e79a15 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetLong.java @@ -0,0 +1,53 @@ +package dev.sheldan.abstracto.core.commands.config; + +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.config.features.CoreFeatures; +import dev.sheldan.abstracto.core.service.ConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class SetLong extends AbstractConditionableCommand { + + @Autowired + private ConfigService configService; + + @Override + public CommandResult execute(CommandContext commandContext) { + String key = (String) commandContext.getParameters().getParameters().get(0); + Long value = (Long) commandContext.getParameters().getParameters().get(1); + configService.setLongValue(key, commandContext.getGuild().getIdLong(), value); + + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter channelGroupName = Parameter.builder().name("key").type(String.class).description("The key to change.").build(); + Parameter channelToAdd = Parameter.builder().name("value").type(Long.class).description("The numeric value to use for the config.").build(); + List parameters = Arrays.asList(channelGroupName, channelToAdd); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("setLong") + .module(ConfigModuleInterface.CONFIG) + .parameters(parameters) + .templated(true) + .help(helpInfo) + .causesReaction(true) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return CoreFeatures.CORE_FEATURE; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ChannelListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ChannelListener.java index 612840358..fb132ff3a 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ChannelListener.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ChannelListener.java @@ -39,7 +39,7 @@ public class ChannelListener extends ListenerAdapter { log.info("Handling channel created event. Channel {}, Server {}", event.getChannel().getIdLong(), event.getGuild().getIdLong()); AServer serverObject = serverRepository.getOne(event.getGuild().getIdLong()); TextChannel createdChannel = event.getChannel(); - AChannelType type = AChannel.getAChannelType(createdChannel.getType()); + AChannelType type = AChannelType.getAChannelType(createdChannel.getType()); channelManagementService.createChannel(createdChannel.getIdLong(), type, serverObject); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageReceivedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageReceivedListenerBean.java index 27a957ccc..93bdb359a 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageReceivedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageReceivedListenerBean.java @@ -1,14 +1,15 @@ package dev.sheldan.abstracto.core.listener; import dev.sheldan.abstracto.core.config.FeatureConfig; +import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.FeatureFlagService; import dev.sheldan.abstracto.core.service.MessageCache; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; import javax.annotation.Nonnull; import java.util.List; @@ -23,9 +24,15 @@ public class MessageReceivedListenerBean extends ListenerAdapter { @Autowired private List listenerList; + @Autowired + private List privateMessageReceivedListeners; + @Autowired private FeatureFlagService featureFlagService; + @Autowired + private BotService botService; + @Override public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) { messageCache.putMessageInCache(event.getMessage()); @@ -42,5 +49,17 @@ public class MessageReceivedListenerBean extends ListenerAdapter { }); } - + @Override + public void onPrivateMessageReceived(@Nonnull PrivateMessageReceivedEvent event) { + if(event.getAuthor().getId().equals(botService.getInstance().getSelfUser().getId())) { + return; + } + privateMessageReceivedListeners.forEach(messageReceivedListener -> { + try { + messageReceivedListener.execute(event.getMessage()); + } catch (Exception e) { + log.error("Listener {} had exception when executing.", messageReceivedListener, e); + } + }); + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/model/database/ALock.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/model/database/ALock.java new file mode 100644 index 000000000..68c733b11 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/model/database/ALock.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.core.model.database; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Entity +@Table(name = "lock") +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class ALock { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/LockRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/LockRepository.java new file mode 100644 index 000000000..75b2a09c1 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/LockRepository.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.core.repository; + +import dev.sheldan.abstracto.core.model.database.ALock; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Lock; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import javax.persistence.LockModeType; + +@Repository +public interface LockRepository extends JpaRepository { + + @Lock(LockModeType.PESSIMISTIC_WRITE) + @Query("select a from ALock a where a.id = :id") + ALock findArticleForRead(@Param("id") Long id); +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/UserInServerRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/UserInServerRepository.java index 89ecddf56..dd050d1d1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/UserInServerRepository.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/UserInServerRepository.java @@ -8,6 +8,7 @@ import org.springframework.data.jpa.repository.QueryHints; import org.springframework.stereotype.Repository; import javax.persistence.QueryHint; +import java.util.List; @Repository public interface UserInServerRepository extends JpaRepository { @@ -17,4 +18,7 @@ public interface UserInServerRepository extends JpaRepository findByUserReference(AUser user); } \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java index 149ba0200..7f6815379 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java @@ -3,13 +3,11 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.exception.ChannelException; import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.core.models.database.AChannel; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.requests.restaction.MessageAction; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -33,7 +31,7 @@ public class ChannelServiceBean implements ChannelService { } @Override - public void sendTextInAChannel(String text, TextChannel channel) { + public void sendTextInAChannel(String text, MessageChannel channel) { sendTextInAChannelFuture(text, channel); } @@ -55,7 +53,7 @@ public class ChannelServiceBean implements ChannelService { } @Override - public CompletableFuture sendTextInAChannelFuture(String text, TextChannel channel) { + public CompletableFuture sendTextInAChannelFuture(String text, MessageChannel channel) { return channel.sendMessage(text).submit(); } @@ -77,7 +75,7 @@ public class ChannelServiceBean implements ChannelService { } @Override - public CompletableFuture sendEmbedInAChannelFuture(MessageEmbed embed, TextChannel channel) { + public CompletableFuture sendEmbedInAChannelFuture(MessageEmbed embed, MessageChannel channel) { return channel.sendMessage(embed).submit(); } @@ -91,7 +89,7 @@ public class ChannelServiceBean implements ChannelService { } @Override - public List> sendMessageToEndInTextChannel(MessageToSend messageToSend, TextChannel textChannel) { + public List> sendMessageToEndInTextChannel(MessageToSend messageToSend, MessageChannel textChannel) { String messageText = messageToSend.getMessage(); List> futures = new ArrayList<>(); if(StringUtils.isBlank(messageText)) { @@ -130,7 +128,7 @@ public class ChannelServiceBean implements ChannelService { } @Override - public void editMessageInAChannel(MessageToSend messageToSend, TextChannel channel, Long messageId) { + public void editMessageInAChannel(MessageToSend messageToSend, MessageChannel channel, Long messageId) { MessageAction messageAction; if(!StringUtils.isBlank(messageToSend.getMessage())) { messageAction = channel.editMessageById(messageId, messageToSend.getMessage()); @@ -146,4 +144,18 @@ public class ChannelServiceBean implements ChannelService { } messageAction.queue(); } + + @Override + public CompletableFuture createTextChannel(String name, AServer server, Long categoryId) { + Optional guildById = botService.getGuildById(server.getId()); + if(guildById.isPresent()) { + Guild guild = guildById.get(); + Category categoryById = guild.getCategoryById(categoryId); + if(categoryById != null) { + return categoryById.createTextChannel(name).submit(); + } + return null; + } + return null; + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConfigServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConfigServiceBean.java index 7f4bf4972..86143bbd1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConfigServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConfigServiceBean.java @@ -17,6 +17,11 @@ public class ConfigServiceBean implements ConfigService{ return getDoubleValue(name, serverId, 0D); } + @Override + public Long getLongValue(String name, Long serverId) { + return getLongValue(name, serverId, 0L); + } + @Override public Double getDoubleValue(String name, Long serverId, Double defaultValue) { AConfig config = configManagementService.loadConfig(serverId, name); @@ -35,6 +40,15 @@ public class ConfigServiceBean implements ConfigService{ return config.getStringValue(); } + @Override + public Long getLongValue(String name, Long serverId, Long defaultValue) { + AConfig config = configManagementService.loadConfig(serverId, name); + if(config == null) { + return defaultValue; + } + return config.getLongValue(); + } + @Override public void setDoubleValue(String name, Long serverId, Double value) { if(configManagementService.configExists(serverId, name)) { @@ -44,6 +58,15 @@ public class ConfigServiceBean implements ConfigService{ } } + @Override + public void setLongValue(String name, Long serverId, Long value) { + if(configManagementService.configExists(serverId, name)) { + configManagementService.setLongValue(serverId, name, value); + } else { + throw new ConfigurationException(String.format("Key %s does not exist.", name)); + } + } + @Override public void setStringValue(String name, Long serverId, String value) { if(configManagementService.configExists(serverId, name)) { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/LockServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/LockServiceBean.java new file mode 100644 index 000000000..d27edabe0 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/LockServiceBean.java @@ -0,0 +1,19 @@ +package dev.sheldan.abstracto.core.service; + +import dev.sheldan.abstracto.core.command.models.TableLocks; +import dev.sheldan.abstracto.core.repository.LockRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class LockServiceBean implements LockService { + + @Autowired + private LockRepository lockRepository; + + @Override + public void lockTable(TableLocks toLock) { + int ordinal = toLock.ordinal(); + lockRepository.findArticleForRead((long) ordinal); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java index a3a9bd09a..b1b7bb855 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java @@ -103,7 +103,7 @@ public class StartupServiceBean implements Startup { newChannels.forEach(aLong -> { GuildChannel channel1 = available.stream().filter(channel -> channel.getIdLong() == aLong).findFirst().get(); log.trace("Adding new channel: {}", aLong); - AChannelType type = AChannel.getAChannelType(channel1.getType()); + AChannelType type = AChannelType.getAChannelType(channel1.getType()); channelManagementService.createChannel(channel1.getIdLong(), type, existingServer); }); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java index 7a6edafe7..f17f352ed 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java @@ -1,9 +1,11 @@ package dev.sheldan.abstracto.core.service.management; +import dev.sheldan.abstracto.core.command.models.TableLocks; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannelType; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.repository.ChannelRepository; +import dev.sheldan.abstracto.core.service.LockService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,6 +17,9 @@ public class ChannelManagementServiceBean implements ChannelManagementService { @Autowired private ChannelRepository repository; + @Autowired + private LockService lockService; + @Override public AChannel loadChannel(Long id) { return repository.getOne(id); @@ -22,15 +27,20 @@ public class ChannelManagementServiceBean implements ChannelManagementService { @Override public AChannel createChannel(Long id, AChannelType type, AServer server) { - log.info("Creating channel {} with type {}", id, type); - AChannel build = AChannel - .builder() - .id(id) - .type(type) - .server(server) - .deleted(false) - .build(); - return repository.save(build); + lockService.lockTable(TableLocks.CHANNELS); + if(!channelExists(id)) { + log.info("Creating channel {} with type {}", id, type); + AChannel build = AChannel + .builder() + .id(id) + .type(type) + .server(server) + .deleted(false) + .build(); + return repository.save(build); + } else { + return loadChannel(id); + } } @Override @@ -40,6 +50,11 @@ public class ChannelManagementServiceBean implements ChannelManagementService { return channel; } + @Override + public boolean channelExists(Long id) { + return repository.existsById(id); + } + @Override public void removeChannel(Long id) { log.info("Deleting channel {}", id); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementServiceBean.java index 7682dc9fe..71d16ecf6 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementServiceBean.java @@ -65,6 +65,19 @@ public class ConfigManagementServiceBean implements ConfigManagementService { return config; } + @Override + public AConfig createConfig(Long serverId, String name, Long value) { + AServer server = serverManagementService.loadOrCreate(serverId); + AConfig config = AConfig + .builder() + .longValue(value) + .server(server) + .name(name) + .build(); + configRepository.save(config); + return config; + } + @Override public AConfig createIfNotExists(Long serverId, String name, String value) { AConfig config = loadConfig(serverId, name); @@ -100,6 +113,13 @@ public class ConfigManagementServiceBean implements ConfigManagementService { return config; } + @Override + public AConfig setLongValue(Long serverId, String name, Long value) { + AConfig config = loadConfig(serverId, name); + config.setLongValue(value); + return config; + } + @Override public AConfig setStringValue(Long serverId, String name, String value) { AConfig config = loadConfig(serverId, name); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementServiceBean.java index 157be0eca..60201bf2b 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementServiceBean.java @@ -9,6 +9,8 @@ import net.dv8tion.jda.api.entities.Member; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.List; + @Component @Slf4j public class UserInServerManagementServiceBean implements UserInServerManagementService { @@ -55,4 +57,10 @@ public class UserInServerManagementServiceBean implements UserInServerManagement userInServerRepository.save(aUserInAServer); return aUserInAServer; } + + @Override + public List getUserInAllServers(Long userId) { + AUser user = userManagementService.loadUser(userId); + return userInServerRepository.findByUserReference(user); + } } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/TableLocks.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/TableLocks.java new file mode 100644 index 000000000..d5f9462f3 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/TableLocks.java @@ -0,0 +1,5 @@ +package dev.sheldan.abstracto.core.command.models; + +public enum TableLocks { + CHANNELS +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/PrivateMessageReceivedListener.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/PrivateMessageReceivedListener.java new file mode 100644 index 000000000..fa18ee289 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/PrivateMessageReceivedListener.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.listener; + +import net.dv8tion.jda.api.entities.Message; + +public interface PrivateMessageReceivedListener extends FeatureAware { + void execute(Message message); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullGuild.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullGuild.java new file mode 100644 index 000000000..b1e6ca4e4 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullGuild.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.core.models; + +import dev.sheldan.abstracto.core.models.database.AServer; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Guild; + +@Setter +@Getter +@Builder +public class FullGuild { + private AServer server; + private Guild guild; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java index 746860cbf..8a084b271 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java @@ -43,15 +43,6 @@ public class AChannel implements SnowFlake { @Column private Boolean deleted; - public static AChannelType getAChannelType(ChannelType type) { - switch (type) { - case TEXT: return AChannelType.TEXT; - case PRIVATE: return AChannelType.DM; - case VOICE: return AChannelType.VOICE; - case CATEGORY: return AChannelType.CATEGORY; - default: return AChannelType.UNKOWN; - } - } @Override public boolean equals(Object o) { diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java index 2182b8cdd..0f1d00173 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java @@ -1,5 +1,17 @@ package dev.sheldan.abstracto.core.models.database; +import net.dv8tion.jda.api.entities.ChannelType; + public enum AChannelType { - TEXT, DM, VOICE, NEWS, CATEGORY, UNKOWN + TEXT, DM, VOICE, NEWS, CATEGORY, UNKOWN; + + public static AChannelType getAChannelType(ChannelType type) { + switch (type) { + case TEXT: return AChannelType.TEXT; + case PRIVATE: return AChannelType.DM; + case VOICE: return AChannelType.VOICE; + case CATEGORY: return AChannelType.CATEGORY; + default: return AChannelType.UNKOWN; + } + } } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AConfig.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AConfig.java index 554895c0b..9aec3938b 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AConfig.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AConfig.java @@ -31,6 +31,10 @@ public class AConfig { @Setter private Double doubleValue; + @Column + @Setter + private Long longValue; + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "server_id", nullable = false) @Getter diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java index eb105bcb7..9c7a8c1b4 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java @@ -1,8 +1,10 @@ package dev.sheldan.abstracto.core.service; +import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.core.models.database.AChannel; import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.TextChannel; @@ -12,14 +14,16 @@ import java.util.concurrent.CompletableFuture; public interface ChannelService { void sendTextInAChannel(String text, AChannel channel); - void sendTextInAChannel(String text, TextChannel channel); + void sendTextInAChannel(String text, MessageChannel channel); CompletableFuture sendTextInAChannelFuture(String text, AChannel channel); - CompletableFuture sendTextInAChannelFuture(String text, TextChannel channel); + CompletableFuture sendTextInAChannelFuture(String text, MessageChannel channel); CompletableFuture sendEmbedInAChannelFuture(MessageEmbed embed, AChannel channel); - CompletableFuture sendEmbedInAChannelFuture(MessageEmbed embed, TextChannel channel); + CompletableFuture sendEmbedInAChannelFuture(MessageEmbed embed, MessageChannel channel); List> sendMessageToEndInAChannel(MessageToSend messageToSend, AChannel channel); - List> sendMessageToEndInTextChannel(MessageToSend messageToSend, TextChannel textChannel); + List> sendMessageToEndInTextChannel(MessageToSend messageToSend, MessageChannel textChannel); Optional getTextChannelInGuild(Long serverId, Long channelId); void editMessageInAChannel(MessageToSend messageToSend, AChannel channel, Long messageId); - void editMessageInAChannel(MessageToSend messageToSend, TextChannel channel, Long messageId); + void editMessageInAChannel(MessageToSend messageToSend, MessageChannel channel, Long messageId); + + CompletableFuture createTextChannel(String name, AServer server, Long categoryId); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConfigService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConfigService.java index a07bcc0be..dd2529a69 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConfigService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConfigService.java @@ -2,9 +2,12 @@ package dev.sheldan.abstracto.core.service; public interface ConfigService { Double getDoubleValue(String name, Long serverId); + Long getLongValue(String name, Long serverId); Double getDoubleValue(String name, Long serverId, Double defaultValue); String getStringValue(String name, Long serverId, String defaultValue); + Long getLongValue(String name, Long serverId, Long defaultValue); void setDoubleValue(String name, Long serverId, Double value); + void setLongValue(String name, Long serverId, Long value); void setStringValue(String name, Long serverId, String value); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/LockService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/LockService.java new file mode 100644 index 000000000..5c44743b1 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/LockService.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.service; + +import dev.sheldan.abstracto.core.command.models.TableLocks; + +public interface LockService { + void lockTable(TableLocks toLock); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java index 3542f5764..19be169ff 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java @@ -8,5 +8,6 @@ public interface ChannelManagementService { AChannel loadChannel(Long id); AChannel createChannel(Long id, AChannelType type, AServer server); AChannel markAsDeleted(Long id); + boolean channelExists(Long id); void removeChannel(Long id); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementService.java index 57da10ef2..4ff5c896a 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ConfigManagementService.java @@ -7,10 +7,12 @@ public interface ConfigManagementService { AConfig setOrCreateDoubleValue(Long serverId, String name, Double value); AConfig createConfig(Long serverId, String name, String value); AConfig createConfig(Long serverId, String name, Double value); + AConfig createConfig(Long serverId, String name, Long value); AConfig createIfNotExists(Long serverId, String name, String value); AConfig createIfNotExists(Long serverId, String name, Double value); AConfig loadConfig(Long serverId, String name); boolean configExists(Long serverId, String name); AConfig setDoubleValue(Long serverId, String name, Double value); + AConfig setLongValue(Long serverId, String name, Long value); AConfig setStringValue(Long serverId, String name, String value); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementService.java index 511ce56f1..7b0c72cbc 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/UserInServerManagementService.java @@ -5,10 +5,13 @@ import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import net.dv8tion.jda.api.entities.Member; +import java.util.List; + public interface UserInServerManagementService { AUserInAServer loadUser(Long serverId, Long userId); AUserInAServer loadUser(AServer server, AUser user); AUserInAServer loadUser(Member member); AUserInAServer createUserInServer(Member member); AUserInAServer createUserInServer(Long guildId, Long userId); + List getUserInAllServers(Long userId); } diff --git a/abstracto-application/executable/pom.xml b/abstracto-application/executable/pom.xml index d3557f365..8a03f681c 100644 --- a/abstracto-application/executable/pom.xml +++ b/abstracto-application/executable/pom.xml @@ -63,6 +63,12 @@ ${project.version} + + dev.sheldan.abstracto.modules + modmail-impl + ${project.version} + + dev.sheldan.abstracto.modules utility-impl diff --git a/abstracto-application/pom.xml b/abstracto-application/pom.xml index ec4969802..b2a239a76 100644 --- a/abstracto-application/pom.xml +++ b/abstracto-application/pom.xml @@ -37,6 +37,12 @@ + + com.jagrosh + jda-utilities-menu + ${jda.utilities.version} + compile + org.apache.commons commons-lang3 diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setNumber/help/setNumber_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setFloat/help/setFloat_description_en_US.ftl similarity index 100% rename from abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setNumber/help/setNumber_description_en_US.ftl rename to abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setFloat/help/setFloat_description_en_US.ftl diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setNumber/help/setNumber_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setFloat/help/setFloat_long_help_en_US.ftl similarity index 100% rename from abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setNumber/help/setNumber_long_help_en_US.ftl rename to abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setFloat/help/setFloat_long_help_en_US.ftl diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setNumber/help/setNumber_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setFloat/help/setFloat_usage_en_US.ftl similarity index 100% rename from abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setNumber/help/setNumber_usage_en_US.ftl rename to abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setFloat/help/setFloat_usage_en_US.ftl diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_description_en_US.ftl new file mode 100644 index 000000000..cd98b92a6 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_description_en_US.ftl @@ -0,0 +1 @@ +Changes the value of a numerical value of the bots configuration \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_long_help_en_US.ftl new file mode 100644 index 000000000..a62f53500 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_long_help_en_US.ftl @@ -0,0 +1 @@ +Sets a numerical value in the bots configuration to the given value. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_usage_en_US.ftl new file mode 100644 index 000000000..cab8588e0 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/core/setLong/help/setLong_usage_en_US.ftl @@ -0,0 +1 @@ +setNumber \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_description_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_description_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_long_help_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_long_help_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_usage_en_US.ftl new file mode 100644 index 000000000..b675504f6 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/anonReply/help/anonReply_usage_en_US.ftl @@ -0,0 +1 @@ +setModMailCategory \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_description_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_description_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_long_help_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_long_help_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_usage_en_US.ftl new file mode 100644 index 000000000..f8b4a41ef --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/close/help/close_usage_en_US.ftl @@ -0,0 +1 @@ +close [note] \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_description_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_description_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_long_help_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_long_help_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_usage_en_US.ftl new file mode 100644 index 000000000..94547b312 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/closeSilently/help/closeSilently_usage_en_US.ftl @@ -0,0 +1 @@ +closeSilenty [note] \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_description_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_description_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_long_help_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_long_help_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_usage_en_US.ftl new file mode 100644 index 000000000..0aea4edc2 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/contact/help/contact_usage_en_US.ftl @@ -0,0 +1 @@ +contact \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_description_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_description_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_long_help_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_long_help_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_usage_en_US.ftl new file mode 100644 index 000000000..21145747a --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/reply/help/reply_usage_en_US.ftl @@ -0,0 +1 @@ +reply \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_description_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_description_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_long_help_en_US.ftl new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_long_help_en_US.ftl @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_usage_en_US.ftl new file mode 100644 index 000000000..b675504f6 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/modmail/setModMailCategory/help/setModMailCategory_usage_en_US.ftl @@ -0,0 +1 @@ +setModMailCategory \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/config/modmail_feature_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/config/modmail_feature_en_US.ftl new file mode 100644 index 000000000..076a26637 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/config/modmail_feature_en_US.ftl @@ -0,0 +1 @@ +Mod mail \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/listener/server_chooser/server_chooser_server_list_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/listener/server_chooser/server_chooser_server_list_description_en_US.ftl new file mode 100644 index 000000000..b9e29496f --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/listener/server_chooser/server_chooser_server_list_description_en_US.ftl @@ -0,0 +1,2 @@ +For which server do you want to open a modmail? +The available servers are: \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/modMail/modmail_thread_staff_message_title_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/modMail/modmail_thread_staff_message_title_en_US.ftl new file mode 100644 index 000000000..36aef3c39 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/modMail/modmail_thread_staff_message_title_en_US.ftl @@ -0,0 +1 @@ +Moderator replied \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/modMail/modmail_thread_user_message_title_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/modMail/modmail_thread_user_message_title_en_US.ftl new file mode 100644 index 000000000..0c0611288 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/modMail/modmail_thread_user_message_title_en_US.ftl @@ -0,0 +1 @@ +User replied \ No newline at end of file diff --git a/abstracto-application/templating/templating-interface/pom.xml b/abstracto-application/templating/templating-interface/pom.xml index 1057af57a..34d6028d3 100644 --- a/abstracto-application/templating/templating-interface/pom.xml +++ b/abstracto-application/templating/templating-interface/pom.xml @@ -22,6 +22,11 @@ JDA + + com.jagrosh + jda-utilities-menu + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 06b8208fd..1d3037a89 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,8 @@ - 4.0.0_73 + 4.1.1_126 + 3.0.3