mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-05 08:54:34 +00:00
[AB-284] adding warn decay notification
adding default mute reason fixing incorrect muting user being stored
This commit is contained in:
@@ -10,6 +10,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
|
||||
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
|
||||
import dev.sheldan.abstracto.moderation.model.template.command.MuteContext;
|
||||
@@ -30,15 +31,21 @@ import static dev.sheldan.abstracto.moderation.service.MuteService.MUTE_EFFECT_K
|
||||
@Component
|
||||
public class Mute extends AbstractConditionableCommand {
|
||||
|
||||
public static final String MUTE_DEFAULT_REASON_TEMPLATE = "mute_default_reason";
|
||||
|
||||
@Autowired
|
||||
private MuteService muteService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Member member = (Member) parameters.get(0);
|
||||
Duration duration = (Duration) parameters.get(1);
|
||||
String reason = (String) parameters.get(2);
|
||||
String defaultReason = templateService.renderSimpleTemplate(MUTE_DEFAULT_REASON_TEMPLATE, commandContext.getGuild().getIdLong());
|
||||
String reason = parameters.size() == 3 ? (String) parameters.get(2) : defaultReason;
|
||||
ServerChannelMessage context = ServerChannelMessage
|
||||
.builder()
|
||||
.serverId(commandContext.getGuild().getIdLong())
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package dev.sheldan.abstracto.moderation.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerSpecificId;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.moderation.model.database.Warning;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.Instant;
|
||||
@@ -13,8 +13,9 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface WarnRepository extends JpaRepository<Warning, Long> {
|
||||
public interface WarnRepository extends JpaRepository<Warning, ServerSpecificId> {
|
||||
List<Warning> findAllByWarnedUser_ServerReferenceAndDecayedFalseAndWarnDateLessThan(AServer server, Instant cutOffDate);
|
||||
List<Warning> findAllByWarnedUser_ServerReferenceAndDecayedFalseAndWarnDateGreaterThan(AServer server, Instant cutOffDate);
|
||||
|
||||
List<Warning> findAllByWarnedUser_ServerReference(AServer server);
|
||||
|
||||
@@ -24,10 +25,6 @@ public interface WarnRepository extends JpaRepository<Warning, Long> {
|
||||
|
||||
List<Warning> findByWarnedUser(AUserInAServer aUserInAServer);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
Optional<Warning> findById(@NonNull Long aLong);
|
||||
|
||||
@NotNull
|
||||
Optional<Warning> findByWarnId_IdAndWarnId_ServerId(Long warnId, Long serverId);
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ public class MuteServiceBean implements MuteService {
|
||||
.messageId(muteContext.getContext().getMessageId())
|
||||
.build();
|
||||
AUserInAServer userInServerBeingMuted = userInServerManagementService.loadOrCreateUser(muteContext.getMutedUser());
|
||||
AUserInAServer userInServerMuting = userInServerManagementService.loadOrCreateUser(muteContext.getMutedUser());
|
||||
AUserInAServer userInServerMuting = userInServerManagementService.loadOrCreateUser(muteContext.getMutingUser());
|
||||
muteManagementService.createMute(userInServerBeingMuted, userInServerMuting, muteContext.getReason(), muteContext.getMuteTargetDate(), origin, triggerKey, muteContext.getMuteId());
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,13 @@ 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.WarnManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.ISnowflake;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -37,6 +39,8 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@@ -85,6 +89,7 @@ public class WarnServiceBean implements WarnService {
|
||||
public static final String WARN_NOTIFICATION_TEMPLATE = "warn_notification";
|
||||
public static final String WARNINGS_COUNTER_KEY = "WARNINGS";
|
||||
public static final String WARN_DECAY_LOG_TEMPLATE_KEY = "warn_decay_log";
|
||||
public static final String WARN_DECAY_NOTIFICATION_TEMPLATE_KEY = "warn_decay_member_notification";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> notifyAndLogFullUserWarning(WarnContext context) {
|
||||
@@ -131,6 +136,7 @@ public class WarnServiceBean implements WarnService {
|
||||
Instant cutOffDay = Instant.now().minus(days, ChronoUnit.DAYS);
|
||||
log.info("Decaying warnings on server {} which are older than {}.", server.getId(), cutOffDay);
|
||||
List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, cutOffDay);
|
||||
List<Long> userIds = new ArrayList<>(getUserIdsForWarnings(warningsToDecay));
|
||||
List<Long> warningIds = flattenWarnings(warningsToDecay);
|
||||
Long serverId = server.getId();
|
||||
CompletableFuture<Void> completableFuture;
|
||||
@@ -141,11 +147,57 @@ public class WarnServiceBean implements WarnService {
|
||||
log.debug("Not logging automatic warn decay, because feature {} has its mode {} disabled in server {}.", ModerationFeatureDefinition.AUTOMATIC_WARN_DECAY, WarnDecayMode.AUTOMATIC_WARN_DECAY_LOG, server.getId());
|
||||
completableFuture = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
if(featureModeService.featureModeActive(ModerationFeatureDefinition.AUTOMATIC_WARN_DECAY, server, WarnDecayMode.NOTIFY_MEMBER_WARNING_DECAYS)) {
|
||||
CompletableFuture<List<Member>> membersInServerAsync = memberService.getMembersInServerAsync(server.getId(), userIds);
|
||||
membersInServerAsync
|
||||
.thenAccept(members -> self.sendMemberNotifications(serverId, warningIds, members, cutOffDay)).exceptionally(throwable -> {
|
||||
log.error("Failed to notify members about warn decays.", throwable);
|
||||
return null;
|
||||
});
|
||||
log.info("Notifying members about warn decay in server {}.", server.getId());
|
||||
} else {
|
||||
log.info("Not notifying members about warn decay in server {}.", server.getId());
|
||||
}
|
||||
return completableFuture.thenAccept(aVoid ->
|
||||
self.decayWarnings(warningIds, serverId)
|
||||
);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> sendMemberNotifications(Long serverId, List<Long> warnIds, List<Member> members, Instant cutOffDay) {
|
||||
List<Warning> decayingWarnings = warnManagementService.getWarningsViaId(warnIds, serverId);
|
||||
AServer server = decayingWarnings.get(0).getWarnedUser().getServerReference();
|
||||
List<CompletableFuture<Message>> notificationFutures = new ArrayList<>();
|
||||
Map<Long, Member> userIdToMember = members.stream().collect(Collectors.toMap(ISnowflake::getIdLong, Function.identity()));
|
||||
decayingWarnings.forEach(warning -> {
|
||||
Long userId = warning.getWarnedUser().getUserReference().getId();
|
||||
Long warningId = warning.getWarnId().getId();
|
||||
if(userIdToMember.containsKey(userId)) {
|
||||
Member memberToSendTo = userIdToMember.get(userId);
|
||||
List<Warning> remainingWarnings = warnManagementService.getActiveWarningsInServerYoungerThan(server, cutOffDay);
|
||||
WarnDecayMemberNotificationModel model =
|
||||
WarnDecayMemberNotificationModel
|
||||
.builder()
|
||||
.warnDate(warning.getWarnDate())
|
||||
.warnReason(warning.getReason())
|
||||
.remainingWarningsCount(remainingWarnings.size())
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(WARN_DECAY_NOTIFICATION_TEMPLATE_KEY, model, serverId);
|
||||
log.info("Notifying user {} in server {} about decayed warning {}.", userId, serverId, warningId);
|
||||
notificationFutures.add(messageService.sendMessageToSendToUser(memberToSendTo.getUser(), messageToSend).exceptionally(throwable -> {
|
||||
log.error("Failed to send warn decay message to user {} in server {} to notify about decay warning {}.", userId, server, warningId);
|
||||
return null;
|
||||
}));
|
||||
} else {
|
||||
log.warn("Could not find user {} in server {}. Not notifying about decayed warning {}.", userId, serverId, warningId);
|
||||
}
|
||||
});
|
||||
CompletableFuture<Void> future = new CompletableFuture();
|
||||
FutureUtils.toSingleFutureGeneric(notificationFutures)
|
||||
.whenComplete((unused, throwable) -> future.complete(null));
|
||||
return future;
|
||||
}
|
||||
|
||||
private List<Long> flattenWarnings(List<Warning> warningsToDecay) {
|
||||
List<Long> warningIds = new ArrayList<>();
|
||||
warningsToDecay.forEach(warning ->
|
||||
@@ -154,6 +206,12 @@ public class WarnServiceBean implements WarnService {
|
||||
return warningIds;
|
||||
}
|
||||
|
||||
private Set<Long> getUserIdsForWarnings(List<Warning> warnings) {
|
||||
Set<Long> userIds = new HashSet<>();
|
||||
warnings.forEach(warning -> userIds.add(warning.getWarnedUser().getUserReference().getId()));
|
||||
return userIds;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void decayWarnings(List<Long> warningIds, Long serverId) {
|
||||
Instant now = Instant.now();
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.springframework.stereotype.Component;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@@ -43,6 +44,11 @@ public class WarnManagementServiceBean implements WarnManagementService {
|
||||
return warnRepository.findAllByWarnedUser_ServerReferenceAndDecayedFalseAndWarnDateLessThan(server, date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Warning> getActiveWarningsInServerYoungerThan(AServer server, Instant date) {
|
||||
return warnRepository.findAllByWarnedUser_ServerReferenceAndDecayedFalseAndWarnDateGreaterThan(server, date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTotalWarnsForUser(AUserInAServer aUserInAServer) {
|
||||
return warnRepository.countByWarnedUser(aUserInAServer);
|
||||
@@ -73,6 +79,15 @@ public class WarnManagementServiceBean implements WarnManagementService {
|
||||
return findByIdOptional(id, serverId).orElseThrow(() -> new AbstractoRunTimeException("Warning not found."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Warning> getWarningsViaId(List<Long> warnIds, Long serverId) {
|
||||
List<ServerSpecificId> serverWarnIds = warnIds
|
||||
.stream()
|
||||
.map(aLong -> new ServerSpecificId(serverId, aLong))
|
||||
.collect(Collectors.toList());
|
||||
return warnRepository.findAllById(serverWarnIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWarning(Warning warning) {
|
||||
log.info("Deleting warning with id {} in server {}.", warning.getWarnId().getId(), warning.getWarnId().getServerId());
|
||||
|
||||
@@ -46,6 +46,10 @@ abstracto.featureModes.automaticWarnDecayLogging.featureName=warnDecay
|
||||
abstracto.featureModes.automaticWarnDecayLogging.mode=automaticWarnDecayLogging
|
||||
abstracto.featureModes.automaticWarnDecayLogging.enabled=true
|
||||
|
||||
abstracto.featureModes.notifyMemberWarningDecays.featureName=warnDecay
|
||||
abstracto.featureModes.notifyMemberWarningDecays.mode=notifyMemberWarningDecays
|
||||
abstracto.featureModes.notifyMemberWarningDecays.enabled=true
|
||||
|
||||
abstracto.featureModes.manualUnMuteLogging.featureName=muting
|
||||
abstracto.featureModes.manualUnMuteLogging.mode=manualUnMuteLogging
|
||||
abstracto.featureModes.manualUnMuteLogging.enabled=true
|
||||
|
||||
@@ -2,8 +2,10 @@ package dev.sheldan.abstracto.moderation.command.mute;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
|
||||
import dev.sheldan.abstracto.moderation.command.Ban;
|
||||
import dev.sheldan.abstracto.moderation.command.Mute;
|
||||
import dev.sheldan.abstracto.moderation.model.template.command.MuteContext;
|
||||
import dev.sheldan.abstracto.moderation.service.MuteService;
|
||||
@@ -29,6 +31,9 @@ public class MuteTest {
|
||||
@Mock
|
||||
private MuteService muteService;
|
||||
|
||||
@Mock
|
||||
private TemplateService templateService;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<MuteContext> muteLogArgumentCaptor;
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum WarnDecayMode implements FeatureMode {
|
||||
AUTOMATIC_WARN_DECAY_LOG("automaticWarnDecayLogging");
|
||||
AUTOMATIC_WARN_DECAY_LOG("automaticWarnDecayLogging"),
|
||||
NOTIFY_MEMBER_WARNING_DECAYS("notifyMemberWarningDecays")
|
||||
;
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.moderation.model.template.listener;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class WarnDecayMemberNotificationModel {
|
||||
private Instant warnDate;
|
||||
private String warnReason;
|
||||
private Integer remainingWarningsCount;
|
||||
}
|
||||
@@ -11,11 +11,13 @@ import java.util.Optional;
|
||||
public interface WarnManagementService {
|
||||
Warning createWarning(AUserInAServer warnedAUser, AUserInAServer warningAUser, String reason, Long warnId);
|
||||
List<Warning> getActiveWarningsInServerOlderThan(AServer server, Instant date);
|
||||
List<Warning> getActiveWarningsInServerYoungerThan(AServer server, Instant date);
|
||||
Long getTotalWarnsForUser(AUserInAServer aUserInAServer);
|
||||
List<Warning> getAllWarnsForUser(AUserInAServer aUserInAServer);
|
||||
List<Warning> getAllWarningsOfServer(AServer server);
|
||||
Long getActiveWarnsForUser(AUserInAServer aUserInAServer);
|
||||
Optional<Warning> findByIdOptional(Long id, Long serverId);
|
||||
Warning findById(Long id, Long serverId);
|
||||
List<Warning> getWarningsViaId(List<Long> warnIds, Long serverId);
|
||||
void deleteWarning(Warning warn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user