Skip to content

Commit

Permalink
[AB-111] adding ability to perform moderation actions on various logg…
Browse files Browse the repository at this point in the history
…ing/report messages
  • Loading branch information
Sheldan committed Mar 17, 2024
1 parent f45721b commit dbf5d99
Show file tree
Hide file tree
Showing 76 changed files with 1,661 additions and 646 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import dev.sheldan.abstracto.invitefilter.model.template.listener.DeletedInvitesNotificationModel;
import dev.sheldan.abstracto.invitefilter.service.management.AllowedInviteLinkManagement;
import dev.sheldan.abstracto.invitefilter.service.management.FilteredInviteLinkManagement;
import dev.sheldan.abstracto.moderation.model.ModerationActionButton;
import dev.sheldan.abstracto.moderation.service.ModerationActionService;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
Expand Down Expand Up @@ -78,6 +80,9 @@ public class InviteLinkFilterServiceBean implements InviteLinkFilterService {
@Autowired
private RoleImmunityService roleImmunityService;

@Autowired(required = false)
private ModerationActionService moderationActionService;

private static final Pattern INVITE_CODE_PATTERN = Pattern.compile("(?<code>[a-z0-9-]+)", Pattern.CASE_INSENSITIVE);

public static final String INVITE_FILTER_METRIC = "invite.filter";
Expand Down Expand Up @@ -230,10 +235,18 @@ private CompletableFuture<Void> sendDeletionNotification(List<InviteToDelete> co
log.info("Post target {} not defined for server {} - not sending invite link deletion notification.", InviteFilterPostTarget.INVITE_DELETE_LOG.getKey(), serverId);
return CompletableFuture.completedFuture(null);
}
boolean moderationActionsEnabled = featureModeService.featureModeActive(InviteFilterFeatureDefinition.INVITE_FILTER, serverId, InviteFilterMode.FILTER_MODERATION_ACTIONS);
List<ModerationActionButton> moderationActionComponents = new ArrayList<>();
if(moderationActionsEnabled && moderationActionService != null) {
ServerUser reportedServerUser = ServerUser.fromMember(message.getMember());
List<ModerationActionButton> moderationActions = moderationActionService.getModerationActionButtons(reportedServerUser);
moderationActionComponents.addAll(moderationActions);
}
DeletedInvitesNotificationModel model = DeletedInvitesNotificationModel
.builder()
.author(message.getMember())
.guild(message.getGuild())
.moderationActionComponents(moderationActionComponents)
.message(message)
.channel(message.getChannel())
.invites(groupInvites(codes))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ abstracto.featureModes.filterNotifications.featureName=inviteFilter
abstracto.featureModes.filterNotifications.mode=filterNotifications
abstracto.featureModes.filterNotifications.enabled=true

abstracto.featureModes.filterModerationActions.featureName=inviteFilter
abstracto.featureModes.filterModerationActions.mode=filterModerationActions
abstracto.featureModes.filterModerationActions.enabled=false
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
<artifactId>core-int</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation-int</artifactId>
<version>1.5.27-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public List<PostTargetEnum> getRequiredPostTargets() {

@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(InviteFilterMode.FILTER_NOTIFICATIONS, InviteFilterMode.TRACK_USES);
return Arrays.asList(InviteFilterMode.values());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

@Getter
public enum InviteFilterMode implements FeatureMode {
TRACK_USES("trackUses"), FILTER_NOTIFICATIONS("filterNotifications");
TRACK_USES("trackUses"), FILTER_NOTIFICATIONS("filterNotifications"), FILTER_MODERATION_ACTIONS("filterModerationActions");

private final String key;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.invitefilter.model.template.listener;

import dev.sheldan.abstracto.moderation.model.ModerationActionButton;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -17,4 +18,5 @@ public class DeletedInvitesNotificationModel {
private Member author;
private Message message;
private List<DeletedInvite> invites;
private List<ModerationActionButton> moderationActionComponents;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.ParseUtils;
Expand Down Expand Up @@ -70,7 +70,7 @@ public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEven
}
if(slashCommandParameterService.hasCommandOptionWithFullType(USER_PARAMETER, event, OptionType.USER)) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, User.class, Member.class);
return banService.banUserWithNotification(member.getUser(), reason, event.getMember(), duration)
return banService.banUserWithNotification(ServerUser.fromMember(member), reason, ServerUser.fromMember(event.getMember()), event.getGuild(), duration)
.thenCompose(banResult -> {
if(banResult == NOTIFICATION_FAILED) {
String errorNotification = templateService.renderSimpleTemplate(BAN_NOTIFICATION_NOT_POSSIBLE, event.getGuild().getIdLong());
Expand All @@ -84,7 +84,7 @@ public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEven
String userIdStr = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, User.class, String.class);
Long userId = Long.parseLong(userIdStr);
return userService.retrieveUserForId(userId)
.thenCompose(user -> banService.banUserWithNotification(user, reason, event.getMember(), duration))
.thenCompose(user -> banService.banUserWithNotification(ServerUser.fromId(event.getGuild().getIdLong(), userId), reason, ServerUser.fromMember(event.getMember()), event.getGuild(), duration))
.thenCompose(banResult -> {
if(banResult == NOTIFICATION_FAILED) {
String errorNotification = templateService.renderSimpleTemplate(BAN_NOTIFICATION_NOT_POSSIBLE, event.getGuild().getIdLong());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@

import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.EffectConfig;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.template.command.KickLogModel;
import dev.sheldan.abstracto.moderation.service.KickServiceBean;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -47,30 +48,6 @@ public class Kick extends AbstractConditionableCommand {
@Autowired
private InteractionService interactionService;

@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
Member member = (Member) parameters.get(0);
if(!member.getGuild().equals(commandContext.getGuild())) {
throw new EntityGuildMismatchException();
}
String defaultReason = templateService.renderSimpleTemplate(KICK_DEFAULT_REASON_TEMPLATE, commandContext.getGuild().getIdLong());
String reason = parameters.size() == 2 ? (String) parameters.get(1) : defaultReason;

KickLogModel kickLogModel = KickLogModel
.builder()
.kickedUser(member)
.reason(reason)
.guild(commandContext.getGuild())
.channel(commandContext.getChannel())
.member(commandContext.getAuthor())
.build();
kickLogModel.setKickedUser(member);
kickLogModel.setReason(reason);
return kickService.kickMember(member, reason, kickLogModel)
.thenApply(aVoid -> CommandResult.fromSuccess());
}

@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
Expand All @@ -84,17 +61,7 @@ public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEven
reason = templateService.renderSimpleTemplate(KICK_DEFAULT_REASON_TEMPLATE, event.getGuild().getIdLong());
}

KickLogModel kickLogModel = KickLogModel
.builder()
.kickedUser(member)
.reason(reason)
.guild(event.getGuild())
.channel(event.getGuildChannel())
.member(event.getMember())
.build();
kickLogModel.setKickedUser(member);
kickLogModel.setReason(reason);
return kickService.kickMember(member, reason, kickLogModel)
return kickService.kickMember(member, event.getMember(), reason)
.thenCompose(unused -> interactionService.replyEmbed(KICK_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
Expand Down Expand Up @@ -143,6 +110,7 @@ public CommandConfiguration getConfiguration() {
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true)
.async(true)
.slashCommandOnly(true)
.effects(effectConfig)
.causesReaction(true)
.parameters(parameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.ServerChannelMessage;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.core.utils.SnowflakeUtils;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.template.command.MuteContext;
import dev.sheldan.abstracto.moderation.service.MuteService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
Expand All @@ -24,17 +29,18 @@
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import static dev.sheldan.abstracto.moderation.model.MuteResult.NOTIFICATION_FAILED;
import static dev.sheldan.abstracto.moderation.service.MuteService.MUTE_EFFECT_KEY;

@Component
public class Mute extends AbstractConditionableCommand {

private static final String MUTE_DEFAULT_REASON_TEMPLATE = "mute_default_reason";
public static final String MUTE_NOTIFICATION_NOT_POSSIBLE_TEMPLATE_KEY = "mute_notification_not_possible";
private static final String DURATION_PARAMETER = "duration";
private static final String MUTE_COMMAND = "mute";
private static final String USER_PARAMETER = "user";
Expand All @@ -53,6 +59,9 @@ public class Mute extends AbstractConditionableCommand {
@Autowired
private InteractionService interactionService;

@Autowired
private ChannelService channelService;

@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
Expand All @@ -64,15 +73,19 @@ public CompletableFuture<CommandResult> executeAsync(CommandContext commandConte
Duration duration = (Duration) parameters.get(1);
String defaultReason = templateService.renderSimpleTemplate(MUTE_DEFAULT_REASON_TEMPLATE, guild.getIdLong());
String reason = parameters.size() == 3 ? (String) parameters.get(2) : defaultReason;
MuteContext muteLogModel = MuteContext
.builder()
.muteTargetDate(Instant.now().plus(duration))
.mutedUser(member)
.channelId(commandContext.getChannel().getIdLong())
.reason(reason)
.mutingUser(commandContext.getAuthor())
.build();
return muteService.muteMemberWithLog(muteLogModel)
ServerUser userToMute = ServerUser.fromMember(member);
ServerUser mutingUser = ServerUser.fromMember(commandContext.getAuthor());
Long serverId = commandContext.getGuild().getIdLong();
ServerChannelMessage serverChannelMessage = ServerChannelMessage.fromMessage(commandContext.getMessage());
return muteService.muteMemberWithLog(userToMute, mutingUser, reason, duration, commandContext.getGuild(), serverChannelMessage)
.thenCompose(muteResult -> {
if(muteResult == NOTIFICATION_FAILED) {
MessageToSend errorNotification = templateService.renderEmbedTemplate(MUTE_NOTIFICATION_NOT_POSSIBLE_TEMPLATE_KEY, new Object(), serverId);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(errorNotification, commandContext.getChannel()));
} else {
return CompletableFuture.completedFuture(null);
}
})
.thenApply(aVoid -> CommandResult.fromSuccess());
}

Expand All @@ -88,16 +101,23 @@ public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEven
} else {
reason = templateService.renderSimpleTemplate(MUTE_DEFAULT_REASON_TEMPLATE, guild.getIdLong());
}
MuteContext muteLogModel = MuteContext
Long serverId = event.getGuild().getIdLong();
ServerChannelMessage commandMessage = ServerChannelMessage
.builder()
.muteTargetDate(Instant.now().plus(duration))
.mutedUser(targetMember)
.reason(reason)
.serverId(serverId)
.channelId(event.getChannel().getIdLong())
.mutingUser(event.getMember())
.messageId(SnowflakeUtils.createSnowFlake())
.build();
return muteService.muteMemberWithLog(muteLogModel)
.thenCompose(unused -> interactionService.replyEmbed(MUTE_RESPONSE, event))
ServerUser userToMute = ServerUser.fromMember(targetMember);
ServerUser mutingUser = ServerUser.fromMember(event.getMember());
return muteService.muteMemberWithLog(userToMute, mutingUser, reason, duration, event.getGuild(), commandMessage)
.thenCompose(muteResult -> {
if(muteResult == NOTIFICATION_FAILED) {
return interactionService.replyEmbed(MUTE_NOTIFICATION_NOT_POSSIBLE_TEMPLATE_KEY, new Object(), event);
} else {
return interactionService.replyEmbed(MUTE_RESPONSE, event);
}
})
.thenApply(aVoid -> CommandResult.fromSuccess());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
Expand Down Expand Up @@ -50,7 +51,7 @@ public CompletableFuture<CommandResult> executeAsync(CommandContext commandConte
String userIdStr = (String) parameters.get(0);
Long userId = Long.parseLong(userIdStr);
return userService.retrieveUserForId(userId)
.thenCompose(user -> banService.unBanUserWithNotification(user, commandContext.getAuthor()))
.thenCompose(user -> banService.unBanUserWithNotification(userId, ServerUser.fromMember(commandContext.getAuthor()), commandContext.getGuild()))
.thenApply(aVoid -> CommandResult.fromSuccess());
}

Expand All @@ -59,7 +60,7 @@ public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEven
String userIdStr = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, String.class);
Long userId = Long.parseLong(userIdStr);
return userService.retrieveUserForId(userId)
.thenCompose(user -> banService.unBanUserWithNotification(user, event.getMember()))
.thenCompose(user -> banService.unBanUserWithNotification(userId, ServerUser.fromMember(event.getMember()), event.getGuild()))
.thenCompose(unused -> interactionService.replyEmbed(UN_BAN_RESPONSE, event))
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
Expand Down
Loading

0 comments on commit dbf5d99

Please sign in to comment.