Compare commits

..

13 Commits

Author SHA1 Message Date
release-bot
a371993c87 [maven-release-plugin] prepare release v1.5.60 2025-01-31 18:07:33 +00:00
Sheldan
77b97507b3 [AB-xxx] adding paginators to emote stats
adding handling for emotes which are only provided as ID to command inputs
removing message commands from emote statistic related commands
2025-01-31 19:03:38 +01:00
Sheldan
e952727849 [AB-xxx] fixing incorrect join for deleted emote stats 2025-01-27 23:19:26 +01:00
release-bot
909a08d3d2 Commit from GitHub Actions (Publishes a new version of abstracto) 2025-01-27 20:23:59 +00:00
release-bot
e02236145f [maven-release-plugin] prepare for next development iteration 2025-01-27 20:13:35 +00:00
release-bot
1d810bdc07 [maven-release-plugin] prepare release v1.5.59 2025-01-27 20:13:33 +00:00
Sheldan
f9334d5210 [AB-xxx] always showing all emotes in emote stats output 2025-01-27 21:09:46 +01:00
release-bot
0a7e30cace Commit from GitHub Actions (Publishes a new version of abstracto) 2025-01-27 00:44:12 +00:00
release-bot
d91091d149 [maven-release-plugin] prepare for next development iteration 2025-01-27 00:35:25 +00:00
release-bot
2690b1a5d9 [maven-release-plugin] prepare release v1.5.58 2025-01-27 00:35:24 +00:00
Sheldan
ed42940e29 [AB-xxx] adding ability to track emotes used in reactions
adding ability to have confirmations for slash commands
2025-01-27 01:31:56 +01:00
release-bot
2c3b16879e Commit from GitHub Actions (Publishes a new version of abstracto) 2025-01-15 21:25:59 +00:00
release-bot
bd7fc6aa65 [maven-release-plugin] prepare for next development iteration 2025-01-15 21:16:39 +00:00
154 changed files with 1757 additions and 615 deletions

2
.env
View File

@@ -1,2 +1,2 @@
REGISTRY_PREFIX=harbor.sheldan.dev/abstracto/
VERSION=1.5.56
VERSION=1.5.59

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>assignable-roles-int</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>dynamic-activity</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>dynamic-activity</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -55,7 +55,7 @@ public class MinesButtonClickedListener implements ButtonClickedListener {
gameService.uncoverBoard(mineBoard);
}
MessageToSend messageToSend = templateService.renderEmbedTemplate(Mines.MINE_BOARD_TEMPLATE_KEY, mineBoard, model.getServerId());
interactionService.editOriginal(messageToSend, model.getEvent().getHook()).thenAccept(message -> {
interactionService.replaceOriginal(messageToSend, model.getEvent().getHook()).thenAccept(message -> {
gameService.updateMineBoard(mineBoard);
log.info("Updated original mineboard for board {}.", mineBoard.getBoardId());
});

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<artifactId>giveaway-impl</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<artifactId>giveaway-int</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<artifactId>giveaway</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>image-generation</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<artifactId>image-generation-impl</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>image-generation</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<artifactId>image-generation-int</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<artifactId>image-generation</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>invite-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>invite-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -18,7 +18,7 @@
<dependency>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation-int</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>link-embed</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>link-embed</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>logging</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>logging</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,6 @@ 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.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
@@ -12,10 +11,8 @@ import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.WarnService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -45,14 +42,6 @@ public class DecayAllWarnings extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
AServer server = serverManagementService.loadServer(event.getGuild());
return warnService.decayAllWarningsForServer(server)
.thenCompose(unused -> interactionService.replyEmbed(DECAY_ALL_WARNINGS_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
@@ -61,19 +50,11 @@ public class DecayAllWarnings extends AbstractConditionableCommand {
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.WARN_DECAY)
.commandName(DECAY_ALL_WARNINGS_COMMAND)
.build();
return CommandConfiguration.builder()
.name(DECAY_ALL_WARNINGS_COMMAND)
.module(ModerationModuleDefinition.MODERATION)
.templated(true)
.async(true)
.slashCommandConfig(slashCommandConfig)
.requiresConfirmation(true)
.supportsEmbedException(true)
.causesReaction(true)

View File

@@ -4,18 +4,14 @@ 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.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.WarnService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -27,7 +23,6 @@ import java.util.concurrent.CompletableFuture;
public class DecayWarnings extends AbstractConditionableCommand {
private static final String DECAY_WARNINGS_COMMAND = "decayWarnings";
private static final String DECAY_WARNINGS_RESPONSE = "decayWarnings_response";
@Autowired
private WarnService warnService;
@@ -35,9 +30,6 @@ public class DecayWarnings extends AbstractConditionableCommand {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private InteractionService interactionService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
AServer server = serverManagementService.loadServer(commandContext.getGuild());
@@ -45,14 +37,6 @@ public class DecayWarnings extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
AServer server = serverManagementService.loadServer(event.getGuild());
return warnService.decayWarningsForServer(server)
.thenCompose(unused -> interactionService.replyEmbed(DECAY_WARNINGS_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
@@ -61,18 +45,10 @@ public class DecayWarnings extends AbstractConditionableCommand {
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.WARN_DECAY)
.commandName(DECAY_WARNINGS_COMMAND)
.build();
return CommandConfiguration.builder()
.name(DECAY_WARNINGS_COMMAND)
.module(ModerationModuleDefinition.MODERATION)
.templated(true)
.slashCommandConfig(slashCommandConfig)
.requiresConfirmation(true)
.async(true)
.supportsEmbedException(true)

View File

@@ -217,7 +217,7 @@ public class PurgeServiceBean implements PurgeService {
}
log.debug("Setting status for {} out of {}", currentCount, totalCount);
MessageToSend finalUpdateMessage = getStatusMessageToSend(totalCount, channel.getGuild().getIdLong(), currentCount);
interactionService.editOriginal(finalUpdateMessage, interactionHook);
interactionService.replaceOriginal(finalUpdateMessage, interactionHook);
};
}
@@ -244,7 +244,7 @@ public class PurgeServiceBean implements PurgeService {
CompletableFuture<MessageHistory> historyFuture = channelService.getHistoryOfChannel(channel, startId, toDeleteInThisIteration);
MessageToSend statusMessageToSend = getStatusMessageToSend(totalCount, channel.getGuild().getIdLong(), 0);
CompletableFuture<Message> statusMessageFuture = interactionService.editOriginal(statusMessageToSend, interactionHook);
CompletableFuture<Message> statusMessageFuture = interactionService.replaceOriginal(statusMessageToSend, interactionHook);
CompletableFuture<Void> deletionFuture = new CompletableFuture<>();
CompletableFuture<Void> retrievalFuture = CompletableFuture.allOf(historyFuture, statusMessageFuture);

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>modmail</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>modmail</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<artifactId>abstracto-application</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>profanity-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>profanity-filter</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>remind</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>remind</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>repost-detection</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>repost-detection</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>starboard</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>starboard</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,14 +4,24 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandService;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import java.util.concurrent.CompletableFuture;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -30,14 +40,35 @@ public class DeleteTrackedEmote extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private SlashCommandService slashCommandService;
private static final String DELETE_TRACKED_EMOTE_TRACKED_EMOTE = "trackedEmote";
private static final String DELETE_TRACKED_EMOTE_COMMAND_NAME = "deleteTrackedEmote";
private static final String DELETE_TRACKED_EMOTE_RESPONSE = "deleteTrackedEmote_response";
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
// need to actually load the TrackedEmote
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String emote = slashCommandParameterService.getCommandOption(DELETE_TRACKED_EMOTE_TRACKED_EMOTE, event, String.class);
Emoji emoji = slashCommandParameterService.loadEmoteFromString(emote, event.getGuild());
if(emoji instanceof CustomEmoji) {
Long emoteId = ((CustomEmoji) emoji).getIdLong();
return createResponse(event, emoteId);
} else if(StringUtils.isNumeric(emote)) {
return createResponse(event, Long.parseLong(emote));
} else {
throw new TrackedEmoteNotFoundException();
}
}
private CompletableFuture<CommandResult> createResponse(SlashCommandInteractionEvent event, Long emoteId) {
ServerSpecificId serverEmoteId = new ServerSpecificId(event.getGuild().getIdLong(), emoteId);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(serverEmoteId);
trackedEmoteService.deleteTrackedEmote(trackedEmote);
return CommandResult.fromSuccess();
return slashCommandService.completeConfirmableCommand(event, DELETE_TRACKED_EMOTE_RESPONSE);
}
@Override
@@ -45,19 +76,33 @@ public class DeleteTrackedEmote extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter trackedEmoteParameter = Parameter
.builder()
.name("trackedEmote")
.name(DELETE_TRACKED_EMOTE_TRACKED_EMOTE)
.templated(true)
.type(TrackedEmote.class)
.build();
parameters.add(trackedEmoteParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC_INTERNAL)
.groupName("manage")
.commandName("deletetrackedemote")
.build();
return CommandConfiguration.builder()
.name("deleteTrackedEmote")
.name(DELETE_TRACKED_EMOTE_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.messageCommandOnly(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.requiresConfirmation(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -4,19 +4,26 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.PaginatorService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.command.parameter.UsedEmoteTypeParameter;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emote.service.UsedEmoteService;
import java.util.Arrays;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -34,49 +41,67 @@ import java.util.concurrent.CompletableFuture;
@Slf4j
public class DeletedEmoteStats extends AbstractConditionableCommand {
public static final String DELETED_EMOTE_STATS_COMMAND_NAME = "deletedEmoteStats";
@Autowired
private UsedEmoteService usedEmoteService;
@Autowired
private ChannelService channelService;
private PaginatorService paginatorService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
public static final String EMOTE_STATS_STATIC_DELETED_RESPONSE = "deletedEmoteStats_static_response";
public static final String EMOTE_STATS_ANIMATED_DELETED_RESPONSE = "deletedEmoteStats_animated_response";
private static final String DELETED_EMOTE_STATS_PERIOD = "period";
private static final String DELETED_EMOTE_STATS_USED_EMOTE_TYPE = "type";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
// default is 1.1.1970
Instant statsSince = Instant.EPOCH;
if(!parameters.isEmpty()) {
// if a duration parameter is available, subtract the current time of this to get the true Instant
Duration duration = (Duration) parameters.get(0);
statsSince = Instant.now().minus(duration);
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
UsedEmoteTypeParameter typeEnum;
if(slashCommandParameterService.hasCommandOption(DELETED_EMOTE_STATS_USED_EMOTE_TYPE, event)) {
String type = slashCommandParameterService.getCommandOption(DELETED_EMOTE_STATS_USED_EMOTE_TYPE, event, String.class);
typeEnum = UsedEmoteTypeParameter.valueOf(type);
} else {
typeEnum = null;
}
AServer server = serverManagementService.loadServer(commandContext.getGuild());
EmoteStatsModel emoteStatsModel = usedEmoteService.getDeletedEmoteStatsForServerSince(server, statsSince);
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
// only show the embed, if there are static emotes to show
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
log.debug("Deleted emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, emoteStatsModel, commandContext.getChannel()));
Instant startTime;
if(slashCommandParameterService.hasCommandOption(DELETED_EMOTE_STATS_PERIOD, event)) {
String durationString = slashCommandParameterService.getCommandOption(DELETED_EMOTE_STATS_PERIOD, event, Duration.class, String.class);
Duration durationSince = ParseUtils.parseDuration(durationString);
startTime = Instant.now().minus(durationSince);
} else {
startTime = Instant.EPOCH;
}
// only show the embed, if there are animated emotes to show
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
log.debug("Deleted emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_ANIMATED_DELETED_RESPONSE, emoteStatsModel, commandContext.getChannel()));
}
// if neither static nor animated emote stats are available, show an embed indicating so
if(!emoteStatsModel.areStatsAvailable()) {
log.info("No delete emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
AServer server = serverManagementService.loadServer(event.getGuild());
EmoteStatsModel emoteStatsModel = usedEmoteService.getDeletedEmoteStatsForServerSince(server, startTime, UsedEmoteTypeParameter.convertToUsedEmoteType(typeEnum));
List<CompletableFuture<Void>> messagePromises = new ArrayList<>();
return event.deferReply().submit().thenCompose(interactionHook -> {
// only show embed if static emote stats are available
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
log.debug("Deleted emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), startTime);
messagePromises.add(paginatorService.sendPaginatorToInteraction(EMOTE_STATS_STATIC_DELETED_RESPONSE, emoteStatsModel, interactionHook));
}
// only show embed if animated emote stats are available
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
log.debug("Deleted emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), startTime);
messagePromises.add(paginatorService.sendPaginatorToInteraction(EMOTE_STATS_ANIMATED_DELETED_RESPONSE, emoteStatsModel, interactionHook));
}
// show an embed if no emote stats are available indicating so
if(!emoteStatsModel.areStatsAvailable()) {
log.info("No delete emote stats available for guild {} since {}.", event.getGuild().getIdLong(), startTime);
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), interactionHook))
.thenApply(unused -> CommandResult.fromSuccess());
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
});
}
@Override
@@ -84,20 +109,51 @@ public class DeletedEmoteStats extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter periodParameter = Parameter
.builder()
.name("period")
.name(DELETED_EMOTE_STATS_PERIOD)
.templated(true)
.optional(true)
.type(Duration.class)
.build();
parameters.add(periodParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
List<String> emoteTypes = Arrays
.stream(UsedEmoteTypeParameter.values())
.map(Enum::name)
.collect(Collectors.toList());
Parameter typeParameter = Parameter
.builder()
.name(DELETED_EMOTE_STATS_USED_EMOTE_TYPE)
.templated(true)
.slashCommandOnly(true)
.optional(true)
.choices(emoteTypes)
.type(String.class)
.build();
parameters.add(typeParameter);
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC)
.groupName("emotestats")
.commandName("deleted")
.build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("deletedEmoteStats")
.name(DELETED_EMOTE_STATS_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.async(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true)
.messageCommandOnly(true)
.slashCommandOnly(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -4,14 +4,24 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import java.util.concurrent.CompletableFuture;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -30,18 +40,42 @@ public class DisableEmoteTracking extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
private static final String DISABLE_EMOTE_TRACKING_COMMAND_NAME = "disableEmoteTracking";
private static final String DISABLE_EMOTE_TRACKING_TRACKED_EMOTE = "trackedEmote";
private static final String DISABLE_EMOTE_TRACKING_RESPONSE = "disableEmoteTracking_response";
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
if(!parameters.isEmpty()) {
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
// need to reload the tracked emote
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
trackedEmoteManagementService.disableTrackedEmote(trackedEmote);
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
if(slashCommandParameterService.hasCommandOption(DISABLE_EMOTE_TRACKING_TRACKED_EMOTE, event)) {
String emote = slashCommandParameterService.getCommandOption(DISABLE_EMOTE_TRACKING_TRACKED_EMOTE, event, String.class);
Emoji emoji = slashCommandParameterService.loadEmoteFromString(emote, event.getGuild());
if(emoji instanceof CustomEmoji) {
Long emoteId = ((CustomEmoji) emoji).getIdLong();
disableTracking(event, emoteId);
} else if(StringUtils.isNumeric(emote)) {
disableTracking(event, Long.parseLong(emote));
} else {
throw new TrackedEmoteNotFoundException();
}
} else {
trackedEmoteService.disableEmoteTracking(commandContext.getGuild());
trackedEmoteService.disableEmoteTracking(event.getGuild());
}
return CommandResult.fromSuccess();
return interactionService.replyEmbed(DISABLE_EMOTE_TRACKING_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromIgnored());
}
private void disableTracking(SlashCommandInteractionEvent event, Long emoteId) {
ServerSpecificId serverEmoteId = new ServerSpecificId(event.getGuild().getIdLong(), emoteId);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(serverEmoteId);
trackedEmoteManagementService.disableTrackedEmote(trackedEmote);
}
@Override
@@ -49,18 +83,32 @@ public class DisableEmoteTracking extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter trackedEmoteParameter = Parameter
.builder()
.name("trackedEmote")
.name(DISABLE_EMOTE_TRACKING_TRACKED_EMOTE)
.templated(true)
.optional(true)
.type(TrackedEmote.class)
.build();
parameters.add(trackedEmoteParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC_INTERNAL)
.groupName("manage")
.commandName("disableemotetracking")
.build();
return CommandConfiguration.builder()
.name("disableEmoteTracking")
.name(DISABLE_EMOTE_TRACKING_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.messageCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.slashCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -4,18 +4,29 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.command.parameter.UsedEmoteTypeParameter;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsResultDisplay;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.service.UsedEmoteService;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import java.util.Arrays;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -34,33 +45,63 @@ public class EmoteStat extends AbstractConditionableCommand {
@Autowired
private UsedEmoteService usedEmoteService;
@Autowired
private ChannelService channelService;
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
public static final String EMOTE_STAT_RESPONSE = "emoteStat_response";
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
private static final String EMOTE_STAT_RESPONSE = "emoteStat_response";
private static final String EMOTE_STAT_USED_EMOTE_TYPE = "type";
private static final String EMOTE_STAT_DURATION = "period";
private static final String EMOTE_STAT_TRACKED_EMOTE = "trackedEmote";
private static final String EMOTE_STAT_COMMAND_NAME = "emoteStat";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
// default is 1.1.1970
Instant statsSince = Instant.EPOCH;
TrackedEmote emote = (TrackedEmote) parameters.get(0);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(emote.getTrackedEmoteId());
if(parameters.size() == 2) {
// subtract the given Duration from the current point in time, if there is any
Duration duration = (Duration) parameters.get(1);
statsSince = Instant.now().minus(duration);
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
UsedEmoteTypeParameter typeEnum;
if(slashCommandParameterService.hasCommandOption(EMOTE_STAT_USED_EMOTE_TYPE, event)) {
String type = slashCommandParameterService.getCommandOption(EMOTE_STAT_USED_EMOTE_TYPE, event, String.class);
typeEnum = UsedEmoteTypeParameter.valueOf(type);
} else {
typeEnum = null;
}
EmoteStatsResultDisplay emoteStatsModel = usedEmoteService.getEmoteStatForEmote(trackedEmote, statsSince);
Instant startTime;
if(slashCommandParameterService.hasCommandOption(EMOTE_STAT_DURATION, event)) {
String durationString = slashCommandParameterService.getCommandOption(EMOTE_STAT_DURATION, event, Duration.class, String.class);
Duration durationSince = ParseUtils.parseDuration(durationString);
startTime = Instant.now().minus(durationSince);
} else {
startTime = Instant.EPOCH;
}
String emote = slashCommandParameterService.getCommandOption(EMOTE_STAT_TRACKED_EMOTE, event, String.class);
Emoji emoji = slashCommandParameterService.loadEmoteFromString(emote, event.getGuild());
if(emoji instanceof CustomEmoji) {
Long emoteId = ((CustomEmoji) emoji).getIdLong();
return showResponse(event, emoteId, startTime, typeEnum);
} else if(StringUtils.isNumeric(emote)) {
return showResponse(event, Long.parseLong(emote), startTime, typeEnum);
} else {
throw new TrackedEmoteNotFoundException();
}
}
private CompletableFuture<CommandResult> showResponse(SlashCommandInteractionEvent event, Long emoteId, Instant startTime,
UsedEmoteTypeParameter typeEnum)
{
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(new ServerSpecificId(event.getGuild().getIdLong(), emoteId));
EmoteStatsResultDisplay emoteStatsModel = usedEmoteService.getEmoteStatForEmote(trackedEmote,
startTime, UsedEmoteTypeParameter.convertToUsedEmoteType(typeEnum));
if(emoteStatsModel.getResult().getAmount() == null) {
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
}
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STAT_RESPONSE, emoteStatsModel, commandContext.getChannel()))
return interactionService.replyEmbed(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), event)
.thenApply(unused -> CommandResult.fromIgnored());
}
return interactionService.replyEmbed(EMOTE_STAT_RESPONSE, emoteStatsModel, event)
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
@@ -68,26 +109,57 @@ public class EmoteStat extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter trackedEmoteParameter = Parameter
.builder()
.name("trackedEmote")
.name(EMOTE_STAT_TRACKED_EMOTE)
.templated(true)
.type(TrackedEmote.class)
.build();
parameters.add(trackedEmoteParameter);
Parameter periodParameter = Parameter
.builder()
.name("period")
.name(EMOTE_STAT_DURATION)
.templated(true)
.optional(true)
.type(Duration.class)
.build();
parameters.add(periodParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
List<String> emoteTypes = Arrays
.stream(UsedEmoteTypeParameter.values())
.map(Enum::name)
.collect(Collectors.toList());
Parameter typeParameter = Parameter
.builder()
.name(EMOTE_STAT_USED_EMOTE_TYPE)
.templated(true)
.slashCommandOnly(true)
.optional(true)
.choices(emoteTypes)
.type(String.class)
.build();
parameters.add(typeParameter);
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC)
.groupName("emotestats")
.commandName("singular")
.build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("emoteStat")
.name(EMOTE_STAT_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true)
.messageCommandOnly(true)
.slashCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -4,19 +4,26 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.PaginatorService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.command.parameter.UsedEmoteTypeParameter;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emote.service.UsedEmoteService;
import java.util.Arrays;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -38,46 +45,64 @@ public class EmoteStats extends AbstractConditionableCommand {
private UsedEmoteService usedEmoteService;
@Autowired
private ChannelService channelService;
private PaginatorService paginatorService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
public static final String EMOTE_STATS_STATIC_RESPONSE = "emoteStats_static_response";
public static final String EMOTE_STATS_ANIMATED_RESPONSE = "emoteStats_animated_response";
public static final String EMOTE_STATS_NO_STATS_AVAILABLE = "emoteStats_no_stats_available";
private static final String EMOTE_STATS_USED_EMOTE_TYPE = "type";
private static final String EMOTE_STATS_DURATION = "period";
private static final String EMOTE_STATS_COMMAND_NAME = "emoteStats";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
// default is 1.1.1970
Instant statsSince = Instant.EPOCH;
if(!parameters.isEmpty()) {
// subtract the given Duration from the current point in time, if there is any
Duration duration = (Duration) parameters.get(0);
statsSince = Instant.now().minus(duration);
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
UsedEmoteTypeParameter typeEnum;
if(slashCommandParameterService.hasCommandOption(EMOTE_STATS_USED_EMOTE_TYPE, event)) {
String type = slashCommandParameterService.getCommandOption(EMOTE_STATS_USED_EMOTE_TYPE, event, String.class);
typeEnum = UsedEmoteTypeParameter.valueOf(type);
} else {
typeEnum = null;
}
AServer server = serverManagementService.loadServer(commandContext.getGuild());
EmoteStatsModel emoteStatsModel = usedEmoteService.getActiveEmoteStatsForServerSince(server, statsSince);
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
// only show embed if static emote stats are available
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
log.debug("Emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_RESPONSE, emoteStatsModel, commandContext.getChannel()));
Instant startTime;
if(slashCommandParameterService.hasCommandOption(EMOTE_STATS_DURATION, event)) {
String durationString = slashCommandParameterService.getCommandOption(EMOTE_STATS_DURATION, event, Duration.class, String.class);
Duration durationSince = ParseUtils.parseDuration(durationString);
startTime = Instant.now().minus(durationSince);
} else {
startTime = Instant.EPOCH;
}
// only show embed if animated emote stats are available
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
log.debug("Emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_ANIMATED_RESPONSE, emoteStatsModel, commandContext.getChannel()));
}
// show an embed if no emote stats are available indicating so
if(!emoteStatsModel.areStatsAvailable()) {
log.info("No emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
AServer server = serverManagementService.loadServer(event.getGuild());
EmoteStatsModel emoteStatsModel = usedEmoteService.getActiveEmoteStatsForServerSince(server, startTime, UsedEmoteTypeParameter.convertToUsedEmoteType(typeEnum));
List<CompletableFuture<Void>> messagePromises = new ArrayList<>();
return event.deferReply().submit().thenCompose(interactionHook -> {
// only show embed if static emote stats are available
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
log.debug("Emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), startTime);
messagePromises.add(paginatorService.sendPaginatorToInteraction(EMOTE_STATS_STATIC_RESPONSE, emoteStatsModel, interactionHook));
}
// only show embed if animated emote stats are available
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
log.debug("Emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), startTime);
messagePromises.add(paginatorService.sendPaginatorToInteraction(EMOTE_STATS_ANIMATED_RESPONSE, emoteStatsModel, interactionHook));
}
// show an embed if no emote stats are available indicating so
if(!emoteStatsModel.areStatsAvailable()) {
log.info("No emote stats available for guild {} since {}.", event.getGuild().getIdLong(), startTime);
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), interactionHook))
.thenApply(unused -> CommandResult.fromSuccess());
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
});
}
@Override
@@ -85,19 +110,46 @@ public class EmoteStats extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter periodParameter = Parameter
.builder()
.name("period")
.name(EMOTE_STATS_DURATION)
.templated(true)
.optional(true)
.type(Duration.class)
.build();
parameters.add(periodParameter);
List<String> emoteTypes = Arrays
.stream(UsedEmoteTypeParameter.values())
.map(Enum::name)
.collect(Collectors.toList());
Parameter typeParameter = Parameter
.builder()
.name(EMOTE_STATS_USED_EMOTE_TYPE)
.templated(true)
.slashCommandOnly(true)
.optional(true)
.choices(emoteTypes)
.type(String.class)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC)
.groupName("emotestats")
.commandName("current")
.build();
parameters.add(typeParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("emoteStats")
.name(EMOTE_STATS_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.messageCommandOnly(true)
.async(true)
.slashCommandConfig(slashCommandConfig)
.slashCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
@@ -109,4 +161,6 @@ public class EmoteStats extends AbstractConditionableCommand {
public FeatureDefinition getFeature() {
return StatisticFeatureDefinition.EMOTE_TRACKING;
}
}

View File

@@ -42,8 +42,6 @@ import java.util.concurrent.CompletableFuture;
@Slf4j
public class ExportEmoteStats extends AbstractConditionableCommand {
public static final String DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_no_stats_available_response";
public static final String DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_response";
@Autowired
private ServerManagementService serverManagementService;
@@ -59,6 +57,11 @@ public class ExportEmoteStats extends AbstractConditionableCommand {
@Autowired
private FileService fileService;
public static final String DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_no_stats_available_response";
private static final String DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_response";
private static final String EXPORT_EMOTE_STATS_COMMAND_NAME = "exportEmoteStats";
private static final String EXPORT_EMOTE_STATS_PERIOD = "period";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
@@ -99,7 +102,7 @@ public class ExportEmoteStats extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter periodParameter = Parameter
.builder()
.name("period")
.name(EXPORT_EMOTE_STATS_PERIOD)
.templated(true)
.optional(true)
.type(Duration.class)
@@ -110,7 +113,7 @@ public class ExportEmoteStats extends AbstractConditionableCommand {
.templated(true)
.build();
return CommandConfiguration.builder()
.name("exportEmoteStats")
.name(EXPORT_EMOTE_STATS_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.async(true)

View File

@@ -4,21 +4,27 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.PaginatorService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.command.parameter.UsedEmoteTypeParameter;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emote.service.UsedEmoteService;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -41,48 +47,68 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
private UsedEmoteService usedEmoteService;
@Autowired
private ChannelService channelService;
private ServerManagementService serverManagementService;
@Autowired
private ServerManagementService serverManagementService;
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Autowired
private PaginatorService paginatorService;
public static final String EMOTE_STATS_STATIC_EXTERNAL_RESPONSE = "externalEmoteStats_static_response";
public static final String EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE = "externalEmoteStats_animated_response";
private static final String EXTERNAL_EMOTE_STATS_USED_EMOTE_TYPE = "type";
private static final String EXTERNAL_EMOTE_STATS_PERIOD = "period";
private static final String EXTERNAL_EMOTE_STATS_COMMAND_NAME = "externalEmoteStats";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
// default is 1.1.1970
Instant statsSince = Instant.EPOCH;
if(!parameters.isEmpty()) {
// subtract the given Duration parameter from the current point in time
Duration duration = (Duration) parameters.get(0);
statsSince = Instant.now().minus(duration);
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
UsedEmoteTypeParameter typeEnum;
if(slashCommandParameterService.hasCommandOption(EXTERNAL_EMOTE_STATS_USED_EMOTE_TYPE, event)) {
String type = slashCommandParameterService.getCommandOption(EXTERNAL_EMOTE_STATS_USED_EMOTE_TYPE, event, String.class);
typeEnum = UsedEmoteTypeParameter.valueOf(type);
} else {
typeEnum = null;
}
AServer server = serverManagementService.loadServer(commandContext.getGuild());
EmoteStatsModel emoteStatsModel = usedEmoteService.getExternalEmoteStatsForServerSince(server, statsSince);
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
// only show embed if static emote stats are available
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
log.debug("External emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, emoteStatsModel, commandContext.getChannel()));
Instant startTime;
if(slashCommandParameterService.hasCommandOption(EXTERNAL_EMOTE_STATS_PERIOD, event)) {
String durationString = slashCommandParameterService.getCommandOption(EXTERNAL_EMOTE_STATS_PERIOD, event, Duration.class, String.class);
Duration durationSince = ParseUtils.parseDuration(durationString);
startTime = Instant.now().minus(durationSince);
} else {
startTime = Instant.EPOCH;
}
// only show embed if animated emote stats are available
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
log.debug("External emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE, emoteStatsModel, commandContext.getChannel()));
}
AServer server = serverManagementService.loadServer(event.getGuild());
EmoteStatsModel emoteStatsModel = usedEmoteService.getExternalEmoteStatsForServerSince(server, startTime, UsedEmoteTypeParameter.convertToUsedEmoteType(typeEnum));
List<CompletableFuture<Void>> messagePromises = new ArrayList<>();
return event.deferReply().submit().thenCompose(interactionHook -> {
// only show embed if static emote stats are available
if (!emoteStatsModel.getStaticEmotes().isEmpty()) {
log.debug("External emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), startTime);
messagePromises.add(paginatorService.sendPaginatorToInteraction(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, emoteStatsModel, interactionHook));
}
// show an embed if no emote stats are available indicating so
if(!emoteStatsModel.areStatsAvailable()) {
log.info("No external emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince);
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
}
// only show embed if animated emote stats are available
if (!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
log.debug("External emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), startTime);
messagePromises.add(paginatorService.sendPaginatorToInteraction(EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE, emoteStatsModel, interactionHook));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
// show an embed if no emote stats are available indicating so
if (!emoteStatsModel.areStatsAvailable()) {
log.info("No external emote stats available for guild {} since {}.", event.getGuild().getIdLong(), startTime);
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), interactionHook))
.thenApply(unused -> CommandResult.fromSuccess());
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
});
}
@Override
@@ -90,22 +116,51 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter periodParameter = Parameter
.builder()
.name("period")
.name(EXTERNAL_EMOTE_STATS_PERIOD)
.templated(true)
.optional(true)
.type(Duration.class)
.build();
parameters.add(periodParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
List<String> emoteTypes = Arrays
.stream(UsedEmoteTypeParameter.values())
.map(Enum::name)
.collect(Collectors.toList());
Parameter typeParameter = Parameter
.builder()
.name(EXTERNAL_EMOTE_STATS_USED_EMOTE_TYPE)
.templated(true)
.slashCommandOnly(true)
.optional(true)
.choices(emoteTypes)
.type(String.class)
.build();
parameters.add(typeParameter);
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC)
.groupName("emotestats")
.commandName("external")
.build();
return CommandConfiguration.builder()
.name("externalEmoteStats")
.name(EXTERNAL_EMOTE_STATS_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.messageCommandOnly(true)
.async(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -4,14 +4,25 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandService;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.service.UsedEmoteService;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import java.util.concurrent.CompletableFuture;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -33,20 +44,43 @@ public class PurgeEmoteStats extends AbstractConditionableCommand {
@Autowired
private UsedEmoteService usedEmoteService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private SlashCommandService slashCommandService;
private static final String PURGE_EMOTE_STATS_COMMAND_NAME = "purgeEmoteStats";
private static final String PURGE_EMOTE_STATS_TRACKED_EMOTE = "trackedEmote";
private static final String PURGE_EMOTE_STATS_PERIOD = "period";
private static final String PURGE_EMOTE_STATS_RESPONSE = "purgeEmoteStats_response";
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String emote = slashCommandParameterService.getCommandOption(PURGE_EMOTE_STATS_TRACKED_EMOTE, event, String.class);
Emoji emoji = slashCommandParameterService.loadEmoteFromString(emote, event.getGuild());
if(emoji instanceof CustomEmoji) {
Long emoteId = ((CustomEmoji) emoji).getIdLong();
return createResponse(event, emoteId);
} else if(StringUtils.isNumeric(emote)) {
return createResponse(event, Long.parseLong(emote));
} else {
throw new TrackedEmoteNotFoundException();
}
}
private CompletableFuture<CommandResult> createResponse(SlashCommandInteractionEvent event, Long emoteId) {
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(new ServerSpecificId(event.getGuild().getIdLong(), emoteId));
// default 1.1.1970
Instant since = Instant.EPOCH;
if(parameters.size() > 1) {
if(slashCommandParameterService.hasCommandOption(PURGE_EMOTE_STATS_PERIOD, event)) {
// if a Duration is given, subtract it from the current point in time
Duration parameter = (Duration) parameters.get(1);
since = Instant.now().minus(parameter);
String durationString = slashCommandParameterService.getCommandOption(PURGE_EMOTE_STATS_PERIOD, event, Duration.class, String.class);
Duration duration = ParseUtils.parseDuration(durationString);
since = Instant.now().minus(duration);
}
usedEmoteService.purgeEmoteUsagesSince(trackedEmote, since);
return CommandResult.fromSuccess();
return slashCommandService.completeConfirmableCommand(event, PURGE_EMOTE_STATS_RESPONSE);
}
@Override
@@ -54,25 +88,39 @@ public class PurgeEmoteStats extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter trackedEmoteParameter = Parameter
.builder()
.name("trackedEmote")
.name(PURGE_EMOTE_STATS_TRACKED_EMOTE)
.templated(true)
.type(TrackedEmote.class)
.build();
parameters.add(trackedEmoteParameter);
Parameter periodParameter = Parameter
.builder()
.name("period")
.name(PURGE_EMOTE_STATS_PERIOD)
.templated(true)
.optional(true)
.type(Duration.class)
.build();
parameters.add(periodParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC_INTERNAL)
.groupName("manage")
.commandName("purgeemotestats")
.build();
return CommandConfiguration.builder()
.name("purgeEmoteStats")
.name(PURGE_EMOTE_STATS_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.messageCommandOnly(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true)
.requiresConfirmation(true)
.causesReaction(true)

View File

@@ -4,12 +4,16 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandService;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import java.util.concurrent.CompletableFuture;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -26,21 +30,42 @@ public class ResetEmoteStats extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private SlashCommandService slashCommandService;
private static final String RESET_EMOTE_STATS_COMMAND_NAME = "resetEmoteStats";
private static final String RESET_EMOTE_STATS_RESPONSE = "resetEmoteStats_response";
@Override
public CommandResult execute(CommandContext commandContext) {
trackedEmoteService.resetEmoteStats(commandContext.getGuild());
return CommandResult.fromSuccess();
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
trackedEmoteService.resetEmoteStats(event.getGuild());
return slashCommandService.completeConfirmableCommand(event, RESET_EMOTE_STATS_RESPONSE);
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC_INTERNAL)
.groupName("manage")
.commandName("resetemotestats")
.build();
return CommandConfiguration.builder()
.name("resetEmoteStats")
.name(RESET_EMOTE_STATS_COMMAND_NAME)
.messageCommandOnly(true)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true)
.requiresConfirmation(true)
.causesReaction(true)

View File

@@ -5,17 +5,25 @@ 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.exception.AbstractoTemplatedException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -31,25 +39,43 @@ import java.util.concurrent.CompletableFuture;
@Component
public class ShowExternalTrackedEmote extends AbstractConditionableCommand {
public static final String SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY = "showExternalTrackedEmote_response";
@Autowired
private ChannelService channelService;
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
public static final String SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY = "showExternalTrackedEmote_response";
private static final String SHOW_EXTERNAL_TRACKED_EMOTE_COMMAND_NAME = "showExternalTrackedEmote";
private static final String SHOW_EXTERNAL_TRACKED_EMOTE_TRACKED_EMOTE = "trackedEmote";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
// load the actual TrackedEmote instance
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
// the command only works for external emotes
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String emote = slashCommandParameterService.getCommandOption(SHOW_EXTERNAL_TRACKED_EMOTE_TRACKED_EMOTE, event, String.class);
Emoji emoji = slashCommandParameterService.loadEmoteFromString(emote, event.getGuild());
if(emoji instanceof CustomEmoji) {
Long emoteId = ((CustomEmoji) emoji).getIdLong();
return createResponse(event, emoteId);
} else if(StringUtils.isNumeric(emote)) {
return createResponse(event, Long.parseLong(emote));
} else {
throw new TrackedEmoteNotFoundException();
}
}
private CompletableFuture<CommandResult> createResponse(SlashCommandInteractionEvent event, Long emoteId) {
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(new ServerSpecificId(event.getGuild().getIdLong(), emoteId));
if(!trackedEmote.getExternal()) {
throw new AbstractoTemplatedException("Emote is not external", "showExternalTrackedEmote_emote_is_not_external");
}
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY, trackedEmote, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
return interactionService.replyEmbed(SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY, trackedEmote, event)
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
@@ -57,18 +83,32 @@ public class ShowExternalTrackedEmote extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter trackedEmoteParameter = Parameter
.builder()
.name("trackedEmote")
.name(SHOW_EXTERNAL_TRACKED_EMOTE_TRACKED_EMOTE)
.templated(true)
.type(TrackedEmote.class)
.build();
parameters.add(trackedEmoteParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC)
.groupName("show")
.commandName("externaltrackedemote")
.build();
return CommandConfiguration.builder()
.name("showExternalTrackedEmote")
.name(SHOW_EXTERNAL_TRACKED_EMOTE_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.async(true)
.messageCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.slashCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -4,18 +4,21 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.model.TrackedEmoteOverview;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -35,10 +38,13 @@ public class ShowTrackedEmotes extends AbstractConditionableCommand {
private TrackedEmoteService trackedEmoteService;
@Autowired
private ChannelService channelService;
private FeatureModeService featureModeService;
@Autowired
private FeatureModeService featureModeService;
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
public static final String SHOW_TRACKED_EMOTES_STATIC_RESPONSE = "showTrackedEmotes_static_response";
public static final String SHOW_TRACKED_EMOTES_ANIMATED_RESPONSE = "showTrackedEmotes_animated_response";
@@ -48,86 +54,102 @@ public class ShowTrackedEmotes extends AbstractConditionableCommand {
public static final String SHOW_TRACKED_EMOTES_DELETED_ANIMATED_RESPONSE = "showTrackedEmotes_deleted_animated_response";
public static final String SHOW_TRACKED_EMOTES_NO_STATS_AVAILABLE = "showTrackedEmotes_no_emotes_available";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
private static final String SHOW_TRACKED_EMOTES_COMMAND_NAME = "showTrackedEmotes";
private static final String SHOW_TRACKED_EMOTES_SHOW_ALL = "showAll";
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
// per default, do not show TrackedEmote for which tracking has been disabled
Boolean showTrackingDisabled = false;
if(!commandContext.getParameters().getParameters().isEmpty()) {
showTrackingDisabled = (Boolean) commandContext.getParameters().getParameters().get(0);
if(slashCommandParameterService.hasCommandOption(SHOW_TRACKED_EMOTES_SHOW_ALL, event)) {
showTrackingDisabled = slashCommandParameterService.getCommandOption(SHOW_TRACKED_EMOTES_SHOW_ALL, event, Boolean.class);
}
TrackedEmoteOverview trackedEmoteOverview = trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), showTrackingDisabled);
boolean noTrackedEmotesAvailable = true;
TrackedEmoteOverview trackedEmoteOverview = trackedEmoteService.loadTrackedEmoteOverview(event.getGuild(), showTrackingDisabled);
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
// only show the embed, if there are static tracked emotes
if(!trackedEmoteOverview.getStaticEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(SHOW_TRACKED_EMOTES_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
// only show the embed if there are animated tracked emotes
if(!trackedEmoteOverview.getAnimatedEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(SHOW_TRACKED_EMOTES_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
// only show the embed, if there are deleted static emotes
if(!trackedEmoteOverview.getDeletedStaticEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(SHOW_TRACKED_EMOTES_DELETED_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
// only show the embed, if there are deleted animated emotes
if(!trackedEmoteOverview.getDeletedAnimatedEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(SHOW_TRACKED_EMOTES_DELETED_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, commandContext.getGuild().getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
// only show external emotes if external emotes are enabled
if(externalTrackingEnabled) {
// only show the embed if there are external static emotes
if(!trackedEmoteOverview.getExternalStaticEmotes().isEmpty()) {
return event.deferReply().submit().thenCompose(interactionHook -> {
boolean noTrackedEmotesAvailable = true;
// only show the embed, if there are static tracked emotes
if(!trackedEmoteOverview.getStaticEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(SHOW_TRACKED_EMOTES_EXTERNAL_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_STATIC_RESPONSE, trackedEmoteOverview, interactionHook));
}
// only show the embed if there are external animated emotes
if(!trackedEmoteOverview.getExternalAnimatedEmotes().isEmpty()) {
// only show the embed if there are animated tracked emotes
if(!trackedEmoteOverview.getAnimatedEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(SHOW_TRACKED_EMOTES_EXTERNAL_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_ANIMATED_RESPONSE, trackedEmoteOverview, interactionHook));
}
}
// if there are no tracked emotes available, show an embed indicating so
if(noTrackedEmotesAvailable) {
messagePromises.addAll(channelService.sendEmbedTemplateInMessageChannel(SHOW_TRACKED_EMOTES_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
// only show the embed, if there are deleted static emotes
if(!trackedEmoteOverview.getDeletedStaticEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_DELETED_STATIC_RESPONSE, trackedEmoteOverview, interactionHook));
}
// only show the embed, if there are deleted animated emotes
if(!trackedEmoteOverview.getDeletedAnimatedEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_DELETED_ANIMATED_RESPONSE, trackedEmoteOverview, interactionHook));
}
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, event.getGuild().getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
// only show external emotes if external emotes are enabled
if(externalTrackingEnabled) {
// only show the embed if there are external static emotes
if(!trackedEmoteOverview.getExternalStaticEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_EXTERNAL_STATIC_RESPONSE, trackedEmoteOverview, interactionHook));
}
// only show the embed if there are external animated emotes
if(!trackedEmoteOverview.getExternalAnimatedEmotes().isEmpty()) {
noTrackedEmotesAvailable = false;
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_EXTERNAL_ANIMATED_RESPONSE, trackedEmoteOverview, interactionHook));
}
}
// if there are no tracked emotes available, show an embed indicating so
if(noTrackedEmotesAvailable) {
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_NO_STATS_AVAILABLE, new Object(), interactionHook));
}
return FutureUtils.toSingleFutureGeneric(messagePromises);
}).thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
Parameter showAllParameter = Parameter
.builder()
.name("showAll")
.name(SHOW_TRACKED_EMOTES_SHOW_ALL)
.templated(true)
.optional(true)
.type(Boolean.class)
.build();
parameters.add(showAllParameter);
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC)
.groupName("show")
.commandName("trackedemotes")
.build();
return CommandConfiguration.builder()
.name("showTrackedEmotes")
.name(SHOW_TRACKED_EMOTES_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.async(true)
.messageCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.slashCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -4,15 +4,16 @@ 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.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.model.TrackedEmoteSynchronizationResult;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -28,19 +29,21 @@ import java.util.concurrent.CompletableFuture;
@Component
public class SyncTrackedEmotes extends AbstractConditionableCommand {
public static final String SYNC_TRACKED_EMOTES_RESULT_RESPONSE = "syncTrackedEmotes_result_response";
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private ChannelService channelService;
private InteractionService interactionService;
static final String SYNC_TRACKED_EMOTES_RESULT_RESPONSE = "syncTrackedEmotes_result_response";
private static final String SYNC_TRACKED_EMOTES_COMMAND_NAME = "syncTrackedEmotes";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
TrackedEmoteSynchronizationResult syncResult = trackedEmoteService.synchronizeTrackedEmotes(commandContext.getGuild());
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
TrackedEmoteSynchronizationResult syncResult = trackedEmoteService.synchronizeTrackedEmotes(event.getGuild());
// show a result of how many emotes were deleted/added
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, syncResult, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
return interactionService.replyEmbed(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, syncResult, event)
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
@@ -50,11 +53,21 @@ public class SyncTrackedEmotes extends AbstractConditionableCommand {
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC_INTERNAL)
.groupName("manage")
.commandName("synctrackedemotes")
.build();
return CommandConfiguration.builder()
.name("syncTrackedEmotes")
.name(SYNC_TRACKED_EMOTES_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.messageCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.slashCommandOnly(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)

View File

@@ -4,19 +4,26 @@ 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.exception.IncorrectParameterException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.config.StatisticSlashCommandNames;
import dev.sheldan.abstracto.statistic.emote.command.parameter.TrackEmoteParameter;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingModuleDefinition;
import dev.sheldan.abstracto.statistic.emote.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import java.util.concurrent.CompletableFuture;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -42,28 +49,44 @@ public class TrackEmote extends AbstractConditionableCommand {
@Autowired
private FeatureModeService featureModeService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
private static final String TRACK_EMOTE_COMMAND_NAME = "trackEmote";
private static final String TRACK_EMOTE_EMOTE = "emote";
private static final String TRACK_EMOTE_RESPONSE = "trackEmote_response";
@Override
public CommandResult execute(CommandContext commandContext) {
TrackEmoteParameter emoteToTrack = (TrackEmoteParameter) commandContext.getParameters().getParameters().get(0);
Long emoteId = emoteToTrack.getTrackedEmote().getTrackedEmoteId().getId();
long serverId = commandContext.getGuild().getIdLong();
// if its already a tracked emote, just set the tracking_enabled flag to true
if(trackedEmoteManagementService.trackedEmoteExists(emoteId, serverId)) {
TrackedEmote trackedemote = trackedEmoteManagementService.loadByEmoteId(emoteId, serverId);
trackedEmoteManagementService.enableTrackedEmote(trackedemote);
} else if(emoteToTrack.getEmote() != null) {
// if its a new emote, lets see if its external
boolean external = !emoteService.emoteIsFromGuild(emoteToTrack.getEmote(), commandContext.getGuild());
if(external) {
// this throws an exception if the feature mode is not enabled
featureModeService.validateActiveFeatureMode(serverId, StatisticFeatureDefinition.EMOTE_TRACKING, EmoteTrackingMode.EXTERNAL_EMOTES);
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String emote = slashCommandParameterService.getCommandOption(TRACK_EMOTE_EMOTE, event, String.class);
Emoji emoji = slashCommandParameterService.loadEmoteFromString(emote, event.getGuild());
if(emoji instanceof CustomEmoji customEmoji) {
Long emoteId = customEmoji.getIdLong();
long serverId = event.getGuild().getIdLong();
// if its already a tracked emote, just set the tracking_enabled flag to true
if(trackedEmoteManagementService.trackedEmoteExists(emoteId, serverId)) {
TrackedEmote trackedemote = trackedEmoteManagementService.loadByEmoteId(emoteId, serverId);
trackedEmoteManagementService.enableTrackedEmote(trackedemote);
return interactionService.replyEmbed(TRACK_EMOTE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromIgnored());
} else {
// if its a new emote, lets see if its external
boolean external = !emoteService.emoteIsFromGuild(customEmoji, event.getGuild());
if (external) {
// this throws an exception if the feature mode is not enabled
featureModeService.validateActiveFeatureMode(serverId, StatisticFeatureDefinition.EMOTE_TRACKING, EmoteTrackingMode.EXTERNAL_EMOTES);
}
trackedEmoteService.createTrackedEmote(customEmoji, event.getGuild(), external);
return interactionService.replyEmbed(TRACK_EMOTE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromIgnored());
}
trackedEmoteService.createTrackedEmote(emoteToTrack.getEmote(), commandContext.getGuild(), external);
} else {
// in case the ID was not an existing TrackedEmote, and no Emote was given, we need to fail
throw new IncorrectParameterException(this, getConfiguration().getParameters().get(0).getName());
throw new TrackedEmoteNotFoundException();
}
return CommandResult.fromSuccess();
}
@Override
@@ -71,17 +94,31 @@ public class TrackEmote extends AbstractConditionableCommand {
List<Parameter> parameters = new ArrayList<>();
Parameter emoteParameter = Parameter
.builder()
.name("emote")
.name(TRACK_EMOTE_EMOTE)
.templated(true)
.type(TrackEmoteParameter.class)
.build();
parameters.add(emoteParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StatisticSlashCommandNames.STATISTIC_INTERNAL)
.groupName("manage")
.commandName("trackemote")
.build();
return CommandConfiguration.builder()
.name("trackEmote")
.name(TRACK_EMOTE_COMMAND_NAME)
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
.templated(true)
.messageCommandOnly(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -0,0 +1,18 @@
package dev.sheldan.abstracto.statistic.emote.command.parameter;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
public enum UsedEmoteTypeParameter {
REACTION,
MESSAGE;
public static UsedEmoteType convertToUsedEmoteType(UsedEmoteTypeParameter usedEmoteTypeParameter) {
if(usedEmoteTypeParameter == null) {
return null;
}
return switch (usedEmoteTypeParameter) {
case MESSAGE -> UsedEmoteType.MESSAGE;
case REACTION -> UsedEmoteType.REACTION;
};
}
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.statistic.emote.command.parameter.handler;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandOptionTypeMapping;
import dev.sheldan.abstracto.core.interaction.slash.parameter.provider.SlashCommandParameterProvider;
import dev.sheldan.abstracto.statistic.emote.command.parameter.TrackEmoteParameter;
import java.util.Arrays;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import org.springframework.stereotype.Component;
@Component
public class TrackEmoteParameterSlashCommandParameterProvider implements SlashCommandParameterProvider {
@Override
public SlashCommandOptionTypeMapping getOptionMapping() {
return SlashCommandOptionTypeMapping
.builder()
.type(TrackEmoteParameter.class)
.optionTypes(Arrays.asList(OptionType.STRING))
.build();
}
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.statistic.emote.command.parameter.handler;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandOptionTypeMapping;
import dev.sheldan.abstracto.core.interaction.slash.parameter.provider.SlashCommandParameterProvider;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import java.util.Arrays;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import org.springframework.stereotype.Component;
@Component
public class TrackedEmoteSlashCommandParameterProvider implements SlashCommandParameterProvider {
@Override
public SlashCommandOptionTypeMapping getOptionMapping() {
return SlashCommandOptionTypeMapping
.builder()
.type(TrackedEmote.class)
.optionTypes(Arrays.asList(OptionType.STRING))
.build();
}
}

View File

@@ -0,0 +1,35 @@
package dev.sheldan.abstracto.statistic.emote.job;
import dev.sheldan.abstracto.statistic.emote.service.RunTimeReactionEmotesService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
@Slf4j
@DisallowConcurrentExecution
@Component
@PersistJobDataAfterExecution
public class EmoteCleanupJob extends QuartzJobBean {
@Autowired
private RunTimeReactionEmotesService runtimeReactionEmotesService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("Cleaning up emote runtime storage.");
try {
runtimeReactionEmotesService.cleanupRunTimeStorage();
} catch (Exception e) {
log.error("Failed to cleanup reaction runtimes.", e);
}
}
}

View File

@@ -6,6 +6,7 @@ import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListene
import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel;
import dev.sheldan.abstracto.core.service.GuildService;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
@@ -46,7 +47,7 @@ public class EmoteTrackingListener implements AsyncMessageReceivedListener {
.stream()
.collect(Collectors.groupingBy(CustomEmoji::getIdLong));
collect.values().forEach(groupedEmotes ->
trackedEmoteService.addEmoteToRuntimeStorage(groupedEmotes.get(0), guildService.getGuildById(model.getServerId()), (long) groupedEmotes.size())
trackedEmoteService.addEmoteToRuntimeStorage(groupedEmotes.get(0), guildService.getGuildById(model.getServerId()), (long) groupedEmotes.size(), UsedEmoteType.MESSAGE)
);
return DefaultListenerResult.PROCESSED;
}

View File

@@ -0,0 +1,65 @@
package dev.sheldan.abstracto.statistic.emote.listener;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.models.listener.ReactionAddedModel;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.emote.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.service.RunTimeReactionEmotesService;
import dev.sheldan.abstracto.statistic.emote.service.TrackedEmoteService;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class EmoteTrackingReactionAddedListener implements AsyncReactionAddedListener {
@Autowired
private RunTimeReactionEmotesService runTimeReactionEmotesService;
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private EmoteService emoteService;
@Override
public DefaultListenerResult execute(ReactionAddedModel model) {
if(model.getReaction().getEmoji().getType() != Emoji.Type.CUSTOM) {
return DefaultListenerResult.IGNORED;
}
Long guildId = model.getServerId();
Long messageId = model.getMessage().getMessageId();
Long userId = model.getUserReacting().getUserId();
CustomEmoji customEmoji = model.getReaction().getEmoji().asCustom();
Long emoteId = customEmoji.getIdLong();
if(runTimeReactionEmotesService.emoteAlreadyUsed(guildId, userId, messageId, emoteId)) {
return DefaultListenerResult.IGNORED;
}
log.debug("Counting usage of emote {} in server {}.", emoteId, guildId);
trackedEmoteService.addEmoteToRuntimeStorage(customEmoji, model.getReaction().getGuild(), 1L, UsedEmoteType.REACTION);
runTimeReactionEmotesService.getRuntimeEmotes().put(runTimeReactionEmotesService.getKeyFormat(guildId, userId, messageId, emoteId), Instant.now());
return DefaultListenerResult.PROCESSED;
}
@Override
public List<FeatureMode> getFeatureModeLimitations() {
return Arrays.asList(EmoteTrackingMode.TRACK_REACTIONS);
}
@Override
public FeatureDefinition getFeature() {
return StatisticFeatureDefinition.EMOTE_TRACKING;
}
}

View File

@@ -24,52 +24,119 @@ public interface UsedEmoteRepository extends JpaRepository<UsedEmote, UsedEmoteD
* @param emoteId The ID of the emote which is being tracked
* @param server_id The ID of the {@link net.dv8tion.jda.api.entities.Guild} which is the server where the emote
* is being tracked
* @param usedEmoteType The type of interaction the emote was used in
* @return An {@link Optional} containing a possible {@link UsedEmote}, if it exists for the criteria, an empty Optional otherwise.
*/
@Query(value="select * from used_emote " +
"where emote_id = :emote_id and server_id = :server_id " +
"and use_date = date_trunc('day', now())", nativeQuery = true)
Optional<UsedEmote> findEmoteFromServerToday(@Param("emote_id") Long emoteId, @Param("server_id") Long server_id);
"and use_date = date_trunc('day', now()) " +
" and type = :used_emote_type", nativeQuery = true)
Optional<UsedEmote> findEmoteFromServerToday(@Param("emote_id") Long emoteId, @Param("server_id") Long server_id, @Param("used_emote_type") String usedEmoteType);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id " +
"group by us.emote_id, us.server_id " +
@Query(value = "select te.id as emoteId, te.server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from tracked_emote te " +
"left join used_emote us " +
"on us.emote_id = te.id " +
"and us.server_id = te.server_id " +
"and us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"where te.server_id = :server_id " +
"group by te.id, te.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.external = true " +
"group by us.emote_id, us.server_id " +
@Query(value = "select te.id as emoteId, te.server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from tracked_emote te " +
"left join used_emote us " +
"on us.emote_id = te.id " +
"and us.server_id = te.server_id " +
"and us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"where us.server_id = :server_id " +
"and te.external = true " +
"group by te.id, te.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getExternalEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.deleted = true " +
"group by us.emote_id, us.server_id " +
@Query(value = "select te.id as emoteId, te.server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from tracked_emote te " +
"left join used_emote us " +
"on us.emote_id = te.id " +
"and us.server_id = te.server_id " +
"and us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"and us.type = :used_emote_type " +
"where te.server_id = :server_id " +
"and te.external = true " +
"group by te.id, te.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getExternalEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since, @Param("used_emote_type") String usedEmoteType);
@Query(value = "select te.id as emoteId, te.server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from tracked_emote te " +
"left join used_emote us " +
"on us.emote_id = te.id " +
"and us.server_id = te.server_id " +
"and us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"where te.server_id = :server_id " +
"and te.deleted = true " +
"group by te.id, te.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getDeletedEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.external = false and te.deleted = false " +
"group by us.emote_id, us.server_id " +
@Query(value = "select te.id as emoteId, te.server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from tracked_emote te " +
"left join used_emote us " +
"on us.emote_id = te.id " +
"and us.server_id = te.server_id " +
"and us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"and us.type = :used_emote_type " +
"where te.server_id = :server_id " +
"and te.deleted = true " +
"group by te.id, te.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getDeletedEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since, @Param("used_emote_type") String usedEmoteType);
@Query(value = "select te.id as emoteId, te.server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from tracked_emote te " +
"left join used_emote us " +
"on us.emote_id = te.id " +
"and us.server_id = te.server_id " +
"and us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"where te.server_id = :server_id " +
"and te.external = false " +
"and te.deleted = false " +
"group by te.id, te.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getCurrentlyExistingEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select :tracked_emote_id as emoteId, :server_id as serverId, sum(us.amount) as amount " +
@Query(value = "select te.id as emoteId, te.server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from tracked_emote te " +
"left join used_emote us " +
"on us.emote_id = te.id " +
"and us.server_id = te.server_id " +
"and us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"and us.type = :used_emote_type " +
"where te.server_id = :server_id " +
"and te.external = false " +
"and te.deleted = false " +
"group by te.id, te.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getCurrentlyExistingEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since, @Param("used_emote_type") String usedEmoteType);
@Query(value = "select :tracked_emote_id as emoteId, :server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from used_emote us " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"and us.server_id = :server_id " +
"and us.emote_id = :tracked_emote_id", nativeQuery = true)
EmoteStatsResult getEmoteStatForTrackedEmote(@Param("tracked_emote_id") Long trackedEmoteId, @Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select :tracked_emote_id as emoteId, :server_id as serverId, coalesce(sum(us.amount), 0) as amount " +
"from used_emote us " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
"and us.server_id = :server_id " +
"and us.emote_id = :tracked_emote_id " +
"and us.type = :used_emote_type", nativeQuery = true)
EmoteStatsResult getEmoteStatForTrackedEmote(@Param("tracked_emote_id") Long trackedEmoteId, @Param("server_id") Long serverId,
@Param("start_date") Instant since, @Param("used_emote_type") String usedEmoteType);
void deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(Long emoteId, Long serverId, Instant timestamp);
List<UsedEmote> getByEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(Long emoteId, Instant timestamp);

View File

@@ -0,0 +1,41 @@
package dev.sheldan.abstracto.statistic.emote.service;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Getter
@Slf4j
public class RunTimeReactionEmotesService {
// key pattern "serverId:userId:messageId:emoteId"
private final Map<String, Instant> runtimeEmotes = new ConcurrentHashMap<>();
public void cleanupRunTimeStorage() {
Instant cutoffDate = Instant.now().minus(2, ChronoUnit.DAYS);
Set<String> keysToRemove = new HashSet<>();
runtimeEmotes.forEach((key, instant) -> {
if(instant.isBefore(cutoffDate)) {
keysToRemove.add(key);
}
});
log.info("Cleaning up {} emote usages.", keysToRemove.size());
keysToRemove.forEach(runtimeEmotes::remove);
}
public boolean emoteAlreadyUsed(Long guildId, Long userId, Long messageId, Long emoteId) {
return runtimeEmotes.containsKey(getKeyFormat(guildId, userId, messageId, emoteId));
}
public String getKeyFormat(Long guildId, Long userId, Long messageId, Long emoteId) {
return String.format("%s:%s:%s:%s", guildId, userId, messageId, emoteId);
}
}

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.statistic.emote.service;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.emote.model.PersistingEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
@@ -25,34 +26,30 @@ public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeServic
return trackedEmoteRunTimeStorage.getRuntimeConfig();
}
@Override
public void addEmoteForServer(CachedEmote emote, Guild guild, boolean external) {
addEmoteForServer(emote, guild, 1L, external);
}
@Override
public void addEmoteForServer(CachedEmote emote, Guild guild, Long count, boolean external) {
public void addEmoteForServer(CachedEmote emote, Guild guild, Long count, boolean external, UsedEmoteType usedEmoteType) {
takeLock();
try {
// generate an appropriate key
Long key = getKey();
// create a PersistingEmote based the given Emote
PersistingEmote newPersistentEmote = createFromEmote(guild, emote, count, external);
PersistingEmote newPersistentEmote = createFromEmote(guild, emote, count, external, usedEmoteType);
if (trackedEmoteRunTimeStorage.contains(key)) {
// if it already exists, we can add to the already existing map
Map<Long, List<PersistingEmote>> elementsForKey = trackedEmoteRunTimeStorage.get(key);
if (elementsForKey.containsKey(guild.getIdLong())) {
// if the server already has an entry, we can just add it to the list of existing ones
List<PersistingEmote> persistingEmotes = elementsForKey.get(guild.getIdLong());
Optional<PersistingEmote> existingEmote = persistingEmotes
.stream()
.filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getEmoteId()))
.findFirst();
List<PersistingEmote> existingEmotes = elementsForKey.get(guild.getIdLong());
Optional<PersistingEmote> existingEmote = existingEmotes
.stream()
.filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getEmoteId()) && persistingEmote.getUsedEmoteType().equals(usedEmoteType))
.findFirst();
// if it exists already, just increment the counter by the given amount
existingEmote.ifPresent(persistingEmote -> persistingEmote.setCount(persistingEmote.getCount() + count));
if (!existingEmote.isPresent()) {
// just add the newly created one
persistingEmotes.add(newPersistentEmote);
existingEmotes.add(newPersistentEmote);
}
} else {
// it did not exist for the server, create a new list of PersistingEmote
@@ -77,12 +74,12 @@ public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeServic
}
@Override
public PersistingEmote createFromEmote(Guild guild, CachedEmote emote, boolean external) {
return createFromEmote(guild, emote, 1L, external);
public PersistingEmote createFromEmote(Guild guild, CachedEmote emote, boolean external, UsedEmoteType usedEmoteType) {
return createFromEmote(guild, emote, 1L, external, usedEmoteType);
}
@Override
public PersistingEmote createFromEmote(Guild guild, CachedEmote emote, Long count, boolean external) {
public PersistingEmote createFromEmote(Guild guild, CachedEmote emote, Long count, boolean external, UsedEmoteType usedEmoteType) {
String url = external ? emote.getImageURL() : null;
return PersistingEmote
.builder()
@@ -90,6 +87,7 @@ public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeServic
.emoteId(emote.getEmoteId())
.external(external)
.externalUrl(url)
.usedEmoteType(usedEmoteType)
.emoteName(emote.getEmoteName())
.count(count)
.serverId(guild.getIdLong())

View File

@@ -15,6 +15,7 @@ import dev.sheldan.abstracto.statistic.emote.model.TrackedEmoteOverview;
import dev.sheldan.abstracto.statistic.emote.model.TrackedEmoteSynchronizationResult;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import dev.sheldan.abstracto.statistic.emote.service.management.UsedEmoteManagementService;
import lombok.extern.slf4j.Slf4j;
@@ -68,28 +69,29 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
@Override
public void addEmoteToRuntimeStorage(List<CachedEmote> emotes, Guild guild) {
public void addEmoteToRuntimeStorage(List<CachedEmote> emotes, Guild guild, UsedEmoteType type) {
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
emotes.forEach(emote -> {
// either the emote is from the current guild (we always add those) or external emote tracking is enabled (we should always add those)
if(externalTrackingEnabled || !emote.getExternal()) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, emote.getExternal());
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, 1L, emote.getExternal(), type);
}
});
}
@Override
public void addEmoteToRuntimeStorage(CachedEmote emote, Guild guild, Long count) {
public void addEmoteToRuntimeStorage(CachedEmote emote, Guild guild, Long count, UsedEmoteType type) {
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
// either the emote is from the current guild (we always add those) or external emote tracking is enabled (we should always add those)
if(externalTrackingEnabled || !emote.getExternal()) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, emote.getExternal());
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, emote.getExternal(), type);
}
}
@Override
public void addEmoteToRuntimeStorage(CustomEmoji emote, Guild guild, Long count) {
addEmoteToRuntimeStorage(cacheEntityService.getCachedEmoteFromEmote(emote, guild), guild, count);
public void addEmoteToRuntimeStorage(CustomEmoji emote, Guild guild, Long count, UsedEmoteType type) {
addEmoteToRuntimeStorage(cacheEntityService.getCachedEmoteFromEmote(emote, guild), guild, count, type);
}
@Override
@@ -105,23 +107,23 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
emoteOptional.ifPresent(trackedEmote -> {
// only track the record, if its enabled
if(trackedEmote.getTrackingEnabled()) {
Optional<UsedEmote> existingUsedEmote = usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote);
Optional<UsedEmote> existingUsedEmote = usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote, persistingEmote.getUsedEmoteType());
// if a use for today already exists, increment the amount
existingUsedEmote.ifPresent(usedEmote ->
usedEmote.setAmount(usedEmote.getAmount() + persistingEmote.getCount())
);
// if none exists, create a new
if(!existingUsedEmote.isPresent()) {
usedEmoteManagementService.createEmoteUsageForToday(trackedEmote, persistingEmote.getCount());
if(existingUsedEmote.isEmpty()) {
usedEmoteManagementService.createEmoteUsageForToday(trackedEmote, persistingEmote.getCount(), persistingEmote.getUsedEmoteType());
}
} else {
log.debug("Tracking disabled for emote {} in server {}.", trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId());
}
});
// if tracked emote does not exists, we might want to create one (only for external emotes)
// if tracked emote does not exist, we might want to create one (only for external emotes)
// we only do it for external emotes, because the feature mode AUTO_TRACK would not make sense
// we might want emotes which are completely ignored by emote tracking
if(!emoteOptional.isPresent() && autoTrackExternalEmotes && trackExternalEmotes) {
if(emoteOptional.isEmpty() && autoTrackExternalEmotes && trackExternalEmotes) {
createNewTrackedEmote(serverId, persistingEmote);
}
});
@@ -137,7 +139,7 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
Optional<Guild> guildOptional = guildService.getGuildByIdOptional(serverId);
guildOptional.ifPresent(guild -> {
TrackedEmote newCreatedTrackedEmote = trackedEmoteManagementService.createExternalTrackedEmote(persistingEmote);
usedEmoteManagementService.createEmoteUsageForToday(newCreatedTrackedEmote, persistingEmote.getCount());
usedEmoteManagementService.createEmoteUsageForToday(newCreatedTrackedEmote, persistingEmote.getCount(), persistingEmote.getUsedEmoteType());
});
}

View File

@@ -6,6 +6,7 @@ import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsResult;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsResultDisplay;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.service.management.UsedEmoteManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -32,26 +33,26 @@ public class UsedEmoteServiceBean implements UsedEmoteService {
}
@Override
public EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(server, since);
public EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(server, since, usedEmoteType);
return converter.fromEmoteStatsResults(emoteStatsResults);
}
@Override
public EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadExternalEmoteStatsForServerSince(server, since);
public EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType type) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadExternalEmoteStatsForServerSince(server, since, type);
return converter.fromEmoteStatsResults(emoteStatsResults);
}
@Override
public EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadActiveEmoteStatsForServerSince(server, since);
public EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadActiveEmoteStatsForServerSince(server, since, usedEmoteType);
return converter.fromEmoteStatsResults(emoteStatsResults);
}
@Override
public EmoteStatsResultDisplay getEmoteStatForEmote(TrackedEmote trackedEmote, Instant since) {
EmoteStatsResult emoteStatsResult = usedEmoteManagementService.loadEmoteStatForEmote(trackedEmote, since);
public EmoteStatsResultDisplay getEmoteStatForEmote(TrackedEmote trackedEmote, Instant since, UsedEmoteType usedEmoteType) {
EmoteStatsResult emoteStatsResult = usedEmoteManagementService.loadEmoteStatForEmote(trackedEmote, since, usedEmoteType);
return converter.convertEmoteStatsResultToDisplay(emoteStatsResult);
}

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsResult;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.model.database.embed.UsedEmoteDay;
import dev.sheldan.abstracto.statistic.emote.repository.UsedEmoteRepository;
import lombok.extern.slf4j.Slf4j;
@@ -22,20 +23,20 @@ public class UsedEmoteManagementServiceBean implements UsedEmoteManagementServic
private UsedEmoteRepository usedEmoteRepository;
@Override
public Optional<UsedEmote> loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote) {
return usedEmoteRepository.findEmoteFromServerToday(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId());
public Optional<UsedEmote> loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote, UsedEmoteType usedEmoteType) {
return usedEmoteRepository.findEmoteFromServerToday(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), usedEmoteType.name());
}
@Override
public UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count) {
return createEmoteUsageFor(trackedEmote, count, Instant.now());
public UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count, UsedEmoteType type) {
return createEmoteUsageFor(trackedEmote, count, Instant.now(), type);
}
@Override
public UsedEmote createEmoteUsageFor(TrackedEmote trackedEmote, Long count, Instant instant) {
public UsedEmote createEmoteUsageFor(TrackedEmote trackedEmote, Long count, Instant instant, UsedEmoteType type) {
UsedEmote usedEmote = UsedEmote
.builder()
.emoteId(new UsedEmoteDay(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), instant))
.emoteId(new UsedEmoteDay(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), instant, type))
.amount(count)
.build();
log.debug("Creating emote usage for emote {} in server {} with count {}.", trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), count);
@@ -53,23 +54,39 @@ public class UsedEmoteManagementServiceBean implements UsedEmoteManagementServic
}
@Override
public List<EmoteStatsResult> loadDeletedEmoteStatsForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getDeletedEmoteStatsForServerSince(server.getId(), since);
public List<EmoteStatsResult> loadDeletedEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType) {
if (usedEmoteType == null) {
return usedEmoteRepository.getDeletedEmoteStatsForServerSince(server.getId(), since);
} else {
return usedEmoteRepository.getDeletedEmoteStatsForServerSince(server.getId(), since, usedEmoteType.name());
}
}
@Override
public List<EmoteStatsResult> loadExternalEmoteStatsForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getExternalEmoteStatsForServerSince(server.getId(), since);
public List<EmoteStatsResult> loadExternalEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType type) {
if (type == null) {
return usedEmoteRepository.getExternalEmoteStatsForServerSince(server.getId(), since);
} else {
return usedEmoteRepository.getExternalEmoteStatsForServerSince(server.getId(), since, type.name());
}
}
@Override
public List<EmoteStatsResult> loadActiveEmoteStatsForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(server.getId(), since);
public List<EmoteStatsResult> loadActiveEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType) {
if(usedEmoteType == null) {
return usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(server.getId(), since);
} else {
return usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(server.getId(), since, usedEmoteType.name());
}
}
@Override
public EmoteStatsResult loadEmoteStatForEmote(TrackedEmote trackedEmote, Instant since) {
return usedEmoteRepository.getEmoteStatForTrackedEmote(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), since);
public EmoteStatsResult loadEmoteStatForEmote(TrackedEmote trackedEmote, Instant since, UsedEmoteType usedEmoteType) {
if(usedEmoteType == null) {
return usedEmoteRepository.getEmoteStatForTrackedEmote(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), since);
} else {
return usedEmoteRepository.getEmoteStatForTrackedEmote(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), since, usedEmoteType.name());
}
}
@Override

View File

@@ -0,0 +1,7 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="emote_statistic_cleanup_job.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,15 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<changeSet author="Sheldan" id="emote-statistic-cleanup-job-insert">
<insert tableName="scheduler_job">
<column name="name" value="emoteStatisticCleanupJob"/>
<column name="group_name" value="statistic"/>
<column name="clazz" value="dev.sheldan.abstracto.statistic.emote.job.EmoteCleanupJob"/>
<column name="active" value="true"/>
<column name="cron_expression" value="0 0 0 * * ?"/>
<column name="recovery" value="false"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="used_emote.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<changeSet author="Sheldan" id="used_emote-add_usage_type">
<addColumn tableName="used_emote">
<column name="type" type="VARCHAR(255)" defaultValue="MESSAGE">
<constraints nullable="false"/>
</column>
</addColumn>
<dropIndex indexName="idx_used_emote" tableName="used_emote"/>
<dropPrimaryKey constraintName="pk_used_emote" dropIndex="true" tableName="used_emote"/>
<addPrimaryKey columnNames="server_id, emote_id, use_date, type" tableName="used_emote" constraintName="pk_used_emote" validate="true"/>
</changeSet>
</databaseChangeLog>

View File

@@ -4,4 +4,5 @@
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="1.0-statistic/collection.xml" relativeToChangelogFile="true"/>
<include file="1.3.10/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.58/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -12,4 +12,8 @@ abstracto.featureModes.externalEmotes.enabled=false
abstracto.featureModes.autoTrackExternal.featureName=emoteTracking
abstracto.featureModes.autoTrackExternal.mode=autoTrackExternal
abstracto.featureModes.autoTrackExternal.enabled=false
abstracto.featureModes.autoTrackExternal.enabled=false
abstracto.featureModes.trackReactions.featureName=emoteTracking
abstracto.featureModes.trackReactions.mode=trackReactions
abstracto.featureModes.trackReactions.enabled=false

View File

@@ -25,6 +25,7 @@ import java.util.Arrays;
import static dev.sheldan.abstracto.statistic.emote.command.DeletedEmoteStats.EMOTE_STATS_ANIMATED_DELETED_RESPONSE;
import static dev.sheldan.abstracto.statistic.emote.command.DeletedEmoteStats.EMOTE_STATS_STATIC_DELETED_RESPONSE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.endsWith;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@@ -54,7 +55,7 @@ public class DeletedEmoteStatsTest {
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -67,7 +68,7 @@ public class DeletedEmoteStatsTest {
when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_ANIMATED_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -78,7 +79,7 @@ public class DeletedEmoteStatsTest {
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
when(model.areStatsAvailable()).thenReturn(false);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -91,7 +92,7 @@ public class DeletedEmoteStatsTest {
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(model);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(eq(server), any(Instant.class), eq(null))).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}

View File

@@ -9,6 +9,7 @@ import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatureDefinition;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsResultDisplay;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.service.UsedEmoteService;
import org.junit.Assert;
import org.junit.Test;
@@ -54,7 +55,7 @@ public class EmoteStatsTest {
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getActiveEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getActiveEmoteStatsForServerSince(server, Instant.EPOCH, UsedEmoteType.REACTION)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -67,7 +68,7 @@ public class EmoteStatsTest {
when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getActiveEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getActiveEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_ANIMATED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -78,7 +79,7 @@ public class EmoteStatsTest {
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
when(model.areStatsAvailable()).thenReturn(false);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getActiveEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getActiveEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -91,7 +92,7 @@ public class EmoteStatsTest {
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getActiveEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(model);
when(usedEmoteService.getActiveEmoteStatsForServerSince(eq(server), any(Instant.class), eq(null))).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}

View File

@@ -54,7 +54,7 @@ public class ExternalEmoteStatsTest {
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getExternalEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getExternalEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -67,7 +67,7 @@ public class ExternalEmoteStatsTest {
when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getExternalEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getExternalEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -78,7 +78,7 @@ public class ExternalEmoteStatsTest {
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
when(model.areStatsAvailable()).thenReturn(false);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getExternalEmoteStatsForServerSince(server, Instant.EPOCH)).thenReturn(model);
when(usedEmoteService.getExternalEmoteStatsForServerSince(server, Instant.EPOCH, null)).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@@ -91,7 +91,7 @@ public class ExternalEmoteStatsTest {
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(serverManagementService.loadServer(noParameters.getGuild())).thenReturn(server);
when(usedEmoteService.getExternalEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(model);
when(usedEmoteService.getExternalEmoteStatsForServerSince(eq(server), any(Instant.class), eq(null))).thenReturn(model);
when(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.statistic.emote.service;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.emote.model.PersistingEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert;
import org.junit.Test;
@@ -47,7 +48,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test
public void testCreateFromEmoteFromGuild() {
when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, false);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, false, UsedEmoteType.MESSAGE);
Assert.assertFalse(createdEmote.getExternal());
Assert.assertNull(createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
@@ -58,7 +59,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
public void testCreateFromEmoteExternal() {
when(emote.getImageURL()).thenReturn(URL);
when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, true);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, true, UsedEmoteType.MESSAGE);
Assert.assertTrue(createdEmote.getExternal());
Assert.assertEquals(URL, createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
@@ -68,7 +69,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test
public void testCreateFromEmoteOneCountFromGuild() {
when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, false);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, false, UsedEmoteType.MESSAGE);
Assert.assertFalse(createdEmote.getExternal());
Assert.assertNull(createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
@@ -79,7 +80,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
public void testCreateFromEmoteOneCountExternal() {
when(emote.getImageURL()).thenReturn(URL);
when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, true);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, true, UsedEmoteType.MESSAGE);
Assert.assertTrue(createdEmote.getExternal());
Assert.assertEquals(URL, createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
@@ -92,7 +93,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
when(emote.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(false);
testUnit.addEmoteForServer(emote, guild, false);
testUnit.addEmoteForServer(emote, guild, 1L, false, UsedEmoteType.REACTION);
verify(trackedEmoteRunTimeStorage, times(1)).put(eq(SECOND), putCaptor.capture());
HashMap<Long, List<PersistingEmote>> value = putCaptor.getValue();
Assert.assertEquals(1, value.keySet().size());
@@ -110,7 +111,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, false);
testUnit.addEmoteForServer(emote, guild, 1L, false, UsedEmoteType.REACTION);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> createdEmotes = serverMap.values().iterator().next();
@@ -127,7 +128,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote)));
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, false);
testUnit.addEmoteForServer(emote, guild, 1L,false, UsedEmoteType.REACTION);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> persistingEmotes = serverMap.values().iterator().next();
@@ -147,7 +148,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
when(persistingEmote.getCount()).thenReturn(COUNT);
serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote)));
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, false);
testUnit.addEmoteForServer(emote, guild, 1L, false, UsedEmoteType.REACTION);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> persistingEmotes = serverMap.values().iterator().next();
@@ -168,7 +169,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
when(persistingEmote.getCount()).thenReturn(COUNT);
serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote)));
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, COUNT, false);
testUnit.addEmoteForServer(emote, guild, COUNT, false, UsedEmoteType.REACTION);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> persistingEmotes = serverMap.values().iterator().next();

View File

@@ -13,6 +13,7 @@ import dev.sheldan.abstracto.statistic.emote.model.TrackedEmoteOverview;
import dev.sheldan.abstracto.statistic.emote.model.TrackedEmoteSynchronizationResult;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.service.management.TrackedEmoteManagementService;
import dev.sheldan.abstracto.statistic.emote.service.management.UsedEmoteManagementService;
import net.dv8tion.jda.api.entities.Guild;
@@ -109,40 +110,40 @@ public class TrackedEmoteServiceBeanTest {
public void addSingleServerEmote() {
externalEmotesEnabled(true);
isEmoteExternal(false);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT,false);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT, false, UsedEmoteType.REACTION);
}
@Test
public void addSingleExternalEmote() {
externalEmotesEnabled(true);
isEmoteExternal(true);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT,true);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT, true, UsedEmoteType.REACTION);
}
@Test
public void addSingleExternalWhenExternalDisabled() {
externalEmotesEnabled(false);
isEmoteExternal(true);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(eq(emote), eq(guild), anyBoolean());
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(eq(emote), eq(guild), anyLong(), anyBoolean(), eq(UsedEmoteType.REACTION));
}
@Test
public void addSingleServerEmoteExternalDisabled() {
externalEmotesEnabled(false);
isEmoteExternal(false);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT, false);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT, false, UsedEmoteType.REACTION);
}
@Test
public void addTwoExternalEmotes() {
externalEmotesEnabled(true);
bothEmotesExternal(true, true);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(true));
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(1L), eq(true), eq(UsedEmoteType.REACTION));
List<CachedEmote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0));
@@ -153,8 +154,8 @@ public class TrackedEmoteServiceBeanTest {
public void addOneExternalAndOneLocalEmote() {
externalEmotesEnabled(true);
bothEmotesExternal(true, false);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(1L), booleanArgumentCaptor.capture(), eq(UsedEmoteType.REACTION));
List<CachedEmote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0));
@@ -169,16 +170,16 @@ public class TrackedEmoteServiceBeanTest {
public void addTwoExternalEmotesWhenExternalDisabled() {
externalEmotesEnabled(false);
bothEmotesExternal(true, true);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(1L), booleanArgumentCaptor.capture(), eq(UsedEmoteType.REACTION));
}
@Test
public void addTwoLocalEmotes() {
externalEmotesEnabled(false);
bothEmotesExternal(false, false);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild, UsedEmoteType.REACTION);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(1L), booleanArgumentCaptor.capture(), eq(UsedEmoteType.REACTION));
List<CachedEmote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0));
@@ -313,7 +314,7 @@ public class TrackedEmoteServiceBeanTest {
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote));
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.of(usedEmote));
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote, UsedEmoteType.REACTION)).thenReturn(Optional.of(usedEmote));
when(trackedEmote.getTrackingEnabled()).thenReturn(true);
when(usedEmote.getAmount()).thenReturn(COUNT);
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
@@ -344,13 +345,14 @@ public class TrackedEmoteServiceBeanTest {
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(persistingEmote.getUsedEmoteType()).thenReturn(UsedEmoteType.REACTION);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote));
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.empty());
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote, UsedEmoteType.REACTION)).thenReturn(Optional.empty());
when(trackedEmote.getTrackingEnabled()).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT, UsedEmoteType.REACTION);
verify(metricService, times(1)).incrementCounter(any());
}
@@ -359,11 +361,12 @@ public class TrackedEmoteServiceBeanTest {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getUsedEmoteType()).thenReturn(UsedEmoteType.REACTION);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong());
verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong(), eq(UsedEmoteType.REACTION));
verify(metricService, times(1)).incrementCounter(any());
}
@@ -372,11 +375,12 @@ public class TrackedEmoteServiceBeanTest {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getUsedEmoteType()).thenReturn(UsedEmoteType.REACTION);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(false);
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong());
verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong(), eq(UsedEmoteType.REACTION));
verify(metricService, times(1)).incrementCounter(any());
}
@@ -385,6 +389,7 @@ public class TrackedEmoteServiceBeanTest {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getUsedEmoteType()).thenReturn(UsedEmoteType.REACTION);
when(guildService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild));
when(persistingEmote.getCount()).thenReturn(COUNT);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
@@ -392,7 +397,7 @@ public class TrackedEmoteServiceBeanTest {
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT, UsedEmoteType.REACTION);
verify(metricService, times(1)).incrementCounter(any());
}
@@ -405,7 +410,7 @@ public class TrackedEmoteServiceBeanTest {
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.of(usedEmote));
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote, UsedEmoteType.REACTION)).thenReturn(Optional.of(usedEmote));
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatureDefinition.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
@@ -413,6 +418,7 @@ public class TrackedEmoteServiceBeanTest {
usagesToStore.put(serverId2, Arrays.asList(persistingEmote2));
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID_2, serverId2)).thenReturn(Optional.of(trackedEmote2));
when(trackedEmote2.getTrackingEnabled()).thenReturn(true);
when(persistingEmote2.getUsedEmoteType()).thenReturn(UsedEmoteType.REACTION);
when(persistingEmote2.getEmoteId()).thenReturn(EMOTE_ID_2);
when(persistingEmote2.getCount()).thenReturn(COUNT);
when(usedEmote.getAmount()).thenReturn(COUNT);
@@ -421,7 +427,7 @@ public class TrackedEmoteServiceBeanTest {
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(eq(trackedEmote2), anyLong());
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(eq(trackedEmote2), anyLong(), eq(UsedEmoteType.REACTION));
verify(usedEmote, times(1)).setAmount(2 * COUNT);
verify(metricService, times(2)).incrementCounter(any());
}

View File

@@ -6,6 +6,7 @@ import dev.sheldan.abstracto.statistic.emote.converter.EmoteStatsConverter;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsResult;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.service.management.UsedEmoteManagementService;
import org.junit.Assert;
import org.junit.Test;
@@ -58,27 +59,27 @@ public class UsedEmoteServiceBeanTest {
@Test
public void testGetDeletedEmoteStatsForServerSince() {
List<EmoteStatsResult> mockedEmoteStatsResult = getMockedStatsResult();
when(usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult);
when(usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(eq(server), any(Instant.class), eq(UsedEmoteType.REACTION))).thenReturn(mockedEmoteStatsResult);
when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel);
EmoteStatsModel result = testUnit.getDeletedEmoteStatsForServerSince(server, pointInTime);
EmoteStatsModel result = testUnit.getDeletedEmoteStatsForServerSince(server, pointInTime, UsedEmoteType.REACTION);
Assert.assertEquals(emoteStatsModel, result);
}
@Test
public void testGetExternalEmoteStatsForServerSince() {
List<EmoteStatsResult> mockedEmoteStatsResult = getMockedStatsResult();
when(usedEmoteManagementService.loadExternalEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult);
when(usedEmoteManagementService.loadExternalEmoteStatsForServerSince(eq(server), any(Instant.class), eq(UsedEmoteType.REACTION))).thenReturn(mockedEmoteStatsResult);
when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel);
EmoteStatsModel result = testUnit.getExternalEmoteStatsForServerSince(server, pointInTime);
EmoteStatsModel result = testUnit.getExternalEmoteStatsForServerSince(server, pointInTime, UsedEmoteType.REACTION);
Assert.assertEquals(emoteStatsModel, result);
}
@Test
public void testGetActiveEmoteStatsForServerSince() {
List<EmoteStatsResult> mockedEmoteStatsResult = getMockedStatsResult();
when(usedEmoteManagementService.loadActiveEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult);
when(usedEmoteManagementService.loadActiveEmoteStatsForServerSince(eq(server), any(Instant.class), eq(UsedEmoteType.REACTION))).thenReturn(mockedEmoteStatsResult);
when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel);
EmoteStatsModel result = testUnit.getActiveEmoteStatsForServerSince(server, pointInTime);
EmoteStatsModel result = testUnit.getActiveEmoteStatsForServerSince(server, pointInTime, UsedEmoteType.REACTION);
Assert.assertEquals(emoteStatsModel, result);
}

View File

@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsResult;
import dev.sheldan.abstracto.statistic.emote.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmote;
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
import dev.sheldan.abstracto.statistic.emote.repository.UsedEmoteRepository;
import org.junit.Assert;
import org.junit.Test;
@@ -47,8 +48,8 @@ public class UsedEmoteManagementServiceBeanTest {
@Test
public void testLoadUsedEmoteForTrackedEmoteToday() {
setupTrackedEmote();
when(usedEmoteRepository.findEmoteFromServerToday(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(usedEmote));
Optional<UsedEmote> usedEmoteOptional = testUnit.loadUsedEmoteForTrackedEmoteToday(trackedEmote);
when(usedEmoteRepository.findEmoteFromServerToday(EMOTE_ID, SERVER_ID, UsedEmoteType.REACTION.name())).thenReturn(Optional.of(usedEmote));
Optional<UsedEmote> usedEmoteOptional = testUnit.loadUsedEmoteForTrackedEmoteToday(trackedEmote, UsedEmoteType.REACTION);
Assert.assertTrue(usedEmoteOptional.isPresent());
usedEmoteOptional.ifPresent(usedEmote1 ->
Assert.assertEquals(usedEmote, usedEmote1)
@@ -58,12 +59,13 @@ public class UsedEmoteManagementServiceBeanTest {
@Test
public void testCreateEmoteUsageForToday() {
setupTrackedEmote();
testUnit.createEmoteUsageForToday(trackedEmote, COUNT);
testUnit.createEmoteUsageForToday(trackedEmote, COUNT, UsedEmoteType.REACTION);
verify(usedEmoteRepository, times(1)).save(usedEmoteArgumentCaptor.capture());
UsedEmote createdUsedEmote = usedEmoteArgumentCaptor.getValue();
Assert.assertEquals(COUNT, createdUsedEmote.getAmount());
Assert.assertEquals(EMOTE_ID, createdUsedEmote.getEmoteId().getEmoteId());
Assert.assertEquals(SERVER_ID, createdUsedEmote.getEmoteId().getServerId());
Assert.assertEquals(UsedEmoteType.REACTION, createdUsedEmote.getEmoteId().getType());
}
@Test
@@ -97,7 +99,7 @@ public class UsedEmoteManagementServiceBeanTest {
setupServer();
List<EmoteStatsResult> results = getEmoteStatsResults();
when(usedEmoteRepository.getDeletedEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadDeletedEmoteStatsForServerSince(server, Instant.EPOCH);
List<EmoteStatsResult> returnedResult = testUnit.loadDeletedEmoteStatsForServerSince(server, Instant.EPOCH, UsedEmoteType.REACTION);
Assert.assertEquals(results.size(), returnedResult.size());
Assert.assertEquals(results, returnedResult);
}
@@ -107,7 +109,7 @@ public class UsedEmoteManagementServiceBeanTest {
setupServer();
List<EmoteStatsResult> results = getEmoteStatsResults();
when(usedEmoteRepository.getExternalEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadExternalEmoteStatsForServerSince(server, Instant.EPOCH);
List<EmoteStatsResult> returnedResult = testUnit.loadExternalEmoteStatsForServerSince(server, Instant.EPOCH, UsedEmoteType.REACTION);
Assert.assertEquals(results.size(), returnedResult.size());
Assert.assertEquals(results, returnedResult);
}
@@ -116,8 +118,8 @@ public class UsedEmoteManagementServiceBeanTest {
public void testLoadActiveEmoteStatsForServerSince() {
setupServer();
List<EmoteStatsResult> results = getEmoteStatsResults();
when(usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadActiveEmoteStatsForServerSince(server, Instant.EPOCH);
when(usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH, UsedEmoteType.REACTION.name())).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadActiveEmoteStatsForServerSince(server, Instant.EPOCH, UsedEmoteType.REACTION);
Assert.assertEquals(results.size(), returnedResult.size());
Assert.assertEquals(results, returnedResult);
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.5.57</version>
<version>1.5.60</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.statistic.config;
public class StatisticSlashCommandNames {
public static final String STATISTIC = "statistics";
public static final String STATISTIC_INTERNAL = "statisticsinteral";
}

Some files were not shown because too many files have changed in this diff Show More