[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

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

View File

@@ -0,0 +1,16 @@
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 EmoteStatsResultDisplay {
private Emote emote;
private EmoteStatsResult result;
private TrackedEmote trackedEmote;
}

View File

@@ -0,0 +1,18 @@
package dev.sheldan.abstracto.statistic.emotes.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class PersistingEmote {
private Long emoteId;
private String emoteName;
private Boolean animated;
private Boolean external;
private String externalUrl;
private Long count;
private Long serverId;
}

View File

@@ -0,0 +1,62 @@
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.Guild;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@Builder
public class TrackedEmoteOverview {
@Builder.Default
private List<AvailableTrackedEmote> animatedEmotes = new ArrayList<>();
@Builder.Default
private List<AvailableTrackedEmote> staticEmotes = new ArrayList<>();
@Builder.Default
private List<TrackedEmote> deletedStaticEmotes = new ArrayList<>();
@Builder.Default
private List<TrackedEmote> deletedAnimatedEmotes = new ArrayList<>();
@Builder.Default
private List<TrackedEmote> externalStaticEmotes = new ArrayList<>();
@Builder.Default
private List<TrackedEmote> externalAnimatedEmotes = new ArrayList<>();
private Guild guild;
public void addTrackedEmote(TrackedEmote trackedEmote, Guild guild) {
if(trackedEmote.getDeleted()) {
if(trackedEmote.getAnimated()) {
deletedAnimatedEmotes.add(trackedEmote);
} else {
deletedStaticEmotes.add(trackedEmote);
}
} else if(trackedEmote.getExternal()){
if(trackedEmote.getAnimated()) {
externalAnimatedEmotes.add(trackedEmote);
} else {
externalStaticEmotes.add(trackedEmote);
}
} else {
AvailableTrackedEmote availableEmote = AvailableTrackedEmote
.builder()
.emote(guild.getEmoteById(trackedEmote.getTrackedEmoteId().getEmoteId()))
.trackedEmote(trackedEmote)
.build();
if(trackedEmote.getAnimated()) {
animatedEmotes.add(availableEmote);
} else {
staticEmotes.add(availableEmote);
}
}
}
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.statistic.emotes.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class TrackedEmoteSynchronizationResult {
private Long emotesAdded;
private Long emotesMarkedDeleted;
}

View File

@@ -0,0 +1,69 @@
package dev.sheldan.abstracto.statistic.emotes.model.database;
import dev.sheldan.abstracto.core.models.Fakeable;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer;
import lombok.*;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.io.Serializable;
import java.time.Instant;
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "tracked_emote")
@Getter
@Setter
@EqualsAndHashCode
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class TrackedEmote implements Serializable, Fakeable {
@EmbeddedId
private TrackedEmoteServer trackedEmoteId;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@MapsId("serverId")
@JoinColumn(name = "server_id", referencedColumnName = "id", nullable = false)
private AServer server;
@Column(name = "name", length = 32)
private String emoteName;
@Column(name = "animated")
private Boolean animated;
@Column(name = "tracking_enabled")
private Boolean trackingEnabled;
@Column(name = "deleted")
private Boolean deleted;
@Column(name = "external")
private Boolean external;
@Column(name = "external_url")
private String externalUrl;
@Column(name = "created")
private Instant created;
@PrePersist
private void onInsert() {
this.created = Instant.now();
}
@Column(name = "updated")
private Instant updated;
@PreUpdate
private void onUpdate() {
this.updated = Instant.now();
}
@Transient
private boolean fake;
}

View File

@@ -0,0 +1,34 @@
package dev.sheldan.abstracto.statistic.emotes.model.database;
import dev.sheldan.abstracto.statistic.emotes.model.database.embed.UsedEmoteDay;
import lombok.*;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "used_emote")
@Getter
@Setter
@EqualsAndHashCode
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class UsedEmote {
@EmbeddedId
private UsedEmoteDay emoteId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns(
{
@JoinColumn(updatable = false, insertable = false, name = "emote_id", referencedColumnName = "id"),
@JoinColumn(updatable = false, insertable = false, name = "server_id", referencedColumnName = "server_id")
})
private TrackedEmote trackedEmote;
@Column(name = "amount")
private Long amount;
}

View File

@@ -0,0 +1,21 @@
package dev.sheldan.abstracto.statistic.emotes.model.database.embed;
import lombok.*;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;
@Embeddable
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class TrackedEmoteServer implements Serializable {
@Column(name = "id")
private Long emoteId;
@Column(name = "server_id")
private Long serverId;
}

View File

@@ -0,0 +1,25 @@
package dev.sheldan.abstracto.statistic.emotes.model.database.embed;
import lombok.*;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;
import java.time.Instant;
@Embeddable
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class UsedEmoteDay implements Serializable {
@Column(name = "emote_id")
private Long emoteId;
@Column(name = "server_id")
private Long serverId;
@Column(name = "use_date")
private Instant useDate;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.statistic.emotes.model.exception;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@Builder
public class DownloadEmoteStatsFileTooBigModel implements Serializable {
private Long fileSize;
private Long fileSizeLimit;
}

View File

@@ -0,0 +1,17 @@
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 java.util.List;
import java.util.Map;
public interface TrackedEmoteRuntimeService {
Map<Long, Map<Long, List<PersistingEmote>>> getRuntimeConfig();
void addEmoteForServer(Emote emote, Guild guild, boolean external);
void addEmoteForServer(Emote emote, Guild guild, Long count, boolean external);
Long getKey();
PersistingEmote createFromEmote(Guild guild, Emote emote, boolean external);
PersistingEmote createFromEmote(Guild guild, Emote emote, Long count, boolean external);
}

View File

@@ -0,0 +1,26 @@
package dev.sheldan.abstracto.statistic.emotes.service;
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 net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import java.util.Map;
import java.util.List;
public interface TrackedEmoteService {
void addEmoteToRuntimeStorage(List<Emote> emotes, Guild guild);
void addEmoteToRuntimeStorage(Emote emote, Guild guild, Long count);
void storeEmoteStatistics(Map<Long, List<PersistingEmote>> usagesToStore);
TrackedEmote getFakeTrackedEmote(Emote emote, Guild guild);
TrackedEmote getFakeTrackedEmote(Long id, Guild guild);
TrackedEmoteSynchronizationResult synchronizeTrackedEmotes(Guild guild);
TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild);
TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild, Boolean showTrackingDisabled);
TrackedEmote createFakeTrackedEmote(Emote emote, Guild guild);
void deleteTrackedEmote(TrackedEmote trackedEmote);
void resetEmoteStats(Guild guild);
void disableEmoteTracking(Guild guild);
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
import java.time.Instant;
public interface UsedEmoteService {
EmoteStatsModel getEmoteStatsForServerSince(AServer server, Instant since);
EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since);
EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since);
EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since);
void purgeEmoteUsagesSince(TrackedEmote emote, Instant since);
void purgeEmoteUsages(TrackedEmote emote);
}

View File

@@ -0,0 +1,36 @@
package dev.sheldan.abstracto.statistic.emotes.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
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 net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import java.util.List;
import java.util.Optional;
public interface TrackedEmoteManagementService {
TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server);
TrackedEmote createTrackedEmote(Emote emote, Guild guild);
TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external);
TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, Boolean tracked, AServer server);
TrackedEmote createExternalEmote(Long emoteId, String emoteName, String externalUrl, Boolean animated, AServer server);
TrackedEmote createNotTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server);
TrackedEmote createExternalEmote(PersistingEmote persistingEmote);
TrackedEmote createExternalEmote(Emote emote, Guild guild);
void markAsDeleted(Long serverId, Long emoteId);
void markAsDeleted(TrackedEmote trackedemote);
TrackedEmote loadByEmoteId(Long emoteId, Long serverId);
TrackedEmote loadByEmote(Emote emote);
boolean trackedEmoteExists(Long emoteId, Long serverId);
TrackedEmote loadByTrackedEmoteServer(TrackedEmoteServer trackedEmoteServer);
Optional<TrackedEmote> loadByEmoteIdOptional(Long emoteId, Long serverId);
List<TrackedEmote> getAllActiveTrackedEmoteForServer(AServer server);
List<TrackedEmote> getAllActiveTrackedEmoteForServer(Long serverId);
List<TrackedEmote> getTrackedEmoteForServer(Long serverId, Boolean showTrackingDisabledEmotes);
void changeName(TrackedEmote emote, String name);
void disableTrackedEmote(TrackedEmote emote);
void enableTrackedEmote(TrackedEmote emote);
void deleteTrackedEmote(TrackedEmote emote);
}

View File

@@ -0,0 +1,21 @@
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 java.time.Instant;
import java.util.List;
import java.util.Optional;
public interface UsedEmoteManagementService {
Optional<UsedEmote> loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote);
UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count);
List<UsedEmote> loadEmoteUsagesForServerSince(AServer server, Instant since);
List<EmoteStatsResult> loadAllEmoteStatsForServerSince(AServer server, Instant since);
List<EmoteStatsResult> loadDeletedEmoteStatsForServerSince(AServer server, Instant since);
List<EmoteStatsResult> loadExternalEmoteStatsForServerSince(AServer server, Instant since);
List<EmoteStatsResult> loadActiveEmoteStatsForServerSince(AServer server, Instant since);
void purgeEmoteUsagesSince(TrackedEmote emote, Instant since);
}