fix: rewrite ModerationLogger with proper audit-log correlation
- Fix onMessageDelete: search audit log for entry matching message ID instead of blindly taking l.get(0) (was showing random moderator) - Increase audit log fetch limit from 1 to 5 for better matching - Fix onMessageBulkDelete: same approach - Unify all handlers to use findEntry() for target-matching - Remove unused handle() helper, simplify send() logic
This commit is contained in:
parent
7cc21213b1
commit
43735de681
1 changed files with 106 additions and 92 deletions
|
|
@ -33,142 +33,156 @@ public class ModerationLogger extends ListenerAdapter {
|
|||
this.messageCache = messageCache;
|
||||
}
|
||||
|
||||
private void handle(
|
||||
final Guild g,
|
||||
final ActionType t,
|
||||
final int l,
|
||||
final Function<List<AuditLogEntry>, EmbedBuilder> fn) {
|
||||
var log = g.getTextChannelById(configRepo.get("moderation.log_channel_id"));
|
||||
if (log == null) {
|
||||
return;
|
||||
private void send(final Guild g, final EmbedBuilder eb) {
|
||||
if (eb == null) return;
|
||||
var ch = g.getTextChannelById(configRepo.get("moderation.log_channel_id"));
|
||||
if (ch == null) return;
|
||||
ch.sendMessageEmbeds(eb.setTimestamp(OffsetDateTime.now()).build()).queue();
|
||||
}
|
||||
var al = g.retrieveAuditLogs().type(t).limit(l);
|
||||
al.queue(
|
||||
|
||||
// ── Message delete ──────────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void onMessageDelete(MessageDeleteEvent e) {
|
||||
var content = messageCache.getContent(e.getMessageId());
|
||||
var g = e.getGuild();
|
||||
g.retrieveAuditLogs().type(ActionType.MESSAGE_DELETE).limit(5).queue(
|
||||
logs -> {
|
||||
var embed = fn.apply(logs);
|
||||
if (embed == null) {
|
||||
return;
|
||||
}
|
||||
log.sendMessageEmbeds(embed.setTimestamp(OffsetDateTime.now()).build()).queue();
|
||||
var entry = logs.stream()
|
||||
.filter(log -> e.getMessageId().equals(log.getTargetId()))
|
||||
.findFirst().orElse(null);
|
||||
send(g, LogEmbeds.messageDelete(entry, e.getChannel().getAsMention(), content));
|
||||
});
|
||||
}
|
||||
|
||||
public void onMessageDelete(MessageDeleteEvent e) {
|
||||
var content = messageCache.getContent(e.getMessageId());
|
||||
handle(e.getGuild(), ActionType.MESSAGE_DELETE, 1, l -> md(e, content, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder md(MessageDeleteEvent e, final String c, final List<AuditLogEntry> l) {
|
||||
var entry = l.isEmpty() ? null : l.get(0);
|
||||
return LogEmbeds.messageDelete(entry, e.getChannel().getAsMention(), c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageBulkDelete(MessageBulkDeleteEvent e) {
|
||||
handle(e.getGuild(), ActionType.MESSAGE_BULK_DELETE, 1, l -> mbd(e, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder mbd(MessageBulkDeleteEvent e, final List<AuditLogEntry> l) {
|
||||
var entry = l.isEmpty() ? null : l.get(0);
|
||||
var g = e.getGuild();
|
||||
var size = e.getMessageIds().size();
|
||||
return LogEmbeds.messageBulkDelete(entry, e.getChannel().getAsMention(), size);
|
||||
g.retrieveAuditLogs().type(ActionType.MESSAGE_BULK_DELETE).limit(3).queue(
|
||||
logs -> {
|
||||
var entry = logs.stream().findFirst().orElse(null);
|
||||
send(g, LogEmbeds.messageBulkDelete(entry, e.getChannel().getAsMention(), size));
|
||||
});
|
||||
}
|
||||
|
||||
public void onGuildBan(final GuildBanEvent ev) {
|
||||
handle(ev.getGuild(), ActionType.BAN, 1, l -> b(ev, l));
|
||||
// ── Ban / Unban ────────────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void onGuildBan(GuildBanEvent ev) {
|
||||
handle(ev.getGuild(), ActionType.BAN, 5, l -> ban(ev, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder b(final GuildBanEvent ev, final List<AuditLogEntry> l) {
|
||||
if (l.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
var user = ev.getUser();
|
||||
var e = l.get(0);
|
||||
var mod = e.getUser() != null ? e.getUser().getAsMention() : "Неизвестно";
|
||||
var reason = e.getReason() != null ? e.getReason() : "Не указана";
|
||||
return LogEmbeds.ban(user.getAsMention(), mod, reason, user.getAvatarUrl());
|
||||
private EmbedBuilder ban(GuildBanEvent ev, List<AuditLogEntry> l) {
|
||||
var entry = findEntry(l, ev.getUser().getId());
|
||||
if (entry == null) return null;
|
||||
return LogEmbeds.ban(
|
||||
ev.getUser().getAsMention(),
|
||||
mod(entry),
|
||||
entry.getReason(),
|
||||
ev.getUser().getAvatarUrl());
|
||||
}
|
||||
|
||||
public void onGuildUnban(final GuildUnbanEvent ev) {
|
||||
handle(ev.getGuild(), ActionType.UNBAN, 1, l -> ub(ev, l));
|
||||
@Override
|
||||
public void onGuildUnban(GuildUnbanEvent ev) {
|
||||
handle(ev.getGuild(), ActionType.UNBAN, 5, l -> unban(ev, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder ub(final GuildUnbanEvent ev, final List<AuditLogEntry> l) {
|
||||
if (l.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
var user = ev.getUser();
|
||||
var e = l.get(0);
|
||||
var mod = e.getUser() != null ? e.getUser().getAsMention() : "Неизвестно";
|
||||
return LogEmbeds.unban(user.getAsMention(), mod, user.getAvatarUrl());
|
||||
private EmbedBuilder unban(GuildUnbanEvent ev, List<AuditLogEntry> l) {
|
||||
var entry = findEntry(l, ev.getUser().getId());
|
||||
if (entry == null) return null;
|
||||
return LogEmbeds.unban(
|
||||
ev.getUser().getAsMention(),
|
||||
mod(entry),
|
||||
ev.getUser().getAvatarUrl());
|
||||
}
|
||||
|
||||
public void onGuildMemberRemove(final GuildMemberRemoveEvent ev) {
|
||||
handle(ev.getGuild(), ActionType.KICK, 1, l -> k(ev, l));
|
||||
// ── Kick ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void onGuildMemberRemove(GuildMemberRemoveEvent ev) {
|
||||
handle(ev.getGuild(), ActionType.KICK, 5, l -> kick(ev, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder k(final GuildMemberRemoveEvent ev, final List<AuditLogEntry> l) {
|
||||
if (l.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
var e = l.get(0);
|
||||
if (!e.getTargetId().equals(ev.getUser().getId())) {
|
||||
return null;
|
||||
}
|
||||
var mod = e.getUser() != null ? e.getUser().getAsMention() : "Неизвестно";
|
||||
var reason = e.getReason() != null ? e.getReason() : "Не указана";
|
||||
return LogEmbeds.kick(ev.getUser().getAsMention(), mod, reason, ev.getUser().getAvatarUrl());
|
||||
private EmbedBuilder kick(GuildMemberRemoveEvent ev, List<AuditLogEntry> l) {
|
||||
var entry = findEntry(l, ev.getUser().getId());
|
||||
if (entry == null) return null;
|
||||
return LogEmbeds.kick(
|
||||
ev.getUser().getAsMention(),
|
||||
mod(entry),
|
||||
entry.getReason(),
|
||||
ev.getUser().getAvatarUrl());
|
||||
}
|
||||
|
||||
public void onGuildMemberUpdateTimeOut(final GuildMemberUpdateTimeOutEvent e) {
|
||||
// ── Timeout ────────────────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void onGuildMemberUpdateTimeOut(GuildMemberUpdateTimeOutEvent e) {
|
||||
var muted = e.getNewTimeOutEnd() != null;
|
||||
handle(e.getGuild(), ActionType.MEMBER_UPDATE, 5, l -> t(e, muted, l));
|
||||
handle(e.getGuild(), ActionType.MEMBER_UPDATE, 5, l -> timeout(e, muted, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder t(
|
||||
final GuildMemberUpdateTimeOutEvent e, boolean muted, final List<AuditLogEntry> l) {
|
||||
private EmbedBuilder timeout(GuildMemberUpdateTimeOutEvent e, boolean muted, List<AuditLogEntry> l) {
|
||||
var entry = findEntry(l, e.getUser().getId());
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
var mod = entry.getUser() != null ? entry.getUser().getAsMention() : "Неизвестно";
|
||||
var end = muted ? e.getNewTimeOutEnd().toEpochSecond() : null;
|
||||
return LogEmbeds.timeout(e.getUser().getAsMention(), mod, muted, end, entry.getReason());
|
||||
if (entry == null) return null;
|
||||
return LogEmbeds.timeout(
|
||||
e.getUser().getAsMention(),
|
||||
mod(entry),
|
||||
muted,
|
||||
muted ? e.getNewTimeOutEnd().toEpochSecond() : null,
|
||||
entry.getReason());
|
||||
}
|
||||
|
||||
public void onGuildVoiceGuildMute(final GuildVoiceGuildMuteEvent e) {
|
||||
// ── Voice mute / deafen ─────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void onGuildVoiceGuildMute(GuildVoiceGuildMuteEvent e) {
|
||||
var muted = e.isGuildMuted();
|
||||
handle(e.getGuild(), ActionType.MEMBER_UPDATE, 5, l -> vm(e, muted, l));
|
||||
handle(e.getGuild(), ActionType.MEMBER_UPDATE, 5, l -> voiceMute(e, muted, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder vm(
|
||||
final GuildVoiceGuildMuteEvent e, final boolean muted, final List<AuditLogEntry> l) {
|
||||
private EmbedBuilder voiceMute(GuildVoiceGuildMuteEvent e, boolean muted, List<AuditLogEntry> l) {
|
||||
var member = e.getMember();
|
||||
var ch = e.getVoiceState().getChannel();
|
||||
var entry = findEntry(l, member.getId(), "mute");
|
||||
var mod = entry != null && entry.getUser() != null ? entry.getUser().getAsMention() : null;
|
||||
return LogEmbeds.voiceMute(member.getAsMention(), ch.getAsMention(), muted, mod);
|
||||
return LogEmbeds.voiceMute(
|
||||
member.getAsMention(),
|
||||
e.getVoiceState().getChannel().getAsMention(),
|
||||
muted,
|
||||
entry != null ? mod(entry) : null);
|
||||
}
|
||||
|
||||
public void onGuildVoiceGuildDeafen(final GuildVoiceGuildDeafenEvent e) {
|
||||
@Override
|
||||
public void onGuildVoiceGuildDeafen(GuildVoiceGuildDeafenEvent e) {
|
||||
var deaf = e.isGuildDeafened();
|
||||
handle(e.getGuild(), ActionType.MEMBER_UPDATE, 5, l -> vd(e, deaf, l));
|
||||
handle(e.getGuild(), ActionType.MEMBER_UPDATE, 5, l -> voiceDeafen(e, deaf, l));
|
||||
}
|
||||
|
||||
private EmbedBuilder vd(
|
||||
final GuildVoiceGuildDeafenEvent e, final boolean deaf, final List<AuditLogEntry> l) {
|
||||
private EmbedBuilder voiceDeafen(GuildVoiceGuildDeafenEvent e, boolean deaf, List<AuditLogEntry> l) {
|
||||
var member = e.getMember();
|
||||
var ch = e.getVoiceState().getChannel();
|
||||
var entry = findEntry(l, member.getId(), "deaf");
|
||||
var mod = entry != null && entry.getUser() != null ? entry.getUser().getAsMention() : null;
|
||||
return LogEmbeds.voiceDeafen(member.getAsMention(), ch.getAsMention(), deaf, mod);
|
||||
return LogEmbeds.voiceDeafen(
|
||||
member.getAsMention(),
|
||||
e.getVoiceState().getChannel().getAsMention(),
|
||||
deaf,
|
||||
entry != null ? mod(entry) : null);
|
||||
}
|
||||
|
||||
private AuditLogEntry findEntry(
|
||||
final List<AuditLogEntry> l, final String targetId, final String... key) {
|
||||
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
private void handle(Guild g, ActionType t, int limit, Function<List<AuditLogEntry>, EmbedBuilder> fn) {
|
||||
g.retrieveAuditLogs().type(t).limit(limit).queue(
|
||||
logs -> send(g, fn.apply(logs)));
|
||||
}
|
||||
|
||||
private static AuditLogEntry findEntry(List<AuditLogEntry> l, String targetId, String... key) {
|
||||
var s = l.stream().filter(e -> targetId.equals(e.getTargetId()));
|
||||
if (key.length > 0) {
|
||||
s = s.filter(e -> e.getChangeByKey(key[0]) != null);
|
||||
}
|
||||
return s.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
private static String mod(AuditLogEntry e) {
|
||||
return e.getUser() != null ? e.getUser().getAsMention() : "Неизвестно";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue