diff --git a/src/commands/automation/autopublish.rs b/src/commands/automation/autopublish.rs index 8ee144b..77b82c3 100644 --- a/src/commands/automation/autopublish.rs +++ b/src/commands/automation/autopublish.rs @@ -12,49 +12,13 @@ pub async fn handle_autopublish(ctx: &Context, msg: &Message, args: &[&str]) { return; }; - if args.is_empty() { - let Some(pool) = ({ - let data = ctx.data.read().await; - data.get::().cloned() - }) else { - return; - }; - - let bot_id = ctx.cache.current_user().id.get() as i64; - let channels = db::get_autopublish_channels(&pool, bot_id, guild_id.get() as i64) - .await - .unwrap_or_default(); - let description = if channels.is_empty() { - "Aucun salon d'annonces configuré.".to_string() - } else { - channels - .into_iter() - .map(|channel| format!("<#{}>", channel.channel_id)) - .collect::>() - .join("\n") - }; - + if !args.is_empty() { send_embed( ctx, msg, CreateEmbed::new() .title("Autopublish") - .description(description) - .colour(Colour::from_rgb(100, 150, 255)), - ) - .await; - return; - } - - let enabled = args[0].eq_ignore_ascii_case("on") || args[0].eq_ignore_ascii_case("enable"); - let disabled = args[0].eq_ignore_ascii_case("off") || args[0].eq_ignore_ascii_case("disable"); - if !enabled && !disabled { - send_embed( - ctx, - msg, - CreateEmbed::new() - .title("Autopublish") - .description("Utilisation: +autopublish on|off [#canal]") + .description("Utilisation: +autopublish") .color(0xED4245), ) .await; @@ -68,18 +32,53 @@ pub async fn handle_autopublish(ctx: &Context, msg: &Message, args: &[&str]) { return; }; + let bot_id = ctx.cache.current_user().id.get() as i64; + let guild_id_i64 = guild_id.get() as i64; + + let channels = db::get_autopublish_channels(&pool, bot_id, guild_id_i64) + .await + .unwrap_or_default(); + let description = if channels.is_empty() { + "Aucun salon d'annonces configuré.".to_string() + } else { + channels + .into_iter() + .map(|channel| format!("<#{}>", channel.channel_id)) + .collect::>() + .join("\n") + }; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Autopublish") + .description(description) + .colour(Colour::from_rgb(100, 150, 255)), + ) + .await; +} + +pub async fn handle_autopublishon(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Some(pool) = ({ + let data = ctx.data.read().await; + data.get::().cloned() + }) else { + return; + }; + let bot_id = ctx.cache.current_user().id.get() as i64; let guild_id_i64 = guild_id.get() as i64; let channel_id = args - .get(1) + .first() .and_then(|value| parse_channel_id(value)) .unwrap_or(msg.channel_id); - let result = if enabled { - db::add_autopublish_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await - } else { - db::remove_autopublish_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await - }; + let result = db::add_autopublish_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await; if result.is_err() { send_embed( @@ -94,21 +93,63 @@ pub async fn handle_autopublish(ctx: &Context, msg: &Message, args: &[&str]) { return; } - let embed = if enabled { + send_embed( + ctx, + msg, CreateEmbed::new() .title("Autopublish activé") .description(format!("Salon: <#{}>", channel_id.get())) .colour(Colour::from_rgb(0, 200, 120)) - .timestamp(Utc::now()) - } else { + .timestamp(Utc::now()), + ) + .await; +} + +pub async fn handle_autopublishoff(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Some(pool) = ({ + let data = ctx.data.read().await; + data.get::().cloned() + }) else { + return; + }; + + let bot_id = ctx.cache.current_user().id.get() as i64; + let guild_id_i64 = guild_id.get() as i64; + let channel_id = args + .first() + .and_then(|value| parse_channel_id(value)) + .unwrap_or(msg.channel_id); + + let result = + db::remove_autopublish_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await; + + if result.is_err() { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Autopublish") + .description("Impossible de mettre à jour le salon d'annonces.") + .color(0xED4245), + ) + .await; + return; + } + + send_embed( + ctx, + msg, CreateEmbed::new() .title("Autopublish désactivé") .description(format!("Salon: <#{}>", channel_id.get())) .colour(Colour::from_rgb(255, 120, 0)) - .timestamp(Utc::now()) - }; - - send_embed(ctx, msg, embed).await; + .timestamp(Utc::now()), + ) + .await; } pub struct AutopublishCommand; @@ -119,13 +160,9 @@ impl crate::commands::command_contract::CommandSpec for AutopublishCommand { crate::commands::command_contract::CommandMetadata { name: "autopublish", category: "automation", - params: "on|off [#canal]", - description: "Affiche, active ou desactive la publication automatique des annonces.", - examples: &[ - "+autopublish", - "+autopublish on #annonces", - "+help autopublish", - ], + params: "aucun", + description: "Affiche les salons ou la publication automatique des annonces est active.", + examples: &["+autopublish", "+help autopublish"], default_aliases: &["apb"], allow_in_dm: false, default_permission: 5, diff --git a/src/commands/automation/autopublishoff.rs b/src/commands/automation/autopublishoff.rs new file mode 100644 index 0000000..911d4a7 --- /dev/null +++ b/src/commands/automation/autopublishoff.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_autopublishoff_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::autopublish::handle_autopublishoff(ctx, msg, args).await; +} + +pub struct AutopublishoffCommand; +pub static COMMAND_DESCRIPTOR: AutopublishoffCommand = AutopublishoffCommand; + +impl crate::commands::command_contract::CommandSpec for AutopublishoffCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "autopublishoff", + category: "automation", + params: "[#canal]", + description: "Desactive la publication automatique des annonces sur un salon.", + examples: &["+autopublishoff", "+autopublishoff #annonces", "+help autopublishoff"], + default_aliases: &["apboff"], + allow_in_dm: false, + default_permission: 5, + } + } +} diff --git a/src/commands/automation/autopublishon.rs b/src/commands/automation/autopublishon.rs new file mode 100644 index 0000000..a584bb9 --- /dev/null +++ b/src/commands/automation/autopublishon.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_autopublishon_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::autopublish::handle_autopublishon(ctx, msg, args).await; +} + +pub struct AutopublishonCommand; +pub static COMMAND_DESCRIPTOR: AutopublishonCommand = AutopublishonCommand; + +impl crate::commands::command_contract::CommandSpec for AutopublishonCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "autopublishon", + category: "automation", + params: "[#canal]", + description: "Active la publication automatique des annonces sur un salon.", + examples: &["+autopublishon", "+autopublishon #annonces", "+help autopublishon"], + default_aliases: &["apbon"], + allow_in_dm: false, + default_permission: 5, + } + } +} diff --git a/src/commands/automation/piconly.rs b/src/commands/automation/piconly.rs index c0cbae2..85bd22e 100644 --- a/src/commands/automation/piconly.rs +++ b/src/commands/automation/piconly.rs @@ -106,61 +106,65 @@ pub async fn handle_piconly(ctx: &Context, msg: &Message, args: &[&str]) { let bot_id = ctx.cache.current_user().id.get() as i64; let guild_id_i64 = guild_id.get() as i64; - if args.is_empty() { - let channels = db::get_piconly_channels(&pool, bot_id, guild_id_i64) - .await - .unwrap_or_default(); - - let description = if channels.is_empty() { - "Aucun salon selfie configure.".to_string() - } else { - channels - .into_iter() - .map(|channel| format!("<#{}>", channel.channel_id)) - .collect::>() - .join("\n") - }; - + if !args.is_empty() { send_embed( ctx, msg, CreateEmbed::new() .title("PicOnly") - .description(description) - .timestamp(Utc::now()), - ) - .await; - return; - } - - let adding = args[0].eq_ignore_ascii_case("add"); - let deleting = args[0].eq_ignore_ascii_case("del") - || args[0].eq_ignore_ascii_case("remove") - || args[0].eq_ignore_ascii_case("delete"); - - if !adding && !deleting { - send_embed( - ctx, - msg, - CreateEmbed::new() - .title("PicOnly") - .description("Utilisation: +piconly [#salon]") + .description("Utilisation: +piconly") .color(0xED4245), ) .await; return; } + let channels = db::get_piconly_channels(&pool, bot_id, guild_id_i64) + .await + .unwrap_or_default(); + + let description = if channels.is_empty() { + "Aucun salon selfie configure.".to_string() + } else { + channels + .into_iter() + .map(|channel| format!("<#{}>", channel.channel_id)) + .collect::>() + .join("\n") + }; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("PicOnly") + .description(description) + .timestamp(Utc::now()), + ) + .await; +} + +pub async fn handle_piconlyadd(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Some(pool) = ({ + let data = ctx.data.read().await; + data.get::().cloned() + }) else { + return; + }; + + let bot_id = ctx.cache.current_user().id.get() as i64; + let guild_id_i64 = guild_id.get() as i64; + let channel_id = args - .get(1) + .first() .and_then(|raw| parse_channel_id(raw)) .unwrap_or(msg.channel_id); - let result = if adding { - db::add_piconly_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await - } else { - db::remove_piconly_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await - }; + let result = db::add_piconly_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await; if result.is_err() { send_embed( @@ -175,19 +179,61 @@ pub async fn handle_piconly(ctx: &Context, msg: &Message, args: &[&str]) { return; } - let embed = if adding { + send_embed( + ctx, + msg, CreateEmbed::new() .title("Salon selfie ajoute") .description(format!("Salon: <#{}>", channel_id.get())) - .timestamp(Utc::now()) - } else { + .timestamp(Utc::now()), + ) + .await; +} + +pub async fn handle_piconlydel(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Some(pool) = ({ + let data = ctx.data.read().await; + data.get::().cloned() + }) else { + return; + }; + + let bot_id = ctx.cache.current_user().id.get() as i64; + let guild_id_i64 = guild_id.get() as i64; + + let channel_id = args + .first() + .and_then(|raw| parse_channel_id(raw)) + .unwrap_or(msg.channel_id); + + let result = db::remove_piconly_channel(&pool, bot_id, guild_id_i64, channel_id.get() as i64).await; + + if result.is_err() { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("PicOnly") + .description("Impossible de mettre a jour le salon selfie.") + .color(0xED4245), + ) + .await; + return; + } + + send_embed( + ctx, + msg, CreateEmbed::new() .title("Salon selfie retire") .description(format!("Salon: <#{}>", channel_id.get())) - .timestamp(Utc::now()) - }; - - send_embed(ctx, msg, embed).await; + .timestamp(Utc::now()), + ) + .await; } pub struct PiconlyCommand; @@ -198,9 +244,9 @@ impl crate::commands::command_contract::CommandSpec for PiconlyCommand { crate::commands::command_contract::CommandMetadata { name: "piconly", category: "automation", - params: " [salon]", - description: "Definit ou supprime un salon selfie, ou les membres ne peuvent envoyer que des photos.", - examples: &["+piconly", "+piconly add #selfie", "+piconly del #selfie"], + params: "aucun", + description: "Affiche la liste des salons selfie, ou les membres ne peuvent envoyer que des photos.", + examples: &["+piconly", "+help piconly"], default_aliases: &["selfieonly"], allow_in_dm: false, default_permission: 6, diff --git a/src/commands/automation/piconlyadd.rs b/src/commands/automation/piconlyadd.rs new file mode 100644 index 0000000..7a24bc7 --- /dev/null +++ b/src/commands/automation/piconlyadd.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_piconlyadd_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::piconly::handle_piconlyadd(ctx, msg, args).await; +} + +pub struct PiconlyaddCommand; +pub static COMMAND_DESCRIPTOR: PiconlyaddCommand = PiconlyaddCommand; + +impl crate::commands::command_contract::CommandSpec for PiconlyaddCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "piconlyadd", + category: "automation", + params: "[#salon]", + description: "Ajoute un salon selfie (photos uniquement).", + examples: &["+piconlyadd", "+piconlyadd #selfie", "+help piconlyadd"], + default_aliases: &["selfieadd"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/automation/piconlydel.rs b/src/commands/automation/piconlydel.rs new file mode 100644 index 0000000..c8a6dac --- /dev/null +++ b/src/commands/automation/piconlydel.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_piconlydel_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::piconly::handle_piconlydel(ctx, msg, args).await; +} + +pub struct PiconlydelCommand; +pub static COMMAND_DESCRIPTOR: PiconlydelCommand = PiconlydelCommand; + +impl crate::commands::command_contract::CommandSpec for PiconlydelCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "piconlydel", + category: "automation", + params: "[#salon]", + description: "Retire un salon selfie (photos uniquement).", + examples: &["+piconlydel", "+piconlydel #selfie", "+help piconlydel"], + default_aliases: &["selfiedel"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/botconfig/change.rs b/src/commands/botconfig/change.rs index 87152de..d6b3100 100644 --- a/src/commands/botconfig/change.rs +++ b/src/commands/botconfig/change.rs @@ -6,6 +6,29 @@ use crate::commands::common::send_embed; use crate::commands::perms_helpers::{ensure_owner, get_pool, normalize_command_name}; use crate::db::{reset_command_permissions, set_command_permission}; +pub async fn handle_changereset(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 = reset_command_permissions(&pool, bot_id).await.unwrap_or(0); + let embed = CreateEmbed::new() + .title("Permissions reinitialisees") + .description(format!("Overrides supprimes: {}", removed)) + .color(0x57F287); + send_embed(ctx, msg, embed).await; +} + pub async fn handle_change(ctx: &Context, msg: &Message, args: &[&str]) { if !ensure_owner(ctx, msg).await { return; @@ -21,20 +44,6 @@ pub async fn handle_change(ctx: &Context, msg: &Message, args: &[&str]) { return; }; - if args - .first() - .map(|s| s.eq_ignore_ascii_case("reset")) - .unwrap_or(false) - { - let removed = reset_command_permissions(&pool, bot_id).await.unwrap_or(0); - let embed = CreateEmbed::new() - .title("Permissions reinitialisees") - .description(format!("Overrides supprimes: {}", removed)) - .color(0x57F287); - send_embed(ctx, msg, embed).await; - return; - } - if args.len() < 2 { let embed = CreateEmbed::new() .title("Erreur") @@ -79,8 +88,8 @@ impl crate::commands::command_contract::CommandSpec for ChangeCommand { crate::commands::command_contract::CommandMetadata { name: "change", category: "botconfig", - params: " | reset", - description: "Definit le niveau ACL requis pour une commande ou reinitialise les overrides.", + params: " ", + description: "Definit le niveau ACL requis pour une commande cible.", examples: &["+change", "+ce", "+help change"], default_aliases: &["chg"], allow_in_dm: false, diff --git a/src/commands/botconfig/changereset.rs b/src/commands/botconfig/changereset.rs new file mode 100644 index 0000000..0f4db6a --- /dev/null +++ b/src/commands/botconfig/changereset.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_changereset_command(ctx: &Context, msg: &Message, _args: &[&str]) { + crate::commands::change::handle_changereset(ctx, msg).await; +} + +pub struct ChangeresetCommand; +pub static COMMAND_DESCRIPTOR: ChangeresetCommand = ChangeresetCommand; + +impl crate::commands::command_contract::CommandSpec for ChangeresetCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "changereset", + category: "botconfig", + params: "aucun", + description: "Reinitialise tous les overrides ACL des commandes.", + examples: &["+changereset", "+help changereset"], + default_aliases: &["chgr"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/botconfig/set.rs b/src/commands/botconfig/set.rs index 6f1fe6a..dfd5ed3 100644 --- a/src/commands/botconfig/set.rs +++ b/src/commands/botconfig/set.rs @@ -8,12 +8,12 @@ use crate::commands::perms_helpers::{ }; use crate::db::{grant_command_access, grant_perm_level}; -async fn handle_set_perm(ctx: &Context, msg: &Message, args: &[&str]) { +pub async fn handle_setperm(ctx: &Context, msg: &Message, args: &[&str]) { if !ensure_owner(ctx, msg).await { return; } - if args.len() < 3 || !args[0].eq_ignore_ascii_case("perm") { + if args.len() < 2 { let embed = CreateEmbed::new() .title("Erreur") .description("Usage: `+setperm `") @@ -22,7 +22,7 @@ async fn handle_set_perm(ctx: &Context, msg: &Message, args: &[&str]) { return; } - let Some((scope_type, scope_id)) = parse_user_or_role(args[2]) else { + let Some((scope_type, scope_id)) = parse_user_or_role(args[1]) else { let embed = CreateEmbed::new() .title("Erreur") .description("Role/membre invalide.") @@ -41,7 +41,7 @@ async fn handle_set_perm(ctx: &Context, msg: &Message, args: &[&str]) { return; }; - if let Ok(level) = args[1].parse::() { + if let Ok(level) = args[0].parse::() { if level > 9 { let embed = CreateEmbed::new() .title("Erreur") @@ -65,7 +65,7 @@ async fn handle_set_perm(ctx: &Context, msg: &Message, args: &[&str]) { return; } - let command = normalize_command_name(args[1]); + let command = normalize_command_name(args[0]); let _ = grant_command_access(&pool, bot_id, scope_type, scope_id, &command).await; let who = if scope_type == "role" { @@ -81,254 +81,209 @@ async fn handle_set_perm(ctx: &Context, msg: &Message, args: &[&str]) { send_embed(ctx, msg, embed).await; } -pub async fn handle_set(ctx: &Context, msg: &Message, args: &[&str]) { - if args - .first() - .map(|a| a.eq_ignore_ascii_case("perm")) - .unwrap_or(false) - { - handle_set_perm(ctx, msg, args).await; - return; - } - +pub async fn handle_setname(ctx: &Context, msg: &Message, args: &[&str]) { if args.is_empty() { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+set name|pic|banner|profil ...`") + .description("Usage: `+setname `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; } - let sub = args[0].to_lowercase(); - - match sub.as_str() { - "name" => { - if args.len() < 2 { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Usage: `+set name `") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - let name = args[1..].join(" "); - let mut me = match ctx.http.get_current_user().await { - Ok(user) => user, - Err(err) => { - let embed = CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de charger le profil bot: {}", err)) - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - }; - - let result = me - .edit(&ctx.http, EditProfile::new().username(name.clone())) - .await; - let embed = match result { - Ok(_) => CreateEmbed::new() - .title("Profil mis à jour") - .description(format!("Nom défini sur: {}", name)) - .color(0x57F287), - Err(err) => CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de modifier le nom: {}", err)) - .color(0xED4245), - }; - send_embed(ctx, msg, embed).await; - } - "pic" => { - if args.len() < 2 { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Usage: `+set pic `") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - let Ok(attachment) = CreateAttachment::url(&ctx.http, args[1]).await else { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Impossible de télécharger l'image.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - }; - - let mut me = match ctx.http.get_current_user().await { - Ok(user) => user, - Err(err) => { - let embed = CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de charger le profil bot: {}", err)) - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - }; - - let result = me - .edit(&ctx.http, EditProfile::new().avatar(&attachment)) - .await; - let embed = match result { - Ok(_) => CreateEmbed::new() - .title("Profil mis à jour") - .description("Photo de profil modifiée.") - .color(0x57F287), - Err(err) => CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de modifier la photo: {}", err)) - .color(0xED4245), - }; - send_embed(ctx, msg, embed).await; - } - "banner" => { - if args.len() < 2 { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Usage: `+set banner `") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - let Ok(attachment) = CreateAttachment::url(&ctx.http, args[1]).await else { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Impossible de télécharger l'image.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - }; - - let mut me = match ctx.http.get_current_user().await { - Ok(user) => user, - Err(err) => { - let embed = CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de charger le profil bot: {}", err)) - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - }; - - let result = me - .edit(&ctx.http, EditProfile::new().banner(&attachment)) - .await; - let embed = match result { - Ok(_) => CreateEmbed::new() - .title("Profil mis à jour") - .description("Bannière modifiée.") - .color(0x57F287), - Err(err) => CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de modifier la bannière: {}", err)) - .color(0xED4245), - }; - send_embed(ctx, msg, embed).await; - } - "profil" => { - let raw = args[1..].join(" "); - let parts: Vec<&str> = raw.split(";;").map(|s| s.trim()).collect(); - - if parts.len() != 3 { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Usage: `+set profil ;; ;; `") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - let mut builder = EditProfile::new(); - - if !parts[0].is_empty() { - builder = builder.username(parts[0].to_string()); - } - - if !parts[1].is_empty() { - match CreateAttachment::url(&ctx.http, parts[1]).await { - Ok(avatar) => builder = builder.avatar(&avatar), - Err(_) => { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Image avatar invalide dans `+set profil`. ") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - } - } - - if !parts[2].is_empty() { - match CreateAttachment::url(&ctx.http, parts[2]).await { - Ok(banner) => builder = builder.banner(&banner), - Err(_) => { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Image bannière invalide dans `+set profil`. ") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - } - } - - let mut me = match ctx.http.get_current_user().await { - Ok(user) => user, - Err(err) => { - let embed = CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de charger le profil bot: {}", err)) - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - }; - - let result = me.edit(&ctx.http, builder).await; - let embed = match result { - Ok(_) => CreateEmbed::new() - .title("Profil mis à jour") - .description("Nom, avatar et bannière traités.") - .color(0x57F287), - Err(err) => CreateEmbed::new() - .title("Erreur") - .description(format!("Impossible de modifier le profil: {}", err)) - .color(0xED4245), - }; - send_embed(ctx, msg, embed).await; - } - _ => { + let name = args.join(" "); + let mut me = match ctx.http.get_current_user().await { + Ok(user) => user, + Err(err) => { let embed = CreateEmbed::new() .title("Erreur") - .description("Sous-commande inconnue. Utilise `name`, `pic`, `banner` ou `profil`.") + .description(format!("Impossible de charger le profil bot: {}", err)) .color(0xED4245); send_embed(ctx, msg, embed).await; + return; } - } + }; + + let result = me + .edit(&ctx.http, EditProfile::new().username(name.clone())) + .await; + let embed = match result { + Ok(_) => CreateEmbed::new() + .title("Profil mis à jour") + .description(format!("Nom défini sur: {}", name)) + .color(0x57F287), + Err(err) => CreateEmbed::new() + .title("Erreur") + .description(format!("Impossible de modifier le nom: {}", err)) + .color(0xED4245), + }; + send_embed(ctx, msg, embed).await; } -pub struct SetCommand; -pub static COMMAND_DESCRIPTOR: SetCommand = SetCommand; +pub async fn handle_setpic(ctx: &Context, msg: &Message, args: &[&str]) { + if args.is_empty() { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Usage: `+setpic `") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } -impl crate::commands::command_contract::CommandSpec for SetCommand { - fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { - crate::commands::command_contract::CommandMetadata { - name: "set", - category: "botconfig", - params: "name | pic | banner | profil ;; ;; | perm ...", - description: "Modifie le nom, lavatar, la banniere ou des options avancees via les sous commandes.", - examples: &["+set", "+st", "+help set"], - default_aliases: &["cfg"], - allow_in_dm: false, - default_permission: 9, + let Ok(attachment) = CreateAttachment::url(&ctx.http, args[0]).await else { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Impossible de télécharger l'image.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let mut me = match ctx.http.get_current_user().await { + Ok(user) => user, + Err(err) => { + let embed = CreateEmbed::new() + .title("Erreur") + .description(format!("Impossible de charger le profil bot: {}", err)) + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + }; + + let result = me + .edit(&ctx.http, EditProfile::new().avatar(&attachment)) + .await; + let embed = match result { + Ok(_) => CreateEmbed::new() + .title("Profil mis à jour") + .description("Photo de profil modifiée.") + .color(0x57F287), + Err(err) => CreateEmbed::new() + .title("Erreur") + .description(format!("Impossible de modifier la photo: {}", err)) + .color(0xED4245), + }; + send_embed(ctx, msg, embed).await; +} + +pub async fn handle_setbanner(ctx: &Context, msg: &Message, args: &[&str]) { + if args.is_empty() { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Usage: `+setbanner `") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + + let Ok(attachment) = CreateAttachment::url(&ctx.http, args[0]).await else { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Impossible de télécharger l'image.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let mut me = match ctx.http.get_current_user().await { + Ok(user) => user, + Err(err) => { + let embed = CreateEmbed::new() + .title("Erreur") + .description(format!("Impossible de charger le profil bot: {}", err)) + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + }; + + let result = me + .edit(&ctx.http, EditProfile::new().banner(&attachment)) + .await; + let embed = match result { + Ok(_) => CreateEmbed::new() + .title("Profil mis à jour") + .description("Bannière modifiée.") + .color(0x57F287), + Err(err) => CreateEmbed::new() + .title("Erreur") + .description(format!("Impossible de modifier la bannière: {}", err)) + .color(0xED4245), + }; + send_embed(ctx, msg, embed).await; +} + +pub async fn handle_setprofil(ctx: &Context, msg: &Message, args: &[&str]) { + let raw = args.join(" "); + let parts: Vec<&str> = raw.split(";;").map(|s| s.trim()).collect(); + + if parts.len() != 3 { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Usage: `+setprofil ;; ;; `") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + + let mut builder = EditProfile::new(); + + if !parts[0].is_empty() { + builder = builder.username(parts[0].to_string()); + } + + if !parts[1].is_empty() { + match CreateAttachment::url(&ctx.http, parts[1]).await { + Ok(avatar) => builder = builder.avatar(&avatar), + Err(_) => { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Image avatar invalide dans `+setprofil`.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } } } + + if !parts[2].is_empty() { + match CreateAttachment::url(&ctx.http, parts[2]).await { + Ok(banner) => builder = builder.banner(&banner), + Err(_) => { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Image bannière invalide dans `+setprofil`.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + } + } + + let mut me = match ctx.http.get_current_user().await { + Ok(user) => user, + Err(err) => { + let embed = CreateEmbed::new() + .title("Erreur") + .description(format!("Impossible de charger le profil bot: {}", err)) + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + }; + + let result = me.edit(&ctx.http, builder).await; + let embed = match result { + Ok(_) => CreateEmbed::new() + .title("Profil mis à jour") + .description("Nom, avatar et bannière traités.") + .color(0x57F287), + Err(err) => CreateEmbed::new() + .title("Erreur") + .description(format!("Impossible de modifier le profil: {}", err)) + .color(0xED4245), + }; + send_embed(ctx, msg, embed).await; } + diff --git a/src/commands/botconfig/setbanner.rs b/src/commands/botconfig/setbanner.rs new file mode 100644 index 0000000..c2dfe41 --- /dev/null +++ b/src/commands/botconfig/setbanner.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_setbanner_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::set::handle_setbanner(ctx, msg, args).await; +} + +pub struct SetbannerCommand; +pub static COMMAND_DESCRIPTOR: SetbannerCommand = SetbannerCommand; + +impl crate::commands::command_contract::CommandSpec for SetbannerCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setbanner", + category: "botconfig", + params: "", + description: "Modifie la banniere du bot.", + examples: &["+setbanner https://exemple/banner.png", "+help setbanner"], + default_aliases: &["stbn"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/botconfig/setname.rs b/src/commands/botconfig/setname.rs new file mode 100644 index 0000000..ff5d858 --- /dev/null +++ b/src/commands/botconfig/setname.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_setname_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::set::handle_setname(ctx, msg, args).await; +} + +pub struct SetnameCommand; +pub static COMMAND_DESCRIPTOR: SetnameCommand = SetnameCommand; + +impl crate::commands::command_contract::CommandSpec for SetnameCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setname", + category: "botconfig", + params: "", + description: "Modifie le nom du bot.", + examples: &["+setname MonBot", "+help setname"], + default_aliases: &["stn"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/botconfig/setperm.rs b/src/commands/botconfig/setperm.rs new file mode 100644 index 0000000..a1e04b1 --- /dev/null +++ b/src/commands/botconfig/setperm.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_setperm_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::set::handle_setperm(ctx, msg, args).await; +} + +pub struct SetpermCommand; +pub static COMMAND_DESCRIPTOR: SetpermCommand = SetpermCommand; + +impl crate::commands::command_contract::CommandSpec for SetpermCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setperm", + category: "botconfig", + params: " ", + description: "Attribue un niveau ACL ou un acces commande a un role ou membre.", + examples: &["+setperm 6 @Moderateur", "+setperm mute @Role", "+help setperm"], + default_aliases: &["stp"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/botconfig/setpic.rs b/src/commands/botconfig/setpic.rs new file mode 100644 index 0000000..d93ebe3 --- /dev/null +++ b/src/commands/botconfig/setpic.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_setpic_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::set::handle_setpic(ctx, msg, args).await; +} + +pub struct SetpicCommand; +pub static COMMAND_DESCRIPTOR: SetpicCommand = SetpicCommand; + +impl crate::commands::command_contract::CommandSpec for SetpicCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setpic", + category: "botconfig", + params: "", + description: "Modifie l'avatar du bot.", + examples: &["+setpic https://exemple/image.png", "+help setpic"], + default_aliases: &["stpic"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/botconfig/setprofil.rs b/src/commands/botconfig/setprofil.rs new file mode 100644 index 0000000..dae3553 --- /dev/null +++ b/src/commands/botconfig/setprofil.rs @@ -0,0 +1,27 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_setprofil_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::set::handle_setprofil(ctx, msg, args).await; +} + +pub struct SetprofilCommand; +pub static COMMAND_DESCRIPTOR: SetprofilCommand = SetprofilCommand; + +impl crate::commands::command_contract::CommandSpec for SetprofilCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "setprofil", + category: "botconfig", + params: " ;; ;; ", + description: "Met a jour en une commande le nom, l'avatar et la banniere du bot.", + examples: &[ + "+setprofil Shadow ;; https://img/a.png ;; https://img/b.png", + "+help setprofil", + ], + default_aliases: &["stpr"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/config/join.rs b/src/commands/config/join.rs index 0a9b7c5..47aaa14 100644 --- a/src/commands/config/join.rs +++ b/src/commands/config/join.rs @@ -15,20 +15,7 @@ pub async fn handle_join(ctx: &Context, msg: &Message, args: &[&str]) { }; 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("join settings") - .description("Usage: +join settings [on/off] [salon] [message...]") - .color(0xED4245), - ) - .await; - return; - } - - if args.len() == 1 { + if args.is_empty() { let row = sqlx::query_as::<_, (bool, Option, Option)>( r#" SELECT enabled, channel_id, custom_message @@ -70,14 +57,27 @@ pub async fn handle_join(ctx: &Context, msg: &Message, args: &[&str]) { return; } - let action = args[1].to_lowercase(); + let action = args[0].to_lowercase(); + if action != "on" && action != "off" { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("join settings") + .description("Usage: +joinsettings [on/off] [salon] [message...]") + .color(0xED4245), + ) + .await; + return; + } + let enabled = action == "on"; let channel = if enabled { - parse_target_channel(msg, args, 2) + parse_target_channel(msg, args, 1) } else { None }; - let message_start = if enabled { 3 } else { 2 }; + let message_start = if enabled { 2 } else { 1 }; let custom_message = if args.len() > message_start { Some(args[message_start..].join(" ")) } else { @@ -125,15 +125,15 @@ pub static COMMAND_DESCRIPTOR: JoinCommand = JoinCommand; impl crate::commands::command_contract::CommandSpec for JoinCommand { fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { crate::commands::command_contract::CommandMetadata { - name: "join", + name: "joinsettings", category: "config", - params: "settings [on/off] [salon] [message]", + params: "[on/off] [salon] [message]", description: "Permet de configurer les actions quand un membre rejoint.", examples: &[ - "+join settings", - "+join settings on #welcome Bienvenue {user}", + "+joinsettings", + "+joinsettings on #welcome Bienvenue {user}", ], - default_aliases: &["jset"], + default_aliases: &["jset", "join"], allow_in_dm: false, default_permission: 5, } diff --git a/src/commands/config/leave_settings.rs b/src/commands/config/leave_settings.rs deleted file mode 100644 index df1c1aa..0000000 --- a/src/commands/config/leave_settings.rs +++ /dev/null @@ -1,142 +0,0 @@ -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: "leave_settings", - 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/leavesettings.rs b/src/commands/config/leavesettings.rs index 13e51bc..e991314 100644 --- a/src/commands/config/leavesettings.rs +++ b/src/commands/config/leavesettings.rs @@ -16,7 +16,7 @@ pub async fn handle_leave_settings(ctx: &Context, msg: &Message, args: &[&str]) }; let bot_id = ctx.cache.current_user().id; - if args.is_empty() || !args[0].eq_ignore_ascii_case("settings") { + if args.is_empty() { send_embed( ctx, msg, @@ -71,14 +71,27 @@ pub async fn handle_leave_settings(ctx: &Context, msg: &Message, args: &[&str]) return; } - let action = args[1].to_lowercase(); + let action = args[0].to_lowercase(); + if action != "on" && action != "off" { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("leave settings") + .description("Usage: +leavesettings [on/off] [salon] [message...]") + .color(0xED4245), + ) + .await; + return; + } + let enabled = action == "on"; let channel = if enabled { - parse_target_channel(msg, args, 2) + parse_target_channel(msg, args, 1) } else { None }; - let message_start = if enabled { 3 } else { 2 }; + let message_start = if enabled { 2 } else { 1 }; let custom_message = if args.len() > message_start { Some(args[message_start..].join(" ")) } else { @@ -128,7 +141,7 @@ impl crate::commands::command_contract::CommandSpec for LeaveSettingsCommand { crate::commands::command_contract::CommandMetadata { name: "leavesettings", category: "config", - params: "settings [on/off] [salon] [message]", + params: "[on/off] [salon] [message]", description: "Configure les actions a executer quand un membre quitte le serveur.", examples: &[ "+leavesettings", diff --git a/src/commands/config/set_boostembed.rs b/src/commands/config/set_boostembed.rs deleted file mode 100644 index 3fe8293..0000000 --- a/src/commands/config/set_boostembed.rs +++ /dev/null @@ -1,115 +0,0 @@ -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: "set_boostembed", - 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/set_modlogs.rs b/src/commands/config/set_modlogs.rs deleted file mode 100644 index 8b32cfa..0000000 --- a/src/commands/config/set_modlogs.rs +++ /dev/null @@ -1,125 +0,0 @@ -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: "set_modlogs", - 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 b37b6c6..43f17cf 100644 --- a/src/commands/event/end.rs +++ b/src/commands/event/end.rs @@ -8,12 +8,8 @@ fn owned_component_id(action: &str, owner_id: UserId) -> String { format!("{}:{}", action, owner_id.get()) } -async fn handle_end_giveaway(ctx: &Context, msg: &Message, args: &[&str]) { - let message_id_raw = args - .get(1) - .or_else(|| args.first()) - .copied() - .unwrap_or_default(); +pub async fn handle_endgiveaway(ctx: &Context, msg: &Message, args: &[&str]) { + let message_id_raw = args.first().copied().unwrap_or_default(); let Ok(message_id) = message_id_raw.trim().parse::() else { send_embed( @@ -76,21 +72,12 @@ pub async fn handle_end(ctx: &Context, msg: &Message, args: &[&str]) { return; } - if args - .first() - .map(|v| v.eq_ignore_ascii_case("giveaway")) - .unwrap_or(false) - { - handle_end_giveaway(ctx, msg, args).await; - return; - } - send_embed( ctx, msg, CreateEmbed::new() .title("End") - .description("Usage: +endgiveaway ") + .description("Usage: +end") .color(0xED4245), ) .await; @@ -104,10 +91,10 @@ impl crate::commands::command_contract::CommandSpec for EndCommand { crate::commands::command_contract::CommandMetadata { name: "end", category: "event", - params: "giveaway ", - description: "Permet de stopper instantanement un giveaway avec l'identifiant du message.", - examples: &["+endgiveaway 123456789012345678"], - default_aliases: &["gend"], + params: "aucun", + description: "Affiche le panneau interactif pour terminer un giveaway.", + examples: &["+end", "+help end"], + default_aliases: &["endmenu"], allow_in_dm: false, default_permission: 6, } diff --git a/src/commands/event/endgiveaway.rs b/src/commands/event/endgiveaway.rs new file mode 100644 index 0000000..6dff26c --- /dev/null +++ b/src/commands/event/endgiveaway.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_endgiveaway_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::end::handle_endgiveaway(ctx, msg, args).await; +} + +pub struct EndgiveawayCommand; +pub static COMMAND_DESCRIPTOR: EndgiveawayCommand = EndgiveawayCommand; + +impl crate::commands::command_contract::CommandSpec for EndgiveawayCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "endgiveaway", + category: "event", + params: "", + description: "Termine instantanement un giveaway a partir de l'identifiant du message.", + examples: &["+endgiveaway 123456789012345678", "+help endgiveaway"], + default_aliases: &["gend"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/fun/suggestion.rs b/src/commands/fun/suggestion.rs index 2299a88..23fc397 100644 --- a/src/commands/fun/suggestion.rs +++ b/src/commands/fun/suggestion.rs @@ -127,6 +127,10 @@ async fn show_menu(ctx: &Context, msg: &Message) { .await; } +pub async fn handle_suggestionsettings(ctx: &Context, msg: &Message, _args: &[&str]) { + show_menu(ctx, msg).await; +} + async fn submit_suggestion( ctx: &Context, guild_id: GuildId, @@ -199,22 +203,13 @@ async fn submit_suggestion( } pub async fn handle_suggestion(ctx: &Context, msg: &Message, args: &[&str]) { - if args - .first() - .map(|value| value.eq_ignore_ascii_case("settings")) - .unwrap_or(false) - { - show_menu(ctx, msg).await; - return; - } - if args.is_empty() { send_embed( ctx, msg, CreateEmbed::new() .title("Suggestion") - .description("Utilisation: +suggestion ou +suggestion settings") + .description("Utilisation: +suggestion ") .color(0xED4245), ) .await; @@ -505,13 +500,9 @@ impl crate::commands::command_contract::CommandSpec for SuggestionCommand { crate::commands::command_contract::CommandMetadata { name: "suggestion", category: "fun", - params: " | settings", - description: "Publie une suggestion utilisateur ou ouvre le panneau de configuration.", - examples: &[ - "+suggestion Ameliorer le salon", - "+suggestion settings", - "+help suggestion", - ], + params: "", + description: "Publie une suggestion utilisateur dans le salon configure.", + examples: &["+suggestion Ameliorer le salon", "+help suggestion"], default_aliases: &[], allow_in_dm: false, default_permission: 0, diff --git a/src/commands/fun/suggestionsettings.rs b/src/commands/fun/suggestionsettings.rs new file mode 100644 index 0000000..3445553 --- /dev/null +++ b/src/commands/fun/suggestionsettings.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_suggestionsettings_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::suggestion::handle_suggestionsettings(ctx, msg, args).await; +} + +pub struct SuggestionsettingsCommand; +pub static COMMAND_DESCRIPTOR: SuggestionsettingsCommand = SuggestionsettingsCommand; + +impl crate::commands::command_contract::CommandSpec for SuggestionsettingsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "suggestionsettings", + category: "fun", + params: "aucun", + description: "Ouvre le panneau de configuration des suggestions du serveur.", + examples: &["+suggestionsettings", "+sgset", "+help suggestionsettings"], + default_aliases: &["sgset"], + allow_in_dm: false, + default_permission: 0, + } + } +} diff --git a/src/commands/info/server.rs b/src/commands/info/server.rs deleted file mode 100644 index e58432b..0000000 --- a/src/commands/info/server.rs +++ /dev/null @@ -1,170 +0,0 @@ -use serenity::builder::{CreateEmbed, CreateMessage}; -use serenity::http::GuildPagination; -use serenity::model::prelude::*; -use serenity::prelude::*; - -use crate::commands::common::{add_list_fields, send_embed, theme_color}; - -pub async fn handle_server(ctx: &Context, msg: &Message, args: &[&str]) { - if args - .first() - .map(|value| value.eq_ignore_ascii_case("list")) - .unwrap_or(false) - { - handle_server_list(ctx, msg).await; - return; - } - - let Some(guild_id) = msg.guild_id else { - return; - }; - - let Ok(guild) = guild_id.to_partial_guild(&ctx).await else { - return; - }; - - if args.is_empty() { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Usage: `+server pic`, `+server banner` ou `+serverlist`") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - match args[0].to_lowercase().as_str() { - "pic" | "icon" | "avatar" => { - let icon_url = guild.icon_url().unwrap_or_default(); - - if icon_url.is_empty() { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Ce serveur n'a pas d'icône.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - let embed = CreateEmbed::new() - .title(format!("Icône du serveur {}", guild.name)) - .image(icon_url) - .color(0x5865F2); - - send_embed(ctx, msg, embed).await; - } - "banner" => { - let banner_url = guild.banner_url().unwrap_or_default(); - - if banner_url.is_empty() { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Ce serveur n'a pas de bannière.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - let embed = CreateEmbed::new() - .title(format!("Bannière du serveur {}", guild.name)) - .image(banner_url) - .color(0x5865F2); - - send_embed(ctx, msg, embed).await; - } - _ => { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Usage: `+server pic`, `+server banner` ou `+serverlist`") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - } - } -} - -pub async fn handle_server_list(ctx: &Context, msg: &Message) { - let guilds = guilds_sorted(ctx).await; - let lines = guilds - .iter() - .enumerate() - .map(|(index, (guild_id, name))| format!("{} · {} · `{}`", index + 1, name, guild_id.get())) - .collect::>(); - - let mut embed = CreateEmbed::new() - .title("Serveurs du bot") - .color(theme_color(ctx).await); - embed = add_list_fields(embed, &lines, "Guildes"); - let _ = msg - .channel_id - .send_message(&ctx.http, CreateMessage::new().embed(embed)) - .await; -} - -pub(crate) async fn resolve_guild_target(ctx: &Context, input: &str) -> Option { - let guilds = guilds_sorted(ctx).await; - if let Ok(index) = input.parse::() { - if index >= 1 && index <= guilds.len() { - return Some(guilds[index - 1].0); - } - } - - input - .parse::() - .ok() - .map(GuildId::new) - .filter(|id| guilds.iter().any(|(guild_id, _)| guild_id == id)) -} - -async fn guilds_sorted(ctx: &Context) -> Vec<(GuildId, String)> { - let mut all_guilds = Vec::new(); - let mut after: Option = None; - - loop { - let page = if let Some(after_id) = after { - ctx.http - .get_guilds(Some(GuildPagination::After(after_id)), Some(100)) - .await - .unwrap_or_default() - } else { - ctx.http - .get_guilds(None, Some(100)) - .await - .unwrap_or_default() - }; - - if page.is_empty() { - break; - } - - after = page.last().map(|guild| guild.id); - all_guilds.extend(page.into_iter().map(|guild| (guild.id, guild.name))); - - if all_guilds.len() % 100 != 0 { - break; - } - } - - all_guilds.sort_by(|a, b| { - a.1.to_lowercase() - .cmp(&b.1.to_lowercase()) - .then_with(|| a.0.get().cmp(&b.0.get())) - }); - all_guilds -} - -pub struct ServerCommand; -pub static COMMAND_DESCRIPTOR: ServerCommand = ServerCommand; - -impl crate::commands::command_contract::CommandSpec for ServerCommand { - fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { - crate::commands::command_contract::CommandMetadata { - name: "server", - category: "info", - params: "pic | banner | list", - description: "Affiche licone ou la banniere du serveur, ou liste les serveurs du bot selon la sous commande.", - examples: &["+server", "+sr", "+help server"], - default_aliases: &["srv"], - allow_in_dm: false, - default_permission: 0, - } - } -} diff --git a/src/commands/info/serverbanner.rs b/src/commands/info/serverbanner.rs new file mode 100644 index 0000000..30dd13f --- /dev/null +++ b/src/commands/info/serverbanner.rs @@ -0,0 +1,49 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::send_embed; + +pub async fn handle_serverbanner(ctx: &Context, msg: &Message, _args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Ok(guild) = guild_id.to_partial_guild(&ctx).await else { + return; + }; + + let banner_url = guild.banner_url().unwrap_or_default(); + if banner_url.is_empty() { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Ce serveur n'a pas de banniere.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + + let embed = CreateEmbed::new() + .title(format!("Banniere du serveur {}", guild.name)) + .image(banner_url) + .color(0x5865F2); + send_embed(ctx, msg, embed).await; +} + +pub struct ServerbannerCommand; +pub static COMMAND_DESCRIPTOR: ServerbannerCommand = ServerbannerCommand; + +impl crate::commands::command_contract::CommandSpec for ServerbannerCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "serverbanner", + category: "info", + params: "aucun", + description: "Affiche la banniere du serveur courant.", + examples: &["+serverbanner", "+sbn", "+help serverbanner"], + default_aliases: &["sbn"], + allow_in_dm: false, + default_permission: 0, + } + } +} diff --git a/src/commands/info/serverlist.rs b/src/commands/info/serverlist.rs new file mode 100644 index 0000000..34f8b4b --- /dev/null +++ b/src/commands/info/serverlist.rs @@ -0,0 +1,42 @@ +use serenity::builder::{CreateEmbed, CreateMessage}; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::{add_list_fields, theme_color}; + +pub async fn handle_serverlist(ctx: &Context, msg: &Message, _args: &[&str]) { + let guilds = crate::commands::servertarget::guilds_sorted(ctx).await; + let lines = guilds + .iter() + .enumerate() + .map(|(index, (guild_id, name))| format!("{} · {} · `{}`", index + 1, name, guild_id.get())) + .collect::>(); + + let mut embed = CreateEmbed::new() + .title("Serveurs du bot") + .color(theme_color(ctx).await); + embed = add_list_fields(embed, &lines, "Guildes"); + + let _ = msg + .channel_id + .send_message(&ctx.http, CreateMessage::new().embed(embed)) + .await; +} + +pub struct ServerlistCommand; +pub static COMMAND_DESCRIPTOR: ServerlistCommand = ServerlistCommand; + +impl crate::commands::command_contract::CommandSpec for ServerlistCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "serverlist", + category: "info", + params: "aucun", + description: "Liste les serveurs ou le bot est present.", + examples: &["+serverlist", "+sls", "+help serverlist"], + default_aliases: &["sls"], + allow_in_dm: false, + default_permission: 0, + } + } +} diff --git a/src/commands/info/serverpic.rs b/src/commands/info/serverpic.rs new file mode 100644 index 0000000..339828f --- /dev/null +++ b/src/commands/info/serverpic.rs @@ -0,0 +1,49 @@ +use serenity::builder::CreateEmbed; +use serenity::model::prelude::*; +use serenity::prelude::*; + +use crate::commands::common::send_embed; + +pub async fn handle_serverpic(ctx: &Context, msg: &Message, _args: &[&str]) { + let Some(guild_id) = msg.guild_id else { + return; + }; + + let Ok(guild) = guild_id.to_partial_guild(&ctx).await else { + return; + }; + + let icon_url = guild.icon_url().unwrap_or_default(); + if icon_url.is_empty() { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Ce serveur n'a pas d'icone.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + + let embed = CreateEmbed::new() + .title(format!("Icone du serveur {}", guild.name)) + .image(icon_url) + .color(0x5865F2); + send_embed(ctx, msg, embed).await; +} + +pub struct ServerpicCommand; +pub static COMMAND_DESCRIPTOR: ServerpicCommand = ServerpicCommand; + +impl crate::commands::command_contract::CommandSpec for ServerpicCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "serverpic", + category: "info", + params: "aucun", + description: "Affiche l'icone du serveur courant.", + examples: &["+serverpic", "+spi", "+help serverpic"], + default_aliases: &["spi"], + allow_in_dm: false, + default_permission: 0, + } + } +} diff --git a/src/commands/info/servertarget.rs b/src/commands/info/servertarget.rs new file mode 100644 index 0000000..594acbe --- /dev/null +++ b/src/commands/info/servertarget.rs @@ -0,0 +1,55 @@ +use serenity::http::GuildPagination; +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub(crate) async fn resolve_guild_target(ctx: &Context, input: &str) -> Option { + let guilds = guilds_sorted(ctx).await; + if let Ok(index) = input.parse::() { + if index >= 1 && index <= guilds.len() { + return Some(guilds[index - 1].0); + } + } + + input + .parse::() + .ok() + .map(GuildId::new) + .filter(|id| guilds.iter().any(|(guild_id, _)| guild_id == id)) +} + +pub(crate) async fn guilds_sorted(ctx: &Context) -> Vec<(GuildId, String)> { + let mut all_guilds = Vec::new(); + let mut after: Option = None; + + loop { + let page = if let Some(after_id) = after { + ctx.http + .get_guilds(Some(GuildPagination::After(after_id)), Some(100)) + .await + .unwrap_or_default() + } else { + ctx.http + .get_guilds(None, Some(100)) + .await + .unwrap_or_default() + }; + + if page.is_empty() { + break; + } + + after = page.last().map(|guild| guild.id); + all_guilds.extend(page.into_iter().map(|guild| (guild.id, guild.name))); + + if all_guilds.len() % 100 != 0 { + break; + } + } + + all_guilds.sort_by(|a, b| { + a.1.to_lowercase() + .cmp(&b.1.to_lowercase()) + .then_with(|| a.0.get().cmp(&b.0.get())) + }); + all_guilds +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 8e28085..27b47a7 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -7,6 +7,8 @@ pub mod admin_service; pub mod advanced_tools; #[path = "perms/alias.rs"] pub mod alias; +#[path = "perms/unalias.rs"] +pub mod unalias; #[path = "info/alladmins.rs"] pub mod alladmins; #[path = "info/allbots.rs"] @@ -30,6 +32,10 @@ pub mod autoconfiglog; pub mod automod_service; #[path = "automation/autopublish.rs"] pub mod autopublish; +#[path = "automation/autopublishoff.rs"] +pub mod autopublishoff; +#[path = "automation/autopublishon.rs"] +pub mod autopublishon; #[path = "automation/autoreact.rs"] pub mod autoreact; #[path = "automation/backup.rs"] @@ -64,6 +70,8 @@ pub mod button; pub mod calc; #[path = "botconfig/change.rs"] pub mod change; +#[path = "botconfig/changereset.rs"] +pub mod changereset; #[path = "botconfig/changeall.rs"] pub mod changeall; #[path = "info/channel.rs"] @@ -102,6 +110,8 @@ pub mod compet; pub mod create; #[path = "perms/del.rs"] pub mod del; +#[path = "perms/delperm.rs"] +pub mod delperm; #[path = "mod/delsanction.rs"] pub mod del_sanction; #[path = "roles/delrole.rs"] @@ -118,6 +128,8 @@ pub mod embed; pub mod emoji; #[path = "event/end.rs"] pub mod end; +#[path = "event/endgiveaway.rs"] +pub mod endgiveaway; #[path = "event/giveaway.rs"] pub mod giveaway; #[path = "perms/help.rs"] @@ -169,6 +181,12 @@ pub mod moderation_tools; pub mod modlog; #[path = "owner/mp.rs"] pub mod mp; +#[path = "owner/mpdelete.rs"] +pub mod mpdelete; +#[path = "owner/mpsent.rs"] +pub mod mpsent; +#[path = "owner/mpsettings.rs"] +pub mod mpsettings; #[path = "mod/mute.rs"] pub mod mute; #[path = "mod/mutelist.rs"] @@ -179,6 +197,10 @@ pub mod muterole; pub mod newsticker; #[path = "roles/noderank.rs"] pub mod noderank; +#[path = "roles/noderankadd.rs"] +pub mod noderankadd; +#[path = "roles/noderankdel.rs"] +pub mod noderankdel; #[path = "config/nolog.rs"] pub mod nolog; #[path = "botconfig/online.rs"] @@ -193,6 +215,10 @@ pub mod perms_service; pub mod pic; #[path = "automation/piconly.rs"] pub mod piconly; +#[path = "automation/piconlyadd.rs"] +pub mod piconlyadd; +#[path = "automation/piconlydel.rs"] +pub mod piconlydel; #[path = "info/ping.rs"] pub mod ping; #[path = "botconfig/playto.rs"] @@ -203,6 +229,12 @@ pub mod prefix; pub mod public; #[path = "mod/punish.rs"] pub mod punish; +#[path = "mod/punishadd.rs"] +pub mod punishadd; +#[path = "mod/punishdel.rs"] +pub mod punishdel; +#[path = "mod/punishsetup.rs"] +pub mod punishsetup; #[path = "config/raidlog.rs"] pub mod raidlog; #[path = "botconfig/removeactivity.rs"] @@ -227,12 +259,28 @@ pub mod rolemenu; pub mod sanctions; #[path = "fun/say.rs"] pub mod say; -#[path = "info/server.rs"] -pub mod server; +#[path = "info/serverbanner.rs"] +pub mod serverbanner; +#[path = "info/serverlist.rs"] +pub mod serverlist; +#[path = "info/serverpic.rs"] +pub mod serverpic; +#[path = "info/servertarget.rs"] +pub mod servertarget; #[path = "info/serverinfo.rs"] pub mod serverinfo; #[path = "botconfig/set.rs"] pub mod set; +#[path = "botconfig/setbanner.rs"] +pub mod setbanner; +#[path = "botconfig/setname.rs"] +pub mod setname; +#[path = "botconfig/setperm.rs"] +pub mod setperm; +#[path = "botconfig/setpic.rs"] +pub mod setpic; +#[path = "botconfig/setprofil.rs"] +pub mod setprofil; #[path = "config/setboostembed.rs"] pub mod set_boostembed; #[path = "config/setmodlogs.rs"] @@ -255,6 +303,8 @@ pub mod stream; pub mod strikes; #[path = "fun/suggestion.rs"] pub mod suggestion; +#[path = "fun/suggestionsettings.rs"] +pub mod suggestionsettings; #[path = "roles/sync.rs"] pub mod sync; #[path = "mod/tempban.rs"] @@ -343,10 +393,13 @@ pub fn all_command_metadata() -> Vec { member::COMMAND_DESCRIPTOR.metadata(), pic::COMMAND_DESCRIPTOR.metadata(), banner::COMMAND_DESCRIPTOR.metadata(), - server::COMMAND_DESCRIPTOR.metadata(), + serverpic::COMMAND_DESCRIPTOR.metadata(), + serverbanner::COMMAND_DESCRIPTOR.metadata(), + serverlist::COMMAND_DESCRIPTOR.metadata(), snipe::COMMAND_DESCRIPTOR.metadata(), emoji::COMMAND_DESCRIPTOR.metadata(), giveaway::COMMAND_DESCRIPTOR.metadata(), + endgiveaway::COMMAND_DESCRIPTOR.metadata(), modlog::COMMAND_DESCRIPTOR.metadata(), messagelog::COMMAND_DESCRIPTOR.metadata(), voicelog::COMMAND_DESCRIPTOR.metadata(), @@ -376,6 +429,9 @@ pub fn all_command_metadata() -> Vec { link::COMMAND_DESCRIPTOR.metadata(), strikes::COMMAND_DESCRIPTOR.metadata(), punish::COMMAND_DESCRIPTOR.metadata(), + punishsetup::COMMAND_DESCRIPTOR.metadata(), + punishadd::COMMAND_DESCRIPTOR.metadata(), + punishdel::COMMAND_DESCRIPTOR.metadata(), public::COMMAND_DESCRIPTOR.metadata(), resetantiraide::COMMAND_DESCRIPTOR.metadata(), backup::COMMAND_DESCRIPTOR.metadata(), @@ -387,8 +443,13 @@ pub fn all_command_metadata() -> Vec { tickets::COMMAND_DESCRIPTOR.metadata(), showpics::COMMAND_DESCRIPTOR.metadata(), piconly::COMMAND_DESCRIPTOR.metadata(), + piconlyadd::COMMAND_DESCRIPTOR.metadata(), + piconlydel::COMMAND_DESCRIPTOR.metadata(), suggestion::COMMAND_DESCRIPTOR.metadata(), + suggestionsettings::COMMAND_DESCRIPTOR.metadata(), autopublish::COMMAND_DESCRIPTOR.metadata(), + autopublishon::COMMAND_DESCRIPTOR.metadata(), + autopublishoff::COMMAND_DESCRIPTOR.metadata(), tempvoc::COMMAND_DESCRIPTOR.metadata(), tempvoc_cmd::COMMAND_DESCRIPTOR.metadata(), autobackup::COMMAND_DESCRIPTOR.metadata(), @@ -430,6 +491,8 @@ pub fn all_command_metadata() -> Vec { delrole::COMMAND_DESCRIPTOR.metadata(), derank::COMMAND_DESCRIPTOR.metadata(), noderank::COMMAND_DESCRIPTOR.metadata(), + noderankadd::COMMAND_DESCRIPTOR.metadata(), + noderankdel::COMMAND_DESCRIPTOR.metadata(), del_sanction::COMMAND_DESCRIPTOR.metadata(), clear_sanctions::COMMAND_DESCRIPTOR.metadata(), clear_all_sanctions::COMMAND_DESCRIPTOR.metadata(), @@ -440,7 +503,11 @@ pub fn all_command_metadata() -> Vec { autoreact::COMMAND_DESCRIPTOR.metadata(), calc::COMMAND_DESCRIPTOR.metadata(), shadowbot::COMMAND_DESCRIPTOR.metadata(), - set::COMMAND_DESCRIPTOR.metadata(), + setname::COMMAND_DESCRIPTOR.metadata(), + setpic::COMMAND_DESCRIPTOR.metadata(), + setbanner::COMMAND_DESCRIPTOR.metadata(), + setprofil::COMMAND_DESCRIPTOR.metadata(), + setperm::COMMAND_DESCRIPTOR.metadata(), theme::COMMAND_DESCRIPTOR.metadata(), playto::COMMAND_DESCRIPTOR.metadata(), listen::COMMAND_DESCRIPTOR.metadata(), @@ -461,17 +528,22 @@ pub fn all_command_metadata() -> Vec { clear_bl::COMMAND_DESCRIPTOR.metadata(), say::COMMAND_DESCRIPTOR.metadata(), change::COMMAND_DESCRIPTOR.metadata(), + changereset::COMMAND_DESCRIPTOR.metadata(), changeall::COMMAND_DESCRIPTOR.metadata(), mainprefix::COMMAND_DESCRIPTOR.metadata(), prefix::COMMAND_DESCRIPTOR.metadata(), perms::COMMAND_DESCRIPTOR.metadata(), - del::COMMAND_DESCRIPTOR.metadata(), + delperm::COMMAND_DESCRIPTOR.metadata(), clear_perms::COMMAND_DESCRIPTOR.metadata(), allperms::COMMAND_DESCRIPTOR.metadata(), help::COMMAND_DESCRIPTOR.metadata(), helpsetting::COMMAND_DESCRIPTOR.metadata(), alias::COMMAND_DESCRIPTOR.metadata(), + unalias::COMMAND_DESCRIPTOR.metadata(), mp::COMMAND_DESCRIPTOR.metadata(), + mpsettings::COMMAND_DESCRIPTOR.metadata(), + mpsent::COMMAND_DESCRIPTOR.metadata(), + mpdelete::COMMAND_DESCRIPTOR.metadata(), invite::COMMAND_DESCRIPTOR.metadata(), leave::COMMAND_DESCRIPTOR.metadata(), leave_settings::COMMAND_DESCRIPTOR.metadata(), diff --git a/src/commands/mod/clearbadwords.rs b/src/commands/mod/clearbadwords.rs index 8402451..4ad04ac 100644 --- a/src/commands/mod/clearbadwords.rs +++ b/src/commands/mod/clearbadwords.rs @@ -39,7 +39,7 @@ impl crate::commands::command_contract::CommandSpec for ClearBadwordsCommand { crate::commands::command_contract::CommandMetadata { name: "clearbadwords", category: "mod", - params: "badwords", + params: "aucun", description: "Supprime l ensemble des mots interdits enregistres.", examples: &["+clearbadwords", "+help clearbadwords"], default_aliases: &["cbw"], diff --git a/src/commands/mod/clearlimit.rs b/src/commands/mod/clearlimit.rs index 244556b..34156f7 100644 --- a/src/commands/mod/clearlimit.rs +++ b/src/commands/mod/clearlimit.rs @@ -11,7 +11,7 @@ pub async fn handle_clear_limit(ctx: &Context, msg: &Message, args: &[&str]) { return; }; - let Some(raw_value) = args.get(1) else { + let Some(raw_value) = args.first() else { send_embed( ctx, msg, @@ -63,7 +63,7 @@ impl crate::commands::command_contract::CommandSpec for ClearLimitCommand { crate::commands::command_contract::CommandMetadata { name: "clearlimit", category: "mod", - params: "limit ", + params: "", description: "Definit la limite max de messages supprimables avec +clear.", examples: &["+clearlimit 100", "+help clearlimit"], default_aliases: &["climit"], diff --git a/src/commands/mod/clearsanctions.rs b/src/commands/mod/clearsanctions.rs index 13e31c4..b02053b 100644 --- a/src/commands/mod/clearsanctions.rs +++ b/src/commands/mod/clearsanctions.rs @@ -10,11 +10,11 @@ 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 { + if args.is_empty() { return; } - let Some(target) = parse_user_id(args[1]) else { + let Some(target) = parse_user_id(args[0]) else { return; }; diff --git a/src/commands/mod/delsanction.rs b/src/commands/mod/delsanction.rs index f0f150f..b7ee07d 100644 --- a/src/commands/mod/delsanction.rs +++ b/src/commands/mod/delsanction.rs @@ -10,14 +10,14 @@ 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 { + if args.len() < 2 { return; } - let Some(target) = parse_user_id(args[1]) else { + let Some(target) = parse_user_id(args[0]) else { return; }; - let Ok(index) = args[2].parse::() else { + let Ok(index) = args[1].parse::() else { return; }; if index == 0 { diff --git a/src/commands/mod/punish.rs b/src/commands/mod/punish.rs index 48fd9a3..3d287dd 100644 --- a/src/commands/mod/punish.rs +++ b/src/commands/mod/punish.rs @@ -35,124 +35,169 @@ pub async fn handle_punish(ctx: &Context, msg: &Message, args: &[&str]) { let bot_id = ctx.cache.current_user().id.get() as i64; let guild_id_raw = guild_id.get() as i64; - if args.is_empty() { - let rules = db::list_punish_rules(&pool, bot_id, guild_id_raw) - .await - .unwrap_or_default(); - - let description = if rules.is_empty() { - "Aucune regle.".to_string() - } else { - rules - .iter() - .enumerate() - .map(|(idx, rule)| describe_rule(idx + 1, rule)) - .collect::>() - .join("\n") - }; - + if !args.is_empty() { send_embed( ctx, msg, CreateEmbed::new() .title("Punish") - .description(description) - .color(0x5865F2), + .description("Usage: +punish") + .color(0xED4245), ) .await; return; } - if args[0].eq_ignore_ascii_case("setup") { - let _ = db::setup_default_punish_rules(&pool, bot_id, guild_id_raw).await; - send_embed( - ctx, - msg, - CreateEmbed::new() - .title("Punish") - .description("Regles par defaut restaurees.") - .color(0x57F287), - ) - .await; - return; - } + let rules = db::list_punish_rules(&pool, bot_id, guild_id_raw) + .await + .unwrap_or_default(); - if args[0].eq_ignore_ascii_case("add") { - if args.len() < 4 { - return; - } - - let Ok(threshold) = args[1].parse::() else { - return; - }; - let Some(window_seconds) = parse_duration_to_seconds(args[2]) else { - return; - }; - let Some(sanction) = parse_sanction(args[3]) else { - return; - }; - let sanction_seconds = args.get(4).and_then(|raw| parse_duration_to_seconds(raw)); - - let _ = db::upsert_punish_rule( - &pool, - bot_id, - guild_id_raw, - threshold.clamp(1, 200), - window_seconds, - sanction, - sanction_seconds, - ) - .await; - - send_embed( - ctx, - msg, - CreateEmbed::new() - .title("Punish") - .description("Regle ajoutee ou mise a jour.") - .color(0x57F287), - ) - .await; - return; - } - - if args[0].eq_ignore_ascii_case("del") { - let Some(raw_index) = args.get(1) else { - return; - }; - let Ok(index) = raw_index.parse::() else { - return; - }; - - let rules = db::list_punish_rules(&pool, bot_id, guild_id_raw) - .await - .unwrap_or_default(); - if index == 0 || index > rules.len() { - return; - } - - let rule = &rules[index - 1]; - let _ = db::delete_punish_rule_by_id(&pool, bot_id, guild_id_raw, rule.id).await; - - send_embed( - ctx, - msg, - CreateEmbed::new() - .title("Punish") - .description(format!("Regle {} supprimee.", index)) - .color(0x57F287), - ) - .await; - return; - } + let description = if rules.is_empty() { + "Aucune regle.".to_string() + } else { + rules + .iter() + .enumerate() + .map(|(idx, rule)| describe_rule(idx + 1, rule)) + .collect::>() + .join("\n") + }; send_embed( ctx, msg, CreateEmbed::new() .title("Punish") - .description("Usage: +punish | +punish add [duree] | +punish del | +punish setup") - .color(0xED4245), + .description(description) + .color(0x5865F2), + ) + .await; +} + +pub async fn handle_punishsetup(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 guild_id_raw = guild_id.get() as i64; + + let _ = db::setup_default_punish_rules(&pool, bot_id, guild_id_raw).await; + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Punish") + .description("Regles par defaut restaurees.") + .color(0x57F287), + ) + .await; +} + +pub async fn handle_punishadd(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 guild_id_raw = guild_id.get() as i64; + + if args.len() < 3 { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Punish") + .description("Usage: +punishadd [duree]") + .color(0xED4245), + ) + .await; + return; + } + + let Ok(threshold) = args[0].parse::() else { + return; + }; + let Some(window_seconds) = parse_duration_to_seconds(args[1]) else { + return; + }; + let Some(sanction) = parse_sanction(args[2]) else { + return; + }; + let sanction_seconds = args.get(3).and_then(|raw| parse_duration_to_seconds(raw)); + + let _ = db::upsert_punish_rule( + &pool, + bot_id, + guild_id_raw, + threshold.clamp(1, 200), + window_seconds, + sanction, + sanction_seconds, + ) + .await; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Punish") + .description("Regle ajoutee ou mise a jour.") + .color(0x57F287), + ) + .await; +} + +pub async fn handle_punishdel(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 guild_id_raw = guild_id.get() as i64; + + let Some(raw_index) = args.first() else { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Punish") + .description("Usage: +punishdel ") + .color(0xED4245), + ) + .await; + return; + }; + let Ok(index) = raw_index.parse::() else { + return; + }; + + let rules = db::list_punish_rules(&pool, bot_id, guild_id_raw) + .await + .unwrap_or_default(); + if index == 0 || index > rules.len() { + return; + } + + let rule = &rules[index - 1]; + let _ = db::delete_punish_rule_by_id(&pool, bot_id, guild_id_raw, rule.id).await; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("Punish") + .description(format!("Regle {} supprimee.", index)) + .color(0x57F287), ) .await; } @@ -165,9 +210,9 @@ impl crate::commands::command_contract::CommandSpec for PunishCommand { crate::commands::command_contract::CommandMetadata { name: "punish", category: "mod", - params: "[add [duree] | del | setup]", - description: "Affiche et gere les sanctions automatiques appliquees selon les strikes.", - examples: &["+punish", "+punish add 8 1h mute 30m", "+punish setup"], + params: "aucun", + description: "Affiche les sanctions automatiques appliquees selon les strikes.", + examples: &["+punish", "+help punish"], default_aliases: &["pn"], allow_in_dm: false, default_permission: 7, diff --git a/src/commands/mod/punishadd.rs b/src/commands/mod/punishadd.rs new file mode 100644 index 0000000..89cb067 --- /dev/null +++ b/src/commands/mod/punishadd.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_punishadd_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::punish::handle_punishadd(ctx, msg, args).await; +} + +pub struct PunishaddCommand; +pub static COMMAND_DESCRIPTOR: PunishaddCommand = PunishaddCommand; + +impl crate::commands::command_contract::CommandSpec for PunishaddCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "punishadd", + category: "mod", + params: " [duree]", + description: "Ajoute ou met a jour une regle Punish.", + examples: &["+punishadd 8 1h mute 30m", "+help punishadd"], + default_aliases: &["pna"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/mod/punishdel.rs b/src/commands/mod/punishdel.rs new file mode 100644 index 0000000..1f889b4 --- /dev/null +++ b/src/commands/mod/punishdel.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_punishdel_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::punish::handle_punishdel(ctx, msg, args).await; +} + +pub struct PunishdelCommand; +pub static COMMAND_DESCRIPTOR: PunishdelCommand = PunishdelCommand; + +impl crate::commands::command_contract::CommandSpec for PunishdelCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "punishdel", + category: "mod", + params: "", + description: "Supprime une regle Punish par son index.", + examples: &["+punishdel 2", "+help punishdel"], + default_aliases: &["pnd"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/mod/punishsetup.rs b/src/commands/mod/punishsetup.rs new file mode 100644 index 0000000..eefbd8a --- /dev/null +++ b/src/commands/mod/punishsetup.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_punishsetup_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::punish::handle_punishsetup(ctx, msg, args).await; +} + +pub struct PunishsetupCommand; +pub static COMMAND_DESCRIPTOR: PunishsetupCommand = PunishsetupCommand; + +impl crate::commands::command_contract::CommandSpec for PunishsetupCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "punishsetup", + category: "mod", + params: "aucun", + description: "Recharge les regles Punish par defaut.", + examples: &["+punishsetup", "+help punishsetup"], + default_aliases: &["pnsetup"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/mod/setmuterole.rs b/src/commands/mod/setmuterole.rs index aca1f78..a2440a7 100644 --- a/src/commands/mod/setmuterole.rs +++ b/src/commands/mod/setmuterole.rs @@ -11,7 +11,7 @@ pub async fn handle_set_muterole(ctx: &Context, msg: &Message, args: &[&str]) { return; }; - let Some(raw_role) = args.get(1) else { + let Some(raw_role) = args.first() else { send_embed( ctx, msg, @@ -68,7 +68,7 @@ impl crate::commands::command_contract::CommandSpec for SetMuteRoleCommand { crate::commands::command_contract::CommandMetadata { name: "setmuterole", category: "mod", - params: "muterole <@role/ID/nom>", + params: "<@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"], diff --git a/src/commands/owner/discussion.rs b/src/commands/owner/discussion.rs index 0fec58b..8dec233 100644 --- a/src/commands/owner/discussion.rs +++ b/src/commands/owner/discussion.rs @@ -3,7 +3,7 @@ use serenity::model::prelude::*; use serenity::prelude::*; use crate::commands::common::send_embed; -use crate::commands::server::resolve_guild_target; +use crate::commands::servertarget::resolve_guild_target; pub async fn handle_discussion(ctx: &Context, msg: &Message, args: &[&str]) { if args.len() < 2 { diff --git a/src/commands/owner/invite.rs b/src/commands/owner/invite.rs index 880887d..b5c6627 100644 --- a/src/commands/owner/invite.rs +++ b/src/commands/owner/invite.rs @@ -3,7 +3,7 @@ use serenity::model::prelude::*; use serenity::prelude::*; use crate::commands::common::send_embed; -use crate::commands::server::resolve_guild_target; +use crate::commands::servertarget::resolve_guild_target; pub async fn handle_invite(ctx: &Context, msg: &Message, args: &[&str]) { if args.is_empty() { diff --git a/src/commands/owner/leave.rs b/src/commands/owner/leave.rs index d4c0718..8621c94 100644 --- a/src/commands/owner/leave.rs +++ b/src/commands/owner/leave.rs @@ -3,7 +3,7 @@ use serenity::model::prelude::*; use serenity::prelude::*; use crate::commands::common::send_embed; -use crate::commands::server::resolve_guild_target; +use crate::commands::servertarget::resolve_guild_target; pub async fn handle_leave(ctx: &Context, msg: &Message, args: &[&str]) { let target = if args.is_empty() { diff --git a/src/commands/owner/mp.rs b/src/commands/owner/mp.rs index b49b99d..91f0a01 100644 --- a/src/commands/owner/mp.rs +++ b/src/commands/owner/mp.rs @@ -13,152 +13,137 @@ use crate::db::{ log_sent_mp_message, mark_sent_mp_deleted, set_mp_enabled, }; -pub async fn handle_mp(ctx: &Context, msg: &Message, args: &[&str]) { - if args - .first() - .map(|value| value.eq_ignore_ascii_case("settings")) - .unwrap_or(false) - { - let bot_id = ctx.cache.current_user().id; - let Some(pool) = pool(ctx).await else { - let embed = CreateEmbed::new() - .title("Erreur") - .description("DB indisponible.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - }; - - if args.len() == 1 { - let enabled = get_mp_enabled(&pool, bot_id) - .await - .ok() - .flatten() - .unwrap_or(true); - let embed = CreateEmbed::new() - .title("MP settings") - .description(format!( - "Envoi de MP: `{}`\nUtilise `+mpsettings on/off`.", - if enabled { "on" } else { "off" } - )) - .color(0x5865F2); - send_embed(ctx, msg, embed).await; - return; - } - - let enabled = match args[1].to_lowercase().as_str() { - "on" | "true" | "yes" => true, - "off" | "false" | "no" => false, - _ => { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Usage: `+mpsettings `") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - }; - - let _ = set_mp_enabled(&pool, bot_id, enabled).await; +pub async fn handle_mpsettings(ctx: &Context, msg: &Message, args: &[&str]) { + let bot_id = ctx.cache.current_user().id; + let Some(pool) = pool(ctx).await else { let embed = CreateEmbed::new() - .title("MP settings mis à jour") + .title("Erreur") + .description("DB indisponible.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + if args.is_empty() { + let enabled = get_mp_enabled(&pool, bot_id) + .await + .ok() + .flatten() + .unwrap_or(true); + let embed = CreateEmbed::new() + .title("MP settings") .description(format!( - "Envoi de MP: `{}`", + "Envoi de MP: `{}`\nUtilise `+mpsettings on/off`.", if enabled { "on" } else { "off" } )) - .color(0x57F287); + .color(0x5865F2); send_embed(ctx, msg, embed).await; return; } - if args - .first() - .map(|value| value.eq_ignore_ascii_case("sent")) - .unwrap_or(false) - { - let page = args - .get(1) - .and_then(|value| value.parse::().ok()) - .filter(|value| *value >= 1) - .unwrap_or(1); - let _ = send_mp_sent_page(ctx, msg, page).await; - return; - } - - if args - .first() - .map(|value| value.eq_ignore_ascii_case("delete") || value.eq_ignore_ascii_case("del")) - .unwrap_or(false) - { - let Some(entry_id_raw) = args.get(1) else { + let enabled = match args[0].to_lowercase().as_str() { + "on" | "true" | "yes" => true, + "off" | "false" | "no" => false, + _ => { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+mpdelete `") + .description("Usage: `+mpsettings `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; - }; - - let Ok(entry_id) = entry_id_raw.parse::() else { - let embed = CreateEmbed::new() - .title("Erreur") - .description("ID invalide.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - }; - - let bot_id = ctx.cache.current_user().id; - let Some(pool) = pool(ctx).await else { - let embed = CreateEmbed::new() - .title("Erreur") - .description("DB indisponible.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - }; - - let Some(entry) = get_sent_mp_message(&pool, bot_id, entry_id) - .await - .ok() - .flatten() - else { - let embed = CreateEmbed::new() - .title("Erreur") - .description("Message MP introuvable.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - }; - - let delete_result = ChannelId::new(entry.dm_channel_id as u64) - .delete_message(&ctx.http, MessageId::new(entry.message_id as u64)) - .await; - - let _ = mark_sent_mp_deleted(&pool, bot_id, entry_id).await; - if delete_result.is_err() { - let embed = CreateEmbed::new() - .title("MP déjà supprimé ou inaccessible") - .description(format!( - "Entrée `#{}` marquée supprimée en base (Discord a refusé la suppression).", - entry.entry_id - )) - .color(0xFEE75C); - send_embed(ctx, msg, embed).await; - } else { - let embed = CreateEmbed::new() - .title("MP supprimé") - .description(format!("Entrée `#{}` supprimée.", entry.entry_id)) - .color(0x57F287); - send_embed(ctx, msg, embed).await; } - return; - } + }; + let _ = set_mp_enabled(&pool, bot_id, enabled).await; + let embed = CreateEmbed::new() + .title("MP settings mis à jour") + .description(format!( + "Envoi de MP: `{}`", + if enabled { "on" } else { "off" } + )) + .color(0x57F287); + send_embed(ctx, msg, embed).await; +} + +pub async fn handle_mpsent(ctx: &Context, msg: &Message, args: &[&str]) { + let page = args + .first() + .and_then(|value| value.parse::().ok()) + .filter(|value| *value >= 1) + .unwrap_or(1); + let _ = send_mp_sent_page(ctx, msg, page).await; +} + +pub async fn handle_mpdelete(ctx: &Context, msg: &Message, args: &[&str]) { + let Some(entry_id_raw) = args.first() else { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Usage: `+mpdelete `") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let Ok(entry_id) = entry_id_raw.parse::() else { + let embed = CreateEmbed::new() + .title("Erreur") + .description("ID invalide.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let bot_id = ctx.cache.current_user().id; + let Some(pool) = pool(ctx).await else { + let embed = CreateEmbed::new() + .title("Erreur") + .description("DB indisponible.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let Some(entry) = get_sent_mp_message(&pool, bot_id, entry_id) + .await + .ok() + .flatten() + else { + let embed = CreateEmbed::new() + .title("Erreur") + .description("Message MP introuvable.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let delete_result = ChannelId::new(entry.dm_channel_id as u64) + .delete_message(&ctx.http, MessageId::new(entry.message_id as u64)) + .await; + + let _ = mark_sent_mp_deleted(&pool, bot_id, entry_id).await; + if delete_result.is_err() { + let embed = CreateEmbed::new() + .title("MP déjà supprimé ou inaccessible") + .description(format!( + "Entrée `#{}` marquée supprimée en base (Discord a refusé la suppression).", + entry.entry_id + )) + .color(0xFEE75C); + send_embed(ctx, msg, embed).await; + } else { + let embed = CreateEmbed::new() + .title("MP supprimé") + .description(format!("Entrée `#{}` supprimée.", entry.entry_id)) + .color(0x57F287); + send_embed(ctx, msg, embed).await; + } +} + +pub async fn handle_mp(ctx: &Context, msg: &Message, args: &[&str]) { if args.len() < 2 { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+mpsettings` ou `+mp `") + .description("Usage: `+mp `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; @@ -462,9 +447,9 @@ impl crate::commands::command_contract::CommandSpec for MpCommand { crate::commands::command_contract::CommandMetadata { name: "mp", category: "owner", - params: "settings [on|off] | sent [page] | delete | <@membre/ID> ", - description: "Permet de configurer, envoyer, lister et supprimer des messages prives envoyes.", - examples: &["+mp", "+help mp"], + params: "<@membre/ID> ", + description: "Envoie un message prive a un membre cible.", + examples: &["+mp @Arthur Salut", "+help mp"], default_aliases: &["dmsg"], allow_in_dm: false, default_permission: 9, diff --git a/src/commands/owner/mpdelete.rs b/src/commands/owner/mpdelete.rs new file mode 100644 index 0000000..f4faf6e --- /dev/null +++ b/src/commands/owner/mpdelete.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_mpdelete_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::mp::handle_mpdelete(ctx, msg, args).await; +} + +pub struct MpdeleteCommand; +pub static COMMAND_DESCRIPTOR: MpdeleteCommand = MpdeleteCommand; + +impl crate::commands::command_contract::CommandSpec for MpdeleteCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "mpdelete", + category: "owner", + params: "", + description: "Supprime un MP envoye precedemment a partir de son identifiant interne.", + examples: &["+mpdelete 12", "+mpdel 12", "+help mpdelete"], + default_aliases: &["mpdel"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/owner/mpsent.rs b/src/commands/owner/mpsent.rs new file mode 100644 index 0000000..2a67241 --- /dev/null +++ b/src/commands/owner/mpsent.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_mpsent_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::mp::handle_mpsent(ctx, msg, args).await; +} + +pub struct MpsentCommand; +pub static COMMAND_DESCRIPTOR: MpsentCommand = MpsentCommand; + +impl crate::commands::command_contract::CommandSpec for MpsentCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "mpsent", + category: "owner", + params: "[page]", + description: "Affiche l'historique des MP envoyes par le bot.", + examples: &["+mpsent", "+mpsent 2", "+help mpsent"], + default_aliases: &["mps"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/owner/mpsettings.rs b/src/commands/owner/mpsettings.rs new file mode 100644 index 0000000..8223c47 --- /dev/null +++ b/src/commands/owner/mpsettings.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_mpsettings_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::mp::handle_mpsettings(ctx, msg, args).await; +} + +pub struct MpsettingsCommand; +pub static COMMAND_DESCRIPTOR: MpsettingsCommand = MpsettingsCommand; + +impl crate::commands::command_contract::CommandSpec for MpsettingsCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "mpsettings", + category: "owner", + params: "[on|off]", + description: "Affiche ou modifie l'etat global de l'envoi de MP par le bot.", + examples: &["+mpsettings", "+mpsettings off", "+help mpsettings"], + default_aliases: &["mpset"], + allow_in_dm: false, + default_permission: 9, + } + } +} diff --git a/src/commands/perms/alias.rs b/src/commands/perms/alias.rs index abbc6ac..d9d08b3 100644 --- a/src/commands/perms/alias.rs +++ b/src/commands/perms/alias.rs @@ -18,7 +18,7 @@ pub async fn handle_alias(ctx: &Context, msg: &Message, args: &[&str]) { return; }; - if args.len() == 1 { + if args.is_empty() { let aliases = list_command_aliases(&pool, bot_id) .await .unwrap_or_default(); @@ -44,28 +44,6 @@ pub async fn handle_alias(ctx: &Context, msg: &Message, args: &[&str]) { return; } - if args[0].eq_ignore_ascii_case("remove") || args[0].eq_ignore_ascii_case("delete") { - let alias_name = args[1].trim_start_matches('+').to_lowercase(); - if alias_name.is_empty() { - let embed = serenity::builder::CreateEmbed::new() - .title("Erreur") - .description("Alias invalide.") - .color(0xED4245); - send_embed(ctx, msg, embed).await; - return; - } - - let removed = remove_command_alias(&pool, bot_id, &alias_name) - .await - .unwrap_or(0); - let embed = serenity::builder::CreateEmbed::new() - .title("Alias supprimé") - .description(format!("`{}` : {} suppression(s).", alias_name, removed)) - .color(0x57F287); - send_embed(ctx, msg, embed).await; - return; - } - let command = args[0].trim_start_matches('+').to_lowercase(); let is_known = all_command_keys().iter().any(|candidate| candidate == &command) || crate::commands::command_metadata_by_key(&command).is_some(); @@ -99,6 +77,46 @@ pub async fn handle_alias(ctx: &Context, msg: &Message, args: &[&str]) { send_embed(ctx, msg, embed).await; } +pub async fn handle_unalias(ctx: &Context, msg: &Message, args: &[&str]) { + let bot_id = ctx.cache.current_user().id; + let Some(pool) = pool(ctx).await else { + let embed = serenity::builder::CreateEmbed::new() + .title("Erreur") + .description("DB indisponible.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let Some(raw_alias) = args.first() else { + let embed = serenity::builder::CreateEmbed::new() + .title("Erreur") + .description("Usage: `+unalias `") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + }; + + let alias_name = raw_alias.trim_start_matches('+').to_lowercase(); + if alias_name.is_empty() { + let embed = serenity::builder::CreateEmbed::new() + .title("Erreur") + .description("Alias invalide.") + .color(0xED4245); + send_embed(ctx, msg, embed).await; + return; + } + + let removed = remove_command_alias(&pool, bot_id, &alias_name) + .await + .unwrap_or(0); + let embed = serenity::builder::CreateEmbed::new() + .title("Alias supprimé") + .description(format!("`{}` : {} suppression(s).", alias_name, removed)) + .color(0x57F287); + send_embed(ctx, msg, embed).await; +} + async fn pool(ctx: &Context) -> Option { let data = ctx.data.read().await; data.get::().cloned() @@ -124,9 +142,9 @@ impl crate::commands::command_contract::CommandSpec for AliasCommand { crate::commands::command_contract::CommandMetadata { name: "alias", category: "perms", - params: " | remove | list", - description: "Liste, ajoute ou supprime des aliases de commandes stockes en base.", - examples: &["+alias", "+as", "+help alias"], + params: "[ ]", + description: "Liste les aliases (sans argument) ou ajoute un alias de commande.", + examples: &["+alias", "+alias mute m", "+help alias"], default_aliases: &["als"], allow_in_dm: false, default_permission: 6, diff --git a/src/commands/perms/del.rs b/src/commands/perms/del.rs index c5a5397..edc9143 100644 --- a/src/commands/perms/del.rs +++ b/src/commands/perms/del.rs @@ -11,16 +11,16 @@ pub async fn handle_del(ctx: &Context, msg: &Message, args: &[&str]) { return; } - if args.len() < 2 || !args[0].eq_ignore_ascii_case("perm") { + if args.is_empty() { let embed = CreateEmbed::new() .title("Erreur") - .description("Usage: `+delperm `") + .description("Usage: `+delperm `") .color(0xED4245); send_embed(ctx, msg, embed).await; return; } - let Some((scope_type, scope_id)) = parse_user_or_role(args[1]) else { + let Some((scope_type, scope_id)) = parse_user_or_role(args[0]) else { let embed = CreateEmbed::new() .title("Erreur") .description("Role/membre invalide.") @@ -50,20 +50,3 @@ pub async fn handle_del(ctx: &Context, msg: &Message, args: &[&str]) { send_embed(ctx, msg, embed).await; } -pub struct DelCommand; -pub static COMMAND_DESCRIPTOR: DelCommand = DelCommand; - -impl crate::commands::command_contract::CommandSpec for DelCommand { - fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { - crate::commands::command_contract::CommandMetadata { - name: "del", - category: "perms", - params: "perm <@&rôle/@membre/ID>", - description: "Supprime les permissions ACL associees a un role ou utilisateur.", - examples: &["+del", "+dl", "+help del"], - default_aliases: &["dlp"], - allow_in_dm: false, - default_permission: 7, - } - } -} diff --git a/src/commands/perms/delperm.rs b/src/commands/perms/delperm.rs new file mode 100644 index 0000000..22bd0d6 --- /dev/null +++ b/src/commands/perms/delperm.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_delperm_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::del::handle_del(ctx, msg, args).await; +} + +pub struct DelpermCommand; +pub static COMMAND_DESCRIPTOR: DelpermCommand = DelpermCommand; + +impl crate::commands::command_contract::CommandSpec for DelpermCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "delperm", + category: "perms", + params: "<@&role/@membre/ID>", + description: "Supprime les permissions ACL associees a un role ou utilisateur.", + examples: &["+delperm @Role", "+help delperm"], + default_aliases: &["dlp"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/perms/help.rs b/src/commands/perms/help.rs index b0ab428..eb8c060 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" | "setmodlogs" | "setboostembed" - | "leavesettings" | "viewlogs" => "logs", + | "autoconfiglog" | "nolog" | "joinsettings" | "boostembed" | "setmodlogs" + | "setboostembed" | "leavesettings" | "viewlogs" => "logs", "warn" | "mute" | "tempmute" @@ -164,14 +164,19 @@ fn help_page_for_command( "giveaway" | "end" | "reroll" | "choose" | "calc" | "emoji" | "embed" | "say" | "create" | "newsticker" | "button" | "autoreact" | "snipe" | "loading" | "backup" | "autobackup" => "outils", - "shadowbot" | "set" | "theme" | "playto" | "listen" | "watch" | "compet" | "stream" - | "removeactivity" | "online" | "idle" | "dnd" | "invisible" | "change" | "changeall" => { + "shadowbot" | "setname" | "setpic" | "setbanner" | "setprofil" | "setperm" + | "theme" | "playto" | "listen" | "watch" | "compet" | "stream" + | "removeactivity" | "online" | "idle" | "dnd" | "invisible" | "change" + | "changereset" | "changeall" => { "bot" } "owner" | "unowner" | "clearowners" | "bl" | "unbl" | "blinfo" | "clearbl" - | "allbots" | "alladmins" | "botadmins" | "mainprefix" | "prefix" | "mp" | "invite" - | "leave" | "discussion" => "administration", - "perms" | "del" | "clearperms" | "allperms" | "alias" | "help" | "helpsetting" => { + | "allbots" | "alladmins" | "botadmins" | "mainprefix" | "prefix" | "mp" + | "mpsettings" | "mpsent" | "mpdelete" | "invite" | "leave" | "discussion" => { + "administration" + } + "perms" | "delperm" | "clearperms" | "allperms" | "alias" | "help" + | "helpsetting" => { "permissions" } _ => match meta.category { @@ -193,6 +198,7 @@ fn help_page_for_command( "administration" => "administration", "permissions" => "permissions", "general" => "infos", + "automation" => "outils", "profile" => "bot", "admin" => "administration", _ => "infos", @@ -332,48 +338,6 @@ async fn aliases_map(ctx: &Context) -> BTreeMap> { fn command_doc(key: &str) -> Option { 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)) @@ -423,22 +387,37 @@ fn help_lookup_to_key(input: &str) -> Option<&'static str> { "member" => Some("member"), "pic" => Some("pic"), "banner" => Some("banner"), - "server" => Some("server"), + "server" | "server list" => Some("serverlist"), + "server pic" | "serverpic" => Some("serverpic"), + "server banner" | "serverbanner" => Some("serverbanner"), "serverlist" => Some("serverlist"), + "suggestion settings" | "suggestionsettings" => Some("suggestionsettings"), "snipe" => Some("snipe"), "emoji" => Some("emoji"), "giveaway" => Some("giveaway"), - "end" | "endgiveaway" => Some("end"), + "end" => Some("end"), + "end giveaway" | "endgiveaway" => Some("endgiveaway"), "reroll" => Some("reroll"), "choose" => Some("choose"), "embed" => Some("embed"), "backup" | "backup list" | "backup delete" | "backup load" => Some("backup"), + "autopublish" => Some("autopublish"), + "autopublish on" | "autopublishon" => Some("autopublishon"), + "autopublish off" | "autopublishoff" => Some("autopublishoff"), "autobackup" => Some("autobackup"), "loading" => Some("loading"), "create" => Some("create"), "newsticker" => Some("newsticker"), + "piconly" => Some("piconly"), + "piconly add" | "piconlyadd" => Some("piconlyadd"), + "piconly del" | "piconly remove" | "piconly delete" | "piconlydel" => { + Some("piconlydel") + } "massiverole" => Some("massiverole"), "unmassiverole" => Some("unmassiverole"), + "noderank" => Some("noderank"), + "noderank add" | "noderankadd" => Some("noderankadd"), + "noderank del" | "noderank remove" | "noderankdel" => Some("noderankdel"), "voicemove" => Some("voicemove"), "voicekick" => Some("voicekick"), "cleanup" => Some("cleanup"), @@ -452,7 +431,10 @@ fn help_lookup_to_key(input: &str) -> Option<&'static str> { "autoreact" => Some("autoreact"), "calc" => Some("calc"), "shadowbot" => Some("shadowbot"), - "set" => Some("set"), + "set" | "set name" | "setname" => Some("setname"), + "set pic" | "setpic" => Some("setpic"), + "set banner" | "setbanner" => Some("setbanner"), + "set profil" | "setprofil" => Some("setprofil"), "theme" => Some("theme"), "playto" => Some("playto"), "listen" => Some("listen"), @@ -479,6 +461,7 @@ fn help_lookup_to_key(input: &str) -> Option<&'static str> { "say" => Some("say"), "invite" => Some("invite"), "leave" => Some("leave"), + "join" | "join settings" | "joinsettings" => Some("joinsettings"), "change" => Some("change"), "changereset" => Some("changereset"), "changeall" => Some("changeall"), @@ -488,8 +471,13 @@ fn help_lookup_to_key(input: &str) -> Option<&'static str> { "allperms" => Some("allperms"), "setperm" => Some("setperm"), "delperm" => Some("delperm"), + "punish" => Some("punish"), + "punish setup" | "punishsetup" => Some("punishsetup"), + "punish add" | "punishadd" => Some("punishadd"), + "punish del" | "punishdel" => Some("punishdel"), "clearperms" => Some("clearperms"), "alias" => Some("alias"), + "alias remove" | "alias delete" | "unalias" => Some("unalias"), "helpsetting" | "helpetting" => Some("helpsetting"), _ => None, }; diff --git a/src/commands/perms/unalias.rs b/src/commands/perms/unalias.rs new file mode 100644 index 0000000..6d3c29d --- /dev/null +++ b/src/commands/perms/unalias.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_unalias_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::alias::handle_unalias(ctx, msg, args).await; +} + +pub struct UnaliasCommand; +pub static COMMAND_DESCRIPTOR: UnaliasCommand = UnaliasCommand; + +impl crate::commands::command_contract::CommandSpec for UnaliasCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "unalias", + category: "perms", + params: "", + description: "Supprime un alias de commande en base.", + examples: &["+unalias m", "+help unalias"], + default_aliases: &["uals"], + allow_in_dm: false, + default_permission: 6, + } + } +} diff --git a/src/commands/roles/noderank.rs b/src/commands/roles/noderank.rs index 9f193c6..aeb577a 100644 --- a/src/commands/roles/noderank.rs +++ b/src/commands/roles/noderank.rs @@ -17,69 +17,145 @@ pub async fn handle_noderank(ctx: &Context, msg: &Message, args: &[&str]) { let bot_id = ctx.cache.current_user().id.get() as i64; let guild_id_raw = guild_id.get() as i64; - if args.is_empty() { - let roles = db::list_noderank_roles(&pool, bot_id, guild_id_raw) - .await - .unwrap_or_default(); - let description = if roles.is_empty() { - "Aucun role protege.".to_string() - } else { - roles - .iter() - .map(|role_id| format!("<@&{}>", role_id)) - .collect::>() - .join("\n") - }; - + if !args.is_empty() { send_embed( ctx, msg, CreateEmbed::new() .title("NoDeRank") - .description(description) - .color(0x5865F2), + .description("Utilisation: +noderank") + .color(0xED4245), ) .await; return; } - if args.len() < 2 { + let roles = db::list_noderank_roles(&pool, bot_id, guild_id_raw) + .await + .unwrap_or_default(); + let description = if roles.is_empty() { + "Aucun role protege.".to_string() + } else { + roles + .iter() + .map(|role_id| format!("<@&{}>", role_id)) + .collect::>() + .join("\n") + }; + + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("NoDeRank") + .description(description) + .color(0x5865F2), + ) + .await; +} + +pub async fn handle_noderankadd(ctx: &Context, msg: &Message, args: &[&str]) { + if args.is_empty() { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("NoDeRank") + .description("Utilisation: +noderankadd <@role/ID/nom>") + .color(0xED4245), + ) + .await; return; } + 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 guild_id_raw = guild_id.get() as i64; + let Ok(guild) = guild_id.to_partial_guild(&ctx.http).await else { return; }; - let Some(role) = parse_role(&guild, args[1]) else { + let Some(role) = parse_role(&guild, args[0]) else { + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("NoDeRank") + .description("Role introuvable.") + .color(0xED4245), + ) + .await; return; }; - if args[0].eq_ignore_ascii_case("add") { - let _ = db::add_noderank_role(&pool, bot_id, guild_id_raw, role.id.get() as i64).await; + let _ = db::add_noderank_role(&pool, bot_id, guild_id_raw, role.id.get() as i64).await; + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("NoDeRank") + .description(format!("Role protege ajoute: <@&{}>", role.id.get())) + .color(0x57F287), + ) + .await; +} + +pub async fn handle_noderankdel(ctx: &Context, msg: &Message, args: &[&str]) { + if args.is_empty() { send_embed( ctx, msg, CreateEmbed::new() .title("NoDeRank") - .description(format!("Role protege ajoute: <@&{}>", role.id.get())) - .color(0x57F287), + .description("Utilisation: +noderankdel <@role/ID/nom>") + .color(0xED4245), ) .await; return; } - if args[0].eq_ignore_ascii_case("del") || args[0].eq_ignore_ascii_case("remove") { - let _ = db::remove_noderank_role(&pool, bot_id, guild_id_raw, role.id.get() as i64).await; + 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 guild_id_raw = guild_id.get() as i64; + + let Ok(guild) = guild_id.to_partial_guild(&ctx.http).await else { + return; + }; + let Some(role) = parse_role(&guild, args[0]) else { send_embed( ctx, msg, CreateEmbed::new() .title("NoDeRank") - .description(format!("Role protege retire: <@&{}>", role.id.get())) - .color(0x57F287), + .description("Role introuvable.") + .color(0xED4245), ) .await; - } + return; + }; + + let _ = db::remove_noderank_role(&pool, bot_id, guild_id_raw, role.id.get() as i64).await; + send_embed( + ctx, + msg, + CreateEmbed::new() + .title("NoDeRank") + .description(format!("Role protege retire: <@&{}>", role.id.get())) + .color(0x57F287), + ) + .await; } pub struct NoderankCommand; @@ -90,9 +166,9 @@ impl crate::commands::command_contract::CommandSpec for NoderankCommand { crate::commands::command_contract::CommandMetadata { name: "noderank", category: "roles", - params: "[add/del <@role/ID/nom>]", - description: "Definit des roles proteges qui ne sont pas retires par +derank.", - examples: &["+noderank", "+noderank add @VIP", "+noderank del @VIP"], + params: "aucun", + description: "Affiche la liste des roles proteges qui ne sont pas retires par +derank.", + examples: &["+noderank", "+help noderank"], default_aliases: &["ndr"], allow_in_dm: false, default_permission: 7, diff --git a/src/commands/roles/noderankadd.rs b/src/commands/roles/noderankadd.rs new file mode 100644 index 0000000..de08854 --- /dev/null +++ b/src/commands/roles/noderankadd.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_noderankadd_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::noderank::handle_noderankadd(ctx, msg, args).await; +} + +pub struct NoderankaddCommand; +pub static COMMAND_DESCRIPTOR: NoderankaddCommand = NoderankaddCommand; + +impl crate::commands::command_contract::CommandSpec for NoderankaddCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "noderankadd", + category: "roles", + params: "<@role/ID/nom>", + description: "Ajoute un role a la liste NoDeRank.", + examples: &["+noderankadd @VIP", "+help noderankadd"], + default_aliases: &["ndra"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/commands/roles/noderankdel.rs b/src/commands/roles/noderankdel.rs new file mode 100644 index 0000000..cade2ca --- /dev/null +++ b/src/commands/roles/noderankdel.rs @@ -0,0 +1,24 @@ +use serenity::model::prelude::*; +use serenity::prelude::*; + +pub async fn handle_noderankdel_command(ctx: &Context, msg: &Message, args: &[&str]) { + crate::commands::noderank::handle_noderankdel(ctx, msg, args).await; +} + +pub struct NoderankdelCommand; +pub static COMMAND_DESCRIPTOR: NoderankdelCommand = NoderankdelCommand; + +impl crate::commands::command_contract::CommandSpec for NoderankdelCommand { + fn metadata(&self) -> crate::commands::command_contract::CommandMetadata { + crate::commands::command_contract::CommandMetadata { + name: "noderankdel", + category: "roles", + params: "<@role/ID/nom>", + description: "Retire un role de la liste NoDeRank.", + examples: &["+noderankdel @VIP", "+help noderankdel"], + default_aliases: &["ndrd"], + allow_in_dm: false, + default_permission: 7, + } + } +} diff --git a/src/events/message_event.rs b/src/events/message_event.rs index a4097e8..47cf415 100644 --- a/src/events/message_event.rs +++ b/src/events/message_event.rs @@ -7,20 +7,24 @@ use crate::commands::moderation_tools; use crate::commands::remove_activity; use crate::commands::{ addrole, alias, ancien, antilink, antimassmention, antiraideautoconfig, antispam, autobackup, - autoconfiglog, autopublish, autoreact, backup, badwords, ban, banlist, banner, bl, blinfo, - boostembed, boosters, boostlog, bringall, button, calc, change, changeall, channel, choose, - claim, cleanup, clear_all_sanctions, clear_badwords, clear_bl, clear_limit, clear_messages, - clear_owners, clear_perms, clear_sanctions, close, cmute, compet, create, del, del_sanction, - delrole, derank, discussion, dnd, embed, emoji, end, giveaway, help, helpsetting, hide, - hideall, idle, invisible, invite, join, kick, leave, leave_settings, link, listen, loading, - lock, lockall, mainprefix, massiverole, member, messagelog, modlog, mp, mute, mutelist, - muterole, newsticker, noderank, nolog, online, owner, perms, pic, piconly, ping, playto, - prefix, public, punish, raidlog, rename, renew, reroll, resetantiraide, role, rolelog, - rolemembers, rolemenu, sanctions, say, server, serverinfo, set, set_boostembed, set_modlogs, - set_muterole, shadowbot, showpics, slowmode, snipe, spam, stream, strikes, suggestion, sync, + autoconfiglog, autopublish, autopublishoff, autopublishon, autoreact, backup, badwords, ban, + banlist, banner, bl, blinfo, boostembed, boosters, boostlog, bringall, button, calc, change, + changeall, changereset, + channel, choose, claim, cleanup, clear_all_sanctions, clear_badwords, clear_bl, clear_limit, + clear_messages, clear_owners, clear_perms, clear_sanctions, close, cmute, compet, create, + del_sanction, delperm, delrole, derank, discussion, dnd, embed, emoji, end, endgiveaway, + giveaway, help, helpsetting, hide, hideall, idle, invisible, invite, join, kick, leave, + leave_settings, link, listen, loading, lock, lockall, mainprefix, massiverole, member, + messagelog, modlog, mp, mpdelete, mpsent, mpsettings, mute, mutelist, muterole, newsticker, + noderank, noderankadd, noderankdel, nolog, online, owner, perms, pic, piconly, piconlyadd, + piconlydel, ping, playto, prefix, public, punish, punishadd, punishdel, punishsetup, + raidlog, rename, renew, reroll, resetantiraide, role, rolelog, rolemembers, rolemenu, + sanctions, say, serverbanner, serverinfo, serverlist, serverpic, set_boostembed, + set_modlogs, set_muterole, setbanner, setname, setperm, setpic, setprofil, shadowbot, + showpics, slowmode, snipe, spam, stream, strikes, suggestion, suggestionsettings, sync, tempban, tempcmute, tempmute, temprole, tempvoc, tempvoc_cmd, theme, ticket, ticket_member, tickets, timeout, unban, unbanall, unbl, uncmute, unhide, unhideall, unlock, unlockall, - unmassiverole, unmute, unmuteall, unowner, untemprole, user, viewlogs, vocinfo, voicekick, + unalias, unmassiverole, unmute, unmuteall, unowner, untemprole, user, viewlogs, vocinfo, voicekick, voicelog, voicemove, warn, watch, }; use crate::commands::{alladmins, allbots, allperms, botadmins}; @@ -141,16 +145,10 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { .or_else(|| { let mapped = match command_key.as_str() { "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"), - "setperm" => Some("set"), - "changereset" => Some("change"), - "serverlist" => Some("server"), - "endgiveaway" => Some("end"), - "mpsettings" | "mpsent" | "mpdelete" => Some("mp"), _ => None, }; @@ -191,23 +189,22 @@ 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, - "delperm" => { - let mut forwarded = vec!["perm"]; - forwarded.extend(args.iter().copied()); - del::handle_del(ctx, msg, &forwarded).await - } - "delsanction" => { - let mut forwarded = vec!["sanction"]; - forwarded.extend(args.iter().copied()); - del_sanction::handle_del_sanction(ctx, msg, &forwarded).await - } + "delperm" => delperm::handle_delperm_command(ctx, msg, &args).await, + "delsanction" => del_sanction::handle_del_sanction(ctx, msg, &args).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, "showpics" => showpics::handle_show_pics(ctx, msg, &args).await, "piconly" => piconly::handle_piconly(ctx, msg, &args).await, + "piconlyadd" => piconlyadd::handle_piconlyadd_command(ctx, msg, &args).await, + "piconlydel" => piconlydel::handle_piconlydel_command(ctx, msg, &args).await, "suggestion" => suggestion::handle_suggestion(ctx, msg, &args).await, + "suggestionsettings" => { + suggestionsettings::handle_suggestionsettings_command(ctx, msg, &args).await + } "autopublish" => autopublish::handle_autopublish(ctx, msg, &args).await, + "autopublishon" => autopublishon::handle_autopublishon_command(ctx, msg, &args).await, + "autopublishoff" => autopublishoff::handle_autopublishoff_command(ctx, msg, &args).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, @@ -224,6 +221,9 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "link" => link::handle_link_override(ctx, msg, &args).await, "strikes" => strikes::handle_strikes(ctx, msg, &args).await, "punish" => punish::handle_punish(ctx, msg, &args).await, + "punishsetup" => punishsetup::handle_punishsetup_command(ctx, msg, &args).await, + "punishadd" => punishadd::handle_punishadd_command(ctx, msg, &args).await, + "punishdel" => punishdel::handle_punishdel_command(ctx, msg, &args).await, "public" => public::handle_public(ctx, msg, &args).await, "resetantiraide" => resetantiraide::handle_resetantiraide(ctx, msg, &args).await, "allbots" => allbots::handle_allbots(ctx, msg, &args).await, @@ -241,8 +241,9 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "member" => member::handle_member(ctx, msg, &args).await, "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, + "serverpic" => serverpic::handle_serverpic(ctx, msg, &args).await, + "serverbanner" => serverbanner::handle_serverbanner(ctx, msg, &args).await, + "serverlist" => serverlist::handle_serverlist(ctx, msg, &args).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, @@ -253,15 +254,11 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "rolelog" => rolelog::handle_rolelog(ctx, msg, &args).await, "raidlog" => raidlog::handle_raidlog(ctx, msg, &args).await, "autoconfiglog" => autoconfiglog::handle_autoconfiglog(ctx, msg).await, - "join" => join::handle_join(ctx, msg, &args).await, + "joinsettings" => join::handle_join(ctx, msg, &args).await, "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 - } + "endgiveaway" => endgiveaway::handle_endgiveaway_command(ctx, msg, &args).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, @@ -391,6 +388,8 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { crate::commands::logs_service::log_moderation_command(ctx, msg, "derank", &args).await; } "noderank" => noderank::handle_noderank(ctx, msg, &args).await, + "noderankadd" => noderankadd::handle_noderankadd_command(ctx, msg, &args).await, + "noderankdel" => noderankdel::handle_noderankdel_command(ctx, msg, &args).await, "temprole" => temprole::handle_temprole(ctx, msg, &args).await, "untemprole" => untemprole::handle_untemprole(ctx, msg, &args).await, "sync" => sync::handle_sync(ctx, msg, &args).await, @@ -398,19 +397,14 @@ 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, - "setperm" => { - let mut forwarded = vec!["perm"]; - forwarded.extend(args.iter().copied()); - set::handle_set(ctx, msg, &forwarded).await - } - "setmuterole" => { - let mut forwarded = vec!["muterole"]; - forwarded.extend(args.iter().copied()); - set_muterole::handle_set_muterole(ctx, msg, &forwarded).await - } + "setperm" => setperm::handle_setperm_command(ctx, msg, &args).await, + "setname" => setname::handle_setname_command(ctx, msg, &args).await, + "setpic" => setpic::handle_setpic_command(ctx, msg, &args).await, + "setbanner" => setbanner::handle_setbanner_command(ctx, msg, &args).await, + "setprofil" => setprofil::handle_setprofil_command(ctx, msg, &args).await, + "setmuterole" => set_muterole::handle_set_muterole(ctx, msg, &args).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, "listen" => listen::handle_listen(ctx, msg, &args).await, @@ -420,28 +414,13 @@ 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 - } + "unalias" => unalias::handle_unalias_command(ctx, msg, &args).await, + "mpsettings" => mpsettings::handle_mpsettings_command(ctx, msg, &args).await, + "mpsent" => mpsent::handle_mpsent_command(ctx, msg, &args).await, + "mpdelete" | "mpdel" => mpdelete::handle_mpdelete_command(ctx, msg, &args).await, "mp" => mp::handle_mp(ctx, msg, &args).await, "invite" => invite::handle_invite(ctx, msg, &args).await, - "leavesettings" => { - let mut forwarded = vec!["settings"]; - forwarded.extend(args.iter().copied()); - leave_settings::handle_leave_settings(ctx, msg, &forwarded).await - } + "leavesettings" => leave_settings::handle_leave_settings(ctx, msg, &args).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, @@ -456,11 +435,7 @@ 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 - } + "changereset" => changereset::handle_changereset_command(ctx, msg, &args).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, @@ -470,17 +445,9 @@ pub async fn handle_message(ctx: &Context, msg: &Message) { "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 - } + "clearlimit" => clear_limit::handle_clear_limit(ctx, msg, &args).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 - } + "clearsanctions" => clear_sanctions::handle_clear_sanctions(ctx, msg, &args).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 64193e4..d66434e 100644 --- a/src/permissions.rs +++ b/src/permissions.rs @@ -15,22 +15,9 @@ const EXTRA_COMMAND_KEYS: &[&str] = &[ "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 { +pub fn command_key(command: &str, _args: &[&str]) -> String { let normalized = command.to_lowercase(); match normalized.as_str() { @@ -39,42 +26,7 @@ pub fn command_key(command: &str, args: &[&str]) -> String { "del" => "ticket_remove".to_string(), "close" => "ticket_close".to_string(), "clear" => "clearmessages".to_string(), - "suggestion" => { - if first_arg_is(args, "settings") { - "suggestion_settings".to_string() - } else { - "suggestion_create".to_string() - } - } - "change" => { - if first_arg_is(args, "reset") { - "changereset".to_string() - } else { - "change".to_string() - } - } - "server" => { - if first_arg_is(args, "list") { - "serverlist".to_string() - } else { - "server".to_string() - } - } - "end" => { - if first_arg_is(args, "giveaway") { - "endgiveaway".to_string() - } else { - "end".to_string() - } - } - "mp" => { - if first_arg_is(args, "settings") { - "mpsettings".to_string() - } else { - "mp".to_string() - } - } - "mpsent" | "mpdelete" | "mpdel" => "mp".to_string(), + "mpdel" => "mpdelete".to_string(), "helpetting" => "helpsetting".to_string(), _ => normalized, } @@ -99,13 +51,6 @@ fn metadata_key_for_permission(command_key: &str) -> &str { "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, } } diff --git a/src/commands/admin_common.rs b/src/utils/admin_common.rs similarity index 100% rename from src/commands/admin_common.rs rename to src/utils/admin_common.rs diff --git a/src/commands/admin_service.rs b/src/utils/admin_service.rs similarity index 100% rename from src/commands/admin_service.rs rename to src/utils/admin_service.rs diff --git a/src/commands/advanced_tools.rs b/src/utils/advanced_tools.rs similarity index 100% rename from src/commands/advanced_tools.rs rename to src/utils/advanced_tools.rs diff --git a/src/commands/automod_service.rs b/src/utils/automod_service.rs similarity index 100% rename from src/commands/automod_service.rs rename to src/utils/automod_service.rs diff --git a/src/commands/botconfig_common.rs b/src/utils/botconfig_common.rs similarity index 100% rename from src/commands/botconfig_common.rs rename to src/utils/botconfig_common.rs diff --git a/src/commands/botconfig_service.rs b/src/utils/botconfig_service.rs similarity index 100% rename from src/commands/botconfig_service.rs rename to src/utils/botconfig_service.rs diff --git a/src/commands/command_contract.rs b/src/utils/command_contract.rs similarity index 100% rename from src/commands/command_contract.rs rename to src/utils/command_contract.rs diff --git a/src/commands/common.rs b/src/utils/common.rs similarity index 100% rename from src/commands/common.rs rename to src/utils/common.rs diff --git a/src/events/handler.rs b/src/utils/events_handler.rs similarity index 100% rename from src/events/handler.rs rename to src/utils/events_handler.rs diff --git a/src/commands/logs_command_helpers.rs b/src/utils/logs_command_helpers.rs similarity index 100% rename from src/commands/logs_command_helpers.rs rename to src/utils/logs_command_helpers.rs diff --git a/src/commands/logs_service.rs b/src/utils/logs_service.rs similarity index 100% rename from src/commands/logs_service.rs rename to src/utils/logs_service.rs diff --git a/src/commands/moderation_channel_helpers.rs b/src/utils/moderation_channel_helpers.rs similarity index 100% rename from src/commands/moderation_channel_helpers.rs rename to src/utils/moderation_channel_helpers.rs diff --git a/src/commands/moderation_sanction_helpers.rs b/src/utils/moderation_sanction_helpers.rs similarity index 100% rename from src/commands/moderation_sanction_helpers.rs rename to src/utils/moderation_sanction_helpers.rs diff --git a/src/commands/moderation_tools.rs b/src/utils/moderation_tools.rs similarity index 100% rename from src/commands/moderation_tools.rs rename to src/utils/moderation_tools.rs diff --git a/src/commands/perms_helpers.rs b/src/utils/perms_helpers.rs similarity index 100% rename from src/commands/perms_helpers.rs rename to src/utils/perms_helpers.rs diff --git a/src/commands/perms_service.rs b/src/utils/perms_service.rs similarity index 100% rename from src/commands/perms_service.rs rename to src/utils/perms_service.rs diff --git a/src/commands/slash_commands_manager.rs b/src/utils/slash_commands_manager.rs similarity index 100% rename from src/commands/slash_commands_manager.rs rename to src/utils/slash_commands_manager.rs