diff --git a/src/main/java/net/discordjug/javabot/systems/moderation/DiscordModerationLogListener.java b/src/main/java/net/discordjug/javabot/systems/moderation/DiscordModerationLogListener.java new file mode 100644 index 000000000..6dc9d3dda --- /dev/null +++ b/src/main/java/net/discordjug/javabot/systems/moderation/DiscordModerationLogListener.java @@ -0,0 +1,66 @@ +package net.discordjug.javabot.systems.moderation; + +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.concurrent.ExecutorService; + +import lombok.RequiredArgsConstructor; +import net.discordjug.javabot.data.config.BotConfig; +import net.discordjug.javabot.systems.moderation.warn.dao.WarnRepository; +import net.discordjug.javabot.systems.notification.NotificationService; +import net.dv8tion.jda.api.audit.AuditLogChange; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +/** + * Logs moderative actions that did not use bot commands. + */ +@RequiredArgsConstructor +public class DiscordModerationLogListener extends ListenerAdapter{ + + private final NotificationService notificationService; + private final BotConfig botConfig; + private final WarnRepository warnRepository; + private final ExecutorService asyncPool; + + @Override + public void onGuildAuditLogEntryCreate(GuildAuditLogEntryCreateEvent event) { + + ModerationService moderationService = new ModerationService(notificationService, botConfig.get(event.getGuild()), warnRepository, asyncPool); + + AuditLogEntry entry = event.getEntry(); + long targetUserId = entry.getTargetIdLong(); + long moderatorUserId = entry.getUserIdLong(); + if (moderatorUserId == event.getJDA().getSelfUser().getIdLong()) { + return; + } + event.getJDA().retrieveUserById(targetUserId).queue(targetUser -> { + event.getGuild().retrieveMemberById(moderatorUserId).queue(moderator -> { + String reason = entry.getReason(); + if (reason == null) { + reason = ""; + } + switch(entry.getType()) { + case KICK -> moderationService.sendKickGuildNotification(targetUser, reason, moderator); + case BAN -> moderationService.sendBanGuildNotification(targetUser, reason, moderator); + case UNBAN -> moderationService.sendUnbanGuildNotification(targetUser, reason, moderator); + case MEMBER_UPDATE -> { + if (entry.getChanges().containsKey("communication_disabled_until")) { + AuditLogChange change = entry.getChangeByKey("communication_disabled_until"); + if (change.getNewValue()!=null) { + ZonedDateTime timeoutRemovalTimestamp = java.time.ZonedDateTime.parse(change.getNewValue()); + moderationService.sendTimeoutGuildNotification(targetUser, reason, moderator, Duration.between(ZonedDateTime.now(), timeoutRemovalTimestamp)); + }else { + moderationService.sendRemoveTimeoutGuildNotification(targetUser, reason, moderator); + } + } + } + default -> {} + } + }); + }); + + } + +} diff --git a/src/main/java/net/discordjug/javabot/systems/moderation/ModerationService.java b/src/main/java/net/discordjug/javabot/systems/moderation/ModerationService.java index 0bfeb42f3..42e435bdd 100644 --- a/src/main/java/net/discordjug/javabot/systems/moderation/ModerationService.java +++ b/src/main/java/net/discordjug/javabot/systems/moderation/ModerationService.java @@ -210,7 +210,7 @@ public void timeout(@Nonnull User user, @Nonnull String reason, @Nonnull Member * @param quiet If true, don't send a message in the channel. */ public void removeTimeout(Member member, String reason, Member removedBy, MessageChannel channel, boolean quiet) { - MessageEmbed removeTimeoutEmbed = buildTimeoutRemovedEmbed(member, removedBy, reason); + MessageEmbed removeTimeoutEmbed = buildTimeoutRemovedEmbed(member.getUser(), removedBy, reason); removedBy.getGuild().removeTimeout(member).queue(s -> { notificationService.withUser(member.getUser(), removedBy.getGuild()).sendDirectMessage(c -> c.sendMessageEmbeds(removeTimeoutEmbed)); notificationService.withGuild(member.getGuild()).sendToModerationLog(c -> c.sendMessageEmbeds(removeTimeoutEmbed)); @@ -291,6 +291,35 @@ public void kick(User user, String reason, Member kickedBy, MessageChannel chann }, ExceptionLogger::capture); } + public void sendKickGuildNotification(User user, String reason, Member moderator) { + sendGuildNotification(moderator.getGuild(), buildKickEmbed(user, moderator, reason)); + } + + public void sendBanGuildNotification(User user, String reason, Member moderator) { + sendGuildNotification(moderator.getGuild(), buildBanEmbed(user, moderator, reason)); + } + + public void sendUnbanGuildNotification(User user, String reason, Member moderator) { + sendGuildNotification(moderator.getGuild(), buildUnbanEmbed(user.getIdLong(), reason, moderator)); + } + + public void sendTimeoutGuildNotification(User user, String reason, Member moderator, Duration duration) { + sendGuildNotification(moderator.getGuild(), buildTimeoutEmbed(user, moderator, reason, duration)); + } + + public void sendRemoveTimeoutGuildNotification(User user, String reason, Member moderator) { + sendGuildNotification(moderator.getGuild(), buildTimeoutRemovedEmbed(user, moderator, reason)); + } + + private void sendGuildNotification(Guild guild, MessageEmbed embed) { + MessageEmbed newEmbed = new EmbedBuilder(embed) + .addField("Source", "This action was executed manually without a bot command.", false) + .build(); + notificationService + .withGuild(guild) + .sendToModerationLog(c -> c.sendMessageEmbeds(newEmbed)); + } + private @NotNull EmbedBuilder buildModerationEmbed(@NotNull User user, @NotNull Member moderator, String reason) { return new EmbedBuilder() .setAuthor(UserUtils.getUserTag(moderator.getUser()), null, moderator.getEffectiveAvatarUrl()) @@ -372,8 +401,8 @@ public void kick(User user, String reason, Member kickedBy, MessageChannel chann .build(); } - private @NotNull MessageEmbed buildTimeoutRemovedEmbed(@NotNull Member member, Member timedOutBy, String reason) { - return buildModerationEmbed(member.getUser(), timedOutBy, reason) + private @NotNull MessageEmbed buildTimeoutRemovedEmbed(@NotNull User user, Member timedOutBy, String reason) { + return buildModerationEmbed(user, timedOutBy, reason) .setTitle("Timeout Removed") .setColor(Responses.Type.SUCCESS.getColor()) .build();