mirror of
https://github.com/arthur-pbty/shadowbot.git
synced 2026-06-13 08:10:20 +02:00
Refactor profile commands to improve status handling and embed responses
- Updated `handle_idle`, `handle_invisible`, `handle_online`, `handle_listen`, `handle_playto`, `handle_stream`, `handle_watch`, and `handle_remove_activity` functions to use a unified approach for setting bot status and sending embed messages. - Removed dependency on `botconfig_common` and replaced it with direct database interactions for status management. - Added new helper functions for logging and moderation channel management. - Introduced permission handling improvements in `set` command with better error messages and user feedback. - Created new utility functions for parsing user and role IDs, ensuring better command access control.
This commit is contained in:
@@ -1,63 +1,17 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use chrono::Utc;
|
||||
use serenity::builder::{CreateChannel, CreateEmbed};
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{parse_channel_id, send_embed, theme_color};
|
||||
use crate::db::DbPoolKey;
|
||||
|
||||
const LOG_TYPES: &[(&str, &str)] = &[
|
||||
("moderation", "modlog"),
|
||||
("message", "messagelog"),
|
||||
("voice", "voicelog"),
|
||||
("boost", "boostlog"),
|
||||
("role", "rolelog"),
|
||||
("raid", "raidlog"),
|
||||
("channel", "channellog"),
|
||||
];
|
||||
|
||||
async fn pool(ctx: &Context) -> Option<sqlx::PgPool> {
|
||||
let data = ctx.data.read().await;
|
||||
data.get::<DbPoolKey>().cloned()
|
||||
}
|
||||
|
||||
fn parse_target_channel(msg: &Message, args: &[&str], idx: usize) -> Option<ChannelId> {
|
||||
args.get(idx)
|
||||
.and_then(|raw| parse_channel_id(raw))
|
||||
.or(Some(msg.channel_id))
|
||||
}
|
||||
|
||||
async fn set_log_channel(
|
||||
ctx: &Context,
|
||||
guild_id: GuildId,
|
||||
log_type: &str,
|
||||
channel_id: Option<ChannelId>,
|
||||
enabled: bool,
|
||||
) {
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO bot_log_channels (bot_id, guild_id, log_type, channel_id, enabled)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (bot_id, guild_id, log_type)
|
||||
DO UPDATE SET channel_id = EXCLUDED.channel_id, enabled = EXCLUDED.enabled, updated_at = NOW();
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(log_type)
|
||||
.bind(channel_id.map(|c| c.get() as i64))
|
||||
.bind(enabled)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn get_log_channel(ctx: &Context, guild_id: GuildId, log_type: &str) -> Option<ChannelId> {
|
||||
let pool = pool(ctx).await?;
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
@@ -160,348 +114,6 @@ pub async fn emit_log(
|
||||
send_log_embed(ctx, guild_id, log_type, embed).await;
|
||||
}
|
||||
|
||||
pub async fn handle_log_toggle(
|
||||
ctx: &Context,
|
||||
msg: &Message,
|
||||
args: &[&str],
|
||||
log_type: &str,
|
||||
label: &str,
|
||||
) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(action) = args.first().map(|s| s.to_lowercase()) else {
|
||||
let embed = CreateEmbed::new()
|
||||
.title(label)
|
||||
.description(format!("Usage: +{} <on [salon]|off>", label.to_lowercase()))
|
||||
.color(0xED4245);
|
||||
send_embed(ctx, msg, embed).await;
|
||||
return;
|
||||
};
|
||||
|
||||
match action.as_str() {
|
||||
"on" => {
|
||||
let channel = parse_target_channel(msg, args, 1);
|
||||
set_log_channel(ctx, guild_id, log_type, channel, true).await;
|
||||
let embed = CreateEmbed::new()
|
||||
.title(label)
|
||||
.description(format!(
|
||||
"Activé dans {}.",
|
||||
channel
|
||||
.map(|c| format!("<#{}>", c.get()))
|
||||
.unwrap_or_else(|| "ce salon".to_string())
|
||||
))
|
||||
.color(theme_color(ctx).await);
|
||||
send_embed(ctx, msg, embed).await;
|
||||
}
|
||||
"off" => {
|
||||
set_log_channel(ctx, guild_id, log_type, None, false).await;
|
||||
let embed = CreateEmbed::new()
|
||||
.title(label)
|
||||
.description("Désactivé.")
|
||||
.color(theme_color(ctx).await);
|
||||
send_embed(ctx, msg, embed).await;
|
||||
}
|
||||
_ => {
|
||||
let embed = CreateEmbed::new()
|
||||
.title(label)
|
||||
.description(format!("Usage: +{} <on [salon]|off>", label.to_lowercase()))
|
||||
.color(0xED4245);
|
||||
send_embed(ctx, msg, embed).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_raidlog(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
if args
|
||||
.first()
|
||||
.map(|a| a.eq_ignore_ascii_case("off"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
set_log_channel(ctx, guild_id, "raid", None, false).await;
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("RaidLog")
|
||||
.description("Désactivé.")
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
let channel = parse_target_channel(msg, args, 0);
|
||||
set_log_channel(ctx, guild_id, "raid", channel, true).await;
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("RaidLog")
|
||||
.description(format!(
|
||||
"Activé dans {}.",
|
||||
channel
|
||||
.map(|c| format!("<#{}>", c.get()))
|
||||
.unwrap_or_else(|| "ce salon".to_string())
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn handle_autoconfiglog(ctx: &Context, msg: &Message) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut created = Vec::new();
|
||||
for (log_type, cmd) in LOG_TYPES {
|
||||
let name = format!("{}-logs", cmd.replace("log", ""));
|
||||
if let Ok(channel) = guild_id
|
||||
.create_channel(&ctx.http, CreateChannel::new(name).kind(ChannelType::Text))
|
||||
.await
|
||||
{
|
||||
set_log_channel(ctx, guild_id, log_type, Some(channel.id), true).await;
|
||||
created.push(format!("{} -> <#{}>", log_type, channel.id.get()));
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("AutoConfigLog")
|
||||
.description(if created.is_empty() {
|
||||
"Aucun salon créé.".to_string()
|
||||
} else {
|
||||
created.join("\n")
|
||||
})
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn handle_set_modlogs(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
let row = sqlx::query_as::<_, (String,)>(
|
||||
r#"
|
||||
SELECT modlog_events
|
||||
FROM bot_log_settings
|
||||
WHERE bot_id = $1 AND guild_id = $2
|
||||
LIMIT 1;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.fetch_optional(&pool)
|
||||
.await
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
let mut events = row
|
||||
.map(|(s,)| {
|
||||
s.split(',')
|
||||
.map(|v| v.trim().to_lowercase())
|
||||
.filter(|v| !v.is_empty())
|
||||
.collect::<BTreeSet<_>>()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
[
|
||||
"warn",
|
||||
"mute",
|
||||
"tempmute",
|
||||
"unmute",
|
||||
"cmute",
|
||||
"tempcmute",
|
||||
"uncmute",
|
||||
"kick",
|
||||
"ban",
|
||||
"tempban",
|
||||
"unban",
|
||||
"lock",
|
||||
"unlock",
|
||||
"hide",
|
||||
"unhide",
|
||||
"addrole",
|
||||
"delrole",
|
||||
"derank",
|
||||
"clear",
|
||||
"sanctions",
|
||||
]
|
||||
.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
});
|
||||
|
||||
if args.len() >= 2 {
|
||||
let event = args[0].to_lowercase();
|
||||
let state = args[1].to_lowercase();
|
||||
if state == "on" {
|
||||
events.insert(event);
|
||||
} else if state == "off" {
|
||||
events.remove(&event);
|
||||
}
|
||||
|
||||
let serialized = events.iter().cloned().collect::<Vec<_>>().join(",");
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO bot_log_settings (bot_id, guild_id, modlog_events)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (bot_id, guild_id)
|
||||
DO UPDATE SET modlog_events = EXCLUDED.modlog_events, updated_at = NOW();
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(serialized)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Set ModLogs")
|
||||
.description(format!(
|
||||
"Événements actifs:\n{}\n\nUsage: +set modlogs <event> <on/off>",
|
||||
events.iter().cloned().collect::<Vec<_>>().join(", ")
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn handle_join_leave_settings(ctx: &Context, msg: &Message, args: &[&str], kind: &str) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
if args.is_empty() || !args[0].eq_ignore_ascii_case("settings") {
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title(format!("{} settings", kind))
|
||||
.description(format!(
|
||||
"Usage: +{} settings [on/off] [salon] [message...]",
|
||||
kind
|
||||
))
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() == 1 {
|
||||
let row = sqlx::query_as::<_, (bool, Option<i64>, Option<String>)>(
|
||||
r#"
|
||||
SELECT enabled, channel_id, custom_message
|
||||
FROM bot_join_leave_settings
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND kind = $3
|
||||
LIMIT 1;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(kind)
|
||||
.fetch_optional(&pool)
|
||||
.await
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
let desc = if let Some((enabled, channel_id, custom_message)) = row {
|
||||
format!(
|
||||
"État: {}\nSalon: {}\nMessage: {}",
|
||||
if enabled { "on" } else { "off" },
|
||||
channel_id
|
||||
.map(|id| format!("<#{}>", id))
|
||||
.unwrap_or_else(|| "non défini".to_string()),
|
||||
custom_message.unwrap_or_else(|| "(défaut)".to_string())
|
||||
)
|
||||
} else {
|
||||
"Aucun réglage configuré.".to_string()
|
||||
};
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title(format!("{} settings", kind))
|
||||
.description(desc)
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
let action = args[1].to_lowercase();
|
||||
let enabled = action == "on";
|
||||
let channel = if enabled {
|
||||
parse_target_channel(msg, args, 2)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let message_start = if enabled { 3 } else { 2 };
|
||||
let custom_message = if args.len() > message_start {
|
||||
Some(args[message_start..].join(" "))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO bot_join_leave_settings (bot_id, guild_id, kind, enabled, channel_id, custom_message)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (bot_id, guild_id, kind)
|
||||
DO UPDATE SET enabled = EXCLUDED.enabled, channel_id = EXCLUDED.channel_id,
|
||||
custom_message = EXCLUDED.custom_message, updated_at = NOW();
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(kind)
|
||||
.bind(enabled)
|
||||
.bind(channel.map(|c| c.get() as i64))
|
||||
.bind(custom_message)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title(format!("{} settings", kind))
|
||||
.description(format!(
|
||||
"{} {}",
|
||||
if enabled { "Activé" } else { "Désactivé" },
|
||||
channel
|
||||
.map(|c| format!("dans <#{}>", c.get()))
|
||||
.unwrap_or_default()
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn on_member_join(ctx: &Context, guild_id: GuildId, user: &User) {
|
||||
if let Some(channel_id) = get_log_channel(ctx, guild_id, "raid").await {
|
||||
let _ = channel_id
|
||||
@@ -569,94 +181,6 @@ async fn run_join_leave_action(ctx: &Context, guild_id: GuildId, kind: &str, use
|
||||
let _ = channel_id.say(&ctx.http, content).await;
|
||||
}
|
||||
|
||||
pub async fn handle_set_boostembed(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.len() < 2 {
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Set BoostEmbed")
|
||||
.description("Usage: +set boostembed <title|description|color> <valeur>")
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
let field = args[0].to_lowercase();
|
||||
let value = args[1..].join(" ");
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO bot_boost_embed (bot_id, guild_id, enabled, title, description, color)
|
||||
VALUES ($1, $2, TRUE, NULL, NULL, NULL)
|
||||
ON CONFLICT (bot_id, guild_id)
|
||||
DO NOTHING;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
|
||||
match field.as_str() {
|
||||
"title" => {
|
||||
let _ = sqlx::query(
|
||||
"UPDATE bot_boost_embed SET title = $3, updated_at = NOW() WHERE bot_id = $1 AND guild_id = $2",
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(value)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
"description" => {
|
||||
let _ = sqlx::query(
|
||||
"UPDATE bot_boost_embed SET description = $3, updated_at = NOW() WHERE bot_id = $1 AND guild_id = $2",
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(value)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
"color" => {
|
||||
let normalized = value
|
||||
.trim()
|
||||
.trim_start_matches('#')
|
||||
.trim_start_matches("0x");
|
||||
if let Ok(color) = u32::from_str_radix(normalized, 16) {
|
||||
let _ = sqlx::query(
|
||||
"UPDATE bot_boost_embed SET color = $3, updated_at = NOW() WHERE bot_id = $1 AND guild_id = $2",
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(color as i32)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Set BoostEmbed")
|
||||
.description("Configuration mise à jour.")
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn send_boost_embed(ctx: &Context, guild_id: GuildId, user: &User) {
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
@@ -705,104 +229,6 @@ pub async fn send_boost_embed(ctx: &Context, guild_id: GuildId, user: &User) {
|
||||
send_log_embed(ctx, guild_id, "boost", embed).await;
|
||||
}
|
||||
|
||||
pub async fn handle_nolog(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("NoLog")
|
||||
.description("Usage: +nolog <add/del> [salon] [message|voice|all]")
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
let action = args[0].to_lowercase();
|
||||
let channel = parse_target_channel(msg, args, 1).unwrap_or(msg.channel_id);
|
||||
let scope = args
|
||||
.get(2)
|
||||
.map(|s| s.to_lowercase())
|
||||
.unwrap_or_else(|| "all".to_string());
|
||||
|
||||
let set_message = scope == "all" || scope == "message";
|
||||
let set_voice = scope == "all" || scope == "voice";
|
||||
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
if action == "add" {
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO bot_nolog_channels (bot_id, guild_id, channel_id, disable_message, disable_voice)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (bot_id, guild_id, channel_id)
|
||||
DO UPDATE SET disable_message = bot_nolog_channels.disable_message OR EXCLUDED.disable_message,
|
||||
disable_voice = bot_nolog_channels.disable_voice OR EXCLUDED.disable_voice,
|
||||
updated_at = NOW();
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(channel.get() as i64)
|
||||
.bind(set_message)
|
||||
.bind(set_voice)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
} else if action == "del" {
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
UPDATE bot_nolog_channels
|
||||
SET disable_message = CASE WHEN $4 THEN FALSE ELSE disable_message END,
|
||||
disable_voice = CASE WHEN $5 THEN FALSE ELSE disable_voice END,
|
||||
updated_at = NOW()
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND channel_id = $3;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(channel.get() as i64)
|
||||
.bind(set_message)
|
||||
.bind(set_voice)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM bot_nolog_channels
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND channel_id = $3
|
||||
AND disable_message = FALSE AND disable_voice = FALSE;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(channel.get() as i64)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("NoLog")
|
||||
.description(format!(
|
||||
"{} appliqué sur <#{}> ({})",
|
||||
action,
|
||||
channel.get(),
|
||||
scope
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn on_message_deleted(
|
||||
ctx: &Context,
|
||||
guild_id: Option<GuildId>,
|
||||
|
||||
Reference in New Issue
Block a user