mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-15 04:02:53 +00:00
[AB-xxx] adding ability to track emotes used in reactions
adding ability to have confirmations for slash commands
This commit is contained in:
@@ -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());
|
||||
});
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -7,11 +7,21 @@ 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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -30,6 +40,16 @@ 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();
|
||||
@@ -40,24 +60,52 @@ public class DeleteTrackedEmote extends AbstractConditionableCommand {
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
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)) {
|
||||
throw new TrackedEmoteNotFoundException();
|
||||
}
|
||||
Long emoteId = ((CustomEmoji) emoji).getIdLong();
|
||||
ServerSpecificId serverEmoteId = new ServerSpecificId(event.getGuild().getIdLong(), emoteId);
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(serverEmoteId);
|
||||
trackedEmoteService.deleteTrackedEmote(trackedEmote);
|
||||
return slashCommandService.completeConfirmableCommand(event, DELETE_TRACKED_EMOTE_RESPONSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.requiresConfirmation(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
|
||||
@@ -7,16 +7,25 @@ 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.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,6 +43,7 @@ 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;
|
||||
|
||||
@@ -43,8 +53,16 @@ public class DeletedEmoteStats extends AbstractConditionableCommand {
|
||||
@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) {
|
||||
@@ -57,7 +75,7 @@ public class DeletedEmoteStats extends AbstractConditionableCommand {
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getDeletedEmoteStatsForServerSince(server, statsSince);
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getDeletedEmoteStatsForServerSince(server, statsSince, null);
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
// only show the embed, if there are static emotes to show
|
||||
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
|
||||
@@ -79,23 +97,95 @@ public class DeletedEmoteStats extends AbstractConditionableCommand {
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getDeletedEmoteStatsForServerSince(server, startTime, UsedEmoteTypeParameter.convertToUsedEmoteType(typeEnum));
|
||||
List<CompletableFuture<Message>> 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.addAll(interactionService.sendMessageToInteraction(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.addAll(interactionService.sendMessageToInteraction(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);
|
||||
messagePromises.addAll(interactionService.sendMessageToInteraction(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, emoteStatsModel, interactionHook));
|
||||
}
|
||||
return FutureUtils.toSingleFutureGeneric(messagePromises)
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -7,11 +7,20 @@ 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.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;
|
||||
|
||||
@@ -30,6 +39,17 @@ 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();
|
||||
@@ -44,22 +64,52 @@ public class DisableEmoteTracking extends AbstractConditionableCommand {
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
Long emoteId = ((CustomEmoji) emoji).getIdLong();
|
||||
ServerSpecificId serverEmoteId = new ServerSpecificId(event.getGuild().getIdLong(), emoteId);
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(serverEmoteId);
|
||||
trackedEmoteManagementService.disableTrackedEmote(trackedEmote);
|
||||
} else {
|
||||
trackedEmoteService.disableEmoteTracking(event.getGuild());
|
||||
}
|
||||
return interactionService.replyEmbed(DISABLE_EMOTE_TRACKING_RESPONSE, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.messageCommandOnly(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -7,15 +7,28 @@ 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.core.service.ChannelService;
|
||||
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.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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -40,7 +53,18 @@ public class EmoteStat extends AbstractConditionableCommand {
|
||||
@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) {
|
||||
@@ -54,7 +78,7 @@ public class EmoteStat extends AbstractConditionableCommand {
|
||||
Duration duration = (Duration) parameters.get(1);
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
EmoteStatsResultDisplay emoteStatsModel = usedEmoteService.getEmoteStatForEmote(trackedEmote, statsSince);
|
||||
EmoteStatsResultDisplay emoteStatsModel = usedEmoteService.getEmoteStatForEmote(trackedEmote, statsSince, null);
|
||||
if(emoteStatsModel.getResult().getAmount() == null) {
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
@@ -63,29 +87,94 @@ public class EmoteStat extends AbstractConditionableCommand {
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
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();
|
||||
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 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());
|
||||
} else {
|
||||
throw new TrackedEmoteNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -7,16 +7,25 @@ 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.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;
|
||||
|
||||
@@ -43,9 +52,18 @@ public class EmoteStats extends AbstractConditionableCommand {
|
||||
@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) {
|
||||
@@ -58,7 +76,7 @@ public class EmoteStats extends AbstractConditionableCommand {
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getActiveEmoteStatsForServerSince(server, statsSince);
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getActiveEmoteStatsForServerSince(server, statsSince, null);
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
// only show embed if static emote stats are available
|
||||
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
|
||||
@@ -80,24 +98,91 @@ public class EmoteStats extends AbstractConditionableCommand {
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getActiveEmoteStatsForServerSince(server, startTime, UsedEmoteTypeParameter.convertToUsedEmoteType(typeEnum));
|
||||
List<CompletableFuture<Message>> 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.addAll(interactionService.sendMessageToInteraction(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.addAll(interactionService.sendMessageToInteraction(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);
|
||||
messagePromises.addAll(interactionService.sendMessageToInteraction(EMOTE_STATS_NO_STATS_AVAILABLE, emoteStatsModel, interactionHook));
|
||||
}
|
||||
return FutureUtils.toSingleFutureGeneric(messagePromises)
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
@@ -109,4 +194,6 @@ public class EmoteStats extends AbstractConditionableCommand {
|
||||
public FeatureDefinition getFeature() {
|
||||
return StatisticFeatureDefinition.EMOTE_TRACKING;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -8,17 +8,25 @@ 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.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;
|
||||
|
||||
@@ -46,8 +54,18 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
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) {
|
||||
@@ -60,7 +78,7 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getExternalEmoteStatsForServerSince(server, statsSince);
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getExternalEmoteStatsForServerSince(server, statsSince, null);
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
|
||||
// only show embed if static emote stats are available
|
||||
@@ -85,27 +103,102 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getExternalEmoteStatsForServerSince(server, startTime, UsedEmoteTypeParameter.convertToUsedEmoteType(typeEnum));
|
||||
List<CompletableFuture<Message>> 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.addAll(
|
||||
interactionService.sendMessageToInteraction(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, emoteStatsModel, interactionHook));
|
||||
}
|
||||
|
||||
// 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.addAll(
|
||||
interactionService.sendMessageToInteraction(EMOTE_STATS_ANIMATED_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 {}.", event.getGuild().getIdLong(), startTime);
|
||||
messagePromises.addAll(interactionService.sendMessageToInteraction(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), interactionHook));
|
||||
}
|
||||
|
||||
return FutureUtils.toSingleFutureGeneric(messagePromises)
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
|
||||
@@ -7,11 +7,22 @@ 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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -33,6 +44,17 @@ 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();
|
||||
@@ -49,30 +71,65 @@ public class PurgeEmoteStats extends AbstractConditionableCommand {
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
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)) {
|
||||
throw new TrackedEmoteNotFoundException();
|
||||
}
|
||||
Long emoteId = ((CustomEmoji) emoji).getIdLong();
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(new ServerSpecificId(event.getGuild().getIdLong(), emoteId));
|
||||
// default 1.1.1970
|
||||
Instant since = Instant.EPOCH;
|
||||
if(slashCommandParameterService.hasCommandOption(PURGE_EMOTE_STATS_PERIOD, event)) {
|
||||
// if a Duration is given, subtract it from the current point in time
|
||||
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 slashCommandService.completeConfirmableCommand(event, PURGE_EMOTE_STATS_RESPONSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.requiresConfirmation(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -7,9 +7,14 @@ 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 +31,47 @@ 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();
|
||||
}
|
||||
|
||||
@Override
|
||||
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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.requiresConfirmation(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -9,13 +9,22 @@ 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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -31,13 +40,22 @@ 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();
|
||||
@@ -52,22 +70,53 @@ public class ShowExternalTrackedEmote extends AbstractConditionableCommand {
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
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 interactionService.replyEmbed(SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY, trackedEmote, event)
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
} else {
|
||||
throw new TrackedEmoteNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.messageCommandOnly(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -7,15 +7,20 @@ 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.service.ChannelService;
|
||||
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;
|
||||
|
||||
@@ -40,6 +45,12 @@ public class ShowTrackedEmotes extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
@Autowired
|
||||
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";
|
||||
public static final String SHOW_TRACKED_EMOTES_EXTERNAL_ANIMATED_RESPONSE = "showTrackedEmotes_external_animated_response";
|
||||
@@ -48,9 +59,11 @@ 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";
|
||||
|
||||
private static final String SHOW_TRACKED_EMOTES_COMMAND_NAME = "showTrackedEmotes";
|
||||
private static final String SHOW_TRACKED_EMOTES_SHOW_ALL = "showAll";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
|
||||
// per default, do not show TrackedEmote for which tracking has been disabled
|
||||
Boolean showTrackingDisabled = false;
|
||||
if(!commandContext.getParameters().getParameters().isEmpty()) {
|
||||
@@ -110,23 +123,98 @@ public class ShowTrackedEmotes extends AbstractConditionableCommand {
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
// per default, do not show TrackedEmote for which tracking has been disabled
|
||||
Boolean showTrackingDisabled = false;
|
||||
if(slashCommandParameterService.hasCommandOption(SHOW_TRACKED_EMOTES_SHOW_ALL, event)) {
|
||||
showTrackingDisabled = slashCommandParameterService.getCommandOption(SHOW_TRACKED_EMOTES_SHOW_ALL, event, Boolean.class);
|
||||
}
|
||||
|
||||
TrackedEmoteOverview trackedEmoteOverview = trackedEmoteService.loadTrackedEmoteOverview(event.getGuild(), showTrackingDisabled);
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
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(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_STATIC_RESPONSE, trackedEmoteOverview, interactionHook));
|
||||
}
|
||||
|
||||
// only show the embed if there are animated tracked emotes
|
||||
if(!trackedEmoteOverview.getAnimatedEmotes().isEmpty()) {
|
||||
noTrackedEmotesAvailable = false;
|
||||
messagePromises.addAll(interactionService.sendMessageToInteraction(SHOW_TRACKED_EMOTES_ANIMATED_RESPONSE, trackedEmoteOverview, interactionHook));
|
||||
}
|
||||
|
||||
// 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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.messageCommandOnly(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -7,12 +7,16 @@ 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.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.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,13 +32,18 @@ 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;
|
||||
|
||||
@Autowired
|
||||
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());
|
||||
@@ -43,6 +52,14 @@ public class SyncTrackedEmotes extends AbstractConditionableCommand {
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
TrackedEmoteSynchronizationResult syncResult = trackedEmoteService.synchronizeTrackedEmotes(event.getGuild());
|
||||
// show a result of how many emotes were deleted/added
|
||||
return interactionService.replyEmbed(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, syncResult, event)
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
@@ -50,10 +67,20 @@ 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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.messageCommandOnly(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -8,15 +8,24 @@ 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,6 +51,17 @@ 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);
|
||||
@@ -66,22 +86,66 @@ public class TrackEmote extends AbstractConditionableCommand {
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
} else {
|
||||
throw new TrackedEmoteNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
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)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,12 +24,14 @@ 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 " +
|
||||
@@ -47,6 +49,17 @@ public interface UsedEmoteRepository extends JpaRepository<UsedEmote, UsedEmoteD
|
||||
"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.external = true " +
|
||||
"and us.type = :used_emote_type " +
|
||||
"group by us.emote_id, us.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 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 " +
|
||||
@@ -55,6 +68,17 @@ public interface UsedEmoteRepository extends JpaRepository<UsedEmote, UsedEmoteD
|
||||
"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.deleted = true " +
|
||||
"and us.type = :used_emote_type " +
|
||||
"group by us.emote_id, us.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 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 " +
|
||||
@@ -63,6 +87,18 @@ public interface UsedEmoteRepository extends JpaRepository<UsedEmote, UsedEmoteD
|
||||
"order by amount desc", nativeQuery = true)
|
||||
List<EmoteStatsResult> getCurrentlyExistingEmoteStatsForServerSince(@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 " +
|
||||
"and us.type = :used_emote_type " +
|
||||
"group by us.emote_id, us.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, sum(us.amount) as amount " +
|
||||
"from used_emote us " +
|
||||
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) " +
|
||||
@@ -70,6 +106,15 @@ public interface UsedEmoteRepository extends JpaRepository<UsedEmote, UsedEmoteD
|
||||
"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, sum(us.amount) 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
List<PersistingEmote> existingEmotes = elementsForKey.get(guild.getIdLong());
|
||||
Optional<PersistingEmote> existingEmote = existingEmotes
|
||||
.stream()
|
||||
.filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getEmoteId()))
|
||||
.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())
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -13,3 +13,7 @@ abstracto.featureModes.externalEmotes.enabled=false
|
||||
abstracto.featureModes.autoTrackExternal.featureName=emoteTracking
|
||||
abstracto.featureModes.autoTrackExternal.mode=autoTrackExternal
|
||||
abstracto.featureModes.autoTrackExternal.enabled=false
|
||||
|
||||
abstracto.featureModes.trackReactions.featureName=emoteTracking
|
||||
abstracto.featureModes.trackReactions.mode=trackReactions
|
||||
abstracto.featureModes.trackReactions.enabled=false
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -29,6 +29,9 @@ public class EmoteTrackingFeatureConfig implements FeatureConfig {
|
||||
*/
|
||||
@Override
|
||||
public List<FeatureMode> getAvailableModes() {
|
||||
return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES, EmoteTrackingMode.AUTO_TRACK, EmoteTrackingMode.AUTO_TRACK_EXTERNAL);
|
||||
return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES,
|
||||
EmoteTrackingMode.AUTO_TRACK,
|
||||
EmoteTrackingMode.AUTO_TRACK_EXTERNAL,
|
||||
EmoteTrackingMode.TRACK_REACTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,14 @@ import lombok.Getter;
|
||||
* Influences:
|
||||
* EXTERNAL_EMOTES: Enables the tracking of emotes which are not from the server the feature is enabled in. This feature alone only enables to track emotes with the `trackEmote` command and makes the command `externalEmoteStats` (and more) available
|
||||
* AUTO_TRACK_EXTERNAL: Every external emote which is encountered in a message will be tracked (created and updated), only works in combination with EXTERNAL_MOTES
|
||||
* TRACK_REACTIONS: if reactions are counted
|
||||
*/
|
||||
@Getter
|
||||
public enum EmoteTrackingMode implements FeatureMode {
|
||||
AUTO_TRACK("emoteAutoTrack"), EXTERNAL_EMOTES("externalEmotes"), AUTO_TRACK_EXTERNAL("autoTrackExternal");
|
||||
AUTO_TRACK("emoteAutoTrack"),
|
||||
EXTERNAL_EMOTES("externalEmotes"),
|
||||
AUTO_TRACK_EXTERNAL("autoTrackExternal"),
|
||||
TRACK_REACTIONS("trackReactions");
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.statistic.emote.model;
|
||||
|
||||
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -33,6 +34,7 @@ public class PersistingEmote {
|
||||
* Only if the emote is external: the URL where the source image of the emote is stored on Discord servers
|
||||
*/
|
||||
private String externalUrl;
|
||||
private UsedEmoteType usedEmoteType;
|
||||
/**
|
||||
* The amount of times the emote has been used.
|
||||
*/
|
||||
|
||||
@@ -47,4 +47,5 @@ public class UsedEmote {
|
||||
|
||||
@Column(name = "updated", insertable = false, updatable = false)
|
||||
private Instant updated;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package dev.sheldan.abstracto.statistic.emote.model.database;
|
||||
|
||||
public enum UsedEmoteType {
|
||||
MESSAGE,
|
||||
REACTION;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package dev.sheldan.abstracto.statistic.emote.model.database.embed;
|
||||
|
||||
import dev.sheldan.abstracto.statistic.emote.model.database.UsedEmoteType;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import lombok.*;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
@@ -36,4 +39,8 @@ public class UsedEmoteDay implements Serializable {
|
||||
*/
|
||||
@Column(name = "use_date")
|
||||
private Instant useDate;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "type")
|
||||
private UsedEmoteType type;
|
||||
}
|
||||
|
||||
@@ -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 java.util.List;
|
||||
@@ -18,24 +19,16 @@ public interface TrackedEmoteRuntimeService {
|
||||
*/
|
||||
Map<Long, Map<Long, List<PersistingEmote>>> getRuntimeConfig();
|
||||
|
||||
/**
|
||||
* Adds the given {@link net.dv8tion.jda.api.entities.emoji.CustomEmoji} used in the {@link Guild} to the runtime storage.
|
||||
* The necessary lock will be acquired by this method.
|
||||
* @param emote The {@link CachedEmote} to add to the runtime storage
|
||||
* @param guild The {@link Guild} in which the {@link net.dv8tion.jda.api.entities.emoji.CustomEmoji} is used
|
||||
* @param external Whether or not the emote is external
|
||||
*/
|
||||
void addEmoteForServer(CachedEmote emote, Guild guild, boolean external);
|
||||
|
||||
/**
|
||||
* Adds the given {@link CachedEmote} used in the {@link Guild} to the runtime storage.
|
||||
* The necessary lock will be acquired by this method.
|
||||
* @param emote The {@link CachedEmote} to add to the runtime storage
|
||||
* @param guild The {@link Guild} in which the {@link net.dv8tion.jda.api.entities.emoji.CustomEmoji} is used
|
||||
* @param count The amount of usages which should be added
|
||||
* @param external Whether or not the emote is external
|
||||
* @param external Whether the emote is external
|
||||
* @param usedEmoteType The type of the emote
|
||||
*/
|
||||
void addEmoteForServer(CachedEmote emote, Guild guild, Long count, boolean external);
|
||||
void addEmoteForServer(CachedEmote emote, Guild guild, Long count, boolean external, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Calculates the key used for the Map containing the emote statistics.
|
||||
@@ -50,7 +43,7 @@ public interface TrackedEmoteRuntimeService {
|
||||
* @param external Whether or not the {@link net.dv8tion.jda.api.entities.emoji.CustomEmoji} is external
|
||||
* @return A created {@link PersistingEmote} instance from the {@link net.dv8tion.jda.api.entities.emoji.CustomEmoji}
|
||||
*/
|
||||
PersistingEmote createFromEmote(Guild guild, CachedEmote emote, boolean external);
|
||||
PersistingEmote createFromEmote(Guild guild, CachedEmote emote, boolean external, UsedEmoteType type);
|
||||
|
||||
/**
|
||||
* Creates a {@link PersistingEmote} from the given parameters.
|
||||
@@ -60,7 +53,7 @@ public interface TrackedEmoteRuntimeService {
|
||||
* @param external Whether or not the {@link net.dv8tion.jda.api.entities.emoji.CustomEmoji} is external
|
||||
* @return A created {@link PersistingEmote} instance from the {@link net.dv8tion.jda.api.entities.emoji.CustomEmoji}
|
||||
*/
|
||||
PersistingEmote createFromEmote(Guild guild, CachedEmote emote, Long count, boolean external);
|
||||
PersistingEmote createFromEmote(Guild guild, CachedEmote emote, Long count, boolean external, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Acquires the lock which should be used when accessing the runtime storage
|
||||
|
||||
@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.statistic.emote.model.PersistingEmote;
|
||||
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.UsedEmoteType;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
|
||||
|
||||
@@ -21,23 +22,25 @@ public interface TrackedEmoteService {
|
||||
* @param emotes The list of {@link CustomEmoji}s to add to the runtime storage
|
||||
* @param guild The {@link Guild} in which the {@link CustomEmoji}s were used and where the usages should be added
|
||||
*/
|
||||
void addEmoteToRuntimeStorage(List<CachedEmote> emotes, Guild guild);
|
||||
void addEmoteToRuntimeStorage(List<CachedEmote> emotes, Guild guild, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Adds the given {@link CustomEmoji} with the given amount to the runtime storage for the given {@link Guild}
|
||||
* @param emote The {@link CachedEmote} to add to the runtime storage
|
||||
* @param guild The {@link Guild} in which the {@link CustomEmoji} was used and in which the usage should be added
|
||||
* @param count The amount of times which the {@link CustomEmoji} has been used and should be reflected in the runtime storage
|
||||
* @param type The type of interaction the emote came from
|
||||
*/
|
||||
void addEmoteToRuntimeStorage(CachedEmote emote, Guild guild, Long count);
|
||||
void addEmoteToRuntimeStorage(CachedEmote emote, Guild guild, Long count, UsedEmoteType type);
|
||||
|
||||
/**
|
||||
* Adds the given {@link CustomEmoji} with the given amount to the runtime storage for the given {@link Guild}
|
||||
* @param emote The {@link CustomEmoji} to add to the runtime storage
|
||||
* @param guild The {@link Guild} in which the {@link CustomEmoji} was used and in which the usage should be added
|
||||
* @param count The amount of times which the {@link CustomEmoji} has been used and should be reflected in the runtime storage
|
||||
* @param type The type of interaction the emote came from
|
||||
*/
|
||||
void addEmoteToRuntimeStorage(CustomEmoji emote, Guild guild, Long count);
|
||||
void addEmoteToRuntimeStorage(CustomEmoji emote, Guild guild, Long count, UsedEmoteType type);
|
||||
|
||||
/**
|
||||
* Takes the given map of server_ids with the list of {@link PersistingEmote} and stores the objects in the database
|
||||
|
||||
@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.statistic.emote.model.EmoteStatsModel;
|
||||
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 java.time.Instant;
|
||||
|
||||
/**
|
||||
@@ -25,29 +26,32 @@ public interface UsedEmoteService {
|
||||
* This {@link EmoteStatsModel} will contain only deleted {@link TrackedEmote} from the server
|
||||
* @param server The {@link AServer} to retrieve the emote stats for
|
||||
* @param since Emote stats should be younger than this {@link Instant}. Only the date portion is considered.
|
||||
* @param usedEmoteType The type of interaction the emote was from
|
||||
* @return An {@link EmoteStatsModel} containing the statistics split by animated and static emote
|
||||
*/
|
||||
EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since);
|
||||
EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link EmoteStatsModel} for the {@link AServer} since {@link Instant}.
|
||||
* This {@link EmoteStatsModel} will contain only external {@link TrackedEmote} from the server
|
||||
* @param server The {@link AServer} to retrieve the emote stats for
|
||||
* @param since Emote stats should be younger than this {@link Instant}. Only the date portion is considered.
|
||||
* @param usedEmoteType The type of interaction the emote was used in
|
||||
* @return An {@link EmoteStatsModel} containing the statistics split by animated and static emote
|
||||
*/
|
||||
EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since);
|
||||
EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link EmoteStatsModel} for the {@link AServer} since {@link Instant}.
|
||||
* This {@link EmoteStatsModel} will contain only active {@link TrackedEmote} from the server. These are emotes which are still present
|
||||
* the {@link net.dv8tion.jda.api.entities.Guild}
|
||||
* @param server The {@link AServer} to retrieve the emote stats for
|
||||
* @param since Emote stats should be younger than this {@link Instant}. Only the date portion is considered.
|
||||
* @param since Emote stats should be younger than this {@link Instant}. Only the date portion is considered
|
||||
* @param usedEmoteType The type of emote the interaction is coming from
|
||||
* @return An {@link EmoteStatsModel} containing the statistics split by animated and static emote
|
||||
*/
|
||||
EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since);
|
||||
EmoteStatsResultDisplay getEmoteStatForEmote(TrackedEmote trackedEmote, Instant since);
|
||||
EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType);
|
||||
EmoteStatsResultDisplay getEmoteStatForEmote(TrackedEmote trackedEmote, Instant since, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Removes all {@link dev.sheldan.abstracto.statistic.emote.model.database.UsedEmote} for the given {@link TrackedEmote} which are younger
|
||||
|
||||
@@ -5,6 +5,7 @@ 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 java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -17,17 +18,19 @@ public interface UsedEmoteManagementService {
|
||||
* Loads an {@link Optional} containing a {@link UsedEmote} for the particular {@link TrackedEmote} for the current day.
|
||||
* The {@link Optional} is empty, if none exists.
|
||||
* @param trackedEmote The {@link TrackedEmote} to search a {@link UsedEmote} for today
|
||||
* @param usedEmoteType The type of interaction this emote was used in
|
||||
* @return An {@link Optional} containing a {@link UsedEmote}, if it exists for the current day
|
||||
*/
|
||||
Optional<UsedEmote> loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote);
|
||||
Optional<UsedEmote> loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Creates and persists and instance of {@link UsedEmote} from the given {@link TrackedEmote}, with the defined count and the current date.
|
||||
* @param trackedEmote The {@link TrackedEmote} for which to create a {@link UsedEmote} for
|
||||
* @param count The amount of usages for the {@link UsedEmote}
|
||||
* @param type The type of emote
|
||||
* @return The created {@link UsedEmote} instance in the database
|
||||
*/
|
||||
UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count);
|
||||
UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count, UsedEmoteType type);
|
||||
|
||||
/**
|
||||
* Creates and persists and instance of {@link UsedEmote} from the given {@link TrackedEmote}, with the defined count and the given date.
|
||||
@@ -36,7 +39,7 @@ public interface UsedEmoteManagementService {
|
||||
* @param instant The date to create the {@link UsedEmote emoteUsage} for
|
||||
* @return The created {@link UsedEmote} instance in the database
|
||||
*/
|
||||
UsedEmote createEmoteUsageFor(TrackedEmote trackedEmote, Long count, Instant instant);
|
||||
UsedEmote createEmoteUsageFor(TrackedEmote trackedEmote, Long count, Instant instant, UsedEmoteType type);
|
||||
|
||||
/**
|
||||
* Loads {@link UsedEmote} for the {@link AServer} which are newer than the given {@link Instant}
|
||||
@@ -58,26 +61,29 @@ public interface UsedEmoteManagementService {
|
||||
* Load {@link EmoteStatsResult} from the {@link AServer} for {@link TrackedEmote} which were deleted and newer than {@link Instant}
|
||||
* @param server The {@link AServer} to retrieve the emote statistics for
|
||||
* @param since Emote stats should be younger than this {@link Instant}. Only the date portion is considered.
|
||||
* @param usedEmoteType The type of interaction the emote was used in
|
||||
* @return A list of {@link EmoteStatsResult} from the {@link AServer} newer than the given {@link Instant} for all deleted {@link TrackedEmote}
|
||||
*/
|
||||
List<EmoteStatsResult> loadDeletedEmoteStatsForServerSince(AServer server, Instant since);
|
||||
List<EmoteStatsResult> loadDeletedEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Load {@link EmoteStatsResult} from the {@link AServer} for {@link TrackedEmote} which are external and newer than {@link Instant}
|
||||
* @param server The {@link AServer} to retrieve the emote statistic for
|
||||
* @param since Emote stats should be younger than this {@link Instant}. Only the date portion is considered.
|
||||
* @param type The type of interaction the emote was used in
|
||||
* @return A list of {@link EmoteStatsResult} from the {@link AServer} newer than the given {@link Instant} for all external {@link TrackedEmote}
|
||||
*/
|
||||
List<EmoteStatsResult> loadExternalEmoteStatsForServerSince(AServer server, Instant since);
|
||||
List<EmoteStatsResult> loadExternalEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType type);
|
||||
|
||||
/**
|
||||
* Load {@link EmoteStatsResult} from the {@link AServer} for {@link TrackedEmote} which are active and newer than {@link Instant}
|
||||
* @param server The {@link AServer} to retrieve the emote statistic for
|
||||
* @param since Emote stats should be younger than this {@link Instant}. Only the date portion is considered.
|
||||
* @param type The type of emote that should be loaded
|
||||
* @return A list of {@link EmoteStatsResult} from the {@link AServer} newer than the given {@link Instant} for all active {@link TrackedEmote}
|
||||
*/
|
||||
List<EmoteStatsResult> loadActiveEmoteStatsForServerSince(AServer server, Instant since);
|
||||
EmoteStatsResult loadEmoteStatForEmote(TrackedEmote trackedEmote, Instant since);
|
||||
List<EmoteStatsResult> loadActiveEmoteStatsForServerSince(AServer server, Instant since, UsedEmoteType type);
|
||||
EmoteStatsResult loadEmoteStatForEmote(TrackedEmote trackedEmote, Instant since, UsedEmoteType usedEmoteType);
|
||||
|
||||
/**
|
||||
* Deletes all emote usages for the {@link TrackedEmote} which are younger than the given {@link Instant}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class SetEmote extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
String emoteKey = slashCommandParameterService.getCommandOption(EMOTE_KEY_PARAMETER, event, String.class);
|
||||
String emote = slashCommandParameterService.getCommandOption(EMOTE_PARAMETER, event, String.class);
|
||||
AEmote aEmote = slashCommandParameterService.loadAEmoteFromString(emote, event);
|
||||
AEmote aEmote = slashCommandParameterService.loadAEmoteFromString(emote, event.getGuild());
|
||||
emoteManagementService.setEmoteToAEmote(emoteKey, aEmote, event.getGuild().getIdLong());
|
||||
return interactionService.replyEmbed(RESPONSE_TEMPLATE, new Object(), event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
|
||||
@@ -10,7 +10,6 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.AttachedFile;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FileService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||
@@ -167,7 +166,7 @@ public class InteractionServiceBean implements InteractionService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> editOriginal(MessageToSend messageToSend, InteractionHook interactionHook) {
|
||||
public CompletableFuture<Message> replaceOriginal(MessageToSend messageToSend, InteractionHook interactionHook) {
|
||||
Long serverId = interactionHook.getInteraction().getGuild().getIdLong();
|
||||
|
||||
if(messageToSend.getEphemeral()) {
|
||||
@@ -231,9 +230,17 @@ public class InteractionServiceBean implements InteractionService {
|
||||
if(action == null) {
|
||||
throw new AbstractoRunTimeException("The callback did not result in any message.");
|
||||
}
|
||||
action.setReplace(true);
|
||||
return action.submit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> replaceOriginal(String template, Object model, InteractionHook interactionHook) {
|
||||
Long serverId = interactionHook.getInteraction().getGuild().getIdLong();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(template, new Object(), serverId);
|
||||
return replaceOriginal(messageToSend, interactionHook);
|
||||
}
|
||||
|
||||
public CompletableFuture<InteractionHook> replyMessageToSend(MessageToSend messageToSend, IReplyCallback callback) {
|
||||
Long serverId = callback.getGuild().getIdLong();
|
||||
ReplyCallbackAction action = null;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.core.interaction.job;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.CommandReceivedHandler;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandListenerBean;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.DisallowConcurrentExecution;
|
||||
@@ -23,12 +24,18 @@ public class ConfirmationCleanupJob extends QuartzJobBean {
|
||||
private Long messageId;
|
||||
private String confirmationPayloadId;
|
||||
private String abortPayloadId;
|
||||
private Long interactionId;
|
||||
|
||||
@Autowired
|
||||
private CommandReceivedHandler commandReceivedHandler;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandListenerBean slashCommandListenerBean;
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
// we either clean up a slash command confirmation or a message command interaction
|
||||
if(interactionId == null) {
|
||||
log.info("Cleaning up confirmation message {} in server {} in channel {}.", messageId, serverId, channelId);
|
||||
commandReceivedHandler.cleanupConfirmationMessage(serverId, channelId, messageId, confirmationPayloadId, abortPayloadId)
|
||||
.thenAccept(unused -> log.info("Deleted confirmation message {}", messageId))
|
||||
@@ -36,5 +43,9 @@ public class ConfirmationCleanupJob extends QuartzJobBean {
|
||||
log.warn("Failed to cleanup confirmation message {}.", messageId);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
log.info("Cleaning up slash command confirmation message in server {}.", serverId);
|
||||
slashCommandListenerBean.removeSlashCommandConfirmationInteraction(interactionId, confirmationPayloadId, abortPayloadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.sheldan.abstracto.core.interaction.slash;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.Command;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class DriedSlashCommand {
|
||||
private Command command;
|
||||
private SlashCommandInteractionEvent event;
|
||||
}
|
||||
@@ -1,19 +1,41 @@
|
||||
package dev.sheldan.abstracto.core.interaction.slash;
|
||||
|
||||
import static dev.sheldan.abstracto.core.command.CommandReceivedHandler.COMMAND_CONFIRMATION_MESSAGE_TEMPLATE_KEY;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.Command;
|
||||
import dev.sheldan.abstracto.core.command.CommandReceivedHandler;
|
||||
import dev.sheldan.abstracto.core.command.condition.ConditionResult;
|
||||
import dev.sheldan.abstracto.core.command.config.features.CoreFeatureConfig;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||
import dev.sheldan.abstracto.core.command.service.PostCommandExecution;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentPayloadManagementService;
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentPayloadService;
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentService;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.button.CommandConfirmationModel;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.payload.SlashCommandConfirmationPayload;
|
||||
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricService;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricTag;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.scheduling.model.JobParameters;
|
||||
import dev.sheldan.abstracto.scheduling.service.SchedulerService;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -60,6 +82,30 @@ public class SlashCommandListenerBean extends ListenerAdapter {
|
||||
@Autowired
|
||||
private MetricService metricService;
|
||||
|
||||
@Autowired
|
||||
private ComponentService componentService;
|
||||
|
||||
@Autowired
|
||||
private ComponentPayloadService componentPayloadService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private SchedulerService schedulerService;
|
||||
|
||||
@Autowired
|
||||
private ComponentPayloadManagementService componentPayloadManagementService;
|
||||
|
||||
private static final Map<Long, DriedSlashCommand> COMMANDS_WAITING_FOR_CONFIRMATION = new ConcurrentHashMap<>();
|
||||
public static final String SLASH_COMMAND_CONFIRMATION_ORIGIN = "SLASH_COMMAND_CONFIRMATION";
|
||||
|
||||
public static final CounterMetric SLASH_COMMANDS_PROCESSED_COUNTER = CounterMetric
|
||||
.builder()
|
||||
.name(CommandReceivedHandler.COMMAND_PROCESSED)
|
||||
@@ -140,12 +186,89 @@ public class SlashCommandListenerBean extends ListenerAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void continueSlashCommand(Long interactionId, ButtonInteractionEvent buttonInteractionEvent) {
|
||||
if(COMMANDS_WAITING_FOR_CONFIRMATION.containsKey(interactionId)) {
|
||||
DriedSlashCommand driedSlashCommand = COMMANDS_WAITING_FOR_CONFIRMATION.get(interactionId);
|
||||
Command commandInstance = driedSlashCommand.getCommand();
|
||||
String commandName = commandInstance.getConfiguration().getName();
|
||||
log.info("Continuing slash command {}", commandName);
|
||||
commandInstance.executeSlash(driedSlashCommand.getEvent()).thenApply(commandResult -> {
|
||||
log.info("Command {} in server {} was executed after confirmation.", commandName, buttonInteractionEvent.getGuild().getIdLong());
|
||||
return commandResult;
|
||||
}).thenAccept(commandResult -> {
|
||||
self.executePostCommandListener(commandInstance, driedSlashCommand.getEvent(), commandResult);
|
||||
COMMANDS_WAITING_FOR_CONFIRMATION.remove(interactionId);
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Error while handling post execution of command with confirmation {}", commandName, throwable);
|
||||
CommandResult commandResult = CommandResult.fromError(throwable.getMessage(), throwable);
|
||||
self.executePostCommandListener(commandInstance, driedSlashCommand.getEvent(), commandResult);
|
||||
COMMANDS_WAITING_FOR_CONFIRMATION.remove(interactionId);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
log.warn("Interaction was not found in internal map - not continuing interaction from user {} in server {}.", buttonInteractionEvent.getUser().getIdLong(), buttonInteractionEvent.getGuild().getIdLong());
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void removeSlashCommandConfirmationInteraction(Long interactionId, String confirmationPayload, String abortPayload) {
|
||||
if(COMMANDS_WAITING_FOR_CONFIRMATION.containsKey(interactionId)) {
|
||||
DriedSlashCommand removedSlashCommand = COMMANDS_WAITING_FOR_CONFIRMATION.remove(interactionId);
|
||||
SlashCommandInteractionEvent event = removedSlashCommand.getEvent();
|
||||
event.getInteraction().getHook().deleteOriginal().queue();
|
||||
log.info("Remove interaction for command {} in server {} from user {}.", removedSlashCommand.getCommand().getConfiguration().getName(), event.getGuild().getIdLong(), event.getUser().getIdLong());
|
||||
} else {
|
||||
log.info("Did not find interaction to clean up.");
|
||||
}
|
||||
componentPayloadManagementService.deletePayloads(Arrays.asList(confirmationPayload, abortPayload));
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = AbstractoRunTimeException.class)
|
||||
public void executeCommand(SlashCommandInteractionEvent event, Command command, ConditionResult conditionResult) {
|
||||
String commandName = command.getConfiguration().getName();
|
||||
if(command.getConfiguration().isRequiresConfirmation() && conditionResult.isResult()) {
|
||||
DriedSlashCommand slashCommand = DriedSlashCommand
|
||||
.builder()
|
||||
.command(command)
|
||||
.event(event)
|
||||
.build();
|
||||
COMMANDS_WAITING_FOR_CONFIRMATION.put(event.getIdLong(), slashCommand);
|
||||
String confirmationId = componentService.generateComponentId();
|
||||
String abortId = componentService.generateComponentId();
|
||||
SlashCommandConfirmationPayload confirmPayload = SlashCommandConfirmationPayload
|
||||
.builder()
|
||||
.action(SlashCommandConfirmationPayload.CommandConfirmationAction.CONFIRM)
|
||||
.interactionId(event.getIdLong())
|
||||
.build();
|
||||
Long serverId = event.getGuild().getIdLong();
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
componentPayloadService.createButtonPayload(confirmationId, confirmPayload, SLASH_COMMAND_CONFIRMATION_ORIGIN, server);
|
||||
SlashCommandConfirmationPayload denialPayload = SlashCommandConfirmationPayload
|
||||
.builder()
|
||||
.action(SlashCommandConfirmationPayload.CommandConfirmationAction.ABORT)
|
||||
.interactionId(event.getIdLong())
|
||||
.build();
|
||||
componentPayloadService.createButtonPayload(abortId, denialPayload, SLASH_COMMAND_CONFIRMATION_ORIGIN, server);
|
||||
CommandConfirmationModel model = CommandConfirmationModel
|
||||
.builder()
|
||||
.abortButtonId(abortId)
|
||||
.confirmButtonId(confirmationId)
|
||||
.commandName(commandName)
|
||||
.build();
|
||||
Long userId = event.getUser().getIdLong();
|
||||
interactionService.replyEmbed(COMMAND_CONFIRMATION_MESSAGE_TEMPLATE_KEY, model, event).thenAccept(interactionHook -> {
|
||||
log.info("Sent confirmation for command {} in server {} for user {}.", commandName, serverId, userId);
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Failed to send confirmation for command {} in server {} for user {}.", commandName, serverId, userId);
|
||||
return null;
|
||||
});
|
||||
scheduleConfirmationDeletion(event.getIdLong(), confirmationId, abortId, serverId);
|
||||
} else {
|
||||
CompletableFuture<CommandResult> commandOutput;
|
||||
if(conditionResult.isResult()) {
|
||||
commandOutput = command.executeSlash(event).thenApply(commandResult -> {
|
||||
log.info("Command {} in server {} was executed.", command.getConfiguration().getName(), event.getGuild().getIdLong());
|
||||
log.info("Command {} in server {} was executed.", commandName, event.getGuild().getIdLong());
|
||||
return commandResult;
|
||||
});
|
||||
} else {
|
||||
@@ -154,12 +277,28 @@ public class SlashCommandListenerBean extends ListenerAdapter {
|
||||
commandOutput.thenAccept(commandResult -> {
|
||||
self.executePostCommandListener(command, event, commandResult);
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Error while handling post execution of command {}", command.getConfiguration().getName(), throwable);
|
||||
log.error("Error while handling post execution of command {}", commandName, throwable);
|
||||
CommandResult commandResult = CommandResult.fromError(throwable.getMessage(), throwable);
|
||||
self.executePostCommandListener(command, event, commandResult);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleConfirmationDeletion(Long interactionId, String confirmationPayloadId, String abortPayloadId, Long serverId) {
|
||||
HashMap<Object, Object> parameters = new HashMap<>();
|
||||
parameters.put("interactionId", interactionId.toString());
|
||||
parameters.put("confirmationPayloadId", confirmationPayloadId);
|
||||
parameters.put("abortPayloadId", abortPayloadId);
|
||||
JobParameters jobParameters = JobParameters
|
||||
.builder()
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
Long confirmationTimeout = configService.getLongValueOrConfigDefault(CoreFeatureConfig.CONFIRMATION_TIMEOUT, serverId);
|
||||
Instant targetDate = Instant.now().plus(confirmationTimeout, ChronoUnit.SECONDS);
|
||||
log.info("Scheduling job to delete slash command confirmation in server {} at {}.", serverId, targetDate);
|
||||
schedulerService.executeJobWithParametersOnce("confirmationCleanupJob", "core", jobParameters, Date.from(targetDate));
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void executePostCommandListener(Command foundCommand, SlashCommandInteractionEvent event, CommandResult result) {
|
||||
|
||||
@@ -2,17 +2,20 @@ package dev.sheldan.abstracto.core.interaction.slash;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.model.database.ACommand;
|
||||
import dev.sheldan.abstracto.core.command.model.database.ACommandInAServer;
|
||||
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureConfigService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureFlagService;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.commands.Command;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.*;
|
||||
@@ -52,6 +55,9 @@ public class SlashCommandServiceBean implements SlashCommandService {
|
||||
@Autowired
|
||||
private FeatureFlagService featureFlagService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public void convertCommandConfigToCommandData(CommandConfiguration commandConfiguration, List<Pair<List<CommandConfiguration>, SlashCommandData>> existingCommands, Long serverId) {
|
||||
boolean isTemplated = commandConfiguration.isTemplated();
|
||||
@@ -107,6 +113,22 @@ public class SlashCommandServiceBean implements SlashCommandService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> completeConfirmableCommand(SlashCommandInteractionEvent event, String template) {
|
||||
return completeConfirmableCommand(event, template, new Object());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> completeConfirmableCommand(SlashCommandInteractionEvent event, String template, Object parameter) {
|
||||
if(event.isAcknowledged()) {
|
||||
return interactionService.replaceOriginal(template, parameter, event.getInteraction().getHook())
|
||||
.thenApply(interactionHook -> CommandResult.fromIgnored());
|
||||
} else {
|
||||
return interactionService.replyMessage(template, parameter, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromIgnored());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void convertCommandConfigToCommandData(CommandConfiguration commandConfiguration, List<Pair<List<CommandConfiguration>, SlashCommandData>> existingCommands) {
|
||||
convertCommandConfigToCommandData(commandConfiguration, existingCommands, null);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package dev.sheldan.abstracto.core.interaction.slash.listener;
|
||||
|
||||
import static dev.sheldan.abstracto.core.interaction.slash.SlashCommandListenerBean.SLASH_COMMAND_CONFIRMATION_ORIGIN;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.features.CoreFeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListener;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerModel;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerResult;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandListenerBean;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.payload.SlashCommandConfirmationPayload;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SlashCommandConfirmationGivenButtonListener implements ButtonClickedListener {
|
||||
|
||||
@Autowired
|
||||
private SlashCommandListenerBean slashCommandListenerBean;
|
||||
|
||||
|
||||
@Override
|
||||
public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) {
|
||||
SlashCommandConfirmationPayload payload = (SlashCommandConfirmationPayload) model.getDeserializedPayload();
|
||||
if(payload.getAction().equals(SlashCommandConfirmationPayload.CommandConfirmationAction.CONFIRM)) {
|
||||
slashCommandListenerBean.continueSlashCommand(payload.getInteractionId(), model.getEvent());
|
||||
return ButtonClickedListenerResult.ACKNOWLEDGED;
|
||||
} else {
|
||||
return ButtonClickedListenerResult.IGNORED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean handlesEvent(ButtonClickedListenerModel model) {
|
||||
return model.getOrigin().equals(SLASH_COMMAND_CONFIRMATION_ORIGIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return CoreFeatureDefinition.CORE_FEATURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPriority() {
|
||||
return ListenerPriority.HIGHEST;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.core.interaction.slash.parameter.provider.SlashComm
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.emoji.Emoji;
|
||||
import net.dv8tion.jda.api.interactions.commands.CommandInteractionPayload;
|
||||
@@ -138,16 +139,16 @@ public class SlashCommandParameterServiceBean implements SlashCommandParameterSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEmote loadAEmoteFromString(String input, CommandInteractionPayload event) {
|
||||
Emoji emoji = loadEmoteFromString(input, event);
|
||||
public AEmote loadAEmoteFromString(String input, Guild guild) {
|
||||
Emoji emoji = loadEmoteFromString(input, guild);
|
||||
return emoteService.getFakeEmoteFromEmoji(emoji);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Emoji loadEmoteFromString(String input, CommandInteractionPayload event) {
|
||||
public Emoji loadEmoteFromString(String input, Guild guild) {
|
||||
if(StringUtils.isNumeric(input)) {
|
||||
long emoteId = Long.parseLong(input);
|
||||
return event.getGuild().getEmojiById(emoteId);
|
||||
return guild.getEmojiById(emoteId);
|
||||
}
|
||||
return Emoji.fromFormatted(input);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.sheldan.abstracto.core.interaction.slash.payload;
|
||||
|
||||
import dev.sheldan.abstracto.core.interaction.button.ButtonPayload;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class SlashCommandConfirmationPayload implements ButtonPayload {
|
||||
|
||||
private CommandConfirmationAction action;
|
||||
private Long interactionId;
|
||||
|
||||
public enum CommandConfirmationAction {
|
||||
CONFIRM, ABORT
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,8 @@ public interface InteractionService {
|
||||
CompletableFuture<InteractionHook> replyString(String text, IReplyCallback callback);
|
||||
CompletableFuture<InteractionHook> replyEmbed(String templateKey, IReplyCallback callback);
|
||||
List<CompletableFuture<Message>> sendEmbed(String templateKey, InteractionHook interactionHook);
|
||||
CompletableFuture<Message> editOriginal(MessageToSend messageToSend, InteractionHook interactionHook);
|
||||
CompletableFuture<Message> replaceOriginal(MessageToSend messageToSend, InteractionHook interactionHook);
|
||||
CompletableFuture<Message> replaceOriginal(String template, Object model, InteractionHook interactionHook);
|
||||
CompletableFuture<InteractionHook> replyMessageToSend(MessageToSend messageToSend, IReplyCallback callback);
|
||||
CompletableFuture<InteractionHook> replyMessage(String templateKey, Object model, IReplyCallback callback);
|
||||
CompletableFuture<Message> replyString(String content, InteractionHook interactionHook);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package dev.sheldan.abstracto.core.interaction.slash;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.commands.Command;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
|
||||
import org.springframework.data.util.Pair;
|
||||
@@ -16,4 +18,6 @@ public interface SlashCommandService {
|
||||
CompletableFuture<Void> deleteGuildSlashCommands(Guild guild, List<Long> slashCommandId, List<Long> commandInServerIdsToUnset);
|
||||
CompletableFuture<Void> addGuildSlashCommands(Guild guild, List<Pair<List<CommandConfiguration>, SlashCommandData>> commandData);
|
||||
void storeCreatedSlashCommands(Guild guild, List<Pair<List<CommandConfiguration>, SlashCommandData>> commandData, List<Command> createdCommands);
|
||||
CompletableFuture<CommandResult> completeConfirmableCommand(SlashCommandInteractionEvent event, String template);
|
||||
CompletableFuture<CommandResult> completeConfirmableCommand(SlashCommandInteractionEvent event, String template, Object parameter);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.core.interaction.slash.parameter;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.emoji.Emoji;
|
||||
import net.dv8tion.jda.api.interactions.commands.CommandInteractionPayload;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
@@ -16,8 +17,8 @@ public interface SlashCommandParameterService {
|
||||
Object getCommandOption(String name, CommandInteractionPayload event);
|
||||
Boolean hasCommandOption(String name, CommandInteractionPayload event);
|
||||
Boolean hasCommandOptionWithFullType(String name, CommandInteractionPayload event, OptionType optionType);
|
||||
AEmote loadAEmoteFromString(String input, CommandInteractionPayload event);
|
||||
Emoji loadEmoteFromString(String input, CommandInteractionPayload event);
|
||||
AEmote loadAEmoteFromString(String input, Guild guild);
|
||||
Emoji loadEmoteFromString(String input, Guild guild);
|
||||
List<OptionType> getTypesFromParameter(Parameter parameter);
|
||||
List<OptionType> getTypesFromParameter(Class clazz);
|
||||
String getFullQualifiedParameterName(String name, OptionType type);
|
||||
|
||||
Reference in New Issue
Block a user