diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/listener/MessageDeletedListener.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/listener/MessageDeletedListener.java index dc1bced9e..0999da638 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/listener/MessageDeletedListener.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/listener/MessageDeletedListener.java @@ -1,6 +1,6 @@ package dev.sheldan.abstracto.moderation.listener; -import dev.sheldan.abstracto.core.ContextUtils; +import dev.sheldan.abstracto.core.utils.ContextUtils; import dev.sheldan.abstracto.core.models.database.PostTarget; import dev.sheldan.abstracto.core.service.MessageCache; import dev.sheldan.abstracto.core.service.PostTargetService; diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/ban/ban_help_description_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/ban/ban_description_en_US.ftl similarity index 100% rename from abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/ban/ban_help_description_en_US.ftl rename to abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/ban/ban_description_en_US.ftl diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/kick/kick_help_description_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/kick/kick_description_en_US.ftl similarity index 100% rename from abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/kick/kick_help_description_en_US.ftl rename to abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/kick/kick_description_en_US.ftl diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_help_description_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_description_en_US.ftl similarity index 100% rename from abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_help_description_en_US.ftl rename to abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_description_en_US.ftl diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_log_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_log_en_US.ftl similarity index 100% rename from abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_log_en_US.ftl rename to abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_log_en_US.ftl diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_long_help_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_long_help_en_US.ftl similarity index 100% rename from abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_long_help_en_US.ftl rename to abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_long_help_en_US.ftl diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_usage_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_usage_en_US.ftl similarity index 100% rename from abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slow_mode_usage_en_US.ftl rename to abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/slowMode/slowmode_usage_en_US.ftl diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/warn/warn_help_description_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/warn/warn_description_en_US.ftl similarity index 100% rename from abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/warn/warn_help_description_en_US.ftl rename to abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/warn/warn_description_en_US.ftl diff --git a/abstracto-application/abstracto-modules/pom.xml b/abstracto-application/abstracto-modules/pom.xml index f13d72de4..322a59ba4 100644 --- a/abstracto-application/abstracto-modules/pom.xml +++ b/abstracto-application/abstracto-modules/pom.xml @@ -13,6 +13,7 @@ pom moderation + utility diff --git a/abstracto-application/abstracto-modules/utility/pom.xml b/abstracto-application/abstracto-modules/utility/pom.xml new file mode 100644 index 000000000..452cd96a6 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/pom.xml @@ -0,0 +1,34 @@ + + + + dev.sheldan.abstracto + abstracto-modules + 1.0-SNAPSHOT + + 4.0.0 + + dev.sheldan.abstracto.modules + utility + pom + + + utility-int + utility-impl + + + + + dev.sheldan.abstracto.command + command-int + ${project.version} + + + dev.sheldan.abstracto.core + core-interface + ${project.version} + compile + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/pom.xml b/abstracto-application/abstracto-modules/utility/utility-impl/pom.xml new file mode 100644 index 000000000..2617dc70f --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/pom.xml @@ -0,0 +1,22 @@ + + + + dev.sheldan.abstracto.modules + utility + 1.0-SNAPSHOT + + 4.0.0 + + utility-impl + + + + dev.sheldan.abstracto.modules + utility-int + ${project.version} + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Accept.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Accept.java new file mode 100644 index 000000000..6475c916c --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Accept.java @@ -0,0 +1,46 @@ +package dev.sheldan.abstracto.utility.command.suggest; + +import dev.sheldan.abstracto.command.Command; +import dev.sheldan.abstracto.command.HelpInfo; +import dev.sheldan.abstracto.command.execution.*; +import dev.sheldan.abstracto.utility.Utility; +import dev.sheldan.abstracto.utility.models.template.SuggestionLog; +import dev.sheldan.abstracto.utility.service.SuggestionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class Accept implements Command { + + @Autowired + private SuggestionService suggestionService; + + @Override + public Result execute(CommandContext commandContext) { + List parameters = commandContext.getParameters().getParameters(); + Long suggestionId = (Long) parameters.get(0); + String text = parameters.size() == 2 ? (String) parameters.get(1) : ""; + SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class); + suggestionService.acceptSuggestion(suggestionId, text, suggestionModel); + return Result.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("suggestionId").type(Long.class).optional(false).build()); + parameters.add(Parameter.builder().name("text").type(String.class).optional(true).remainder(true).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("accept") + .module(Utility.UTILITY) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } +} diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Reject.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Reject.java new file mode 100644 index 000000000..a484d59a3 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Reject.java @@ -0,0 +1,45 @@ +package dev.sheldan.abstracto.utility.command.suggest; + +import dev.sheldan.abstracto.command.Command; +import dev.sheldan.abstracto.command.HelpInfo; +import dev.sheldan.abstracto.command.execution.*; +import dev.sheldan.abstracto.utility.Utility; +import dev.sheldan.abstracto.utility.models.template.SuggestionLog; +import dev.sheldan.abstracto.utility.service.SuggestionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class Reject implements Command { + @Autowired + private SuggestionService suggestionService; + + @Override + public Result execute(CommandContext commandContext) { + List parameters = commandContext.getParameters().getParameters(); + Long suggestionId = (Long) parameters.get(0); + String text = parameters.size() == 2 ? (String) parameters.get(1) : ""; + SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class); + suggestionService.rejectSuggestion(suggestionId, text, suggestionModel); + return Result.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("suggestionId").type(Long.class).optional(false).build()); + parameters.add(Parameter.builder().name("text").type(String.class).optional(true).remainder(true).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("reject") + .module(Utility.UTILITY) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } +} diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Suggest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Suggest.java new file mode 100644 index 000000000..c82b16259 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/command/suggest/Suggest.java @@ -0,0 +1,46 @@ +package dev.sheldan.abstracto.utility.command.suggest; + +import dev.sheldan.abstracto.command.Command; +import dev.sheldan.abstracto.command.HelpInfo; +import dev.sheldan.abstracto.command.execution.*; +import dev.sheldan.abstracto.utility.Utility; +import dev.sheldan.abstracto.utility.models.template.SuggestionLog; +import dev.sheldan.abstracto.utility.service.SuggestionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class Suggest implements Command { + + @Autowired + private SuggestionService suggestionService; + + @Override + public Result execute(CommandContext commandContext) { + List parameters = commandContext.getParameters().getParameters(); + String text = (String) parameters.get(0); + SuggestionLog suggestLogModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class); + suggestLogModel.setSuggester(commandContext.getAuthor()); + suggestionService.createSuggestion(commandContext.getAuthor(), text, suggestLogModel); + return Result.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("text").type(String.class).optional(false).remainder(true).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("suggest") + .module(Utility.UTILITY) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } +} diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/repository/SuggestionRepository.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/repository/SuggestionRepository.java new file mode 100644 index 000000000..0563056e3 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/repository/SuggestionRepository.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.utility.repository; + +import dev.sheldan.abstracto.utility.models.Suggestion; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SuggestionRepository extends JpaRepository { +} diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/SuggestionServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/SuggestionServiceBean.java new file mode 100644 index 000000000..e1190af81 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/SuggestionServiceBean.java @@ -0,0 +1,109 @@ +package dev.sheldan.abstracto.utility.service; + +import dev.sheldan.abstracto.core.management.EmoteManagementService; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.models.database.PostTarget; +import dev.sheldan.abstracto.core.service.Bot; +import dev.sheldan.abstracto.core.service.MessageService; +import dev.sheldan.abstracto.core.service.PostTargetService; +import dev.sheldan.abstracto.core.utils.MessageUtils; +import dev.sheldan.abstracto.templating.TemplateService; +import dev.sheldan.abstracto.utility.models.Suggestion; +import dev.sheldan.abstracto.utility.models.SuggestionState; +import dev.sheldan.abstracto.utility.models.template.SuggestionLog; +import dev.sheldan.abstracto.utility.service.management.AsyncSuggestionServiceBean; +import dev.sheldan.abstracto.utility.service.management.SuggestionManagementService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class SuggestionServiceBean implements SuggestionService { + + public static final String SUGGESTION_LOG_TEMPLATE = "suggest_log"; + public static final String SUGGESTION_YES_EMOTE = "SUGGESTION_YES"; + public static final String SUGGESTION_NO_EMOTE = "SUGGESTION_NO"; + @Autowired + private SuggestionManagementService suggestionManagementService; + + @Autowired + private PostTargetService postTargetService; + + @Autowired + private TemplateService templateService; + + @Autowired + private Bot botService; + + @Autowired + private AsyncSuggestionServiceBean suggestionServiceBean; + + @Autowired + private EmoteManagementService emoteManagementService; + + @Autowired + private MessageService messageService; + + @Override + public void createSuggestion(Member member, String text, SuggestionLog suggestionLog) { + Suggestion suggestion = suggestionManagementService.createSuggestion(member, text); + suggestionLog.setSuggestion(suggestion); + suggestionLog.setText(text); + MessageEmbed embed = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog); + long guildId = member.getGuild().getIdLong(); + JDA instance = botService.getInstance(); + Guild guildById = instance.getGuildById(guildId); + if(guildById != null) { + postTargetService.sendEmbedInPostTarget(embed, PostTarget.SUGGESTIONS, guildId).thenAccept(message -> { + messageService.addReactionToMessage(SUGGESTION_YES_EMOTE, guildId, message); + messageService.addReactionToMessage(SUGGESTION_NO_EMOTE, guildId, message); + suggestionManagementService.setPostedMessage(suggestion, message); + }); + } else { + log.warn("Guild {} or member {} was not found when creating suggestion.", member.getGuild().getIdLong(), member.getIdLong()); + } + } + + @Override + public void acceptSuggestion(Long suggestionId, String text, SuggestionLog suggestionLog) { + Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId); + suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED); + updateSuggestion(text, suggestionLog, suggestion); + } + + private void updateSuggestion(String text, SuggestionLog suggestionLog, Suggestion suggestion) { + Long channelId = suggestion.getChannel().getId(); + Long originalMessageId = suggestion.getMessageId(); + Long serverId = suggestion.getServer().getId(); + + suggestionLog.setOriginalChannelId(channelId); + suggestionLog.setOriginalMessageId(originalMessageId); + suggestionLog.setOriginalMessageUrl(MessageUtils.buildMessageUrl(serverId, channelId, originalMessageId)); + AUserInAServer suggester = suggestion.getSuggester(); + JDA instance = botService.getInstance(); + Guild guildById = instance.getGuildById(serverId); + if(guildById != null) { + Member memberById = guildById.getMemberById(suggester.getUserReference().getId()); + if(memberById != null) { + suggestionLog.setSuggester(memberById); + suggestionLog.setSuggestion(suggestion); + TextChannel textChannelById = guildById.getTextChannelById(channelId); + if(textChannelById != null) { + textChannelById.retrieveMessageById(originalMessageId).queue(message -> { + suggestionServiceBean.updateSuggestionMessageText(text, suggestionLog, message); + }); + } + } + } + } + + @Override + public void rejectSuggestion(Long suggestionId, String text, SuggestionLog log) { + Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId); + suggestionManagementService.setSuggestionState(suggestion, SuggestionState.REJECTED); + updateSuggestion(text, log, suggestion); + } +} diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/AsyncSuggestionServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/AsyncSuggestionServiceBean.java new file mode 100644 index 000000000..5d7c44723 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/AsyncSuggestionServiceBean.java @@ -0,0 +1,41 @@ +package dev.sheldan.abstracto.utility.service.management; + +import dev.sheldan.abstracto.core.models.database.PostTarget; +import dev.sheldan.abstracto.core.service.PostTargetService; +import dev.sheldan.abstracto.templating.TemplateService; +import dev.sheldan.abstracto.utility.models.template.SuggestionLog; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +import static dev.sheldan.abstracto.utility.service.SuggestionServiceBean.SUGGESTION_LOG_TEMPLATE; + +@Component +@Slf4j +public class AsyncSuggestionServiceBean { + + @Autowired + private TemplateService templateService; + + @Autowired + private PostTargetService postTargetService; + + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void updateSuggestionMessageText(String text, SuggestionLog suggestionLog, Message message) { + Optional embedOptional = message.getEmbeds().stream().filter(embed -> embed.getDescription() != null).findFirst(); + if(embedOptional.isPresent()) { + MessageEmbed suggestionEmbed = embedOptional.get(); + suggestionLog.setReason(text); + suggestionLog.setText(suggestionEmbed.getDescription()); + MessageEmbed embed = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog); + postTargetService.sendEmbedInPostTarget(embed, PostTarget.SUGGESTIONS, suggestionLog.getServer().getId()); + } + } + +} diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBean.java new file mode 100644 index 000000000..0b05b424d --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBean.java @@ -0,0 +1,73 @@ +package dev.sheldan.abstracto.utility.service.management; + +import dev.sheldan.abstracto.core.management.ChannelManagementService; +import dev.sheldan.abstracto.core.management.ServerManagementService; +import dev.sheldan.abstracto.core.management.UserManagementService; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.utility.models.Suggestion; +import dev.sheldan.abstracto.utility.models.SuggestionState; +import dev.sheldan.abstracto.utility.repository.SuggestionRepository; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; + +@Component +public class SuggestionManagementServiceBean implements SuggestionManagementService { + + @Autowired + private SuggestionRepository suggestionRepository; + + @Autowired + private ChannelManagementService channelManagementService; + + @Autowired + private UserManagementService userManagementService; + + @Autowired + private ServerManagementService serverManagementService; + + @Override + public Suggestion createSuggestion(Member suggester, String text) { + AUserInAServer user = userManagementService.loadUser(suggester); + return this.createSuggestion(user, text); + } + + @Override + public Suggestion createSuggestion(AUserInAServer suggester, String text) { + Suggestion suggestion = Suggestion + .builder() + .state(SuggestionState.NEW) + .suggester(suggester) + .suggestionDate(Instant.now()) + .build(); + suggestionRepository.save(suggestion); + return suggestion; + } + + @Override + public Suggestion getSuggestion(Long suggestionId) { + return suggestionRepository.getOne(suggestionId); + } + + + @Override + public void setPostedMessage(Suggestion suggestion, Message message) { + suggestion.setMessageId(message.getIdLong()); + AChannel channel = channelManagementService.loadChannel(message.getTextChannel().getIdLong()); + suggestion.setChannel(channel); + AServer server = serverManagementService.loadServer(message.getGuild().getIdLong()); + suggestion.setServer(server); + suggestionRepository.save(suggestion); + } + + @Override + public void setSuggestionState(Suggestion suggestion, SuggestionState newState) { + suggestion.setState(newState); + suggestionRepository.save(suggestion); + } +} diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_description_en_US.ftl b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_description_en_US.ftl new file mode 100644 index 000000000..33fefbed6 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_description_en_US.ftl @@ -0,0 +1 @@ +Suggests a text in the suggestions channel to be voted on. \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_log_embed_en_US.ftl b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_log_embed_en_US.ftl new file mode 100644 index 000000000..28b83b474 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_log_embed_en_US.ftl @@ -0,0 +1,29 @@ +{ + "author": { + "name": "${suggester.effectiveName}", + "avatar": "${suggester.user.effectiveAvatarUrl}" + }, + "color" : { + "r": 200, + "g": 0, + "b": 255 + }, + <#if suggestion.state = "ACCEPTED"> + "description": "~~${text}~~ \n✅ ${reason} - Accepted by ${member.effectiveName}", + <#elseif suggestion.state = "REJECTED"> + "description": "~~${text}~~ \n❌ ${reason} - Rejected by ${member.effectiveName}", + <#else> + "description": "${text}", + + <#if suggestion.state = "ACCEPTED" || suggestion.state = "REJECTED"> + "fields": [ + { + "name": "Link", + "value": "[Jump](${originalMessageUrl})" + } + ], + + "footer": { + "text": "Suggestion #${suggestion.id}" + } +} \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_long_help_en_US.ftl b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_long_help_en_US.ftl new file mode 100644 index 000000000..33fefbed6 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_long_help_en_US.ftl @@ -0,0 +1 @@ +Suggests a text in the suggestions channel to be voted on. \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_usage_en_US.ftl b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_usage_en_US.ftl new file mode 100644 index 000000000..21890d59d --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/resources/templates/suggest/suggest_usage_en_US.ftl @@ -0,0 +1 @@ +suggest \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/utility/utility-int/pom.xml b/abstracto-application/abstracto-modules/utility/utility-int/pom.xml new file mode 100644 index 000000000..455ba0723 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-int/pom.xml @@ -0,0 +1,14 @@ + + + + dev.sheldan.abstracto.modules + utility + 1.0-SNAPSHOT + + 4.0.0 + + utility-int + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/Utility.java b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/Utility.java new file mode 100644 index 000000000..caa2fdabe --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/Utility.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.utility; + +import dev.sheldan.abstracto.command.Module; +import dev.sheldan.abstracto.command.module.ModuleInfo; +import org.springframework.stereotype.Component; + +@Component +public class Utility implements Module { + + public static final String UTILITY = "utility"; + + @Override + public ModuleInfo getInfo() { + return ModuleInfo.builder().name(UTILITY).description("General utilities").build(); + } + + @Override + public String getParentModule() { + return "default"; + } +} diff --git a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/Suggestion.java b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/Suggestion.java new file mode 100644 index 000000000..80678b3c4 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/Suggestion.java @@ -0,0 +1,50 @@ +package dev.sheldan.abstracto.utility.models; + +import dev.sheldan.abstracto.core.models.AChannelType; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import lombok.*; + +import javax.persistence.*; +import java.time.Instant; + +@Entity +@Table(name="suggestion") +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter @Setter +public class Suggestion { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Getter + private Long id; + + @Getter + @ManyToOne + @JoinColumn(name = "suggesterId") + private AUserInAServer suggester; + + @Getter + private Long messageId; + + @Getter + @ManyToOne + @JoinColumn(name = "channelId") + private AChannel channel; + + @Getter + @ManyToOne + @JoinColumn(name = "serverId") + private AServer server; + + @Getter + private Instant suggestionDate; + + @Getter + @Enumerated(EnumType.STRING) + private SuggestionState state; + +} diff --git a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/SuggestionState.java b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/SuggestionState.java new file mode 100644 index 000000000..771c8141d --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/SuggestionState.java @@ -0,0 +1,5 @@ +package dev.sheldan.abstracto.utility.models; + +public enum SuggestionState { + NEW, ACCEPTED, REJECTED +} diff --git a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/template/SuggestionLog.java b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/template/SuggestionLog.java new file mode 100644 index 000000000..e11d0d88f --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/models/template/SuggestionLog.java @@ -0,0 +1,19 @@ +package dev.sheldan.abstracto.utility.models.template; + +import dev.sheldan.abstracto.core.models.UserInitiatedServerContext; +import dev.sheldan.abstracto.utility.models.Suggestion; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import net.dv8tion.jda.api.entities.Member; + +@Getter @Setter @SuperBuilder +public class SuggestionLog extends UserInitiatedServerContext { + private Suggestion suggestion; + private Member suggester; + private String text; + private String reason; + private Long originalMessageId; + private Long originalChannelId; + private String originalMessageUrl; +} diff --git a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/service/SuggestionService.java b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/service/SuggestionService.java new file mode 100644 index 000000000..43675cfc6 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/service/SuggestionService.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.utility.service; + +import dev.sheldan.abstracto.utility.models.template.SuggestionLog; +import net.dv8tion.jda.api.entities.Member; + +public interface SuggestionService { + void createSuggestion(Member member, String text, SuggestionLog log); + void acceptSuggestion(Long suggestionId, String text, SuggestionLog log); + void rejectSuggestion(Long suggestionId, String text, SuggestionLog log); +} diff --git a/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementService.java b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementService.java new file mode 100644 index 000000000..0abc90820 --- /dev/null +++ b/abstracto-application/abstracto-modules/utility/utility-int/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementService.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.utility.service.management; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.utility.models.Suggestion; +import dev.sheldan.abstracto.utility.models.SuggestionState; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; + +public interface SuggestionManagementService { + Suggestion createSuggestion(Member suggester, String text); + Suggestion createSuggestion(AUserInAServer suggester, String text); + Suggestion getSuggestion(Long suggestionId); + void setPostedMessage(Suggestion suggestion, Message message); + void setSuggestionState(Suggestion suggestion, SuggestionState newState); +} diff --git a/abstracto-application/command/command-support/src/main/java/dev/sheldan/abstracto/commands/management/CommandReceivedHandler.java b/abstracto-application/command/command-support/src/main/java/dev/sheldan/abstracto/commands/management/CommandReceivedHandler.java index 6381581d0..b0787303a 100644 --- a/abstracto-application/command/command-support/src/main/java/dev/sheldan/abstracto/commands/management/CommandReceivedHandler.java +++ b/abstracto-application/command/command-support/src/main/java/dev/sheldan/abstracto/commands/management/CommandReceivedHandler.java @@ -11,7 +11,6 @@ import dev.sheldan.abstracto.core.management.UserManagementService; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.UserInitiatedServerContext; -import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; @@ -19,6 +18,7 @@ import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -45,6 +45,7 @@ public class CommandReceivedHandler extends ListenerAdapter { @Override @Transactional + @Async public void onMessageReceived(@Nonnull MessageReceivedEvent event) { if(!commandManager.isCommand(event.getMessage())) { return; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/SetPostTargetCommand.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/PostTargetCommand.java similarity index 93% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/SetPostTargetCommand.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/PostTargetCommand.java index 205010818..01b6d2900 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/SetPostTargetCommand.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/PostTargetCommand.java @@ -19,7 +19,7 @@ import java.util.List; @Service @Slf4j -public class SetPostTargetCommand implements Command { +public class PostTargetCommand implements Command { @Autowired private PostTargetManagement postTargetManagement; @@ -32,7 +32,7 @@ public class SetPostTargetCommand implements Command { GuildChannel channel = (GuildChannel) commandContext.getParameters().getParameters().get(1); String targetName = (String) commandContext.getParameters().getParameters().get(0); Guild guild = channel.getGuild(); - postTargetManagement.createOrUpdate(targetName, channel.getIdLong(), guild.getIdLong()); + postTargetManagement.createOrUpdate(targetName, guild.getIdLong(), channel.getIdLong()); log.info("Setting posttarget {} in {} to {}", targetName, guild.getIdLong(), channel.getId()); return Result.fromSuccess(); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java new file mode 100644 index 000000000..a347419db --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java @@ -0,0 +1,41 @@ +package dev.sheldan.abstracto.core.service; + +import dev.sheldan.abstracto.core.management.EmoteManagementService; +import dev.sheldan.abstracto.core.models.database.AEmote; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class MessageServiceBean implements MessageService { + + @Autowired + private Bot bot; + + @Autowired + private EmoteManagementService emoteManagementService; + + @Override + public void addReactionToMessage(String emoteKey, Long serverId, Message message) { + Guild guildById = bot.getInstance().getGuildById(serverId); + if(guildById != null) { + AEmote emote = emoteManagementService.loadEmoteByName(emoteKey, serverId); + if(emote.getCustom()) { + Emote emoteById = guildById.getEmoteById(emote.getEmoteId()); + if(emoteById != null) { + message.addReaction(emoteById).queue(); + } else { + log.warn("Emote with key {} and id {} for guild {} was not found.", emoteKey, emote.getEmoteId(), guildById.getId()); + } + } else { + message.addReaction(emote.getEmoteKey()).queue(); + } + } else { + log.warn("Guild {} was not found when trying to react to a message.", serverId); + } + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java index d34cb486f..e1bb46167 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java @@ -6,11 +6,14 @@ import dev.sheldan.abstracto.core.management.ServerManagementService; import dev.sheldan.abstracto.core.models.database.PostTarget; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.concurrent.CompletableFuture; + @Slf4j @Component @@ -26,15 +29,15 @@ public class PostTargetServiceBean implements PostTargetService { private Bot botService; @Override - public void sendTextInPostTarget(String text, PostTarget target) { + public CompletableFuture sendTextInPostTarget(String text, PostTarget target) { TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target); - textChannelForPostTarget.sendMessage(text).queue(); + return textChannelForPostTarget.sendMessage(text).submit(); } @Override - public void sendEmbedInPostTarget(MessageEmbed embed, PostTarget target) { + public CompletableFuture sendEmbedInPostTarget(MessageEmbed embed, PostTarget target) { TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target); - textChannelForPostTarget.sendMessage(embed).queue(); + return textChannelForPostTarget.sendMessage(embed).submit(); } private TextChannel getTextChannelForPostTarget(PostTarget target) { @@ -64,14 +67,14 @@ public class PostTargetServiceBean implements PostTargetService { } @Override - public void sendTextInPostTarget(String text, String postTargetName, Long serverId) { + public CompletableFuture sendTextInPostTarget(String text, String postTargetName, Long serverId) { PostTarget postTarget = this.getPostTarget(postTargetName, serverId); - this.sendTextInPostTarget(text, postTarget); + return this.sendTextInPostTarget(text, postTarget); } @Override - public void sendEmbedInPostTarget(MessageEmbed embed, String postTargetName, Long serverId) { + public CompletableFuture sendEmbedInPostTarget(MessageEmbed embed, String postTargetName, Long serverId) { PostTarget postTarget = this.getPostTarget(postTargetName, serverId); - this.sendEmbedInPostTarget(embed, postTarget); + return this.sendEmbedInPostTarget(embed, postTarget); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementServiceBean.java new file mode 100644 index 000000000..e6fcfb8aa --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementServiceBean.java @@ -0,0 +1,54 @@ +package dev.sheldan.abstracto.core.service.management; + +import dev.sheldan.abstracto.core.management.EmoteManagementService; +import dev.sheldan.abstracto.core.management.ServerManagementService; +import dev.sheldan.abstracto.core.models.database.AEmote; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.repository.EmoteRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class EmoteManagementServiceBean implements EmoteManagementService { + + @Autowired + private EmoteRepository repository; + + @Autowired + private ServerManagementService serverManagementService; + + @Override + public AEmote loadEmote(Long id) { + return repository.getOne(id); + } + + @Override + public AEmote loadEmoteByName(String name, Long serverId) { + AServer server = serverManagementService.loadServer(serverId); + return repository.findAEmoteByNameAndServerRef(name, server); + } + + @Override + public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated) { + AEmote emote = AEmote.builder() + .animated(animated) + .custom(true) + .emoteKey(emoteKey) + .emoteId(emoteId) + .name(name) + .build(); + repository.save(emote); + return emote; + } + + @Override + public AEmote createDefaultEmote(String name, String emoteKey) { + AEmote emote = AEmote.builder() + .custom(false) + .emoteKey(emoteKey) + .name(name) + .build(); + repository.save(emote); + return emote; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java index e833ac4c3..a20ecc724 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java @@ -26,7 +26,7 @@ public class PostTargetManagementBean implements PostTargetManagement { private ServerManagementService serverManagementService; @Override - public void createPostTarget(String name, AChannel targetChannel, AServer server) { + public void createPostTarget(String name, AServer server, AChannel targetChannel) { if(!PostTarget.AVAILABLE_POST_TARGETS.contains(name)) { throw new PostTargetException("PostTarget not found"); } @@ -35,26 +35,26 @@ public class PostTargetManagementBean implements PostTargetManagement { } @Override - public void createOrUpdate(String name, AChannel targetChannel, AServer server) { + public void createOrUpdate(String name, AServer server, AChannel targetChannel) { PostTarget existing = postTargetRepository.findPostTargetByName(name); if(existing == null){ - this.createPostTarget(name, targetChannel, server); + this.createPostTarget(name, server, targetChannel); } else { - this.updatePostTarget(existing, targetChannel, server); + this.updatePostTarget(existing, server, targetChannel); } } @Override - public void createOrUpdate(String name, Long channelId, AServer server) { + public void createOrUpdate(String name, AServer server, Long channelId) { AChannel dbChannel = channelManagementService.loadChannel(channelId); - createOrUpdate(name, dbChannel, server); + createOrUpdate(name, server, dbChannel); } @Override - public void createOrUpdate(String name, Long channelId, Long serverId) { + public void createOrUpdate(String name, Long serverId, Long channelId) { AChannel dbChannel = channelManagementService.loadChannel(channelId); AServer dbServer = serverManagementService.loadServer(serverId); - createOrUpdate(name, dbChannel, dbServer); + createOrUpdate(name, dbServer, dbChannel); } @Override @@ -70,7 +70,7 @@ public class PostTargetManagementBean implements PostTargetManagement { } @Override - public void updatePostTarget(PostTarget target, AChannel newTargetChannel, AServer server) { + public void updatePostTarget(PostTarget target, AServer server, AChannel newTargetChannel) { postTargetRepository.getOne(target.getId()).setChannelReference(newTargetChannel); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java index d57685143..d0f948825 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java @@ -3,12 +3,15 @@ package dev.sheldan.abstracto.core.service.management; import dev.sheldan.abstracto.core.management.ChannelManagementService; import dev.sheldan.abstracto.core.management.PostTargetManagement; import dev.sheldan.abstracto.core.management.ServerManagementService; +import dev.sheldan.abstracto.core.management.UserManagementService; import dev.sheldan.abstracto.core.models.database.*; import dev.sheldan.abstracto.repository.ServerRepository; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service +@Slf4j public class ServerManagementServiceBean implements ServerManagementService { @Autowired @@ -20,6 +23,9 @@ public class ServerManagementServiceBean implements ServerManagementService { @Autowired private ChannelManagementService channelManagementService; + @Autowired + private UserManagementService userManagementService; + @Override public AServer createServer(Long id) { return repository.save(AServer.builder().id(id).build()); @@ -27,7 +33,11 @@ public class ServerManagementServiceBean implements ServerManagementService { @Override public AServer loadServer(Long id) { - return repository.getOne(id); + if(repository.existsById(id)) { + return repository.getOne(id); + } else { + return createServer(id); + } } @Override @@ -37,6 +47,14 @@ public class ServerManagementServiceBean implements ServerManagementService { @Override public AUserInAServer addUserToServer(AServer server, AUser user) { + return this.addUserToServer(server.getId(), user.getId()); + } + + @Override + public AUserInAServer addUserToServer(Long serverId, Long userId) { + log.info("Adding user {} to server {}", userId, serverId); + AServer server = repository.getOne(serverId); + AUser user = userManagementService.loadUser(userId); AUserInAServer aUserInAServer = AUserInAServer.builder().serverReference(server).userReference(user).build(); server.getUsers().add(aUserInAServer); return aUserInAServer; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserManagementServiceBean.java index 6bbf03d06..33ac0fe1c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/UserManagementServiceBean.java @@ -7,11 +7,13 @@ import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.repository.UserInServerRepository; import dev.sheldan.abstracto.repository.UserRepository; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Member; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class UserManagementServiceBean implements UserManagementService { @Autowired @@ -25,41 +27,55 @@ public class UserManagementServiceBean implements UserManagementService { @Override - public AUserInAServer loadUser(Long userId, Long serverId) { - AUser user = userRepository.getOne(userId); + public AUserInAServer loadUser(Long serverId, Long userId) { + AUser user = this.loadUser(userId); AServer server = serverManagementService.loadServer(serverId); - return loadUser(user, server); + return loadUser(server, user); } @Override - public AUserInAServer loadUser(AUser user, AServer server) { - return userInServerRepository.findByServerReferenceAndUserReference(server, user); + public AUserInAServer loadUser(AServer server, AUser user) { + if(userInServerRepository.existsByServerReferenceAndUserReference(server, user)) { + return userInServerRepository.findByServerReferenceAndUserReference(server, user); + } else { + return this.createUserInServer(server.getId(), user.getId()); + } } @Override public AUserInAServer loadUser(Member member) { - AUserInAServer aUserInAServer = this.loadUser(member.getGuild().getIdLong(), member.getIdLong()); - if(aUserInAServer == null) { - return this.createUserInServer(member); - } - return null; + return this.loadUser(member.getGuild().getIdLong(), member.getIdLong()); } @Override public AUserInAServer createUserInServer(Member member) { - AServer server = serverManagementService.loadServer(member.getGuild().getIdLong()); + return this.createUserInServer(member.getGuild().getIdLong(), member.getIdLong()); + } - if(!userRepository.existsById(member.getIdLong())) { - this.createUser(member); - } - AUser aUser = userRepository.getOne(member.getIdLong()); - return serverManagementService.addUserToServer(server, aUser); + @Override + public AUserInAServer createUserInServer(Long guildId, Long userId) { + return serverManagementService.addUserToServer(guildId, userId); } @Override public AUser createUser(Member member) { - AUser aUser = AUser.builder().id(member.getIdLong()).build(); + return createUser(member.getIdLong()); + } + + @Override + public AUser createUser(Long userId) { + log.info("Creating user {}", userId); + AUser aUser = AUser.builder().id(userId).build(); userRepository.save(aUser); return aUser; } + + @Override + public AUser loadUser(Long userId) { + if(userRepository.existsById(userId)) { + return userRepository.getOne(userId); + } else { + return this.createUser(userId); + } + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/EmoteRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/EmoteRepository.java new file mode 100644 index 000000000..a781e27c2 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/EmoteRepository.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.repository; + +import dev.sheldan.abstracto.core.models.database.AEmote; +import dev.sheldan.abstracto.core.models.database.AServer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface EmoteRepository extends JpaRepository { + AEmote findAEmoteByNameAndServerRef(String name, AServer server); +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserInServerRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserInServerRepository.java index 365dfea39..89a09a4c3 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserInServerRepository.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserInServerRepository.java @@ -9,4 +9,5 @@ import org.springframework.stereotype.Repository; @Repository public interface UserInServerRepository extends JpaRepository { AUserInAServer findByServerReferenceAndUserReference(AServer serverId, AUser userId); + boolean existsByServerReferenceAndUserReference(AServer server, AUser user); } \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserRepository.java index 3b411ee77..e1b473add 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserRepository.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/repository/UserRepository.java @@ -2,6 +2,8 @@ package dev.sheldan.abstracto.repository; import dev.sheldan.abstracto.core.models.database.AUser; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +@Repository public interface UserRepository extends JpaRepository { } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/EmoteManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/EmoteManagementService.java new file mode 100644 index 000000000..929ff6261 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/EmoteManagementService.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.core.management; + +import dev.sheldan.abstracto.core.models.database.AEmote; + +public interface EmoteManagementService { + AEmote loadEmote(Long id); + AEmote loadEmoteByName(String name, Long serverId); + AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated); + AEmote createDefaultEmote(String name, String emoteKey); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/PostTargetManagement.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/PostTargetManagement.java index 9e3f078ae..fe14a1002 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/PostTargetManagement.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/PostTargetManagement.java @@ -5,11 +5,11 @@ import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.PostTarget; public interface PostTargetManagement { - void createPostTarget(String name, AChannel targetChanel, AServer server); - void createOrUpdate(String name, AChannel targetChannel, AServer server); - void createOrUpdate(String name, Long channelId, AServer server); - void createOrUpdate(String name, Long channelId, Long serverId); + void createPostTarget(String name, AServer server, AChannel targetChanel); + void createOrUpdate(String name, AServer server, AChannel targetChannel); + void createOrUpdate(String name, AServer server, Long channelId); + void createOrUpdate(String name, Long serverId, Long channelId); PostTarget getPostTarget(String name, AServer server); PostTarget getPostTarget(String name, Long serverId); - void updatePostTarget(PostTarget target, AChannel newTargetChannel, AServer server); + void updatePostTarget(PostTarget target, AServer server, AChannel newTargetChannel); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/ServerManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/ServerManagementService.java index 63bbf6be5..8aab6032b 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/ServerManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/ServerManagementService.java @@ -7,6 +7,7 @@ public interface ServerManagementService { AServer loadServer(Long id); void addChannelToServer(AServer server, AChannel channel); AUserInAServer addUserToServer(AServer server, AUser user); + AUserInAServer addUserToServer(Long serverId, Long userId); AChannel getPostTarget(Long serverId, String name); AChannel getPostTarget(Long serverId, PostTarget target); AChannel getPostTarget(AServer server, PostTarget target); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/UserManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/UserManagementService.java index 747b69bf0..32f2fd3ec 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/UserManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/management/UserManagementService.java @@ -6,9 +6,12 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer; import net.dv8tion.jda.api.entities.Member; public interface UserManagementService { - AUserInAServer loadUser(Long userId, Long serverId); - AUserInAServer loadUser(AUser user, AServer server); + 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); AUser createUser(Member member); + AUser createUser(Long userId); + AUser loadUser(Long userId); } 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 2dfc6bbad..6da40242a 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 @@ -21,7 +21,7 @@ public class AChannel implements SnowFlake { @Getter @ManyToMany(mappedBy = "channels") - private Set groups; + private Set groups; @ManyToOne(fetch = FetchType.LAZY) @Getter @Setter diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/ChannelGroup.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelGroup.java similarity index 88% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/ChannelGroup.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelGroup.java index 4d79c9584..70f96d84d 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/ChannelGroup.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelGroup.java @@ -10,15 +10,15 @@ import java.util.Set; @Builder @AllArgsConstructor @NoArgsConstructor -public class ChannelGroup { +@Getter +public class AChannelGroup { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Getter private Long id; @Column - @Getter @Setter + @Setter private String groupName; @ManyToMany @@ -26,7 +26,6 @@ public class ChannelGroup { name = "channel_in_group", joinColumns = @JoinColumn(name = "group_id"), inverseJoinColumns = @JoinColumn(name = "channel_id")) - @Getter private Set channels; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AEmote.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AEmote.java new file mode 100644 index 000000000..129c74314 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AEmote.java @@ -0,0 +1,38 @@ +package dev.sheldan.abstracto.core.models.database; + +import lombok.*; + +import javax.persistence.*; + +@Entity +@Table(name = "emote") +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class AEmote { + + @javax.persistence.Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer Id; + + @Column + private String name; + + @Column + private String emoteKey; + + @Column + private Long emoteId; + + @Column + private Boolean animated; + + @Column + private Boolean custom; + + @ManyToOne(fetch = FetchType.LAZY) + private AServer serverRef; + + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AServer.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AServer.java index 801bf57f5..22f809ad5 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AServer.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AServer.java @@ -36,7 +36,15 @@ public class AServer implements SnowFlake { fetch = FetchType.LAZY, mappedBy = "serverReference", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - private List users; + @Builder.Default + private List users = new ArrayList<>(); + + @OneToMany( + fetch = FetchType.LAZY, + mappedBy = "serverRef", + cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @Builder.Default + private List emotes = new ArrayList<>(); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AUserInAServer.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AUserInAServer.java index 3cb2b4117..eaea822d8 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AUserInAServer.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AUserInAServer.java @@ -1,11 +1,15 @@ package dev.sheldan.abstracto.core.models.database; -import lombok.Builder; -import lombok.Getter; +import lombok.*; import javax.persistence.*; -@Entity @Getter @Builder +@Entity +@Getter +@Builder +@Setter +@AllArgsConstructor +@NoArgsConstructor public class AUserInAServer { @Id diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/PostTarget.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/PostTarget.java index 3db3c3f3b..dbfc04d5e 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/PostTarget.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/PostTarget.java @@ -39,6 +39,7 @@ public class PostTarget { public static String BAN_LOG = "banLog"; public static String EDIT_LOG = "editLog"; public static String DELETE_LOG = "deleteLog"; + public static String SUGGESTIONS = "suggestions"; - public static List AVAILABLE_POST_TARGETS = Arrays.asList(JOIN_LOG, LEAVE_LOG, WARN_LOG, KICK_LOG, BAN_LOG, EDIT_LOG, DELETE_LOG); + public static List AVAILABLE_POST_TARGETS = Arrays.asList(JOIN_LOG, LEAVE_LOG, WARN_LOG, KICK_LOG, BAN_LOG, EDIT_LOG, DELETE_LOG, SUGGESTIONS); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/MessageService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/MessageService.java new file mode 100644 index 000000000..a98690eb2 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/MessageService.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.service; + +import net.dv8tion.jda.api.entities.Message; + +public interface MessageService { + void addReactionToMessage(String emoteKey, Long serverId, Message message); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/PostTargetService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/PostTargetService.java index f3f9d2067..a08f86239 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/PostTargetService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/PostTargetService.java @@ -1,11 +1,14 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.models.database.PostTarget; +import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; +import java.util.concurrent.CompletableFuture; + public interface PostTargetService { - void sendTextInPostTarget(String text, PostTarget target); - void sendEmbedInPostTarget(MessageEmbed embed, PostTarget target); - void sendTextInPostTarget(String text, String postTargetName, Long serverId); - void sendEmbedInPostTarget(MessageEmbed embed, String postTargetName, Long serverId); + CompletableFuture sendTextInPostTarget(String text, PostTarget target); + CompletableFuture sendEmbedInPostTarget(MessageEmbed embed, PostTarget target); + CompletableFuture sendTextInPostTarget(String text, String postTargetName, Long serverId); + CompletableFuture sendEmbedInPostTarget(MessageEmbed embed, String postTargetName, Long serverId); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/ContextUtils.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java similarity index 98% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/ContextUtils.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java index 2199b6578..a040cc944 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/ContextUtils.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java @@ -1,4 +1,4 @@ -package dev.sheldan.abstracto.core; +package dev.sheldan.abstracto.core.utils; import dev.sheldan.abstracto.core.management.ChannelManagementService; import dev.sheldan.abstracto.core.management.ServerManagementService; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/MessageUtils.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/MessageUtils.java new file mode 100644 index 000000000..419d9c615 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/MessageUtils.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.utils; + +public class MessageUtils { + public static String buildMessageUrl(Long serverId, Long channelId, Long messageId) { + return String.format("https://discordapp.com/channels/%s/%s/%s", serverId, channelId, messageId); + } +} diff --git a/abstracto-application/executable/pom.xml b/abstracto-application/executable/pom.xml index bdd3a67ca..cba6c5281 100644 --- a/abstracto-application/executable/pom.xml +++ b/abstracto-application/executable/pom.xml @@ -54,6 +54,12 @@ ${project.version} + + dev.sheldan.abstracto.modules + utility-impl + ${project.version} + + diff --git a/abstracto-application/executable/src/main/java/dev/sheldan/abstracto/Application.java b/abstracto-application/executable/src/main/java/dev/sheldan/abstracto/Application.java index 393575b29..35d7f16a0 100644 --- a/abstracto-application/executable/src/main/java/dev/sheldan/abstracto/Application.java +++ b/abstracto-application/executable/src/main/java/dev/sheldan/abstracto/Application.java @@ -9,11 +9,15 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @EnableAutoConfiguration(exclude = { FreeMarkerAutoConfiguration.class }) @ComponentScan(basePackages = {"dev.sheldan.abstracto"}) @EnableCaching +@EnableAsync +@EnableTransactionManagement public class Application implements CommandLineRunner { @Autowired diff --git a/abstracto-application/executable/src/main/resources/application.properties b/abstracto-application/executable/src/main/resources/application.properties index 8e0960598..55a7096a9 100644 --- a/abstracto-application/executable/src/main/resources/application.properties +++ b/abstracto-application/executable/src/main/resources/application.properties @@ -10,6 +10,7 @@ spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.ImprovedNamingStrategy log4j.logger.org.hibernate.SQL=debug log4j.logger.org.hibernate.type.descriptor.sql=trace log4j.logger.org.hibernate.type=trace +log4j.logger.dev.sheldan=debug spring.cache.cache-names=messages spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s