diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Purge.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Purge.java new file mode 100644 index 000000000..a163f99a4 --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Purge.java @@ -0,0 +1,67 @@ +package dev.sheldan.abstracto.moderation.commands; + +import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; +import dev.sheldan.abstracto.core.command.config.CommandConfiguration; +import dev.sheldan.abstracto.core.command.config.HelpInfo; +import dev.sheldan.abstracto.core.command.config.Parameter; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.utils.ExceptionUtils; +import dev.sheldan.abstracto.moderation.config.ModerationModule; +import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures; +import dev.sheldan.abstracto.moderation.service.PurgeService; +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 java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class Purge extends AbstractConditionableCommand { + + @Autowired + private PurgeService purgeService; + + @Autowired + private TemplateService templateService; + + @Autowired + private ExceptionUtils exceptionUtils; + + @Override + public CommandResult execute(CommandContext commandContext) { + Integer amountOfMessages = (Integer) commandContext.getParameters().getParameters().get(0); + Member memberToPurgeMessagesOf = null; + if(commandContext.getParameters().getParameters().size() == 2) { + memberToPurgeMessagesOf = (Member) commandContext.getParameters().getParameters().get(1); + } + CompletableFuture future = purgeService.purgeMessagesInChannel(amountOfMessages, commandContext.getChannel(), commandContext.getMessage(), memberToPurgeMessagesOf); + future.whenComplete((aVoid, throwable) -> exceptionUtils.handleExceptionIfTemplatable(throwable, commandContext.getChannel())); + return CommandResult.fromSelfDestruct(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("amount").type(Integer.class).templated(true).build()); + parameters.add(Parameter.builder().name("member").type(Member.class).optional(true).templated(true).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("purge") + .module(ModerationModule.MODERATION) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return ModerationFeatures.MODERATION; + } +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBean.java new file mode 100644 index 000000000..616b1dd88 --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBean.java @@ -0,0 +1,148 @@ +package dev.sheldan.abstracto.moderation.service; + +import dev.sheldan.abstracto.core.service.MessageService; +import dev.sheldan.abstracto.moderation.exception.NoMessageFoundException; +import dev.sheldan.abstracto.moderation.models.template.commands.PurgeStatusUpdateModel; +import dev.sheldan.abstracto.templating.model.MessageToSend; +import dev.sheldan.abstracto.templating.service.TemplateService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageHistory; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.utils.MiscUtil; +import net.dv8tion.jda.api.utils.TimeUtil; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +@Component +@Slf4j +public class PurgeServiceBean implements PurgeService { + + @Autowired + private MessageService messageService; + + @Autowired + private TemplateService templateService; + + @Override + public CompletableFuture purgeMessagesInChannel(Integer amountToDelete, TextChannel channel, Long startId, Member purgedMember) { + return purgeMessages(amountToDelete, channel, startId, purgedMember, amountToDelete, 0, 0L); + } + + @NotNull + private CompletableFuture purgeMessages(Integer amountToDelete, TextChannel channel, Long startId, Member purgedMember, Integer totalCount, Integer currentCount, Long statusMessageId) { + CompletableFuture deletionFuture = new CompletableFuture<>(); + int toDeleteInThisIteration; + int messageLimit = 100; + if(amountToDelete >= messageLimit){ + toDeleteInThisIteration = messageLimit; + } else { + toDeleteInThisIteration = amountToDelete % messageLimit; + } + + CompletableFuture historyFuture = channel.getHistoryBefore(startId, toDeleteInThisIteration).submit(); + CompletableFuture statusMessageFuture = getOrCreatedStatusMessage(channel, totalCount, statusMessageId); + + CompletableFuture coreFuture = CompletableFuture.allOf(historyFuture, statusMessageFuture); + coreFuture.thenAccept(voidParam -> { + try { + List retrievedHistory = historyFuture.get().getRetrievedHistory(); + List messagesToDeleteNow = filterMessagesToDelete(retrievedHistory, purgedMember); + Long currentStatusMessageId = statusMessageFuture.get(); + if(messagesToDeleteNow.size() == 0) { + deletionFuture.completeExceptionally(new NoMessageFoundException()); + channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS); + return; + } + Message latestMessage = messagesToDeleteNow.get(messagesToDeleteNow.size() - 1); + log.trace("Deleting {} messages directly", messagesToDeleteNow.size()); + int newCurrentCount = currentCount + messagesToDeleteNow.size(); + int newAmountToDelete = amountToDelete - messageLimit; + Consumer consumer = deletionConsumer(newAmountToDelete, channel, purgedMember, totalCount, newCurrentCount, deletionFuture, currentStatusMessageId, latestMessage); + if (messagesToDeleteNow.size() > 1) { + bulkDeleteMessages(channel, deletionFuture, messagesToDeleteNow, consumer); + } else if (messagesToDeleteNow.size() == 1) { + messagesToDeleteNow.get(0).delete().queue(consumer, deletionFuture::completeExceptionally); + } + + } catch (Exception e) { + log.warn("Failed to purge messages.", e); + deletionFuture.completeExceptionally(e); + } + }).exceptionally(throwable -> { + log.warn("Failed to fetch messages.", throwable); + return null; + }); + + return CompletableFuture.allOf(coreFuture, deletionFuture); + } + + private void bulkDeleteMessages(TextChannel channel, CompletableFuture deletionFuture, List messagesToDeleteNow, Consumer consumer) { + try { + channel.deleteMessages(messagesToDeleteNow).queue(consumer, deletionFuture::completeExceptionally); + } catch (IllegalArgumentException e) { + channel.sendMessage(e.getMessage()).queue(); + log.warn("Failed to bulk delete, message was most likely too old to delete by bulk.", e); + deletionFuture.complete(null); + } + } + + private CompletableFuture getOrCreatedStatusMessage(TextChannel channel, Integer totalCount, Long statusMessageId) { + CompletableFuture statusMessageFuture; + if(statusMessageId == 0) { + PurgeStatusUpdateModel model = PurgeStatusUpdateModel.builder().currentlyDeleted(0).totalToDelete(totalCount).build(); + MessageToSend messageToSend = templateService.renderTemplateToMessageToSend("purge_status_update", model); + statusMessageFuture = messageService.createStatusMessageId(messageToSend, channel); + } else { + statusMessageFuture = CompletableFuture.completedFuture(statusMessageId); + } + return statusMessageFuture; + } + + private List filterMessagesToDelete(List retrievedHistory, Member purgedMember) { + long twoWeeksAgo = TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000))); + List messagesToDeleteNow = new ArrayList<>(); + for (Message messageObj : retrievedHistory) { + if (MiscUtil.parseSnowflake(messageObj.getId()) > twoWeeksAgo) { + if(purgedMember != null) { + if(messageObj.getAuthor().getIdLong() == purgedMember.getIdLong()) { + messagesToDeleteNow.add(messageObj); + } + } else { + messagesToDeleteNow.add(messageObj); + } + } + } + return messagesToDeleteNow; + } + + private Consumer deletionConsumer(Integer amountToDelete, TextChannel channel, Member purgedMember, Integer totalCount, Integer currentCount, CompletableFuture deletionFuture, Long currentStatusMessageId, Message earliestMessage) { + return aVoid -> { + if (amountToDelete > 1) { + purgeMessages(amountToDelete, channel, earliestMessage.getIdLong(), purgedMember, totalCount, currentCount, currentStatusMessageId).thenAccept(aVoid1 -> + deletionFuture.complete(null) + ); + } else { + channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS); + deletionFuture.complete(null); + } + log.info("Setting status for {} out of {}", currentCount, totalCount); + PurgeStatusUpdateModel finalUpdateModel = PurgeStatusUpdateModel.builder().currentlyDeleted(currentCount).totalToDelete(totalCount).build(); + MessageToSend finalUpdateMessage = templateService.renderTemplateToMessageToSend("purge_status_update", finalUpdateModel); + messageService.updateStatusMessage(channel, currentStatusMessageId, finalUpdateMessage); + }; + } + + @Override + public CompletableFuture purgeMessagesInChannel(Integer count, TextChannel channel, Message origin, Member purgingRestriction) { + return purgeMessagesInChannel(count, channel, origin.getIdLong(), purgingRestriction); + } +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/purge/purge_status_update_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/purge/purge_status_update_en_US.ftl new file mode 100644 index 000000000..36202062b --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/command/purge/purge_status_update_en_US.ftl @@ -0,0 +1 @@ +<#include "purge_status_update_message"> \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/exception/no_message_found_exception_en_US.ftl b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/exception/no_message_found_exception_en_US.ftl new file mode 100644 index 000000000..b3ac0014f --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/resources/templates/exception/no_message_found_exception_en_US.ftl @@ -0,0 +1 @@ +<#include "no_message_found_exception_message"> \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/exception/NoMessageFoundException.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/exception/NoMessageFoundException.java new file mode 100644 index 000000000..0a378c83a --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/exception/NoMessageFoundException.java @@ -0,0 +1,20 @@ +package dev.sheldan.abstracto.moderation.exception; + +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.Templatable; + +public class NoMessageFoundException extends AbstractoRunTimeException implements Templatable { + public NoMessageFoundException() { + super(""); + } + + @Override + public String getTemplateName() { + return "no_message_found_exception"; + } + + @Override + public Object getTemplateModel() { + return new Object(); + } +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/PurgeStatusUpdateModel.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/PurgeStatusUpdateModel.java new file mode 100644 index 000000000..91c349179 --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/models/template/commands/PurgeStatusUpdateModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.moderation.models.template.commands; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class PurgeStatusUpdateModel { + private Integer currentlyDeleted; + private Integer totalToDelete; +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeService.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeService.java new file mode 100644 index 000000000..a78072bbe --- /dev/null +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeService.java @@ -0,0 +1,12 @@ +package dev.sheldan.abstracto.moderation.service; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; + +import java.util.concurrent.CompletableFuture; + +public interface PurgeService { + CompletableFuture purgeMessagesInChannel(Integer count, TextChannel channel, Long messageId, Member purgingRestriction); + CompletableFuture purgeMessagesInChannel(Integer count, TextChannel channel, Message origin, Member purgingRestriction); +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/SelfDestructPostExecution.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/SelfDestructPostExecution.java new file mode 100644 index 000000000..a4dd68110 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/SelfDestructPostExecution.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.core.command.post; + +import dev.sheldan.abstracto.core.command.Command; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.command.execution.ResultState; +import dev.sheldan.abstracto.core.command.service.PostCommandExecution; +import org.springframework.stereotype.Component; + +@Component +public class SelfDestructPostExecution implements PostCommandExecution { + @Override + public void execute(CommandContext commandContext, CommandResult commandResult, Command command) { + if(commandResult.getResult().equals(ResultState.SELF_DESTRUCT)) { + commandContext.getMessage().delete().queue(); + } + } +} 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 index e9ed59e93..4ee584c33 100644 --- 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 @@ -83,11 +83,26 @@ public class MessageServiceBean implements MessageService { return channelService.sendMessageToSendToAChannel(messageToSend, channel).get(0); } + @Override + public CompletableFuture createStatusMessage(MessageToSend messageToSend, MessageChannel channel) { + return channelService.sendMessageToSendToChannel(messageToSend, channel).get(0); + } + + @Override + public CompletableFuture createStatusMessageId(MessageToSend messageToSend, MessageChannel channel) { + return channelService.sendMessageToSendToChannel(messageToSend, channel).get(0).thenApply(ISnowflake::getIdLong); + } + @Override public void updateStatusMessage(AChannel channel, Long messageId, MessageToSend messageToSend) { channelService.editMessageInAChannel(messageToSend, channel, messageId); } + @Override + public void updateStatusMessage(MessageChannel channel, Long messageId, MessageToSend messageToSend) { + channelService.editMessageInAChannel(messageToSend, channel, messageId); + } + @Override public void sendMessageToUser(AUserInAServer userInAServer, String text, TextChannel feedbackChannel) { Member memberInServer = botService.getMemberInServer(userInAServer); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java index 687ee3845..df4b82595 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java @@ -19,6 +19,10 @@ public class CommandResult { return CommandResult.builder().result(ResultState.SUCCESSFUL).build(); } + public static CommandResult fromSelfDestruct() { + return CommandResult.builder().result(ResultState.SELF_DESTRUCT).build(); + } + public static CommandResult fromError(String message){ return CommandResult.builder().result(ResultState.ERROR).message(message).build(); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java index 76ac552d5..6089fa8bc 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java @@ -1,5 +1,5 @@ package dev.sheldan.abstracto.core.command.execution; public enum ResultState { - ERROR, SUCCESSFUL, IGNORED, CONDITION + ERROR, SUCCESSFUL, IGNORED, CONDITION, SELF_DESTRUCT } 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 index 099dd860f..e14373e98 100644 --- 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 @@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.templating.model.MessageToSend; import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.User; @@ -16,7 +17,10 @@ public interface MessageService { List> addReactionsToMessageWithFuture(List emoteKeys, Long serverId, Message message); CompletableFuture deleteMessageInChannelInServer(Long serverId, Long channelId, Long messageId); CompletableFuture createStatusMessage(MessageToSend messageToSend, AChannel channel); + CompletableFuture createStatusMessage(MessageToSend messageToSend, MessageChannel channel); + CompletableFuture createStatusMessageId(MessageToSend messageToSend, MessageChannel channel); void updateStatusMessage(AChannel channel, Long messageId, MessageToSend messageToSend); + void updateStatusMessage(MessageChannel channel, Long messageId, MessageToSend messageToSend); void sendMessageToUser(AUserInAServer userInAServer, String text, TextChannel feedbackChannel); void sendMessageToUser(User user, String text, TextChannel feedbackChannel); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ExceptionUtils.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ExceptionUtils.java new file mode 100644 index 000000000..bdf3a5a06 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ExceptionUtils.java @@ -0,0 +1,27 @@ +package dev.sheldan.abstracto.core.utils; + +import dev.sheldan.abstracto.templating.Templatable; +import dev.sheldan.abstracto.templating.service.TemplateService; +import net.dv8tion.jda.api.entities.MessageChannel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +public class ExceptionUtils { + + @Autowired + private TemplateService templateService; + + @Transactional + public void handleExceptionIfTemplatable(Throwable throwable, MessageChannel channel) { + if(throwable != null) { + if(throwable.getCause() instanceof Templatable) { + String exceptionText = templateService.renderTemplatable((Templatable) throwable.getCause()); + channel.sendMessage(exceptionText).queue(); + } else { + channel.sendMessage(throwable.getCause().getMessage()).queue(); + } + } + } +} diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/moderation.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/features/moderation.adoc index 23c76132a..28265b35a 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/features/moderation.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/features/moderation.adoc @@ -29,6 +29,11 @@ Change the slow mode in a channel:: * Usage: `slowmode [channel]` * Description: This command sets the slow mode in the `channel` to the given `duration`. This command uses duration parsing. The `channel` is optional and if none is provided, the current channel is used. * Example: `slowMode 1h2m3s #general` in order to set the slow mode in channel `general` to 1 hour 2 minutes and 3 seconds (the #general is a user mention) +Purging messages in a channel:: +* Usage: `purge [member]` +* Description: Deletes the last `messageCount` messages in the current channel. If a `member` is provided as parameter, only the messages by this member +will be deleted. The deletion of this messages will *not* be logged by the logging mechanism. The messages to be deleted need to be from within the last 2 weeks, but there is no limit on how much messages can be deleted besides that. +While the command is ongoing, a status update message will be shown indicating how far the command is. This message will be deleted after the command is done. === Warning diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_description_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_description_en_US.ftl new file mode 100644 index 000000000..7be1b6cb7 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_description_en_US.ftl @@ -0,0 +1 @@ +Deletes the last n messages in the channel \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_long_help_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_long_help_en_US.ftl new file mode 100644 index 000000000..2247dd8cc --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_long_help_en_US.ftl @@ -0,0 +1,6 @@ +Deletes the last n messages in the channel. The messages are allowed to be at most 2 weeks old. +If a member is provided as a parameter, only messages by this member are deleted, but at most n messages are considered. +For example, if you execute the command with 200 messages and specify member User#1234, and User#1234 does not have any messages +in the last 200 message, no message will be deleted. +While the command is going on a status message indicating how many messages are currently being deleted is shown. +If messages older than two weeks are found, the command will stop and post an error message. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_parameter_amount_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_parameter_amount_en_US.ftl new file mode 100644 index 000000000..1a254096f --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_parameter_amount_en_US.ftl @@ -0,0 +1 @@ +Amount of messages do delete. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_parameter_member_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_parameter_member_en_US.ftl new file mode 100644 index 000000000..536f26b99 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_parameter_member_en_US.ftl @@ -0,0 +1 @@ +The member to delete messages of. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_usage_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_usage_en_US.ftl new file mode 100644 index 000000000..3ad3aba6a --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/help/purge_usage_en_US.ftl @@ -0,0 +1 @@ +purge [member] \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/purge_status_update_message_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/purge_status_update_message_en_US.ftl new file mode 100644 index 000000000..88f8bcff0 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/commands/purge/purge_status_update_message_en_US.ftl @@ -0,0 +1 @@ +${currentlyDeleted} out of ${totalToDelete} messages deleted. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/exception/no_message_found_exception_message_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/exception/no_message_found_exception_message_en_US.ftl new file mode 100644 index 000000000..3539f17d6 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/moderation/exception/no_message_found_exception_message_en_US.ftl @@ -0,0 +1 @@ +No more messages found to delete. \ 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 b6ff0419b..11c1233e7 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 @@ -114,6 +114,11 @@ public class TemplateServiceBean implements TemplateService { .build(); } + @Override + public MessageToSend renderTemplateToMessageToSend(String key, Object model) { + return MessageToSend.builder().message(renderTemplate(key, model)).build(); + } + private void createFieldsForEmbed(List embedBuilders, EmbedConfiguration configuration) { for (int i = 0; i < configuration.getFields().size(); i++) { EmbedField field = configuration.getFields().get(i); 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 e16151a49..f5c6aa695 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 @@ -18,6 +18,14 @@ public interface TemplateService { */ MessageToSend renderEmbedTemplate(String key, Object model); + /** + * Renders the given template directly into a {@link MessageToSend} but the template only represents a text message. + * @param key The key of the string template to be rendered. + * @param model The model used to render the template + * @return A {@link MessageToSend} instance only containing the string property. + */ + MessageToSend renderTemplateToMessageToSend(String key, Object model); + /** * Renders the template identified by the key with the given {@link HashMap} used as model and returns the value as a string * @param key The key of the template to be rendered.