[AB-80] added tracking of emotes used by server members and configuration

updated sonar scanner version
changed some commands to be silent instead of adding a check reaction
This commit is contained in:
Sheldan
2020-11-11 17:11:30 +01:00
parent c60cdb9d98
commit 04f1db2408
202 changed files with 7989 additions and 131 deletions

View File

@@ -29,7 +29,7 @@ public class ShowAssignableRolePlaceConfig extends AbstractConditionableCommand
String name = (String) parameters.get(0);
// TODO refactor to return something to be posted in this command here instead of relying it to be posted somewhere else
service.showAssignablePlaceConfig(commandContext.getUserInitiatedContext().getServer(), name, commandContext.getChannel());
return CommandResult.fromSuccess();
return CommandResult.fromIgnored();
}
@Override

View File

@@ -23,7 +23,7 @@ public class ShowAssignableRolePlaces extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
return service.showAllAssignableRolePlaces(commandContext.getUserInitiatedContext().getServer(), commandContext.getChannel())
.thenApply(aVoid -> CommandResult.fromSuccess());
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override

View File

@@ -28,7 +28,7 @@ public class TestAssignableRolePlace extends AbstractConditionableCommand {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
return service.testAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name, commandContext.getChannel())
.thenApply(aVoid -> CommandResult.fromSuccess());
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override

View File

@@ -3,13 +3,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<packaging>pom</packaging>

View File

@@ -74,7 +74,7 @@ public class LeaderBoardCommand extends AbstractConditionableCommand {
leaderBoardModel.setUserExecuting(userRankFuture.join());
MessageToSend messageToSend = templateService.renderEmbedTemplate(LEADER_BOARD_POST_EMBED_TEMPLATE, leaderBoardModel);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()));
}).thenApply(aVoid -> CommandResult.fromSuccess());
}).thenApply(aVoid -> CommandResult.fromIgnored());
}

View File

@@ -54,7 +54,7 @@ public class ListDisabledExperienceRoles extends AbstractConditionableCommand {
disabledExperienceRolesModel.getRoles().add(role);
});
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInChannel("list_disabled_experience_roles", disabledExperienceRolesModel, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromSuccess());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override

View File

@@ -72,7 +72,7 @@ public class Rank extends AbstractConditionableCommand {
CompletableFuture<LeaderBoardEntryModel> future = converter.fromLeaderBoardEntry(userRank);
return future.thenCompose(leaderBoardEntryModel ->
self.renderAndSendRank(commandContext, rankModel, leaderBoardEntryModel)
).thenApply(result -> CommandResult.fromSuccess());
).thenApply(result -> CommandResult.fromIgnored());
}
@Transactional

View File

@@ -36,7 +36,7 @@ public class SyncRoles extends AbstractConditionableCommand {
AServer server = commandContext.getUserInitiatedContext().getServer();
log.info("Synchronizing roles on server {}", server.getId());
return userExperienceService.syncUserRolesWithFeedback(server, commandContext.getUserInitiatedContext().getChannel())
.thenApply(aVoid -> CommandResult.fromSuccess());
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override

View File

@@ -3,13 +3,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<packaging>pom</packaging>

View File

@@ -38,7 +38,7 @@ public class MyWarnings extends AbstractConditionableCommand {
Long totalWarnCount = warnManagementService.getTotalWarnsForUser(commandContext.getUserInitiatedContext().getAUserInAServer());
model.setTotalWarnCount(totalWarnCount);
channelService.sendEmbedTemplateInChannel(MY_WARNINGS_RESPONSE_EMBED_TEMPLATE, model, commandContext.getChannel());
return CommandResult.fromSuccess();
return CommandResult.fromIgnored();
}
@Override

View File

@@ -71,7 +71,7 @@ public class UserNotes extends AbstractConditionableCommand {
return listCompletableFuture.thenCompose(noteEntryModels -> {
model.setUserNotes(noteEntryModels);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(USER_NOTES_RESPONSE_TEMPLATE, model, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess());
.thenApply(aVoid -> CommandResult.fromIgnored());
});
}

View File

@@ -62,7 +62,7 @@ public class Warnings extends AbstractConditionableCommand {
}
return warnEntryConverter.fromWarnings(warnsToDisplay).thenApply(warnEntries -> {
self.renderWarnings(commandContext, warnEntries);
return CommandResult.fromSuccess();
return CommandResult.fromIgnored();
});

View File

@@ -3,13 +3,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation</artifactId>
<packaging>pom</packaging>

View File

@@ -49,7 +49,7 @@ public class Close extends AbstractConditionableCommand {
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object());
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
return modMailThreadService.closeModMailThread(thread, note, true, commandContext.getUndoActions(), true)
.thenApply(aVoid -> CommandResult.fromSuccess());
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override

View File

@@ -47,7 +47,7 @@ public class CloseNoLog extends AbstractConditionableCommand {
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
// we don't have a note, therefore we cant pass any, the method handles this accordingly
return modMailThreadService.closeModMailThread(thread, null, false, commandContext.getUndoActions(), false)
.thenApply(aVoid -> CommandResult.fromSuccess());
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override

View File

@@ -46,7 +46,7 @@ public class CloseSilently extends AbstractConditionableCommand {
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object());
ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel());
return modMailThreadService.closeModMailThread(thread, note, false, commandContext.getUndoActions(), true)
.thenApply(aVoid -> CommandResult.fromSuccess());
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override

View File

@@ -59,7 +59,7 @@ public class Contact extends AbstractConditionableCommand {
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
model.setExistingModMailThread(existingThread);
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInChannel("modmail_thread_already_exists", model, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromSuccess());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
} else {
return modMailThreadService.createModMailThreadForUser(targetUser, null, commandContext.getChannel(), false, commandContext.getUndoActions())
.thenApply(aVoid -> CommandResult.fromSuccess());

View File

@@ -3,13 +3,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>modmail</artifactId>
<packaging>pom</packaging>

View File

@@ -10,6 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<packaging>pom</packaging>
<modules>
<module>moderation</module>
@@ -17,6 +18,7 @@
<module>experience-tracking</module>
<module>modmail</module>
<module>assignable-roles</module>
<module>statistic</module>
</modules>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>statistic</artifactId>
<packaging>pom</packaging>
<modules>
<module>statistic-int</module>
<module>statistic-impl</module>
</modules>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>core-interface</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>statistic-impl</artifactId>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/liquibase.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic-int</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>core-interface</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<type>test-jar</type>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,18 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>liquibase</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<outputDirectory>.</outputDirectory>
<directory>${project.basedir}/src/main/resources/migrations</directory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@@ -0,0 +1,21 @@
package dev.sheldan.abstracto.statistic.config;
import dev.sheldan.abstracto.core.command.config.ModuleInfo;
import dev.sheldan.abstracto.core.command.config.ModuleInterface;
import org.springframework.stereotype.Component;
@Component
public class StatisticModule implements ModuleInterface {
public static final String STATISTIC = "statistic";
@Override
public ModuleInfo getInfo() {
return ModuleInfo.builder().name(STATISTIC).description("Module containing commands related to statistic.").build();
}
@Override
public String getParentModule() {
return "default";
}
}

View File

@@ -0,0 +1,60 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.config.StatisticModule;
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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class DeleteTrackedEmote extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Autowired
private TrackedEmoteService trackedEmoteService;
@Override
public CommandResult execute(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
trackedEmoteService.deleteTrackedEmote(trackedEmote);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("trackedEmote").templated(true).type(TrackedEmote.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("deleteTrackedEmote")
.module(StatisticModule.STATISTIC)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,89 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.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.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class DeletedEmoteStats extends AbstractConditionableCommand {
@Autowired
private UsedEmoteService usedEmoteService;
@Autowired
private ChannelService channelService;
public static final String EMOTE_STATS_STATIC_DELETED_RESPONSE = "deletedEmoteStats_static_response";
public static final String EMOTE_STATS_ANIMATED_DELETED_RESPONSE = "deletedEmoteStats_animated_response";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
Instant statsSince = Instant.EPOCH;
if(!parameters.isEmpty()) {
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<>();
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()));
}
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(!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()));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("deletedEmoteStats")
.module(StatisticModule.STATISTIC)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,64 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.config.StatisticModule;
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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class DisableEmoteTracking extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
if(!parameters.isEmpty()) {
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
trackedEmoteManagementService.disableTrackedEmote(trackedEmote);
} else {
trackedEmoteService.disableEmoteTracking(commandContext.getGuild());
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("trackedEmote").templated(true).optional(true).type(TrackedEmote.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("disableEmoteTracking")
.module(StatisticModule.STATISTIC)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,94 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.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.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class EmoteStats extends AbstractConditionableCommand {
@Autowired
private UsedEmoteService usedEmoteService;
@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";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
Instant statsSince = Instant.EPOCH;
if(!parameters.isEmpty()) {
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<>();
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()));
}
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()));
}
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()));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("emoteStats")
.module(StatisticModule.STATISTIC)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,130 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.utils.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.exception.DownloadEmoteStatsFileTooBigException;
import dev.sheldan.abstracto.statistic.emotes.model.DownloadEmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ExportEmoteStats extends AbstractConditionableCommand {
public static final String DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_no_stats_available_response";
public static final String DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY = "downloadEmoteStats_file_name";
public static final String DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY = "downloadEmoteStats_file_content";
public static final String DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_response";
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Autowired
private UsedEmoteManagementService usedEmoteManagementService;
@Autowired
private FileUtils fileUtils;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
Instant statsSince = Instant.EPOCH;
if(!parameters.isEmpty()) {
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(usedEmotes.isEmpty()) {
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY, new Object(), commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
}
// info might not be nice to handle in the template, and 1970 would look weird to users
// effectively this means if its null its EPOCH, so it would be possible to render it still
Instant toUseForModel = statsSince != Instant.EPOCH ? statsSince : null;
DownloadEmoteStatsModel model = DownloadEmoteStatsModel
.builder()
.emotes(usedEmotes)
.guild(commandContext.getGuild())
.downloadDate(Instant.now())
.requester(commandContext.getAuthor())
.statsSince(toUseForModel)
.build();
String fileName = templateService.renderTemplate(DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY, model);
String fileContent = templateService.renderTemplate(DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY, model);
File tempFile = fileUtils.createTempFile(fileName);
try {
fileUtils.writeContentToFile(tempFile, fileContent);
long maxFileSize = commandContext.getGuild().getMaxFileSize();
if(maxFileSize < tempFile.length()) {
throw new DownloadEmoteStatsFileTooBigException(tempFile.length(), maxFileSize);
}
MessageToSend messageToSend = templateService.renderEmbedTemplate(DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY, model);
messageToSend.setFileToSend(tempFile);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
} catch (IOException e) {
throw new AbstractoRunTimeException(e);
} finally {
try {
fileUtils.safeDelete(tempFile);
} catch (IOException e) {
log.error("Failed to delete temporary export emote statistics file {}.", tempFile.getAbsoluteFile(), e);
}
}
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("exportEmoteStats")
.module(StatisticModule.STATISTIC)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,102 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.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.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ExternalEmoteStats extends AbstractConditionableCommand {
@Autowired
private UsedEmoteService usedEmoteService;
@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";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
Instant statsSince = Instant.EPOCH;
if(!parameters.isEmpty()) {
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<>();
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()));
}
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()));
}
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()));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("externalEmoteStats")
.module(StatisticModule.STATISTIC)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
@Override
public List<FeatureMode> getFeatureModeLimitations() {
return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES);
}
}

View File

@@ -0,0 +1,68 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.config.StatisticModule;
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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@Component
public class PurgeEmoteStats extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Autowired
private UsedEmoteService usedEmoteService;
@Override
public CommandResult execute(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
Instant since = Instant.EPOCH;
if(parameters.size() > 1) {
Duration parameter = (Duration) parameters.get(1);
since = Instant.now().minus(parameter);
}
usedEmoteService.purgeEmoteUsagesSince(trackedEmote, since);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("trackedEmote").templated(true).type(TrackedEmote.class).build());
parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("purgeEmoteStats")
.module(StatisticModule.STATISTIC)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,50 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.config.StatisticModule;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class ResetEmoteStats extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Override
public CommandResult execute(CommandContext commandContext) {
trackedEmoteService.resetEmoteStats(commandContext.getGuild());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("resetEmoteStats")
.module(StatisticModule.STATISTIC)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException;
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.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.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class ShowExternalTrackedEmote extends AbstractConditionableCommand {
public static final String SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY = "showExternalTrackedEmote_response";
@Autowired
private ChannelService channelService;
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0);
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId());
if(!trackedEmote.getExternal()) {
throw new AbstractoTemplatedException("Emote is not external", "showExternalTrackedEmote_emote_is_not_external");
}
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY, trackedEmote, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("trackedEmote").templated(true).type(TrackedEmote.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("showExternalTrackedEmote")
.module(StatisticModule.STATISTIC)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
@Override
public List<FeatureMode> getFeatureModeLimitations() {
return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES);
}
}

View File

@@ -0,0 +1,114 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.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.model.TrackedEmoteOverview;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class ShowTrackedEmotes extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private ChannelService channelService;
@Autowired
private FeatureModeService featureModeService;
public static final String EMOTE_STATS_STATIC_RESPONSE = "showTrackedEmotes_static_response";
public static final String EMOTE_STATS_ANIMATED_RESPONSE = "showTrackedEmotes_animated_response";
public static final String EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE = "showTrackedEmotes_external_animated_response";
public static final String EMOTE_STATS_EXTERNAL_STATIC_RESPONSE = "showTrackedEmotes_external_static_response";
public static final String EMOTE_STATS_DELETED_STATIC_RESPONSE = "showTrackedEmotes_deleted_static_response";
public static final String EMOTE_STATS_DELETED_ANIMATED_RESPONSE = "showTrackedEmotes_deleted_animated_response";
public static final String EMOTE_STATS_NO_STATS_AVAILABLE = "showTrackedEmotes_no_emotes_available";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
checkParameters(commandContext);
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;
List<CompletableFuture<Message>> messagePromises = new ArrayList<>();
if(!trackedEmoteOverview.getStaticEmotes().isEmpty()) {
noStatsAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
if(!trackedEmoteOverview.getAnimatedEmotes().isEmpty()) {
noStatsAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
if(!trackedEmoteOverview.getDeletedStaticEmotes().isEmpty()) {
noStatsAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
if(!trackedEmoteOverview.getDeletedAnimatedEmotes().isEmpty()) {
noStatsAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
if(externalTrackingEnabled) {
if(!trackedEmoteOverview.getExternalStaticEmotes().isEmpty()) {
noStatsAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
if(!trackedEmoteOverview.getExternalAnimatedEmotes().isEmpty()) {
noStatsAvailable = false;
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel()));
}
}
if(noStatsAvailable) {
messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel()));
}
return FutureUtils.toSingleFutureGeneric(messagePromises)
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
parameters.add(Parameter.builder().name("showAll").templated(true).optional(true).type(Boolean.class).build());
return CommandConfiguration.builder()
.name("showTrackedEmotes")
.module(StatisticModule.STATISTIC)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,60 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.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.model.TrackedEmoteSynchronizationResult;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class SyncTrackedEmotes extends AbstractConditionableCommand {
public static final String SYNC_TRACKED_EMOTES_RESULT_RESPONSE = "syncTrackedEmotes_result_response";
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private ChannelService channelService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
TrackedEmoteSynchronizationResult syncResult = trackedEmoteService.synchronizeTrackedEmotes(commandContext.getGuild());
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, syncResult, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("syncTrackedEmotes")
.module(StatisticModule.STATISTIC)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,87 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.exception.IncorrectFeatureModeException;
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.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
public class TrackEmote extends AbstractConditionableCommand {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Autowired
private EmoteService emoteService;
@Autowired
private FeatureModeService featureModeService;
@Override
public CommandResult execute(CommandContext commandContext) {
checkParameters(commandContext);
TrackEmoteParameter emoteToTrack = (TrackEmoteParameter) commandContext.getParameters().getParameters().get(0);
Long emoteId = emoteToTrack.getTrackedEmote().getTrackedEmoteId().getEmoteId();
long serverId = commandContext.getGuild().getIdLong();
if(trackedEmoteManagementService.trackedEmoteExists(emoteId, serverId)) {
TrackedEmote trackedemote = trackedEmoteManagementService.loadByEmoteId(emoteId, serverId);
trackedEmoteManagementService.enableTrackedEmote(trackedemote);
} else if(emoteToTrack.getEmote() != null) {
boolean external = !emoteService.emoteIsFromGuild(emoteToTrack.getEmote(), commandContext.getGuild());
if(external) {
boolean trackExternalEmotes = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId, EmoteTrackingMode.EXTERNAL_EMOTES);
if(!trackExternalEmotes) {
throw new IncorrectFeatureModeException(StatisticFeatures.EMOTE_TRACKING, Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES));
}
}
trackedEmoteService.createFakeTrackedEmote(emoteToTrack.getEmote(), commandContext.getGuild());
} else {
throw new IncorrectParameterException(this, getConfiguration().getParameters().get(0).getName());
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("emote").templated(true).type(TrackEmoteParameter.class).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("trackEmote")
.module(StatisticModule.STATISTIC)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.statistic.emotes.command.parameter;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Emote;
@Getter
@Setter
@Builder
public class TrackEmoteParameter {
private Emote emote;
private TrackedEmote trackedEmote;
}

View File

@@ -0,0 +1,42 @@
package dev.sheldan.abstracto.statistic.emotes.command.parameter.handler;
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.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;
@Component
public class TrackedEmoteParameterHandler implements CommandParameterHandler {
@Autowired
private EmoteParameterHandler emoteParameterHandler;
@Autowired
private TrackedEmoteService trackedEmoteService;
@Override
public boolean handles(Class clazz) {
return clazz.equals(TrackedEmote.class);
}
@Override
public Object handle(String input, CommandParameterIterators iterators, Class clazz, Message context) {
Emote emote = (Emote) emoteParameterHandler.handle(input, iterators, Emote.class, context);
if(emote != null) {
return trackedEmoteService.getFakeTrackedEmote(emote, context.getGuild());
} else {
long trackedEmoteId = Long.parseLong(input);
return trackedEmoteService.getFakeTrackedEmote(trackedEmoteId, context.getGuild());
}
}
@Override
public Integer getPriority() {
return 51;
}
}

View File

@@ -0,0 +1,45 @@
package dev.sheldan.abstracto.statistic.emotes.command.parameter.handler;
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.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;
@Component
public class TrackedEmoteParameterParameterHandler implements CommandParameterHandler {
@Autowired
private EmoteParameterHandler emoteParameterHandler;
@Autowired
private TrackedEmoteService trackedEmoteService;
@Override
public boolean handles(Class clazz) {
return clazz.equals(TrackEmoteParameter.class);
}
@Override
public Object handle(String input, CommandParameterIterators iterators, Class clazz, Message context) {
TrackEmoteParameter parameter = TrackEmoteParameter.builder().build();
Emote emote = (Emote) emoteParameterHandler.handle(input, iterators, Emote.class, context);
if(emote != null) {
parameter.setEmote(emote);
parameter.setTrackedEmote(trackedEmoteService.getFakeTrackedEmote(emote, context.getGuild()));
} else {
long trackedEmoteId = Long.parseLong(input);
parameter.setTrackedEmote(trackedEmoteService.getFakeTrackedEmote(trackedEmoteId, context.getGuild()));
}
return parameter;
}
@Override
public Integer getPriority() {
return 51;
}
}

View File

@@ -0,0 +1,51 @@
package dev.sheldan.abstracto.statistic.emotes.converter;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay;
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 net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class EmoteStatsConverter {
@Autowired
private BotService botService;
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
public EmoteStatsModel fromEmoteStatsResults(List<EmoteStatsResult> resultList) {
if(resultList.isEmpty()) {
return EmoteStatsModel.builder().build();
}
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(!trackedEmote.getExternal() && !trackedEmote.getDeleted()) {
loadedEmote = relevantGuild.getEmoteById(trackedEmote.getTrackedEmoteId().getEmoteId());
}
EmoteStatsResultDisplay display = EmoteStatsResultDisplay
.builder()
.emote(loadedEmote)
.result(emoteStatsResult)
.trackedEmote(trackedEmote)
.build();
if(display.getTrackedEmote().getAnimated()) {
resultingModel.getAnimatedEmotes().add(display);
} else {
resultingModel.getStaticEmotes().add(display);
}
});
return resultingModel;
}
}

View File

@@ -0,0 +1,60 @@
package dev.sheldan.abstracto.statistic.emotes.job;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteRuntimeService;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@DisallowConcurrentExecution
@Component
@PersistJobDataAfterExecution
public class EmotePersistingJob extends QuartzJobBean {
@Autowired
private TrackedEmoteRuntimeService trackedEmoteRuntimeService;
@Autowired
private TrackedEmoteService trackedEmoteService;
@Override
@Transactional
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Map<Long, Map<Long, List<PersistingEmote>>> runtimeConfig = trackedEmoteRuntimeService.getRuntimeConfig();
log.info("Running statistic persisting job.");
Long pastMinute = getPastMinute();
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);
checkForPastEmoteStats(pastMinute, runtimeConfig);
}
}
private void checkForPastEmoteStats(Long minuteToCheck, Map<Long, Map<Long, List<PersistingEmote>>> runtimeConfig) {
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);
trackedEmoteService.storeEmoteStatistics(runtimeConfig.get(pastMinute));
runtimeConfig.remove(pastMinute);
});
}
public long getPastMinute() {
return (Instant.now().getEpochSecond() / 60) - 1;
}
}

View File

@@ -0,0 +1,36 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
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.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;
@Component
@Slf4j
public class CreateTrackedEmoteListener implements EmoteCreatedListener {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public void emoteCreated(Emote createdEmote) {
// guild should be available, because we are in the emote created event, and the emote object should come from there
log.info("Creating tracked emote {} in server {}.", createdEmote.getGuild().getIdLong(), createdEmote.getIdLong());
trackedEmoteManagementService.createTrackedEmote(createdEmote, createdEmote.getGuild());
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -0,0 +1,35 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
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.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;
@Component
@Slf4j
public class DeleteTrackedEmoteListener implements EmoteDeletedListener {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public void emoteDeleted(Emote deletedEmote) {
log.info("Marking tracked emote {} in gild {} as deleted.", deletedEmote.getId(), deletedEmote.getGuild().getIdLong());
trackedEmoteManagementService.markAsDeleted(deletedEmote.getGuild().getIdLong(), deletedEmote.getIdLong());
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -0,0 +1,43 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.ISnowflake;
import net.dv8tion.jda.api.entities.Message;
import org.apache.commons.collections4.Bag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class EmoteTrackingListener implements MessageReceivedListener {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Override
public void execute(Message message) {
Bag<Emote> emotesBag = message.getEmotesBag();
Map<Long, List<Emote>> collect = emotesBag.stream().collect(Collectors.groupingBy(ISnowflake::getIdLong));
collect.values().forEach(groupedEmotes ->
trackedEmoteService.addEmoteToRuntimeStorage(groupedEmotes.get(0), message.getGuild(), (long) groupedEmotes.size())
);
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
@Override
public Integer getPriority() {
return ListenerPriority.LOW;
}
}

View File

@@ -0,0 +1,34 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
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.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;
@Component
public class UpdateTrackedEmoteListener implements EmoteUpdatedListener {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public void emoteUpdated(Emote updatedEmote, String oldValue, String newValue) {
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmote(updatedEmote);
trackedEmoteManagementService.changeName(trackedEmote, newValue);
}
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -0,0 +1,22 @@
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

@@ -0,0 +1,22 @@
package dev.sheldan.abstracto.statistic.emotes.repository;
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;
import javax.persistence.QueryHint;
import java.util.List;
@Repository
public interface TrackedEmoteRepository extends JpaRepository<TrackedEmote, TrackedEmoteServer> {
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
List<TrackedEmote> findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(Long serverId);
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
List<TrackedEmote> findByTrackedEmoteId_ServerIdAndTrackingEnabledTrue(Long serverId);
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
List<TrackedEmote> findByTrackedEmoteId_ServerId(Long serverId);
}

View File

@@ -0,0 +1,58 @@
package dev.sheldan.abstracto.statistic.emotes.repository;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult;
import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote;
import dev.sheldan.abstracto.statistic.emotes.model.database.embed.UsedEmoteDay;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
@Repository
public interface UsedEmoteRepository extends JpaRepository<UsedEmote, UsedEmoteDay> {
@Query(value="select * from used_emote " +
"where emote_id = :emote_id and server_id = :server_id " +
"and use_date = date_trunc('day', now())", nativeQuery = true)
Optional<UsedEmote> findEmoteFromServerToday(@Param("emote_id") Long emoteId, @Param("server_id") Long server_id);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id " +
"group by us.emote_id, us.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.external = true " +
"group by us.emote_id, us.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getExternalEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.deleted = true " +
"group by us.emote_id, us.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getDeletedEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
@Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " +
"inner join tracked_emote te " +
"on us.emote_id = te.id and us.server_id = te.server_id " +
"where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.external = false and te.deleted = false " +
"group by us.emote_id, us.server_id " +
"order by amount desc", nativeQuery = true)
List<EmoteStatsResult> getCurrentlyExistingEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since);
void deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(Long emoteId, Long serverId, Instant timestamp);
List<UsedEmote> getByEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(Long emoteId, Instant timestamp);
}

View File

@@ -0,0 +1,29 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class TrackedEmoteRunTimeStorage {
private HashMap<Long, Map<Long, List<PersistingEmote>>> trackedEmotes = new HashMap<>();
public Map<Long, Map<Long, List<PersistingEmote>>> getRuntimeConfig() {
return trackedEmotes;
}
public boolean contains(Long key) {
return trackedEmotes.containsKey(key);
}
public void put(Long key, Map<Long, List<PersistingEmote>> objectToPut) {
trackedEmotes.put(key, objectToPut);
}
public Map<Long, List<PersistingEmote>> get(Long key) {
return trackedEmotes.get(key);
}
}

View File

@@ -0,0 +1,82 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.*;
@Component
@Slf4j
public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeService {
@Autowired
private TrackedEmoteRunTimeStorage trackedEmoteRunTimeStorage;
@Override
public Map<Long, Map<Long, List<PersistingEmote>>> getRuntimeConfig() {
return trackedEmoteRunTimeStorage.getRuntimeConfig();
}
@Override
public void addEmoteForServer(Emote emote, Guild guild, boolean external) {
addEmoteForServer(emote, guild, 1L, external);
}
@Override
public void addEmoteForServer(Emote emote, Guild guild, Long count, boolean external) {
Long key = getKey();
PersistingEmote newPersistentEmote = createFromEmote(guild, emote, count, external);
if(trackedEmoteRunTimeStorage.contains(key)) {
Map<Long, List<PersistingEmote>> elementsForKey = trackedEmoteRunTimeStorage.get(key);
if(elementsForKey.containsKey(guild.getIdLong())) {
List<PersistingEmote> persistingEmotes = elementsForKey.get(guild.getIdLong());
Optional<PersistingEmote> existingEmote = persistingEmotes
.stream()
.filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getIdLong()))
.findFirst();
existingEmote.ifPresent(persistingEmote -> persistingEmote.setCount(persistingEmote.getCount() + count));
if(!existingEmote.isPresent()) {
persistingEmotes.add(newPersistentEmote);
}
} else {
log.trace("Adding emote {} to list of server {}.", newPersistentEmote.getEmoteId(), guild.getIdLong());
elementsForKey.put(guild.getIdLong(), new ArrayList<>(Arrays.asList(newPersistentEmote)));
}
} else {
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());
trackedEmoteRunTimeStorage.put(key, serverEmotes);
}
}
@Override
public Long getKey() {
return Instant.now().getEpochSecond() / 60;
}
@Override
public PersistingEmote createFromEmote(Guild guild, Emote emote, boolean external) {
return createFromEmote(guild, emote, 1L, external);
}
@Override
public PersistingEmote createFromEmote(Guild guild, Emote emote, Long count, boolean external) {
String url = external ? emote.getImageUrl() : null;
return PersistingEmote
.builder()
.animated(emote.isAnimated())
.emoteId(emote.getIdLong())
.external(external)
.externalUrl(url)
.emoteName(emote.getName())
.count(count)
.serverId(guild.getIdLong())
.build();
}
}

View File

@@ -0,0 +1,197 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.service.BotService;
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.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
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;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.Map;
import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class TrackedEmoteServiceBean implements TrackedEmoteService {
@Autowired
private TrackedEmoteRuntimeService trackedEmoteRuntimeService;
@Autowired
private FeatureModeService featureModeService;
@Autowired
private EmoteService emoteService;
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Autowired
private UsedEmoteManagementService usedEmoteManagementService;
@Autowired
private BotService botService;
@Override
public void addEmoteToRuntimeStorage(List<Emote> emotes, Guild guild) {
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
emotes.forEach(emote -> {
boolean emoteIsFromGuild = emoteService.emoteIsFromGuild(emote, guild);
if(externalTrackingEnabled || emoteIsFromGuild) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, !emoteIsFromGuild);
}
});
}
@Override
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);
if(externalTrackingEnabled || emoteIsFromGuild) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, !emoteIsFromGuild);
}
}
@Override
@Transactional
public void storeEmoteStatistics(Map<Long, List<PersistingEmote>> usagesToStore) {
usagesToStore.forEach((serverId, persistingEmotes) -> {
log.info("Storing {} emotes for server {}.", persistingEmotes.size(), serverId);
boolean autoTrackExternalEmotes = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId, EmoteTrackingMode.AUTO_TRACK_EXTERNAL);
boolean trackExternalEmotes = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId, EmoteTrackingMode.EXTERNAL_EMOTES);
persistingEmotes.forEach(persistingEmote -> {
Optional<TrackedEmote> emoteOptional = trackedEmoteManagementService.loadByEmoteIdOptional(persistingEmote.getEmoteId(), serverId);
emoteOptional.ifPresent(trackedEmote -> {
if(trackedEmote.getTrackingEnabled()) {
Optional<UsedEmote> existingUsedEmote = usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote);
existingUsedEmote.ifPresent(usedEmote ->
usedEmote.setAmount(usedEmote.getAmount() + persistingEmote.getCount())
);
if(!existingUsedEmote.isPresent()) {
usedEmoteManagementService.createEmoteUsageForToday(trackedEmote, persistingEmote.getCount());
}
} else {
log.trace("Tracking disabled for emote {} in server {}.", trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId());
}
});
if(!emoteOptional.isPresent()) {
createNewTrackedEmote(serverId, autoTrackExternalEmotes, trackExternalEmotes, persistingEmote);
}
});
});
}
private void createNewTrackedEmote(Long serverId, boolean autoTrackExternalEmotes, boolean trackExternalEmotes, 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());
}
});
}
@Override
public TrackedEmote getFakeTrackedEmote(Emote emote, Guild guild) {
return getFakeTrackedEmote(emote.getIdLong(), guild);
}
@Override
public TrackedEmote getFakeTrackedEmote(Long id, Guild guild) {
return TrackedEmote
.builder()
.trackedEmoteId(new TrackedEmoteServer(id, guild.getIdLong()))
.fake(true)
.build();
}
@Override
public TrackedEmoteSynchronizationResult synchronizeTrackedEmotes(Guild guild) {
List<TrackedEmote> activeTrackedEmotes = trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(guild.getIdLong());
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());
for (Emote emote : allExistingEmotes) {
Optional<TrackedEmote> trackedEmoteOptional = activeTrackedEmotes
.stream()
.filter(trackedEmote ->
trackedEmote.getTrackedEmoteId().getEmoteId().equals(emote.getIdLong())
&& trackedEmote.getTrackedEmoteId().getServerId().equals(guild.getIdLong()))
.findFirst();
if (!trackedEmoteOptional.isPresent()) {
trackedEmoteManagementService.createTrackedEmote(emote, guild);
addedEmotes++;
} else {
activeTrackedEmotes.remove(trackedEmoteOptional.get());
}
}
activeTrackedEmotes.forEach(trackedEmote ->
trackedEmoteManagementService.markAsDeleted(trackedEmote)
);
return TrackedEmoteSynchronizationResult
.builder()
.emotesAdded(addedEmotes)
.emotesMarkedDeleted((long) activeTrackedEmotes.size())
.build();
}
@Override
public TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild) {
return loadTrackedEmoteOverview(guild, false);
}
@Override
public TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild, Boolean showTrackingDisabled) {
List<TrackedEmote> trackedEmotes = trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), showTrackingDisabled);
TrackedEmoteOverview emoteOverView = TrackedEmoteOverview.builder().build();
trackedEmotes.forEach(trackedEmote ->
emoteOverView.addTrackedEmote(trackedEmote, guild)
);
return emoteOverView;
}
@Override
public TrackedEmote createFakeTrackedEmote(Emote emote, Guild guild) {
boolean external = !emoteService.emoteIsFromGuild(emote, guild);
return trackedEmoteManagementService.createTrackedEmote(emote, guild, external);
}
@Override
public void deleteTrackedEmote(TrackedEmote trackedEmote) {
usedEmoteManagementService.purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH);
trackedEmoteManagementService.deleteTrackedEmote(trackedEmote);
}
@Override
public void resetEmoteStats(Guild guild) {
List<TrackedEmote> trackedEmotes = trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true);
trackedEmotes.forEach(this::deleteTrackedEmote);
}
@Override
public void disableEmoteTracking(Guild guild) {
List<TrackedEmote> trackedEmotes = trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true);
trackedEmotes.forEach(trackedEmote -> trackedEmote.setTrackingEnabled(false));
}
}

View File

@@ -0,0 +1,61 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emotes.converter.EmoteStatsConverter;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
@Component
@Slf4j
public class UsedEmoteServiceBean implements UsedEmoteService {
@Autowired
private EmoteStatsConverter converter;
@Autowired
private UsedEmoteManagementService usedEmoteManagementService;
@Override
public EmoteStatsModel getEmoteStatsForServerSince(AServer server, Instant since) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadAllEmoteStatsForServerSince(server, since);
return converter.fromEmoteStatsResults(emoteStatsResults);
}
@Override
public EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(server, since);
return converter.fromEmoteStatsResults(emoteStatsResults);
}
@Override
public EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadExternalEmoteStatsForServerSince(server, since);
return converter.fromEmoteStatsResults(emoteStatsResults);
}
@Override
public EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since) {
List<EmoteStatsResult> emoteStatsResults = usedEmoteManagementService.loadActiveEmoteStatsForServerSince(server, since);
return converter.fromEmoteStatsResults(emoteStatsResults);
}
@Override
public void purgeEmoteUsagesSince(TrackedEmote emote, Instant since) {
log.info("Purging emote {} in server {} since {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId(), since);
usedEmoteManagementService.purgeEmoteUsagesSince(emote, since.truncatedTo(ChronoUnit.DAYS));
}
@Override
public void purgeEmoteUsages(TrackedEmote emote) {
purgeEmoteUsagesSince(emote, Instant.EPOCH);
}
}

View File

@@ -0,0 +1,179 @@
package dev.sheldan.abstracto.statistic.emotes.service.management;
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;
import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagementService {
@Autowired
private TrackedEmoteRepository repository;
@Autowired
private ServerManagementService serverManagementService;
@Override
public TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server) {
return createTrackedEmote(emoteId, emoteName, animated, true, server);
}
@Override
public TrackedEmote createTrackedEmote(Emote emote, Guild guild) {
AServer server = serverManagementService.loadServer(guild.getIdLong());
return createTrackedEmote(emote.getIdLong(), emote.getName(), emote.isAnimated(), true, server);
}
@Override
public TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external) {
if(external) {
return createExternalEmote(emote, guild);
} else {
return createTrackedEmote(emote, guild);
}
}
@Override
public TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, Boolean tracked, AServer server) {
TrackedEmote emote = TrackedEmote
.builder()
.animated(animated)
.trackedEmoteId(new TrackedEmoteServer(emoteId, server.getId()))
.trackingEnabled(tracked)
.emoteName(emoteName)
.server(server)
.external(false)
.deleted(false)
.build();
log.info("Creating tracking emote with id {} and server {}.", emoteId, server.getId());
return repository.save(emote);
}
@Override
public TrackedEmote createExternalEmote(Long emoteId, String emoteName, String externalUrl, Boolean animated, AServer server) {
TrackedEmote emote = TrackedEmote
.builder()
.animated(animated)
.trackedEmoteId(new TrackedEmoteServer(emoteId, server.getId()))
.trackingEnabled(true)
.deleted(false)
.emoteName(emoteName)
.server(server)
.external(true)
.externalUrl(externalUrl)
.build();
log.info("Creating external emote with id {} for server {}.", emoteId, server.getId());
return repository.save(emote);
}
@Override
public TrackedEmote createNotTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server) {
return createTrackedEmote(emoteId, emoteName, animated, false, server);
}
@Override
public TrackedEmote createExternalEmote(PersistingEmote persistingEmote) {
AServer server = serverManagementService.loadServer(persistingEmote.getServerId());
return createExternalEmote(persistingEmote.getEmoteId(), persistingEmote.getEmoteName(), persistingEmote.getExternalUrl(), persistingEmote.getAnimated(), server);
}
@Override
public TrackedEmote createExternalEmote(Emote emote, Guild guild) {
AServer server = serverManagementService.loadServer(guild.getIdLong());
return createExternalEmote(emote.getIdLong(), emote.getName(), emote.getImageUrl(), emote.isAnimated(), server);
}
@Override
public void markAsDeleted(Long serverId, Long emoteId) {
TrackedEmote emote = loadByEmoteId(emoteId, serverId);
markAsDeleted(emote);
}
@Override
public void markAsDeleted(TrackedEmote trackedemote) {
log.info("Marking tracked emote {} in server {} as deleted.", trackedemote.getTrackedEmoteId().getEmoteId(), trackedemote.getTrackedEmoteId().getServerId());
trackedemote.setDeleted(true);
}
@Override
public TrackedEmote loadByEmoteId(Long emoteId, Long serverId) {
return loadByEmoteIdOptional(emoteId, serverId).orElseThrow(() -> new TrackedEmoteNotFoundException(String.format("Tracked emote %s in server %s not found.", emoteId, serverId)));
}
@Override
public TrackedEmote loadByEmote(Emote emote) {
return loadByEmoteId(emote.getIdLong(), emote.getGuild().getIdLong());
}
@Override
public boolean trackedEmoteExists(Long emoteId, Long serverId) {
return loadByEmoteIdOptional(emoteId, serverId).isPresent();
}
@Override
public TrackedEmote loadByTrackedEmoteServer(TrackedEmoteServer trackedEmoteServer) {
return loadByEmoteId(trackedEmoteServer.getEmoteId(), trackedEmoteServer.getServerId());
}
@Override
public Optional<TrackedEmote> loadByEmoteIdOptional(Long emoteId, Long serverId) {
return repository.findById(new TrackedEmoteServer(emoteId, serverId));
}
@Override
public List<TrackedEmote> getAllActiveTrackedEmoteForServer(AServer server) {
return getAllActiveTrackedEmoteForServer(server.getId());
}
@Override
public List<TrackedEmote> getAllActiveTrackedEmoteForServer(Long serverId) {
return repository.findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(serverId);
}
@Override
public List<TrackedEmote> getTrackedEmoteForServer(Long serverId, Boolean showTrackingDisabledEmotes) {
if(showTrackingDisabledEmotes) {
return repository.findByTrackedEmoteId_ServerId(serverId);
} else {
return repository.findByTrackedEmoteId_ServerIdAndTrackingEnabledTrue(serverId);
}
}
@Override
public void changeName(TrackedEmote emote, String newName) {
log.info("Changing name of emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), 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());
emote.setTrackingEnabled(false);
}
@Override
public void enableTrackedEmote(TrackedEmote emote) {
log.info("Enabling tracking for tracked emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), 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());
repository.delete(emote);
}
}

View File

@@ -0,0 +1,69 @@
package dev.sheldan.abstracto.statistic.emotes.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult;
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.UsedEmoteDay;
import dev.sheldan.abstracto.statistic.emotes.repository.UsedEmoteRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class UsedEmoteManagementServiceBean implements UsedEmoteManagementService {
@Autowired
private UsedEmoteRepository usedEmoteRepository;
@Override
public Optional<UsedEmote> loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote) {
return usedEmoteRepository.findEmoteFromServerToday(trackedEmote.getTrackedEmoteId().getEmoteId() , 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()))
.amount(count)
.build();
log.trace("Creating emote usage for emote {} in server {} with count {}.", trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId(), count);
return usedEmoteRepository.save(usedEmote);
}
@Override
public List<UsedEmote> loadEmoteUsagesForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getByEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(server.getId(), since);
}
@Override
public List<EmoteStatsResult> loadAllEmoteStatsForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getEmoteStatsForServerSince(server.getId(), since);
}
@Override
public List<EmoteStatsResult> loadDeletedEmoteStatsForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getDeletedEmoteStatsForServerSince(server.getId(), since);
}
@Override
public List<EmoteStatsResult> loadExternalEmoteStatsForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getExternalEmoteStatsForServerSince(server.getId(), since);
}
@Override
public List<EmoteStatsResult> loadActiveEmoteStatsForServerSince(AServer server, Instant since) {
return usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(server.getId(), since);
}
@Override
public void purgeEmoteUsagesSince(TrackedEmote emote, Instant since) {
usedEmoteRepository.deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId(), since);
}
}

View File

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

View File

@@ -0,0 +1,88 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<property name="statisticModule" value="(SELECT id FROM module WHERE name = 'statistic')"/>
<property name="emoteTrackingFeature" value="(SELECT id FROM feature WHERE key = 'emote_tracking')"/>
<property name="today" value="(SELECT NOW())"/>
<changeSet author="Sheldan" id="statistic-commands">
<insert tableName="command">
<column name="name" value="emoteStats"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="deletedEmoteStats"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="externalEmoteStats"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="purgeEmoteStats"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="syncTrackedEmotes"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="trackEmote"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="disableEmoteTracking"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="deleteTrackedEmote"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="resetEmoteStats"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="exportEmoteStats"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="showExternalTrackedEmote"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="showTrackedEmotes"/>
<column name="module_id" valueComputed="${statisticModule}"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,15 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<include file="feature.xml" relativeToChangelogFile="true"/>
<include file="module.xml" relativeToChangelogFile="true"/>
<include file="default_feature_flag.xml" relativeToChangelogFile="true"/>
<include file="emote_statistic_job.xml" relativeToChangelogFile="true"/>
<include file="command.xml" relativeToChangelogFile="true"/>
<include file="default_feature_mode.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,18 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<property name="emoteTrackingFeature" value="(SELECT id FROM feature WHERE key = 'emote_tracking')"/>
<property name="today" value="(SELECT NOW())"/>
<changeSet author="Sheldan" id="emote_tracking_default_feature_flag-insertion">
<insert tableName="default_feature_flag">
<column name="enabled" value="false"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,31 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<property name="emoteTrackingFeature" value="(SELECT id FROM feature WHERE key = 'emote_tracking')"/>
<property name="today" value="(SELECT NOW())"/>
<changeSet author="Sheldan" id="emote_tracking_default_feature_mode-insertion">
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="emoteAutoTrack"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="false"/>
<column name="mode" value="externalEmotes"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="false"/>
<column name="mode" value="autoTrackExternal"/>
<column name="feature_id" valueComputed="${emoteTrackingFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

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

View File

@@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<property name="today" value="(SELECT NOW())"/>
<changeSet author="Sheldan" id="emote_tracking_feature-insertion">
<insert tableName="feature">
<column name="key" value="emote_tracking"/>
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<property name="today" value="(SELECT NOW())"/>
<changeSet author="Sheldan" id="statistic-module-insertion">
<insert tableName="module">
<column name="name" value="statistic"/>
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

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

View File

@@ -0,0 +1,30 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="tracked_emote-table">
<createTable tableName="tracked_emote">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="tracked_emote_pkey"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="name" type="VARCHAR(32)"/>
<column name="animated" type="BOOLEAN"/>
<column name="tracking_enabled" type="BOOLEAN"/>
<column name="deleted" type="BOOLEAN"/>
<column name="external" type="BOOLEAN"/>
<column name="external_url" type="VARCHAR(255)"/>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="Sheldan" id="tracked_emote-fk_tracked_emote_server">
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="tracked_emote" constraintName="fk_tracked_emote_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,29 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="used_emote-table">
<createTable tableName="used_emote">
<column name="emote_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="used_emote_pkey"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="used_emote_pkey"/>
</column>
<column name="use_date" type="DATE">
<constraints nullable="false" primaryKey="true" primaryKeyName="used_emote_pkey"/>
</column>
<column name="amount" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="Sheldan" id="used_emote-fk_used_emote_server">
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="used_emote" constraintName="fk_used_emote_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
</changeSet>
<changeSet author="Sheldan" id="used_emote-fk_used_emote_tracked_emote">
<addForeignKeyConstraint baseColumnNames="emote_id" baseTableName="used_emote" constraintName="fk_used_emote_tracked_emote" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="tracked_emote" validate="true"/>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog-3.8.xsd" >
<include file="1.0-statistic/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,72 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException;
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.service.TrackedEmoteService;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class DeleteTrackedEmoteTest {
@InjectMocks
private DeleteTrackedEmote testUnit;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Mock
private TrackedEmoteService trackedEmoteService;
@Test(expected = InsufficientParametersException.class)
public void testTooLittleParameters() {
CommandTestUtilities.executeNoParametersTest(testUnit);
}
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTest(testUnit);
}
@Test
public void testExecuteWithExistingTrackedEmote() {
TrackedEmote fakedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(1L, 1L);
when(fakedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class);
when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote);
CommandResult result = testUnit.execute(CommandTestUtilities.getWithParameters(Arrays.asList(fakedEmote)));
CommandTestUtilities.checkSuccessfulCompletion(result);
verify(trackedEmoteService, times(1)).deleteTrackedEmote(actualTrackedEmote);
}
@Test(expected = TrackedEmoteNotFoundException.class)
public void testExecuteNonExistingTrackedEmote() {
TrackedEmote fakedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(1L, 1L);
when(fakedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenThrow(new TrackedEmoteNotFoundException());
testUnit.execute(CommandTestUtilities.getWithParameters(Arrays.asList(fakedEmote)));
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,97 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay;
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import static dev.sheldan.abstracto.statistic.emotes.command.DeletedEmoteStats.EMOTE_STATS_ANIMATED_DELETED_RESPONSE;
import static dev.sheldan.abstracto.statistic.emotes.command.DeletedEmoteStats.EMOTE_STATS_STATIC_DELETED_RESPONSE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class DeletedEmoteStatsTest {
@InjectMocks
private DeletedEmoteStats testUnit;
@Mock
private UsedEmoteService usedEmoteService;
@Mock
private ChannelService channelService;
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTestAsync(testUnit);
}
@Test
public void testWithoutParameterStaticEmotes() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithoutParameterAnimatedEmotesEmotes() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithoutParametersNoResult() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
when(model.areStatsAvailable()).thenReturn(false);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithParameterStaticEmotes() {
CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(4)));
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getDeletedEmoteStatsForServerSince(eq(noParameters.getUserInitiatedContext().getServer()), any(Instant.class))).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,63 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
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.service.TrackedEmoteService;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class DisableEmoteTrackingTest {
@InjectMocks
private DisableEmoteTracking testUnit;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTest(testUnit);
}
@Test
public void testDisableAllTracking() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
testUnit.execute(commandContext);
verify(trackedEmoteService, times(1)).disableEmoteTracking(commandContext.getGuild());
}
@Test
public void testDisableTrackingForOneTrackedEmote() {
TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class);
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote));
TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class);
when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote);
testUnit.execute(commandContext);
verify(trackedEmoteManagementService, times(1)).disableTrackedEmote(actualTrackedEmote);
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,96 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay;
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import static dev.sheldan.abstracto.statistic.emotes.command.EmoteStats.EMOTE_STATS_ANIMATED_RESPONSE;
import static dev.sheldan.abstracto.statistic.emotes.command.EmoteStats.EMOTE_STATS_STATIC_RESPONSE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class EmoteStatsTest {
@InjectMocks
private EmoteStats testUnit;
@Mock
private UsedEmoteService usedEmoteService;
@Mock
private ChannelService channelService;
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTestAsync(testUnit);
}
@Test
public void testWithoutParameterStaticEmotes() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getActiveEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithoutParameterAnimatedEmotesEmotes() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getActiveEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithoutParametersNoResult() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
when(model.areStatsAvailable()).thenReturn(false);
when(usedEmoteService.getActiveEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithParameterStaticEmotes() {
CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(4)));
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getActiveEmoteStatsForServerSince(eq(noParameters.getUserInitiatedContext().getServer()), any(Instant.class))).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,179 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.core.utils.FileUtils;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
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;
import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.statistic.emotes.command.ExportEmoteStats.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ExportEmoteStatsTest {
@InjectMocks
private ExportEmoteStats testUnit;
@Mock
private ServerManagementService serverManagementService;
@Mock
private TemplateService templateService;
@Mock
private ChannelService channelService;
@Mock
private UsedEmoteManagementService usedEmoteManagementService;
@Mock
private FileUtils fileUtils;
@Captor
private ArgumentCaptor<DownloadEmoteStatsModel> modelArgumentCaptor;
@Mock
private UsedEmote usedEmote;
private static final Long SERVER_ID = 4L;
private static final String FILE_NAME = "name";
private static final String FILE_CONTENT = "content";
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTestAsync(testUnit);
}
@Test
public void testExportAllEmoteStats() throws IOException {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getMaxFileSize()).thenReturn(4L);
mockServerAndFileRendering(commandContext);
File file = Mockito.mock(File.class);
when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file);
when(file.length()).thenReturn(3L);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY), any())).thenReturn(messageToSend);
when(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verify(fileUtils, times(1)).writeContentToFile(file, FILE_CONTENT);
verify(messageToSend, times(1)).setFileToSend(file);
verify(fileUtils, times(1)).safeDelete(file);
verifyModel();
}
@Test
public void testExportAllEmoteStatsSince() throws IOException {
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(3)));
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
AServer server = Mockito.mock(AServer.class);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
when(commandContext.getGuild().getMaxFileSize()).thenReturn(4L);
List<UsedEmote> usedEmotes = Arrays.asList(usedEmote);
when(usedEmoteManagementService.loadEmoteUsagesForServerSince(eq(server), any(Instant.class))).thenReturn(usedEmotes);
when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY), modelArgumentCaptor.capture())).thenReturn(FILE_NAME);
when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY), any())).thenReturn(FILE_CONTENT);
File file = Mockito.mock(File.class);
when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file);
when(file.length()).thenReturn(3L);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY), any())).thenReturn(messageToSend);
when(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verify(fileUtils, times(1)).writeContentToFile(file, FILE_CONTENT);
verify(messageToSend, times(1)).setFileToSend(file);
verify(fileUtils, times(1)).safeDelete(file);
verifyModel();
}
@Test
public void testExportNoStatsAvailable() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
AServer server = Mockito.mock(AServer.class);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
List<UsedEmote> usedEmotes = new ArrayList<>();
when(usedEmoteManagementService.loadEmoteUsagesForServerSince(server, Instant.EPOCH)).thenReturn(usedEmotes);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verify(channelService, times(1)).sendEmbedTemplateInChannel(eq(DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY), any(), eq(commandContext.getChannel()));
}
@Test(expected = AbstractoRunTimeException.class)
public void testFileIOException() throws IOException {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
mockServerAndFileRendering(commandContext);
File file = Mockito.mock(File.class);
when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file);
doThrow(new IOException()).when(fileUtils).writeContentToFile(file, FILE_CONTENT);
testUnit.executeAsync(commandContext);
}
@Test(expected = DownloadEmoteStatsFileTooBigException.class)
public void testExportAllEmoteStatsTooBig() throws IOException {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getMaxFileSize()).thenReturn(2L);
mockServerAndFileRendering(commandContext);
File file = Mockito.mock(File.class);
when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file);
when(file.length()).thenReturn(3L);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verify(fileUtils, times(1)).writeContentToFile(file, FILE_CONTENT);
verify(messageToSend, times(1)).setFileToSend(file);
verify(fileUtils, times(1)).safeDelete(file);
verifyModel();
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
private void verifyModel() {
DownloadEmoteStatsModel model = modelArgumentCaptor.getValue();
Assert.assertEquals(1, model.getEmotes().size());
Assert.assertEquals(usedEmote, model.getEmotes().get(0));
}
private void mockServerAndFileRendering(CommandContext commandContext) {
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
AServer server = Mockito.mock(AServer.class);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
List<UsedEmote> usedEmotes = Arrays.asList(usedEmote);
when(usedEmoteManagementService.loadEmoteUsagesForServerSince(server, Instant.EPOCH)).thenReturn(usedEmotes);
when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY), modelArgumentCaptor.capture())).thenReturn(FILE_NAME);
when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY), any())).thenReturn(FILE_CONTENT);
}
}

View File

@@ -0,0 +1,96 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay;
import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import static dev.sheldan.abstracto.statistic.emotes.command.ExternalEmoteStats.EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE;
import static dev.sheldan.abstracto.statistic.emotes.command.ExternalEmoteStats.EMOTE_STATS_STATIC_EXTERNAL_RESPONSE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ExternalEmoteStatsTest {
@InjectMocks
private ExternalEmoteStats testUnit;
@Mock
private UsedEmoteService usedEmoteService;
@Mock
private ChannelService channelService;
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTestAsync(testUnit);
}
@Test
public void testWithoutParameterStaticEmotes() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getExternalEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithoutParameterAnimatedEmotesEmotes() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getExternalEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithoutParametersNoResult() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
when(model.areStatsAvailable()).thenReturn(false);
when(usedEmoteService.getExternalEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testWithParameterStaticEmotes() {
CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(4)));
EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class);
EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class);
when(model.getStaticEmotes()).thenReturn(Arrays.asList(display));
when(model.areStatsAvailable()).thenReturn(true);
when(usedEmoteService.getExternalEmoteStatsForServerSince(eq(noParameters.getUserInitiatedContext().getServer()), any(Instant.class))).thenReturn(model);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters));
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,72 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
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.service.UsedEmoteService;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class PurgeEmoteStatsTest {
@InjectMocks
private PurgeEmoteStats testUnit;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Mock
private UsedEmoteService usedEmoteService;
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTest(testUnit);
}
@Test
public void testPurgeEntireTimeLineOfEmote() {
TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class);
when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote);
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote));
testUnit.execute(commandContext);
verify(usedEmoteService, times(1)).purgeEmoteUsagesSince(actualTrackedEmote, Instant.EPOCH);
}
@Test
public void testPurgeEmoteWithPeriod() {
TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class);
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote, Duration.ofHours(4)));
TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class);
when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote);
testUnit.execute(commandContext);
verify(usedEmoteService, times(1)).purgeEmoteUsagesSince(eq(actualTrackedEmote), any(Instant.class));
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,39 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class ResetEmoteStatsTest {
@InjectMocks
private ResetEmoteStats testUnit;
@Mock
private TrackedEmoteService trackedEmoteService;
@Test
public void testExecute() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
CommandResult result = testUnit.execute(commandContext);
CommandTestUtilities.checkSuccessfulCompletion(result);
verify(trackedEmoteService, times(1)).resetEmoteStats(commandContext.getGuild());
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,87 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
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.model.database.embed.TrackedEmoteServer;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.statistic.emotes.command.ShowExternalTrackedEmote.SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ShowExternalTrackedEmoteTest {
@InjectMocks
private ShowExternalTrackedEmote testUnit;
@Mock
private ChannelService channelService;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Test(expected = InsufficientParametersException.class)
public void testTooLittleParameters() {
CommandTestUtilities.executeNoParametersTestAsync(testUnit);
}
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTestAsync(testUnit);
}
@Test
public void testShowExternalEmote() {
TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class);
when(actualTrackedEmote.getExternal()).thenReturn(true);
TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class);
when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId())).thenReturn(actualTrackedEmote);
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote));
when(channelService.sendEmbedTemplateInChannel(SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY, actualTrackedEmote, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> resultFuture = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(resultFuture);
}
@Test(expected = AbstractoTemplatedException.class)
public void testShowNotExternalEmote() {
TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class);
TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class);
when(actualTrackedEmote.getExternal()).thenReturn(false);
TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class);
when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId())).thenReturn(actualTrackedEmote);
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote));
CompletableFuture<CommandResult> resultFuture = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(resultFuture);
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
@Test
public void testFeatureModeLimitations() {
Assert.assertTrue(testUnit.getFeatureModeLimitations().contains(EmoteTrackingMode.EXTERNAL_EMOTES));
}
}

View File

@@ -0,0 +1,233 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.model.AvailableTrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.statistic.emotes.command.ShowTrackedEmotes.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ShowTrackedEmotesTest {
@InjectMocks
private ShowTrackedEmotes testUnit;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private ChannelService channelService;
@Mock
private FeatureModeService featureModeService;
private static final Long SERVER_ID = 4L;
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTestAsync(testUnit);
}
@Test
public void testShowTrackedEmotesNoStats() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false);
when(channelService.sendEmbedTemplateInChannel(eq(EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(commandContext.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, false, true, true, true, true, true, true);
}
@Test
public void testShowTrackedEmotesNoStatsWithShowAll() {
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(Boolean.TRUE));
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false);
when(channelService.sendEmbedTemplateInChannel(eq(EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(commandContext.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), true)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, false, true, true, true, true, true, true);
}
@Test
public void testShowStaticEmotes() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
AvailableTrackedEmote staticEmote = Mockito.mock(AvailableTrackedEmote.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(overview.getStaticEmotes()).thenReturn(Arrays.asList(staticEmote));
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, true, false, true, true, true, true, true);
}
@Test
public void testShowAnimatedEmotes() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
AvailableTrackedEmote animatedEmote = Mockito.mock(AvailableTrackedEmote.class);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(overview.getAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, true, true, false, true, true, true, true);
}
@Test
public void testShowDeletedStaticEmote() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false);
TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(overview.getDeletedStaticEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, true, true, true, false, true, true, true);
}
@Test
public void testShowDeletedAnimatedEmote() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false);
TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(overview.getDeletedAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, true, true, true, true, false, true, true);
}
@Test
public void testShowExternalStatic() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(overview.getExternalStaticEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, true, true, true, true, true, false, true);
}
@Test
public void testShowExternalAnimated() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(overview.getExternalAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, true, true, true, true, true, true, false);
}
@Test
public void testShowAll() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class);
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
when(overview.getExternalAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(overview.getExternalStaticEmotes()).thenReturn(Arrays.asList(animatedEmote));
AvailableTrackedEmote trackedEmote = Mockito.mock(AvailableTrackedEmote.class);
when(overview.getStaticEmotes()).thenReturn(Arrays.asList(trackedEmote));
when(overview.getAnimatedEmotes()).thenReturn(Arrays.asList(trackedEmote));
when(overview.getDeletedStaticEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(overview.getDeletedAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote));
when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview);
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
verifyNoMessage(commandContext, true, false, false, false, false, false, false);
}
private void verifyNoMessage(CommandContext commandContext, boolean noStats, boolean staticEmote, boolean animatedEmote, boolean deletedStatic, boolean deletedAnimated, boolean externalStatic, boolean externalAnimated) {
if(noStats) {
verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(commandContext.getChannel()));
}
if(staticEmote) {
verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_STATIC_RESPONSE), any(), eq(commandContext.getChannel()));
}
if(animatedEmote) {
verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_ANIMATED_RESPONSE), any(), eq(commandContext.getChannel()));
}
if(deletedStatic) {
verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_DELETED_STATIC_RESPONSE), any(), eq(commandContext.getChannel()));
}
if(deletedAnimated) {
verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_DELETED_ANIMATED_RESPONSE), any(), eq(commandContext.getChannel()));
}
if(externalStatic) {
verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE), any(), eq(commandContext.getChannel()));
}
if(externalAnimated) {
verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE), any(), eq(commandContext.getChannel()));
}
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,50 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.statistic.emotes.command.SyncTrackedEmotes.SYNC_TRACKED_EMOTES_RESULT_RESPONSE;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class SyncTrackedEmotesTest {
@InjectMocks
private SyncTrackedEmotes testUnit;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private ChannelService channelService;
@Test
public void testExecuteSync() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
TrackedEmoteSynchronizationResult result = Mockito.mock(TrackedEmoteSynchronizationResult.class);
when(trackedEmoteService.synchronizeTrackedEmotes(commandContext.getGuild())).thenReturn(result);
when(channelService.sendEmbedTemplateInChannel(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, result, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> asyncResult = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult);
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,127 @@
package dev.sheldan.abstracto.statistic.emotes.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.exception.IncorrectFeatureModeException;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.command.parameter.TrackEmoteParameter;
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
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.service.TrackedEmoteService;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class TrackEmoteTest {
@InjectMocks
private TrackEmote testUnit;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Mock
private EmoteService emoteService;
@Mock
private FeatureModeService featureModeService;
@Mock
private TrackEmoteParameter trackEmoteParameter;
private static final Long EMOTE_ID = 4L;
private static final Long SERVER_ID = 5L;
@Test(expected = InsufficientParametersException.class)
public void testTooLittleParameters() {
CommandTestUtilities.executeNoParametersTest(testUnit);
}
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTest(testUnit);
}
@Test
public void testReTrackTrackedEmote(){
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter));
when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(true);
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class);
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
when(trackedEmoteManagementService.loadByEmoteId(EMOTE_ID, SERVER_ID)).thenReturn(trackedEmote);
when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote);
CommandResult result = testUnit.execute(commandContext);
CommandTestUtilities.checkSuccessfulCompletion(result);
verify(trackedEmoteManagementService, times(1)).enableTrackedEmote(trackedEmote);
}
@Test(expected = IncorrectFeatureModeException.class)
public void testTrackExternalWithExternalDisabled(){
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter));
when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(false);
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class);
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
Emote emoteToTrack = Mockito.mock(Emote.class);
when(trackEmoteParameter.getEmote()).thenReturn(emoteToTrack);
when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote);
when(emoteService.emoteIsFromGuild(emoteToTrack, commandContext.getGuild())).thenReturn(false);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false);
testUnit.execute(commandContext);
}
@Test
public void testTrackExternalWithExternalEnabled(){
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter));
when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(false);
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class);
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
Emote emoteToTrack = Mockito.mock(Emote.class);
when(trackEmoteParameter.getEmote()).thenReturn(emoteToTrack);
when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote);
when(emoteService.emoteIsFromGuild(emoteToTrack, commandContext.getGuild())).thenReturn(false);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
CommandResult result = testUnit.execute(commandContext);
CommandTestUtilities.checkSuccessfulCompletion(result);
verify(trackedEmoteService, times(1)).createFakeTrackedEmote(emoteToTrack, commandContext.getGuild());
}
@Test(expected = IncorrectParameterException.class)
public void testTrackExternalIncorrectParameter(){
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter));
when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(false);
when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID);
TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class);
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote);
testUnit.execute(commandContext);
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
}

View File

@@ -0,0 +1,83 @@
package dev.sheldan.abstracto.statistic.emotes.command.handler;
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.handler.TrackedEmoteParameterHandler;
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.Guild;
import net.dv8tion.jda.api.entities.Message;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class TrackedEmoteParameterHandlerTest {
@InjectMocks
private TrackedEmoteParameterHandler testUnit;
@Mock
private EmoteParameterHandler emoteParameterHandler;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private Message contextMessage;
@Mock
private CommandParameterIterators iterators;
@Mock
private Guild guild;
@Mock
private TrackedEmote trackedEmote;
private static final String WRONG_FORMATTED_INPUT = "input";
@Test
public void testHandleIncorrect() {
Assert.assertFalse(testUnit.handles(String.class));
}
@Test
public void testHandleCorrect() {
Assert.assertTrue(testUnit.handles(TrackedEmote.class));
}
@Test
public void testHandleWithEmote() {
when(contextMessage.getGuild()).thenReturn(guild);
Emote emote = Mockito.mock(Emote.class);
when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(emote);
when(trackedEmoteService.getFakeTrackedEmote(emote, guild)).thenReturn(trackedEmote);
TrackedEmote parsedEmote = (TrackedEmote) testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage);
Assert.assertEquals(trackedEmote, parsedEmote);
}
@Test
public void testHandleWithId() {
Long emoteId = 5L;
when(contextMessage.getGuild()).thenReturn(guild);
when(trackedEmoteService.getFakeTrackedEmote(emoteId, guild)).thenReturn(trackedEmote);
when(emoteParameterHandler.handle(emoteId.toString(), iterators, Emote.class, contextMessage)).thenReturn(null);
TrackedEmote parsedEmote = (TrackedEmote) testUnit.handle(emoteId.toString(), iterators, TrackedEmote.class, contextMessage);
verify(trackedEmoteService, times(0)).getFakeTrackedEmote(any(Emote.class), eq(guild));
Assert.assertEquals(trackedEmote, parsedEmote);
}
@Test(expected = NumberFormatException.class)
public void testWithIllegalInput() {
when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(null);
testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage);
}
}

View File

@@ -0,0 +1,89 @@
package dev.sheldan.abstracto.statistic.emotes.command.handler;
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.command.parameter.handler.TrackedEmoteParameterParameterHandler;
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.Guild;
import net.dv8tion.jda.api.entities.Message;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class TrackedEmoteParameterParameterHandlerTest {
@InjectMocks
private TrackedEmoteParameterParameterHandler testUnit;
@Mock
private EmoteParameterHandler emoteParameterHandler;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private Message contextMessage;
@Mock
private CommandParameterIterators iterators;
@Mock
private Guild guild;
@Mock
private TrackedEmote trackedEmote;
private static final String WRONG_FORMATTED_INPUT = "input";
@Test
public void testHandleIncorrect() {
Assert.assertFalse(testUnit.handles(String.class));
}
@Test
public void testHandleCorrect() {
Assert.assertTrue(testUnit.handles(TrackEmoteParameter.class));
}
@Test
public void testHandleWithEmote() {
when(contextMessage.getGuild()).thenReturn(guild);
Emote emote = Mockito.mock(Emote.class);
when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(emote);
when(trackedEmoteService.getFakeTrackedEmote(emote, guild)).thenReturn(trackedEmote);
TrackEmoteParameter parsedEmote = (TrackEmoteParameter) testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage);
Assert.assertEquals(trackedEmote, parsedEmote.getTrackedEmote());
Assert.assertEquals(emote, parsedEmote.getEmote());
}
@Test
public void testHandleWithId() {
Long emoteId = 5L;
when(contextMessage.getGuild()).thenReturn(guild);
when(trackedEmoteService.getFakeTrackedEmote(emoteId, guild)).thenReturn(trackedEmote);
when(emoteParameterHandler.handle(emoteId.toString(), iterators, Emote.class, contextMessage)).thenReturn(null);
TrackEmoteParameter parsedEmote = (TrackEmoteParameter) testUnit.handle(emoteId.toString(), iterators, TrackedEmote.class, contextMessage);
verify(trackedEmoteService, times(0)).getFakeTrackedEmote(any(Emote.class), eq(guild));
Assert.assertEquals(trackedEmote, parsedEmote.getTrackedEmote());
}
@Test(expected = NumberFormatException.class)
public void testWithIllegalInput() {
when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(null);
testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage);
}
}

View File

@@ -0,0 +1,138 @@
package dev.sheldan.abstracto.statistic.emotes.converter;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult;
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.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class EmoteStatsConverterTest {
@InjectMocks
private EmoteStatsConverter testUnit;
@Mock
private BotService botService;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Mock
private EmoteStatsResult emoteStatsResult;
@Mock
private EmoteStatsResult emoteStatsResult2;
@Mock
private TrackedEmote trackedEmote;
@Mock
private TrackedEmote trackedEmote2;
@Mock
private Guild guild;
private static final Long EMOTE_ID = 4L;
private static final Long EMOTE_ID_2 = 5L;
private static final Long SERVER_ID = 6L;
@Test
public void testFromEmoteStatsResultsEmpty() {
EmoteStatsModel result = testUnit.fromEmoteStatsResults(new ArrayList<>());
Assert.assertEquals(0, result.getStaticEmotes().size());
Assert.assertEquals(0, result.getAnimatedEmotes().size());
Assert.assertFalse(result.areStatsAvailable());
}
@Test
public void testFromEmoteStatsExternal() {
setupResults();
when(trackedEmote.getExternal()).thenReturn(true);
when(trackedEmote.getAnimated()).thenReturn(false);
when(trackedEmote2.getExternal()).thenReturn(true);
when(trackedEmote2.getAnimated()).thenReturn(true);
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
EmoteStatsModel result = testUnit.fromEmoteStatsResults(Arrays.asList(emoteStatsResult, emoteStatsResult2));
Assert.assertEquals(1, result.getStaticEmotes().size());
Assert.assertEquals(trackedEmote, result.getStaticEmotes().get(0).getTrackedEmote());
Assert.assertNull(result.getStaticEmotes().get(0).getEmote());
Assert.assertEquals(1, result.getAnimatedEmotes().size());
Assert.assertNull(result.getAnimatedEmotes().get(0).getEmote());
Assert.assertEquals(trackedEmote2, result.getAnimatedEmotes().get(0).getTrackedEmote());
Assert.assertTrue(result.areStatsAvailable());
}
@Test
public void testFromEmoteStatsInternal() {
setupResults();
when(trackedEmote.getExternal()).thenReturn(false);
when(trackedEmote.getAnimated()).thenReturn(false);
when(trackedEmote.getDeleted()).thenReturn(false);
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
when(trackedEmote2.getExternal()).thenReturn(false);
when(trackedEmote2.getAnimated()).thenReturn(true);
when(trackedEmote2.getDeleted()).thenReturn(false);
when(trackedEmote2.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID_2, SERVER_ID));
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
Emote emote1 = Mockito.mock(Emote.class);
when(guild.getEmoteById(EMOTE_ID)).thenReturn(emote1);
Emote emote2 = Mockito.mock(Emote.class);
when(guild.getEmoteById(EMOTE_ID_2)).thenReturn(emote2);
EmoteStatsModel result = testUnit.fromEmoteStatsResults(Arrays.asList(emoteStatsResult, emoteStatsResult2));
Assert.assertEquals(1, result.getStaticEmotes().size());
Assert.assertEquals(trackedEmote, result.getStaticEmotes().get(0).getTrackedEmote());
Assert.assertEquals(emote1, result.getStaticEmotes().get(0).getEmote());
Assert.assertEquals(1, result.getAnimatedEmotes().size());
Assert.assertEquals(emote2, result.getAnimatedEmotes().get(0).getEmote());
Assert.assertEquals(trackedEmote2, result.getAnimatedEmotes().get(0).getTrackedEmote());
Assert.assertTrue(result.areStatsAvailable());
}
@Test
public void testFromEmoteStatsInternalDeleted() {
setupResults();
when(trackedEmote.getExternal()).thenReturn(false);
when(trackedEmote.getDeleted()).thenReturn(true);
when(trackedEmote.getAnimated()).thenReturn(false);
when(trackedEmote2.getExternal()).thenReturn(false);
when(trackedEmote2.getAnimated()).thenReturn(true);
when(trackedEmote2.getDeleted()).thenReturn(true);
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
EmoteStatsModel result = testUnit.fromEmoteStatsResults(Arrays.asList(emoteStatsResult, emoteStatsResult2));
Assert.assertEquals(1, result.getStaticEmotes().size());
Assert.assertEquals(trackedEmote, result.getStaticEmotes().get(0).getTrackedEmote());
Assert.assertNull(result.getStaticEmotes().get(0).getEmote());
Assert.assertEquals(1, result.getAnimatedEmotes().size());
Assert.assertNull(result.getAnimatedEmotes().get(0).getEmote());
Assert.assertEquals(trackedEmote2, result.getAnimatedEmotes().get(0).getTrackedEmote());
Assert.assertTrue(result.areStatsAvailable());
}
private void setupResults() {
when(emoteStatsResult.getEmoteId()).thenReturn(EMOTE_ID);
when(emoteStatsResult.getServerId()).thenReturn(SERVER_ID);
when(trackedEmoteManagementService.loadByEmoteId(EMOTE_ID, SERVER_ID)).thenReturn(trackedEmote);
when(emoteStatsResult2.getEmoteId()).thenReturn(EMOTE_ID_2);
when(emoteStatsResult2.getServerId()).thenReturn(SERVER_ID);
when(trackedEmoteManagementService.loadByEmoteId(EMOTE_ID_2, SERVER_ID)).thenReturn(trackedEmote2);
}
}

View File

@@ -0,0 +1,72 @@
package dev.sheldan.abstracto.statistic.emotes.job;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteRuntimeService;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class EmotePersistingJobTest {
@InjectMocks
@Spy
private EmotePersistingJob testUnit;
@Mock
private TrackedEmoteRuntimeService trackedEmoteRuntimeService;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private JobExecutionContext executionContext;
@Test
public void testExecuteNoEmoteStats() throws JobExecutionException {
when(trackedEmoteRuntimeService.getRuntimeConfig()).thenReturn(new HashMap<>());
testUnit.executeInternal(executionContext);
verify(trackedEmoteService, times(0)).storeEmoteStatistics(any());
}
@Test
public void testExecuteWithStats() throws JobExecutionException {
Map<Long, Map<Long, List<PersistingEmote>>> emoteStats = new HashMap<>();
long minuteToPersist = 4L;
Map<Long, List<PersistingEmote>> statsForMinute = new HashMap<>();
statsForMinute.put(8L, new ArrayList<>());
emoteStats.put(minuteToPersist, statsForMinute);
when(trackedEmoteRuntimeService.getRuntimeConfig()).thenReturn(emoteStats);
when(testUnit.getPastMinute()).thenReturn(minuteToPersist);
testUnit.executeInternal(executionContext);
verify(trackedEmoteService, times(1)).storeEmoteStatistics(any());
}
@Test
public void testExecuteWithPastStats() throws JobExecutionException {
Map<Long, Map<Long, List<PersistingEmote>>> emoteStats = new HashMap<>();
long minuteToPersist = 4L;
Map<Long, List<PersistingEmote>> statsForMinute = new HashMap<>();
statsForMinute.put(8L, new ArrayList<>());
emoteStats.put(minuteToPersist, statsForMinute);
emoteStats.put(minuteToPersist - 2, statsForMinute);
when(trackedEmoteRuntimeService.getRuntimeConfig()).thenReturn(emoteStats);
when(testUnit.getPastMinute()).thenReturn(minuteToPersist);
testUnit.executeInternal(executionContext);
verify(trackedEmoteService, times(2)).storeEmoteStatistics(any());
}
}

View File

@@ -0,0 +1,49 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class CreateTrackedEmoteListenerTest {
@InjectMocks
private CreateTrackedEmoteListener testUnit;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Test
public void testEmoteCreated() {
Long serverId = 4L;
Long emoteId = 5L;
Emote emote = Mockito.mock(Emote.class);
Guild guild = Mockito.mock(Guild.class);
when(guild.getIdLong()).thenReturn(serverId);
when(emote.getIdLong()).thenReturn(emoteId);
when(emote.getGuild()).thenReturn(guild);
testUnit.emoteCreated(emote);
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote, guild);
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
@Test
public void testPriority() {
Assert.assertEquals(ListenerPriority.MEDIUM, testUnit.getPriority());
}
}

View File

@@ -0,0 +1,49 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class DeleteTrackedEmoteListenerTest {
@InjectMocks
private DeleteTrackedEmoteListener testUnit;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Test
public void testEmoteDeleted() {
Long serverId = 4L;
Long emoteId = 5L;
Emote emote = Mockito.mock(Emote.class);
Guild guild = Mockito.mock(Guild.class);
when(guild.getIdLong()).thenReturn(serverId);
when(emote.getIdLong()).thenReturn(emoteId);
when(emote.getGuild()).thenReturn(guild);
testUnit.emoteDeleted(emote);
verify(trackedEmoteManagementService, times(1)).markAsDeleted(serverId, emoteId);
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
@Test
public void testPriority() {
Assert.assertEquals(ListenerPriority.MEDIUM, testUnit.getPriority());
}
}

View File

@@ -0,0 +1,96 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import org.apache.commons.collections4.bag.HashBag;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class EmoteTrackingListenerTest {
@InjectMocks
private EmoteTrackingListener testUnit;
@Mock
private TrackedEmoteService trackedEmoteService;
@Mock
private Message message;
@Mock
private Emote emote1;
@Mock
private Emote emote2;
@Mock
private Guild guild;
private static final Long EMOTE_ID = 4L;
@Test
public void testExecuteOneEmote() {
HashBag<Emote> emotesBag = new HashBag<>();
emotesBag.add(emote1);
when(message.getGuild()).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag);
testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L);
}
@Test
public void testExecuteOneEmoteMultipleTimes() {
HashBag<Emote> emotesBag = new HashBag<>();
when(emote1.getIdLong()).thenReturn(EMOTE_ID);
when(emote2.getIdLong()).thenReturn(EMOTE_ID);
emotesBag.add(emote1);
emotesBag.add(emote2);
when(message.getGuild()).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag);
testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(any(Emote.class), eq(guild), eq(2L));
}
@Test
public void testExecuteMultipleEmotes() {
HashBag<Emote> emotesBag = new HashBag<>();
when(emote1.getIdLong()).thenReturn(EMOTE_ID);
when(emote2.getIdLong()).thenReturn(EMOTE_ID + 1);
emotesBag.add(emote1);
emotesBag.add(emote2);
when(message.getGuild()).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag);
testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote2, guild, 1L);
}
@Test
public void testExecuteNoEmote() {
when(message.getEmotesBag()).thenReturn(new HashBag<>());
testUnit.execute(message);
verify(trackedEmoteService, times(0)).addEmoteToRuntimeStorage(any(), any(), anyLong());
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
@Test
public void testPriority() {
Assert.assertEquals(ListenerPriority.LOW, testUnit.getPriority());
}
}

View File

@@ -0,0 +1,46 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
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.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class UpdateTrackedEmoteListenerTest {
@InjectMocks
private UpdateTrackedEmoteListener testUnit;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Test
public void testEmoteUpdated() {
Emote changedEmote = Mockito.mock(Emote.class);
TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class);
when(trackedEmoteManagementService.loadByEmote(changedEmote)).thenReturn(trackedEmote);
String newValue = "AFTER";
testUnit.emoteUpdated(changedEmote, "BEFORE", newValue);
verify(trackedEmoteManagementService, times(1)).changeName(trackedEmote, newValue);
}
@Test
public void testFeature() {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
}
@Test
public void testPriority() {
Assert.assertEquals(ListenerPriority.MEDIUM, testUnit.getPriority());
}
}

View File

@@ -0,0 +1,181 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class TrackedEmoteRuntimeServiceBeanTest {
@InjectMocks
@Spy
private TrackedEmoteRuntimeServiceBean testUnit;
@Mock
private TrackedEmoteRunTimeStorage trackedEmoteRunTimeStorage;
@Mock
private Guild guild;
@Mock
private Emote emote;
@Mock
private PersistingEmote persistingEmote;
@Captor
private ArgumentCaptor<HashMap<Long, List<PersistingEmote>>> putCaptor;
private static final Long COUNT = 4L;
private static final String URL = "url";
private static final Long EMOTE_ID = 8L;
private static final Long SECOND = 9L;
private static final Long SERVER_ID = 45L;
@Test
public void testCreateFromEmoteFromGuild() {
when(emote.getIdLong()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, false);
Assert.assertFalse(createdEmote.getExternal());
Assert.assertNull(createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
Assert.assertEquals(COUNT, createdEmote.getCount());
}
@Test
public void testCreateFromEmoteExternal() {
when(emote.getImageUrl()).thenReturn(URL);
when(emote.getIdLong()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, true);
Assert.assertTrue(createdEmote.getExternal());
Assert.assertEquals(URL, createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
Assert.assertEquals(COUNT, createdEmote.getCount());
}
@Test
public void testCreateFromEmoteOneCountFromGuild() {
when(emote.getIdLong()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, false);
Assert.assertFalse(createdEmote.getExternal());
Assert.assertNull(createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
Assert.assertEquals(1, createdEmote.getCount().longValue());
}
@Test
public void testCreateFromEmoteOneCountExternal() {
when(emote.getImageUrl()).thenReturn(URL);
when(emote.getIdLong()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, true);
Assert.assertTrue(createdEmote.getExternal());
Assert.assertEquals(URL, createdEmote.getExternalUrl());
Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId());
Assert.assertEquals(1, createdEmote.getCount().longValue());
}
@Test
public void testEmoteForServerWithoutExistingSecond() {
doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(false);
testUnit.addEmoteForServer(emote, guild, false);
verify(trackedEmoteRunTimeStorage, times(1)).put(eq(SECOND), putCaptor.capture());
HashMap<Long, List<PersistingEmote>> value = putCaptor.getValue();
Assert.assertEquals(1, value.keySet().size());
Assert.assertEquals(SERVER_ID, value.keySet().iterator().next());
List<PersistingEmote> createdEmotes = value.values().iterator().next();
Assert.assertEquals(1, createdEmotes.size());
Assert.assertEquals(EMOTE_ID, createdEmotes.get(0).getEmoteId());
}
@Test
public void testEmoteForServerWithExistingSecondButNotServer() {
doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, false);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> createdEmotes = serverMap.values().iterator().next();
Assert.assertEquals(1, createdEmotes.size());
Assert.assertEquals(EMOTE_ID, createdEmotes.get(0).getEmoteId());
}
@Test
public void testEmoteForServerWithExistingSecondAndServerButNotEmote() {
doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote)));
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, false);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> persistingEmotes = serverMap.values().iterator().next();
Assert.assertEquals(2, persistingEmotes.size());
Assert.assertEquals(persistingEmote, persistingEmotes.get(0));
Assert.assertEquals(EMOTE_ID, persistingEmotes.get(1).getEmoteId());
}
@Test
public void testEmoteForServerWithExistingSecondAndServerAndEmote() {
doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote)));
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, false);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> persistingEmotes = serverMap.values().iterator().next();
Assert.assertEquals(1, persistingEmotes.size());
PersistingEmote persistedEmote = persistingEmotes.get(0);
Assert.assertEquals(EMOTE_ID, persistedEmote.getEmoteId());
verify(persistedEmote, times(1)).setCount(COUNT + 1);
}
@Test
public void testEmoteForServerWithExistingSecondAndServerAndEmoteCustomCount() {
doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote)));
when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap);
testUnit.addEmoteForServer(emote, guild, COUNT, false);
Assert.assertEquals(1, serverMap.keySet().size());
Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next());
List<PersistingEmote> persistingEmotes = serverMap.values().iterator().next();
Assert.assertEquals(1, persistingEmotes.size());
PersistingEmote persistedEmote = persistingEmotes.get(0);
Assert.assertEquals(EMOTE_ID, persistedEmote.getEmoteId());
verify(persistedEmote, times(1)).setCount(COUNT + COUNT);
}
}

View File

@@ -0,0 +1,540 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.service.BotService;
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.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
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 net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Instant;
import java.util.*;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class TrackedEmoteServiceBeanTest {
private static final Long COUNT = 2L;
private static final Long SERVER_ID = 3L;
private static final Long EMOTE_ID = 5L;
private static final Long EMOTE_ID_2 = 6L;
@InjectMocks
private TrackedEmoteServiceBean testUnit;
@Mock
private TrackedEmoteRuntimeService trackedEmoteRuntimeService;
@Mock
private FeatureModeService featureModeService;
@Mock
private EmoteService emoteService;
@Mock
private TrackedEmoteManagementService trackedEmoteManagementService;
@Mock
private UsedEmoteManagementService usedEmoteManagementService;
@Mock
private BotService botService;
@Mock
private Emote emote;
@Mock
private Emote secondEmote;
@Mock
private Guild guild;
@Mock
private TrackedEmote trackedEmote;
@Mock
private TrackedEmote trackedEmote2;
@Mock
private TrackedEmoteServer trackedEmoteServer;
@Mock
private TrackedEmote secondTrackedEmote;
@Mock
private PersistingEmote persistingEmote;
@Mock
private PersistingEmote persistingEmote2;
@Mock
private UsedEmote usedEmote;
@Mock
private TrackedEmoteServer secondTrackedEmoteServer;
@Captor
private ArgumentCaptor<Emote> emoteArgumentCaptor;
@Captor
private ArgumentCaptor<Boolean> booleanArgumentCaptor;
@Test
public void addSingleServerEmote() {
externalEmotesEnabled(true);
isEmoteExternal(false);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT,false);
}
@Test
public void addSingleExternalEmote() {
externalEmotesEnabled(true);
isEmoteExternal(true);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT,true);
}
@Test
public void addSingleExternalWhenExternalDisabled() {
externalEmotesEnabled(false);
isEmoteExternal(true);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(eq(emote), eq(guild), anyBoolean());
}
@Test
public void addSingleServerEmoteExternalDisabled() {
externalEmotesEnabled(false);
isEmoteExternal(false);
testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT);
verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT, false);
}
@Test
public void addTwoExternalEmotes() {
externalEmotesEnabled(true);
bothEmotesExternal(true, true);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(true));
List<Emote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0));
Assert.assertEquals(secondEmote, usedEmotes.get(1));
}
@Test
public void addOneExternalAndOneLocalEmote() {
externalEmotesEnabled(true);
bothEmotesExternal(true, false);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
List<Emote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0));
Assert.assertEquals(secondEmote, usedEmotes.get(1));
List<Boolean> externalValues = booleanArgumentCaptor.getAllValues();
Assert.assertEquals(2, externalValues.size());
Assert.assertTrue(externalValues.get(0));
Assert.assertFalse(externalValues.get(1));
}
@Test
public void addTwoExternalEmotesWhenExternalDisabled() {
externalEmotesEnabled(false);
bothEmotesExternal(true, true);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
}
@Test
public void addTwoLocalEmotes() {
externalEmotesEnabled(false);
bothEmotesExternal(false, false);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
List<Emote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0));
Assert.assertEquals(secondEmote, usedEmotes.get(1));
List<Boolean> externalValues = booleanArgumentCaptor.getAllValues();
Assert.assertEquals(2, externalValues.size());
Assert.assertFalse(externalValues.get(0));
Assert.assertFalse(externalValues.get(1));
}
public void bothEmotesExternal(boolean external, boolean external2) {
when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external);
when(emoteService.emoteIsFromGuild(secondEmote, guild)).thenReturn(!external2);
}
public void isEmoteExternal(boolean external) {
when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external);
}
public void externalEmotesEnabled(boolean external) {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(external);
}
@Test
public void testCrateFakeEmote() {
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
TrackedEmote fakeTrackedEmote = testUnit.getFakeTrackedEmote(emote, guild);
Assert.assertTrue(fakeTrackedEmote.isFake());
Assert.assertEquals(EMOTE_ID, fakeTrackedEmote.getTrackedEmoteId().getEmoteId());
Assert.assertEquals(SERVER_ID, fakeTrackedEmote.getTrackedEmoteId().getServerId());
}
@Test
public void testCrateFakeEmoteViaId() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
TrackedEmote fakedTrackedEmote = testUnit.getFakeTrackedEmote(EMOTE_ID, guild);
Assert.assertTrue(fakedTrackedEmote.isFake());
Assert.assertEquals(EMOTE_ID, fakedTrackedEmote.getTrackedEmoteId().getEmoteId());
Assert.assertEquals(SERVER_ID, fakedTrackedEmote.getTrackedEmoteId().getServerId());
}
@Test
public void testSynchronizeTrackedEmotesNoNewEmotes() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID);
when(trackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID);
when(secondTrackedEmote.getTrackedEmoteId()).thenReturn(secondTrackedEmoteServer);
when(secondTrackedEmoteServer.getServerId()).thenReturn(SERVER_ID);
when(secondTrackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID_2);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote));
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(secondEmote.getIdLong()).thenReturn(EMOTE_ID_2);
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote)));
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(0L, result.getEmotesAdded().longValue());
Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue());
verify(trackedEmoteManagementService, times(0)).createTrackedEmote(any(Emote.class), any(Guild.class));
verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class));
}
@Test
public void testSynchronizeTrackedEmotesOneNewEmote() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID);
when(trackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote));
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote)));
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(1L, result.getEmotesAdded().longValue());
Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue());
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(secondEmote, guild);
verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class));
}
@Test
public void testSynchronizeTrackedEmotesWithEmotesDeleted() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID);
when(trackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote));
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote)));
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(0L, result.getEmotesAdded().longValue());
Assert.assertEquals(1L, result.getEmotesMarkedDeleted().longValue());
verify(trackedEmoteManagementService, times(0)).createTrackedEmote(any(Emote.class), any(Guild.class));
verify(trackedEmoteManagementService, times(1)).markAsDeleted(secondTrackedEmote);
}
@Test
public void testSynchronizeTrackedEmotesNoEmotesLeft() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(guild.getEmotes()).thenReturn(new ArrayList<>());
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote)));
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(0L, result.getEmotesAdded().longValue());
Assert.assertEquals(2L, result.getEmotesMarkedDeleted().longValue());
verify(trackedEmoteManagementService, times(0)).createTrackedEmote(any(Emote.class), any(Guild.class));
verify(trackedEmoteManagementService, times(2)).markAsDeleted(any(TrackedEmote.class));
}
@Test
public void testSynchronizeTrackedEmotesAllEmotesAreNew() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote));
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>());
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(2L, result.getEmotesAdded().longValue());
Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue());
verify(trackedEmoteManagementService, times(2)).createTrackedEmote(any(Emote.class), any(Guild.class));
verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class));
}
@Test
public void testStoreEmptyEmoteStatistics() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
testUnit.storeEmoteStatistics(usagesToStore);
verify(featureModeService, times(0)).featureModeActive(eq(StatisticFeatures.EMOTE_TRACKING), anyLong(), eq(EmoteTrackingMode.AUTO_TRACK));
}
@Test
public void testStoreStatisticOneServerExistingInternalEmoteUsageExistsYetTrackingEnabled() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote));
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.of(usedEmote));
when(trackedEmote.getTrackingEnabled()).thenReturn(true);
when(usedEmote.getAmount()).thenReturn(COUNT);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmote, times(1)).setAmount(2 * COUNT);
}
@Test
public void testStoreStatisticOneServerExistingInternalEmoteUsageExistsTrackingDisabled() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote));
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
when(trackedEmote.getTrackingEnabled()).thenReturn(false);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmote, times(0)).setAmount(anyLong());
}
@Test
public void testStoreStatisticOneServerExistingInternalEmoteNoUsageYetTrackingEnabled() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote));
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.empty());
when(trackedEmote.getTrackingEnabled()).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT);
}
@Test
public void testStoreStatisticOneServerNotInternalEmoteTrackingDisabledAutoTracking() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong());
}
@Test
public void testStoreStatisticOneServerInternalEmoteTrackingEnabledAutoTracking() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild));
when(guild.getEmoteById(EMOTE_ID)).thenReturn(emote);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(trackedEmoteManagementService.createTrackedEmote(emote, guild)).thenReturn(trackedEmote);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT);
}
@Test
public void testStoreStatisticOneServerExternalEmoteTrackingEnabledAutoTrackingDisabledExternal() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild));
when(guild.getEmoteById(EMOTE_ID)).thenReturn(null);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(false);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong());
}
@Test
public void testStoreStatisticOneServerExternalEmoteTrackingEnabledAutoTrackingEnabledExternal() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild));
when(guild.getEmoteById(EMOTE_ID)).thenReturn(null);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
when(trackedEmoteManagementService.createExternalEmote(persistingEmote)).thenReturn(trackedEmote);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT);
}
@Test
public void testStoreStatisticTwoServerInternalEmoteCreateNewTrackedEmote() {
HashMap<Long, List<PersistingEmote>> usagesToStore = new HashMap<>();
usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote));
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty());
when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild));
when(guild.getEmoteById(EMOTE_ID)).thenReturn(null);
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getCount()).thenReturn(COUNT);
when(trackedEmoteManagementService.createExternalEmote(persistingEmote)).thenReturn(trackedEmote);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
Long serverId2 = SERVER_ID + 1;
usagesToStore.put(serverId2, Arrays.asList(persistingEmote2));
when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID_2, serverId2)).thenReturn(Optional.of(trackedEmote));
when(trackedEmote.getTrackingEnabled()).thenReturn(true);
when(persistingEmote2.getEmoteId()).thenReturn(EMOTE_ID_2);
when(persistingEmote2.getCount()).thenReturn(COUNT);
when(usedEmote.getAmount()).thenReturn(COUNT);
when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.of(usedEmote));
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId2, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true);
when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId2, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true);
testUnit.storeEmoteStatistics(usagesToStore);
verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(eq(trackedEmote), anyLong());
verify(usedEmote, times(1)).setAmount(2 * COUNT);
}
@Test
public void testCreateFakeTrackedEmoteExternal() {
executeCreateFakeTrackedEmoteTest(true);
}
@Test
public void testCreateFakeTrackedEmoteInternal() {
executeCreateFakeTrackedEmoteTest(false);
}
private void executeCreateFakeTrackedEmoteTest(boolean external) {
when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external);
testUnit.createFakeTrackedEmote(emote, guild);
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote, guild, external);
}
@Test
public void testDeleteTrackedEmote() {
testUnit.deleteTrackedEmote(trackedEmote);
verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH);
verify(trackedEmoteManagementService, times(1)).deleteTrackedEmote(trackedEmote);
}
@Test
public void testResetEmoteStats() {
when(trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true)).thenReturn(Arrays.asList(trackedEmote));
testUnit.resetEmoteStats(guild);
verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH);
verify(trackedEmoteManagementService, times(1)).deleteTrackedEmote(trackedEmote);
}
@Test
public void testResetEmoteStatsNoEmotes() {
when(trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true)).thenReturn(new ArrayList<>());
testUnit.resetEmoteStats(guild);
verify(usedEmoteManagementService, times(0)).purgeEmoteUsagesSince(any(TrackedEmote.class), eq(Instant.EPOCH));
verify(trackedEmoteManagementService, times(0)).deleteTrackedEmote(any(TrackedEmote.class));
}
@Test
public void testDisableEmoteTracking() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote));
testUnit.disableEmoteTracking(guild);
verify(trackedEmote, times(1)).setTrackingEnabled(false);
}
@Test
public void testLoadTrackedEmoteOverviewInternal() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmote.getDeleted()).thenReturn(false);
when(trackedEmote.getExternal()).thenReturn(false);
when(trackedEmote.getAnimated()).thenReturn(false);
when(trackedEmote2.getDeleted()).thenReturn(false);
when(trackedEmote2.getExternal()).thenReturn(false);
when(trackedEmote2.getAnimated()).thenReturn(true);
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
when(trackedEmote2.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID_2, SERVER_ID));
when(guild.getEmoteById(EMOTE_ID)).thenReturn(emote);
Emote emote2 = Mockito.mock(Emote.class);
when(guild.getEmoteById(EMOTE_ID_2)).thenReturn(emote2);
when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2));
TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true);
Assert.assertEquals(emote, trackedEmoteOverview.getStaticEmotes().get(0).getEmote());
Assert.assertEquals(trackedEmote, trackedEmoteOverview.getStaticEmotes().get(0).getTrackedEmote());
Assert.assertEquals(emote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getEmote());
Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getTrackedEmote());
}
@Test
public void testLoadTrackedEmoteOverviewExternal() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmote.getDeleted()).thenReturn(false);
when(trackedEmote.getExternal()).thenReturn(true);
when(trackedEmote.getAnimated()).thenReturn(false);
when(trackedEmote2.getDeleted()).thenReturn(false);
when(trackedEmote2.getExternal()).thenReturn(true);
when(trackedEmote2.getAnimated()).thenReturn(true);
when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2));
TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true);
Assert.assertEquals(trackedEmote, trackedEmoteOverview.getExternalStaticEmotes().get(0));
Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getExternalAnimatedEmotes().get(0));
}
@Test
public void testLoadTrackedEmoteOverviewDeleted() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmote.getDeleted()).thenReturn(true);
when(trackedEmote.getAnimated()).thenReturn(false);
when(trackedEmote2.getDeleted()).thenReturn(true);
when(trackedEmote2.getAnimated()).thenReturn(true);
when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2));
TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true);
Assert.assertEquals(trackedEmote, trackedEmoteOverview.getDeletedStaticEmotes().get(0));
Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getDeletedAnimatedEmotes().get(0));
}
@Test
public void testLoadTrackedEmoteOverviewDeletedShowTrackedFalse() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmote.getDeleted()).thenReturn(true);
when(trackedEmote.getAnimated()).thenReturn(false);
when(trackedEmote2.getDeleted()).thenReturn(true);
when(trackedEmote2.getAnimated()).thenReturn(true);
when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, false)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2));
TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, false);
Assert.assertEquals(trackedEmote, trackedEmoteOverview.getDeletedStaticEmotes().get(0));
Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getDeletedAnimatedEmotes().get(0));
}
}

View File

@@ -0,0 +1,105 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emotes.converter.EmoteStatsConverter;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult;
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.service.management.UsedEmoteManagementService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class UsedEmoteServiceBeanTest {
@InjectMocks
private UsedEmoteServiceBean testUnit;
@Mock
private EmoteStatsConverter converter;
@Mock
private UsedEmoteManagementService usedEmoteManagementService;
@Mock
private AServer server;
@Mock
private EmoteStatsModel emoteStatsModel;
@Mock
private TrackedEmote trackedEmote;
private static final Instant pointInTime = Instant.parse("2020-12-12T00:00:00.00Z");
private static final Long SERVER_ID = 4L;
private static final Long EMOTE_ID = 7L;
@Test
public void testGetEmoteStatsForServerSince() {
List<EmoteStatsResult> mockedEmoteStatsResult = getMockedStatsResult();
when(usedEmoteManagementService.loadAllEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult);
when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel);
EmoteStatsModel result = testUnit.getEmoteStatsForServerSince(server, pointInTime);
Assert.assertEquals(emoteStatsModel, result);
}
@Test
public void testGetDeletedEmoteStatsForServerSince() {
List<EmoteStatsResult> mockedEmoteStatsResult = getMockedStatsResult();
when(usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult);
when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel);
EmoteStatsModel result = testUnit.getDeletedEmoteStatsForServerSince(server, pointInTime);
Assert.assertEquals(emoteStatsModel, result);
}
@Test
public void testGetExternalEmoteStatsForServerSince() {
List<EmoteStatsResult> mockedEmoteStatsResult = getMockedStatsResult();
when(usedEmoteManagementService.loadExternalEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult);
when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel);
EmoteStatsModel result = testUnit.getExternalEmoteStatsForServerSince(server, pointInTime);
Assert.assertEquals(emoteStatsModel, result);
}
@Test
public void testGetActiveEmoteStatsForServerSince() {
List<EmoteStatsResult> mockedEmoteStatsResult = getMockedStatsResult();
when(usedEmoteManagementService.loadActiveEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult);
when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel);
EmoteStatsModel result = testUnit.getActiveEmoteStatsForServerSince(server, pointInTime);
Assert.assertEquals(emoteStatsModel, result);
}
@Test
public void testPurgeEmoteUsagesSince() {
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
testUnit.purgeEmoteUsagesSince(trackedEmote, pointInTime);
verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, pointInTime);
}
@Test
public void testPurgeEmoteUsages() {
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
testUnit.purgeEmoteUsages(trackedEmote);
verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH);
}
private List<EmoteStatsResult> getMockedStatsResult() {
return Arrays.asList(Mockito.mock(EmoteStatsResult.class), Mockito.mock(EmoteStatsResult.class));
}
}

View File

@@ -0,0 +1,284 @@
package dev.sheldan.abstracto.statistic.emotes.service.management;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
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 net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class TrackedEmoteManagementServiceBeanTest {
private static final Long SERVER_ID = 3L;
private static final Long EMOTE_ID = 4L;
private static final String EMOTE_NAME = "name";
private static final Boolean ANIMATED = true;
private static final String EXTERNAL_URL = "url";
@InjectMocks
private TrackedEmoteManagementServiceBean testUnit;
@Mock
private TrackedEmoteRepository repository;
@Mock
private ServerManagementService serverManagementService;
@Mock
private Emote emote;
@Mock
private Guild guild;
@Mock
private AServer server;
@Mock
private TrackedEmote trackedEmote;
@Captor
private ArgumentCaptor<TrackedEmote> trackedEmoteArgumentCaptor;
@Test
public void testCreateTrackedEmote() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(emote.getName()).thenReturn(EMOTE_NAME);
when(emote.isAnimated()).thenReturn(ANIMATED);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
testUnit.createTrackedEmote(emote, guild);
verifyEmoteCreation(true, false, null);
}
@Test
public void testCreateTrackedEmoteAllParams() {
when(server.getId()).thenReturn(SERVER_ID);
testUnit.createTrackedEmote(EMOTE_ID, EMOTE_NAME, ANIMATED, server);
verifyEmoteCreation(true, false, null);
}
@Test
public void testCreateExternalEmote() {
when(server.getId()).thenReturn(SERVER_ID);
testUnit.createExternalEmote(EMOTE_ID, EMOTE_NAME, EXTERNAL_URL, ANIMATED, server);
verifyEmoteCreation(true, true, EXTERNAL_URL);
}
@Test
public void testCreateTrackedEmoteExternal() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(emote.getName()).thenReturn(EMOTE_NAME);
when(emote.getImageUrl()).thenReturn(EXTERNAL_URL);
when(emote.isAnimated()).thenReturn(ANIMATED);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
testUnit.createTrackedEmote(emote, guild, true);
verifyEmoteCreation(true, true, EXTERNAL_URL);
}
@Test
public void testCreateTrackedEmoteInternal() {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(emote.getName()).thenReturn(EMOTE_NAME);
when(emote.isAnimated()).thenReturn(ANIMATED);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
testUnit.createTrackedEmote(emote, guild, false);
verifyEmoteCreation(true, false, null);
}
@Test
public void testCreateNotTrackedEmote() {
when(server.getId()).thenReturn(SERVER_ID);
testUnit.createNotTrackedEmote(EMOTE_ID, EMOTE_NAME, ANIMATED, server);
verifyEmoteCreation(false, false, null);
}
@Test
public void testCreateExternalEmotePersistingEmote() {
when(server.getId()).thenReturn(SERVER_ID);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
PersistingEmote persistingEmote = Mockito.mock(PersistingEmote.class);
when(persistingEmote.getServerId()).thenReturn(SERVER_ID);
when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID);
when(persistingEmote.getEmoteName()).thenReturn(EMOTE_NAME);
when(persistingEmote.getAnimated()).thenReturn(ANIMATED);
when(persistingEmote.getExternalUrl()).thenReturn(EXTERNAL_URL);
testUnit.createExternalEmote(persistingEmote);
verifyEmoteCreation(true, true, EXTERNAL_URL);
}
@Test
public void testCreateExternalEmoteDirect() {
when(emote.getImageUrl()).thenReturn(EXTERNAL_URL);
when(emote.isAnimated()).thenReturn(ANIMATED);
when(emote.getName()).thenReturn(EMOTE_NAME);
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(server.getId()).thenReturn(SERVER_ID);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
testUnit.createExternalEmote(emote, guild);
verifyEmoteCreation(true, true, EXTERNAL_URL);
}
public void verifyEmoteCreation(boolean tracked, boolean external, String externalUrl) {
verify(repository, times(1)).save(trackedEmoteArgumentCaptor.capture());
TrackedEmote createdTrackedEmote = trackedEmoteArgumentCaptor.getValue();
Assert.assertEquals(EMOTE_ID, createdTrackedEmote.getTrackedEmoteId().getEmoteId());
Assert.assertEquals(SERVER_ID, createdTrackedEmote.getTrackedEmoteId().getServerId());
Assert.assertEquals(EMOTE_NAME, createdTrackedEmote.getEmoteName());
Assert.assertEquals(ANIMATED, createdTrackedEmote.getAnimated());
Assert.assertEquals(tracked, createdTrackedEmote.getTrackingEnabled());
Assert.assertEquals(server, createdTrackedEmote.getServer());
Assert.assertFalse(createdTrackedEmote.getDeleted());
Assert.assertEquals(external, createdTrackedEmote.getExternal());
Assert.assertEquals(externalUrl, createdTrackedEmote.getExternalUrl());
}
@Test
public void testMarkAsDeleted() {
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
testUnit.markAsDeleted(trackedEmote);
verify(trackedEmote, times(1)).setDeleted(true);
}
@Test
public void testMarkAsDeletedId() {
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote));
when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
testUnit.markAsDeleted(SERVER_ID, EMOTE_ID);
verify(trackedEmote, times(1)).setDeleted(true);
}
@Test
public void testLoadByEmoteEmote() {
when(emote.getIdLong()).thenReturn(EMOTE_ID);
when(emote.getGuild()).thenReturn(guild);
when(guild.getIdLong()).thenReturn(SERVER_ID);
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote));
TrackedEmote retrievedTrackedEmote = testUnit.loadByEmote(emote);
Assert.assertEquals(trackedEmote, retrievedTrackedEmote);
}
@Test
public void testLoadByEmoteId() {
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote));
TrackedEmote retrievedEmote = testUnit.loadByEmoteId(EMOTE_ID, SERVER_ID);
Assert.assertEquals(trackedEmote, retrievedEmote);
}
@Test(expected = AbstractoRunTimeException.class)
public void testLoadByEmoteIdNotFound() {
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(repository.findById(trackedEmoteServer)).thenReturn(Optional.empty());
testUnit.loadByEmoteId(EMOTE_ID, SERVER_ID);
}
@Test
public void testTrackedEmoteExists() {
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote));
boolean exists = testUnit.trackedEmoteExists(EMOTE_ID, SERVER_ID);
Assert.assertTrue(exists);
}
@Test
public void testTrackedEmoteExistsNot() {
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(repository.findById(trackedEmoteServer)).thenReturn(Optional.empty());
boolean exists = testUnit.trackedEmoteExists(EMOTE_ID, SERVER_ID);
Assert.assertFalse(exists);
}
@Test
public void testLoadByTrackedEmoteServer() {
TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID);
when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote));
TrackedEmote retrievedTrackedEmote = testUnit.loadByTrackedEmoteServer(trackedEmoteServer);
Assert.assertEquals(trackedEmote, retrievedTrackedEmote);
}
@Test
public void testGetAllActiveTrackedEmoteForServer() {
List<TrackedEmote> controlTrackedEmotes = Arrays.asList(trackedEmote);
when(repository.findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(SERVER_ID)).thenReturn(controlTrackedEmotes);
List<TrackedEmote> retrievedTrackedEmotes = testUnit.getAllActiveTrackedEmoteForServer(SERVER_ID);
Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes);
}
@Test
public void testGetAllActiveTrackedEmoteForServerId() {
when(server.getId()).thenReturn(SERVER_ID);
List<TrackedEmote> controlTrackedEmotes = Arrays.asList(trackedEmote);
when(repository.findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(SERVER_ID)).thenReturn(controlTrackedEmotes);
List<TrackedEmote> retrievedTrackedEmotes = testUnit.getAllActiveTrackedEmoteForServer(server);
Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes);
}
@Test
public void testGetTrackedEmoteForServerGetAll() {
List<TrackedEmote> controlTrackedEmotes = Arrays.asList(trackedEmote);
when(repository.findByTrackedEmoteId_ServerId(SERVER_ID)).thenReturn(controlTrackedEmotes);
List<TrackedEmote> retrievedTrackedEmotes = testUnit.getTrackedEmoteForServer(SERVER_ID, true);
Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes);
}
@Test
public void testGetTrackedEmoteForServerGet() {
List<TrackedEmote> controlTrackedEmotes = Arrays.asList(trackedEmote);
when(repository.findByTrackedEmoteId_ServerIdAndTrackingEnabledTrue(SERVER_ID)).thenReturn(controlTrackedEmotes);
List<TrackedEmote> retrievedTrackedEmotes = testUnit.getTrackedEmoteForServer(SERVER_ID, false);
Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes);
}
@Test
public void testSetName() {
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
testUnit.changeName(trackedEmote, EMOTE_NAME);
verify(trackedEmote, times(1)).setEmoteName(EMOTE_NAME);
}
@Test
public void testDisableTrackedEmote() {
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
testUnit.disableTrackedEmote(trackedEmote);
verify(trackedEmote, times(1)).setTrackingEnabled(false);
}
@Test
public void testEnableTrackedEmote() {
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
testUnit.enableTrackedEmote(trackedEmote);
verify(trackedEmote, times(1)).setTrackingEnabled(true);
}
@Test
public void testDeleteTrackedEmote() {
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
testUnit.deleteTrackedEmote(trackedEmote);
verify(repository, times(1)).delete(trackedEmote);
}
}

View File

@@ -0,0 +1,139 @@
package dev.sheldan.abstracto.statistic.emotes.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult;
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.repository.UsedEmoteRepository;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class UsedEmoteManagementServiceBeanTest {
private static final Long EMOTE_ID = 4L;
private static final Long SERVER_ID = 3L;
private static final Long COUNT = 5L;
@InjectMocks
private UsedEmoteManagementServiceBean testUnit;
@Mock
private UsedEmoteRepository usedEmoteRepository;
@Mock
private TrackedEmote trackedEmote;
@Mock
private UsedEmote usedEmote;
@Mock
private AServer server;
@Captor
private ArgumentCaptor<UsedEmote> usedEmoteArgumentCaptor;
@Test
public void testLoadUsedEmoteForTrackedEmoteToday() {
setupTrackedEmote();
when(usedEmoteRepository.findEmoteFromServerToday(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(usedEmote));
Optional<UsedEmote> usedEmoteOptional = testUnit.loadUsedEmoteForTrackedEmoteToday(trackedEmote);
Assert.assertTrue(usedEmoteOptional.isPresent());
usedEmoteOptional.ifPresent(usedEmote1 ->
Assert.assertEquals(usedEmote, usedEmote1)
);
}
@Test
public void testCreateEmoteUsageForToday() {
setupTrackedEmote();
testUnit.createEmoteUsageForToday(trackedEmote, COUNT);
verify(usedEmoteRepository, times(1)).save(usedEmoteArgumentCaptor.capture());
UsedEmote createdUsedEmote = usedEmoteArgumentCaptor.getValue();
Assert.assertEquals(COUNT, createdUsedEmote.getAmount());
Assert.assertEquals(EMOTE_ID, createdUsedEmote.getEmoteId().getEmoteId());
Assert.assertEquals(SERVER_ID, createdUsedEmote.getEmoteId().getServerId());
}
@Test
public void testPurgeEmoteUsagesSince() {
setupTrackedEmote();
testUnit.purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH);
verify(usedEmoteRepository, times(1)).deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(EMOTE_ID, SERVER_ID, Instant.EPOCH);
}
@Test
public void testLoadEmoteUsagesForServerSince() {
setupServer();
when(usedEmoteRepository.getByEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(SERVER_ID, Instant.EPOCH)).thenReturn(Arrays.asList(usedEmote));
List<UsedEmote> returnedUsedEmotes = testUnit.loadEmoteUsagesForServerSince(server, Instant.EPOCH);
Assert.assertEquals(1, returnedUsedEmotes.size());
Assert.assertEquals(usedEmote, returnedUsedEmotes.get(0));
}
@Test
public void testLoadAllEmoteStatsForServerSince() {
setupServer();
List<EmoteStatsResult> results = getEmoteStatsResults();
when(usedEmoteRepository.getEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadAllEmoteStatsForServerSince(server, Instant.EPOCH);
Assert.assertEquals(results.size(), returnedResult.size());
Assert.assertEquals(results, returnedResult);
}
@Test
public void testLoadDeletedEmoteStatsForServerSince() {
setupServer();
List<EmoteStatsResult> results = getEmoteStatsResults();
when(usedEmoteRepository.getDeletedEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadDeletedEmoteStatsForServerSince(server, Instant.EPOCH);
Assert.assertEquals(results.size(), returnedResult.size());
Assert.assertEquals(results, returnedResult);
}
@Test
public void testLoadExternalEmoteStatsForServerSince() {
setupServer();
List<EmoteStatsResult> results = getEmoteStatsResults();
when(usedEmoteRepository.getExternalEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadExternalEmoteStatsForServerSince(server, Instant.EPOCH);
Assert.assertEquals(results.size(), returnedResult.size());
Assert.assertEquals(results, returnedResult);
}
@Test
public void testLoadActiveEmoteStatsForServerSince() {
setupServer();
List<EmoteStatsResult> results = getEmoteStatsResults();
when(usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results);
List<EmoteStatsResult> returnedResult = testUnit.loadActiveEmoteStatsForServerSince(server, Instant.EPOCH);
Assert.assertEquals(results.size(), returnedResult.size());
Assert.assertEquals(results, returnedResult);
}
public List<EmoteStatsResult> getEmoteStatsResults() {
EmoteStatsResult emoteStatsResult = Mockito.mock(EmoteStatsResult.class);
EmoteStatsResult emoteStatsResult2 = Mockito.mock(EmoteStatsResult.class);
return Arrays.asList(emoteStatsResult, emoteStatsResult2);
}
private void setupTrackedEmote() {
when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID));
}
private void setupServer() {
when(server.getId()).thenReturn(SERVER_ID);
}
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>statistic-int</artifactId>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.scheduling</groupId>
<artifactId>scheduling-int</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,18 @@
package dev.sheldan.abstracto.statistic.config;
import dev.sheldan.abstracto.core.config.FeatureEnum;
public enum StatisticFeatures implements FeatureEnum {
EMOTE_TRACKING("emote_tracking");
private String key;
StatisticFeatures(String key) {
this.key = key;
}
@Override
public String getKey() {
return this.key;
}
}

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.statistic.emotes.config;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class EmoteTrackingFeature implements FeatureConfig {
@Override
public FeatureEnum getFeature() {
return StatisticFeatures.EMOTE_TRACKING;
}
@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES, EmoteTrackingMode.AUTO_TRACK, EmoteTrackingMode.AUTO_TRACK_EXTERNAL);
}
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.statistic.emotes.config;
import dev.sheldan.abstracto.core.config.FeatureMode;
import lombok.Getter;
@Getter
public enum EmoteTrackingMode implements FeatureMode {
AUTO_TRACK("emoteAutoTrack"), EXTERNAL_EMOTES("externalEmotes"), AUTO_TRACK_EXTERNAL("autoTrackExternal");
private final String key;
EmoteTrackingMode(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.statistic.emotes.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.statistic.emotes.model.exception.DownloadEmoteStatsFileTooBigModel;
import dev.sheldan.abstracto.templating.Templatable;
public class DownloadEmoteStatsFileTooBigException extends AbstractoRunTimeException implements Templatable {
private final DownloadEmoteStatsFileTooBigModel model;
public DownloadEmoteStatsFileTooBigException(Long fileSize, Long maxFileSize) {
this.model = DownloadEmoteStatsFileTooBigModel.builder().fileSize(fileSize).fileSizeLimit(maxFileSize).build();
}
@Override
public String getTemplateName() {
return "emote_stats_download_file_size_too_big";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.statistic.emotes.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
public class TrackedEmoteNotFoundException extends AbstractoRunTimeException {
public TrackedEmoteNotFoundException(String message) {
super(message);
}
public TrackedEmoteNotFoundException() {
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.statistic.emotes.model;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Emote;
@Getter
@Setter
@Builder
public class AvailableTrackedEmote {
private Emote emote;
private TrackedEmote trackedEmote;
}

View File

@@ -0,0 +1,25 @@
package dev.sheldan.abstracto.statistic.emotes.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Guild;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@Builder
public class EmoteStatsModel {
@Builder.Default
private List<EmoteStatsResultDisplay> animatedEmotes = new ArrayList<>();
@Builder.Default
private List<EmoteStatsResultDisplay> staticEmotes = new ArrayList<>();
private Guild guild;
public boolean areStatsAvailable() {
return !animatedEmotes.isEmpty() || !staticEmotes.isEmpty();
}
}

View File

@@ -0,0 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.model;
public interface EmoteStatsResult {
Long getEmoteId();
Long getServerId();
Long getAmount();
}

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