[AB-73] adding different feature modes to define whether or not certain actions should be logged, changing name of setup, disable and enable command to show that they are supposed to be for features

This commit is contained in:
Sheldan
2020-10-17 16:26:02 +02:00
parent 44dfdca6e6
commit 1b98436736
53 changed files with 525 additions and 165 deletions

View File

@@ -38,7 +38,7 @@ public class BanId extends AbstractConditionableCommand {
banLogModel.setBannedUserId(userId);
banLogModel.setBanningUser(commandContext.getAuthor());
banLogModel.setReason(reason);
return banService.banMember(commandContext.getGuild().getIdLong(), userId, reason, banLogModel)
return banService.banUserViaId(commandContext.getGuild().getIdLong(), userId, reason, banLogModel)
.thenApply(aVoid -> CommandResult.fromSuccess());
}

View File

@@ -26,18 +26,14 @@ public class DecayAllWarnings extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters();
boolean logWarnings = !parameters.isEmpty() ? (Boolean) parameters.get(0) : Boolean.FALSE;
return warnService.decayAllWarningsForServer(commandContext.getUserInitiatedContext().getServer(), logWarnings)
return warnService.decayAllWarningsForServer(commandContext.getUserInitiatedContext().getServer())
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
Parameter logWarnings = Parameter.builder().optional(true).name("writeLog").templated(true).type(Boolean.class).build();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
parameters.add(logWarnings);
return CommandConfiguration.builder()
.name("decayAllWarnings")
.module(ModerationModule.MODERATION)

View File

@@ -56,6 +56,7 @@ public class Kick extends AbstractConditionableCommand {
.module(ModerationModule.MODERATION)
.templated(true)
.supportsEmbedException(true)
.async(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -25,7 +25,6 @@ import java.util.concurrent.CompletableFuture;
@Component
public class UnMute extends AbstractConditionableCommand {
public static final String NO_ACTIVE_MUTE = "unMute_has_no_active_mute";
@Autowired
private MuteService muteService;

View File

@@ -3,8 +3,11 @@ package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.exception.GuildNotFoundException;
import dev.sheldan.abstracto.core.models.context.ServerContext;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.ModerationMode;
import dev.sheldan.abstracto.moderation.config.posttargets.ModerationPostTarget;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
@@ -12,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -35,20 +39,36 @@ public class BanServiceBean implements BanService {
@Autowired
private PostTargetService postTargetService;
@Autowired
private FeatureModeService featureModeService;
@Override
public CompletableFuture<Void> banMember(Member member, String reason, ServerContext banLog) {
CompletableFuture<Void> banFuture = banUser(member.getGuild(), member.getIdLong(), reason);
MessageToSend banLogMessage = templateService.renderEmbedTemplate(BAN_LOG_TEMPLATE, banLog);
List<CompletableFuture<Message>> notificationFutures = postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.BAN_LOG, member.getGuild().getIdLong());
return CompletableFuture.allOf(banFuture, FutureUtils.toSingleFutureGeneric(notificationFutures));
CompletableFuture<Void> messageFuture = sendBanLogMessage(banLog, member.getGuild().getIdLong(), BAN_LOG_TEMPLATE);
return CompletableFuture.allOf(banFuture, messageFuture);
}
@NotNull
public CompletableFuture<Void> sendBanLogMessage(ServerContext banLog, Long guildId, String template) {
CompletableFuture<Void> completableFuture;
if(featureModeService.featureModeActive(ModerationFeatures.MODERATION, guildId, ModerationMode.BAN_LOG)) {
MessageToSend banLogMessage = templateService.renderEmbedTemplate(template, banLog);
log.trace("Sending ban log message in guild {}.", guildId);
List<CompletableFuture<Message>> notificationFutures = postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.BAN_LOG, guildId);
completableFuture = FutureUtils.toSingleFutureGeneric(notificationFutures);
} else {
log.trace("Feature {} has mode {} for logging disabled for server {}. Not sending notification.", ModerationFeatures.MODERATION, ModerationMode.BAN_LOG, guildId);
completableFuture = CompletableFuture.completedFuture(null);
}
return completableFuture;
}
@Override
public CompletableFuture<Void> banMember(Long guildId, Long userId, String reason, ServerContext banIdLog) {
public CompletableFuture<Void> banUserViaId(Long guildId, Long userId, String reason, ServerContext banIdLog) {
CompletableFuture<Void> banFuture = banUser(guildId, userId, reason);
MessageToSend banLogMessage = templateService.renderEmbedTemplate(BAN_ID_LOG_TEMPLATE, banIdLog);
List<CompletableFuture<Message>> notificationFutures = postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.BAN_LOG, guildId);
return CompletableFuture.allOf(banFuture, FutureUtils.toSingleFutureGeneric(notificationFutures));
CompletableFuture<Void> messageFuture = sendBanLogMessage(banIdLog, guildId, BAN_ID_LOG_TEMPLATE);
return CompletableFuture.allOf(banFuture, messageFuture);
}
private CompletableFuture<Void> banUser(Long guildId, Long userId, String reason) {

View File

@@ -1,7 +1,10 @@
package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.ModerationMode;
import dev.sheldan.abstracto.moderation.config.posttargets.ModerationPostTarget;
import dev.sheldan.abstracto.moderation.models.template.commands.KickLogModel;
import dev.sheldan.abstracto.templating.model.MessageToSend;
@@ -26,6 +29,9 @@ public class KickServiceBean implements KickService {
@Autowired
private PostTargetService postTargetService;
@Autowired
private FeatureModeService featureModeService;
@Override
public CompletableFuture<Void> kickMember(Member member, String reason, KickLogModel kickLogModel) {
Guild guild = member.getGuild();
@@ -36,7 +42,15 @@ public class KickServiceBean implements KickService {
}
private CompletableFuture<Void> sendKickLog(KickLogModel kickLogModel) {
MessageToSend warnLogMessage = templateService.renderEmbedTemplate(KICK_LOG_TEMPLATE, kickLogModel);
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(warnLogMessage, ModerationPostTarget.KICK_LOG, kickLogModel.getGuild().getIdLong()));
CompletableFuture<Void> completableFuture;
if(featureModeService.featureModeActive(ModerationFeatures.MODERATION, kickLogModel.getGuild().getIdLong(), ModerationMode.KICK_LOG)) {
MessageToSend warnLogMessage = templateService.renderEmbedTemplate(KICK_LOG_TEMPLATE, kickLogModel);
log.trace("Sending kick log message in guild {}.", kickLogModel.getGuild().getIdLong());
completableFuture = FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(warnLogMessage, ModerationPostTarget.KICK_LOG, kickLogModel.getGuild().getIdLong()));
} else {
log.trace("Feature {} has mode {} for logging disabled for server {}. Not sending kick notification.", ModerationFeatures.MODERATION, ModerationMode.BAN_LOG, kickLogModel.getGuild().getIdLong());
completableFuture = CompletableFuture.completedFuture(null);
}
return completableFuture;
}
}

View File

@@ -11,6 +11,8 @@ import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.MutingMode;
import dev.sheldan.abstracto.moderation.config.posttargets.MutingPostTarget;
import dev.sheldan.abstracto.moderation.exception.MuteRoleNotSetupException;
import dev.sheldan.abstracto.moderation.exception.NoMuteFoundException;
@@ -39,7 +41,6 @@ import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -90,6 +91,9 @@ public class MuteServiceBean implements MuteService {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private FeatureModeService featureModeService;
public static final String MUTE_LOG_TEMPLATE = "mute_log";
public static final String UN_MUTE_LOG_TEMPLATE = "unmute_log";
public static final String MUTE_NOTIFICATION_TEMPLATE = "mute_notification";
@@ -212,12 +216,12 @@ public class MuteServiceBean implements MuteService {
@Override
public CompletableFuture<Void> muteMemberWithLog(MuteContext context) {
log.trace("Muting member {} in server {} and sending a mute log.", context.getMutedUser().getId(), context.getMutedUser().getGuild().getId());
log.trace("Muting member {} in server {}.", context.getMutedUser().getId(), context.getMutedUser().getGuild().getId());
AServer server = serverManagementService.loadOrCreate(context.getContext().getServerId());
Long nextCounterValue = counterService.getNextCounterValue(server, MUTE_COUNTER_KEY);
context.setMuteId(nextCounterValue);
CompletableFuture<Void> mutingFuture = muteMember(context.getMutedUser(), context.getMutingUser(), context.getReason(), context.getMuteTargetDate(), context.getContext());
CompletableFuture<Void> muteLogFuture = sendMuteLog(context);
CompletableFuture<Void> muteLogFuture = sendMuteLog(context, server);
return CompletableFuture.allOf(mutingFuture, muteLogFuture).thenAccept(aVoid ->
self.persistMute(context)
);
@@ -229,24 +233,38 @@ public class MuteServiceBean implements MuteService {
createMuteObject(context, triggerKey);
}
public CompletableFuture<Void> sendMuteLog(MuteContext muteLogModel) {
log.trace("Sending mute log to the mute posttarget.");
MessageToSend message = templateService.renderEmbedTemplate(MUTE_LOG_TEMPLATE, muteLogModel);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getContext().getServerId());
return FutureUtils.toSingleFutureGeneric(completableFutures);
private CompletableFuture<Void> sendMuteLog(MuteContext muteLogModel, AServer server) {
CompletableFuture<Void> completableFuture;
if(featureModeService.featureModeActive(ModerationFeatures.MUTING, server, MutingMode.MUTE_LOGGING)) {
log.trace("Sending mute log to the mute post target.");
MessageToSend message = templateService.renderEmbedTemplate(MUTE_LOG_TEMPLATE, muteLogModel);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getContext().getServerId());
completableFuture = FutureUtils.toSingleFutureGeneric(completableFutures);
} else {
completableFuture = CompletableFuture.completedFuture(null);
log.trace("Not sending mute log, because feature mode {} in feature {} has been disabled for server {}.", MutingMode.MUTE_LOGGING, ModerationFeatures.WARNING, server.getId());
}
return completableFuture;
}
private CompletableFuture<Void> sendUnMuteLogMessage(UnMuteLog muteLogModel) {
log.trace("Sending unMute log to the mute posttarget.");
MessageToSend message = templateService.renderEmbedTemplate(UN_MUTE_LOG_TEMPLATE, muteLogModel);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getServer().getId());
return FutureUtils.toSingleFutureGeneric(completableFutures);
private CompletableFuture<Void> sendUnMuteLogMessage(UnMuteLog muteLogModel, AServer server) {
CompletableFuture<Void> completableFuture;
if(featureModeService.featureModeActive(ModerationFeatures.MUTING, server, MutingMode.MUTE_LOGGING)) {
log.trace("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);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getServer().getId());
completableFuture = FutureUtils.toSingleFutureGeneric(completableFutures);
} else {
completableFuture = CompletableFuture.completedFuture(null);
log.trace("Not sending unMute log, because feature mode {} in feature {} has been disabled for server {}.", MutingMode.UN_MUTE_LOGGING, ModerationFeatures.WARNING, server.getId());
}
return completableFuture;
}
@Override
@Transactional
public CompletableFuture<Void> unMuteUser(AUserInAServer aUserInAServer) {
if(muteManagementService.hasActiveMute(aUserInAServer)) {
if(!muteManagementService.hasActiveMute(aUserInAServer)) {
throw new NoMuteFoundException();
}
Mute mute = muteManagementService.getAMuteOf(aUserInAServer);
@@ -254,7 +272,27 @@ public class MuteServiceBean implements MuteService {
log.info("Mute {} has ended already, user {} does not need to be unMuted anymore.", mute.getMuteId().getId(), mute.getMutedUser().getUserReference().getId());
return CompletableFuture.completedFuture(null);
}
return endMute(mute);
Long muteId = mute.getMuteId().getId();
CompletableFuture<Member> mutingMemberFuture = botService.getMemberInServerAsync(mute.getMutingUser());
CompletableFuture<Member> mutedMemberFuture = botService.getMemberInServerAsync(mute.getMutedUser());
Guild guild = botService.getGuildById(mute.getServer().getId());
return endMute(mute).thenCompose(unused ->
CompletableFuture.allOf(mutingMemberFuture, mutedMemberFuture)
).thenCompose(unused -> self.sendUnMuteLogForManualUnMute(muteId, mutingMemberFuture, mutedMemberFuture, guild));
}
@Transactional
public CompletableFuture<Void> sendUnMuteLogForManualUnMute(Long muteId, CompletableFuture<Member> mutingMemberFuture, CompletableFuture<Member> mutedMemberFuture, Guild guild) {
CompletableFuture<Void> completableFuture;
if(featureModeService.featureModeActive(ModerationFeatures.MUTING, guild.getIdLong(), MutingMode.MANUAL_UN_MUTE_LOGGING)) {
completableFuture = self.sendUnmuteLog(muteId, guild, mutingMemberFuture, mutedMemberFuture);
log.trace("Sending un mute notification for manual un mute for mute {} in server {}.", muteId, guild.getIdLong());
} else {
completableFuture = CompletableFuture.completedFuture(null);
log.trace("Not sending unMute log, because feature mode {} in feature {} has been disabled for server {}.", MutingMode.MANUAL_UN_MUTE_LOGGING, ModerationFeatures.WARNING, guild.getIdLong());
}
return completableFuture;
}
@Override
@@ -287,7 +325,7 @@ public class MuteServiceBean implements MuteService {
}
@Transactional
public CompletionStage<Void> sendUnmuteLog(Long muteId, Guild guild, CompletableFuture<Member> mutingMemberFuture, CompletableFuture<Member> mutedMemberFuture) {
public CompletableFuture<Void> sendUnmuteLog(Long muteId, Guild guild, CompletableFuture<Member> mutingMemberFuture, CompletableFuture<Member> mutedMemberFuture) {
Mute mute = muteManagementService.findMute(muteId, guild.getIdLong());
AServer mutingServer = serverManagementService.loadServer(guild.getIdLong());
UnMuteLog unMuteLog = UnMuteLog
@@ -298,7 +336,7 @@ public class MuteServiceBean implements MuteService {
.guild(guild)
.server(mutingServer)
.build();
CompletableFuture<Void> notificationFuture = sendUnMuteLogMessage(unMuteLog);
CompletableFuture<Void> notificationFuture = sendUnMuteLogMessage(unMuteLog, mutingServer);
return CompletableFuture.allOf(notificationFuture).thenAccept(aVoid ->
self.endMuteInDatabase(muteId, guild.getIdLong())
);

View File

@@ -6,7 +6,10 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.WarnDecayMode;
import dev.sheldan.abstracto.moderation.config.features.WarningDecayFeature;
import dev.sheldan.abstracto.moderation.config.features.WarningMode;
import dev.sheldan.abstracto.moderation.config.posttargets.WarnDecayPostTarget;
import dev.sheldan.abstracto.moderation.config.posttargets.WarningPostTarget;
import dev.sheldan.abstracto.moderation.models.template.job.WarnDecayLogModel;
@@ -66,6 +69,9 @@ public class WarnServiceBean implements WarnService {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private FeatureModeService featureModeService;
@Autowired
private WarnServiceBean self;
@@ -87,8 +93,13 @@ public class WarnServiceBean implements WarnService {
String warnNotificationMessage = templateService.renderTemplate(WARN_NOTIFICATION_TEMPLATE, warnNotification);
List<CompletableFuture<Message>> futures = new ArrayList<>();
futures.add(messageService.sendMessageToUser(warnedMember.getUser(), warnNotificationMessage));
MessageToSend message = templateService.renderEmbedTemplate(WARN_LOG_TEMPLATE, context);
futures.addAll(postTargetService.sendEmbedInPostTarget(message, WarningPostTarget.WARN_LOG, context.getGuild().getIdLong()));
if(featureModeService.featureModeActive(ModerationFeatures.WARNING, server.getId(), WarningMode.WARN_LOG)) {
log.trace("Logging warning for server {}.", server.getId());
MessageToSend message = templateService.renderEmbedTemplate(WARN_LOG_TEMPLATE, context);
futures.addAll(postTargetService.sendEmbedInPostTarget(message, WarningPostTarget.WARN_LOG, context.getGuild().getIdLong()));
} else {
log.trace("Not logging warning because of feature {} with feature mode {} in server {}.", ModerationFeatures.WARNING, WarningMode.WARN_LOG, server.getId());
}
return FutureUtils.toSingleFutureGeneric(futures);
}
@@ -119,7 +130,15 @@ public class WarnServiceBean implements WarnService {
List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, cutOffDay);
List<Long> warningIds = flattenWarnings(warningsToDecay);
Long serverId = server.getId();
return logDecayedWarnings(server, warningsToDecay).thenAccept(aVoid ->
CompletableFuture<Void> completableFuture;
if(featureModeService.featureModeActive(ModerationFeatures.AUTOMATIC_WARN_DECAY, server, WarnDecayMode.AUTOMATIC_WARN_DECAY_LOG)) {
log.trace("Sending log messages for automatic warn decay in server {}.", server.getId());
completableFuture = logDecayedWarnings(server, warningsToDecay);
} else {
log.trace("Not logging automatic warn decay, because feature {} has its mode {} disabled in server {}.", ModerationFeatures.AUTOMATIC_WARN_DECAY, WarnDecayMode.AUTOMATIC_WARN_DECAY_LOG, server.getId());
completableFuture = CompletableFuture.completedFuture(null);
}
return completableFuture.thenAccept(aVoid ->
self.decayWarnings(warningIds, serverId)
);
}
@@ -187,8 +206,8 @@ public class WarnServiceBean implements WarnService {
// TODO add ids to render in case any member left the server
WarnDecayWarning warnDecayWarning = WarnDecayWarning
.builder()
.warnedMember(pair.getFirstMember().join())
.warningMember(pair.getSecondMember().join())
.warningMember(pair.getFirstMember().join())
.warnedMember(pair.getSecondMember().join())
.warning(warning)
.build();
warnDecayWarnings.add(warnDecayWarning);
@@ -205,16 +224,18 @@ public class WarnServiceBean implements WarnService {
}
@Override
public CompletableFuture<Void> decayAllWarningsForServer(AServer server, boolean logWarnings) {
public CompletableFuture<Void> decayAllWarningsForServer(AServer server) {
List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, Instant.now());
List<Long> warnIds = flattenWarnings(warningsToDecay);
log.info("Decaying ALL warning in server {} with logging {}.", server.getId(), logWarnings);
log.info("Decaying ALL warning in server {}.", server.getId());
Long serverId = server.getId();
if(logWarnings) {
if(featureModeService.featureModeActive(ModerationFeatures.WARNING, server, WarningMode.WARN_DECAY_LOG)) {
log.trace("Logging warn decays in server {}", serverId);
return logDecayedWarnings(server, warningsToDecay).thenAccept(aVoid ->
self.decayWarnings(warnIds, serverId)
);
} else {
log.trace("Not logging warn decays for manual decay in server {} because feature {} with feature mode: {}", serverId, ModerationFeatures.WARNING, WarningMode.WARN_DECAY_LOG);
decayWarnings(warnIds, serverId);
return CompletableFuture.completedFuture(null);
}

View File

@@ -0,0 +1,64 @@
<?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="moderationFeature" value="(SELECT id FROM feature WHERE key = 'moderation')"/>
<property name="warningsFeature" value="(SELECT id FROM feature WHERE key = 'warnings')"/>
<property name="warnDecayFeature" value="(SELECT id FROM feature WHERE key = 'warnDecay')"/>
<property name="mutingFeature" value="(SELECT id FROM feature WHERE key = 'muting')"/>
<property name="today" value="(SELECT NOW())"/>
<changeSet author="Sheldan" id="moderation_default_feature_mode-insertion">
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="banLogging"/>
<column name="feature_id" valueComputed="${moderationFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="kickLogging"/>
<column name="feature_id" valueComputed="${moderationFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="warnLogging"/>
<column name="feature_id" valueComputed="${warningsFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="warnDecayLogging"/>
<column name="feature_id" valueComputed="${warningsFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="automaticWarnDecayLogging"/>
<column name="feature_id" valueComputed="${warningsFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="muteLogging"/>
<column name="feature_id" valueComputed="${mutingFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="unMuteLogging"/>
<column name="feature_id" valueComputed="${mutingFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="default_feature_mode">
<column name="enabled" value="true"/>
<column name="mode" value="manualUnMuteLogging"/>
<column name="feature_id" valueComputed="${mutingFeature}" />
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -44,7 +44,7 @@ public class BanIdTest {
Long guildId = parameters.getUserInitiatedContext().getServer().getId();
when(templateService.renderSimpleTemplate(Ban.BAN_DEFAULT_REASON_TEMPLATE)).thenReturn(REASON);
when(parameters.getGuild().getIdLong()).thenReturn(guildId);
when(banService.banMember(eq(guildId), eq(BANNED_USER_ID), eq(REASON), banLogModelCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
when(banService.banUserViaId(eq(guildId), eq(BANNED_USER_ID), eq(REASON), banLogModelCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
BanIdLog usedModel = banLogModelCaptor.getValue();
Assert.assertEquals(REASON, usedModel.getReason());
@@ -60,7 +60,7 @@ public class BanIdTest {
Long guildId = parameters.getUserInitiatedContext().getServer().getId();
when(parameters.getGuild().getIdLong()).thenReturn(guildId);
when(templateService.renderSimpleTemplate(Ban.BAN_DEFAULT_REASON_TEMPLATE)).thenReturn(REASON);
when(banService.banMember(eq(guildId), eq(BANNED_USER_ID), eq(customReason), banLogModelCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
when(banService.banUserViaId(eq(guildId), eq(BANNED_USER_ID), eq(customReason), banLogModelCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
BanIdLog usedModel = banLogModelCaptor.getValue();
Assert.assertEquals(customReason, usedModel.getReason());

View File

@@ -1,6 +1,5 @@
package dev.sheldan.abstracto.moderation.commands;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.moderation.service.WarnService;
@@ -12,7 +11,6 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@@ -27,13 +25,11 @@ public class DecayAllWarningsTest {
private WarnService warnService;
@Test
public void testDecayAllWarningsWithLog() {
executeTest(true);
}
@Test
public void testDecayAllWarningsWithoutLog() {
executeTest(false);
public void testDecayAllWarnings() {
CommandContext commandContext = CommandTestUtilities.getNoParameters();
when(warnService.decayAllWarningsForServer(commandContext.getUserInitiatedContext().getServer())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
@Test
@@ -41,15 +37,4 @@ public class DecayAllWarningsTest {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
@Test(expected = IncorrectParameterTypeException.class)
public void testIncorrectParameterType() {
CommandTestUtilities.executeWrongParametersTestAsync(testUnit);
}
private void executeTest(Boolean logWarnings) {
CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(logWarnings));
when(warnService.decayAllWarningsForServer(commandContext.getUserInitiatedContext().getServer(), logWarnings)).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(commandContext);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
}

View File

@@ -3,7 +3,10 @@ package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.exception.GuildNotFoundException;
import dev.sheldan.abstracto.core.models.context.ServerContext;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.ModerationMode;
import dev.sheldan.abstracto.moderation.config.posttargets.ModerationPostTarget;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
@@ -38,8 +41,32 @@ public class BanServiceBeanTest {
@Mock
private PostTargetService postTargetService;
@Mock
private FeatureModeService featureModeService;
@Test
public void testBanMemberByMember() {
public void testBanMemberByMemberWithoutLog() {
Long userId = 8L;
Long serverId = 9L;
Member memberToBan = Mockito.mock(Member.class);
when(memberToBan.getIdLong()).thenReturn(userId);
ServerContext context = Mockito.mock(ServerContext.class);
Guild mockedGuild = Mockito.mock(Guild.class);
when(memberToBan.getGuild()).thenReturn(mockedGuild);
when(mockedGuild.getIdLong()).thenReturn(serverId);
AuditableRestAction mockedAction = mock(AuditableRestAction.class);
when(mockedAction.submit()).thenReturn(CompletableFuture.completedFuture(null));
when(mockedGuild.ban(userId.toString(), 0, REASON)).thenReturn(mockedAction);
MessageToSend mockedMessage = Mockito.mock(MessageToSend.class);
when(featureModeService.featureModeActive(ModerationFeatures.MODERATION, serverId, ModerationMode.BAN_LOG)).thenReturn(false);
testUnit.banMember(memberToBan, REASON, context);
verify(mockedGuild, times(1)).ban(userId.toString(), 0, REASON);
verify(postTargetService, times(0)).sendEmbedInPostTarget(mockedMessage, ModerationPostTarget.BAN_LOG, serverId);
verify(templateService, times(0)).renderEmbedTemplate(BanServiceBean.BAN_LOG_TEMPLATE, context);
}
@Test
public void testBanMemberWithLog() {
Long userId = 8L;
Long serverId = 9L;
Member memberToBan = Mockito.mock(Member.class);
@@ -53,6 +80,7 @@ public class BanServiceBeanTest {
when(mockedGuild.ban(userId.toString(), 0, REASON)).thenReturn(mockedAction);
MessageToSend mockedMessage = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(BanServiceBean.BAN_LOG_TEMPLATE, context)).thenReturn(mockedMessage);
when(featureModeService.featureModeActive(ModerationFeatures.MODERATION, serverId, ModerationMode.BAN_LOG)).thenReturn(true);
testUnit.banMember(memberToBan, REASON, context);
verify(mockedGuild, times(1)).ban(userId.toString(), 0, REASON);
verify(postTargetService, times(1)).sendEmbedInPostTarget(mockedMessage, ModerationPostTarget.BAN_LOG, serverId);
@@ -70,8 +98,9 @@ public class BanServiceBeanTest {
when(mockedGuild.ban(userId.toString(), 0, REASON)).thenReturn(mockedAction);
MessageToSend mockedMessage = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(BanServiceBean.BAN_ID_LOG_TEMPLATE, context)).thenReturn(mockedMessage);
when(featureModeService.featureModeActive(ModerationFeatures.MODERATION, serverId, ModerationMode.BAN_LOG)).thenReturn(true);
when(botService.getGuildByIdOptional(serverId)).thenReturn(Optional.of(mockedGuild));
testUnit.banMember(serverId, userId, REASON, context);
testUnit.banUserViaId(serverId, userId, REASON, context);
verify(mockedGuild, times(1)).ban(userId.toString(), 0, REASON);
verify(postTargetService, times(1)).sendEmbedInPostTarget(mockedMessage, ModerationPostTarget.BAN_LOG, serverId);
}
@@ -82,7 +111,7 @@ public class BanServiceBeanTest {
Long serverId = 5L;
ServerContext context = Mockito.mock(ServerContext.class);
when(botService.getGuildByIdOptional(serverId)).thenReturn(Optional.empty());
testUnit.banMember(serverId, userId, REASON, context);
testUnit.banUserViaId(serverId, userId, REASON, context);
}
}

View File

@@ -1,13 +1,15 @@
package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.ModerationMode;
import dev.sheldan.abstracto.moderation.config.posttargets.ModerationPostTarget;
import dev.sheldan.abstracto.moderation.models.template.commands.KickLogModel;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
import dev.sheldan.abstracto.core.test.MockUtils;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
@@ -35,8 +37,33 @@ public class KickServiceBeanTest {
@Mock
private PostTargetService postTargetService;
@Mock
private FeatureModeService featureModeService;
@Test
public void testKickMember() {
public void testKickMemberWithoutLog() {
AServer server = MockUtils.getServer();
User user = Mockito.mock(User.class);
Member member = Mockito.mock(Member.class);
when(member.getUser()).thenReturn(user);
when(user.getIdLong()).thenReturn(6L);
Guild mockedGuild = Mockito.mock(Guild.class);
when(mockedGuild.getIdLong()).thenReturn(server.getId());
when(member.getGuild()).thenReturn(mockedGuild);
String reason = "reason";
AuditableRestAction<Void> mockedAction = Mockito.mock(AuditableRestAction.class);
when(mockedGuild.kick(member, reason)).thenReturn(mockedAction);
when(mockedAction.submit()).thenReturn(CompletableFuture.completedFuture(null));
KickLogModel model = Mockito.mock(KickLogModel.class);
when(model.getGuild()).thenReturn(mockedGuild);
when(featureModeService.featureModeActive(ModerationFeatures.MODERATION, server.getId(), ModerationMode.KICK_LOG)).thenReturn(false);
testUnit.kickMember(member, reason, model);
verify(postTargetService, times(0)).sendEmbedInPostTarget(any(MessageToSend.class), eq(ModerationPostTarget.KICK_LOG), eq(server.getId()));
verify(templateService, times(0)).renderEmbedTemplate(KickServiceBean.KICK_LOG_TEMPLATE, model);
}
@Test
public void testKickMemberWithLog() {
AServer server = MockUtils.getServer();
User user = Mockito.mock(User.class);
Member member = Mockito.mock(Member.class);
@@ -53,7 +80,8 @@ public class KickServiceBeanTest {
when(model.getGuild()).thenReturn(mockedGuild);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(KickServiceBean.KICK_LOG_TEMPLATE, model)).thenReturn(messageToSend);
when(postTargetService.sendEmbedInPostTarget(messageToSend, ModerationPostTarget.KICK_LOG, server.getId())).thenReturn(CommandTestUtilities.messageFutureList());
when(featureModeService.featureModeActive(ModerationFeatures.MODERATION, server.getId(), ModerationMode.KICK_LOG)).thenReturn(true);
testUnit.kickMember(member, reason, model);
verify(postTargetService, times(1)).sendEmbedInPostTarget(messageToSend, ModerationPostTarget.KICK_LOG, server.getId());
}
}

View File

@@ -11,6 +11,8 @@ import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.MutingMode;
import dev.sheldan.abstracto.moderation.config.posttargets.MutingPostTarget;
import dev.sheldan.abstracto.moderation.exception.MuteRoleNotSetupException;
import dev.sheldan.abstracto.moderation.exception.NoMuteFoundException;
@@ -18,7 +20,6 @@ import dev.sheldan.abstracto.moderation.models.database.Mute;
import dev.sheldan.abstracto.moderation.models.database.MuteRole;
import dev.sheldan.abstracto.moderation.models.template.commands.MuteContext;
import dev.sheldan.abstracto.moderation.models.template.commands.MuteNotification;
import dev.sheldan.abstracto.moderation.models.template.commands.UnMuteLog;
import dev.sheldan.abstracto.moderation.service.management.MuteManagementService;
import dev.sheldan.abstracto.moderation.service.management.MuteRoleManagementService;
import dev.sheldan.abstracto.scheduling.service.SchedulerService;
@@ -42,7 +43,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import static dev.sheldan.abstracto.moderation.service.MuteServiceBean.MUTE_NOTIFICATION_TEMPLATE;
import static dev.sheldan.abstracto.moderation.service.MuteServiceBean.UN_MUTE_LOG_TEMPLATE;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
@@ -134,6 +134,9 @@ public class MuteServiceBeanTest {
@Mock
private CounterService counterService;
@Mock
private FeatureModeService featureModeService;
private static final Long CHANNEL_ID = 8L;
private static final String REASON = "reason";
private static final String NOTIFICATION_TEXT = "text";
@@ -251,6 +254,8 @@ public class MuteServiceBeanTest {
when(muteLog.getMutingUser()).thenReturn(memberMuting);
when(muteLog.getContext()).thenReturn(serverChannelMessage);
when(muteLog.getMuteTargetDate()).thenReturn(unMuteDate);
when(serverManagementService.loadOrCreate(SERVER_ID)).thenReturn(server);
when(featureModeService.featureModeActive(ModerationFeatures.MUTING, server, MutingMode.MUTE_LOGGING)).thenReturn(true);
String notificationText = "text";
when(templateService.renderTemplate(eq(MUTE_NOTIFICATION_TEMPLATE), any(MuteNotification.class))).thenReturn(notificationText);
when(messageService.sendMessageToUser(memberBeingMuted.getUser(), notificationText)).thenReturn(CompletableFuture.completedFuture(null));
@@ -262,10 +267,39 @@ public class MuteServiceBeanTest {
verify(postTargetService, times(1)).sendEmbedInPostTarget(messageToSend, MutingPostTarget.MUTE_LOG, SERVER_ID);
}
@Test
public void testMuteMemberWithoutLog() {
when(userInServerManagementService.loadUser(memberBeingMuted)).thenReturn(userBeingMuted);
when(userInServerManagementService.loadUser(memberMuting)).thenReturn(userMuting);
Instant unMuteDate = shorterMute();
when(memberBeingMuted.getGuild()).thenReturn(guild);
when(memberBeingMuted.getUser()).thenReturn(jdaUserBeingMuted);
when(muteRoleManagementService.muteRoleForServerExists(server)).thenReturn(true);
when(muteRoleManagementService.retrieveMuteRoleForServer(server)).thenReturn(muteRole);
ServerChannelMessage serverChannelMessage = Mockito.mock(ServerChannelMessage.class);
when(serverChannelMessage.getServerId()).thenReturn(SERVER_ID);
MuteContext muteLog = Mockito.mock(MuteContext.class);
when(muteLog.getMutedUser()).thenReturn(memberBeingMuted);
when(muteLog.getMutingUser()).thenReturn(memberMuting);
when(muteLog.getContext()).thenReturn(serverChannelMessage);
when(muteLog.getMuteTargetDate()).thenReturn(unMuteDate);
when(serverManagementService.loadOrCreate(SERVER_ID)).thenReturn(server);
when(featureModeService.featureModeActive(ModerationFeatures.MUTING, server, MutingMode.MUTE_LOGGING)).thenReturn(false);
String notificationText = "text";
when(templateService.renderTemplate(eq(MUTE_NOTIFICATION_TEMPLATE), any(MuteNotification.class))).thenReturn(notificationText);
when(messageService.sendMessageToUser(memberBeingMuted.getUser(), notificationText)).thenReturn(CompletableFuture.completedFuture(null));
when(roleService.addRoleToUserFuture(userBeingMuted, muteRole.getRole())).thenReturn(CompletableFuture.completedFuture(null));
testUnit.muteMemberWithLog(muteLog);
verifyDirectMute();
verify(postTargetService, times(0)).sendEmbedInPostTarget(messageToSend, MutingPostTarget.MUTE_LOG, SERVER_ID);
}
@Test
public void testUnMuteMemberWhoseMuteEnded() {
when(mute.getMuteEnded()).thenReturn(true);
when(mute.getMutedUser()).thenReturn(userBeingMuted);
when(muteManagementService.hasActiveMute(userBeingMuted)).thenReturn(true);
when(muteManagementService.getAMuteOf(userBeingMuted)).thenReturn(mute);
when(mute.getMuteId()).thenReturn(new ServerSpecificId(SERVER_ID, MUTE_ID));
testUnit.unMuteUser(userBeingMuted);
@@ -291,8 +325,6 @@ public class MuteServiceBeanTest {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(muteManagementService.findMute(MUTE_ID, SERVER_ID)).thenReturn(mute);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
when(templateService.renderEmbedTemplate(eq(UN_MUTE_LOG_TEMPLATE), any(UnMuteLog.class))).thenReturn(messageToSend);
when(postTargetService.sendEmbedInPostTarget(eq(messageToSend), eq(MutingPostTarget.MUTE_LOG), anyLong())).thenReturn(Arrays.asList(CompletableFuture.completedFuture(null)));
testUnit.sendUnmuteLog(MUTE_ID, guild, CompletableFuture.completedFuture(memberMuting), CompletableFuture.completedFuture(memberBeingMuted));
verify(self, times(1)).endMuteInDatabase(MUTE_ID, SERVER_ID);
}
@@ -383,6 +415,7 @@ public class MuteServiceBeanTest {
private void setupUnMuteMocks(boolean stillInGuild) {
when(mute.getMuteId()).thenReturn(new ServerSpecificId(SERVER_ID, MUTE_ID));
when(muteManagementService.getAMuteOf(userBeingMuted)).thenReturn(mute);
when(muteManagementService.hasActiveMute(userBeingMuted)).thenReturn(true);
when(muteRoleManagementService.retrieveMuteRoleForServer(server)).thenReturn(muteRole);
when(botService.getGuildById(server.getId())).thenReturn(guild);
when(botService.isUserInGuild(guild, userBeingMuted)).thenReturn(stillInGuild);

View File

@@ -5,7 +5,10 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.features.WarnDecayMode;
import dev.sheldan.abstracto.moderation.config.features.WarningDecayFeature;
import dev.sheldan.abstracto.moderation.config.features.WarningMode;
import dev.sheldan.abstracto.moderation.config.posttargets.WarnDecayPostTarget;
import dev.sheldan.abstracto.moderation.config.posttargets.WarningPostTarget;
import dev.sheldan.abstracto.moderation.models.database.Warning;
@@ -114,6 +117,9 @@ public class WarnServiceBeanTest {
@Mock
private MessageService messageService;
@Mock
private FeatureModeService featureModeService;
private static final String NOTIFICATION_TEXT = "text";
private static final String GUILD_NAME = "guild";
private static final Long SERVER_ID = 4L;
@@ -130,36 +136,60 @@ public class WarnServiceBeanTest {
@Test
public void testDecayWarningsForServer() {
setupWarnDecay();
when(featureModeService.featureModeActive(ModerationFeatures.AUTOMATIC_WARN_DECAY, server, WarnDecayMode.AUTOMATIC_WARN_DECAY_LOG)).thenReturn(true);
testUnit.decayWarningsForServer(server);
verify(self, times(1)).renderAndSendWarnDecayLogs(eq(SERVER_ID), any());
}
@Test
public void testDecayAllWarningsForServerWithLog() {
public void testDecayWarningsForServerWithoutLog() {
setupWarnDecay();
testUnit.decayAllWarningsForServer(server, true);
when(featureModeService.featureModeActive(ModerationFeatures.AUTOMATIC_WARN_DECAY, server, WarnDecayMode.AUTOMATIC_WARN_DECAY_LOG)).thenReturn(false);
testUnit.decayWarningsForServer(server);
verify(self, times(0)).renderAndSendWarnDecayLogs(eq(SERVER_ID), any());
}
@Test
public void testDecayAllWarningsForServer() {
setupWarnDecay();
when(featureModeService.featureModeActive(ModerationFeatures.WARNING, server, WarningMode.WARN_DECAY_LOG)).thenReturn(true);
testUnit.decayAllWarningsForServer(server);
verify(self, times(1)).renderAndSendWarnDecayLogs(eq(SERVER_ID), any());
}
@Test
public void testDecayAllWarningsForServerWithoutLog() {
setupWarnDecay();
testUnit.decayAllWarningsForServer(server, false);
verifyWarnDecayWithLog(false);
when(featureModeService.featureModeActive(ModerationFeatures.WARNING, server, WarningMode.WARN_DECAY_LOG)).thenReturn(false);
testUnit.decayAllWarningsForServer(server);
verify(self, times(0)).renderAndSendWarnDecayLogs(eq(SERVER_ID), any());
}
@Test
public void testDecayAllWarningsWithoutWarnings() {
public void testDecayAllWarningsWithoutWarningsWithoutLog() {
List<Warning> warnings = Collections.emptyList();
when(server.getId()).thenReturn(SERVER_ID);
when(warnManagementService.getActiveWarningsInServerOlderThan(eq(server), any(Instant.class))).thenReturn(warnings);
testUnit.decayAllWarningsForServer(server, true);
when(featureModeService.featureModeActive(ModerationFeatures.WARNING, server, WarningMode.WARN_DECAY_LOG)).thenReturn(false);
testUnit.decayAllWarningsForServer(server);
verify(self, times(0)).renderAndSendWarnDecayLogs(eq(SERVER_ID), any());
}
@Test
public void testDecayAllWarningsWithoutWarningsWithLog() {
List<Warning> warnings = Collections.emptyList();
when(server.getId()).thenReturn(SERVER_ID);
when(warnManagementService.getActiveWarningsInServerOlderThan(eq(server), any(Instant.class))).thenReturn(warnings);
when(featureModeService.featureModeActive(ModerationFeatures.WARNING, server, WarningMode.WARN_DECAY_LOG)).thenReturn(true);
testUnit.decayAllWarningsForServer(server);
verify(self, times(1)).renderAndSendWarnDecayLogs(eq(SERVER_ID), any());
}
@Test
public void testWarnFullUser() {
setupWarnContext();
when(featureModeService.featureModeActive(ModerationFeatures.WARNING, SERVER_ID, WarningMode.WARN_LOG)).thenReturn(true);
setupMocksForWarning();
testUnit.notifyAndLogFullUserWarning(context);
}
@@ -197,22 +227,6 @@ public class WarnServiceBeanTest {
when(server.getId()).thenReturn(SERVER_ID);
}
private void verifyWarnDecayWithLog(boolean withLog) {
int logCount = withLog ? 1 : 0;
verify(postTargetService, times(logCount)).sendEmbedInPostTarget(messageToSend, WarnDecayPostTarget.DECAY_LOG, server.getId());
if(withLog) {
WarnDecayLogModel model = warnDecayLogModelArgumentCaptor.getValue();
List<WarnDecayWarning> usedWarnings = model.getWarnings();
Assert.assertEquals(firstWarning, usedWarnings.get(0).getWarning());
Assert.assertEquals(warnedMember, usedWarnings.get(0).getWarnedMember());
Assert.assertEquals(warningMember, usedWarnings.get(0).getWarningMember());
Assert.assertEquals(secondWarning, usedWarnings.get(1).getWarning());
Assert.assertEquals(secondWarnedMember, usedWarnings.get(1).getWarnedMember());
Assert.assertEquals(warningMember, usedWarnings.get(1).getWarningMember());
Assert.assertEquals(2, usedWarnings.size());
}
}
private void setupWarnDecay() {
setupWarnings();
when(configService.getLongValue(WarningDecayFeature.DECAY_DAYS_KEY, server.getId())).thenReturn(5L);

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import dev.sheldan.abstracto.moderation.config.posttargets.ModerationPostTarget;
import org.springframework.stereotype.Component;
@@ -21,4 +22,9 @@ public class ModerationFeature implements FeatureConfig {
public List<PostTargetEnum> getRequiredPostTargets() {
return Arrays.asList(ModerationPostTarget.BAN_LOG, ModerationPostTarget.KICK_LOG);
}
@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(ModerationMode.BAN_LOG, ModerationMode.KICK_LOG);
}
}

View File

@@ -7,7 +7,7 @@ import lombok.Getter;
public enum ModerationFeatures implements FeatureEnum {
MODERATION("moderation"), WARNING("warnings"), LOGGING("logging"), MUTING("muting"), AUTOMATIC_WARN_DECAY("warnDecay"), USER_NOTES("userNotes");
private String key;
private final String key;
ModerationFeatures(String key) {
this.key = key;

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureMode;
import lombok.Getter;
@Getter
public enum ModerationMode implements FeatureMode {
BAN_LOG("banLogging"), KICK_LOG("kickLogging");
private final String key;
ModerationMode(String key) {
this.key = key;
}
}

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import dev.sheldan.abstracto.moderation.config.posttargets.MutingPostTarget;
import org.springframework.stereotype.Component;
@@ -21,4 +22,9 @@ public class MutingFeature implements FeatureConfig {
public List<PostTargetEnum> getRequiredPostTargets() {
return Arrays.asList(MutingPostTarget.MUTE_LOG);
}
@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(MutingMode.MANUAL_UN_MUTE_LOGGING, MutingMode.MUTE_LOGGING, MutingMode.UN_MUTE_LOGGING);
}
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureMode;
import lombok.Getter;
@Getter
public enum MutingMode implements FeatureMode {
MUTE_LOGGING("muteLogging"), UN_MUTE_LOGGING("unMuteLogging"), MANUAL_UN_MUTE_LOGGING("manualUnMuteLogging");
private final String key;
MutingMode(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,17 @@
package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureMode;
import lombok.Getter;
@Getter
public enum WarnDecayMode implements FeatureMode {
AUTOMATIC_WARN_DECAY_LOG("automaticWarnDecayLogging");
private final String key;
WarnDecayMode(String key) {
this.key = key;
}
}

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import dev.sheldan.abstracto.moderation.config.posttargets.WarnDecayPostTarget;
import org.springframework.beans.factory.annotation.Autowired;
@@ -38,4 +39,8 @@ public class WarningDecayFeature implements FeatureConfig {
return Arrays.asList(WarnDecayPostTarget.DECAY_LOG);
}
@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(WarnDecayMode.AUTOMATIC_WARN_DECAY_LOG);
}
}

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import dev.sheldan.abstracto.moderation.config.posttargets.WarningPostTarget;
import org.springframework.beans.factory.annotation.Autowired;
@@ -30,4 +31,9 @@ public class WarningFeature implements FeatureConfig {
public List<PostTargetEnum> getRequiredPostTargets() {
return Arrays.asList(WarningPostTarget.WARN_LOG);
}
@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(WarningMode.WARN_DECAY_LOG, WarningMode.WARN_LOG);
}
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.moderation.config.features;
import dev.sheldan.abstracto.core.config.FeatureMode;
import lombok.Getter;
@Getter
public enum WarningMode implements FeatureMode {
WARN_LOG("warnLogging"), WARN_DECAY_LOG("warnDecayLogging");
private final String key;
WarningMode(String key) {
this.key = key;
}
}

View File

@@ -7,5 +7,5 @@ import java.util.concurrent.CompletableFuture;
public interface BanService {
CompletableFuture<Void> banMember(Member member, String reason, ServerContext banLog);
CompletableFuture<Void> banMember(Long guildId, Long userId, String reason, ServerContext banIdLog);
CompletableFuture<Void> banUserViaId(Long guildId, Long userId, String reason, ServerContext banIdLog);
}

View File

@@ -13,5 +13,5 @@ public interface WarnService {
CompletableFuture<Void> warnUserWithLog(WarnContext context);
void decayWarning(Warning warning, Instant decayDate);
CompletableFuture<Void> decayWarningsForServer(AServer server);
CompletableFuture<Void> decayAllWarningsForServer(AServer server, boolean logWarnings);
CompletableFuture<Void> decayAllWarningsForServer(AServer server);
}

View File

@@ -14,7 +14,7 @@ public class InvalidCategoryException extends AbstractoRunTimeException implemen
@Override
public String getTemplateName() {
return "setup_category_not_valid_exception";
return "feature_setup_category_not_valid_exception";
}
@Override

View File

@@ -23,7 +23,7 @@ public class ModMailCategoryDelayedActionConfig implements DelayedActionConfig {
@Override
public String getTemplateName() {
return "setup_modmail_category_action";
return "feature_setup_modmail_category_action";
}
@Override

View File

@@ -73,7 +73,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
*/
@Override
public CompletableFuture<SetupStepResult> execute(AServerChannelUserId user, SetupStepParameter parameter) {
String messageTemplateKey = "setup_modmail_category_message";
String messageTemplateKey = "feature_setup_modmail_category_message";
SetupModMailCategoryMessageModel model = SetupModMailCategoryMessageModel
.builder()
.build();

View File

@@ -11,7 +11,7 @@ import lombok.Getter;
public enum ModMailMode implements FeatureMode {
LOGGING("log");
private String key;
private final String key;
ModMailMode(String key) {
this.key = key;

View File

@@ -18,7 +18,7 @@ public class ModMailCategoryValidationErrorModel implements ValidationErrorModel
@Override
public String getTemplateName() {
return "setup_modmail_category_not_setup";
return "feature_setup_modmail_category_not_setup";
}
@Override

View File

@@ -14,7 +14,7 @@ import dev.sheldan.abstracto.core.exception.FeatureNotFoundException;
import dev.sheldan.abstracto.core.interactive.InteractiveService;
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.SetupService;
import dev.sheldan.abstracto.core.service.FeatureSetupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -23,7 +23,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class Setup extends AbstractConditionableCommand {
public class SetupFeature extends AbstractConditionableCommand {
@Autowired
private InteractiveService interactiveService;
@@ -35,7 +35,7 @@ public class Setup extends AbstractConditionableCommand {
private FeatureConfigService featureConfigService;
@Autowired
private SetupService setupService;
private FeatureSetupService setupService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
@@ -48,7 +48,7 @@ public class Setup extends AbstractConditionableCommand {
.channelId(commandContext.getChannel().getIdLong())
.userId(commandContext.getAuthor().getIdLong())
.build();
return setupService.performSetup(feature, initiatingUser, commandContext.getMessage().getIdLong())
return setupService.performFeatureSetup(feature, initiatingUser, commandContext.getMessage().getIdLong())
.thenApply(aVoid -> CommandResult.fromSuccess());
}
throw new FeatureNotFoundException(name, featureConfigService.getFeaturesAsList());
@@ -60,7 +60,7 @@ public class Setup extends AbstractConditionableCommand {
List<Parameter> parameters = Arrays.asList(newPrefixParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("setup")
.name("setupFeature")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.templated(true)

View File

@@ -25,7 +25,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class Disable extends AbstractConditionableCommand {
public class DisableFeature extends AbstractConditionableCommand {
@Autowired
private FeatureConfigService featureConfigService;
@@ -67,7 +67,7 @@ public class Disable extends AbstractConditionableCommand {
List<Parameter> parameters = Arrays.asList(featureName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build();
return CommandConfiguration.builder()
.name("disable")
.name("disableFeature")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.async(true)

View File

@@ -28,7 +28,7 @@ import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class Enable extends AbstractConditionableCommand {
public class EnableFeature extends AbstractConditionableCommand {
@Autowired
private FeatureConfigService featureConfigService;
@@ -75,7 +75,7 @@ public class Enable extends AbstractConditionableCommand {
List<Parameter> parameters = Arrays.asList(featureName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build();
return CommandConfiguration.builder()
.name("enable")
.name("enableFeature")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.async(true)

View File

@@ -10,7 +10,7 @@ public class NoChannelProvidedException extends AbstractoRunTimeException implem
@Override
public String getTemplateName() {
return "setup_no_channel_provided_exception";
return "feature_setup_no_channel_provided_exception";
}
@Override

View File

@@ -18,7 +18,7 @@ public class PostTargetDelayedActionConfig implements DelayedActionConfig {
@Override
public String getTemplateName() {
return "setup_post_target_action";
return "feature_setup_post_target_action";
}
@Override

View File

@@ -27,6 +27,7 @@ import java.util.function.Consumer;
@Slf4j
public class PostTargetSetupStep extends AbstractConfigSetupStep {
public static final String FEATURE_SETUP_POST_TARGET_MESSAGE_TEMPLATE_KEY = "feature_setup_post_target_message";
@Autowired
private ConfigService configService;
@@ -66,8 +67,7 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep {
.postTargetKey(postTargetStepParameter.getPostTargetKey())
.currentTextChannel(currentTextChannel)
.build();
String messageTemplateKey = "setup_post_target_message";
String messageText = templateService.renderTemplate(messageTemplateKey, model);
String messageText = templateService.renderTemplate(FEATURE_SETUP_POST_TARGET_MESSAGE_TEMPLATE_KEY, model);
AChannel channel = channelManagementService.loadChannel(user.getChannelId());
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId());

View File

@@ -20,6 +20,7 @@ import java.util.function.Consumer;
@Slf4j
public class SetupSummaryStep extends AbstractConfigSetupStep {
public static final String FEATURE_SETUP_CONFIRMATION_TEMPLATE_KEY = "feature_setup_confirmation";
@Autowired
private InteractiveService interactiveService;
@@ -45,7 +46,7 @@ public class SetupSummaryStep extends AbstractConfigSetupStep {
.builder()
.actionConfigs(parameter.getDelayedActionList())
.build();
String messageToSend = templateService.renderTemplate("setup_confirmation", model);
String messageToSend = templateService.renderTemplate(FEATURE_SETUP_CONFIRMATION_TEMPLATE_KEY, model);
AChannel channel = channelManagementService.loadChannel(user.getChannelId());
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId());

View File

@@ -16,7 +16,7 @@ public class SystemConfigDelayedActionConfig implements DelayedActionConfig {
@Override
public String getTemplateName() {
return "setup_system_config_action";
return "feature_setup_system_config_action";
}
@Override

View File

@@ -27,6 +27,7 @@ import java.util.function.Consumer;
@Slf4j
public class SystemConfigSetupStep extends AbstractConfigSetupStep {
public static final String SETUP_SYSTEM_CONFIG_MESSAGE_TEMPLATE_KEY = "feature_setup_system_config_message";
@Autowired
private ConfigService configService;
@@ -57,8 +58,7 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep {
.configKey(systemConfigStepParameter.getConfigKey())
.defaultConfig(defaultConfig)
.build();
String messageTemplateKey = "setup_system_config_message";
String messageText = templateService.renderTemplate(messageTemplateKey, model);
String messageText = templateService.renderTemplate(SETUP_SYSTEM_CONFIG_MESSAGE_TEMPLATE_KEY, model);
AChannel channel = channelManagementService.loadChannel(user.getChannelId());
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId());

View File

@@ -10,6 +10,7 @@ import dev.sheldan.abstracto.core.models.template.commands.FeatureModeDisplay;
import dev.sheldan.abstracto.core.service.management.DefaultFeatureModeManagement;
import dev.sheldan.abstracto.core.service.management.FeatureFlagManagementService;
import dev.sheldan.abstracto.core.service.management.FeatureModeManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -38,6 +39,9 @@ public class FeatureModeServiceBean implements FeatureModeService {
@Autowired
private DefaultFeatureModeManagement defaultFeatureModeManagement;
@Autowired
private ServerManagementService serverManagementService;
@Override
public void enableFeatureModeForFeature(FeatureEnum featureEnum, AServer server, FeatureMode mode) {
AFeature feature = featureManagementService.getFeature(featureEnum.getKey());
@@ -81,6 +85,12 @@ public class FeatureModeServiceBean implements FeatureModeService {
}
}
@Override
public boolean featureModeActive(FeatureEnum featureEnum, Long serverId, FeatureMode mode) {
AServer server = serverManagementService.loadServer(serverId);
return featureModeActive(featureEnum, server, mode);
}
@Override
public FeatureMode getFeatureModeForKey(String key) {
return getAllAvailableFeatureModes().stream().filter(mode -> mode.getKey().equalsIgnoreCase(key)).findAny().orElseThrow(() -> new FeatureModeNotFoundException(key, getFeatureModesAsStrings()));

View File

@@ -22,8 +22,11 @@ import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class SetupServiceBean implements SetupService {
public class FeatureSetupServiceBean implements FeatureSetupService {
public static final String FEATURE_SETUP_CANCELLATION_NOTIFICATION_TEMPLATE = "feature_setup_cancellation_notification";
public static final String FEATURE_SETUP_COMPLETION_NOTIFICATION_TEMPLATE = "feature_setup_completion_notification";
public static final String FEATURE_SETUP_INITIAL_MESSAGE_TEMPLATE_KEY = "feature_setup_initial_message";
@Autowired
private SystemConfigSetupStep systemConfigSetupStep;
@@ -34,7 +37,7 @@ public class SetupServiceBean implements SetupService {
private DelayedActionService delayedActionService;
@Autowired
private SetupServiceBean self;
private FeatureSetupServiceBean self;
@Autowired
private SetupSummaryStep setupSummaryStep;
@@ -52,7 +55,7 @@ public class SetupServiceBean implements SetupService {
private ExceptionService exceptionService;
@Override
public CompletableFuture<Void> performSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId) {
public CompletableFuture<Void> performFeatureSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId) {
log.info("Performing setup of feature {} for user {} in channel {} in server {}.",
featureConfig.getFeature().getKey(), user.getUserId(), user.getChannelId(), user.getGuildId());
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelInGuild(user.getGuildId(), user.getChannelId());
@@ -99,15 +102,15 @@ public class SetupServiceBean implements SetupService {
.featureConfig(featureConfig)
.build();
TextChannel textChannel = textChannelInGuild.get();
String text = templateService.renderTemplate("setup_initial_message", setupInitialMessageModel);
String text = templateService.renderTemplate(FEATURE_SETUP_INITIAL_MESSAGE_TEMPLATE_KEY, setupInitialMessageModel);
channelService.sendTextToChannel(text, textChannel);
return executeSetup(featureConfig, steps, user, new ArrayList<>());
return executeFeatureSetup(featureConfig, steps, user, new ArrayList<>());
}
throw new ChannelNotFoundException(user.getChannelId());
}
@Override
public CompletableFuture<Void> executeSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs) {
public CompletableFuture<Void> executeFeatureSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs) {
SetupExecution nextStep = steps.get(0);
return executeStep(user, nextStep, delayedActionConfigs, featureConfig);
}
@@ -162,7 +165,7 @@ public class SetupServiceBean implements SetupService {
public void notifyAboutCompletion(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig) {
log.trace("Notifying user {} in channel {} in server {} about completion of setup for feature {}.",
aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureConfig.getFeature().getKey());
notifyUserWithTemplate(aServerChannelUserId, featureConfig, "setup_completion_notification");
notifyUserWithTemplate(aServerChannelUserId, featureConfig, FEATURE_SETUP_COMPLETION_NOTIFICATION_TEMPLATE);
}
private void notifyUserWithTemplate(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig, String templateName) {
@@ -179,6 +182,6 @@ public class SetupServiceBean implements SetupService {
public void notifyAboutCancellation(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig) {
log.trace("Notifying user {} in channel {} in server {} about cancellation of setup for feature {}.",
aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureConfig.getFeature().getKey());
notifyUserWithTemplate(aServerChannelUserId, featureConfig, "setup_cancellation_notification");
notifyUserWithTemplate(aServerChannelUserId, featureConfig, FEATURE_SETUP_CANCELLATION_NOTIFICATION_TEMPLATE);
}
}

View File

@@ -110,7 +110,7 @@
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="setup"/>
<column name="name" value="setupFeature"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
@@ -128,7 +128,7 @@
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="disable"/>
<column name="name" value="disableFeature"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
@@ -140,7 +140,7 @@
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="enable"/>
<column name="name" value="enableFeature"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>

View File

@@ -24,7 +24,7 @@ import java.util.Arrays;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class DisableModeTest {
public class DisableFeatureModeTest {
@InjectMocks
private DisableMode testUnit;

View File

@@ -26,7 +26,7 @@ import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class EnableModeTest {
public class EnableFeatureModeTest {
@InjectMocks
private EnableMode testUnit;

View File

@@ -20,7 +20,7 @@ public class InteractiveUtils {
@Transactional
public void sendTimeoutMessage(Long serverId, Long channelId) {
String s = templateService.renderSimpleTemplate("setup_configuration_timeout");
String s = templateService.renderSimpleTemplate("feature_setup_configuration_timeout");
Optional<TextChannel> channelOptional = channelService.getTextChannelInGuild(serverId, channelId);
channelOptional.ifPresent(channel -> channelService.sendTextToChannelNotAsync(s, channel));
}

View File

@@ -21,7 +21,7 @@ public class SetupStepException extends AbstractoRunTimeException implements Tem
@Override
public String getTemplateName() {
return "setup_step_exception";
return "feature_setup_step_exception";
}
@Override

View File

@@ -14,6 +14,7 @@ public interface FeatureModeService {
void setFutureModeForFuture(FeatureEnum featureEnum, AServer server, FeatureMode mode, Boolean newValue);
void disableFeatureModeForFeature(FeatureEnum featureEnum, AServer server, FeatureMode mode);
boolean featureModeActive(FeatureEnum featureEnum, AServer server, FeatureMode mode);
boolean featureModeActive(FeatureEnum featureEnum, Long serverId, FeatureMode mode);
FeatureMode getFeatureModeForKey(String key);
List<FeatureMode> getAllAvailableFeatureModes();
List<FeatureModeDisplay> getEffectiveFeatureModes(AServer server);

View File

@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.models.AServerChannelUserId;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public interface SetupService {
CompletableFuture<Void> performSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId);
CompletableFuture<Void> executeSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs);
public interface FeatureSetupService {
CompletableFuture<Void> performFeatureSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId);
CompletableFuture<Void> executeFeatureSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs);
}

View File

@@ -3,8 +3,8 @@
The core feature contains necessary commands in order for Abstracto to function and be configured.
==== Emotes
* reaction emote in case the command completed successfully `successReaction`
* reaction emote in case the command did not complete successfully `warnReaction`
* `successReaction` reaction emote in case the command completed successfully
* `warnReaction` reaction emote in case the command did not complete successfully
==== Commands
Help::
@@ -43,13 +43,13 @@ Listing the features::
* Usage: `features`
* Description: Lists the available features and whether or not they are enabled in this server.
Enabling a feature::
* Usage: `enable <key>`
* Usage: `enableFeature <key>`
* Description: Enables the feature identified by `key` in this server. If the feature dependents on other features, they will be enabled as well.
* Example: `enable moderation` to enable the moderation feature
* Example: `enableFeature moderation` to enable the moderation feature
Disabling a feature::
* Usage: `disable <key>`
* Usage: `disableFeature <key>`
* Description: Disables the feature identified by `key` in this server. If the feature is required for other features, they will be disabled as well.
* Example: `disable moderation` to disable the moderation feature
* Example: `disableFeature moderation` to disable the moderation feature
Creating a channel group::
* Usage: `createChannelGroup <key>`
* Description: Creates a new channel group identified by `key`.
@@ -112,7 +112,7 @@ Listing all feature modes::
* usage `featureModes [feature]`
* Description: Lists all of the currently available feature modes and the feature they are associated with. If `feature` is given, it only lists the feature modes of this feature. The output also includes whether or not the current mode is enabled and if this value comes from the default configuration.
Setting up a feature with an interactive wizard::
Usage: `setup <featureName>`
Usage: `setupFeature <featureName>`
* Description: Starts an interactive wizard to configure the necessary properties and post targets of a feature. Also includes custom steps. Closes with a summary page to see all changes.

View File

@@ -6,6 +6,10 @@ Feature key: `moderation`
`banLog`:: target of the log message containing information about the ban for both `ban` and `banId`. Will still ban if not setup.
`kickLog`:: target of the log message containing information about the kick. Will still kick if not setup.
==== Feature modes
`banLogging`:: if enabled, log bans to the post target `banLog`. Enabled by default.
`kickLogging`:: if enabled, log bans to the post target `kickLog`. Enabled by default.
==== Commands
Ban a member::
* Usage: `ban <member> [reason]`
@@ -42,8 +46,13 @@ This feature can be used to warn specific users if they did something not allowe
Feature key: `warnings`
==== Post targets
`warnLog`:: target of the log message containing information about the warn.
`decayLog`:: Will be used when all the warnings are decayed by a command and logging has been selected.
`warnLog`:: target of the log message containing information about a created warn, only used if feature mode `warnLogging` is enabled.
`decayLog`:: will be used when all the warnings are decayed by `decayAllWarnings` and feature mode `warnDecayLogging` is enabled.
==== Feature modes
`warnLogging`:: if enabled, each warn is logged to the post target `warnLog`. Enabled by default.
`automaticWarnDecayLogging`:: if enabled, warn decays by `decayAllWarnings` are logged to the post target `decayLog`. Enabled by default.
==== Commands
Warn a user::
@@ -59,9 +68,8 @@ Showing your warnings::
* Usage: `myWarnings`
* Description: Displays the amount of warnings of the user executing on the server. This will show both active and total warnings.
Decaying all warnings regardless of the date::
* Usage: `decayAllWarnings [writeLog]`
* Description: This will cause all warnings of this server which are not decayed yet to be decayed instantly. If this command should log the decaying of the warnings
the `writeLog` parameter needs to be `true`.
* Usage: `decayAllWarnings`
* Description: This will cause all warnings of this server which are not decayed yet to be decayed instantly.
Deleting a warning::
* Usage: `deleteWarning <warnId>`
* Description: Deletes the warning identified by `warnId` completely from the database.
@@ -79,6 +87,9 @@ Feature key: `warnDecay`
==== Post targets
`decayLog`:: target of the log message containing the information in case a warning is decayed.
==== Feature modes
`automaticWarnDecayLogging`:: if enabled, automatic warn decays are logged to the `decayLog` post target. Enabled by default.
==== Commands
Decaying all warnings if necessary::
* Usage: `decayWarnings`
@@ -95,6 +106,12 @@ Feature key `muting`
==== Post targets
`muteLog`:: target of log message containing the information in case a member was muted and when the mute ended automatically.
==== Feature modes
`muteLogging`:: if enabled, each mute is to be logged to the post target `muteLog`. Enabled by default.
`unMuteLogging`:: if enabled, each un mute which happens 'naturally' (after the defined time period is over) will be logged to the `muteLog` post target. Enabled by default.
`manualUnMuteLogging`:: if enabled, each un mute which happens via the command `unmute` will be logged to the `muteLog` post target. Enabled by default.
==== Commands
Muting a user::
* Usage: `mute <member> <duration> [reason]`

View File

@@ -26,11 +26,11 @@ Feature key: `modmail`
`modmailLog`:: Will be used to log the interactions when a thread is closed.
==== Feature modes
`log`:: If this is enabled, the messages should be logged into the `modmailLog` post target when the thread is closed (by the respective commands). This is required for the command `closeNoLog` to be available.
`log`:: If this is enabled, the messages should be logged into the `modmailLog` post target when the thread is closed (by the respective commands). This is required for the command `closeNoLog` to be available. Enabled by default.
==== Emotes
* to indicate to the user that the message sent was processed `readReaction`
* `readReaction` to indicate to the user that the message sent was processed
==== Commands
Opening a mod mail thread for a user::

View File

@@ -29,16 +29,14 @@ When the poster of the message reacts to the message with a star, this is not co
Feature key: `starboard`
==== Emotes
* to vote on posting something to starboard: `star`
* for the different level of starboard posts:
** Level 1: `star1`
** Level 2: `star2`
** Level 3: `star3`
** Level 4: `star4`
* as badges in the `starStats` command:
** First place: `starboardBadge1`
** Second place: `starboardBadge2`
** Third place: `starboardBadge3`
* `star` to vote on posting something to starboard
* `star1` for level 1 of starboard
* `star2` for level 2 of starboard
* `star3` for level 3 of starboard
* `star4` for level 4 of starboard
* `starboardBadge1` used as marker for first place in the command `starStats`
* `starboardBadge2` used as marker for first place in the command `starStats`
* `starboardBadge3` used as marker for first place in the command `starStats`
==== Relevant system configuration
@@ -68,8 +66,8 @@ Feature key: `suggestion`
`suggestions`:: the target of the messages containing the suggestions
==== Emotes
* for up-voting a suggestion: `suggestionYes`
* for down-voting a suggestion: `suggestionNo`
* `suggestionYes` for up-voting a suggestion
* `suggestionNo` for down-voting a suggestion
==== Commands
Creating a suggestion::
@@ -110,7 +108,7 @@ Displaying information about server::
=== Link embeds
==== Emotes
* to remove the embed of a link: `removeEmbed`
* `removeEmbed` to remove the embed of a link
This feature enables the automatic embedding of messages containing a message link.
If a message contains a link to a discord message this will create an embed containing the the message content. This supports image attachments, but not videos or files.