mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-14 19:56:29 +00:00
[AB-60] added java doc for statistic module, added feature mode limitations to emote listener, replaced redundant Embeddable with ServerSpecificId
This commit is contained in:
@@ -4,6 +4,9 @@ import dev.sheldan.abstracto.core.command.config.ModuleInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleInterface;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Help module for all statistics related commands, they have their own module if they have a significant emount of commands on their own.
|
||||
*/
|
||||
@Component
|
||||
public class StatisticModule implements ModuleInterface {
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
@@ -18,6 +18,9 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command completely deletes one individual {@link TrackedEmote} and all of its usages from the database. This command cannot be undone.
|
||||
*/
|
||||
@Component
|
||||
public class DeleteTrackedEmote extends AbstractConditionableCommand {
|
||||
|
||||
@@ -32,6 +35,7 @@ public class DeleteTrackedEmote extends AbstractConditionableCommand {
|
||||
checkParameters(commandContext);
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
|
||||
// need to actually load the TrackedEmote
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
|
||||
trackedEmoteService.deleteTrackedEmote(trackedEmote);
|
||||
return CommandResult.fromSuccess();
|
||||
@@ -44,7 +48,7 @@ public class DeleteTrackedEmote extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("deleteTrackedEmote")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -10,7 +10,7 @@ import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -24,6 +24,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* This command will show the emote statistics for all deleted emotes in the current server. There is an optional
|
||||
* {@link Duration} parameter, which will define the amount of time to retrieve the stats for. If not provided, all stats will be shown.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DeletedEmoteStats extends AbstractConditionableCommand {
|
||||
@@ -41,21 +45,26 @@ public class DeletedEmoteStats extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
checkParameters(commandContext);
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// default is 1.1.1970
|
||||
Instant statsSince = Instant.EPOCH;
|
||||
if(!parameters.isEmpty()) {
|
||||
// if a duration parameter is available, subtract the current time of this to get the true Instant
|
||||
Duration duration = (Duration) parameters.get(0);
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getDeletedEmoteStatsForServerSince(commandContext.getUserInitiatedContext().getServer(), statsSince);
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
// only show the embed, if there are static emotes to show
|
||||
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
|
||||
log.trace("Deleted emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, emoteStatsModel, commandContext.getChannel()));
|
||||
}
|
||||
// only show the embed, if there are animated emotes to show
|
||||
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
|
||||
log.trace("Deleted emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_DELETED_RESPONSE, emoteStatsModel, commandContext.getChannel()));
|
||||
}
|
||||
// if neither static nor animated emote stats are available, show an embed indicating so
|
||||
if(!emoteStatsModel.areStatsAvailable()) {
|
||||
log.info("No delete emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
|
||||
@@ -72,7 +81,7 @@ public class DeletedEmoteStats extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("deletedEmoteStats")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
@@ -18,6 +18,9 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command disables the tracking for either one {@link TrackedEmote} or for all of them, if no emote is given as a parameter
|
||||
*/
|
||||
@Component
|
||||
public class DisableEmoteTracking extends AbstractConditionableCommand {
|
||||
|
||||
@@ -33,6 +36,7 @@ public class DisableEmoteTracking extends AbstractConditionableCommand {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
if(!parameters.isEmpty()) {
|
||||
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
|
||||
// need to reload the tracked emote
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
|
||||
trackedEmoteManagementService.disableTrackedEmote(trackedEmote);
|
||||
} else {
|
||||
@@ -48,7 +52,7 @@ public class DisableEmoteTracking extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("disableEmoteTracking")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -8,10 +8,9 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureModeService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -25,6 +24,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* This command displays the emote stats for the current {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote} within the
|
||||
* {@link net.dv8tion.jda.api.entities.Guild} the command has been executed in
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class EmoteStats extends AbstractConditionableCommand {
|
||||
@@ -35,9 +38,6 @@ public class EmoteStats extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
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";
|
||||
@@ -46,21 +46,26 @@ public class EmoteStats extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
checkParameters(commandContext);
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// default is 1.1.1970
|
||||
Instant statsSince = Instant.EPOCH;
|
||||
if(!parameters.isEmpty()) {
|
||||
// subtract the given Duration from the current point in time, if there is any
|
||||
Duration duration = (Duration) parameters.get(0);
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getActiveEmoteStatsForServerSince(commandContext.getUserInitiatedContext().getServer(), statsSince);
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
// only show embed if static emote stats are available
|
||||
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
|
||||
log.trace("Emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, emoteStatsModel, commandContext.getChannel()));
|
||||
}
|
||||
// only show embed if animated emote stats are available
|
||||
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
|
||||
log.trace("Emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, emoteStatsModel, commandContext.getChannel()));
|
||||
}
|
||||
// show an embed if no emote stats are available indicating so
|
||||
if(!emoteStatsModel.areStatsAvailable()) {
|
||||
log.info("No emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
|
||||
@@ -77,7 +82,7 @@ public class EmoteStats extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("emoteStats")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -14,7 +14,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.FileUtils;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.exception.DownloadEmoteStatsFileTooBigException;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.DownloadEmoteStatsModel;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote;
|
||||
@@ -33,6 +33,13 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
||||
/**
|
||||
* This command renders a file containing information about emote statistics and provides the file as a download.
|
||||
* If the file size is over the size limit of the {@link net.dv8tion.jda.api.entities.Guild}, this command will fail, but
|
||||
* throw an {@link DownloadEmoteStatsFileTooBigException}.
|
||||
* This will create a temporary file on the server, which will be deleted after it has been send.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ExportEmoteStats extends AbstractConditionableCommand {
|
||||
@@ -61,12 +68,15 @@ public class ExportEmoteStats extends AbstractConditionableCommand {
|
||||
checkParameters(commandContext);
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Instant statsSince = Instant.EPOCH;
|
||||
// default is 1.1.1970
|
||||
if(!parameters.isEmpty()) {
|
||||
// if a duration is given, subtract this duration from the current point in time
|
||||
Duration duration = (Duration) parameters.get(0);
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
AServer actualServer = serverManagementService.loadServer(commandContext.getGuild().getIdLong());
|
||||
List<UsedEmote> usedEmotes = usedEmoteManagementService.loadEmoteUsagesForServerSince(actualServer, statsSince);
|
||||
// if there are no stats available, render a message indicating so
|
||||
if(usedEmotes.isEmpty()) {
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY, new Object(), commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
@@ -88,6 +98,7 @@ public class ExportEmoteStats extends AbstractConditionableCommand {
|
||||
try {
|
||||
fileUtils.writeContentToFile(tempFile, fileContent);
|
||||
long maxFileSize = commandContext.getGuild().getMaxFileSize();
|
||||
// in this case, we cannot upload the file, so we need to fail
|
||||
if(maxFileSize < tempFile.length()) {
|
||||
throw new DownloadEmoteStatsFileTooBigException(tempFile.length(), maxFileSize);
|
||||
}
|
||||
@@ -113,7 +124,7 @@ public class ExportEmoteStats extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("exportEmoteStats")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -9,11 +9,10 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
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.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,6 +27,10 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* This command will show the emote statistics for all emotes which are tracked in the current server, but are not from that server.
|
||||
* There is an optional {@link Duration} parameter, which will define the amount of time to retrieve the stats for. If not provided, all stats will be shown.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ExternalEmoteStats extends AbstractConditionableCommand {
|
||||
@@ -38,9 +41,6 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
public static final String EMOTE_STATS_STATIC_EXTERNAL_RESPONSE = "externalEmoteStats_static_response";
|
||||
public static final String EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE = "externalEmoteStats_animated_response";
|
||||
|
||||
@@ -48,22 +48,29 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
checkParameters(commandContext);
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// default is 1.1.1970
|
||||
Instant statsSince = Instant.EPOCH;
|
||||
if(!parameters.isEmpty()) {
|
||||
// subtract the given Duration parameter from the current point in time
|
||||
Duration duration = (Duration) parameters.get(0);
|
||||
statsSince = Instant.now().minus(duration);
|
||||
}
|
||||
EmoteStatsModel emoteStatsModel = usedEmoteService.getExternalEmoteStatsForServerSince(commandContext.getUserInitiatedContext().getServer(), statsSince);
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
|
||||
// only show embed if static emote stats are available
|
||||
if(!emoteStatsModel.getStaticEmotes().isEmpty()) {
|
||||
log.trace("External emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, emoteStatsModel, commandContext.getChannel()));
|
||||
}
|
||||
|
||||
// only show embed if animated emote stats are available
|
||||
if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) {
|
||||
log.trace("External emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE, emoteStatsModel, commandContext.getChannel()));
|
||||
}
|
||||
|
||||
// show an embed if no emote stats are available indicating so
|
||||
if(!emoteStatsModel.areStatsAvailable()) {
|
||||
log.info("No external emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince);
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
|
||||
@@ -80,7 +87,7 @@ public class ExternalEmoteStats extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("externalEmoteStats")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
@@ -20,6 +20,10 @@ import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command will delete the instances of {@link dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote} of a given {@link TrackedEmote}
|
||||
* for the desired {@link Duration}, or all of them. This command cannot be undone.
|
||||
*/
|
||||
@Component
|
||||
public class PurgeEmoteStats extends AbstractConditionableCommand {
|
||||
|
||||
@@ -35,8 +39,10 @@ public class PurgeEmoteStats extends AbstractConditionableCommand {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
|
||||
// default 1.1.1970
|
||||
Instant since = Instant.EPOCH;
|
||||
if(parameters.size() > 1) {
|
||||
// if a Duration is given, subtract it from the current point in time
|
||||
Duration parameter = (Duration) parameters.get(1);
|
||||
since = Instant.now().minus(parameter);
|
||||
}
|
||||
@@ -52,7 +58,7 @@ public class PurgeEmoteStats extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("purgeEmoteStats")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -16,6 +16,10 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command removes all {@link dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote} instances
|
||||
* and all {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote} in a guild. This command cannot be undone.
|
||||
*/
|
||||
@Component
|
||||
public class ResetEmoteStats extends AbstractConditionableCommand {
|
||||
|
||||
@@ -34,7 +38,7 @@ public class ResetEmoteStats extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("resetEmoteStats")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -12,8 +12,8 @@ import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -24,6 +24,10 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* This command is used to show the image and provide the link of an external {@link TrackedEmote}. It is only available, if the
|
||||
* EmoteTrackingMode.EXTERNAL_EMOTES is active.
|
||||
*/
|
||||
@Component
|
||||
public class ShowExternalTrackedEmote extends AbstractConditionableCommand {
|
||||
|
||||
@@ -39,7 +43,9 @@ public class ShowExternalTrackedEmote extends AbstractConditionableCommand {
|
||||
checkParameters(commandContext);
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
|
||||
// load the actual TrackedEmote instance
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
|
||||
// the command only works for external emotes
|
||||
if(!trackedEmote.getExternal()) {
|
||||
throw new AbstractoTemplatedException("Emote is not external", "showExternalTrackedEmote_emote_is_not_external");
|
||||
}
|
||||
@@ -54,7 +60,7 @@ public class ShowExternalTrackedEmote extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("showExternalTrackedEmote")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -11,8 +11,8 @@ 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.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
@@ -23,6 +23,11 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* This command gives an overview over all {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote} in a guild.
|
||||
* It will not show external emotes, if the feature mode EmoteTrackingMode.EXTERNAL_EMOTES is disabled. There is a parameter to also show
|
||||
* emotes for which the tracking has been disabled
|
||||
*/
|
||||
@Component
|
||||
public class ShowTrackedEmotes extends AbstractConditionableCommand {
|
||||
|
||||
@@ -47,43 +52,59 @@ public class ShowTrackedEmotes extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
checkParameters(commandContext);
|
||||
|
||||
// per default, do not show TrackedEmote for which tracking has been disabled
|
||||
Boolean showTrackingDisabled = false;
|
||||
if(!commandContext.getParameters().getParameters().isEmpty()) {
|
||||
showTrackingDisabled = (Boolean) commandContext.getParameters().getParameters().get(0);
|
||||
}
|
||||
|
||||
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, commandContext.getGuild().getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
|
||||
|
||||
TrackedEmoteOverview trackedEmoteOverview = trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), showTrackingDisabled);
|
||||
boolean noStatsAvailable = true;
|
||||
boolean noTrackedEmotesAvailable = true;
|
||||
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
|
||||
// only show the embed, if there are static tracked emotes
|
||||
if(!trackedEmoteOverview.getStaticEmotes().isEmpty()) {
|
||||
noStatsAvailable = false;
|
||||
noTrackedEmotesAvailable = false;
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
|
||||
}
|
||||
|
||||
// only show the embed if there are animated tracked emotes
|
||||
if(!trackedEmoteOverview.getAnimatedEmotes().isEmpty()) {
|
||||
noStatsAvailable = false;
|
||||
noTrackedEmotesAvailable = false;
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
|
||||
}
|
||||
|
||||
// only show the embed, if there are deleted static emotes
|
||||
if(!trackedEmoteOverview.getDeletedStaticEmotes().isEmpty()) {
|
||||
noStatsAvailable = false;
|
||||
noTrackedEmotesAvailable = false;
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
|
||||
}
|
||||
|
||||
// only show the embed, if there are deleted animated emotes
|
||||
if(!trackedEmoteOverview.getDeletedAnimatedEmotes().isEmpty()) {
|
||||
noStatsAvailable = false;
|
||||
noTrackedEmotesAvailable = false;
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
|
||||
}
|
||||
|
||||
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, commandContext.getGuild().getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
|
||||
|
||||
// only show external emotes if external emotes are enabled
|
||||
if(externalTrackingEnabled) {
|
||||
|
||||
// only show the embed if there are external static emotes
|
||||
if(!trackedEmoteOverview.getExternalStaticEmotes().isEmpty()) {
|
||||
noStatsAvailable = false;
|
||||
noTrackedEmotesAvailable = false;
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
|
||||
}
|
||||
|
||||
// only show the embed if there are external animated emotes
|
||||
if(!trackedEmoteOverview.getExternalAnimatedEmotes().isEmpty()) {
|
||||
noStatsAvailable = false;
|
||||
noTrackedEmotesAvailable = false;
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
|
||||
}
|
||||
}
|
||||
if(noStatsAvailable) {
|
||||
|
||||
// if there are no tracked emotes available, show an embed indicating so
|
||||
if(noTrackedEmotesAvailable) {
|
||||
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
|
||||
}
|
||||
return FutureUtils.toSingleFutureGeneric(messagePromises)
|
||||
@@ -97,7 +118,7 @@ public class ShowTrackedEmotes extends AbstractConditionableCommand {
|
||||
parameters.add(Parameter.builder().name("showAll").templated(true).optional(true).type(Boolean.class).build());
|
||||
return CommandConfiguration.builder()
|
||||
.name("showTrackedEmotes")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -10,7 +10,7 @@ import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -20,6 +20,11 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* This command can be used to synchronize the state of {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote}
|
||||
* in the database, with the state of {@link net.dv8tion.jda.api.entities.Emote} in the {@link net.dv8tion.jda.api.entities.Guild}.
|
||||
* It will mark emotes not in the guild anymore and add emotes which are not yet tracked.
|
||||
*/
|
||||
@Component
|
||||
public class SyncTrackedEmotes extends AbstractConditionableCommand {
|
||||
|
||||
@@ -33,6 +38,7 @@ public class SyncTrackedEmotes extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
TrackedEmoteSynchronizationResult syncResult = trackedEmoteService.synchronizeTrackedEmotes(commandContext.getGuild());
|
||||
// show a result of how many emotes were deleted/added
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, syncResult, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
@@ -43,7 +49,7 @@ public class SyncTrackedEmotes extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("syncTrackedEmotes")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -11,9 +11,9 @@ import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureModeService;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.command.parameter.TrackEmoteParameter;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingModule;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
@@ -23,6 +23,10 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This command can be used to track one individual {@link TrackedEmote} newly, or set the emote to be tracked again.
|
||||
* This can either be done via providing the {@link net.dv8tion.jda.api.entities.Emote} or via ID.
|
||||
*/
|
||||
@Component
|
||||
public class TrackEmote extends AbstractConditionableCommand {
|
||||
|
||||
@@ -42,18 +46,22 @@ public class TrackEmote extends AbstractConditionableCommand {
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
checkParameters(commandContext);
|
||||
TrackEmoteParameter emoteToTrack = (TrackEmoteParameter) commandContext.getParameters().getParameters().get(0);
|
||||
Long emoteId = emoteToTrack.getTrackedEmote().getTrackedEmoteId().getEmoteId();
|
||||
Long emoteId = emoteToTrack.getTrackedEmote().getTrackedEmoteId().getId();
|
||||
long serverId = commandContext.getGuild().getIdLong();
|
||||
// if its already a tracked emote, just set the tracking_enabled flag to true
|
||||
if(trackedEmoteManagementService.trackedEmoteExists(emoteId, serverId)) {
|
||||
TrackedEmote trackedemote = trackedEmoteManagementService.loadByEmoteId(emoteId, serverId);
|
||||
trackedEmoteManagementService.enableTrackedEmote(trackedemote);
|
||||
} else if(emoteToTrack.getEmote() != null) {
|
||||
// if its a new emote, lets see if its external
|
||||
boolean external = !emoteService.emoteIsFromGuild(emoteToTrack.getEmote(), commandContext.getGuild());
|
||||
if(external) {
|
||||
// this throws an exception if the feature mode is not enabled
|
||||
featureModeService.validateActiveFeatureMode(serverId, StatisticFeatures.EMOTE_TRACKING, EmoteTrackingMode.EXTERNAL_EMOTES);
|
||||
}
|
||||
trackedEmoteService.createFakeTrackedEmote(emoteToTrack.getEmote(), commandContext.getGuild(), external);
|
||||
trackedEmoteService.createTrackedEmote(emoteToTrack.getEmote(), commandContext.getGuild(), external);
|
||||
} else {
|
||||
// in case the ID was not an existing TrackedEmote, and no Emote was given, we need to fail
|
||||
throw new IncorrectParameterException(this, getConfiguration().getParameters().get(0).getName());
|
||||
}
|
||||
return CommandResult.fromSuccess();
|
||||
@@ -66,7 +74,7 @@ public class TrackEmote extends AbstractConditionableCommand {
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("trackEmote")
|
||||
.module(StatisticModule.STATISTIC)
|
||||
.module(EmoteTrackingModule.EMOTE_TRACKING)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
|
||||
@@ -6,10 +6,21 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
|
||||
/**
|
||||
* Container class for containing both an {@link Emote} and a {@link TrackedEmote} for the purpose of a {@link dev.sheldan.abstracto.core.command.config.Parameter}.
|
||||
* This is used in {@link dev.sheldan.abstracto.statistic.emotes.command.TrackEmote} and is used as a convenience parameter, in which there
|
||||
* might both a {@link Emote} and a {@link TrackedEmote} as parameter
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class TrackEmoteParameter {
|
||||
/**
|
||||
* If an {@link Emote} has been used as parameter, this will have the appropriate value
|
||||
*/
|
||||
private Emote emote;
|
||||
/**
|
||||
* If a {@link Long} or {@link Emote} has been supplied as the parameter, this will contain a faked instance of the respective values
|
||||
*/
|
||||
private TrackedEmote trackedEmote;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* {@link CommandParameterHandler} for the {@link TrackedEmote} class. This parameter handler will only create
|
||||
* fake {@link TrackedEmote} and it has a priority a bit higher than medium.
|
||||
*/
|
||||
@Component
|
||||
public class TrackedEmoteParameterHandler implements CommandParameterHandler {
|
||||
|
||||
@@ -19,11 +23,29 @@ public class TrackedEmoteParameterHandler implements CommandParameterHandler {
|
||||
@Autowired
|
||||
private TrackedEmoteService trackedEmoteService;
|
||||
|
||||
/**
|
||||
* This {@link CommandParameterHandler} only handles {@link TrackedEmote}
|
||||
* @param clazz The desired {@link Class} of a parameter
|
||||
* @return Whether or not the given {@link Class} will be handled by this {@link CommandParameterHandler}
|
||||
*/
|
||||
@Override
|
||||
public boolean handles(Class clazz) {
|
||||
return clazz.equals(TrackedEmote.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will parse the input for potential {@link TrackedEmote} and return a fake instance of such.
|
||||
* At first it will see if there are any {@link Emote} directly in the message. If there are none at the current position
|
||||
* it will try to parse the parameter to a {@link Long}. It is *not* guaranteed that a {@link TrackedEmote} with this ID
|
||||
* really exists for this server. So, any commands using this are required to do checks on their own.
|
||||
* @param input The {@link String} input at the current position
|
||||
* @param iterators The {@link CommandParameterIterators} containing all available iterators to directly retrieve JDA related
|
||||
* entities from
|
||||
* @param clazz The {@link Class} which this type should handle
|
||||
* @param context The {@link Message} which caused the command to be executed
|
||||
* @return A faked {@link TrackedEmote} based on the given input or from {@link CommandParameterIterators} directly. This {@link TrackedEmote}
|
||||
* does not need to actually exist.
|
||||
*/
|
||||
@Override
|
||||
public Object handle(String input, CommandParameterIterators iterators, Class clazz, Message context) {
|
||||
Emote emote = (Emote) emoteParameterHandler.handle(input, iterators, Emote.class, context);
|
||||
|
||||
@@ -4,12 +4,20 @@ import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler;
|
||||
import dev.sheldan.abstracto.core.command.handler.CommandParameterIterators;
|
||||
import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler;
|
||||
import dev.sheldan.abstracto.statistic.emotes.command.parameter.TrackEmoteParameter;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* {@link CommandParameterHandler} for the {@link TrackEmoteParameter} class. It will call the
|
||||
* {@link EmoteParameterHandler} and use the returned {@link Emote} if one is available. Otherwise it will only use the
|
||||
* {@link Long} which was passed. This handler will create a fake instance for the {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote}
|
||||
* and only make the {@link Emote} available in the result, if it was passed as such. This handler has a slightly higher priority
|
||||
* than medium.
|
||||
*/
|
||||
@Component
|
||||
public class TrackedEmoteParameterParameterHandler implements CommandParameterHandler {
|
||||
|
||||
@@ -19,11 +27,28 @@ public class TrackedEmoteParameterParameterHandler implements CommandParameterHa
|
||||
@Autowired
|
||||
private TrackedEmoteService trackedEmoteService;
|
||||
|
||||
/**
|
||||
* This {@link CommandParameterHandler} only handles {@link TrackEmoteParameter}
|
||||
* @param clazz The desired {@link Class} of a parameter
|
||||
* @return Whether or not the given {@link Class} will be handled by this {@link CommandParameterHandler}
|
||||
*/
|
||||
@Override
|
||||
public boolean handles(Class clazz) {
|
||||
return clazz.equals(TrackEmoteParameter.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This tries to parse the input and extract an {@link Emote} or just an {@link Long}. It uses a {@link EmoteParameterHandler} at first,
|
||||
* and if nothing is found tries to parse the {@link Long} directly from the input. In case an {@link Emote} was used, this will populate the
|
||||
* respective member variable in {@link TrackEmoteParameter}.
|
||||
* @param input The {@link String} input at the current position
|
||||
* @param iterators The {@link CommandParameterIterators} containing all available iterators to directly retrieve JDA related
|
||||
* entities from
|
||||
* @param clazz The {@link Class} which this type should handle
|
||||
* @param context The {@link Message} which caused the command to be executed
|
||||
* @return An instance of {@link TrackEmoteParameter} which contains the available instances. This is an {@link Emote} in case it was
|
||||
* used directly. In every successful case, it will contain a faked {@link TrackedEmote}.
|
||||
*/
|
||||
@Override
|
||||
public Object handle(String input, CommandParameterIterators iterators, Class clazz, Message context) {
|
||||
TrackEmoteParameter parameter = TrackEmoteParameter.builder().build();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleInterface;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticModule;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Separate module just for all commands related to emote tracking.
|
||||
*/
|
||||
@Component
|
||||
public class EmoteTrackingModule implements ModuleInterface {
|
||||
public static final String EMOTE_TRACKING = "emoteTracking";
|
||||
|
||||
@Override
|
||||
public ModuleInfo getInfo() {
|
||||
return ModuleInfo.builder().name(EMOTE_TRACKING).description("Module containing commands related to emote tracking.").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentModule() {
|
||||
return StatisticModule.STATISTIC;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,11 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Component to convert from a {@link EmoteStatsResult} to a proper instance of {@link EmoteStatsModel}.
|
||||
* This for example loads the relevant {@link Emote} to be used within the model and also splits it up
|
||||
* into static and animated emotes
|
||||
*/
|
||||
@Component
|
||||
public class EmoteStatsConverter {
|
||||
|
||||
@@ -24,15 +29,18 @@ public class EmoteStatsConverter {
|
||||
|
||||
public EmoteStatsModel fromEmoteStatsResults(List<EmoteStatsResult> resultList) {
|
||||
if(resultList.isEmpty()) {
|
||||
// no stats are available, do nothing
|
||||
return EmoteStatsModel.builder().build();
|
||||
}
|
||||
// it is assumed all emotes are tracked in the same server
|
||||
Guild relevantGuild = botService.getGuildById(resultList.get(0).getServerId());
|
||||
EmoteStatsModel resultingModel = EmoteStatsModel.builder().build();
|
||||
resultList.forEach(emoteStatsResult -> {
|
||||
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmoteId(emoteStatsResult.getEmoteId(), emoteStatsResult.getServerId());
|
||||
Emote loadedEmote = null;
|
||||
// if the emote should still exist, we try to load it
|
||||
if(!trackedEmote.getExternal() && !trackedEmote.getDeleted()) {
|
||||
loadedEmote = relevantGuild.getEmoteById(trackedEmote.getTrackedEmoteId().getEmoteId());
|
||||
loadedEmote = relevantGuild.getEmoteById(trackedEmote.getTrackedEmoteId().getId());
|
||||
}
|
||||
EmoteStatsResultDisplay display = EmoteStatsResultDisplay
|
||||
.builder()
|
||||
|
||||
@@ -18,6 +18,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Job responsible for persisting the emote usages found in {@link TrackedEmoteRuntimeService} to the database.
|
||||
* This will create new instances, if there are non before, and increment past instances. This job runs for all servers globally.
|
||||
*/
|
||||
@Slf4j
|
||||
@DisallowConcurrentExecution
|
||||
@Component
|
||||
@@ -33,24 +37,30 @@ public class EmotePersistingJob extends QuartzJobBean {
|
||||
@Override
|
||||
@Transactional
|
||||
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
// acquire the lock, because we are modifying
|
||||
trackedEmoteRuntimeService.takeLock();
|
||||
Long pastMinute = getPastMinute();
|
||||
Map<Long, Map<Long, List<PersistingEmote>>> runtimeConfig = trackedEmoteRuntimeService.getRuntimeConfig();
|
||||
try {
|
||||
Map<Long, Map<Long, List<PersistingEmote>>> runtimeConfig = trackedEmoteRuntimeService.getRuntimeConfig();
|
||||
log.info("Running statistic persisting job.");
|
||||
Long pastMinute = getPastMinute();
|
||||
// only take the emotes from the last minute, if there are any
|
||||
if(runtimeConfig.containsKey(pastMinute)) {
|
||||
Map<Long, List<PersistingEmote>> foundStatistics = runtimeConfig.get(pastMinute);
|
||||
log.info("Found emote statistics from {} servers to persist.", foundStatistics.size());
|
||||
trackedEmoteService.storeEmoteStatistics(foundStatistics);
|
||||
runtimeConfig.remove(pastMinute);
|
||||
// remove it, because we processed it
|
||||
// check for earlier entries which were missed
|
||||
checkForPastEmoteStats(pastMinute, runtimeConfig);
|
||||
}
|
||||
} finally {
|
||||
runtimeConfig.remove(pastMinute);
|
||||
// release the lock, so other listeners can add onto it again
|
||||
trackedEmoteRuntimeService.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForPastEmoteStats(Long minuteToCheck, Map<Long, Map<Long, List<PersistingEmote>>> runtimeConfig) {
|
||||
// if there are any keys which have a lower minute, we need to process them, because they most likely have not been processed yet
|
||||
List<Long> missedMinutes = runtimeConfig.keySet().stream().filter(aLong -> aLong < minuteToCheck).collect(Collectors.toList());
|
||||
missedMinutes.forEach(pastMinute -> {
|
||||
log.info("Persisting emotes for a minute in the past, it should have been previously, but was not. Minute {}.", pastMinute);
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||
import dev.sheldan.abstracto.core.listener.EmoteCreatedListener;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This listener listens for created {@link Emote} in a {@link net.dv8tion.jda.api.entities.Guild} and creates appropriate
|
||||
* {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote}, if the EMOTE_TRACKING feature is enabled and the AUTO_TRACK
|
||||
* feature mode as well.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class CreateTrackedEmoteListener implements EmoteCreatedListener {
|
||||
@@ -33,4 +43,9 @@ public class CreateTrackedEmoteListener implements EmoteCreatedListener {
|
||||
public Integer getPriority() {
|
||||
return ListenerPriority.MEDIUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(EmoteTrackingMode.AUTO_TRACK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||
import dev.sheldan.abstracto.core.listener.EmoteDeletedListener;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This listener listens for deleted {@link Emote} in a {@link net.dv8tion.jda.api.entities.Guild} and markes respective
|
||||
* {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote} as deleted, if the EMOTE_TRACKING feature is enabled and the AUTO_TRACK
|
||||
* feature mode as well.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DeleteTrackedEmoteListener implements EmoteDeletedListener {
|
||||
@@ -32,4 +42,9 @@ public class DeleteTrackedEmoteListener implements EmoteDeletedListener {
|
||||
public Integer getPriority() {
|
||||
return ListenerPriority.MEDIUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(EmoteTrackingMode.AUTO_TRACK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This listener listens to every received message, if the EMOTE_TRACKING feature is enabled, and stores *all* used emotes in
|
||||
* the runtime storage for emote tracking.
|
||||
*/
|
||||
@Component
|
||||
public class EmoteTrackingListener implements MessageReceivedListener {
|
||||
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureEnum;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||
import dev.sheldan.abstracto.core.listener.EmoteUpdatedListener;
|
||||
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
|
||||
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This listener listens for emote name changes and appropriately updates the name of the {@link TrackedEmote} in the database,
|
||||
* if the emote is tracked. This is only executed if the EMOTE_TRACKING feature is enabled,and if the AUTO_TRACK feature mode is enabled.
|
||||
*/
|
||||
@Component
|
||||
public class UpdateTrackedEmoteListener implements EmoteUpdatedListener {
|
||||
|
||||
@@ -31,4 +40,9 @@ public class UpdateTrackedEmoteListener implements EmoteUpdatedListener {
|
||||
public Integer getPriority() {
|
||||
return ListenerPriority.MEDIUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(EmoteTrackingMode.AUTO_TRACK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.model;
|
||||
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class DownloadEmoteStatsModel {
|
||||
private Guild guild;
|
||||
private Instant downloadDate;
|
||||
private Instant statsSince;
|
||||
private Member requester;
|
||||
private List<UsedEmote> emotes;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerSpecificId;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.QueryHints;
|
||||
import org.springframework.stereotype.Repository;
|
||||
@@ -9,14 +9,35 @@ import org.springframework.stereotype.Repository;
|
||||
import javax.persistence.QueryHint;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository responsible for database operations on {@link TrackedEmote}
|
||||
*/
|
||||
@Repository
|
||||
public interface TrackedEmoteRepository extends JpaRepository<TrackedEmote, TrackedEmoteServer> {
|
||||
public interface TrackedEmoteRepository extends JpaRepository<TrackedEmote, ServerSpecificId> {
|
||||
/**
|
||||
* Retrieves all {@link TrackedEmote} from a {@link dev.sheldan.abstracto.core.models.database.AServer} via the ID
|
||||
* which are not deleted and not external
|
||||
* @param serverId The ID of the {@link dev.sheldan.abstracto.core.models.database.AServer} to retrieve the {@link TrackedEmote} for
|
||||
* @return A list of {@link TrackedEmote} from the {@link dev.sheldan.abstracto.core.models.database.AServer} identified by ID, which are not deleted or external
|
||||
*/
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
List<TrackedEmote> findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(Long serverId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link TrackedEmote} from a {@link dev.sheldan.abstracto.core.models.database.AServer} via the ID
|
||||
* which have their tracking enabled
|
||||
* @param serverId The ID of the {@link dev.sheldan.abstracto.core.models.database.AServer} to retrieve the {@link TrackedEmote} for
|
||||
* @return A list of {@link TrackedEmote} from the {@link dev.sheldan.abstracto.core.models.database.AServer} identified by ID, which have their tracking enabled
|
||||
*/
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
List<TrackedEmote> findByTrackedEmoteId_ServerIdAndTrackingEnabledTrue(Long serverId);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves all {@link TrackedEmote} from a {@link dev.sheldan.abstracto.core.models.database.AServer} via the ID
|
||||
* @param serverId The ID of the {@link dev.sheldan.abstracto.core.models.database.AServer} to retrieve the {@link TrackedEmote} for
|
||||
* @return A list of {@link TrackedEmote} from the {@link dev.sheldan.abstracto.core.models.database.AServer} identified by ID
|
||||
*/
|
||||
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
|
||||
List<TrackedEmote> findByTrackedEmoteId_ServerId(Long serverId);
|
||||
}
|
||||
|
||||
@@ -12,9 +12,20 @@ import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Repository used to query and created {@link UsedEmote}. This also includes query for the emote statistics.
|
||||
*/
|
||||
@Repository
|
||||
public interface UsedEmoteRepository extends JpaRepository<UsedEmote, UsedEmoteDay> {
|
||||
|
||||
/**
|
||||
* Selects the {@link UsedEmote} for one particular {@link dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote}
|
||||
* for the current date.
|
||||
* @param emoteId The ID of the {@link net.dv8tion.jda.api.entities.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 {@link net.dv8tion.jda.api.entities.Emote}
|
||||
* is being tracked
|
||||
* @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)
|
||||
|
||||
@@ -7,22 +7,50 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Component actually containing the data structure containing the runtime storage for emote statistics.
|
||||
*/
|
||||
@Component
|
||||
public class TrackedEmoteRunTimeStorage {
|
||||
/**
|
||||
* A map of *minutes* containing a map of server_ids containing a list of {@link PersistingEmote}, which contains
|
||||
* all necessary information about the emotes which were used.
|
||||
* The top most map contains all the different minutes in which there were used emotes. Mostly this
|
||||
* map will not contain many keys, because the {@link dev.sheldan.abstracto.statistic.emotes.job.EmotePersistingJob}
|
||||
* will remove them a minute later. The Map within the current minute will contain every server as a key in which
|
||||
* there were emotes used in the particular minute. {@link PersistingEmote} does not contain any JDA related objects
|
||||
* but only the information necessary to identify any {@link net.dv8tion.jda.api.entities.Emote}.
|
||||
*/
|
||||
private HashMap<Long, Map<Long, List<PersistingEmote>>> trackedEmotes = new HashMap<>();
|
||||
|
||||
public Map<Long, Map<Long, List<PersistingEmote>>> getRuntimeConfig() {
|
||||
return trackedEmotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the minute has already been tracked.
|
||||
* @param key The minute since 1970 to check for
|
||||
* @return Whether or not the minute already has an entry
|
||||
*/
|
||||
public boolean contains(Long key) {
|
||||
return trackedEmotes.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the minute identified by the {@link Long} since 1970 into the Map, with the associated Map of server_ids and
|
||||
* {@link PersistingEmote}.
|
||||
* @param key The minute since 1970 to add
|
||||
* @param objectToPut The Map of server_ids mapping to List of {@link PersistingEmote} toa dd
|
||||
*/
|
||||
public void put(Long key, Map<Long, List<PersistingEmote>> objectToPut) {
|
||||
trackedEmotes.put(key, objectToPut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entry identified by the minute since 1970
|
||||
* @param key The key of the minute to retrieve
|
||||
* @return The Map of server_ids and {@link PersistingEmote} which already exists for the given minute
|
||||
*/
|
||||
public Map<Long, List<PersistingEmote>> get(Long key) {
|
||||
return trackedEmotes.get(key);
|
||||
}
|
||||
|
||||
@@ -34,25 +34,33 @@ public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeServic
|
||||
public void addEmoteForServer(Emote emote, Guild guild, Long count, boolean external) {
|
||||
takeLock();
|
||||
try {
|
||||
// generate an appropriate key
|
||||
Long key = getKey();
|
||||
// create a PersistingEmote based the given Emote
|
||||
PersistingEmote newPersistentEmote = createFromEmote(guild, emote, count, external);
|
||||
if (trackedEmoteRunTimeStorage.contains(key)) {
|
||||
// if it already exists, we can add to the already existing map
|
||||
Map<Long, List<PersistingEmote>> elementsForKey = trackedEmoteRunTimeStorage.get(key);
|
||||
if (elementsForKey.containsKey(guild.getIdLong())) {
|
||||
// if the server already has an entry, we can just add it to the list of existing ones
|
||||
List<PersistingEmote> persistingEmotes = elementsForKey.get(guild.getIdLong());
|
||||
Optional<PersistingEmote> existingEmote = persistingEmotes
|
||||
.stream()
|
||||
.filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getIdLong()))
|
||||
.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);
|
||||
}
|
||||
} else {
|
||||
// it did not exist for the server, create a new list of PersistingEmote
|
||||
log.trace("Adding emote {} to list of server {}.", newPersistentEmote.getEmoteId(), guild.getIdLong());
|
||||
elementsForKey.put(guild.getIdLong(), new ArrayList<>(Arrays.asList(newPersistentEmote)));
|
||||
}
|
||||
} else {
|
||||
// no entry for the minute exists yet, add a new one
|
||||
HashMap<Long, List<PersistingEmote>> serverEmotes = new HashMap<>();
|
||||
serverEmotes.put(guild.getIdLong(), new ArrayList<>(Arrays.asList(newPersistentEmote)));
|
||||
log.trace("Adding emote map entry for server {}.", guild.getIdLong());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerSpecificId;
|
||||
import dev.sheldan.abstracto.core.service.BotService;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureModeService;
|
||||
@@ -10,7 +11,6 @@ import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
|
||||
import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -52,6 +52,7 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
|
||||
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
|
||||
emotes.forEach(emote -> {
|
||||
boolean emoteIsFromGuild = emoteService.emoteIsFromGuild(emote, guild);
|
||||
// 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 || emoteIsFromGuild) {
|
||||
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, !emoteIsFromGuild);
|
||||
}
|
||||
@@ -62,6 +63,7 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
|
||||
public void addEmoteToRuntimeStorage(Emote emote, Guild guild, Long count) {
|
||||
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
|
||||
boolean emoteIsFromGuild = emoteService.emoteIsFromGuild(emote, guild);
|
||||
// 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 || emoteIsFromGuild) {
|
||||
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, !emoteIsFromGuild);
|
||||
}
|
||||
@@ -77,36 +79,41 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
|
||||
persistingEmotes.forEach(persistingEmote -> {
|
||||
Optional<TrackedEmote> emoteOptional = trackedEmoteManagementService.loadByEmoteIdOptional(persistingEmote.getEmoteId(), serverId);
|
||||
emoteOptional.ifPresent(trackedEmote -> {
|
||||
// only track the record, if its enabled
|
||||
if(trackedEmote.getTrackingEnabled()) {
|
||||
Optional<UsedEmote> existingUsedEmote = usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote);
|
||||
// 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());
|
||||
}
|
||||
} else {
|
||||
log.trace("Tracking disabled for emote {} in server {}.", trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId());
|
||||
log.trace("Tracking disabled for emote {} in server {}.", trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId());
|
||||
}
|
||||
});
|
||||
if(!emoteOptional.isPresent()) {
|
||||
createNewTrackedEmote(serverId, autoTrackExternalEmotes, trackExternalEmotes, persistingEmote);
|
||||
// if tracked emote does not exists, 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) {
|
||||
createNewTrackedEmote(serverId, persistingEmote);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void createNewTrackedEmote(Long serverId, boolean autoTrackExternalEmotes, boolean trackExternalEmotes, PersistingEmote persistingEmote) {
|
||||
/**
|
||||
* Creates a new {@link TrackedEmote} from the given {@link PersistingEmote}.
|
||||
* @param serverId The ID of the {@link dev.sheldan.abstracto.core.models.database.AServer} for which the {@link TrackedEmote} should be created for
|
||||
* @param persistingEmote The {@link PersistingEmote} which contains all information necessary to create a {@link TrackedEmote}
|
||||
*/
|
||||
private void createNewTrackedEmote(Long serverId, PersistingEmote persistingEmote) {
|
||||
Optional<Guild> guildOptional = botService.getGuildByIdOptional(serverId);
|
||||
guildOptional.ifPresent(guild -> {
|
||||
Emote emoteFromGuild = guild.getEmoteById(persistingEmote.getEmoteId());
|
||||
if(emoteFromGuild != null) {
|
||||
TrackedEmote newCreatedTrackedEmote = trackedEmoteManagementService.createTrackedEmote(emoteFromGuild, guild);
|
||||
usedEmoteManagementService.createEmoteUsageForToday(newCreatedTrackedEmote, persistingEmote.getCount());
|
||||
} else if(autoTrackExternalEmotes && trackExternalEmotes){
|
||||
TrackedEmote newCreatedTrackedEmote = trackedEmoteManagementService.createExternalEmote(persistingEmote);
|
||||
usedEmoteManagementService.createEmoteUsageForToday(newCreatedTrackedEmote, persistingEmote.getCount());
|
||||
}
|
||||
TrackedEmote newCreatedTrackedEmote = trackedEmoteManagementService.createExternalTrackedEmote(persistingEmote);
|
||||
usedEmoteManagementService.createEmoteUsageForToday(newCreatedTrackedEmote, persistingEmote.getCount());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -116,10 +123,10 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedEmote getFakeTrackedEmote(Long id, Guild guild) {
|
||||
public TrackedEmote getFakeTrackedEmote(Long emoteId, Guild guild) {
|
||||
return TrackedEmote
|
||||
.builder()
|
||||
.trackedEmoteId(new TrackedEmoteServer(id, guild.getIdLong()))
|
||||
.trackedEmoteId(new ServerSpecificId(guild.getIdLong(), emoteId))
|
||||
.fake(true)
|
||||
.build();
|
||||
}
|
||||
@@ -130,21 +137,26 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
|
||||
Long addedEmotes = 0L;
|
||||
List<Emote> allExistingEmotes = guild.getEmotes();
|
||||
log.info("Synchronizing emotes for server {}, currently tracked emotes {}, available emotes for server {}.", guild.getIdLong(), activeTrackedEmotes.size(), allExistingEmotes.size());
|
||||
// iterate over all emotes currently available in the guild
|
||||
for (Emote emote : allExistingEmotes) {
|
||||
// find the emote in the list of known TrackedEmote
|
||||
Optional<TrackedEmote> trackedEmoteOptional = activeTrackedEmotes
|
||||
.stream()
|
||||
.filter(trackedEmote ->
|
||||
trackedEmote.getTrackedEmoteId().getEmoteId().equals(emote.getIdLong())
|
||||
trackedEmote.getTrackedEmoteId().getId().equals(emote.getIdLong())
|
||||
&& trackedEmote.getTrackedEmoteId().getServerId().equals(guild.getIdLong()))
|
||||
.findFirst();
|
||||
// if its not present, create it
|
||||
if (!trackedEmoteOptional.isPresent()) {
|
||||
trackedEmoteManagementService.createTrackedEmote(emote, guild);
|
||||
addedEmotes++;
|
||||
} else {
|
||||
// if we know it, remove it from the current tracked emotes
|
||||
activeTrackedEmotes.remove(trackedEmoteOptional.get());
|
||||
}
|
||||
}
|
||||
|
||||
// the ones which are still around here, were not found in the emotes retrieved from the guild, we can mark them as deleted
|
||||
activeTrackedEmotes.forEach(trackedEmote ->
|
||||
trackedEmoteManagementService.markAsDeleted(trackedEmote)
|
||||
);
|
||||
@@ -171,13 +183,13 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedEmote createFakeTrackedEmote(Emote emote, Guild guild) {
|
||||
public TrackedEmote createTrackedEmote(Emote emote, Guild guild) {
|
||||
boolean external = !emoteService.emoteIsFromGuild(emote, guild);
|
||||
return createFakeTrackedEmote(emote, guild, external);
|
||||
return createTrackedEmote(emote, guild, external);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedEmote createFakeTrackedEmote(Emote emote, Guild guild, boolean external) {
|
||||
public TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external) {
|
||||
return trackedEmoteManagementService.createTrackedEmote(emote, guild, external);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public class UsedEmoteServiceBean implements UsedEmoteService {
|
||||
|
||||
@Override
|
||||
public void purgeEmoteUsagesSince(TrackedEmote emote, Instant since) {
|
||||
log.info("Purging emote {} in server {} since {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId(), since);
|
||||
log.info("Purging emote {} in server {} since {}.", emote.getTrackedEmoteId().getId(), emote.getTrackedEmoteId().getServerId(), since);
|
||||
usedEmoteManagementService.purgeEmoteUsagesSince(emote, since.truncatedTo(ChronoUnit.DAYS));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package dev.sheldan.abstracto.statistic.emotes.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerSpecificId;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
|
||||
import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer;
|
||||
import dev.sheldan.abstracto.statistic.emotes.repository.TrackedEmoteRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
@@ -40,7 +40,7 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
|
||||
@Override
|
||||
public TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external) {
|
||||
if(external) {
|
||||
return createExternalEmote(emote, guild);
|
||||
return createExternalTrackedEmote(emote, guild);
|
||||
} else {
|
||||
return createTrackedEmote(emote, guild);
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
|
||||
TrackedEmote emote = TrackedEmote
|
||||
.builder()
|
||||
.animated(animated)
|
||||
.trackedEmoteId(new TrackedEmoteServer(emoteId, server.getId()))
|
||||
.trackedEmoteId(new ServerSpecificId(server.getId(), emoteId))
|
||||
.trackingEnabled(tracked)
|
||||
.emoteName(emoteName)
|
||||
.server(server)
|
||||
@@ -63,11 +63,11 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedEmote createExternalEmote(Long emoteId, String emoteName, String externalUrl, Boolean animated, AServer server) {
|
||||
public TrackedEmote createExternalEmote(Long emoteId, String emoteName, String externalUrl, Boolean animated, AServer server, boolean trackingEnabled) {
|
||||
TrackedEmote emote = TrackedEmote
|
||||
.builder()
|
||||
.animated(animated)
|
||||
.trackedEmoteId(new TrackedEmoteServer(emoteId, server.getId()))
|
||||
.trackedEmoteId(new ServerSpecificId(server.getId(), emoteId))
|
||||
.trackingEnabled(true)
|
||||
.deleted(false)
|
||||
.emoteName(emoteName)
|
||||
@@ -85,15 +85,15 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedEmote createExternalEmote(PersistingEmote persistingEmote) {
|
||||
public TrackedEmote createExternalTrackedEmote(PersistingEmote persistingEmote) {
|
||||
AServer server = serverManagementService.loadServer(persistingEmote.getServerId());
|
||||
return createExternalEmote(persistingEmote.getEmoteId(), persistingEmote.getEmoteName(), persistingEmote.getExternalUrl(), persistingEmote.getAnimated(), server);
|
||||
return createExternalEmote(persistingEmote.getEmoteId(), persistingEmote.getEmoteName(), persistingEmote.getExternalUrl(), persistingEmote.getAnimated(), server, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedEmote createExternalEmote(Emote emote, Guild guild) {
|
||||
public TrackedEmote createExternalTrackedEmote(Emote emote, Guild guild) {
|
||||
AServer server = serverManagementService.loadServer(guild.getIdLong());
|
||||
return createExternalEmote(emote.getIdLong(), emote.getName(), emote.getImageUrl(), emote.isAnimated(), server);
|
||||
return createExternalEmote(emote.getIdLong(), emote.getName(), emote.getImageUrl(), emote.isAnimated(), server, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,7 +104,7 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
|
||||
|
||||
@Override
|
||||
public void markAsDeleted(TrackedEmote trackedemote) {
|
||||
log.info("Marking tracked emote {} in server {} as deleted.", trackedemote.getTrackedEmoteId().getEmoteId(), trackedemote.getTrackedEmoteId().getServerId());
|
||||
log.info("Marking tracked emote {} in server {} as deleted.", trackedemote.getTrackedEmoteId().getId(), trackedemote.getTrackedEmoteId().getServerId());
|
||||
trackedemote.setDeleted(true);
|
||||
}
|
||||
|
||||
@@ -124,13 +124,13 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedEmote loadByTrackedEmoteServer(TrackedEmoteServer trackedEmoteServer) {
|
||||
return loadByEmoteId(trackedEmoteServer.getEmoteId(), trackedEmoteServer.getServerId());
|
||||
public TrackedEmote loadByTrackedEmoteServer(ServerSpecificId trackedEmoteServer) {
|
||||
return loadByEmoteId(trackedEmoteServer.getId(), trackedEmoteServer.getServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TrackedEmote> loadByEmoteIdOptional(Long emoteId, Long serverId) {
|
||||
return repository.findById(new TrackedEmoteServer(emoteId, serverId));
|
||||
return repository.findById(new ServerSpecificId(serverId, emoteId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,25 +154,25 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
|
||||
|
||||
@Override
|
||||
public void changeName(TrackedEmote emote, String newName) {
|
||||
log.info("Changing name of emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId());
|
||||
log.info("Changing name of emote {} in server {}.", emote.getTrackedEmoteId().getId(), emote.getTrackedEmoteId().getServerId());
|
||||
emote.setEmoteName(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableTrackedEmote(TrackedEmote emote) {
|
||||
log.info("Disabling tracking for tracked emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId());
|
||||
log.info("Disabling tracking for tracked emote {} in server {}.", emote.getTrackedEmoteId().getId(), emote.getTrackedEmoteId().getServerId());
|
||||
emote.setTrackingEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableTrackedEmote(TrackedEmote emote) {
|
||||
log.info("Enabling tracking for tracked emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId());
|
||||
log.info("Enabling tracking for tracked emote {} in server {}.", emote.getTrackedEmoteId().getId(), emote.getTrackedEmoteId().getServerId());
|
||||
emote.setTrackingEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTrackedEmote(TrackedEmote emote) {
|
||||
log.info("Deleting tracked emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId());
|
||||
log.info("Deleting tracked emote {} in server {}.", emote.getTrackedEmoteId().getId(), emote.getTrackedEmoteId().getServerId());
|
||||
repository.delete(emote);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,17 @@ public class UsedEmoteManagementServiceBean implements UsedEmoteManagementServic
|
||||
|
||||
@Override
|
||||
public Optional<UsedEmote> loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote) {
|
||||
return usedEmoteRepository.findEmoteFromServerToday(trackedEmote.getTrackedEmoteId().getEmoteId() , trackedEmote.getTrackedEmoteId().getServerId());
|
||||
return usedEmoteRepository.findEmoteFromServerToday(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count) {
|
||||
UsedEmote usedEmote = UsedEmote
|
||||
.builder()
|
||||
.emoteId(new UsedEmoteDay(trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId(), Instant.now()))
|
||||
.emoteId(new UsedEmoteDay(trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), Instant.now()))
|
||||
.amount(count)
|
||||
.build();
|
||||
log.trace("Creating emote usage for emote {} in server {} with count {}.", trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId(), count);
|
||||
log.trace("Creating emote usage for emote {} in server {} with count {}.", trackedEmote.getTrackedEmoteId().getId(), trackedEmote.getTrackedEmoteId().getServerId(), count);
|
||||
return usedEmoteRepository.save(usedEmote);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,6 @@ public class UsedEmoteManagementServiceBean implements UsedEmoteManagementServic
|
||||
|
||||
@Override
|
||||
public void purgeEmoteUsagesSince(TrackedEmote emote, Instant since) {
|
||||
usedEmoteRepository.deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId(), since);
|
||||
usedEmoteRepository.deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(emote.getTrackedEmoteId().getId(), emote.getTrackedEmoteId().getServerId(), since);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,5 +12,9 @@
|
||||
<column name="name" value="statistic"/>
|
||||
<column name="created" valueComputed="${today}"/>
|
||||
</insert>
|
||||
<insert tableName="module">
|
||||
<column name="name" value="emoteTracking"/>
|
||||
<column name="created" valueComputed="${today}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user