mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-25 11:22:06 +00:00
[AB-84] adding profanity filter with different feature modes
react command: adding additional mapping for character r
This commit is contained in:
@@ -119,7 +119,8 @@
|
||||
"♌"
|
||||
],
|
||||
"r": [
|
||||
"🇷"
|
||||
"🇷",
|
||||
"🌱"
|
||||
],
|
||||
"s": [
|
||||
"🇸",
|
||||
|
||||
@@ -57,7 +57,8 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService {
|
||||
|
||||
@Override
|
||||
public Long calculateExperienceToNextLevel(Integer level, Long currentExperience) {
|
||||
AExperienceLevel nextLevel = experienceLevelManagementService.getLevel(level + 1).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", level)));
|
||||
AExperienceLevel nextLevel = experienceLevelManagementService.getLevel(level + 1)
|
||||
.orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", level)));
|
||||
return nextLevel.getExperienceNeeded() - currentExperience;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import dev.sheldan.abstracto.core.metric.service.MetricTag;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel;
|
||||
import dev.sheldan.abstracto.core.service.*;
|
||||
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
@@ -25,7 +24,6 @@ import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Invite;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.entities.MessageType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -67,14 +65,14 @@ public class InviteLinkFilterListener implements AsyncMessageReceivedListener {
|
||||
@Autowired
|
||||
private RoleImmunityService roleImmunityService;
|
||||
|
||||
public static final String MODERATION_PURGE_METRIC = "invite.filter";
|
||||
public static final String INVITE_FILTER_METRIC = "invite.filter";
|
||||
public static final String CONSEQUENCE = "consequence";
|
||||
|
||||
private static final CounterMetric MESSAGE_INVITE_FILTERED =
|
||||
CounterMetric
|
||||
.builder()
|
||||
.tagList(Arrays.asList(MetricTag.getTag(CONSEQUENCE, "filtered")))
|
||||
.name(MODERATION_PURGE_METRIC)
|
||||
.name(INVITE_FILTER_METRIC)
|
||||
.build();
|
||||
|
||||
public static final String INVITE_LINK_DELETED_NOTIFICATION_EMBED_TEMPLATE_KEY = "invite_link_deleted_notification";
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<module>webservices</module>
|
||||
<module>logging</module>
|
||||
<module>invite-filter</module>
|
||||
<module>profanity-filter</module>
|
||||
</modules>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?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>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.2.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>profanity-filter</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>profanity-filter-int</module>
|
||||
<module>profanity-filter-impl</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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>
|
||||
<artifactId>profanity-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.2.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>profanity-filter-impl</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<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>profanity-filter-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>metrics-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,93 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.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.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterFeatureDefinition;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterMode;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterModerationModuleDefinition;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.template.ProfanitiesModel;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.ProfanityFilterService;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.management.ProfanityUserInServerManagementService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class Profanities extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private ProfanityFilterService profanityFilterService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityUserInServerManagementService profanityUserInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
private static final String PROFANITIES_TEMPLATE_KEY = "profanities_response";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
Member member = (Member) commandContext.getParameters().getParameters().get(0);
|
||||
AUserInAServer userInServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
ProfanityUserInAServer profanityUser = profanityUserInServerManagementService.getProfanityUser(userInServer);
|
||||
Long positiveReports = profanityFilterService.getPositiveReportCountForUser(profanityUser);
|
||||
Long falsePositives = profanityFilterService.getFalseProfanityReportCountForUser(profanityUser);
|
||||
List<ServerChannelMessage> reports = profanityFilterService.getRecentPositiveReports(profanityUser, 3);
|
||||
ProfanitiesModel model = ProfanitiesModel
|
||||
.builder()
|
||||
.member(member)
|
||||
.recentPositiveReports(reports)
|
||||
.falsePositives(falsePositives)
|
||||
.truePositives(positiveReports)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(PROFANITIES_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
Parameter memberParameter = Parameter.builder().templated(true).name("member").type(Member.class).optional(true).build();
|
||||
List<Parameter> parameters = Collections.singletonList(memberParameter);
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("profanities")
|
||||
.module(ProfanityFilterModerationModuleDefinition.MODERATION)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.causesReaction(false)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ProfanityFilterFeatureDefinition.PROFANITY_FILTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(ProfanityFilterMode.TRACK_PROFANITIES);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:profanityFilter-config.properties")
|
||||
public class ProfanityFilterProperties {
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
|
||||
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
|
||||
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricService;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricTag;
|
||||
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
|
||||
import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel;
|
||||
import dev.sheldan.abstracto.core.service.FeatureModeService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.core.service.ProfanityService;
|
||||
import dev.sheldan.abstracto.core.service.RoleImmunityService;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterFeatureDefinition;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterMode;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.ProfanityFilterService;
|
||||
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 javax.annotation.PostConstruct;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.sheldan.abstracto.profanityfilter.service.ProfanityFilterService.PROFANITY_FILTER_EFFECT_KEY;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ProfanityDetectionListener implements AsyncMessageReceivedListener {
|
||||
|
||||
@Autowired
|
||||
private ProfanityService profanityService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityFilterService profanityFilterService;
|
||||
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Autowired
|
||||
private MetricService metricService;
|
||||
|
||||
@Autowired
|
||||
private RoleImmunityService roleImmunityService;
|
||||
|
||||
public static final String MODERATION_PURGE_METRIC = "profanity.filter";
|
||||
public static final String STEP = "step";
|
||||
|
||||
private static final CounterMetric PROFANITIES_DETECTED_METRIC =
|
||||
CounterMetric
|
||||
.builder()
|
||||
.tagList(Arrays.asList(MetricTag.getTag(STEP, "detection")))
|
||||
.name(MODERATION_PURGE_METRIC)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MessageReceivedModel model) {
|
||||
Message message = model.getMessage();
|
||||
if(message.isWebhookMessage() || message.getType().isSystem() || !message.isFromGuild()) {
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
|
||||
if(roleImmunityService.isImmune(message.getMember(), PROFANITY_FILTER_EFFECT_KEY)) {
|
||||
log.info("Not checking for profanities in message, because author {} in channel {} in guild {} is immune against profanity filter.",
|
||||
message.getMember().getIdLong(), message.getGuild().getIdLong(), message.getChannel().getIdLong());
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
|
||||
Long serverId = model.getServerId();
|
||||
Optional<ProfanityRegex> potentialProfanityGroup = profanityService.getProfanityRegex(message.getContentRaw(), serverId);
|
||||
if(potentialProfanityGroup.isPresent()) {
|
||||
metricService.incrementCounter(PROFANITIES_DETECTED_METRIC);
|
||||
if(featureModeService.featureModeActive(ProfanityFilterFeatureDefinition.PROFANITY_FILTER, serverId, ProfanityFilterMode.PROFANITY_REPORT)) {
|
||||
ProfanityRegex foundProfanityGroup = potentialProfanityGroup.get();
|
||||
profanityFilterService.createProfanityReport(message, foundProfanityGroup).exceptionally(throwable -> {
|
||||
log.error("Failed to report or persist profanities in server {} for message {} in channel {}.",
|
||||
serverId, message.getChannel().getIdLong(), message.getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
if(featureModeService.featureModeActive(ProfanityFilterFeatureDefinition.PROFANITY_FILTER, serverId, ProfanityFilterMode.AUTO_DELETE_PROFANITIES)) {
|
||||
messageService.deleteMessage(message).exceptionally(throwable -> {
|
||||
log.error("Failed to delete profanity message with id {} in channel {} in server {}.",
|
||||
message.getIdLong(), message.getChannel().getIdLong(), message.getGuild().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ProfanityFilterFeatureDefinition.PROFANITY_FILTER;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
metricService.registerCounter(PROFANITIES_DETECTED_METRIC, "Amount of profanities detected");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
|
||||
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import dev.sheldan.abstracto.core.models.listener.ReactionAddedModel;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterFeatureDefinition;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUse;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.ProfanityFilterService;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.management.ProfanityUseManagementService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static dev.sheldan.abstracto.profanityfilter.service.ProfanityFilterService.PROFANITY_VOTES_CONFIG_KEY;
|
||||
|
||||
@Component
|
||||
public class ProfanityReportVoteListener implements AsyncReactionAddedListener {
|
||||
|
||||
@Autowired
|
||||
private EmoteService emoteService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityUseManagementService profanityUseManagementService;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityFilterService profanityFilterService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(ReactionAddedModel model) {
|
||||
Optional<ProfanityUse> profanityUseOptional = profanityUseManagementService.getProfanityUseViaReportMessageId(model.getMessage().getMessageId());
|
||||
if(profanityUseOptional.isPresent()) {
|
||||
ProfanityUse use = profanityUseOptional.get();
|
||||
if(use.getVerified()) {
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
AEmote addedEmote = emoteService.buildAEmoteFromReaction(model.getReaction().getReactionEmote());
|
||||
AEmote agreeEmote = emoteService.getEmoteOrDefaultEmote(ProfanityFilterService.REPORT_AGREE_EMOTE, model.getServerId());
|
||||
boolean isAgreement = emoteService.compareAEmote(addedEmote, agreeEmote);
|
||||
boolean reactionWasVote;
|
||||
AEmote disApproveEmote = emoteService.getEmoteOrDefaultEmote(ProfanityFilterService.REPORT_DISAGREE_EMOTE, model.getServerId());
|
||||
if(!isAgreement) {
|
||||
reactionWasVote = emoteService.compareAEmote(addedEmote, disApproveEmote);
|
||||
} else {
|
||||
reactionWasVote = true;
|
||||
}
|
||||
if(reactionWasVote) {
|
||||
ProfanityFilterService.VoteResult voteResult = getVoteResultOnMessage(model.getMessage(), agreeEmote, disApproveEmote);
|
||||
if(ProfanityFilterService.VoteResult.isFinal(voteResult)) {
|
||||
profanityFilterService.verifyProfanityUse(use, voteResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
|
||||
private ProfanityFilterService.VoteResult getVoteResultOnMessage(CachedMessage cachedMessage, AEmote agreementEmote, AEmote disagreementEmote) {
|
||||
Long voteThreshold = configService.getLongValueOrConfigDefault(PROFANITY_VOTES_CONFIG_KEY, cachedMessage.getServerId());
|
||||
Optional<CachedReactions> agreementReactionsOptional = emoteService.getReactionFromMessageByEmote(cachedMessage, agreementEmote);
|
||||
Optional<CachedReactions> disAgreementReactionsOptional = emoteService.getReactionFromMessageByEmote(cachedMessage, disagreementEmote);
|
||||
int agreementVotes = 0;
|
||||
int disagreementVotes = 0;
|
||||
if(agreementReactionsOptional.isPresent()) {
|
||||
agreementVotes = getUserCount(agreementReactionsOptional.get());
|
||||
}
|
||||
if(disAgreementReactionsOptional.isPresent()) {
|
||||
disagreementVotes = getUserCount(disAgreementReactionsOptional.get());
|
||||
}
|
||||
if(agreementVotes >= voteThreshold) {
|
||||
return ProfanityFilterService.VoteResult.AGREEMENT;
|
||||
} else if(disagreementVotes >= voteThreshold) {
|
||||
return ProfanityFilterService.VoteResult.DISAGREEMENT;
|
||||
} else {
|
||||
return ProfanityFilterService.VoteResult.BELOW_THRESHOLD;
|
||||
}
|
||||
}
|
||||
|
||||
private int getUserCount(CachedReactions agreementReactionsOptional) {
|
||||
int reactionCount = agreementReactionsOptional.getUsers().size();
|
||||
if(agreementReactionsOptional.getSelf()) {
|
||||
reactionCount--;
|
||||
}
|
||||
return reactionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ProfanityFilterFeatureDefinition.PROFANITY_FILTER;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.repository;
|
||||
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUse;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface ProfanityUseRepository extends JpaRepository<ProfanityUse, Long> {
|
||||
Long countByProfanityUserAndVerifiedTrueAndConfirmedTrue(ProfanityUserInAServer profanityUserInAServer);
|
||||
Long countByProfanityUserAndVerifiedTrueAndConfirmedFalse(ProfanityUserInAServer profanityUserInAServer);
|
||||
List<ProfanityUse> findAllByProfanityUserAndConfirmedTrueOrderByCreatedDesc(ProfanityUserInAServer profanityUserInAServer, Pageable pageable);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.repository;
|
||||
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProfanityUserInServerRepository extends JpaRepository<ProfanityUserInAServer, Long> {
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricService;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricTag;
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
|
||||
import dev.sheldan.abstracto.core.service.FeatureModeService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.core.service.PostTargetService;
|
||||
import dev.sheldan.abstracto.core.service.ReactionService;
|
||||
import dev.sheldan.abstracto.core.service.management.ProfanityRegexManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterFeatureDefinition;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterMode;
|
||||
import dev.sheldan.abstracto.profanityfilter.config.ProfanityFilterPostTarget;
|
||||
import dev.sheldan.abstracto.profanityfilter.listener.ProfanityDetectionListener;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUse;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.template.ProfanityReportModel;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.management.ProfanityUseManagementService;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.management.ProfanityUserInServerManagementService;
|
||||
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 org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ProfanityFilterServiceBean implements ProfanityFilterService {
|
||||
|
||||
@Autowired
|
||||
private PostTargetService postTargetService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ReactionService reactionService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityUserInServerManagementService profanityUserInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityUseManagementService profanityUseManagementService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityRegexManagementService profanityRegexManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Autowired
|
||||
private MetricService metricService;
|
||||
|
||||
@Autowired
|
||||
private ProfanityFilterServiceBean self;
|
||||
|
||||
private static final String PROFANITY_REPORT_TEMPLATE_KEY = "profanityDetection_listener_report";
|
||||
|
||||
private static final CounterMetric PROFANITIES_AGREEMENT =
|
||||
CounterMetric
|
||||
.builder()
|
||||
.tagList(Arrays.asList(MetricTag.getTag(ProfanityDetectionListener.STEP, "agreement")))
|
||||
.name(ProfanityDetectionListener.MODERATION_PURGE_METRIC)
|
||||
.build();
|
||||
|
||||
private static final CounterMetric PROFANITIES_DISAGREEMENT =
|
||||
CounterMetric
|
||||
.builder()
|
||||
.tagList(Arrays.asList(MetricTag.getTag(ProfanityDetectionListener.STEP, "disagreement")))
|
||||
.name(ProfanityDetectionListener.MODERATION_PURGE_METRIC)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> createProfanityReport(Message message, ProfanityRegex foundProfanityRegex) {
|
||||
ProfanityReportModel reportModel = ProfanityReportModel
|
||||
.builder()
|
||||
.profaneMessage(message)
|
||||
.profanityGroupKey(foundProfanityRegex.getGroup().getGroupName())
|
||||
.profanityRegexName(foundProfanityRegex.getRegexName())
|
||||
.build();
|
||||
Long serverId = message.getGuild().getIdLong();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PROFANITY_REPORT_TEMPLATE_KEY, reportModel, serverId);
|
||||
List<CompletableFuture<Message>> messageFutures = postTargetService
|
||||
.sendEmbedInPostTarget(messageToSend, ProfanityFilterPostTarget.PROFANITY_FILTER_QUEUE, serverId);
|
||||
Long profanityRegexId = foundProfanityRegex.getId();
|
||||
return FutureUtils.toSingleFutureGeneric(messageFutures).thenCompose(aVoid -> {
|
||||
Message createdMessage = messageFutures.get(0).join();
|
||||
return self.afterReportCreation(message, serverId, profanityRegexId, createdMessage);
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> afterReportCreation(Message message, Long serverId, Long profanityRegexId, Message createdMessage) {
|
||||
if(featureModeService.featureModeActive(ProfanityFilterFeatureDefinition.PROFANITY_FILTER, serverId, ProfanityFilterMode.PROFANITY_VOTE)) {
|
||||
CompletableFuture<Void> firstReaction = reactionService.addReactionToMessageAsync(ProfanityFilterService.REPORT_AGREE_EMOTE, serverId, createdMessage);
|
||||
CompletableFuture<Void> secondReaction = reactionService.addReactionToMessageAsync(ProfanityFilterService.REPORT_DISAGREE_EMOTE, serverId, createdMessage);
|
||||
return CompletableFuture.allOf(firstReaction, secondReaction).thenAccept(aVoid1 -> {
|
||||
log.debug("Reaction added to message {} for a profanity report.", message.getId());
|
||||
self.persistProfanityReport(message, createdMessage, profanityRegexId);
|
||||
});
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMessageProfanityReport(Long messageId) {
|
||||
return profanityUseManagementService.getProfanityUseViaReportMessageId(messageId).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyProfanityUse(ProfanityUse profanityUse, VoteResult result) {
|
||||
switch(result) {
|
||||
case DISAGREEMENT:
|
||||
profanityUse.setConfirmed(false);
|
||||
metricService.incrementCounter(PROFANITIES_DISAGREEMENT);
|
||||
break;
|
||||
case AGREEMENT:
|
||||
profanityUse.setConfirmed(true);
|
||||
metricService.incrementCounter(PROFANITIES_AGREEMENT);
|
||||
deleteProfaneMessage(profanityUse);
|
||||
break;
|
||||
default: throw new IllegalArgumentException("Final vote result given. No mapping to action found.");
|
||||
}
|
||||
profanityUse.setVerified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getPositiveReportCountForUser(AUserInAServer aUserInAServer) {
|
||||
ProfanityUserInAServer profanityUserInAServer = profanityUserInServerManagementService.getProfanityUser(aUserInAServer);
|
||||
return getPositiveReportCountForUser(profanityUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getPositiveReportCountForUser(ProfanityUserInAServer aUserInAServer) {
|
||||
return profanityUseManagementService.getPositiveReports(aUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getFalseProfanityReportCountForUser(AUserInAServer aUserInAServer) {
|
||||
ProfanityUserInAServer profanityUserInAServer = profanityUserInServerManagementService.getProfanityUser(aUserInAServer);
|
||||
return getFalseProfanityReportCountForUser(profanityUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getFalseProfanityReportCountForUser(ProfanityUserInAServer aUserInAServer) {
|
||||
return profanityUseManagementService.getFalsePositiveReports(aUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServerChannelMessage> getRecentPositiveReports(AUserInAServer aUserInAServer, int count) {
|
||||
ProfanityUserInAServer profanityUserInAServer = profanityUserInServerManagementService.getProfanityUser(aUserInAServer);
|
||||
return getRecentPositiveReports(profanityUserInAServer, count);
|
||||
}
|
||||
|
||||
private void deleteProfaneMessage(ProfanityUse profanityUse) {
|
||||
messageService.deleteMessageInChannelInServer(profanityUse.getServer().getId(), profanityUse.getProfaneChannel().getId(), profanityUse.getProfaneMessageId())
|
||||
.exceptionally(throwable -> {
|
||||
log.info("Failed to delete profane message ");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServerChannelMessage> getRecentPositiveReports(ProfanityUserInAServer aUserInAServer, int count) {
|
||||
return profanityUseManagementService.getMostRecentProfanityReports(aUserInAServer, count)
|
||||
.stream()
|
||||
.map(profanityUse -> ServerChannelMessage
|
||||
.builder()
|
||||
.messageId(profanityUse.getReportMessageId())
|
||||
.channelId(profanityUse.getReportChannel().getId())
|
||||
.serverId(profanityUse.getServer().getId()).build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void persistProfanityReport(Message profaneMessage, Message reportMessage, Long profanityRegexId) {
|
||||
ServerChannelMessage profaneMessageObj = ServerChannelMessage.fromMessage(profaneMessage);
|
||||
ServerChannelMessage reportMessageObj = ServerChannelMessage.fromMessage(reportMessage);
|
||||
ProfanityRegex profanityRegex = profanityRegexManagementService.getProfanityRegexViaId(profanityRegexId);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(profaneMessage.getMember());
|
||||
ProfanityUserInAServer profaneUser = profanityUserInServerManagementService.getOrCreateProfanityUser(aUserInAServer);
|
||||
profanityUseManagementService.createProfanityUse(profaneMessageObj, reportMessageObj, profaneUser, profanityRegex.getGroup());
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
metricService.registerCounter(PROFANITIES_AGREEMENT, "Amount of profanity votes resulting in agreement");
|
||||
metricService.registerCounter(PROFANITIES_DISAGREEMENT, "Amount of profanity votes resulting in disagreement");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
|
||||
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUse;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import dev.sheldan.abstracto.profanityfilter.repository.ProfanityUseRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class ProfanityUseManagementServiceBean implements ProfanityUseManagementService {
|
||||
|
||||
@Autowired
|
||||
private ProfanityUseRepository profanityUseRepository;
|
||||
|
||||
@Autowired
|
||||
private ChannelManagementService channelManagementService;
|
||||
|
||||
@Override
|
||||
public ProfanityUse createProfanityUse(ServerChannelMessage profaneMessage, ServerChannelMessage reportMessage, ProfanityUserInAServer reportedUser, ProfanityGroup usedProfanityGroup) {
|
||||
AChannel profaneChannel = channelManagementService.loadChannel(profaneMessage.getChannelId());
|
||||
AChannel reportChannel = channelManagementService.loadChannel(reportMessage.getChannelId());
|
||||
ProfanityUse profanityUse = ProfanityUse
|
||||
.builder()
|
||||
.profanityUser(reportedUser)
|
||||
.profanityGroup(usedProfanityGroup)
|
||||
.profaneMessageId(profaneMessage.getMessageId())
|
||||
.profaneChannel(profaneChannel)
|
||||
.reportMessageId(reportMessage.getMessageId())
|
||||
.reportChannel(reportChannel)
|
||||
.verified(false)
|
||||
.server(reportedUser.getServer())
|
||||
.build();
|
||||
return profanityUseRepository.save(profanityUse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ProfanityUse> getProfanityUseViaReportMessageId(Long messageId) {
|
||||
return profanityUseRepository.findById(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getPositiveReports(ProfanityUserInAServer profanityUserInAServer) {
|
||||
return profanityUseRepository.countByProfanityUserAndVerifiedTrueAndConfirmedTrue(profanityUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getFalsePositiveReports(ProfanityUserInAServer profanityUserInAServer) {
|
||||
return profanityUseRepository.countByProfanityUserAndVerifiedTrueAndConfirmedFalse(profanityUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProfanityUse> getMostRecentProfanityReports(ProfanityUserInAServer profanityUserInAServer, int count) {
|
||||
return profanityUseRepository.findAllByProfanityUserAndConfirmedTrueOrderByCreatedDesc(profanityUserInAServer, PageRequest.of(0, count));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import dev.sheldan.abstracto.profanityfilter.repository.ProfanityUserInServerRepository;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class ProfanityUserInServerManagementServiceBean implements ProfanityUserInServerManagementService {
|
||||
|
||||
@Autowired
|
||||
private ProfanityUserInServerRepository repository;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Override
|
||||
public Optional<ProfanityUserInAServer> getProfanityUserOptional(Member member) {
|
||||
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
return getProfanityUserOptional(userInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ProfanityUserInAServer> getProfanityUserOptional(AUserInAServer aUserInAServer) {
|
||||
return repository.findById(aUserInAServer.getUserInServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfanityUserInAServer getProfanityUser(AUserInAServer aUserInAServer) {
|
||||
return getProfanityUserOptional(aUserInAServer).orElseThrow(() -> new AbstractoRunTimeException("Profanity user in server not found."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfanityUserInAServer createProfanityUser(AUserInAServer aUserInAServer) {
|
||||
ProfanityUserInAServer profanityUserInAServer = ProfanityUserInAServer
|
||||
.builder()
|
||||
.user(aUserInAServer)
|
||||
.id(aUserInAServer.getUserInServerId())
|
||||
.server(aUserInAServer.getServerReference())
|
||||
.build();
|
||||
return repository.save(profanityUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfanityUserInAServer getOrCreateProfanityUser(AUserInAServer aUserInAServer) {
|
||||
Optional<ProfanityUserInAServer> profanityUserOptional = getProfanityUserOptional(aUserInAServer);
|
||||
return profanityUserOptional.orElseGet(() -> createProfanityUser(aUserInAServer));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<property name="profanityFilterFeature" value="(SELECT id FROM feature WHERE key = 'profanityFilter')"/>
|
||||
<property name="moderationModule" value="(SELECT id FROM module WHERE name = 'moderation')"/>
|
||||
<changeSet author="Sheldan" id="profanityFilter_command-commands">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="profanities"/>
|
||||
<column name="module_id" valueComputed="${moderationModule}"/>
|
||||
<column name="feature_id" valueComputed="${profanityFilterFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="feature.xml" relativeToChangelogFile="true"/>
|
||||
<include file="module.xml" relativeToChangelogFile="true"/>
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
<include file="effect_types.xml" relativeToChangelogFile="true"/>
|
||||
<include file="default_emote.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd">
|
||||
<changeSet author="Sheldan" id="profanityFilter_emote-insert">
|
||||
<insert tableName="default_emote">
|
||||
<column name="emote_key" value="profanityFilterAgreeEmote"/>
|
||||
<column name="name" value="⏫"/>
|
||||
</insert>
|
||||
<insert tableName="default_emote">
|
||||
<column name="emote_key" value="profanityFilterDisagreeEmote"/>
|
||||
<column name="name" value="⏬"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="profanityFilter_effect_type-insertion">
|
||||
<insert tableName="effect_type">
|
||||
<column name="effect_type_key" value="profanityFilter"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="profanityFilter_feature-insertion">
|
||||
<insert tableName="feature">
|
||||
<column name="key" value="profanityFilter"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="profanityFilter-moderation-module-insertion">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">
|
||||
SELECT COUNT(*) FROM module WHERE name='moderation';
|
||||
</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="module">
|
||||
<column name="name" value="moderation"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,76 @@
|
||||
<?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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
|
||||
<changeSet author="Sheldan" id="profanity_use-table">
|
||||
<createTable tableName="profanity_use">
|
||||
<column name="report_message_id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_profanity_use"/>
|
||||
</column>
|
||||
<column name="profanity_group_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="profanity_user_in_server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="report_channel_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="profane_message_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="profane_channel_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
<column name="confirmed" type="BOOLEAN">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="verified" type="BOOLEAN">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<createIndex indexName="idx_profanity_use_user_in_server" tableName="profanity_use">
|
||||
<column name="profanity_user_in_server_id"/>
|
||||
</createIndex>
|
||||
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="profanity_use" constraintName="fk_profanity_use_server"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id" referencedTableName="server" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="report_channel_id" baseTableName="profanity_use" constraintName="fk_profanity_use_report_channel"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id"
|
||||
referencedTableName="channel" validate="true"/>
|
||||
|
||||
<addForeignKeyConstraint baseColumnNames="profane_channel_id" baseTableName="profanity_use" constraintName="fk_profanity_use_profane_channel"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id"
|
||||
referencedTableName="channel" validate="true"/>
|
||||
|
||||
<addForeignKeyConstraint baseColumnNames="profanity_group_id" baseTableName="profanity_use" constraintName="fk_profanity_use_profanity_group"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id"
|
||||
referencedTableName="profanity_group" validate="true"/>
|
||||
|
||||
<addForeignKeyConstraint baseColumnNames="profanity_user_in_server_id" baseTableName="profanity_use" constraintName="fk_profanity_use_profanity_user"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id"
|
||||
referencedTableName="profanity_user_in_server" validate="true"/>
|
||||
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS profanity_use_update_trigger ON profanity_use;
|
||||
CREATE TRIGGER profanity_use_update_trigger BEFORE UPDATE ON profanity_use FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS profanity_use_insert_trigger ON profanity_use;
|
||||
CREATE TRIGGER profanity_use_insert_trigger BEFORE INSERT ON profanity_use FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
|
||||
<changeSet author="Sheldan" id="profanity_user_in_server-table">
|
||||
<createTable tableName="profanity_user_in_server">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_profanity_user_in_server"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
<column name="server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="profanity_user_in_server" constraintName="fk_profanity_user_in_server_server"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id" referencedTableName="server" validate="true"/>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS profanity_user_in_server_update_trigger ON profanity_user_in_server;
|
||||
CREATE TRIGGER profanity_user_in_server_update_trigger BEFORE UPDATE ON profanity_user_in_server FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS profanity_user_in_server_insert_trigger ON profanity_user_in_server;
|
||||
CREATE TRIGGER profanity_user_in_server_insert_trigger BEFORE INSERT ON profanity_user_in_server FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="profanity_user_in_server.xml" relativeToChangelogFile="true"/>
|
||||
<include file="profanity_use.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="1.2.12/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,27 @@
|
||||
abstracto.featureFlags.profanityFilter.featureName=profanityFilter
|
||||
abstracto.featureFlags.profanityFilter.enabled=false
|
||||
|
||||
abstracto.postTargets.profanityQueue.name=profanityQueue
|
||||
|
||||
abstracto.featureModes.profanityVote.featureName=profanityFilter
|
||||
abstracto.featureModes.profanityVote.mode=profanityVote
|
||||
abstracto.featureModes.profanityVote.enabled=true
|
||||
|
||||
abstracto.featureModes.autoDeleteProfanities.featureName=profanityFilter
|
||||
abstracto.featureModes.autoDeleteProfanities.mode=autoDeleteProfanities
|
||||
abstracto.featureModes.autoDeleteProfanities.enabled=false
|
||||
|
||||
abstracto.featureModes.profanityReport.featureName=profanityFilter
|
||||
abstracto.featureModes.profanityReport.mode=profanityReport
|
||||
abstracto.featureModes.profanityReport.enabled=true
|
||||
|
||||
abstracto.featureModes.trackProfanities.featureName=profanityFilter
|
||||
abstracto.featureModes.trackProfanities.mode=trackProfanities
|
||||
abstracto.featureModes.trackProfanities.enabled=true
|
||||
|
||||
abstracto.featureModes.autoDeleteAfterVote.featureName=profanityFilter
|
||||
abstracto.featureModes.autoDeleteAfterVote.mode=autoDeleteAfterVote
|
||||
abstracto.featureModes.autoDeleteAfterVote.enabled=true
|
||||
|
||||
abstracto.systemConfigs.profanityVotes.name=profanityVotes
|
||||
abstracto.systemConfigs.profanityVotes.longValue=5
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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>profanity-filter</artifactId>
|
||||
<version>1.2.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>profanity-filter-int</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>core-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,46 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.config.PostTargetEnum;
|
||||
import dev.sheldan.abstracto.profanityfilter.service.ProfanityFilterService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class ProfanityFilterFeatureConfig implements FeatureConfig {
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ProfanityFilterFeatureDefinition.PROFANITY_FILTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PostTargetEnum> getRequiredPostTargets() {
|
||||
return Arrays.asList(ProfanityFilterPostTarget.PROFANITY_FILTER_QUEUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getAvailableModes() {
|
||||
return Arrays.asList(
|
||||
ProfanityFilterMode.PROFANITY_VOTE,
|
||||
ProfanityFilterMode.AUTO_DELETE_PROFANITIES,
|
||||
ProfanityFilterMode.TRACK_PROFANITIES,
|
||||
ProfanityFilterMode.AUTO_DELETE_AFTER_VOTE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRequiredSystemConfigKeys() {
|
||||
return Arrays.asList(ProfanityFilterService.PROFANITY_VOTES_CONFIG_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRequiredEmotes() {
|
||||
return Arrays.asList(ProfanityFilterService.REPORT_AGREE_EMOTE, ProfanityFilterService.REPORT_DISAGREE_EMOTE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ProfanityFilterFeatureDefinition implements FeatureDefinition {
|
||||
PROFANITY_FILTER("profanityFilter");
|
||||
|
||||
private final String key;
|
||||
|
||||
ProfanityFilterFeatureDefinition(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ProfanityFilterMode implements FeatureMode {
|
||||
AUTO_DELETE_PROFANITIES("autoDeleteProfanities"),
|
||||
PROFANITY_VOTE("profanityVote"),
|
||||
PROFANITY_REPORT("profanityReport"),
|
||||
AUTO_DELETE_AFTER_VOTE("autoDeleteAfterVote"),
|
||||
TRACK_PROFANITIES("trackProfanities");
|
||||
|
||||
private final String key;
|
||||
|
||||
ProfanityFilterMode(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleInfo;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ProfanityFilterModerationModuleDefinition implements ModuleDefinition {
|
||||
|
||||
public static final String MODERATION = "moderation";
|
||||
|
||||
@Override
|
||||
public ModuleInfo getInfo() {
|
||||
return ModuleInfo.builder().name(MODERATION).templated(true).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentModule() {
|
||||
return "default";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.PostTargetEnum;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ProfanityFilterPostTarget implements PostTargetEnum {
|
||||
PROFANITY_FILTER_QUEUE("profanityQueue");
|
||||
|
||||
private String key;
|
||||
|
||||
ProfanityFilterPostTarget(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.model.database;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "profanity_use")
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class ProfanityUse {
|
||||
|
||||
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
|
||||
@JoinColumn(name = "profanity_group_id", referencedColumnName = "id", nullable = false)
|
||||
private ProfanityGroup profanityGroup;
|
||||
|
||||
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
|
||||
@JoinColumn(name = "profanity_user_in_server_id", referencedColumnName = "id", nullable = false)
|
||||
private ProfanityUserInAServer profanityUser;
|
||||
|
||||
@Column(name = "report_message_id")
|
||||
@Id
|
||||
private Long reportMessageId;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "report_channel_id", nullable = false)
|
||||
private AChannel reportChannel;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "server_id", nullable = false)
|
||||
private AServer server;
|
||||
|
||||
@Column(name = "profane_message_id")
|
||||
private Long profaneMessageId;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "profane_channel_id", nullable = false)
|
||||
private AChannel profaneChannel;
|
||||
|
||||
@Column(name = "confirmed")
|
||||
private Boolean confirmed;
|
||||
|
||||
@Column(name = "verified")
|
||||
private Boolean verified;
|
||||
|
||||
@Column(name = "created")
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "updated")
|
||||
private Instant updated;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.model.database;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "profanity_user_in_server")
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class ProfanityUserInAServer {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* The {@link AUserInAServer user} which is represented by this object
|
||||
*/
|
||||
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
|
||||
@PrimaryKeyJoinColumn
|
||||
private AUserInAServer user;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "server_id", nullable = false)
|
||||
private AServer server;
|
||||
|
||||
@Column(name = "created")
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "updated")
|
||||
private Instant updated;
|
||||
|
||||
@OneToMany(mappedBy = "profanityUser", fetch = FetchType.LAZY)
|
||||
private List<ProfanityUse> usedProfanities;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ProfanitiesModel {
|
||||
private Member member;
|
||||
private Long falsePositives;
|
||||
private Long truePositives;
|
||||
private List<ServerChannelMessage> recentPositiveReports;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.model.template;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ProfanityReportModel {
|
||||
private String profanityGroupKey;
|
||||
private String profanityRegexName;
|
||||
private Message profaneMessage;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUse;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface ProfanityFilterService {
|
||||
String REPORT_AGREE_EMOTE = "profanityFilterAgreeEmote";
|
||||
String PROFANITY_VOTES_CONFIG_KEY = "profanityVotes";
|
||||
String REPORT_DISAGREE_EMOTE = "profanityFilterDisagreeEmote";
|
||||
String PROFANITY_FILTER_EFFECT_KEY = "profanityFilter";
|
||||
|
||||
enum VoteResult {
|
||||
AGREEMENT, DISAGREEMENT, BELOW_THRESHOLD;
|
||||
public static boolean isFinal(VoteResult result) {
|
||||
return result.equals(AGREEMENT) || result.equals(DISAGREEMENT);
|
||||
}
|
||||
}
|
||||
|
||||
CompletableFuture<Void> createProfanityReport(Message message, ProfanityRegex profanityRegex);
|
||||
boolean isMessageProfanityReport(Long messageId);
|
||||
void verifyProfanityUse(ProfanityUse profanityUse, VoteResult result);
|
||||
Long getPositiveReportCountForUser(AUserInAServer aUserInAServer);
|
||||
Long getPositiveReportCountForUser(ProfanityUserInAServer aUserInAServer);
|
||||
Long getFalseProfanityReportCountForUser(AUserInAServer aUserInAServer);
|
||||
Long getFalseProfanityReportCountForUser(ProfanityUserInAServer aUserInAServer);
|
||||
List<ServerChannelMessage> getRecentPositiveReports(AUserInAServer aUserInAServer, int count);
|
||||
List<ServerChannelMessage> getRecentPositiveReports(ProfanityUserInAServer aUserInAServer, int count);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUse;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProfanityUseManagementService {
|
||||
ProfanityUse createProfanityUse(ServerChannelMessage profaneMessage, ServerChannelMessage reportMessage, ProfanityUserInAServer reportedUser, ProfanityGroup usedProfanityGroup);
|
||||
Optional<ProfanityUse> getProfanityUseViaReportMessageId(Long messageId);
|
||||
Long getPositiveReports(ProfanityUserInAServer profanityUserInAServer);
|
||||
Long getFalsePositiveReports(ProfanityUserInAServer profanityUserInAServer);
|
||||
List<ProfanityUse> getMostRecentProfanityReports(ProfanityUserInAServer profanityUserInAServer, int count);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.profanityfilter.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.profanityfilter.model.database.ProfanityUserInAServer;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProfanityUserInServerManagementService {
|
||||
Optional<ProfanityUserInAServer> getProfanityUserOptional(Member member);
|
||||
Optional<ProfanityUserInAServer> getProfanityUserOptional(AUserInAServer aUserInAServer);
|
||||
ProfanityUserInAServer getProfanityUser(AUserInAServer aUserInAServer);
|
||||
ProfanityUserInAServer createProfanityUser(AUserInAServer aUserInAServer);
|
||||
ProfanityUserInAServer getOrCreateProfanityUser(AUserInAServer aUserInAServer);
|
||||
}
|
||||
@@ -55,7 +55,6 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>core-int</artifactId>
|
||||
@@ -63,8 +62,6 @@
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user