diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Warnings.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Warnings.java new file mode 100644 index 000000000..b9214d86f --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Warnings.java @@ -0,0 +1,92 @@ +package dev.sheldan.abstracto.moderation.commands; + +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import com.jagrosh.jdautilities.menu.ButtonMenu; +import com.jagrosh.jdautilities.menu.Paginator; +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.command.execution.ContextConverter; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.core.service.PaginatorService; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import dev.sheldan.abstracto.moderation.config.ModerationModule; +import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures; +import dev.sheldan.abstracto.moderation.converter.WarnEntryConverter; +import dev.sheldan.abstracto.moderation.models.database.Warning; +import dev.sheldan.abstracto.moderation.models.template.commands.WarnEntry; +import dev.sheldan.abstracto.moderation.models.template.commands.WarningsModel; +import dev.sheldan.abstracto.moderation.service.management.WarnManagementService; +import dev.sheldan.abstracto.templating.service.TemplateService; +import net.dv8tion.jda.api.entities.Member; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.naming.Context; +import java.util.ArrayList; +import java.util.List; + +@Component +public class Warnings extends AbstractConditionableCommand { + + @Autowired + private BotService botService; + + @Autowired + private WarnManagementService warnManagementService; + + @Autowired + private TemplateService templateService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private WarnEntryConverter warnEntryConverter; + + @Autowired + private PaginatorService paginatorService; + + @Override + public CommandResult execute(CommandContext commandContext) { + List warnsToDisplay; + if(commandContext.getParameters().getParameters().size() > 0) { + Member member = (Member) commandContext.getParameters().getParameters().get(0); + warnsToDisplay = warnManagementService.getAllWarnsForUser(userInServerManagementService.loadUser(member)); + } else { + warnsToDisplay = warnManagementService.getAllWarningsOfServer(commandContext.getUserInitiatedContext().getServer()); + } + List warnEntries = warnEntryConverter.fromWarnings(warnsToDisplay); + + WarningsModel model = (WarningsModel) ContextConverter.fromCommandContext(commandContext, WarningsModel.class); + model.setWarnings(warnEntries); + + Paginator paginator = paginatorService.createPaginatorFromTemplate("warnings_response", model, new EventWaiter()); + paginator.display(commandContext.getChannel()); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("user").type(Member.class).optional(true).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("warnings") + .module(ModerationModule.MODERATION) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return ModerationFeatures.WARNING; + } +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/converter/WarnEntryConverter.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/converter/WarnEntryConverter.java new file mode 100644 index 000000000..87f66b280 --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/converter/WarnEntryConverter.java @@ -0,0 +1,47 @@ +package dev.sheldan.abstracto.moderation.converter; + +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import dev.sheldan.abstracto.moderation.models.database.Warning; +import dev.sheldan.abstracto.moderation.models.template.commands.WarnEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class WarnEntryConverter { + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private BotService botService; + + public List fromWarnings(List warnings) { + List entries = new ArrayList<>(); + warnings.forEach(warning -> { + FullUser warnedUser = FullUser + .builder() + .member(botService.getMemberInServer(warning.getWarnedUser())) + .aUserInAServer(warning.getWarnedUser()) + .build(); + + FullUser warningUser = FullUser + .builder() + .member(botService.getMemberInServer(warning.getWarningUser())) + .aUserInAServer(warning.getWarningUser()) + .build(); + WarnEntry entry = WarnEntry + .builder() + .warnedUser(warnedUser) + .warningUser(warningUser) + .warning(warning) + .build(); + entries.add(entry); + }); + return entries; + } +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/repository/WarnRepository.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/repository/WarnRepository.java index e24b9e759..8d36d2698 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/repository/WarnRepository.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/repository/WarnRepository.java @@ -16,9 +16,16 @@ public interface WarnRepository extends JpaRepository { @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) List findAllByWarnedUser_ServerReferenceAndDecayedFalseAndWarnDateLessThan(AServer server, Instant cutOffDate); + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + List findAllByWarnedUser_ServerReference(AServer server); + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) Long countByWarnedUser(AUserInAServer aUserInAServer); @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) Long countByWarnedUserAndDecayedFalse(AUserInAServer aUserInAServer); + + + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + List findByWarnedUser(AUserInAServer aUserInAServer); } diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementServiceBean.java index 96416d07c..9c817db6f 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementServiceBean.java @@ -39,6 +39,16 @@ public class WarnManagementServiceBean implements WarnManagementService { return warnRepository.countByWarnedUser(aUserInAServer); } + @Override + public List getAllWarnsForUser(AUserInAServer aUserInAServer) { + return warnRepository.findByWarnedUser(aUserInAServer); + } + + @Override + public List getAllWarningsOfServer(AServer server) { + return warnRepository.findAllByWarnedUser_ServerReference(server); + } + @Override public Long getActiveWarnsForUser(AUserInAServer aUserInAServer) { return warnRepository.countByWarnedUserAndDecayedFalse(aUserInAServer); diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/warnings/warnings_response_paginator_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/warnings/warnings_response_paginator_en_US.ftl new file mode 100644 index 000000000..3b3e5647a --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/warnings/warnings_response_paginator_en_US.ftl @@ -0,0 +1,7 @@ +{ +<#assign warnCount>${warnings?size} + "headerText": "<#include "warnings_header_text">", + "items": [ + <#list warnings as warning>"<#include "warnings_warn_entry">"<#sep>, + ] +} \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/warnings/warnings_warn_entry_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/warnings/warnings_warn_entry_en_US.ftl new file mode 100644 index 000000000..2fcb9d2ec --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/warnings/warnings_warn_entry_en_US.ftl @@ -0,0 +1,11 @@ +<#assign warnId>${warning.warning.id} +<#assign reason>${warning.warning.reason} +<#assign warnedUserText><#if warning.warnedUser.member??>${warning.warnedUser.member.asMention}(${warning.warnedUser.member.user.id})<#else>${warning.warnedUser.aUserInAServer.id} +<#assign warningUserText><#if warning.warningUser.member??>${warning.warningUser.member.asMention}(${warning.warningUser.member.user.id})<#else>${warning.warningUser.aUserInAServer.id} +<#assign warnDate>${formatInstant(warning.warning.warnDate, "yyyy-MM-dd HH:mm:ss")} + +<#include "warnings_warn_entry_text"> +<#if warning.warning.decayed> +<#assign decayDate>${formatInstant(warning.warning.decayDate, "yyyy-MM-dd HH:mm:ss")} +<#include "warnings_warn_is_decayed"> + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/WarnEntry.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/WarnEntry.java new file mode 100644 index 000000000..5ed03ddeb --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/WarnEntry.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.moderation.models.template.commands; + +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.moderation.models.database.Warning; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class WarnEntry { + private Warning warning; + private FullUser warnedUser; + private FullUser warningUser; +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/WarningsModel.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/WarningsModel.java new file mode 100644 index 000000000..1600c24c9 --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/WarningsModel.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.moderation.models.template.commands; + +import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@Getter +@Setter +@SuperBuilder +public class WarningsModel extends UserInitiatedServerContext { + private List warnings; +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementService.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementService.java index e00c4efa8..294a692df 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementService.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/management/WarnManagementService.java @@ -12,5 +12,7 @@ public interface WarnManagementService { Warning createWarning(AUserInAServer warnedAUser, AUserInAServer warningAUser, String reason); List getActiveWarningsInServerOlderThan(AServer server, Instant date); Long getTotalWarnsForUser(AUserInAServer aUserInAServer); + List getAllWarnsForUser(AUserInAServer aUserInAServer); + List getAllWarningsOfServer(AServer server); Long getActiveWarnsForUser(AUserInAServer aUserInAServer); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/model/PaginatorConfiguration.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/model/PaginatorConfiguration.java new file mode 100644 index 000000000..b5fef715e --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/model/PaginatorConfiguration.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.core.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class PaginatorConfiguration { + private String headerText; + private List items; + private Long timeoutSeconds; + private Boolean showPageNumbers; + private Boolean useNumberedItems; +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PaginatorServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PaginatorServiceBean.java new file mode 100644 index 000000000..e8064ae8a --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PaginatorServiceBean.java @@ -0,0 +1,70 @@ +package dev.sheldan.abstracto.core.service; + +import com.google.gson.Gson; +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import com.jagrosh.jdautilities.menu.Paginator; +import dev.sheldan.abstracto.core.model.PaginatorConfiguration; +import dev.sheldan.abstracto.templating.service.TemplateService; +import net.dv8tion.jda.api.entities.MessageEmbed; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Component +public class PaginatorServiceBean implements PaginatorService { + + @Autowired + private BotService botService; + + @Autowired + private TemplateService templateService; + + @Autowired + private Gson gson; + + + @Override + public Paginator createPaginatorFromTemplate(String templateKey, Object model, EventWaiter waiter) { + String embedConfig = templateService.renderTemplate(templateKey + "_paginator", model); + PaginatorConfiguration configuration = gson.fromJson(embedConfig, PaginatorConfiguration.class); + botService.getInstance().addEventListener(waiter); + List items = configuration.getItems(); + int itemsPerPage = findAppropriateCountPerPage(items); + + return new Paginator.Builder() + .setItemsPerPage(itemsPerPage) + .setText(configuration.getHeaderText()) + .showPageNumbers(ObjectUtils.defaultIfNull(configuration.getShowPageNumbers(), false)) + .setItems(configuration.getItems().toArray(new String[0])) + .useNumberedItems(ObjectUtils.defaultIfNull(configuration.getUseNumberedItems(), false)) + .setEventWaiter(waiter) + .setTimeout(ObjectUtils.defaultIfNull(configuration.getTimeoutSeconds(), 120L), TimeUnit.SECONDS) + .setFinalAction(message -> { + botService.getInstance().removeEventListener(waiter); + message.delete().queue(); + }) + .build(); + } + + private int findAppropriateCountPerPage(List items) { + int currentMin = Integer.MAX_VALUE; + // to be sure, because the paginator adds some characters here and there + int carefulMax = MessageEmbed.TEXT_MAX_LENGTH - 50; + for (int i = 0; i < items.size(); i++) { + int count = 0; + int length = 0; + for (String innerItem : items) { + length += innerItem.length(); + if (length > carefulMax) { + currentMin = Math.min(currentMin, count); + break; + } + count++; + } + } + return currentMin; + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/PaginatorService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/PaginatorService.java new file mode 100644 index 000000000..a592b84da --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/PaginatorService.java @@ -0,0 +1,8 @@ +package dev.sheldan.abstracto.core.service; + +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import com.jagrosh.jdautilities.menu.Paginator; + +public interface PaginatorService { + Paginator createPaginatorFromTemplate(String templateKey, Object model, EventWaiter waiter); +} diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_header_text_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_header_text_en_US.ftl new file mode 100644 index 000000000..66cbdfc0f --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_header_text_en_US.ftl @@ -0,0 +1 @@ +Amount of warns ${warnCount}. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_warn_entry_text_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_warn_entry_text_en_US.ftl new file mode 100644 index 000000000..13b7dc6ce --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_warn_entry_text_en_US.ftl @@ -0,0 +1 @@ +Warnings #${warnId} with reason: ${reason} towards user ${warnedUserText} by user ${warningUserText} on `${warnDate}`. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_warn_is_decayed_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_warn_is_decayed_en_US.ftl new file mode 100644 index 000000000..9e9bc44b0 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/commands/moderation/warnings/warnings_warn_is_decayed_en_US.ftl @@ -0,0 +1 @@ +This warning was decayed on ${decayDate}. \ No newline at end of file diff --git a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java index b7f3ad84f..64b5d01e1 100644 --- a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java +++ b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java @@ -29,10 +29,6 @@ public class TemplateServiceBean implements TemplateService { @Autowired private Gson gson; - @Override - public String renderTemplate(Template template) { - return null; - } private String getPageString(Integer count) { HashMap params = new HashMap<>(); diff --git a/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java b/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java index 8032f0d1e..013518cd9 100644 --- a/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java +++ b/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java @@ -1,12 +1,10 @@ package dev.sheldan.abstracto.templating.service; import dev.sheldan.abstracto.templating.model.MessageToSend; -import dev.sheldan.abstracto.templating.model.database.Template; import java.util.HashMap; public interface TemplateService { - String renderTemplate(Template template); MessageToSend renderEmbedTemplate(String key, Object model); String renderTemplateWithMap(String key, HashMap parameters); String renderTemplate(String key, Object model);