[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:
Sheldan
2020-11-23 02:27:49 +01:00
parent b05a834b59
commit e966c710ce
68 changed files with 1219 additions and 218 deletions

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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()

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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);
}

View File

@@ -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));
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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>