[AB-217] adding profanity service

using profanity service to filter profanities in urban define
adding cache clearing listeners
fixing using 0 as default for maxMessages if not defined
This commit is contained in:
Sheldan
2021-04-04 16:23:13 +02:00
parent d6bb269ffc
commit 602f0d5bf4
41 changed files with 1245 additions and 34 deletions

View File

@@ -0,0 +1,64 @@
package dev.sheldan.abstracto.core.commands.config.profanity;
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.config.features.CoreFeatureDefinition;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ProfanityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class AddProfanityRegex extends AbstractConditionableCommand {
@Autowired
private ProfanityService profanityService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String profanityGroupName = (String) parameters.get(0);
String profanityName = (String) parameters.get(1);
String regex = (String) parameters.get(2);
Long serverId = commandContext.getGuild().getIdLong();
if(parameters.size() < 4) {
profanityService.createProfanityRegex(serverId, profanityGroupName, profanityName, regex);
} else {
String replacement = (String) parameters.get(3);
profanityService.createProfanityRegex(serverId, profanityGroupName, profanityName, regex, replacement);
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter profanityGroupParameter = Parameter.builder().name("profanityGroup").type(String.class).templated(true).build();
Parameter nameParameter = Parameter.builder().name("profanityName").type(String.class).templated(true).build();
Parameter regexParameter = Parameter.builder().name("regex").type(String.class).templated(true).build();
Parameter replacement = Parameter.builder().name("replacement").type(String.class).optional(true).templated(true).build();
List<Parameter> parameters = Arrays.asList(profanityGroupParameter, nameParameter, regexParameter, replacement);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("addProfanityRegex")
.module(ConfigModuleDefinition.CONFIG)
.parameters(parameters)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,52 @@
package dev.sheldan.abstracto.core.commands.config.profanity;
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.config.features.CoreFeatureDefinition;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ProfanityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class CreateProfanityGroup extends AbstractConditionableCommand {
@Autowired
private ProfanityService profanityService;
@Override
public CommandResult execute(CommandContext commandContext) {
String profanityGroupName = (String) commandContext.getParameters().getParameters().get(0);
profanityService.createProfanityGroup(commandContext.getGuild().getIdLong(), profanityGroupName);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter profanityGroupName = Parameter.builder().name("profanityGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(profanityGroupName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("createProfanityGroup")
.module(ConfigModuleDefinition.CONFIG)
.parameters(parameters)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,52 @@
package dev.sheldan.abstracto.core.commands.config.profanity;
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.config.features.CoreFeatureDefinition;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ProfanityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class DeleteProfanityGroup extends AbstractConditionableCommand {
@Autowired
private ProfanityService profanityService;
@Override
public CommandResult execute(CommandContext commandContext) {
String profanityGroupName = (String) commandContext.getParameters().getParameters().get(0);
profanityService.deleteProfanityGroup(commandContext.getGuild().getIdLong(), profanityGroupName);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter profanityGroupParameter = Parameter.builder().name("profanityGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(profanityGroupParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("deleteProfanityGroup")
.module(ConfigModuleDefinition.CONFIG)
.parameters(parameters)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,55 @@
package dev.sheldan.abstracto.core.commands.config.profanity;
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.config.features.CoreFeatureDefinition;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ProfanityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class DeleteProfanityRegex extends AbstractConditionableCommand {
@Autowired
private ProfanityService profanityService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String profanityGroupName = (String) parameters.get(0);
String profanityName = (String) parameters.get(1);
profanityService.deleteProfanityRegex(commandContext.getGuild().getIdLong(), profanityGroupName, profanityName);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter profanityGroupParameter = Parameter.builder().name("profanityGroup").type(String.class).templated(true).build();
Parameter profanityNameParameter = Parameter.builder().name("profanityName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(profanityGroupParameter, profanityNameParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("deleteProfanityRegex")
.module(ConfigModuleDefinition.CONFIG)
.parameters(parameters)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,67 @@
package dev.sheldan.abstracto.core.commands.config.profanity;
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.features.CoreFeatureDefinition;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.models.template.commands.ProfanityConfigModel;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ProfanityGroupManagementService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class ShowProfanityConfig extends AbstractConditionableCommand {
public static final String SHOW_PROFANITY_CONFIG_RESPONSE_TEMPLATE_KEY = "showProfanityConfig_response";
@Autowired
private ProfanityGroupManagementService profanityGroupManagementService;
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
ProfanityConfigModel model = (ProfanityConfigModel) ContextConverter.slimFromCommandContext(commandContext, ProfanityConfigModel.class);
Long serverId = commandContext.getGuild().getIdLong();
List<ProfanityGroup> groups = profanityGroupManagementService.getAllForServer(serverId);
model.setProfanityGroups(groups);
MessageToSend message = templateService.renderEmbedTemplate(SHOW_PROFANITY_CONFIG_RESPONSE_TEMPLATE_KEY, model, serverId);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(message, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("showProfanityConfig")
.module(ConfigModuleDefinition.CONFIG)
.templated(true)
.async(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -82,6 +82,11 @@ public class ListenerExecutorConfig {
return executorService.setupExecutorFor("aChannelCreatedListener");
}
@Bean(name = "cacheClearedExecutor")
public TaskExecutor cacheClearedExecutor() {
return executorService.setupExecutorFor("cacheClearedListener");
}
@Bean(name = "aChannelDeletedExecutor")
public TaskExecutor aChannelDeletedExecutor() {
return executorService.setupExecutorFor("aChannelDeletedListener");

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.listener.async.entity.AsyncCacheClearingListener;
import dev.sheldan.abstracto.core.models.listener.VoidListenerModel;
import dev.sheldan.abstracto.core.service.ProfanityService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class ProfanityCacheClearListener implements AsyncCacheClearingListener {
@Autowired
private ProfanityService profanityService;
@Override
public DefaultListenerResult execute(VoidListenerModel model) {
log.info("Reloading regexes, because cache cleared.");
profanityService.reloadRegex();
return DefaultListenerResult.PROCESSED;
}
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.core.repository;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface ProfanityGroupRepository extends JpaRepository<ProfanityGroup, Long> {
Optional<ProfanityGroup> findByServerAndGroupNameIgnoreCase(AServer server, String name);
void deleteByServerAndGroupNameIgnoreCase(AServer server, String name);
List<ProfanityGroup> findByServer_Id(Long serverId);
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.core.repository;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface ProfanityRegexRepository extends JpaRepository<ProfanityRegex, Long> {
Optional<ProfanityRegex> findByGroupAndRegexNameIgnoreCase(ProfanityGroup group, String name);
void deleteByGroupAndRegexNameIgnoreCase(ProfanityGroup group, String name);
}

View File

@@ -1,16 +1,9 @@
package dev.sheldan.abstracto.core.repository;
import dev.sheldan.abstracto.core.models.database.ARole;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface RoleRepository extends JpaRepository<ARole, Long> {
@NotNull
@Override
Optional<ARole> findById(@NonNull Long aLong);
}

View File

@@ -1,25 +1,10 @@
package dev.sheldan.abstracto.core.repository;
import dev.sheldan.abstracto.core.models.database.AServer;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface ServerRepository extends JpaRepository<AServer, Long> {
@NotNull
@Override
Optional<AServer> findById(@NonNull Long aLong);
@Override
boolean existsById(@NonNull Long aLong);
@NotNull
@Override
List<AServer> findAll();
}

View File

@@ -1,20 +1,35 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.listener.async.entity.AsyncCacheClearingListener;
import dev.sheldan.abstracto.core.models.listener.VoidListenerModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class CacheServiceBean {
@Autowired(required = false)
private List<AsyncCacheClearingListener> listeners;
@Autowired
private TemplateService templateService;
private ListenerService listenerService;
@Autowired
@Qualifier("cacheClearedExecutor")
private TaskExecutor cacheClearedExecutor;
public void clearCaches() {
log.info("Clearing all caches.");
templateService.clearCache();
if(listeners == null) return;
log.info("Executing {} cache cleared listeners.", listeners.size());
VoidListenerModel model = VoidListenerModel.builder().build();
listeners.forEach(asyncCacheClearingListener ->
listenerService.executeListener(asyncCacheClearingListener, model, cacheClearedExecutor));
}
}

View File

@@ -0,0 +1,174 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.exception.ProfanityGroupExistsException;
import dev.sheldan.abstracto.core.exception.ProfanityRegexExistsException;
import dev.sheldan.abstracto.core.exception.ProfanityRegexNotFoundException;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
import dev.sheldan.abstracto.core.service.management.ProfanityGroupManagementService;
import dev.sheldan.abstracto.core.service.management.ProfanityRegexManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
@Slf4j
public class ProfanityServiceBean implements ProfanityService {
@Autowired
private ProfanityGroupManagementService profanityGroupManagementService;
@Autowired
private ProfanityRegexManagementService profanityRegexManagementService;
@Autowired
private ServerManagementService serverManagementService;
private Map<Long, List<PatternReplacement>> regex = new HashMap<>();
@Override
public String replaceProfanities(String input, Long serverId) {
return replaceProfanitiesWithDefault(input, serverId, "");
}
@Override
public String replaceProfanities(String input, Long serverId, String replacement) {
if(regex.containsKey(serverId)) {
List<PatternReplacement> regexes = regex.get(serverId);
log.trace("Checking {} regexes for server {} with static replacement.", regexes.size(), serverId);
for (PatternReplacement pattern: regexes) {
Matcher matcher = pattern.getPattern().matcher(input);
input = matcher.replaceAll(replacement);
}
}
return input;
}
@Override
public String replaceProfanitiesWithDefault(String input, Long serverId, String defaultReplacement) {
if(regex.containsKey(serverId)) {
List<PatternReplacement> regexes = regex.get(serverId);
log.trace("Checking {} regexes for server {} with dynamic replacement.", regexes.size(), serverId);
for (PatternReplacement pattern: regexes) {
Matcher matcher = pattern.getPattern().matcher(input);
String replacement = pattern.getReplacement() != null ? pattern.getReplacement() : defaultReplacement;
input = matcher.replaceAll(replacement);
}
}
return input;
}
@Override
public boolean containsProfanity(String input, Long serverId) {
if(regex.containsKey(serverId)) {
List<PatternReplacement> regexes = regex.get(serverId);
log.trace("Checking existence of {} regexes for server {}.", regexes.size(), serverId);
for (PatternReplacement pattern: regexes) {
Matcher matcher = pattern.getPattern().matcher(input);
if(matcher.matches()) {
return true;
}
}
}
return false;
}
@Override
public ProfanityGroup createProfanityGroup(Long serverId, String profanityGroupName) {
AServer server = serverManagementService.loadServer(serverId);
if(profanityGroupManagementService.doesProfanityGroupExist(server, profanityGroupName)) {
throw new ProfanityGroupExistsException();
}
return profanityGroupManagementService.createProfanityGroup(server, profanityGroupName);
}
@Override
public void deleteProfanityGroup(Long serverId, String profanityGroupName) {
AServer server = serverManagementService.loadServer(serverId);
profanityGroupManagementService.deleteProfanityGroup(server, profanityGroupName);
this.reloadRegex(serverId);
}
@Override
public void deleteProfanityRegex(Long serverId, String profanityGroupName, String profanityRegexName) {
AServer server = serverManagementService.loadServer(serverId);
ProfanityGroup group = profanityGroupManagementService.getProfanityGroup(server, profanityGroupName);
Optional<ProfanityRegex> profanityRegexOptional = profanityRegexManagementService.getProfanityRegexOptional(group, profanityRegexName);
if(!profanityRegexOptional.isPresent()) {
throw new ProfanityRegexNotFoundException();
}
profanityRegexManagementService.deleteProfanityRegex(profanityRegexOptional.get());
this.reloadRegex(serverId);
}
@Override
public ProfanityRegex createProfanityRegex(Long serverId, String profanityGroupName, String profanityRegexName, String regex) {
return createProfanityRegex(serverId, profanityGroupName, profanityRegexName, regex, null);
}
@Override
public ProfanityRegex createProfanityRegex(Long serverId, String profanityGroupName, String profanityRegexName, String regex, String replacement) {
AServer server = serverManagementService.loadServer(serverId);
ProfanityGroup group = profanityGroupManagementService.getProfanityGroup(server, profanityGroupName);
if(profanityRegexManagementService.doesProfanityRegexExist(group, profanityRegexName)) {
throw new ProfanityRegexExistsException();
}
ProfanityRegex created = profanityRegexManagementService.createProfanityRegex(group, profanityRegexName, regex, replacement);
this.reloadRegex(serverId);
return created;
}
@Override
public void reloadRegex() {
log.info("Reloading regex for all servers.");
regex = new HashMap<>();
List<ProfanityGroup> allGroups = profanityGroupManagementService.getAllGroups();
allGroups.forEach(profanityGroup -> profanityGroup.getProfanities().forEach(profanityRegex -> {
Pattern pattern = Pattern.compile(profanityRegex.getRegex());
List<PatternReplacement> newPatterns = new ArrayList<>();
Long serverId = profanityGroup.getServer().getId();
if(regex.containsKey(serverId)) {
regex.get(serverId).add(PatternReplacement.builder().pattern(pattern).replacement(profanityRegex.getReplacement()).build());
} else {
newPatterns.add(PatternReplacement.builder().pattern(pattern).replacement(profanityRegex.getReplacement()).build());
regex.put(serverId, newPatterns);
}
}));
}
@Override
public void reloadRegex(Long serverId) {
log.info("Reloading regex for server {}.", serverId);
if(regex == null) {
regex = new HashMap<>();
}
regex.remove(serverId);
List<ProfanityGroup> allGroups = profanityGroupManagementService.getAllForServer(serverId);
allGroups.forEach(profanityGroup -> profanityGroup.getProfanities().forEach(profanityRegex -> {
Pattern pattern = Pattern.compile(profanityRegex.getRegex());
List<PatternReplacement> newPatterns = new ArrayList<>();
if(regex.containsKey(serverId)) {
regex.get(serverId).add(PatternReplacement.builder().pattern(pattern).replacement(profanityRegex.getReplacement()).build());
} else {
newPatterns.add(PatternReplacement.builder().pattern(pattern).replacement(profanityRegex.getReplacement()).build());
regex.put(serverId, newPatterns);
}
}));
}
@Getter
@Builder
private static class PatternReplacement {
private final Pattern pattern;
private final String replacement;
}
}

View File

@@ -52,6 +52,9 @@ public class StartupServiceBean implements Startup {
@Autowired
private CommandInServerManagementService commandInServerManagementService;
@Autowired
private ProfanityService profanityService;
@Override
public void startBot() throws LoginException {
service.login();
@@ -64,6 +67,7 @@ public class StartupServiceBean implements Startup {
log.info("Synchronizing servers.");
synchronizeServers();
log.info("Done synchronizing servers");
profanityService.reloadRegex();
}
private void synchronizeServers(){

View File

@@ -0,0 +1,66 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.exception.ProfanityGroupNotFoundException;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.repository.ProfanityGroupRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class ProfanityGroupManagementServiceBean implements ProfanityGroupManagementService {
@Autowired
private ProfanityGroupRepository repository;
@Override
public List<ProfanityGroup> getAllGroups() {
return repository.findAll();
}
@Override
public List<ProfanityGroup> getAllForServer(Long serverId) {
return repository.findByServer_Id(serverId);
}
@Override
public ProfanityGroup createProfanityGroup(AServer server, String name) {
ProfanityGroup profanityGroup = ProfanityGroup
.builder()
.groupName(name)
.server(server)
.build();
log.info("Creating profanity group in server {}.", server.getId());
return repository.save(profanityGroup);
}
@Override
public boolean doesProfanityGroupExist(AServer server, String name) {
return getProfanityGroupOptional(server, name).isPresent();
}
@Override
public Optional<ProfanityGroup> getProfanityGroupOptional(AServer server, String name) {
return repository.findByServerAndGroupNameIgnoreCase(server, name);
}
@Override
public ProfanityGroup getProfanityGroup(AServer server, String name) {
return getProfanityGroupOptional(server, name).orElseThrow(ProfanityGroupNotFoundException::new);
}
@Override
public void deleteProfanityGroup(ProfanityGroup profanityGroup) {
repository.delete(profanityGroup);
}
@Override
public void deleteProfanityGroup(AServer server, String name) {
repository.deleteByServerAndGroupNameIgnoreCase(server, name);
}
}

View File

@@ -0,0 +1,57 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
import dev.sheldan.abstracto.core.repository.ProfanityRegexRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class ProfanityRegexManagementServiceBean implements ProfanityRegexManagementService {
@Autowired
private ProfanityRegexRepository repository;
@Override
public ProfanityRegex createProfanityRegex(ProfanityGroup profanityGroup, String name, String regex, String replacement) {
ProfanityRegex creatingRegex = ProfanityRegex
.builder()
.regex(regex)
.regexName(name)
.group(profanityGroup)
.replacement(replacement)
.build();
log.info("Creating profanity regex for server {} in group {}.", profanityGroup.getServer().getId(), profanityGroup.getId());
return repository.save(creatingRegex);
}
@Override
public ProfanityRegex createProfanityRegex(ProfanityGroup profanityGroup, String name, String regex) {
return createProfanityRegex(profanityGroup, name, regex, null);
}
@Override
public void deleteProfanityRegex(ProfanityRegex profanityRegex) {
profanityRegex.getGroup().getProfanities().remove(profanityRegex);
profanityRegex.setGroup(null);
}
@Override
public void deleteProfanityRegex(ProfanityGroup group, String profanityName) {
log.info("Deleting profanity regex for group {} in server {}.", group.getId(), group.getServer().getId());
repository.deleteByGroupAndRegexNameIgnoreCase(group, profanityName);
}
@Override
public boolean doesProfanityRegexExist(ProfanityGroup profanityGroup, String name) {
return getProfanityRegexOptional(profanityGroup, name).isPresent();
}
@Override
public Optional<ProfanityRegex> getProfanityRegexOptional(ProfanityGroup profanityGroup, String name) {
return repository.findByGroupAndRegexNameIgnoreCase(profanityGroup, name);
}
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.core.templating.listener;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.async.entity.AsyncCacheClearingListener;
import dev.sheldan.abstracto.core.models.listener.VoidListenerModel;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class TemplateCacheListener implements AsyncCacheClearingListener {
@Autowired
private TemplateService templateService;
@Override
public DefaultListenerResult execute(VoidListenerModel model) {
log.info("Clearing freemarker caches.");
templateService.clearCache();
return DefaultListenerResult.PROCESSED;
}
}

View File

@@ -148,7 +148,7 @@ public class TemplateServiceBean implements TemplateService {
}
Long messageLimit = 100L;
if(serverContext.getServerId() != null) {
messageLimit = Math.min(messageLimit, configService.getLongValue(CoreFeatureConfig.MAX_MESSAGES_KEY, serverContext.getServerId()));
messageLimit = Math.min(messageLimit, configService.getLongValueOrConfigDefault(CoreFeatureConfig.MAX_MESSAGES_KEY, serverContext.getServerId()));
}
if(embedConfiguration.getMessageLimit() != null) {
messageLimit = Math.min(messageLimit, embedConfiguration.getMessageLimit());

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="core-tables/tables.xml" relativeToChangelogFile="true"/>
<include file="core-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,38 @@
<?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="coreFeature" value="(SELECT id FROM feature WHERE key = 'core')"/>
<property name="configModule" value="(SELECT id FROM module WHERE name = 'config')"/>
<changeSet author="Sheldan" id="profanity-commands" >
<insert tableName="command">
<column name="name" value="createProfanityGroup"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="addProfanityRegex"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="showProfanityConfig"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="deleteProfanityRegex"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="deleteProfanityGroup"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
</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="command.xml" relativeToChangelogFile="true"/>
</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" >
<changeSet author="Sheldan" id="profanity_group-table">
<createTable tableName="profanity_group">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_profanity_group"/>
</column>
<column name="name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="profanity_group" constraintName="fk_profanity_group_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS profanity_group_insert_trigger ON profanity_group;
CREATE TRIGGER profanity_group_insert_trigger BEFORE INSERT ON profanity_group FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,35 @@
<?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="profanity_regex-table">
<createTable tableName="profanity_regex">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_profanity_regex"/>
</column>
<column name="name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="regex" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="replacement" type="VARCHAR(255)" />
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="profanity_group_id" type="BIGINT">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint baseColumnNames="profanity_group_id" baseTableName="profanity_regex" constraintName="fk_profanity_regex_group" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="profanity_group" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS profanity_regex_insert_trigger ON profanity_regex;
CREATE TRIGGER profanity_regex_insert_trigger BEFORE INSERT ON profanity_regex FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</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="profanity_group.xml" relativeToChangelogFile="true"/>
<include file="profanity_regex.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -11,4 +11,5 @@
<include file="1.1-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.5-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.7-core/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,167 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
import dev.sheldan.abstracto.core.service.management.ProfanityGroupManagementService;
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 ProfanityServiceTest {
@InjectMocks
private ProfanityServiceBean testUnit;
@Mock
private ProfanityGroupManagementService profanityGroupManagementService;
@Mock
private ProfanityGroup group;
@Mock
private ProfanityRegex regex;
@Mock
private AServer server;
private final static String INPUT = "input";
private final static String REPLACEMENT = "repl";
private static final Long SERVER_ID = 4L;
@Test
public void testEmptyConfig() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(new ArrayList<>());
testUnit.reloadRegex();
String result = testUnit.replaceProfanitiesWithDefault(INPUT, SERVER_ID, REPLACEMENT);
Assert.assertEquals(INPUT, result);
}
@Test
public void testOneGroupNoRegex() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
testUnit.reloadRegex();
String result = testUnit.replaceProfanitiesWithDefault(INPUT, SERVER_ID, REPLACEMENT);
Assert.assertEquals(INPUT, result);
}
@Test
public void testOneGroupWithOneRegexNotMatching() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(group.getProfanities()).thenReturn(Arrays.asList(regex));
when(regex.getRegex()).thenReturn("a");
testUnit.reloadRegex();
String result = testUnit.replaceProfanitiesWithDefault(INPUT, SERVER_ID, REPLACEMENT);
Assert.assertEquals(INPUT, result);
}
@Test
public void testOneGroupWithOneRegexMatching() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(group.getProfanities()).thenReturn(Arrays.asList(regex));
when(regex.getRegex()).thenReturn("input");
testUnit.reloadRegex();
String result = testUnit.replaceProfanitiesWithDefault(INPUT, SERVER_ID, REPLACEMENT);
Assert.assertEquals(REPLACEMENT, result);
}
@Test
public void testOneGroupWithOneRegexMatchingDefinedReplacement() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(group.getProfanities()).thenReturn(Arrays.asList(regex));
when(regex.getRegex()).thenReturn("input");
when(regex.getReplacement()).thenReturn(REPLACEMENT);
testUnit.reloadRegex();
String result = testUnit.replaceProfanitiesWithDefault(INPUT, SERVER_ID, "");
Assert.assertEquals(REPLACEMENT, result);
}
@Test
public void testOneGroupWithTwoRegexOneMatching() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
ProfanityRegex regex2 = Mockito.mock(ProfanityRegex.class);
when(regex2.getRegex()).thenReturn("asdf");
when(group.getProfanities()).thenReturn(Arrays.asList(regex, regex2));
when(regex.getRegex()).thenReturn("input");
when(regex.getReplacement()).thenReturn(REPLACEMENT);
testUnit.reloadRegex();
String result = testUnit.replaceProfanitiesWithDefault(INPUT, SERVER_ID, "");
Assert.assertEquals(REPLACEMENT, result);
}
/**
* This scenario is not desired, generally, the outputs should be independent, because the user cannot define the order in which
* the regexes are applied
*/
@Test
public void testOneGroupWithTwoRegexBothMatching() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
ProfanityRegex regex2 = Mockito.mock(ProfanityRegex.class);
when(regex2.getRegex()).thenReturn(REPLACEMENT);
String finalString = "FINAL";
when(regex2.getReplacement()).thenReturn(finalString);
when(group.getProfanities()).thenReturn(Arrays.asList(regex, regex2));
when(regex.getRegex()).thenReturn("input");
when(regex.getReplacement()).thenReturn(REPLACEMENT);
testUnit.reloadRegex();
String result = testUnit.replaceProfanitiesWithDefault(INPUT, SERVER_ID, "");
Assert.assertEquals(finalString, result);
}
@Test
public void testOneGroupWithOneRegexMatchingAndFixReplacement() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(group.getProfanities()).thenReturn(Arrays.asList(regex));
when(regex.getRegex()).thenReturn("input");
testUnit.reloadRegex();
String result = testUnit.replaceProfanities(INPUT, SERVER_ID, REPLACEMENT);
Assert.assertEquals(REPLACEMENT, result);
}
@Test
public void testOneGroupWithOneRegexMatchingNoProvidedReplacement() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(group.getProfanities()).thenReturn(Arrays.asList(regex));
when(regex.getRegex()).thenReturn("input");
when(regex.getReplacement()).thenReturn(REPLACEMENT);
testUnit.reloadRegex();
String result = testUnit.replaceProfanities(INPUT, SERVER_ID);
Assert.assertEquals(REPLACEMENT, result);
}
@Test
public void testOneGroupWithOneRegexMatchingUsingProvidedReplacement() {
when(profanityGroupManagementService.getAllGroups()).thenReturn(Arrays.asList(group));
when(group.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(group.getProfanities()).thenReturn(Arrays.asList(regex));
when(regex.getRegex()).thenReturn("input");
testUnit.reloadRegex();
String result = testUnit.replaceProfanities(INPUT, SERVER_ID);
Assert.assertEquals("", result);
}
}

View File

@@ -79,7 +79,7 @@ public class TemplateServiceBeanTest {
private void setupServerAware() {
when(serverContext.getServerId()).thenReturn(SERVER_ID);
when(configService.getLongValue(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
when(configService.getLongValueOrConfigDefault(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
}
@Test
@@ -95,7 +95,7 @@ public class TemplateServiceBeanTest {
public void testRenderTooLongAdditionalMessage() throws IOException, TemplateException {
when(serverContext.getServerId()).thenReturn(SERVER_ID);
String additionalMessage = RandomStringUtils.randomAlphabetic(3500);
when(configService.getLongValue(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
when(configService.getLongValueOrConfigDefault(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
String templateContent = String.format("{ \"additionalMessage\": \"%s\"}", additionalMessage);
EmbedConfiguration config = Mockito.mock(EmbedConfiguration.class);
when(config.getAdditionalMessageLengthLimit()).thenReturn(2000L);
@@ -113,7 +113,7 @@ public class TemplateServiceBeanTest {
public void testRenderEmbedWithMessageLimit() throws IOException, TemplateException {
when(serverContext.getServerId()).thenReturn(SERVER_ID);
String additionalMessage = RandomStringUtils.randomAlphabetic(3500);
when(configService.getLongValue(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
when(configService.getLongValueOrConfigDefault(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
String templateContent = String.format("{ \"additionalMessage\": \"%s\", \"messageLimit\": 1}", additionalMessage);
EmbedConfiguration config = Mockito.mock(EmbedConfiguration.class);
when(config.getAdditionalMessageLengthLimit()).thenReturn(2000L);
@@ -130,7 +130,7 @@ public class TemplateServiceBeanTest {
public void testRenderTooLongMultipleAdditionalMessages() throws IOException, TemplateException {
when(serverContext.getServerId()).thenReturn(SERVER_ID);
String additionalMessage = RandomStringUtils.randomAlphabetic(3500);
when(configService.getLongValue(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
when(configService.getLongValueOrConfigDefault(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
String templateContent = String.format("{ \"additionalMessage\": \"%s\"}", additionalMessage);
EmbedConfiguration config = Mockito.mock(EmbedConfiguration.class);
when(config.getAdditionalMessageLengthLimit()).thenReturn(500L);
@@ -228,7 +228,7 @@ public class TemplateServiceBeanTest {
public void testEmbedWithTooLongFieldNoSpace() throws IOException, TemplateException {
when(serverContext.getServerId()).thenReturn(SERVER_ID);
String fieldValue = RandomStringUtils.randomAlphabetic(1500);
when(configService.getLongValue(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
when(configService.getLongValueOrConfigDefault(CoreFeatureConfig.MAX_MESSAGES_KEY, SERVER_ID)).thenReturn(5L);
when(configuration.getTemplate(getEmbedTemplateKey(), null, SERVER_ID, null, true, false)).thenReturn(getEmbedTemplateWithTooLongField(fieldValue));
when(gson.fromJson(getSingleFieldWithValue(fieldValue), EmbedConfiguration.class)).thenReturn(getEmbedWithSingleFieldOfValue(fieldValue));
MessageToSend messageToSend = templateServiceBean.renderEmbedTemplate(TEMPLATE_KEY, new HashMap<>());

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.templating.Templatable;
public class ProfanityGroupExistsException extends AbstractoRunTimeException implements Templatable {
@Override
public String getTemplateName() {
return "profanity_group_exists_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.templating.Templatable;
public class ProfanityGroupNotFoundException extends AbstractoRunTimeException implements Templatable {
@Override
public String getTemplateName() {
return "profanity_group_not_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.templating.Templatable;
public class ProfanityRegexExistsException extends AbstractoRunTimeException implements Templatable {
@Override
public String getTemplateName() {
return "profanity_regex_exists_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.templating.Templatable;
public class ProfanityRegexNotFoundException extends AbstractoRunTimeException implements Templatable {
@Override
public String getTemplateName() {
return "profanity_regex_not_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.abstracto.core.listener.async.entity;
import dev.sheldan.abstracto.core.listener.AbstractoListener;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.models.listener.VoidListenerModel;
public interface AsyncCacheClearingListener extends AbstractoListener<VoidListenerModel, DefaultListenerResult> {
}

View File

@@ -26,12 +26,14 @@ public class PostTarget implements Serializable {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "channel_id", nullable = false)
@Getter @Setter
@Getter
@Setter
private AChannel channelReference;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="server_id", nullable = false)
@Getter @Setter
@Getter
@Setter
private AServer serverReference;
@Column(name = "created")

View File

@@ -0,0 +1,45 @@
package dev.sheldan.abstracto.core.models.database;
import lombok.*;
import javax.persistence.*;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "profanity_group")
@Getter
@Builder
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class ProfanityGroup {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String groupName;
@OneToMany(
fetch = FetchType.LAZY,
orphanRemoval = true,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
mappedBy = "group")
@Builder.Default
private List<ProfanityRegex> profanities = new ArrayList<>();
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="server_id", nullable = false)
@Getter
@Setter
private AServer server;
@Column(name = "created")
private Instant created;
}

View File

@@ -0,0 +1,39 @@
package dev.sheldan.abstracto.core.models.database;
import lombok.*;
import javax.persistence.*;
import java.time.Instant;
@Entity
@Table(name = "profanity_regex")
@Getter
@Builder
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class ProfanityRegex {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String regexName;
@Column(name = "regex")
private String regex;
@Column(name = "replacement")
private String replacement;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="profanity_group_id", nullable = false)
@Getter
@Setter
private ProfanityGroup group;
@Column(name = "created")
private Instant created;
}

View File

@@ -0,0 +1,12 @@
package dev.sheldan.abstracto.core.models.listener;
import dev.sheldan.abstracto.core.listener.ListenerModel;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class VoidListenerModel implements ListenerModel {
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.core.models.template.commands;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import java.util.List;
@Getter
@Setter
@SuperBuilder
public class ProfanityConfigModel extends SlimUserInitiatedServerContext {
private List<ProfanityGroup> profanityGroups;
}

View File

@@ -0,0 +1,18 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
public interface ProfanityService {
String replaceProfanities(String input, Long serverId);
String replaceProfanities(String input, Long serverId, String replacement);
String replaceProfanitiesWithDefault(String input, Long serverId, String replacement);
boolean containsProfanity(String input, Long serverId);
ProfanityGroup createProfanityGroup(Long serverId, String profanityGroupName);
void deleteProfanityGroup(Long serverId, String profanityGroupName);
void deleteProfanityRegex(Long serverId, String profanityGroupName, String profanityRegexName);
ProfanityRegex createProfanityRegex(Long serverId, String profanityGroupName, String profanityRegexName, String regex);
ProfanityRegex createProfanityRegex(Long serverId, String profanityGroupName, String profanityRegexName, String regex, String replacement);
void reloadRegex();
void reloadRegex(Long serverId);
}

View File

@@ -0,0 +1,18 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import java.util.List;
import java.util.Optional;
public interface ProfanityGroupManagementService {
List<ProfanityGroup> getAllGroups();
List<ProfanityGroup> getAllForServer(Long serverId);
ProfanityGroup createProfanityGroup(AServer server, String name);
boolean doesProfanityGroupExist(AServer server, String name);
Optional<ProfanityGroup> getProfanityGroupOptional(AServer server, String name);
ProfanityGroup getProfanityGroup(AServer server, String name);
void deleteProfanityGroup(ProfanityGroup profanityGroup);
void deleteProfanityGroup(AServer server, String name);
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.ProfanityGroup;
import dev.sheldan.abstracto.core.models.database.ProfanityRegex;
import java.util.Optional;
public interface ProfanityRegexManagementService {
ProfanityRegex createProfanityRegex(ProfanityGroup profanityGroup, String name, String regex, String replacement);
ProfanityRegex createProfanityRegex(ProfanityGroup profanityGroup, String name, String regex);
void deleteProfanityRegex(ProfanityRegex profanityRegex);
void deleteProfanityRegex(ProfanityGroup group, String profanityName);
boolean doesProfanityRegexExist(ProfanityGroup profanityGroup, String name);
Optional<ProfanityRegex> getProfanityRegexOptional(ProfanityGroup profanityGroup, String name);
}