From 6dc68159dffb86524ab3399649fece2c9600b9fc Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Sun, 4 Oct 2026 12:47:24 +0200 Subject: [PATCH] feat: bot core and moderation logging updates --- src/core/bot.rs | 10 ++++------ src/feature/moderation/logging.rs | 30 ++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/core/bot.rs b/src/core/bot.rs index fc0a917..962d6cc 100644 --- a/src/core/bot.rs +++ b/src/core/bot.rs @@ -91,14 +91,12 @@ impl EventHandler for Handler { &self, ctx: Context, _old: Option, - new: Option, + _new: Option, event: serenity::all::MessageUpdateEvent, ) { - if let Some(msg) = new { - if msg.author.bot { - return; - } - } + // All guards (real-edit only, bot/webhook authors, #mod-logs itself) + // live in moderation::logging - serenity message cache is off, so the + // `new` argument is always None and cannot be used for bot filtering. crate::feature::moderation::logging::on_message_edit(&ctx, &event).await; } diff --git a/src/feature/moderation/logging.rs b/src/feature/moderation/logging.rs index 0e2810b..f31ea8e 100644 --- a/src/feature/moderation/logging.rs +++ b/src/feature/moderation/logging.rs @@ -25,19 +25,37 @@ pub async fn on_member_leave( let _ = MOD_LOGS.send_message(&ctx.http, CreateMessage::new().embed(embed)).await; } +/// Guards against non-edits: Discord sends `MESSAGE_UPDATE` with +/// `edited_timestamp = null` ~1s after `MESSAGE_CREATE` for embed-only +/// messages. Logging that would post a new embed, which gets its own spurious +/// update → infinite self-sustaining loop in #mod-logs. pub async fn on_message_edit(ctx: &Context, event: &MessageUpdateEvent) { + if event.edited_timestamp.is_none() { + return; + } + // Never log #mod-logs itself (feedback guard). + if event.channel_id == MOD_LOGS { + return; + } + // Author lives in the event payload: serenity message cache is off + // (`max_messages = 0`), so the `new: Option` bot filter never fires. + // Webhooks report `bot = true` too (GitHub integrations update themselves). + let Some(author) = event.author.as_ref() else { return }; + if author.bot { + return; + } let Some(content) = event.content.clone() else { return }; if content.len() > 1000 { return; } + let body = if content.is_empty() { + "*content cleared*".to_string() + } else { + format!("```{}```", content.chars().take(900).collect::()) + }; let embed = CreateEmbed::new() .title("Message edited") - .description(format!( - "<#{}> by <@{}>\n```{}```", - event.channel_id, - event.author.as_ref().map(|a| a.id.to_string()).unwrap_or_default(), - content.chars().take(900).collect::() - )) + .description(format!("<#{}> by <@{}>\n{}", event.channel_id, author.id, body)) .color(0x00FAA81A); let _ = MOD_LOGS.send_message(&ctx.http, CreateMessage::new().embed(embed)).await; }