mirror of
https://github.com/arthur-pbty/shadowbot.git
synced 2026-06-03 23:36:25 +02:00
Ajout de la gestion des canaux de logs et amélioration de l'enregistrement des logs d'audit avec les identifiants de message.
This commit is contained in:
+107
-43
@@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serenity::builder::{CreateActionRow, CreateButton, CreateEmbed, CreateMessage};
|
use serenity::builder::{CreateActionRow, CreateButton, CreateEmbed, CreateMessage};
|
||||||
use serenity::model::application::ButtonStyle;
|
use serenity::model::application::ButtonStyle;
|
||||||
use serenity::model::prelude::*;
|
use serenity::model::prelude::*;
|
||||||
@@ -17,6 +19,101 @@ pub async fn pool(ctx: &Context) -> Option<sqlx::PgPool> {
|
|||||||
data.get::<DbPoolKey>().cloned()
|
data.get::<DbPoolKey>().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn fetch_log_channels(
|
||||||
|
pool: &sqlx::PgPool,
|
||||||
|
bot_id: UserId,
|
||||||
|
guild_id: GuildId,
|
||||||
|
) -> HashMap<String, u64> {
|
||||||
|
let rows = sqlx::query_as::<_, (String, Option<i64>)>(
|
||||||
|
r#"
|
||||||
|
SELECT log_type, channel_id
|
||||||
|
FROM bot_log_channels
|
||||||
|
WHERE bot_id = $1 AND guild_id = $2 AND enabled = TRUE;
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(bot_id.get() as i64)
|
||||||
|
.bind(guild_id.get() as i64)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
rows.into_iter()
|
||||||
|
.filter_map(|(log_type, channel_id)| {
|
||||||
|
channel_id
|
||||||
|
.and_then(|id| u64::try_from(id).ok())
|
||||||
|
.map(|id| (log_type, id))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_log_channel_id(
|
||||||
|
log: &crate::db::AuditLog,
|
||||||
|
channels: &HashMap<String, u64>,
|
||||||
|
) -> Option<u64> {
|
||||||
|
let from_details = log
|
||||||
|
.details
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|details| details.get("log_channel_id"))
|
||||||
|
.and_then(|value| value.as_i64())
|
||||||
|
.and_then(|id| u64::try_from(id).ok());
|
||||||
|
|
||||||
|
from_details.or_else(|| channels.get(&log.log_type).copied())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_log_link(
|
||||||
|
log: &crate::db::AuditLog,
|
||||||
|
guild_id: GuildId,
|
||||||
|
channels: &HashMap<String, u64>,
|
||||||
|
) -> Option<String> {
|
||||||
|
let message_id = log.message_id.and_then(|id| u64::try_from(id).ok())?;
|
||||||
|
let log_channel_id = extract_log_channel_id(log, channels)?;
|
||||||
|
|
||||||
|
Some(format!(
|
||||||
|
"https://discord.com/channels/{}/{}/{}",
|
||||||
|
guild_id.get(),
|
||||||
|
log_channel_id,
|
||||||
|
message_id
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_log_fields(
|
||||||
|
mut embed: CreateEmbed,
|
||||||
|
logs: Vec<crate::db::AuditLog>,
|
||||||
|
guild_id: GuildId,
|
||||||
|
channels: &HashMap<String, u64>,
|
||||||
|
) -> CreateEmbed {
|
||||||
|
for log in logs {
|
||||||
|
let actor = log
|
||||||
|
.user_id
|
||||||
|
.map(|id| format!("<@{}>", id))
|
||||||
|
.unwrap_or_else(|| "Systeme".to_string());
|
||||||
|
|
||||||
|
let target = match (log.channel_id, log.role_id) {
|
||||||
|
(Some(ch_id), _) => format!("<#{}>", ch_id),
|
||||||
|
(_, Some(role_id)) => format!("<@&{}>", role_id),
|
||||||
|
_ => "-".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let link = build_log_link(&log, guild_id, channels)
|
||||||
|
.map(|url| format!("[Voir]({})", url))
|
||||||
|
.unwrap_or_else(|| "indisponible".to_string());
|
||||||
|
|
||||||
|
embed = embed.field(
|
||||||
|
format!("[{}] {}", log.log_type.to_uppercase(), log.action),
|
||||||
|
format!(
|
||||||
|
"Acteur: {}\nQuand: <t:{}:R>\nCible: {}\nLien: {}",
|
||||||
|
actor,
|
||||||
|
log.created_at.timestamp(),
|
||||||
|
target,
|
||||||
|
link
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
embed
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_viewlogs(ctx: &Context, msg: &Message, args: &[&str]) {
|
pub async fn handle_viewlogs(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||||
let Some(guild_id) = msg.guild_id else {
|
let Some(guild_id) = msg.guild_id else {
|
||||||
send_embed(
|
send_embed(
|
||||||
@@ -75,32 +172,14 @@ pub async fn handle_viewlogs(ctx: &Context, msg: &Message, args: &[&str]) {
|
|||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut embed = CreateEmbed::new()
|
let log_channels = fetch_log_channels(&pool, bot_id, guild_id).await;
|
||||||
|
|
||||||
|
let embed = CreateEmbed::new()
|
||||||
.title("Logs d'audit")
|
.title("Logs d'audit")
|
||||||
.description(format!(
|
.description(format!("Page {}/{} • {} logs", page, total_pages, total))
|
||||||
"Page {}/{} ({} logs total)",
|
|
||||||
page, total_pages, total
|
|
||||||
))
|
|
||||||
.color(theme_color(ctx).await);
|
.color(theme_color(ctx).await);
|
||||||
|
|
||||||
for log in logs {
|
let embed = append_log_fields(embed, logs, guild_id, &log_channels);
|
||||||
let user_mention = log
|
|
||||||
.user_id
|
|
||||||
.map(|id| format!("<@{}>", id))
|
|
||||||
.unwrap_or_else(|| "Système".to_string());
|
|
||||||
|
|
||||||
let extra = match (log.channel_id, log.role_id) {
|
|
||||||
(Some(ch_id), _) => format!(" · <#{}>", ch_id),
|
|
||||||
(_, Some(role_id)) => format!(" · <@&{}>", role_id),
|
|
||||||
_ => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
embed = embed.field(
|
|
||||||
format!("[{}] {} {}", &log.log_type, user_mention, log.action),
|
|
||||||
format!("<t:{}:R>{}", log.created_at.timestamp(), extra),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut components = Vec::new();
|
let mut components = Vec::new();
|
||||||
|
|
||||||
@@ -187,32 +266,17 @@ pub async fn handle_viewlogs_button(ctx: &Context, component: &ComponentInteract
|
|||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut embed = CreateEmbed::new()
|
let log_channels = fetch_log_channels(&pool, bot_id, guild_id).await;
|
||||||
|
|
||||||
|
let embed = CreateEmbed::new()
|
||||||
.title("Logs d'audit")
|
.title("Logs d'audit")
|
||||||
.description(format!(
|
.description(format!(
|
||||||
"Page {}/{} ({} logs total)",
|
"Page {}/{} • {} logs",
|
||||||
new_page, total_pages, total
|
new_page, total_pages, total
|
||||||
))
|
))
|
||||||
.color(theme_color(ctx).await);
|
.color(theme_color(ctx).await);
|
||||||
|
|
||||||
for log in logs {
|
let embed = append_log_fields(embed, logs, guild_id, &log_channels);
|
||||||
let user_mention = log
|
|
||||||
.user_id
|
|
||||||
.map(|id| format!("<@{}>", id))
|
|
||||||
.unwrap_or_else(|| "Système".to_string());
|
|
||||||
|
|
||||||
let extra = match (log.channel_id, log.role_id) {
|
|
||||||
(Some(ch_id), _) => format!(" · <#{}>", ch_id),
|
|
||||||
(_, Some(role_id)) => format!(" · <@&{}>", role_id),
|
|
||||||
_ => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
embed = embed.field(
|
|
||||||
format!("[{}] {} {}", &log.log_type, user_mention, log.action),
|
|
||||||
format!("<t:{}:R>{}", log.created_at.timestamp(), extra),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut components = Vec::new();
|
let mut components = Vec::new();
|
||||||
if total_pages > 1 {
|
if total_pages > 1 {
|
||||||
|
|||||||
+45
-10
@@ -1,6 +1,7 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use serde_json::json;
|
||||||
use serenity::builder::{CreateEmbed, CreateEmbedFooter};
|
use serenity::builder::{CreateEmbed, CreateEmbedFooter};
|
||||||
use serenity::model::prelude::*;
|
use serenity::model::prelude::*;
|
||||||
use serenity::prelude::*;
|
use serenity::prelude::*;
|
||||||
@@ -85,7 +86,9 @@ async fn record_audit_log(
|
|||||||
user_id: Option<UserId>,
|
user_id: Option<UserId>,
|
||||||
channel_id: Option<ChannelId>,
|
channel_id: Option<ChannelId>,
|
||||||
role_id: Option<RoleId>,
|
role_id: Option<RoleId>,
|
||||||
|
message_id: Option<MessageId>,
|
||||||
action: &str,
|
action: &str,
|
||||||
|
details: Option<sqlx::types::JsonValue>,
|
||||||
) {
|
) {
|
||||||
let Some(pool) = pool(ctx).await else {
|
let Some(pool) = pool(ctx).await else {
|
||||||
return;
|
return;
|
||||||
@@ -93,11 +96,16 @@ async fn record_audit_log(
|
|||||||
|
|
||||||
let bot_id = ctx.cache.current_user().id;
|
let bot_id = ctx.cache.current_user().id;
|
||||||
let _ = crate::db::insert_audit_log(
|
let _ = crate::db::insert_audit_log(
|
||||||
&pool, bot_id, guild_id, log_type, user_id, channel_id, role_id, None, action, None,
|
&pool, bot_id, guild_id, log_type, user_id, channel_id, role_id, message_id, action,
|
||||||
|
details,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_audit_details(log_channel_id: Option<ChannelId>) -> Option<sqlx::types::JsonValue> {
|
||||||
|
log_channel_id.map(|id| json!({ "log_channel_id": id.get() as i64 }))
|
||||||
|
}
|
||||||
|
|
||||||
fn color_for_log_type(log_type: &str) -> u32 {
|
fn color_for_log_type(log_type: &str) -> u32 {
|
||||||
match log_type {
|
match log_type {
|
||||||
"message" => 0xF4C430,
|
"message" => 0xF4C430,
|
||||||
@@ -199,9 +207,8 @@ fn enrich_log_embed(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_log_embed(ctx: &Context, guild_id: GuildId, log_type: &str, embed: CreateEmbed) {
|
pub async fn send_log_embed(ctx: &Context, guild_id: GuildId, log_type: &str, embed: CreateEmbed) {
|
||||||
record_audit_log(ctx, guild_id, log_type, None, None, None, log_type).await;
|
|
||||||
|
|
||||||
let log_channel_id = get_log_channel(ctx, guild_id, log_type).await;
|
let log_channel_id = get_log_channel(ctx, guild_id, log_type).await;
|
||||||
|
let mut sent_log_message_id = None;
|
||||||
|
|
||||||
if let Some(channel_id) = log_channel_id {
|
if let Some(channel_id) = log_channel_id {
|
||||||
let embed = enrich_log_embed(
|
let embed = enrich_log_embed(
|
||||||
@@ -216,13 +223,28 @@ pub async fn send_log_embed(ctx: &Context, guild_id: GuildId, log_type: &str, em
|
|||||||
embed,
|
embed,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = channel_id
|
let sent = channel_id
|
||||||
.send_message(
|
.send_message(
|
||||||
&ctx.http,
|
&ctx.http,
|
||||||
serenity::builder::CreateMessage::new().embed(embed),
|
serenity::builder::CreateMessage::new().embed(embed),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
sent_log_message_id = sent.ok().map(|message| message.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record_audit_log(
|
||||||
|
ctx,
|
||||||
|
guild_id,
|
||||||
|
log_type,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
sent_log_message_id,
|
||||||
|
log_type,
|
||||||
|
build_audit_details(log_channel_id),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn emit_log(
|
pub async fn emit_log(
|
||||||
@@ -235,12 +257,10 @@ pub async fn emit_log(
|
|||||||
action: &str,
|
action: &str,
|
||||||
embed: CreateEmbed,
|
embed: CreateEmbed,
|
||||||
) {
|
) {
|
||||||
record_audit_log(
|
let log_channel_id = get_log_channel(ctx, guild_id, log_type).await;
|
||||||
ctx, guild_id, log_type, user_id, channel_id, role_id, action,
|
let mut sent_log_message_id = None;
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let Some(log_channel_id) = get_log_channel(ctx, guild_id, log_type).await {
|
if let Some(log_channel_id) = log_channel_id {
|
||||||
let embed = enrich_log_embed(
|
let embed = enrich_log_embed(
|
||||||
ctx,
|
ctx,
|
||||||
guild_id,
|
guild_id,
|
||||||
@@ -253,13 +273,28 @@ pub async fn emit_log(
|
|||||||
embed,
|
embed,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = log_channel_id
|
let sent = log_channel_id
|
||||||
.send_message(
|
.send_message(
|
||||||
&ctx.http,
|
&ctx.http,
|
||||||
serenity::builder::CreateMessage::new().embed(embed),
|
serenity::builder::CreateMessage::new().embed(embed),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
sent_log_message_id = sent.ok().map(|message| message.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record_audit_log(
|
||||||
|
ctx,
|
||||||
|
guild_id,
|
||||||
|
log_type,
|
||||||
|
user_id,
|
||||||
|
channel_id,
|
||||||
|
role_id,
|
||||||
|
sent_log_message_id,
|
||||||
|
action,
|
||||||
|
build_audit_details(log_channel_id),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn on_member_join(ctx: &Context, guild_id: GuildId, user: &User) {
|
pub async fn on_member_join(ctx: &Context, guild_id: GuildId, user: &User) {
|
||||||
|
|||||||
Reference in New Issue
Block a user