[AB-167] adding warning created events and infraction counter

adding disabling of post targets
adding some logging for message sending failure consumer
This commit is contained in:
Sheldan
2021-10-25 00:04:08 +02:00
parent 8909e8ebe5
commit 0514d355c7
69 changed files with 1197 additions and 158 deletions

View File

@@ -39,7 +39,7 @@ public class MyWarnings extends AbstractConditionableCommand {
public CommandResult execute(CommandContext commandContext) {
MyWarningsModel model = (MyWarningsModel) ContextConverter.fromCommandContext(commandContext, MyWarningsModel.class);
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
Long currentWarnCount = warnManagementService.getActiveWarnsForUser(userInAServer);
Long currentWarnCount = warnManagementService.getActiveWarnCountForUser(userInAServer);
model.setCurrentWarnCount(currentWarnCount);
Long totalWarnCount = warnManagementService.getTotalWarnsForUser(userInAServer);
model.setTotalWarnCount(totalWarnCount);

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.moderation.config;
import dev.sheldan.abstracto.core.service.ExecutorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
@Configuration
public class ModerationListenerConfig {
@Autowired
private ExecutorService executorService;
@Bean(name = "infractionLevelChangedExecutor")
public TaskExecutor infractionLevelChangedExecutor() {
return executorService.setupExecutorFor("infractionLevelChangedListener");
}
@Bean(name = "warningCreatedExecutor")
public TaskExecutor warningCreatedExecutor() {
return executorService.setupExecutorFor("warningCreatedListener");
}
}

View File

@@ -0,0 +1,48 @@
package dev.sheldan.abstracto.moderation.listener.manager;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.moderation.listener.InfractionLevelChangedListener;
import dev.sheldan.abstracto.moderation.model.listener.InfractionLevelChangedEventModel;
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 InfractionLevelChangedListenerManager {
@Autowired(required = false)
private List<InfractionLevelChangedListener> listeners;
@Autowired
private ListenerService listenerService;
@Autowired
@Qualifier("infractionLevelChangedExecutor")
private TaskExecutor infractionLevelChangedExecutor;
public void sendInfractionLevelChangedEvent(Integer newLevel, Integer oldLevel, Long newPoints, Long oldPoints, ServerUser serverUser) {
if(listeners == null || listeners.isEmpty()) {
return;
}
InfractionLevelChangedEventModel model = createInfractionChangedModel(newLevel, oldLevel, oldPoints, newPoints, serverUser);
listeners.forEach(listener -> listenerService.executeFeatureAwareListener(listener, model, infractionLevelChangedExecutor));
}
private InfractionLevelChangedEventModel createInfractionChangedModel(Integer newLevel, Integer oldLevel, Long oldPoints, Long newPoints, ServerUser serverUser) {
return InfractionLevelChangedEventModel
.builder()
.newLevel(newLevel)
.oldLevel(oldLevel)
.oldPoints(oldPoints)
.newPoints(newPoints)
.userId(serverUser.getUserId())
.serverId(serverUser.getServerId())
.build();
}
}

View File

@@ -0,0 +1,53 @@
package dev.sheldan.abstracto.moderation.listener.manager;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.moderation.listener.WarningCreatedListener;
import dev.sheldan.abstracto.moderation.model.listener.WarningCreatedEventModel;
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 WarningCreatedListenerManager {
@Autowired(required = false)
private List<WarningCreatedListener> listeners;
@Autowired
private ListenerService listenerService;
@Autowired
@Qualifier("warningCreatedExecutor")
private TaskExecutor warningCreatedExecutor;
public void sendWarningCreatedEvent(ServerSpecificId warnId, ServerUser warnedUser, ServerUser warningUser,
String reason, ServerChannelMessage warnCommand) {
if(listeners == null || listeners.isEmpty()) {
return;
}
WarningCreatedEventModel model = createWarningCreatedEventModel(warnId, warnedUser, warningUser, reason, warnCommand);
listeners.forEach(listener -> listenerService.executeFeatureAwareListener(listener, model, warningCreatedExecutor));
}
private WarningCreatedEventModel createWarningCreatedEventModel(ServerSpecificId warnId, ServerUser warnedUser,
ServerUser warningUser, String reason, ServerChannelMessage warnCommandMessage) {
return WarningCreatedEventModel
.builder()
.warningId(warnId.getId())
.serverId(warnId.getServerId())
.warningUserId(warningUser.getUserId())
.warnedUserId(warnedUser.getUserId())
.reason(reason)
.warningChannelId(warnCommandMessage.getChannelId())
.warningMessageId(warnCommandMessage.getMessageId())
.build();
}
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.moderation.repository;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.moderation.model.database.Infraction;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface InfractionRepository extends JpaRepository<Infraction, Long> {
List<Infraction> findByUserAndDecayedFalse(AUserInAServer aUserInAServer);
}

View File

@@ -23,6 +23,7 @@ public interface WarnRepository extends JpaRepository<Warning, ServerSpecificId>
Long countByWarnedUser(AUserInAServer aUserInAServer);
Long countByWarnedUserAndDecayedFalse(AUserInAServer aUserInAServer);
List<Warning> findByWarnedUserAndDecayedFalse(AUserInAServer aUserInAServer);
List<Warning> findByWarnedUser(AUserInAServer aUserInAServer);

View File

@@ -17,7 +17,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@@ -139,20 +138,14 @@ public class BanServiceBean implements BanService {
}
public CompletableFuture<Void> sendBanLogMessage(BanLog banLog, Long guildId, String template) {
CompletableFuture<Void> completableFuture;
MessageToSend banLogMessage = templateService.renderEmbedTemplate(template, banLog, guildId);
log.debug("Sending ban log message in guild {}.", guildId);
List<CompletableFuture<Message>> notificationFutures = postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.BAN_LOG, guildId);
completableFuture = FutureUtils.toSingleFutureGeneric(notificationFutures);
return completableFuture;
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.BAN_LOG, guildId));
}
public CompletableFuture<Void> sendUnBanLogMessage(UnBanLog banLog, Long guildId, String template) {
CompletableFuture<Void> completableFuture;
MessageToSend banLogMessage = templateService.renderEmbedTemplate(template, banLog, guildId);
log.debug("Sending unban log message in guild {}.", guildId);
List<CompletableFuture<Message>> notificationFutures = postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.UN_BAN_LOG, guildId);
completableFuture = FutureUtils.toSingleFutureGeneric(notificationFutures);
return completableFuture;
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.UN_BAN_LOG, guildId));
}
}

View File

@@ -0,0 +1,144 @@
package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
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.moderation.config.feature.InfractionFeatureConfig;
import dev.sheldan.abstracto.moderation.config.posttarget.InfractionPostTarget;
import dev.sheldan.abstracto.moderation.listener.manager.InfractionLevelChangedListenerManager;
import dev.sheldan.abstracto.moderation.model.database.Infraction;
import dev.sheldan.abstracto.moderation.model.template.InfractionLevelChangeModel;
import dev.sheldan.abstracto.moderation.service.management.InfractionManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@Component
@Slf4j
public class InfractionServiceBean implements InfractionService {
@Autowired
private InfractionManagementService infractionManagementService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private ConfigService configService;
@Autowired
private ConfigManagementService configManagementService;
@Autowired
private TemplateService templateService;
@Autowired
private PostTargetService postTargetService;
@Autowired
private InfractionServiceBean self;
@Autowired
private InfractionLevelChangedListenerManager infractionLevelChangedListenerManager;
private static final String INFRACTION_NOTIFICATION_TEMPLATE_KEY = "infraction_level_notification";
@Override
public void decayInfraction(Infraction infraction) {
log.info("Decaying infraction {}", infraction.getId());
infraction.setDecayed(true);
infraction.setDecayedDate(Instant.now());
}
@Override
public Long getActiveInfractionPointsForUser(AUserInAServer aUserInAServer) {
List<Infraction> infractions = infractionManagementService.getActiveInfractionsForUser(aUserInAServer);
log.info("Calculating points for user {} in server {} with {} infractions.",
aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId(), infractions.size());
return infractions.stream().collect(Collectors.summarizingLong(Infraction::getPoints)).getCount();
}
@Override
public CompletableFuture<Infraction> createInfractionWithNotification(AUserInAServer aUserInAServer, Long points) {
Infraction createdInfraction = infractionManagementService.createInfraction(aUserInAServer, points);
Long infractionId = createdInfraction.getId();
return createInfractionNotification(aUserInAServer, points)
.thenApply(aBoolean -> self.reloadInfraction(infractionId));
}
@Override
public CompletableFuture<Void> createInfractionNotification(AUserInAServer aUserInAServer, Long points) {
Long serverId = aUserInAServer.getServerReference().getId();
Long currentPoints = getActiveInfractionPointsForUser(aUserInAServer);
Long newPoints = currentPoints + points;
Pair<Integer, Integer> levelChange = infractionLevelChanged(serverId, newPoints, currentPoints);
Integer oldLevel = levelChange.getFirst();
Integer newLevel = levelChange.getSecond();
if(!oldLevel.equals(newLevel)) {
InfractionLevelChangeModel model = InfractionLevelChangeModel
.builder()
.member(MemberDisplay.fromAUserInAServer(aUserInAServer))
.newLevel(newLevel)
.oldLevel(oldLevel)
.oldPoints(currentPoints)
.newPoints(newPoints)
.build();
infractionLevelChangedListenerManager.sendInfractionLevelChangedEvent(newLevel, oldLevel, newPoints, currentPoints, ServerUser.fromAUserInAServer(aUserInAServer));
MessageToSend messageToSend = templateService.renderEmbedTemplate(INFRACTION_NOTIFICATION_TEMPLATE_KEY, model, serverId);
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, InfractionPostTarget.INFRACTION_NOTIFICATION, serverId));
} else {
return CompletableFuture.completedFuture(null);
}
}
@Transactional
public Infraction reloadInfraction(Long infractionId) {
return infractionManagementService.loadInfraction(infractionId);
}
private Pair<Integer, Integer> infractionLevelChanged(Long serverId, Long newPoints, Long oldPoints) {
List<Long> levelConfig = loadInfractionConfig(serverId);
Integer newLevel = getInfractionLevel(newPoints, levelConfig);
Integer oldLevel = getInfractionLevel(oldPoints, levelConfig);
return Pair.of(oldLevel, newLevel);
}
private List<Long> loadInfractionConfig(Long serverId) {
Long levelAmount = configService.getLongValueOrConfigDefault(InfractionFeatureConfig.INFRACTION_LEVELS, serverId);
List<Long> levelConfig = new ArrayList<>();
for (long i = 1; i <= levelAmount; i++) {
String levelKey = InfractionFeatureConfig.INFRACTION_LEVEL_PREFIX + i;
if(configManagementService.configExists(serverId, levelKey)) {
levelConfig.add(configService.getLongValue(levelKey, serverId));
}
}
return levelConfig;
}
private Integer getInfractionLevel(Long points, List<Long> levelConfig) {
for (int i = 0; i < levelConfig.size(); i++) {
if(points >= levelConfig.get(i)) {
return i;
}
}
return 0;
}
}

View File

@@ -40,10 +40,8 @@ public class KickServiceBean implements KickService {
}
private CompletableFuture<Void> sendKickLog(KickLogModel kickLogModel) {
CompletableFuture<Void> completableFuture;
MessageToSend warnLogMessage = templateService.renderEmbedTemplate(KICK_LOG_TEMPLATE, kickLogModel, kickLogModel.getGuild().getIdLong());
log.debug("Sending kick log message in guild {}.", kickLogModel.getGuild().getIdLong());
completableFuture = FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(warnLogMessage, ModerationPostTarget.KICK_LOG, kickLogModel.getGuild().getIdLong()));
return completableFuture;
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(warnLogMessage, ModerationPostTarget.KICK_LOG, kickLogModel.getGuild().getIdLong()));
}
}

View File

@@ -244,21 +244,15 @@ public class MuteServiceBean implements MuteService {
}
private CompletableFuture<Void> sendMuteLog(MuteContext muteLogModel, AServer server) {
CompletableFuture<Void> completableFuture;
log.debug("Sending mute log to the mute post target.");
MessageToSend message = templateService.renderEmbedTemplate(MUTE_LOG_TEMPLATE, muteLogModel, server.getId());
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getContext().getServerId());
completableFuture = FutureUtils.toSingleFutureGeneric(completableFutures);
return completableFuture;
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getContext().getServerId()));
}
private CompletableFuture<Void> sendUnMuteLogMessage(UnMuteLog muteLogModel, AServer server) {
CompletableFuture<Void> completableFuture;
log.debug("Sending unMute log for mute {} to the mute posttarget in server {}", muteLogModel.getMute().getMuteId().getId(), server.getId());
MessageToSend message = templateService.renderEmbedTemplate(UN_MUTE_LOG_TEMPLATE, muteLogModel, server.getId());
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, server.getId());
completableFuture = FutureUtils.toSingleFutureGeneric(completableFutures);
return completableFuture;
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, server.getId()));
}
@Override

View File

@@ -100,9 +100,13 @@ public class ReactionReportServiceBean implements ReactionReportService {
@Transactional
public void createReactionReportInDb(CachedMessage cachedMessage, Message reportMessage, ServerUser reporter) {
log.info("Creation reaction report in message {} about message {} in database.", reportMessage.getIdLong(), cachedMessage.getMessageId());
reactionReportManagementService.createReactionReport(cachedMessage, reportMessage);
updateModerationUserReportCooldown(reporter);
if(reportMessage == null) {
log.info("Creation reaction report about message {} was not sent - post target might be disabled in server {}.", cachedMessage.getMessageId(), cachedMessage.getServerId());
} else {
log.info("Creation reaction report in message {} about message {} in database.", reportMessage.getIdLong(), cachedMessage.getMessageId());
reactionReportManagementService.createReactionReport(cachedMessage, reportMessage);
updateModerationUserReportCooldown(reporter);
}
}
@Transactional

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.models.FutureMemberPair;
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AServer;
@@ -12,16 +13,20 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.config.feature.WarningDecayFeatureConfig;
import dev.sheldan.abstracto.moderation.config.feature.WarningFeatureConfig;
import dev.sheldan.abstracto.moderation.config.feature.mode.WarnDecayMode;
import dev.sheldan.abstracto.moderation.config.feature.mode.WarningMode;
import dev.sheldan.abstracto.moderation.config.posttarget.WarnDecayPostTarget;
import dev.sheldan.abstracto.moderation.config.posttarget.WarningPostTarget;
import dev.sheldan.abstracto.moderation.listener.manager.WarningCreatedListenerManager;
import dev.sheldan.abstracto.moderation.model.database.Infraction;
import dev.sheldan.abstracto.moderation.model.database.Warning;
import dev.sheldan.abstracto.moderation.model.template.command.WarnContext;
import dev.sheldan.abstracto.moderation.model.template.command.WarnNotification;
import dev.sheldan.abstracto.moderation.model.template.job.WarnDecayLogModel;
import dev.sheldan.abstracto.moderation.model.template.job.WarnDecayWarning;
import dev.sheldan.abstracto.moderation.model.template.listener.WarnDecayMemberNotificationModel;
import dev.sheldan.abstracto.moderation.service.management.InfractionManagementService;
import dev.sheldan.abstracto.moderation.service.management.WarnManagementService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
@@ -85,6 +90,18 @@ public class WarnServiceBean implements WarnService {
@Autowired
private WarnServiceBean self;
@Autowired
private InfractionService infractionService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private InfractionManagementService infractionManagementService;
@Autowired
private WarningCreatedListenerManager warningCreatedListenerManager;
public static final String WARN_LOG_TEMPLATE = "warn_log";
public static final String WARN_NOTIFICATION_TEMPLATE = "warn_notification";
public static final String WARNINGS_COUNTER_KEY = "WARNINGS";
@@ -100,22 +117,34 @@ public class WarnServiceBean implements WarnService {
Member warningMember = context.getMember();
Guild guild = warnedMember.getGuild();
log.info("User {} is warning {} in server {}", warnedMember.getId(), warningMember.getId(), guild.getIdLong());
WarnNotification warnNotification = WarnNotification.builder().reason(context.getReason()).warnId(warningId).serverName(guild.getName()).build();
WarnNotification warnNotification = WarnNotification
.builder()
.reason(context.getReason())
.warnId(warningId)
.serverName(guild.getName())
.build();
Long serverId = server.getId();
String warnNotificationMessage = templateService.renderTemplate(WARN_NOTIFICATION_TEMPLATE, warnNotification, server.getId());
List<CompletableFuture<Message>> futures = new ArrayList<>();
List<CompletableFuture> futures = new ArrayList<>();
futures.add(messageService.sendMessageToUser(warnedMember.getUser(), warnNotificationMessage));
log.debug("Logging warning for server {}.", server.getId());
if(featureFlagService.getFeatureFlagValue(ModerationFeatureDefinition.INFRACTIONS, serverId)) {
Long infractionPoints = configService.getLongValueOrConfigDefault(WarningFeatureConfig.WARN_INFRACTION_POINTS, serverId);
AUserInAServer warnedUser = userInServerManagementService.loadOrCreateUser(warnedMember);
warnedUser.setServerReference(server);
futures.add(infractionService.createInfractionWithNotification(warnedUser, infractionPoints)
.thenAccept(infraction -> context.setInfractionId(infraction.getId())));
}
MessageToSend message = templateService.renderEmbedTemplate(WARN_LOG_TEMPLATE, context, server.getId());
futures.addAll(postTargetService.sendEmbedInPostTarget(message, WarningPostTarget.WARN_LOG, context.getGuild().getIdLong()));
return FutureUtils.toSingleFutureGeneric(futures);
return FutureUtils.toSingleFuture(futures);
}
@Override
public CompletableFuture<Void> warnUserWithLog(WarnContext context) {
return notifyAndLogFullUserWarning(context).thenAccept(aVoid ->
self.persistWarning(context)
);
return notifyAndLogFullUserWarning(context)
.thenAccept(aVoid -> self.persistWarning(context));
}
@Transactional
@@ -124,8 +153,15 @@ public class WarnServiceBean implements WarnService {
context.getWarnId(), context.getGuild().getId(), context.getWarnedMember().getId(), context.getMember().getId());
AUserInAServer warnedUser = userInServerManagementService.loadOrCreateUser(context.getWarnedMember());
AUserInAServer warningUser = userInServerManagementService.loadOrCreateUser(context.getMember());
warnManagementService.createWarning(warnedUser, warningUser, context.getReason(), context.getWarnId());
Warning createdWarning = warnManagementService.createWarning(warnedUser, warningUser, context.getReason(), context.getWarnId());
if(context.getInfractionId() != null) {
Infraction infraction = infractionManagementService.loadInfraction(context.getInfractionId());
createdWarning.setInfraction(infraction);
}
ServerUser warnedServerUser = ServerUser.fromAUserInAServer(warnedUser);
ServerUser warningServerUser = ServerUser.fromAUserInAServer(warnedUser);
ServerChannelMessage commandMessage = ServerChannelMessage.fromMessage(context.getMessage());
warningCreatedListenerManager.sendWarningCreatedEvent(createdWarning.getWarnId(), warnedServerUser, warningServerUser, context.getReason(), commandMessage);
}
@Override
@@ -235,10 +271,13 @@ public class WarnServiceBean implements WarnService {
}
@Override
public void decayWarning(Warning warning, Instant now) {
log.debug("Decaying warning {} in server {} with date {}.", warning.getWarnId().getId(), warning.getWarnId().getServerId(), now);
warning.setDecayDate(now);
public void decayWarning(Warning warning, Instant decayDate) {
log.debug("Decaying warning {} in server {} with date {}.", warning.getWarnId().getId(), warning.getWarnId().getServerId(), decayDate);
warning.setDecayDate(decayDate);
warning.setDecayed(true);
if(warning.getInfraction() != null) {
infractionService.decayInfraction(warning.getInfraction());
}
}
private CompletableFuture<Void> logDecayedWarnings(AServer server, List<Warning> warningsToDecay) {
@@ -307,8 +346,7 @@ public class WarnServiceBean implements WarnService {
.warnings(warnDecayWarnings)
.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate(WARN_DECAY_LOG_TEMPLATE_KEY, warnDecayLogModel, serverId);
List<CompletableFuture<Message>> messageFutures = postTargetService.sendEmbedInPostTarget(messageToSend, WarnDecayPostTarget.DECAY_LOG, server.getId());
return FutureUtils.toSingleFutureGeneric(messageFutures);
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, WarnDecayPostTarget.DECAY_LOG, server.getId()));
}
@Override

View File

@@ -0,0 +1,38 @@
package dev.sheldan.abstracto.moderation.service.management;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.moderation.model.database.Infraction;
import dev.sheldan.abstracto.moderation.repository.InfractionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class InfractionManagementServiceBean implements InfractionManagementService{
@Autowired
private InfractionRepository infractionRepository;
@Override
public Infraction createInfraction(AUserInAServer aUserInAServer, Long points) {
Infraction infraction = Infraction
.builder()
.user(aUserInAServer)
.server(aUserInAServer.getServerReference())
.points(points)
.build();
return infractionRepository.save(infraction);
}
@Override
public List<Infraction> getActiveInfractionsForUser(AUserInAServer aUserInAServer) {
return infractionRepository.findByUserAndDecayedFalse(aUserInAServer);
}
@Override
public Infraction loadInfraction(Long infraction) {
return infractionRepository.getOne(infraction);
}
}

View File

@@ -70,10 +70,15 @@ public class WarnManagementServiceBean implements WarnManagementService {
}
@Override
public Long getActiveWarnsForUser(AUserInAServer aUserInAServer) {
public Long getActiveWarnCountForUser(AUserInAServer aUserInAServer) {
return warnRepository.countByWarnedUserAndDecayedFalse(aUserInAServer);
}
@Override
public List<Warning> getActiveWarnsForUser(AUserInAServer aUserInAServer) {
return warnRepository.findByWarnedUserAndDecayedFalse(aUserInAServer);
}
@Override
public Optional<Warning> findByIdOptional(Long id, Long serverId) {
return warnRepository.findByWarnId_IdAndWarnId_ServerId(id, serverId);

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

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.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"/>
</databaseChangeLog>

View File

@@ -6,10 +6,9 @@
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="warn-decay-job-update_schedule">
<update tableName="scheduler_job">
<column name="cron_expression" value="0 0 0 * * ?"/>
<where>name='warnDecayJob'</where>
</update>
<changeSet author="Sheldan" id="infraction_feature-insertion">
<insert tableName="feature">
<column name="key" value="infractions"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,46 @@
<?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="infraction-table">
<createTable tableName="infraction">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_infraction"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="points" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="decayed_date" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="decayed" type="BOOLEAN"/>
<column name="infraction_user_in_server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="infraction" constraintName="fk_infraction_server"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id"
referencedTableName="server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="infraction_user_in_server_id" baseTableName="infraction" constraintName="fk_infraction_user_in_server"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS infraction_update_trigger ON infraction;
CREATE TRIGGER infraction_update_trigger BEFORE UPDATE ON infraction FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS infraction_insert_trigger ON infraction;
CREATE TRIGGER infraction_insert_trigger BEFORE INSERT ON infraction 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.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="infraction.xml" relativeToChangelogFile="true"/>
<include file="warning.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,17 @@
<?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="warning-infraction_id">
<addColumn tableName="warning">
<column name="infraction_id" type="BIGINT" />
</addColumn>
<addForeignKeyConstraint baseColumnNames="infraction_id" baseTableName="warning" constraintName="fk_warning_infraction"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
referencedColumnNames="id" referencedTableName="infraction" validate="true"/>
</changeSet>
</databaseChangeLog>

View File

@@ -11,4 +11,5 @@
<include file="1.2.15/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.16/collection.xml" relativeToChangelogFile="true"/>
<include file="1.3.4/collection.xml" relativeToChangelogFile="true"/>
<include file="1.3.9/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -7,6 +7,9 @@ abstracto.systemConfigs.reactionReportCooldownSeconds.longValue=300
abstracto.featureFlags.moderation.featureName=moderation
abstracto.featureFlags.moderation.enabled=false
abstracto.featureFlags.infractions.featureName=infractions
abstracto.featureFlags.infractions.enabled=false
abstracto.featureFlags.reportReactions.featureName=reportReactions
abstracto.featureFlags.reportReactions.enabled=false
@@ -42,6 +45,31 @@ abstracto.featureModes.warnDecayLogging.featureName=warnings
abstracto.featureModes.warnDecayLogging.mode=warnDecayLogging
abstracto.featureModes.warnDecayLogging.enabled=true
abstracto.featureModes.infractionReporting.featureName=infractions
abstracto.featureModes.infractionReporting.mode=infractionReporting
abstracto.featureModes.infractionReporting.enabled=true
abstracto.systemConfigs.infractionLvl1.name=infractionLvl1
abstracto.systemConfigs.infractionLvl1.longValue=10
abstracto.systemConfigs.infractionLvl2.name=infractionLvl2
abstracto.systemConfigs.infractionLvl2.longValue=20
abstracto.systemConfigs.infractionLvl3.name=infractionLvl3
abstracto.systemConfigs.infractionLvl3.longValue=30
abstracto.systemConfigs.infractionLvl4.name=infractionLvl4
abstracto.systemConfigs.infractionLvl4.longValue=40
abstracto.systemConfigs.infractionLvl5.name=infractionLvl5
abstracto.systemConfigs.infractionLvl5.longValue=50
abstracto.systemConfigs.infractionLevels.name=infractionLevels
abstracto.systemConfigs.infractionLevels.longValue=5
abstracto.systemConfigs.warnInfractionPoints.name=warnInfractionPoints
abstracto.systemConfigs.warnInfractionPoints.longValue=0
abstracto.featureModes.automaticWarnDecayLogging.featureName=warnDecay
abstracto.featureModes.automaticWarnDecayLogging.mode=automaticWarnDecayLogging
abstracto.featureModes.automaticWarnDecayLogging.enabled=true

View File

@@ -49,7 +49,7 @@ public class MyWarningsTest {
Long activeWarnCount = 8L;
AUserInAServer aUserInAServer = Mockito.mock(AUserInAServer.class);
when(userInServerManagementService.loadOrCreateUser(noParameter.getAuthor())).thenReturn(aUserInAServer);
when(warnManagementService.getActiveWarnsForUser(aUserInAServer)).thenReturn(activeWarnCount);
when(warnManagementService.getActiveWarnCountForUser(aUserInAServer)).thenReturn(activeWarnCount);
Long totalWarnCount = 10L;
when(warnManagementService.getTotalWarnsForUser(aUserInAServer)).thenReturn(totalWarnCount);
CommandResult result = testUnit.execute(noParameter);

View File

@@ -29,6 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import java.time.Instant;
import java.util.Arrays;
@@ -134,6 +135,9 @@ public class WarnServiceBeanTest {
@Mock
private DefaultConfigManagementService defaultConfigManagementService;
@Mock
private FeatureFlagService featureFlagService;
private static final String NOTIFICATION_TEXT = "text";
private static final String GUILD_NAME = "guild";
private static final Long SERVER_ID = 4L;
@@ -204,6 +208,7 @@ public class WarnServiceBeanTest {
public void testWarnFullUser() {
setupWarnContext();
setupMocksForWarning();
when(featureFlagService.getFeatureFlagValue(ModerationFeatureDefinition.INFRACTIONS, SERVER_ID)).thenReturn(false);
CompletableFuture<Void> future = testUnit.notifyAndLogFullUserWarning(context);
future.join();
Assert.assertFalse(future.isCompletedExceptionally());

View File

@@ -97,7 +97,7 @@ public class WarnManagementServiceBeanTest {
public void testActiveWarnCountOfUser() {
Long count = 5L;
when(warnRepository.countByWarnedUserAndDecayedFalse(warnedUser)).thenReturn(count);
Long activeWarnsForUserCount = testUnit.getActiveWarnsForUser(warnedUser);
Long activeWarnsForUserCount = testUnit.getActiveWarnCountForUser(warnedUser);
Assert.assertEquals(count, activeWarnsForUserCount);
}