From 9a47588cdfff0386c3ab2eb203c28e81076f8860 Mon Sep 17 00:00:00 2001 From: Puechberty Arthur Date: Fri, 10 Apr 2026 16:41:03 +0200 Subject: [PATCH] netoyage des commands --- src/commands/advanced_tools.rs | 2 +- src/commands/automod_service.rs | 2 +- src/commands/botconfig/remove_activity.rs | 2 +- src/commands/botconfig/removeactivity.rs | 47 ++ src/commands/botconfig/set.rs | 2 +- src/commands/channel/tempvoc.rs | 2 +- src/commands/channel/tempvoc_cmd.rs | 4 +- src/commands/channel/tempvoccmd.rs | 35 ++ src/commands/config/leave_settings.rs | 6 +- src/commands/config/leavesettings.rs | 142 +++++ src/commands/config/set_boostembed.rs | 6 +- src/commands/config/set_modlogs.rs | 4 +- src/commands/config/setboostembed.rs | 115 ++++ src/commands/config/setmodlogs.rs | 125 ++++ src/commands/event/end.rs | 4 +- src/commands/info/server.rs | 4 +- src/commands/info/showpics.rs | 2 +- src/commands/mod.rs | 40 +- src/commands/mod/clear_all_sanctions.rs | 2 +- src/commands/mod/clear_badwords.rs | 2 +- src/commands/mod/clear_limit.rs | 4 +- src/commands/mod/clear_sanctions.rs | 2 +- src/commands/mod/clearallsanctions.rs | 66 +++ src/commands/mod/clearbadwords.rs | 50 ++ src/commands/mod/clearlimit.rs | 74 +++ .../{clear_messages.rs => clearmessages.rs} | 4 +- src/commands/mod/clearsanctions.rs | 76 +++ src/commands/mod/del_sanction.rs | 2 +- src/commands/mod/delsanction.rs | 98 ++++ src/commands/mod/set_muterole.rs | 4 +- src/commands/mod/setmuterole.rs | 79 +++ src/commands/owner/clear_bl.rs | 2 +- src/commands/owner/clear_owners.rs | 2 +- src/commands/owner/clearbl.rs | 52 ++ src/commands/owner/clearowners.rs | 52 ++ src/commands/owner/mp.rs | 10 +- src/commands/perms/alias.rs | 7 +- src/commands/perms/clear_perms.rs | 2 +- src/commands/perms/clearperms.rs | 48 ++ src/commands/perms/del.rs | 2 +- src/commands/perms/help.rs | 122 ++-- src/commands/perms_helpers.rs | 24 +- .../{ticket_member.rs => ticketmember.rs} | 0 src/events/message_event.rs | 212 +++---- src/permissions.rs | 549 +++--------------- 45 files changed, 1381 insertions(+), 710 deletions(-) create mode 100644 src/commands/botconfig/removeactivity.rs create mode 100644 src/commands/channel/tempvoccmd.rs create mode 100644 src/commands/config/leavesettings.rs create mode 100644 src/commands/config/setboostembed.rs create mode 100644 src/commands/config/setmodlogs.rs create mode 100644 src/commands/mod/clearallsanctions.rs create mode 100644 src/commands/mod/clearbadwords.rs create mode 100644 src/commands/mod/clearlimit.rs rename src/commands/mod/{clear_messages.rs => clearmessages.rs} (96%) create mode 100644 src/commands/mod/clearsanctions.rs create mode 100644 src/commands/mod/delsanction.rs create mode 100644 src/commands/mod/setmuterole.rs create mode 100644 src/commands/owner/clearbl.rs create mode 100644 src/commands/owner/clearowners.rs create mode 100644 src/commands/perms/clearperms.rs rename src/commands/ticket/{ticket_member.rs => ticketmember.rs} (100%) diff --git a/src/commands/advanced_tools.rs b/src/commands/advanced_tools.rs index d5c716f..05850e8 100644 --- a/src/commands/advanced_tools.rs +++ b/src/commands/advanced_tools.rs @@ -1177,7 +1177,7 @@ pub async fn handle_modal_interaction(ctx: &Context, modal: &ModalInteraction) - )) .color(theme_color(ctx).await) .footer(CreateEmbedFooter::new( - "Utilise +end giveaway pour terminer", + "Utilise +endgiveaway pour terminer", )); let _ = modal diff --git a/src/commands/automod_service.rs b/src/commands/automod_service.rs index 22b3c34..f231fed 100644 --- a/src/commands/automod_service.rs +++ b/src/commands/automod_service.rs @@ -594,7 +594,7 @@ pub async fn public_command_allowed( .title("Commandes publiques desactivees") .description(format!( "La commande `{}` est desactivee dans ce salon.", - command_key.replace('_', " ") + command_key.replace('_', "") )) .color(0xED4245); send_embed(ctx, msg, embed).await; diff --git a/src/commands/botconfig/remove_activity.rs b/src/commands/botconfig/remove_activity.rs index 23e6676..6e27407 100644 --- a/src/commands/botconfig/remove_activity.rs +++ b/src/commands/botconfig/remove_activity.rs @@ -38,7 +38,7 @@ impl crate::commands::command_contract::CommandSpec for RemoveActivityCommand { category: "botconfig", params: "aucun", description: "Arrete la rotation d activite et retire lactivite courante du bot.", - examples: &["+remove activity", "+ry", "+help remove activity"], + examples: &["+removeactivity", "+ry", "+help removeactivity"], default_aliases: &["rma"], allow_in_dm: false, default_permission: 7, diff --git a/src/commands/botconfig/removeactivity.rs b/src/commands/botconfig/removeactivity.rs new file mode 100644 index 0000000..e2082ca --- /dev/null +++ b/src/commands/botconfig/removeactivity.rs @@ -0,0 +1,47 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::activity::stop_rotation; +use crate::commands::common::send_embed; +use crate::db::DbPoolKey; + +pub async fn handle_remove_activity(ctx: &Context, msg: &Message) { + stop_rotation(ctx).await; + ctx.set_activity(None); + + let bot_id = ctx.cache.current_user().id; + let pool = { + let data = ctx.data.read().await; + data.get::().cloned() + }; + + if let Some(pool) = pool { + let _ = crate::db::clear_bot_activity(&pool, bot_id).await; + } + + let embed = CreateEmbed::new() + .title("Activité supprimée") + .description("L'activité du bot a été retirée.") + .color(0x57F287); + + send_embed(ctx, msg, embed).await; +} + +pub struct RemoveActivityCommand; +pub static COMMAND_DESCRIPTOR: RemoveActivityCommand = RemoveActivityCommand; + +impl crate::commands::command_contract::CommandSpec for RemoveActivityCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "removeactivity", + category: "botconfig", + params: "aucun", + description: "Arrete la rotation d activite et retire lactivite courante du bot.", + examples: &["+removeactivity", "+ry", "+help removeactivity"], + default_aliases: &["rma"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/botconfig/set.rs b/src/commands/botconfig/set.rs index 19c628c..6f1fe6a 100644 --- a/src/commands/botconfig/set.rs +++ b/src/commands/botconfig/set.rs @@ -16,7 +16,7 @@ async fn handle_set_perm(ctx: &Context, msg: &Message, args: &[&str]) { if args.len() < 3 || !args[0].eq_ignore_ascii_case("perm") { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `set perm `") + .description("Usage: `+setperm `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; diff --git a/src/commands/channel/tempvoc.rs b/src/commands/channel/tempvoc.rs index 1cf5f41..bcc7b23 100644 --- a/src/commands/channel/tempvoc.rs +++ b/src/commands/channel/tempvoc.rs @@ -1507,7 +1507,7 @@ impl crate::commands::command_contract::CommandSpec for TempvocCommand { category: "channel", params: "[cmd]", description: "Affiche le menu de configuration du systeme de vocaux temporaires.", - examples: &["+tempvoc", "+tempvoc cmd", "+help tempvoc"], + examples: &["+tempvoc", "+tempvoccmd", "+help tempvoc"], default_aliases: &[], allow_in_dm: false, default_permission: 5, diff --git a/src/commands/channel/tempvoc_cmd.rs b/src/commands/channel/tempvoc_cmd.rs index 71df690..dd2fb82 100644 --- a/src/commands/channel/tempvoc_cmd.rs +++ b/src/commands/channel/tempvoc_cmd.rs @@ -9,7 +9,7 @@ use crate::commands::common::send_embed; pub async fn handle_tempvoc_cmd(ctx: &Context, msg: &Message, _args: &[&str]) { let embed = CreateEmbed::new() .title("Commandes Tempvoc") - .description("\n+tempvoc\n+tempvoc cmd\n\nLe salon de création est surveillé automatiquement: lorsqu'un membre le rejoint, un vocal temporaire est créé et l'utilisateur y est déplacé.") + .description("\n+tempvoc\n+tempvoccmd\n\nLe salon de création est surveillé automatiquement: lorsqu'un membre le rejoint, un vocal temporaire est créé et l'utilisateur y est déplacé.") .colour(Colour::from_rgb(100, 180, 255)) .timestamp(Utc::now()); @@ -26,7 +26,7 @@ impl crate::commands::command_contract::CommandSpec for TempvocCmdCommand { category: "channel", params: "aucun", description: "Affiche un rappel des commandes et du fonctionnement de tempvoc.", - examples: &["+tempvoc cmd", "+help tempvoc_cmd"], + examples: &["+tempvoccmd", "+help tempvoc_cmd"], default_aliases: &[], allow_in_dm: false, default_permission: 0, diff --git a/src/commands/channel/tempvoccmd.rs b/src/commands/channel/tempvoccmd.rs new file mode 100644 index 0000000..2e5f08d --- /dev/null +++ b/src/commands/channel/tempvoccmd.rs @@ -0,0 +1,35 @@ +use chrono::Utc; +use serenity::builder::CreateEmbed; +use serenity::model::Colour; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::send_embed; + +pub async fn handle_tempvoc_cmd(ctx: &Context, msg: &Message, _args: &[&str]) { + let embed = CreateEmbed::new() + .title("Commandes Tempvoc") + .description("\n+tempvoc\n+tempvoccmd\n\nLe salon de création est surveillé automatiquement: lorsqu'un membre le rejoint, un vocal temporaire est créé et l'utilisateur y est déplacé.") + .colour(Colour::from_rgb(100, 180, 255)) + .timestamp(Utc::now()); + + send_embed(ctx, msg, embed).await; +} + +pub struct TempvocCmdCommand; +pub static COMMAND_DESCRIPTOR: TempvocCmdCommand = TempvocCmdCommand; + +impl crate::commands::command_contract::CommandSpec for TempvocCmdCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "tempvoccmd", + category: "channel", + params: "aucun", + description: "Affiche un rappel des commandes et du fonctionnement de tempvoc.", + examples: &["+tempvoccmd", "+help tempvoccmd"], + default_aliases: &[], + allow_in_dm: false, + default_permission: 0, + } + } +} diff --git a/src/commands/config/leave_settings.rs b/src/commands/config/leave_settings.rs index a363aab..df1c1aa 100644 --- a/src/commands/config/leave_settings.rs +++ b/src/commands/config/leave_settings.rs @@ -22,7 +22,7 @@ pub async fn handle_leave_settings(ctx: &Context, msg: &Message, args: &[&str]) msg, CreateEmbed::new() .title("leave settings") - .description("Usage: +leave settings [on/off] [salon] [message...]") + .description("Usage: +leavesettings [on/off] [salon] [message...]") .color(0xED4245), ) .await; @@ -131,8 +131,8 @@ impl crate::commands::command_contract::CommandSpec for LeaveSettingsCommand { params: "settings [on/off] [salon] [message]", description: "Configure les actions a executer quand un membre quitte le serveur.", examples: &[ - "+leave settings", - "+leave settings on #logs {user} a quitte", + "+leavesettings", + "+leavesettings on #logs {user} a quitte", ], default_aliases: &["lset"], allow_in_dm: false, diff --git a/src/commands/config/leavesettings.rs b/src/commands/config/leavesettings.rs new file mode 100644 index 0000000..13e51bc --- /dev/null +++ b/src/commands/config/leavesettings.rs @@ -0,0 +1,142 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +use serenity::builder::CreateEmbed; + +use crate::commands::common::{send_embed, theme_color}; +use crate::commands::logs_command_helpers::{parse_target_channel, pool}; + +pub async fn handle_leave_settings(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; + + if args.is_empty() || !args[0].eq_ignore_ascii_case("settings") { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("leave settings") + .description("Usage: +leavesettings [on/off] [salon] [message...]") + .color(0xED4245), + ) + .await; + return; + } + + if args.len() == 1 { + let row = sqlx::query_as::<_, (bool, Option, Option)>( + 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("leave") + .fetch_optional(&pool) + .await + .ok() + .flatten(); + + let desc = if let Some((enabled, channel_id, custom_message)) = row { + format!( + "Etat: {}\nSalon: {}\nMessage: {}", + if enabled { "on" } else { "off" }, + channel_id + .map(|id| format!("<#{}>", id)) + .unwrap_or_else(|| "non defini".to_string()), + custom_message.unwrap_or_else(|| "(defaut)".to_string()) + ) + } else { + "Aucun reglage configure.".to_string() + }; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("leave settings") + .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("leave") + .bind(enabled) + .bind(channel.map(|c| c.get() as i64)) + .bind(custom_message) + .execute(&pool) + .await; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("leave settings") + .description(format!( + "{} {}", + if enabled { "Active" } else { "Desactive" }, + channel + .map(|c| format!("dans <#{}>", c.get())) + .unwrap_or_default() + )) + .color(theme_color(ctx).await), + ) + .await; +} + +pub struct LeaveSettingsCommand; +pub static COMMAND_DESCRIPTOR: LeaveSettingsCommand = LeaveSettingsCommand; + +impl crate::commands::command_contract::CommandSpec for LeaveSettingsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "leavesettings", + category: "config", + params: "settings [on/off] [salon] [message]", + description: "Configure les actions a executer quand un membre quitte le serveur.", + examples: &[ + "+leavesettings", + "+leavesettings on #logs {user} a quitte", + ], + default_aliases: &["lset"], + allow_in_dm: false, + default_permission: 5, + } + } +} diff --git a/src/commands/config/set_boostembed.rs b/src/commands/config/set_boostembed.rs index 21473aa..3fe8293 100644 --- a/src/commands/config/set_boostembed.rs +++ b/src/commands/config/set_boostembed.rs @@ -15,7 +15,7 @@ pub async fn handle_set_boostembed(ctx: &Context, msg: &Message, args: &[&str]) msg, CreateEmbed::new() .title("Set BoostEmbed") - .description("Usage: +set boostembed ") + .description("Usage: +setboostembed ") .color(0xED4245), ) .await; @@ -104,8 +104,8 @@ impl crate::commands::command_contract::CommandSpec for SetBoostembedCommand { params: " ", description: "Configure le titre, la description et la couleur de l embed boost.", examples: &[ - "+set boostembed title Merci", - "+set boostembed color #FF66CC", + "+setboostembed title Merci", + "+setboostembed color #FF66CC", ], default_aliases: &["sboostembed"], allow_in_dm: false, diff --git a/src/commands/config/set_modlogs.rs b/src/commands/config/set_modlogs.rs index 89adbd8..8b32cfa 100644 --- a/src/commands/config/set_modlogs.rs +++ b/src/commands/config/set_modlogs.rs @@ -98,7 +98,7 @@ pub async fn handle_set_modlogs(ctx: &Context, msg: &Message, args: &[&str]) { CreateEmbed::new() .title("Set ModLogs") .description(format!( - "Evenements actifs:\n{}\n\nUsage: +set modlogs ", + "Evenements actifs:\n{}\n\nUsage: +setmodlogs ", events.iter().cloned().collect::>().join(", ") )) .color(theme_color(ctx).await), @@ -116,7 +116,7 @@ impl crate::commands::command_contract::CommandSpec for SetModlogsCommand { category: "config", params: "[event on/off]", description: "Affiche ou modifie les evenements qui apparaissent dans les logs de moderation.", - examples: &["+set modlogs", "+set modlogs warn off"], + examples: &["+setmodlogs", "+setmodlogs warn off"], default_aliases: &["smodlog"], allow_in_dm: false, default_permission: 6, diff --git a/src/commands/config/setboostembed.rs b/src/commands/config/setboostembed.rs new file mode 100644 index 0000000..8101835 --- /dev/null +++ b/src/commands/config/setboostembed.rs @@ -0,0 +1,115 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::{send_embed, theme_color}; +use crate::commands::logs_command_helpers::pool; + +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: +setboostembed ") + .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 a jour.") + .color(theme_color(ctx).await), + ) + .await; +} + +pub struct SetBoostembedCommand; +pub static COMMAND_DESCRIPTOR: SetBoostembedCommand = SetBoostembedCommand; + +impl crate::commands::command_contract::CommandSpec for SetBoostembedCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setboostembed", + category: "config", + params: " ", + description: "Configure le titre, la description et la couleur de l embed boost.", + examples: &[ + "+setboostembed title Merci", + "+setboostembed color #FF66CC", + ], + default_aliases: &["sboostembed"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/config/setmodlogs.rs b/src/commands/config/setmodlogs.rs new file mode 100644 index 0000000..db9e17f --- /dev/null +++ b/src/commands/config/setmodlogs.rs @@ -0,0 +1,125 @@ +use std::collections::BTreeSet; + +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::{send_embed, theme_color}; +use crate::commands::logs_command_helpers::pool; + +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::>() + }) + .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::>().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!( + "Evenements actifs:\n{}\n\nUsage: +setmodlogs ", + events.iter().cloned().collect::>().join(", ") + )) + .color(theme_color(ctx).await), + ) + .await; +} + +pub struct SetModlogsCommand; +pub static COMMAND_DESCRIPTOR: SetModlogsCommand = SetModlogsCommand; + +impl crate::commands::command_contract::CommandSpec for SetModlogsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setmodlogs", + category: "config", + params: "[event on/off]", + description: "Affiche ou modifie les evenements qui apparaissent dans les logs de moderation.", + examples: &["+setmodlogs", "+setmodlogs warn off"], + default_aliases: &["smodlog"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/event/end.rs b/src/commands/event/end.rs index fa8c878..b37b6c6 100644 --- a/src/commands/event/end.rs +++ b/src/commands/event/end.rs @@ -90,7 +90,7 @@ pub async fn handle_end(ctx: &Context, msg: &Message, args: &[&str]) { msg, CreateEmbed::new() .title("End") - .description("Usage: +end giveaway ") + .description("Usage: +endgiveaway ") .color(0xED4245), ) .await; @@ -106,7 +106,7 @@ impl crate::commands::command_contract::CommandSpec for EndCommand { category: "event", params: "giveaway ", description: "Permet de stopper instantanement un giveaway avec l'identifiant du message.", - examples: &["+end giveaway 123456789012345678"], + examples: &["+endgiveaway 123456789012345678"], default_aliases: &["gend"], allow_in_dm: false, default_permission: 6, diff --git a/src/commands/info/server.rs b/src/commands/info/server.rs index 6dfa2c0..e58432b 100644 --- a/src/commands/info/server.rs +++ b/src/commands/info/server.rs @@ -26,7 +26,7 @@ pub async fn handle_server(ctx: &Context, msg: &Message, args: &[&str]) { if args.is_empty() { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+server pic`, `+server banner` ou `+server list`") + .description("Usage: `+server pic`, `+server banner` ou `+serverlist`") .color(0xED4245); send_embed(ctx, msg, embed).await; return; @@ -74,7 +74,7 @@ pub async fn handle_server(ctx: &Context, msg: &Message, args: &[&str]) { _ => { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+server pic`, `+server banner` ou `+server list`") + .description("Usage: `+server pic`, `+server banner` ou `+serverlist`") .color(0xED4245); send_embed(ctx, msg, embed).await; } diff --git a/src/commands/info/showpics.rs b/src/commands/info/showpics.rs index c69d1e1..29bb373 100644 --- a/src/commands/info/showpics.rs +++ b/src/commands/info/showpics.rs @@ -65,7 +65,7 @@ impl crate::commands::command_contract::CommandSpec for ShowpicsCommand { category: "info", params: "[nombre 1-5]", description: "Affiche jusqua 5 avatars de membres du serveur.", - examples: &["+show pics", "+help showpics"], + examples: &["+showpics", "+help showpics"], default_aliases: &[], allow_in_dm: false, default_permission: 0, diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 35fac2a..8e28085 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -74,21 +74,21 @@ pub mod choose; pub mod claim; #[path = "mod/cleanup.rs"] pub mod cleanup; -#[path = "mod/clear_all_sanctions.rs"] +#[path = "mod/clearallsanctions.rs"] pub mod clear_all_sanctions; -#[path = "mod/clear_badwords.rs"] +#[path = "mod/clearbadwords.rs"] pub mod clear_badwords; -#[path = "owner/clear_bl.rs"] +#[path = "owner/clearbl.rs"] pub mod clear_bl; -#[path = "mod/clear_limit.rs"] +#[path = "mod/clearlimit.rs"] pub mod clear_limit; -#[path = "mod/clear_messages.rs"] +#[path = "mod/clearmessages.rs"] pub mod clear_messages; -#[path = "owner/clear_owners.rs"] +#[path = "owner/clearowners.rs"] pub mod clear_owners; -#[path = "perms/clear_perms.rs"] +#[path = "perms/clearperms.rs"] pub mod clear_perms; -#[path = "mod/clear_sanctions.rs"] +#[path = "mod/clearsanctions.rs"] pub mod clear_sanctions; #[path = "ticket/close.rs"] pub mod close; @@ -102,7 +102,7 @@ pub mod compet; pub mod create; #[path = "perms/del.rs"] pub mod del; -#[path = "mod/del_sanction.rs"] +#[path = "mod/delsanction.rs"] pub mod del_sanction; #[path = "roles/delrole.rs"] pub mod delrole; @@ -140,7 +140,7 @@ pub mod join; pub mod kick; #[path = "owner/leave.rs"] pub mod leave; -#[path = "config/leave_settings.rs"] +#[path = "config/leavesettings.rs"] pub mod leave_settings; #[path = "security/link.rs"] pub mod link; @@ -205,7 +205,7 @@ pub mod public; pub mod punish; #[path = "config/raidlog.rs"] pub mod raidlog; -#[path = "botconfig/remove_activity.rs"] +#[path = "botconfig/removeactivity.rs"] pub mod remove_activity; #[path = "ticket/rename.rs"] pub mod rename; @@ -233,11 +233,11 @@ pub mod server; pub mod serverinfo; #[path = "botconfig/set.rs"] pub mod set; -#[path = "config/set_boostembed.rs"] +#[path = "config/setboostembed.rs"] pub mod set_boostembed; -#[path = "config/set_modlogs.rs"] +#[path = "config/setmodlogs.rs"] pub mod set_modlogs; -#[path = "mod/set_muterole.rs"] +#[path = "mod/setmuterole.rs"] pub mod set_muterole; #[path = "botconfig/shadowbot.rs"] pub mod shadowbot; @@ -267,13 +267,13 @@ pub mod tempmute; pub mod temprole; #[path = "channel/tempvoc.rs"] pub mod tempvoc; -#[path = "channel/tempvoc_cmd.rs"] +#[path = "channel/tempvoccmd.rs"] pub mod tempvoc_cmd; #[path = "botconfig/theme.rs"] pub mod theme; #[path = "ticket/ticket.rs"] pub mod ticket; -#[path = "ticket/ticket_member.rs"] +#[path = "ticket/ticketmember.rs"] pub mod ticket_member; #[path = "ticket/tickets.rs"] pub mod tickets; @@ -481,9 +481,15 @@ pub fn all_command_metadata() -> Vec { } pub fn command_metadata_by_key(key: &str) -> Option { + let normalized = key.to_lowercase(); + let compact = normalized.replace('_', ""); + all_command_metadata() .into_iter() - .find(|meta| meta.name == key) + .find(|meta| { + meta.name.eq_ignore_ascii_case(&normalized) + || meta.name.replace('_', "").eq_ignore_ascii_case(&compact) + }) } pub fn resolve_default_alias(alias: &str) -> Option<&'static str> { diff --git a/src/commands/mod/clear_all_sanctions.rs b/src/commands/mod/clear_all_sanctions.rs index b9ff51b..907d8cd 100644 --- a/src/commands/mod/clear_all_sanctions.rs +++ b/src/commands/mod/clear_all_sanctions.rs @@ -57,7 +57,7 @@ impl crate::commands::command_contract::CommandSpec for ClearAllSanctionsCommand category: "mod", params: "aucun", description: "Efface toutes les sanctions de tous les membres du serveur.", - examples: &["+clear all sanctions"], + examples: &["+clearallsanctions"], default_aliases: &["casanctions"], allow_in_dm: false, default_permission: 8, diff --git a/src/commands/mod/clear_badwords.rs b/src/commands/mod/clear_badwords.rs index 8a24eb9..e939658 100644 --- a/src/commands/mod/clear_badwords.rs +++ b/src/commands/mod/clear_badwords.rs @@ -41,7 +41,7 @@ impl crate::commands::command_contract::CommandSpec for ClearBadwordsCommand { category: "mod", params: "badwords", description: "Supprime l ensemble des mots interdits enregistres.", - examples: &["+clear badwords", "+help clear badwords"], + examples: &["+clearbadwords", "+help clearbadwords"], default_aliases: &["cbw"], allow_in_dm: false, default_permission: 7, diff --git a/src/commands/mod/clear_limit.rs b/src/commands/mod/clear_limit.rs index 29f3656..afcf252 100644 --- a/src/commands/mod/clear_limit.rs +++ b/src/commands/mod/clear_limit.rs @@ -17,7 +17,7 @@ pub async fn handle_clear_limit(ctx: &Context, msg: &Message, args: &[&str]) { msg, CreateEmbed::new() .title("Clear Limit") - .description("Usage: +clear limit ") + .description("Usage: +clearlimit ") .color(0xED4245), ) .await; @@ -65,7 +65,7 @@ impl crate::commands::command_contract::CommandSpec for ClearLimitCommand { category: "mod", params: "limit ", description: "Definit la limite max de messages supprimables avec +clear.", - examples: &["+clear limit 100", "+help clear limit"], + examples: &["+clearlimit 100", "+help clearlimit"], default_aliases: &["climit"], allow_in_dm: false, default_permission: 7, diff --git a/src/commands/mod/clear_sanctions.rs b/src/commands/mod/clear_sanctions.rs index bd96e70..73c1506 100644 --- a/src/commands/mod/clear_sanctions.rs +++ b/src/commands/mod/clear_sanctions.rs @@ -67,7 +67,7 @@ impl crate::commands::command_contract::CommandSpec for ClearSanctionsCommand { category: "mod", params: "<@membre/ID>", description: "Efface completement les sanctions d un membre cible.", - examples: &["+clear sanctions @User"], + examples: &["+clearsanctions @User"], default_aliases: &["csanctions"], allow_in_dm: false, default_permission: 6, diff --git a/src/commands/mod/clearallsanctions.rs b/src/commands/mod/clearallsanctions.rs new file mode 100644 index 0000000..d3a8008 --- /dev/null +++ b/src/commands/mod/clearallsanctions.rs @@ -0,0 +1,66 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::{send_embed, theme_color}; +use crate::db::DbPoolKey; + +pub async fn handle_clear_all_sanctions(ctx: &Context, msg: &Message) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let pool = { + let data = ctx.data.read().await; + data.get::().cloned() + }; + let Some(pool) = pool else { + return; + }; + let bot_id = ctx.cache.current_user().id; + + let removed = sqlx::query( + r#" + DELETE FROM bot_sanctions + WHERE bot_id = $1 AND guild_id = $2; + "#, + ) + .bind(bot_id.get() as i64) + .bind(guild_id.get() as i64) + .execute(&pool) + .await + .ok() + .map(|r| r.rows_affected()) + .unwrap_or(0); + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Sanctions") + .description(format!( + "{} sanction(s) supprimée(s) sur le serveur.", + removed + )) + .color(theme_color(ctx).await), + ) + .await; +} + +pub struct ClearAllSanctionsCommand; +pub static COMMAND_DESCRIPTOR: ClearAllSanctionsCommand = ClearAllSanctionsCommand; + +impl crate::commands::command_contract::CommandSpec for ClearAllSanctionsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "clearallsanctions", + category: "mod", + params: "aucun", + description: "Efface toutes les sanctions de tous les membres du serveur.", + examples: &["+clearallsanctions"], + default_aliases: &["casanctions"], + allow_in_dm: false, + default_permission: 8, + } + } +} diff --git a/src/commands/mod/clearbadwords.rs b/src/commands/mod/clearbadwords.rs new file mode 100644 index 0000000..8402451 --- /dev/null +++ b/src/commands/mod/clearbadwords.rs @@ -0,0 +1,50 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::automod_service::pool; +use crate::commands::common::send_embed; +use crate::db; + +pub async fn handle_clear_badwords(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.get() as i64; + let cleared = db::clear_badwords(&pool, bot_id, guild_id.get() as i64) + .await + .unwrap_or(0); + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Clear BadWords") + .description(format!("{} mot(s) interdit(s) supprime(s).", cleared)) + .color(0x57F287), + ) + .await; +} + +pub struct ClearBadwordsCommand; +pub static COMMAND_DESCRIPTOR: ClearBadwordsCommand = ClearBadwordsCommand; + +impl crate::commands::command_contract::CommandSpec for ClearBadwordsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "clearbadwords", + category: "mod", + params: "badwords", + description: "Supprime l ensemble des mots interdits enregistres.", + examples: &["+clearbadwords", "+help clearbadwords"], + default_aliases: &["cbw"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/mod/clearlimit.rs b/src/commands/mod/clearlimit.rs new file mode 100644 index 0000000..244556b --- /dev/null +++ b/src/commands/mod/clearlimit.rs @@ -0,0 +1,74 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::automod_service::pool; +use crate::commands::common::send_embed; +use crate::db; + +pub async fn handle_clear_limit(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Some(raw_value) = args.get(1) else { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Clear Limit") + .description("Usage: +clearlimit ") + .color(0xED4245), + ) + .await; + return; + }; + + let Ok(value) = raw_value.parse::() else { + return; + }; + + let clamped = value.clamp(1, 1_000); + let Some(pool) = pool(ctx).await else { + return; + }; + + let bot_id = ctx.cache.current_user().id.get() as i64; + if db::set_clear_limit(&pool, bot_id, guild_id.get() as i64, clamped) + .await + .is_err() + { + return; + } + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Clear Limit") + .description(format!( + "Limite de suppression definie a **{}** message(s) par commande clear.", + clamped + )) + .color(0x57F287), + ) + .await; +} + +pub struct ClearLimitCommand; +pub static COMMAND_DESCRIPTOR: ClearLimitCommand = ClearLimitCommand; + +impl crate::commands::command_contract::CommandSpec for ClearLimitCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "clearlimit", + category: "mod", + params: "limit ", + description: "Definit la limite max de messages supprimables avec +clear.", + examples: &["+clearlimit 100", "+help clearlimit"], + default_aliases: &["climit"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/mod/clear_messages.rs b/src/commands/mod/clearmessages.rs similarity index 96% rename from src/commands/mod/clear_messages.rs rename to src/commands/mod/clearmessages.rs index a5587be..5e0134b 100644 --- a/src/commands/mod/clear_messages.rs +++ b/src/commands/mod/clearmessages.rs @@ -76,11 +76,11 @@ pub static COMMAND_DESCRIPTOR: ClearMessagesCommand = ClearMessagesCommand; impl crate::commands::command_contract::CommandSpec for ClearMessagesCommand { fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { crate::commands::command_contract::CommandMetadata { - name: "clear_messages", + name: "clearmessages", category: "mod", params: " [@membre/ID]", description: "Supprime un nombre de messages, optionnellement filtres par membre.", - examples: &["+clear 20", "+clear 20 @User"], + examples: &["+clearmessages 20", "+clearmessages 20 @User"], default_aliases: &["purge"], allow_in_dm: false, default_permission: 5, diff --git a/src/commands/mod/clearsanctions.rs b/src/commands/mod/clearsanctions.rs new file mode 100644 index 0000000..13e31c4 --- /dev/null +++ b/src/commands/mod/clearsanctions.rs @@ -0,0 +1,76 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::admin_common::parse_user_id; +use crate::commands::common::{send_embed, theme_color}; +use crate::db::DbPoolKey; + +pub async fn handle_clear_sanctions(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + if args.len() < 2 { + return; + } + + let Some(target) = parse_user_id(args[1]) else { + return; + }; + + let pool = { + let data = ctx.data.read().await; + data.get::().cloned() + }; + let Some(pool) = pool else { + return; + }; + let bot_id = ctx.cache.current_user().id; + + let removed = sqlx::query( + r#" + DELETE FROM bot_sanctions + WHERE bot_id = $1 AND guild_id = $2 AND user_id = $3; + "#, + ) + .bind(bot_id.get() as i64) + .bind(guild_id.get() as i64) + .bind(target.get() as i64) + .execute(&pool) + .await + .ok() + .map(|r| r.rows_affected()) + .unwrap_or(0); + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Sanctions") + .description(format!( + "{} sanction(s) supprimée(s) pour <@{}>.", + removed, + target.get() + )) + .color(theme_color(ctx).await), + ) + .await; +} + +pub struct ClearSanctionsCommand; +pub static COMMAND_DESCRIPTOR: ClearSanctionsCommand = ClearSanctionsCommand; + +impl crate::commands::command_contract::CommandSpec for ClearSanctionsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "clearsanctions", + category: "mod", + params: "<@membre/ID>", + description: "Efface completement les sanctions d un membre cible.", + examples: &["+clearsanctions @User"], + default_aliases: &["csanctions"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/mod/del_sanction.rs b/src/commands/mod/del_sanction.rs index bb90876..df1b59d 100644 --- a/src/commands/mod/del_sanction.rs +++ b/src/commands/mod/del_sanction.rs @@ -89,7 +89,7 @@ impl crate::commands::command_contract::CommandSpec for DelSanctionCommand { category: "mod", params: "<@membre/ID> ", description: "Supprime une sanction specifique dans l historique d un membre.", - examples: &["+del sanction @User 1"], + examples: &["+delsanction @User 1"], default_aliases: &["delsanction"], allow_in_dm: false, default_permission: 6, diff --git a/src/commands/mod/delsanction.rs b/src/commands/mod/delsanction.rs new file mode 100644 index 0000000..f0f150f --- /dev/null +++ b/src/commands/mod/delsanction.rs @@ -0,0 +1,98 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::admin_common::parse_user_id; +use crate::commands::common::{send_embed, theme_color}; +use crate::db::DbPoolKey; + +pub async fn handle_del_sanction(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + if args.len() < 3 { + return; + } + + let Some(target) = parse_user_id(args[1]) else { + return; + }; + let Ok(index) = args[2].parse::() else { + return; + }; + if index == 0 { + return; + } + + let pool = { + let data = ctx.data.read().await; + data.get::().cloned() + }; + let Some(pool) = pool else { + return; + }; + let bot_id = ctx.cache.current_user().id; + + let rows = sqlx::query_as::<_, (i64,)>( + r#" + SELECT id + FROM bot_sanctions + WHERE bot_id = $1 AND guild_id = $2 AND user_id = $3 + ORDER BY created_at DESC; + "#, + ) + .bind(bot_id.get() as i64) + .bind(guild_id.get() as i64) + .bind(target.get() as i64) + .fetch_all(&pool) + .await + .unwrap_or_default(); + + let Some((sanction_id,)) = rows.get(index - 1).copied() else { + return; + }; + + let _ = sqlx::query( + r#" + DELETE FROM bot_sanctions + WHERE id = $1 AND bot_id = $2 AND guild_id = $3; + "#, + ) + .bind(sanction_id) + .bind(bot_id.get() as i64) + .bind(guild_id.get() as i64) + .execute(&pool) + .await; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Sanctions") + .description(format!( + "Sanction #{} supprimée pour <@{}>.", + sanction_id, + target.get() + )) + .color(theme_color(ctx).await), + ) + .await; +} + +pub struct DelSanctionCommand; +pub static COMMAND_DESCRIPTOR: DelSanctionCommand = DelSanctionCommand; + +impl crate::commands::command_contract::CommandSpec for DelSanctionCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "delsanction", + category: "mod", + params: "<@membre/ID> ", + description: "Supprime une sanction specifique dans l historique d un membre.", + examples: &["+delsanction @User 1"], + default_aliases: &["delsanction"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/mod/set_muterole.rs b/src/commands/mod/set_muterole.rs index 8c25ff7..2094dfa 100644 --- a/src/commands/mod/set_muterole.rs +++ b/src/commands/mod/set_muterole.rs @@ -17,7 +17,7 @@ pub async fn handle_set_muterole(ctx: &Context, msg: &Message, args: &[&str]) { msg, CreateEmbed::new() .title("Set MuteRole") - .description("Usage: +set muterole <@role/ID/nom>") + .description("Usage: +setmuterole <@role/ID/nom>") .color(0xED4245), ) .await; @@ -70,7 +70,7 @@ impl crate::commands::command_contract::CommandSpec for SetMuteRoleCommand { category: "mod", params: "muterole <@role/ID/nom>", description: "Definit le role utilise pour le mute lorsque le mode timeout est desactive.", - examples: &["+set muterole @Muted", "+help set muterole"], + examples: &["+setmuterole @Muted", "+help setmuterole"], default_aliases: &["smr"], allow_in_dm: false, default_permission: 7, diff --git a/src/commands/mod/setmuterole.rs b/src/commands/mod/setmuterole.rs new file mode 100644 index 0000000..aca1f78 --- /dev/null +++ b/src/commands/mod/setmuterole.rs @@ -0,0 +1,79 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::automod_service::pool; +use crate::commands::common::{parse_role, send_embed}; +use crate::db; + +pub async fn handle_set_muterole(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Some(raw_role) = args.get(1) else { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Set MuteRole") + .description("Usage: +setmuterole <@role/ID/nom>") + .color(0xED4245), + ) + .await; + return; + }; + + let Ok(guild) = guild_id.to_partial_guild(&ctx.http).await else { + return; + }; + + let Some(role) = parse_role(&guild, raw_role) else { + return; + }; + + let Some(pool) = pool(ctx).await else { + return; + }; + + let bot_id = ctx.cache.current_user().id.get() as i64; + if db::set_mute_role( + &pool, + bot_id, + guild_id.get() as i64, + Some(role.id.get() as i64), + ) + .await + .is_err() + { + return; + } + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("MuteRole") + .description(format!("Role muet defini sur <@&{}>.", role.id.get())) + .color(0x57F287), + ) + .await; +} + +pub struct SetMuteRoleCommand; +pub static COMMAND_DESCRIPTOR: SetMuteRoleCommand = SetMuteRoleCommand; + +impl crate::commands::command_contract::CommandSpec for SetMuteRoleCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setmuterole", + category: "mod", + params: "muterole <@role/ID/nom>", + description: "Definit le role utilise pour le mute lorsque le mode timeout est desactive.", + examples: &["+setmuterole @Muted", "+help setmuterole"], + default_aliases: &["smr"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/owner/clear_bl.rs b/src/commands/owner/clear_bl.rs index a8fc9b8..cbf2132 100644 --- a/src/commands/owner/clear_bl.rs +++ b/src/commands/owner/clear_bl.rs @@ -43,7 +43,7 @@ impl crate::commands::command_contract::CommandSpec for ClearBlCommand { category: "owner", params: "aucun", description: "Supprime toutes les entrees de la blacklist globale.", - examples: &["+clear bl", "+cl", "+help clear bl"], + examples: &["+clearbl", "+cl", "+help clearbl"], default_aliases: &["cbl"], allow_in_dm: false, default_permission: 9, diff --git a/src/commands/owner/clear_owners.rs b/src/commands/owner/clear_owners.rs index 053fdca..9e2017e 100644 --- a/src/commands/owner/clear_owners.rs +++ b/src/commands/owner/clear_owners.rs @@ -43,7 +43,7 @@ impl crate::commands::command_contract::CommandSpec for ClearOwnersCommand { category: "owner", params: "aucun", description: "Supprime tous les owners supplementaires en base de donnees.", - examples: &["+clear owners", "+cs", "+help clear owners"], + examples: &["+clearowners", "+cs", "+help clearowners"], default_aliases: &["cro"], allow_in_dm: false, default_permission: 9, diff --git a/src/commands/owner/clearbl.rs b/src/commands/owner/clearbl.rs new file mode 100644 index 0000000..b81d647 --- /dev/null +++ b/src/commands/owner/clearbl.rs @@ -0,0 +1,52 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::admin_common::ensure_owner; +use crate::commands::common::send_embed; +use crate::db::{DbPoolKey, clear_blacklist}; + +pub async fn handle_clear_bl(ctx: &Context, msg: &Message) { + if ensure_owner(ctx, msg).await.is_err() { + return; + } + + let bot_id = ctx.cache.current_user().id; + let pool = { + let data = ctx.data.read().await; + data.get::().cloned() + }; + + let Some(pool) = pool else { + let embed = serenity::builder::CreateEmbed::new() + .title("Erreur") + .description("DB indisponible.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let count = clear_blacklist(&pool, bot_id).await.unwrap_or(0); + let embed = serenity::builder::CreateEmbed::new() + .title("Blacklist réinitialisée") + .description(format!("{} membre(s) retiré(s) de la blacklist.", count)) + .color(0x57F287); + send_embed(ctx, msg, embed).await; +} + +pub struct ClearBlCommand; +pub static COMMAND_DESCRIPTOR: ClearBlCommand = ClearBlCommand; + +impl crate::commands::command_contract::CommandSpec for ClearBlCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "clearbl", + category: "owner", + params: "aucun", + description: "Supprime toutes les entrees de la blacklist globale.", + examples: &["+clearbl", "+cl", "+help clearbl"], + default_aliases: &["cbl"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/owner/clearowners.rs b/src/commands/owner/clearowners.rs new file mode 100644 index 0000000..2abd8b7 --- /dev/null +++ b/src/commands/owner/clearowners.rs @@ -0,0 +1,52 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::admin_common::ensure_owner; +use crate::commands::common::send_embed; +use crate::db::{DbPoolKey, clear_bot_owners}; + +pub async fn handle_clear_owners(ctx: &Context, msg: &Message) { + if ensure_owner(ctx, msg).await.is_err() { + return; + } + + let bot_id = ctx.cache.current_user().id; + let pool = { + let data = ctx.data.read().await; + data.get::().cloned() + }; + + let Some(pool) = pool else { + let embed = serenity::builder::CreateEmbed::new() + .title("Erreur") + .description("DB indisponible.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let count = clear_bot_owners(&pool, bot_id).await.unwrap_or(0); + let embed = serenity::builder::CreateEmbed::new() + .title("Owners réinitialisés") + .description(format!("{} owner(s) supprimé(s).", count)) + .color(0x57F287); + send_embed(ctx, msg, embed).await; +} + +pub struct ClearOwnersCommand; +pub static COMMAND_DESCRIPTOR: ClearOwnersCommand = ClearOwnersCommand; + +impl crate::commands::command_contract::CommandSpec for ClearOwnersCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "clearowners", + category: "owner", + params: "aucun", + description: "Supprime tous les owners supplementaires en base de donnees.", + examples: &["+clearowners", "+cs", "+help clearowners"], + default_aliases: &["cro"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/owner/mp.rs b/src/commands/owner/mp.rs index 860c547..b49b99d 100644 --- a/src/commands/owner/mp.rs +++ b/src/commands/owner/mp.rs @@ -38,7 +38,7 @@ pub async fn handle_mp(ctx: &Context, msg: &Message, args: &[&str]) { let embed = CreateEmbed::new() .title("MP settings") .description(format!( - "Envoi de MP: `{}`\nUtilise `+mp settings on/off`.", + "Envoi de MP: `{}`\nUtilise `+mpsettings on/off`.", if enabled { "on" } else { "off" } )) .color(0x5865F2); @@ -52,7 +52,7 @@ pub async fn handle_mp(ctx: &Context, msg: &Message, args: &[&str]) { _ => { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+mp settings `") + .description("Usage: `+mpsettings `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; @@ -93,7 +93,7 @@ pub async fn handle_mp(ctx: &Context, msg: &Message, args: &[&str]) { let Some(entry_id_raw) = args.get(1) else { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+mp delete `") + .description("Usage: `+mpdelete `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; @@ -158,7 +158,7 @@ pub async fn handle_mp(ctx: &Context, msg: &Message, args: &[&str]) { if args.len() < 2 { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+mp settings` ou `+mp `") + .description("Usage: `+mpsettings` ou `+mp `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; @@ -182,7 +182,7 @@ pub async fn handle_mp(ctx: &Context, msg: &Message, args: &[&str]) { if !enabled { let embed = CreateEmbed::new() .title("MP désactivés") - .description("Réactive-les avec `+mp settings on`.") + .description("Réactive-les avec `+mpsettings on`.") .color(0xED4245); send_embed(ctx, msg, embed).await; return; diff --git a/src/commands/perms/alias.rs b/src/commands/perms/alias.rs index bbaf6e5..abbc6ac 100644 --- a/src/commands/perms/alias.rs +++ b/src/commands/perms/alias.rs @@ -67,10 +67,9 @@ pub async fn handle_alias(ctx: &Context, msg: &Message, args: &[&str]) { } let command = args[0].trim_start_matches('+').to_lowercase(); - if !all_command_keys() - .iter() - .any(|candidate| candidate == &command) - { + let is_known = all_command_keys().iter().any(|candidate| candidate == &command) + || crate::commands::command_metadata_by_key(&command).is_some(); + if !is_known { let embed = serenity::builder::CreateEmbed::new() .title("Erreur") .description("Commande cible inconnue.") diff --git a/src/commands/perms/clear_perms.rs b/src/commands/perms/clear_perms.rs index 67ca73c..8c8f99d 100644 --- a/src/commands/perms/clear_perms.rs +++ b/src/commands/perms/clear_perms.rs @@ -39,7 +39,7 @@ impl crate::commands::command_contract::CommandSpec for ClearPermsCommand { category: "perms", params: "aucun", description: "Supprime toutes les permissions ACL configurees en base.", - examples: &["+clear perms", "+cs", "+help clear perms"], + examples: &["+clearperms", "+cs", "+help clearperms"], default_aliases: &["cpm"], allow_in_dm: false, default_permission: 9, diff --git a/src/commands/perms/clearperms.rs b/src/commands/perms/clearperms.rs new file mode 100644 index 0000000..942a1cc --- /dev/null +++ b/src/commands/perms/clearperms.rs @@ -0,0 +1,48 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::send_embed; +use crate::commands::perms_helpers::{ensure_owner, get_pool}; +use crate::db::clear_role_permissions; + +pub async fn handle_clear_perms(ctx: &Context, msg: &Message) { + if !ensure_owner(ctx, msg).await { + return; + } + + let bot_id = ctx.cache.current_user().id; + let Some(pool) = get_pool(ctx).await else { + let embed = CreateEmbed::new() + .title("Erreur") + .description("DB indisponible.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let removed = clear_role_permissions(&pool, bot_id).await.unwrap_or(0); + let embed = CreateEmbed::new() + .title("Permissions roles supprimees") + .description(format!("{} entree(s) supprimee(s).", removed)) + .color(0x57F287); + send_embed(ctx, msg, embed).await; +} + +pub struct ClearPermsCommand; +pub static COMMAND_DESCRIPTOR: ClearPermsCommand = ClearPermsCommand; + +impl crate::commands::command_contract::CommandSpec for ClearPermsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "clearperms", + category: "perms", + params: "aucun", + description: "Supprime toutes les permissions ACL configurees en base.", + examples: &["+clearperms", "+cs", "+help clearperms"], + default_aliases: &["cpm"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/perms/del.rs b/src/commands/perms/del.rs index 7a71299..c5a5397 100644 --- a/src/commands/perms/del.rs +++ b/src/commands/perms/del.rs @@ -14,7 +14,7 @@ pub async fn handle_del(ctx: &Context, msg: &Message, args: &[&str]) { if args.len() < 2 || !args[0].eq_ignore_ascii_case("perm") { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `del perm `") + .description("Usage: `+delperm `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; diff --git a/src/commands/perms/help.rs b/src/commands/perms/help.rs index a91a8a4..b0ab428 100644 --- a/src/commands/perms/help.rs +++ b/src/commands/perms/help.rs @@ -133,8 +133,8 @@ fn help_page_for_command( ) -> &'static str { match meta.name { "modlog" | "messagelog" | "voicelog" | "boostlog" | "rolelog" | "raidlog" - | "autoconfiglog" | "nolog" | "join" | "boostembed" | "set_modlogs" | "set_boostembed" - | "leave_settings" | "viewlogs" => "logs", + | "autoconfiglog" | "nolog" | "join" | "boostembed" | "setmodlogs" | "setboostembed" + | "leavesettings" | "viewlogs" => "logs", "warn" | "mute" | "tempmute" @@ -151,12 +151,12 @@ fn help_page_for_command( | "banlist" | "unbanall" | "sanctions" - | "del_sanction" - | "clear_sanctions" - | "clear_all_sanctions" + | "delsanction" + | "clearsanctions" + | "clearallsanctions" | "cleanup" | "renew" - | "clear_messages" => "moderation", + | "clearmessages" => "moderation", "addrole" | "delrole" | "derank" | "massiverole" | "unmassiverole" | "temprole" | "untemprole" | "sync" => "roles", "lock" | "unlock" | "lockall" | "unlockall" | "hide" | "unhide" | "hideall" @@ -165,16 +165,24 @@ fn help_page_for_command( | "create" | "newsticker" | "button" | "autoreact" | "snipe" | "loading" | "backup" | "autobackup" => "outils", "shadowbot" | "set" | "theme" | "playto" | "listen" | "watch" | "compet" | "stream" - | "remove_activity" | "online" | "idle" | "dnd" | "invisible" | "change" | "changeall" => { + | "removeactivity" | "online" | "idle" | "dnd" | "invisible" | "change" | "changeall" => { "bot" } - "owner" | "unowner" | "clear_owners" | "bl" | "unbl" | "blinfo" | "clear_bl" + "owner" | "unowner" | "clearowners" | "bl" | "unbl" | "blinfo" | "clearbl" | "allbots" | "alladmins" | "botadmins" | "mainprefix" | "prefix" | "mp" | "invite" | "leave" | "discussion" => "administration", - "perms" | "del" | "clear_perms" | "allperms" | "alias" | "help" | "helpsetting" => { + "perms" | "del" | "clearperms" | "allperms" | "alias" | "help" | "helpsetting" => { "permissions" } _ => match meta.category { + "info" => "infos", + "mod" => "moderation", + "config" => "logs", + "botconfig" => "bot", + "owner" => "administration", + "perms" => "permissions", + "channel" => "salons_vocal", + "event" => "outils", "infos" => "infos", "logs" => "logs", "moderation" => "moderation", @@ -209,12 +217,14 @@ fn help_page_title_for_command_key(key: &str) -> &'static str { fn help_metadata_lookup_key(input: &str) -> Option<&'static str> { let normalized = help_lookup_key(input); let underscored = normalized.replace(' ', "_"); + let compact = normalized.replace(' ', ""); crate::commands::all_command_metadata() .into_iter() .find(|meta| { meta.name.eq_ignore_ascii_case(&normalized) || meta.name.eq_ignore_ascii_case(&underscored) + || meta.name.replace('_', "").eq_ignore_ascii_case(&compact) || meta .name .replace('_', " ") @@ -321,18 +331,58 @@ async fn aliases_map(ctx: &Context) -> BTreeMap> { } fn command_doc(key: &str) -> Option { - let meta = match key { - "mp_settings" | "mp_sent" | "mp_delete" => crate::commands::command_metadata_by_key("mp")?, - "server_list" => crate::commands::command_metadata_by_key("server")?, - "change_reset" => crate::commands::command_metadata_by_key("change")?, - "set_perm" => crate::commands::command_metadata_by_key("set")?, - "del_perm" => crate::commands::command_metadata_by_key("del")?, - other => crate::commands::command_metadata_by_key(other)?, + let (meta, command, acl_key, alias_source_key) = match key { + "mpsettings" => ( + crate::commands::command_metadata_by_key("mp")?, + "mpsettings", + "mpsettings", + Some("mp"), + ), + "mpsent" => ( + crate::commands::command_metadata_by_key("mp")?, + "mpsent", + "mpsent", + Some("mp"), + ), + "mpdelete" => ( + crate::commands::command_metadata_by_key("mp")?, + "mpdelete", + "mpdelete", + Some("mp"), + ), + "serverlist" => ( + crate::commands::command_metadata_by_key("server")?, + "serverlist", + "serverlist", + Some("server"), + ), + "changereset" => ( + crate::commands::command_metadata_by_key("change")?, + "changereset", + "changereset", + Some("change"), + ), + "setperm" => ( + crate::commands::command_metadata_by_key("set")?, + "setperm", + "setperm", + Some("set"), + ), + "delperm" => ( + crate::commands::command_metadata_by_key("del")?, + "delperm", + "delperm", + Some("del"), + ), + other => { + let meta = crate::commands::command_metadata_by_key(other)?; + (meta, meta.name, meta.name, Some(meta.name)) + } }; Some(CommandDoc { - key: meta.name, - command: meta.name, + key: acl_key, + command, allow_in_dm: meta.allow_in_dm, default_permission: meta.default_permission, params: meta.params, @@ -342,7 +392,7 @@ fn command_doc(key: &str) -> Option { } else { meta.examples }, - alias_source_key: Some(meta.name), + alias_source_key, }) } @@ -351,7 +401,6 @@ fn help_lookup_key(input: &str) -> String { .trim() .trim_start_matches('+') .to_lowercase() - .replace('_', " ") .split_whitespace() .collect::>() .join(" ") @@ -375,11 +424,11 @@ fn help_lookup_to_key(input: &str) -> Option<&'static str> { "pic" => Some("pic"), "banner" => Some("banner"), "server" => Some("server"), - "server list" => Some("server_list"), + "serverlist" => Some("serverlist"), "snipe" => Some("snipe"), "emoji" => Some("emoji"), "giveaway" => Some("giveaway"), - "end" | "end giveaway" => Some("end"), + "end" | "endgiveaway" => Some("end"), "reroll" => Some("reroll"), "choose" => Some("choose"), "embed" => Some("embed"), @@ -410,36 +459,36 @@ fn help_lookup_to_key(input: &str) -> Option<&'static str> { "watch" => Some("watch"), "compet" => Some("compet"), "stream" => Some("stream"), - "remove activity" => Some("remove_activity"), + "removeactivity" => Some("removeactivity"), "online" => Some("online"), "idle" => Some("idle"), "dnd" => Some("dnd"), "invisible" => Some("invisible"), "mp" => Some("mp"), - "mp settings" => Some("mp_settings"), - "mp sent" => Some("mp_sent"), - "mp delete" | "mp del" => Some("mp_delete"), + "mpsettings" => Some("mpsettings"), + "mpsent" => Some("mpsent"), + "mpdelete" | "mpdel" => Some("mpdelete"), "discussion" => Some("discussion"), "owner" => Some("owner"), "unowner" => Some("unowner"), - "clear owners" => Some("clear_owners"), + "clearowners" => Some("clearowners"), "bl" => Some("bl"), "unbl" => Some("unbl"), "blinfo" => Some("blinfo"), - "clear bl" => Some("clear_bl"), + "clearbl" => Some("clearbl"), "say" => Some("say"), "invite" => Some("invite"), "leave" => Some("leave"), "change" => Some("change"), - "change reset" => Some("change_reset"), + "changereset" => Some("changereset"), "changeall" => Some("changeall"), "mainprefix" => Some("mainprefix"), "prefix" => Some("prefix"), "perms" => Some("perms"), "allperms" => Some("allperms"), - "set perm" => Some("set_perm"), - "del perm" => Some("del_perm"), - "clear perms" => Some("clear_perms"), + "setperm" => Some("setperm"), + "delperm" => Some("delperm"), + "clearperms" => Some("clearperms"), "alias" => Some("alias"), "helpsetting" | "helpetting" => Some("helpsetting"), _ => None, @@ -518,7 +567,7 @@ fn help_page_content( let mut lines = Vec::with_capacity(commands.len()); for meta in commands { - let label = meta.name.replace('_', " "); + let label = meta.name.replace('_', ""); let alias_key = meta.name; let params = if meta.params.trim().is_empty() { "aucun" @@ -854,14 +903,11 @@ async fn build_command_help_embed( .join("\n"); let mut embed = CreateEmbed::new() - .title(format!( - "Aide commande · +{}", - doc.command.replace('_', " ") - )) + .title(format!("Aide commande · +{}", doc.command.replace('_', ""))) .description(doc.description) .field( "Commande", - format!("`+{}`", doc.command.replace('_', " ")), + format!("`+{}`", doc.command.replace('_', "")), false, ) .field("Clé ACL", format!("`{}`", doc.key), false) diff --git a/src/commands/perms_helpers.rs b/src/commands/perms_helpers.rs index 27edd89..c164b06 100644 --- a/src/commands/perms_helpers.rs +++ b/src/commands/perms_helpers.rs @@ -33,10 +33,26 @@ pub fn parse_user_or_role(input: &str) -> Option<(&'static str, u64)> { } pub fn normalize_command_name(input: &str) -> String { - input - .trim_start_matches('+') - .replace(' ', "_") - .to_lowercase() + let normalized = input.trim_start_matches('+').to_lowercase(); + let underscored = normalized + .split_whitespace() + .collect::>() + .join("_"); + let compact = underscored.replace('_', ""); + + let known = crate::permissions::all_command_keys(); + + let direct = crate::permissions::command_key(&underscored, &[]); + if known.iter().any(|value| value == &direct) { + return direct; + } + + let compact_mapped = crate::permissions::command_key(&compact, &[]); + if known.iter().any(|value| value == &compact_mapped) { + return compact_mapped; + } + + underscored } pub async fn ensure_owner(ctx: &Context, msg: &Message) -> bool { diff --git a/src/commands/ticket/ticket_member.rs b/src/commands/ticket/ticketmember.rs similarity index 100% rename from src/commands/ticket/ticket_member.rs rename to src/commands/ticket/ticketmember.rs diff --git a/src/events/message_event.rs b/src/events/message_event.rs index ae0fcb8..a4097e8 100644 --- a/src/events/message_event.rs +++ b/src/events/message_event.rs @@ -114,12 +114,19 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { } let mut parts = without_prefix.split_whitespace(); - let mut command = parts.next().unwrap_or("").to_lowercase(); - let args = parts.collect::>(); + let typed_command = parts.next().unwrap_or("").to_lowercase(); + let typed_args = parts.collect::>(); + + let mut command = typed_command; + let args = typed_args; // Ne laisse pas un alias écraser une commande native. let native_commands = permissions::all_command_keys(); - if !native_commands.iter().any(|cmd| cmd == &command) { + let is_native = native_commands.iter().any(|cmd| cmd == &command) + || crate::commands::all_command_metadata() + .into_iter() + .any(|meta| meta.name.eq_ignore_ascii_case(&command)); + if !is_native { if let Some(alias_target) = alias::resolve_command_alias_name(ctx, &command).await { command = alias_target; } else if let Some(default_target) = crate::commands::resolve_default_alias(&command) { @@ -133,17 +140,17 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { let dm_metadata = crate::commands::command_metadata_by_key(&command_key) .or_else(|| { let mapped = match command_key.as_str() { - "show_pics" => Some("showpics"), + "showpics" => Some("showpics"), "suggestion_create" | "suggestion_settings" => Some("suggestion"), "ticket_settings" => Some("ticket"), "ticket_add" => Some("add"), "ticket_remove" => Some("del"), "ticket_close" => Some("close"), - "set_perm" => Some("set"), - "change_reset" => Some("change"), - "server_list" => Some("server"), - "end_giveaway" => Some("end"), - "mp_settings" | "mp_sent" | "mp_delete" => Some("mp"), + "setperm" => Some("set"), + "changereset" => Some("change"), + "serverlist" => Some("server"), + "endgiveaway" => Some("end"), + "mpsettings" | "mpsent" | "mpdelete" => Some("mp"), _ => None, }; @@ -157,7 +164,7 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { .title("Commande indisponible en DM") .description(format!( "La commande `+{}` n'est pas autorisee en message prive.", - command.replace('_', " ") + command.replace('_', "") )) .color(0xED4245); crate::commands::common::send_embed(ctx, msg, embed).await; @@ -184,44 +191,24 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "claim" => claim::handle_claim(ctx, msg, &args).await, "rename" => rename::handle_rename(ctx, msg, &args).await, "add" => ticket_member::handle_ticket_add(ctx, msg, &args).await, - "del" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("perm")) - .unwrap_or(false) => - { - del::handle_del(ctx, msg, &args).await + "delperm" => { + let mut forwarded = vec!["perm"]; + forwarded.extend(args.iter().copied()); + del::handle_del(ctx, msg, &forwarded).await } - "del" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("sanction")) - .unwrap_or(false) => - { - del_sanction::handle_del_sanction(ctx, msg, &args).await + "delsanction" => { + let mut forwarded = vec!["sanction"]; + forwarded.extend(args.iter().copied()); + del_sanction::handle_del_sanction(ctx, msg, &forwarded).await } "del" => ticket_member::handle_ticket_remove(ctx, msg, &args).await, "close" => close::handle_close(ctx, msg, &args).await, "tickets" => tickets::handle_tickets(ctx, msg, &args).await, - "show" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("pics")) - .unwrap_or(false) => - { - showpics::handle_show_pics(ctx, msg, &args[1..]).await - } + "showpics" => showpics::handle_show_pics(ctx, msg, &args).await, "piconly" => piconly::handle_piconly(ctx, msg, &args).await, "suggestion" => suggestion::handle_suggestion(ctx, msg, &args).await, "autopublish" => autopublish::handle_autopublish(ctx, msg, &args).await, - "tempvoc" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("cmd")) - .unwrap_or(false) => - { - tempvoc_cmd::handle_tempvoc_cmd(ctx, msg, &args[1..]).await - } + "tempvoccmd" => tempvoc_cmd::handle_tempvoc_cmd(ctx, msg, &args).await, "tempvoc" => tempvoc::handle_tempvoc(ctx, msg, &args).await, "ping" => ping::handle_ping(ctx, msg, &args).await, "timeout" => timeout::handle_timeout_toggle(ctx, msg, &args).await, @@ -255,6 +242,7 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "pic" => pic::handle_pic(ctx, msg, &args).await, "banner" => banner::handle_banner(ctx, msg, &args).await, "server" => server::handle_server(ctx, msg, &args).await, + "serverlist" => server::handle_server_list(ctx, msg).await, "snipe" => snipe::handle_snipe(ctx, msg, &args).await, "emoji" => emoji::handle_emoji(ctx, msg, &args).await, "giveaway" => giveaway::handle_giveaway(ctx, msg, &args).await, @@ -269,6 +257,11 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "boostembed" => boostembed::handle_boostembed(ctx, msg, &args).await, "nolog" => nolog::handle_nolog(ctx, msg, &args).await, "sanctions" => sanctions::handle_sanctions(ctx, msg, &args).await, + "endgiveaway" => { + let mut forwarded = vec!["giveaway"]; + forwarded.extend(args.iter().copied()); + end::handle_end(ctx, msg, &forwarded).await + } "end" => end::handle_end(ctx, msg, &args).await, "reroll" => reroll::handle_reroll(ctx, msg, &args).await, "choose" => choose::handle_choose(ctx, msg, &args).await, @@ -405,30 +398,18 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "autoreact" => autoreact::handle_autoreact(ctx, msg, &args).await, "calc" => calc::handle_calc(ctx, msg, &args).await, "shadowbot" => shadowbot::handle_shadowbot(ctx, msg, &args).await, - "set" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("muterole")) - .unwrap_or(false) => - { - set_muterole::handle_set_muterole(ctx, msg, &args).await + "setperm" => { + let mut forwarded = vec!["perm"]; + forwarded.extend(args.iter().copied()); + set::handle_set(ctx, msg, &forwarded).await } - "set" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("modlogs")) - .unwrap_or(false) => - { - set_modlogs::handle_set_modlogs(ctx, msg, &args[1..]).await - } - "set" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("boostembed")) - .unwrap_or(false) => - { - set_boostembed::handle_set_boostembed(ctx, msg, &args[1..]).await + "setmuterole" => { + let mut forwarded = vec!["muterole"]; + forwarded.extend(args.iter().copied()); + set_muterole::handle_set_muterole(ctx, msg, &forwarded).await } + "setmodlogs" => set_modlogs::handle_set_modlogs(ctx, msg, &args).await, + "setboostembed" => set_boostembed::handle_set_boostembed(ctx, msg, &args).await, "set" => set::handle_set(ctx, msg, &args).await, "theme" => theme::handle_theme(ctx, msg, &args).await, "playto" => playto::handle_playto(ctx, msg, &args).await, @@ -439,27 +420,32 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "help" => help::handle_help(ctx, msg, &args).await, "helpsetting" => helpsetting::handle_helpsetting(ctx, msg, &args).await, "alias" => alias::handle_alias(ctx, msg, &args).await, + "mpsettings" => { + let mut forwarded = vec!["settings"]; + forwarded.extend(args.iter().copied()); + mp::handle_mp(ctx, msg, &forwarded).await + } + "mpsent" => { + let mut forwarded = vec!["sent"]; + forwarded.extend(args.iter().copied()); + mp::handle_mp(ctx, msg, &forwarded).await + } + "mpdelete" | "mpdel" => { + let mut forwarded = vec!["delete"]; + forwarded.extend(args.iter().copied()); + mp::handle_mp(ctx, msg, &forwarded).await + } "mp" => mp::handle_mp(ctx, msg, &args).await, "invite" => invite::handle_invite(ctx, msg, &args).await, - "leave" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("settings")) - .unwrap_or(false) => - { - leave_settings::handle_leave_settings(ctx, msg, &args).await + "leavesettings" => { + let mut forwarded = vec!["settings"]; + forwarded.extend(args.iter().copied()); + leave_settings::handle_leave_settings(ctx, msg, &forwarded).await } "leave" => leave::handle_leave(ctx, msg, &args).await, "viewlogs" => viewlogs::handle_viewlogs(ctx, msg, &args).await, "discussion" => discussion::handle_discussion(ctx, msg, &args).await, - "remove" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("activity")) - .unwrap_or(false) => - { - remove_activity::handle_remove_activity(ctx, msg).await - } + "removeactivity" => remove_activity::handle_remove_activity(ctx, msg).await, "online" => online::handle_online(ctx, msg).await, "idle" => idle::handle_idle(ctx, msg).await, "dnd" => dnd::handle_dnd(ctx, msg).await, @@ -470,67 +456,33 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "unbl" => unbl::handle_unbl(ctx, msg, &args).await, "blinfo" => blinfo::handle_blinfo(ctx, msg, &args).await, "say" => say::handle_say(ctx, msg, &args).await, + "changereset" => { + let mut forwarded = vec!["reset"]; + forwarded.extend(args.iter().copied()); + change::handle_change(ctx, msg, &forwarded).await + } "change" => change::handle_change(ctx, msg, &args).await, "changeall" => changeall::handle_changeall(ctx, msg, &args).await, "mainprefix" => mainprefix::handle_mainprefix(ctx, msg, &args).await, "prefix" => prefix::handle_prefix(ctx, msg, &args).await, "perms" => perms::handle_perms(ctx, msg, &args).await, "allperms" => allperms::handle_allperms(ctx, msg, &args).await, - "clear" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("owners")) - .unwrap_or(false) => - { - clear_owners::handle_clear_owners(ctx, msg).await + "clearowners" => clear_owners::handle_clear_owners(ctx, msg).await, + "clearbl" => clear_bl::handle_clear_bl(ctx, msg).await, + "clearperms" => clear_perms::handle_clear_perms(ctx, msg).await, + "clearlimit" => { + let mut forwarded = vec!["limit"]; + forwarded.extend(args.iter().copied()); + clear_limit::handle_clear_limit(ctx, msg, &forwarded).await } - "clear" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("bl")) - .unwrap_or(false) => - { - clear_bl::handle_clear_bl(ctx, msg).await - } - "clear" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("perms")) - .unwrap_or(false) => - { - clear_perms::handle_clear_perms(ctx, msg).await - } - "clear" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("limit")) - .unwrap_or(false) => - { - clear_limit::handle_clear_limit(ctx, msg, &args).await - } - "clear" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("badwords")) - .unwrap_or(false) => - { - clear_badwords::handle_clear_badwords(ctx, msg, &args).await - } - "clear" - if args - .first() - .map(|s| s.eq_ignore_ascii_case("sanctions")) - .unwrap_or(false) => - { - clear_sanctions::handle_clear_sanctions(ctx, msg, &args).await - } - "clear" - if args.len() >= 2 - && args[0].eq_ignore_ascii_case("all") - && args[1].eq_ignore_ascii_case("sanctions") => - { - clear_all_sanctions::handle_clear_all_sanctions(ctx, msg).await + "clearbadwords" => clear_badwords::handle_clear_badwords(ctx, msg, &args).await, + "clearsanctions" => { + let mut forwarded = vec!["sanctions"]; + forwarded.extend(args.iter().copied()); + clear_sanctions::handle_clear_sanctions(ctx, msg, &forwarded).await } + "clearallsanctions" => clear_all_sanctions::handle_clear_all_sanctions(ctx, msg).await, + "clearmessages" => clear_messages::handle_clear_messages(ctx, msg, &args).await, "clear" => clear_messages::handle_clear_messages(ctx, msg, &args).await, _ => {} } diff --git a/src/permissions.rs b/src/permissions.rs index c4c3db9..64193e4 100644 --- a/src/permissions.rs +++ b/src/permissions.rs @@ -1,6 +1,7 @@ use serenity::builder::CreateEmbed; use serenity::model::prelude::*; use serenity::prelude::*; +use std::collections::BTreeSet; use std::env; use crate::commands::common::send_embed; @@ -9,519 +10,111 @@ use crate::db::{ has_perm_level_access, is_bot_owner, }; +const EXTRA_COMMAND_KEYS: &[&str] = &[ + "ticket_settings", + "ticket_add", + "ticket_remove", + "ticket_close", + "suggestion_settings", + "setperm", + "delperm", + "changereset", + "serverlist", + "endgiveaway", + "mpsettings", +]; + +fn first_arg_is(args: &[&str], expected: &str) -> bool { + args.first() + .map(|value| value.eq_ignore_ascii_case(expected)) + .unwrap_or(false) +} + pub fn command_key(command: &str, args: &[&str]) -> String { - match command { + let normalized = command.to_lowercase(); + + match normalized.as_str() { "ticket" => "ticket_settings".to_string(), - "claim" => "claim".to_string(), - "rename" => "rename".to_string(), "add" => "ticket_add".to_string(), - "del" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("perm")) - .unwrap_or(false) - { - "del_perm".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("sanction")) - .unwrap_or(false) - { - "del_sanction".to_string() - } else { - "ticket_remove".to_string() - } - } + "del" => "ticket_remove".to_string(), "close" => "ticket_close".to_string(), - "tickets" => "tickets".to_string(), - "show" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("pics")) - .unwrap_or(false) - { - "show_pics".to_string() - } else { - "show".to_string() - } - } - "showpics" => "show_pics".to_string(), + "clear" => "clearmessages".to_string(), "suggestion" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("settings")) - .unwrap_or(false) - { + if first_arg_is(args, "settings") { "suggestion_settings".to_string() } else { "suggestion_create".to_string() } } - "autopublish" => "autopublish".to_string(), - "tempvoc" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("cmd")) - .unwrap_or(false) - { - "tempvoc_cmd".to_string() - } else { - "tempvoc".to_string() - } - } - "clear" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("owners")) - .unwrap_or(false) - { - "clear_owners".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("bl")) - .unwrap_or(false) - { - "clear_bl".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("limit")) - .unwrap_or(false) - { - "clear_limit".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("badwords")) - .unwrap_or(false) - { - "clear_badwords".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("perms")) - .unwrap_or(false) - { - "clear_perms".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("sanctions")) - .unwrap_or(false) - { - "clear_sanctions".to_string() - } else if args.len() >= 2 - && args[0].eq_ignore_ascii_case("all") - && args[1].eq_ignore_ascii_case("sanctions") - { - "clear_all_sanctions".to_string() - } else { - "clear_messages".to_string() - } - } "change" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("reset")) - .unwrap_or(false) - { - "change_reset".to_string() + if first_arg_is(args, "reset") { + "changereset".to_string() } else { "change".to_string() } } - "remove" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("activity")) - .unwrap_or(false) - { - "remove_activity".to_string() - } else { - "remove".to_string() - } - } - "set" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("perm")) - .unwrap_or(false) - { - "set_perm".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("muterole")) - .unwrap_or(false) - { - "set_muterole".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("modlogs")) - .unwrap_or(false) - { - "set_modlogs".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("boostembed")) - .unwrap_or(false) - { - "set_boostembed".to_string() - } else { - "set".to_string() - } - } - "mp" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("settings")) - .unwrap_or(false) - { - "mp_settings".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("sent")) - .unwrap_or(false) - { - "mp".to_string() - } else if args - .first() - .map(|s| s.eq_ignore_ascii_case("delete") || s.eq_ignore_ascii_case("del")) - .unwrap_or(false) - { - "mp".to_string() - } else { - "mp".to_string() - } - } "server" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("list")) - .unwrap_or(false) - { - "server_list".to_string() + if first_arg_is(args, "list") { + "serverlist".to_string() } else { "server".to_string() } } "end" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("giveaway")) - .unwrap_or(false) - { - "end_giveaway".to_string() + if first_arg_is(args, "giveaway") { + "endgiveaway".to_string() } else { "end".to_string() } } - "help" => "help".to_string(), - "helpsetting" => "helpsetting".to_string(), - "helpetting" => "helpsetting".to_string(), - "alias" => "alias".to_string(), - "modlog" => "modlog".to_string(), - "messagelog" => "messagelog".to_string(), - "voicelog" => "voicelog".to_string(), - "boostlog" => "boostlog".to_string(), - "rolelog" => "rolelog".to_string(), - "raidlog" => "raidlog".to_string(), - "autoconfiglog" => "autoconfiglog".to_string(), - "join" => "join".to_string(), - "boostembed" => "boostembed".to_string(), - "nolog" => "nolog".to_string(), - "invite" => "invite".to_string(), - "leave" => { - if args - .first() - .map(|s| s.eq_ignore_ascii_case("settings")) - .unwrap_or(false) - { - "leave_settings".to_string() + "mp" => { + if first_arg_is(args, "settings") { + "mpsettings".to_string() } else { - "leave".to_string() + "mp".to_string() } } - "discussion" => "discussion".to_string(), - other => other.to_string(), + "mpsent" | "mpdelete" | "mpdel" => "mp".to_string(), + "helpetting" => "helpsetting".to_string(), + _ => normalized, } } pub fn all_command_keys() -> Vec { - vec![ - "ping", - "allbots", - "alladmins", - "botadmins", - "boosters", - "rolemembers", - "rolemenu", - "ancien", - "serverinfo", - "vocinfo", - "role", - "channel", - "user", - "member", - "pic", - "banner", - "server", - "snipe", - "emoji", - "giveaway", - "end", - "end_giveaway", - "sanctions", - "del_sanction", - "clear_sanctions", - "clear_all_sanctions", - "clear_messages", - "clear_limit", - "clear_badwords", - "timeout", - "muterole", - "set_muterole", - "antispam", - "antiraideautoconfig", - "antilink", - "antimassmention", - "badwords", - "spam", - "link", - "strikes", - "punish", - "noderank", - "public", - "resetantiraide", - "warn", - "mute", - "tempmute", - "unmute", - "cmute", - "tempcmute", - "uncmute", - "mutelist", - "unmuteall", - "kick", - "ban", - "tempban", - "unban", - "banlist", - "slowmode", - "lock", - "unlock", - "lockall", - "unlockall", - "hide", - "unhide", - "hideall", - "unhideall", - "addrole", - "delrole", - "derank", - "reroll", - "choose", - "embed", - "backup", - "ticket_settings", - "claim", - "rename", - "ticket_add", - "ticket_remove", - "ticket_close", - "tickets", - "show_pics", - "piconly", - "suggestion_create", - "suggestion_settings", - "autopublish", - "tempvoc", - "tempvoc_cmd", - "autobackup", - "loading", - "create", - "newsticker", - "massiverole", - "unmassiverole", - "voicemove", - "voicekick", - "cleanup", - "bringall", - "renew", - "unbanall", - "temprole", - "untemprole", - "sync", - "button", - "autoreact", - "calc", - "shadowbot", - "set", - "set_modlogs", - "set_boostembed", - "theme", - "playto", - "listen", - "watch", - "compet", - "stream", - "remove_activity", - "online", - "idle", - "dnd", - "invisible", - "owner", - "unowner", - "clear_owners", - "bl", - "unbl", - "blinfo", - "clear_bl", - "say", - "change", - "changeall", - "change_reset", - "mainprefix", - "prefix", - "perms", - "set_perm", - "del_perm", - "clear_perms", - "allperms", - "help", - "helpsetting", - "alias", - "modlog", - "messagelog", - "voicelog", - "boostlog", - "rolelog", - "raidlog", - "autoconfiglog", - "join", - "leave_settings", - "boostembed", - "nolog", - "mp", - "mp_settings", - "server_list", - "invite", - "leave", - "discussion", - ] - .into_iter() - .map(String::from) - .collect() + let mut keys = BTreeSet::new(); + + for meta in crate::commands::all_command_metadata() { + keys.insert(command_key(meta.name, &[])); + } + + for key in EXTRA_COMMAND_KEYS { + keys.insert((*key).to_string()); + } + + keys.into_iter().collect() +} + +fn metadata_key_for_permission(command_key: &str) -> &str { + match command_key { + "ticket_settings" => "ticket", + "ticket_add" | "ticket_remove" => "add", + "ticket_close" => "close", + "suggestion_create" | "suggestion_settings" => "suggestion", + "setperm" => "set", + "delperm" => "del", + "changereset" => "change", + "serverlist" => "server", + "endgiveaway" => "end", + "mpsettings" => "mp", + _ => command_key, + } } pub fn default_permission(command_key: &str) -> u8 { - match command_key { - "ticket_settings" | "suggestion_settings" | "autopublish" | "piconly" | "tempvoc" => 8, - "claim" | "rename" | "ticket_add" | "ticket_remove" | "ticket_close" | "tickets" => 2, - "show_pics" | "suggestion_create" | "tempvoc_cmd" => 0, - "owner" | "unowner" | "clear_owners" => 9, - "bl" | "unbl" | "blinfo" | "clear_bl" => 9, - "change" | "changeall" | "change_reset" | "mainprefix" | "set_perm" | "del_perm" - | "clear_perms" => 9, - "set_modlogs" | "set_boostembed" | "set_muterole" => 8, - "prefix" | "perms" | "allperms" => 8, - "help" | "server_list" => 0, - "helpsetting" | "alias" | "leave" => 9, - "mp_settings" => 9, - "mp" | "mp_sent" | "mp_delete" | "invite" | "discussion" => 8, - "set" - | "theme" - | "playto" - | "listen" - | "watch" - | "compet" - | "stream" - | "remove_activity" - | "online" - | "idle" - | "dnd" - | "invisible" - | "say" - | "giveaway" - | "end_giveaway" - | "reroll" - | "choose" - | "embed" - | "backup" - | "autobackup" - | "loading" - | "create" - | "newsticker" - | "massiverole" - | "unmassiverole" - | "voicemove" - | "voicekick" - | "cleanup" - | "bringall" - | "renew" - | "unbanall" - | "temprole" - | "untemprole" - | "sync" - | "button" - | "autoreact" - | "sanctions" - | "del_sanction" - | "clear_sanctions" - | "clear_all_sanctions" - | "clear_messages" - | "clear_limit" - | "clear_badwords" - | "timeout" - | "muterole" - | "antispam" - | "antiraideautoconfig" - | "antilink" - | "antimassmention" - | "badwords" - | "spam" - | "link" - | "strikes" - | "punish" - | "noderank" - | "public" - | "resetantiraide" - | "warn" - | "mute" - | "tempmute" - | "unmute" - | "cmute" - | "tempcmute" - | "uncmute" - | "mutelist" - | "unmuteall" - | "kick" - | "ban" - | "tempban" - | "unban" - | "banlist" - | "slowmode" - | "lock" - | "unlock" - | "lockall" - | "unlockall" - | "hide" - | "unhide" - | "hideall" - | "unhideall" - | "addrole" - | "delrole" - | "derank" - | "rolemenu" - | "ancien" - | "modlog" - | "messagelog" - | "voicelog" - | "boostlog" - | "rolelog" - | "raidlog" - | "autoconfiglog" - | "join" - | "boostembed" - | "leave_settings" - | "nolog" => 8, - _ => 0, - } + let metadata_key = metadata_key_for_permission(command_key); + crate::commands::command_metadata_by_key(metadata_key) + .map(|meta| meta.default_permission) + .unwrap_or(0) } fn is_forced_owner_from_env(user_id: UserId) -> bool {