chore(commands): reorganize command files by metadata categories

This commit is contained in:
Puechberty Arthur
2026-04-10 15:25:21 +02:00
parent 23dcc69977
commit 1b5e51c428
154 changed files with 399 additions and 399 deletions
+90
View File
@@ -0,0 +1,90 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::commands::perms_helpers::{ensure_owner, get_pool, normalize_command_name};
use crate::db::{reset_command_permissions, set_command_permission};
pub async fn handle_change(ctx: &Context, msg: &Message, args: &[&str]) {
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;
};
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")
.description("Usage: `change <commande> <permission>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let command = normalize_command_name(args[0]);
let Ok(level) = args[1].parse::<u8>() else {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Permission invalide (0..9).")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
};
if level > 9 {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Permission invalide (0..9).")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let _ = set_command_permission(&pool, bot_id, &command, level).await;
let embed = CreateEmbed::new()
.title("Permission modifiee")
.description(format!("`{}` -> niveau `{}`", command, level))
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct ChangeCommand;
pub static COMMAND_DESCRIPTOR: ChangeCommand = ChangeCommand;
impl crate::commands::command_contract::CommandSpec for ChangeCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "change",
category: "botconfig",
params: "<commande> <niveau 0-9> | reset",
description: "Definit le niveau ACL requis pour une commande ou reinitialise les overrides.",
examples: &["+change", "+ce", "+help change"],
default_aliases: &["chg"],
allow_in_dm: false,
default_permission: 8,
}
}
}
+93
View File
@@ -0,0 +1,93 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::commands::perms_helpers::{ensure_owner, get_pool};
use crate::db::set_command_permission;
use crate::permissions::{all_command_keys, command_required_permission};
pub async fn handle_changeall(ctx: &Context, msg: &Message, args: &[&str]) {
if !ensure_owner(ctx, msg).await {
return;
}
if args.len() < 2 {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `changeall <permission> <permission>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let Ok(from) = args[0].parse::<u8>() else {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Permission source invalide.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
};
let Ok(to) = args[1].parse::<u8>() else {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Permission cible invalide.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
};
if from > 9 || to > 9 {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Permissions valides: 0..9")
.color(0xED4245);
send_embed(ctx, msg, embed).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 mut updated = 0usize;
for cmd in all_command_keys() {
let current = command_required_permission(ctx, &cmd).await;
if current == from {
let _ = set_command_permission(&pool, bot_id, &cmd, to).await;
updated += 1;
}
}
let embed = CreateEmbed::new()
.title("Changeall applique")
.description(format!("{} commande(s): {} -> {}", updated, from, to))
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct ChangeallCommand;
pub static COMMAND_DESCRIPTOR: ChangeallCommand = ChangeallCommand;
impl crate::commands::command_contract::CommandSpec for ChangeallCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "changeall",
category: "botconfig",
params: "<niveau_source 0-9> <niveau_cible 0-9>",
description: "Remplace en masse un niveau ACL source par un niveau ACL cible.",
examples: &["+changeall", "+cl", "+help changeall"],
default_aliases: &["cga"],
allow_in_dm: false,
default_permission: 9,
}
}
}
+100
View File
@@ -0,0 +1,100 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::activity::{RotatingActivityKind, parse_status, start_rotation};
use crate::commands::common::send_embed;
use crate::db::DbPoolKey;
pub async fn handle_compet(ctx: &Context, msg: &Message, args: &[&str]) {
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `+playto|+listen|+watch|+compet|+stream <message>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let Some(kind) = RotatingActivityKind::from_command("+compet") else {
return;
};
let joined = args.join(" ");
let messages: Vec<String> = joined
.split(",,")
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
if messages.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Aucun message d'activité valide.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let bot_id = ctx.cache.current_user().id;
let status = {
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
if let Ok(Some(saved)) = crate::db::get_bot_status(&pool, bot_id).await {
parse_status(&saved)
} else {
OnlineStatus::Online
}
} else {
OnlineStatus::Online
}
};
start_rotation(ctx, kind, messages.clone(), status).await;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ =
crate::db::set_bot_activity(&pool, bot_id, kind.as_db(), &messages.join("\n")).await;
}
let embed = CreateEmbed::new()
.title("Activité mise à jour")
.description(format!("{} message(s) configuré(s).", messages.len()))
.field(
"Rotation",
"Les textes alternent toutes les 30 secondes.",
false,
)
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct CompetCommand;
pub static COMMAND_DESCRIPTOR: CompetCommand = CompetCommand;
impl crate::commands::command_contract::CommandSpec for CompetCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "compet",
category: "botconfig",
params: "<texte[, ,texte2,...]>",
description: "Configure la rotation des messages d activite en mode competing.",
examples: &["+compet", "+ct", "+help compet"],
default_aliases: &["cpt"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+44
View File
@@ -0,0 +1,44 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::db::{DbPoolKey, set_bot_status};
pub async fn handle_dnd(ctx: &Context, msg: &Message) {
ctx.dnd();
let bot_id = ctx.cache.current_user().id;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ = set_bot_status(&pool, bot_id, "dnd").await;
}
let embed = CreateEmbed::new()
.title("Statut mis à jour")
.description("Nouveau statut: dnd")
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct DndCommand;
pub static COMMAND_DESCRIPTOR: DndCommand = DndCommand;
impl crate::commands::command_contract::CommandSpec for DndCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "dnd",
category: "botconfig",
params: "aucun",
description: "Change le statut du bot en do not disturb et sauvegarde ce statut.",
examples: &["+dnd", "+dd", "+help dnd"],
default_aliases: &["dnm"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+44
View File
@@ -0,0 +1,44 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::db::{DbPoolKey, set_bot_status};
pub async fn handle_idle(ctx: &Context, msg: &Message) {
ctx.idle();
let bot_id = ctx.cache.current_user().id;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ = set_bot_status(&pool, bot_id, "idle").await;
}
let embed = CreateEmbed::new()
.title("Statut mis à jour")
.description("Nouveau statut: idle")
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct IdleCommand;
pub static COMMAND_DESCRIPTOR: IdleCommand = IdleCommand;
impl crate::commands::command_contract::CommandSpec for IdleCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "idle",
category: "botconfig",
params: "aucun",
description: "Change le statut du bot en idle et sauvegarde ce statut.",
examples: &["+idle", "+ie", "+help idle"],
default_aliases: &["idl"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+44
View File
@@ -0,0 +1,44 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::db::{DbPoolKey, set_bot_status};
pub async fn handle_invisible(ctx: &Context, msg: &Message) {
ctx.invisible();
let bot_id = ctx.cache.current_user().id;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ = set_bot_status(&pool, bot_id, "invisible").await;
}
let embed = CreateEmbed::new()
.title("Statut mis à jour")
.description("Nouveau statut: invisible")
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct InvisibleCommand;
pub static COMMAND_DESCRIPTOR: InvisibleCommand = InvisibleCommand;
impl crate::commands::command_contract::CommandSpec for InvisibleCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "invisible",
category: "botconfig",
params: "aucun",
description: "Change le statut du bot en invisible et sauvegarde ce statut.",
examples: &["+invisible", "+ie", "+help invisible"],
default_aliases: &["ivs"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+100
View File
@@ -0,0 +1,100 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::activity::{RotatingActivityKind, parse_status, start_rotation};
use crate::commands::common::send_embed;
use crate::db::DbPoolKey;
pub async fn handle_listen(ctx: &Context, msg: &Message, args: &[&str]) {
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `+playto|+listen|+watch|+compet|+stream <message>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let Some(kind) = RotatingActivityKind::from_command("+listen") else {
return;
};
let joined = args.join(" ");
let messages: Vec<String> = joined
.split(",,")
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
if messages.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Aucun message d'activité valide.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let bot_id = ctx.cache.current_user().id;
let status = {
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
if let Ok(Some(saved)) = crate::db::get_bot_status(&pool, bot_id).await {
parse_status(&saved)
} else {
OnlineStatus::Online
}
} else {
OnlineStatus::Online
}
};
start_rotation(ctx, kind, messages.clone(), status).await;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ =
crate::db::set_bot_activity(&pool, bot_id, kind.as_db(), &messages.join("\n")).await;
}
let embed = CreateEmbed::new()
.title("Activité mise à jour")
.description(format!("{} message(s) configuré(s).", messages.len()))
.field(
"Rotation",
"Les textes alternent toutes les 30 secondes.",
false,
)
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct ListenCommand;
pub static COMMAND_DESCRIPTOR: ListenCommand = ListenCommand;
impl crate::commands::command_contract::CommandSpec for ListenCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "listen",
category: "botconfig",
params: "<texte[, ,texte2,...]>",
description: "Configure la rotation des messages d activite en mode listening.",
examples: &["+listen", "+ln", "+help listen"],
default_aliases: &["lsn"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+61
View File
@@ -0,0 +1,61 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::commands::perms_helpers::{ensure_owner, get_pool};
use crate::db::set_main_prefix;
pub async fn handle_mainprefix(ctx: &Context, msg: &Message, args: &[&str]) {
if !ensure_owner(ctx, msg).await {
return;
}
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `mainprefix <prefixe>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let prefix = args[0].trim();
if prefix.is_empty() || prefix.len() > 5 {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Prefixe invalide (1 a 5 caracteres).")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let bot_id = ctx.cache.current_user().id;
if let Some(pool) = get_pool(ctx).await {
let _ = set_main_prefix(&pool, bot_id, prefix).await;
}
let embed = CreateEmbed::new()
.title("Prefixe principal mis a jour")
.description(format!("Nouveau prefixe principal: `{}`", prefix))
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct MainprefixCommand;
pub static COMMAND_DESCRIPTOR: MainprefixCommand = MainprefixCommand;
impl crate::commands::command_contract::CommandSpec for MainprefixCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "mainprefix",
category: "botconfig",
params: "<prefix>",
description: "Definit le prefixe principal utilise par le bot sur tous les serveurs.",
examples: &["+mainprefix", "+mx", "+help mainprefix"],
default_aliases: &["mpx"],
allow_in_dm: false,
default_permission: 9,
}
}
}
+44
View File
@@ -0,0 +1,44 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::db::{DbPoolKey, set_bot_status};
pub async fn handle_online(ctx: &Context, msg: &Message) {
ctx.online();
let bot_id = ctx.cache.current_user().id;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ = set_bot_status(&pool, bot_id, "online").await;
}
let embed = CreateEmbed::new()
.title("Statut mis à jour")
.description("Nouveau statut: online")
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct OnlineCommand;
pub static COMMAND_DESCRIPTOR: OnlineCommand = OnlineCommand;
impl crate::commands::command_contract::CommandSpec for OnlineCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "online",
category: "botconfig",
params: "aucun",
description: "Change le statut du bot en online et sauvegarde ce statut.",
examples: &["+online", "+oe", "+help online"],
default_aliases: &["onl"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+100
View File
@@ -0,0 +1,100 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::activity::{RotatingActivityKind, parse_status, start_rotation};
use crate::commands::common::send_embed;
use crate::db::DbPoolKey;
pub async fn handle_playto(ctx: &Context, msg: &Message, args: &[&str]) {
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `+playto|+listen|+watch|+compet|+stream <message>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let Some(kind) = RotatingActivityKind::from_command("+playto") else {
return;
};
let joined = args.join(" ");
let messages: Vec<String> = joined
.split(",,")
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
if messages.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Aucun message d'activité valide.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let bot_id = ctx.cache.current_user().id;
let status = {
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
if let Ok(Some(saved)) = crate::db::get_bot_status(&pool, bot_id).await {
parse_status(&saved)
} else {
OnlineStatus::Online
}
} else {
OnlineStatus::Online
}
};
start_rotation(ctx, kind, messages.clone(), status).await;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ =
crate::db::set_bot_activity(&pool, bot_id, kind.as_db(), &messages.join("\n")).await;
}
let embed = CreateEmbed::new()
.title("Activité mise à jour")
.description(format!("{} message(s) configuré(s).", messages.len()))
.field(
"Rotation",
"Les textes alternent toutes les 30 secondes.",
false,
)
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct PlaytoCommand;
pub static COMMAND_DESCRIPTOR: PlaytoCommand = PlaytoCommand;
impl crate::commands::command_contract::CommandSpec for PlaytoCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "playto",
category: "botconfig",
params: "<texte[, ,texte2,...]>",
description: "Configure la rotation des messages d activite en mode playing.",
examples: &["+playto", "+po", "+help playto"],
default_aliases: &["ply"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+70
View File
@@ -0,0 +1,70 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::commands::perms_helpers::{ensure_owner, get_pool};
use crate::db::set_guild_prefix;
pub async fn handle_prefix(ctx: &Context, msg: &Message, args: &[&str]) {
if !ensure_owner(ctx, msg).await {
return;
}
let Some(guild_id) = msg.guild_id else {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Commande disponible uniquement sur un serveur.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
};
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `prefix <prefixe>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let prefix = args[0].trim();
if prefix.is_empty() || prefix.len() > 5 {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Prefixe invalide (1 a 5 caracteres).")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let bot_id = ctx.cache.current_user().id;
if let Some(pool) = get_pool(ctx).await {
let _ = set_guild_prefix(&pool, bot_id, guild_id, prefix).await;
}
let embed = CreateEmbed::new()
.title("Prefixe serveur mis a jour")
.description(format!("Nouveau prefixe ici: `{}`", prefix))
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct PrefixCommand;
pub static COMMAND_DESCRIPTOR: PrefixCommand = PrefixCommand;
impl crate::commands::command_contract::CommandSpec for PrefixCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "prefix",
category: "botconfig",
params: "<prefix>",
description: "Definit le prefixe du serveur courant.",
examples: &["+prefix", "+px", "+help prefix"],
default_aliases: &["pfx"],
allow_in_dm: false,
default_permission: 6,
}
}
}
+47
View File
@@ -0,0 +1,47 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::activity::stop_rotation;
use crate::commands::common::send_embed;
use crate::db::DbPoolKey;
pub async fn handle_remove_activity(ctx: &Context, msg: &Message) {
stop_rotation(ctx).await;
ctx.set_activity(None);
let bot_id = ctx.cache.current_user().id;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ = crate::db::clear_bot_activity(&pool, bot_id).await;
}
let embed = CreateEmbed::new()
.title("Activité supprimée")
.description("L'activité du bot a été retirée.")
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct RemoveActivityCommand;
pub static COMMAND_DESCRIPTOR: RemoveActivityCommand = RemoveActivityCommand;
impl crate::commands::command_contract::CommandSpec for RemoveActivityCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "remove_activity",
category: "botconfig",
params: "aucun",
description: "Arrete la rotation d activite et retire lactivite courante du bot.",
examples: &["+remove activity", "+ry", "+help remove activity"],
default_aliases: &["rma"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+334
View File
@@ -0,0 +1,334 @@
use serenity::builder::{CreateAttachment, CreateEmbed, EditProfile};
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::send_embed;
use crate::commands::perms_helpers::{
ensure_owner, get_pool, normalize_command_name, parse_user_or_role,
};
use crate::db::{grant_command_access, grant_perm_level};
async fn handle_set_perm(ctx: &Context, msg: &Message, args: &[&str]) {
if !ensure_owner(ctx, msg).await {
return;
}
if args.len() < 3 || !args[0].eq_ignore_ascii_case("perm") {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `set perm <permission/commande> <role/membre>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let Some((scope_type, scope_id)) = parse_user_or_role(args[2]) else {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Role/membre invalide.")
.color(0xED4245);
send_embed(ctx, msg, embed).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;
};
if let Ok(level) = args[1].parse::<u8>() {
if level > 9 {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Permission invalide (0..9).")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let _ = grant_perm_level(&pool, bot_id, scope_type, scope_id, level).await;
let who = if scope_type == "role" {
format!("<@&{}>", scope_id)
} else {
format!("<@{}>", scope_id)
};
let embed = CreateEmbed::new()
.title("Permission attribuee")
.description(format!("{} recoit la permission `{}`", who, level))
.color(0x57F287);
send_embed(ctx, msg, embed).await;
return;
}
let command = normalize_command_name(args[1]);
let _ = grant_command_access(&pool, bot_id, scope_type, scope_id, &command).await;
let who = if scope_type == "role" {
format!("<@&{}>", scope_id)
} else {
format!("<@{}>", scope_id)
};
let embed = CreateEmbed::new()
.title("Acces commande attribue")
.description(format!("{} recoit l'acces direct a `{}`", who, command))
.color(0x57F287);
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;
}
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `+set name|pic|banner|profil ...`")
.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 <nom>`")
.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 <lien_image>`")
.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 <lien_image>`")
.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 <nom> ;; <lien_pic> ;; <lien_banner>`")
.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 embed = CreateEmbed::new()
.title("Erreur")
.description("Sous-commande inconnue. Utilise `name`, `pic`, `banner` ou `profil`.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
}
}
}
pub struct SetCommand;
pub static COMMAND_DESCRIPTOR: SetCommand = SetCommand;
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 <nom> | pic <url> | banner <url> | profil <nom> ;; <url_pic> ;; <url_banner> | 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,
}
}
}
+35
View File
@@ -0,0 +1,35 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::common::{send_embed, theme_color};
pub async fn handle_shadowbot(ctx: &Context, msg: &Message, _args: &[&str]) {
let invite = "https://discord.gg/NbMWHh54bp";
let color = theme_color(ctx).await;
let embed = CreateEmbed::new()
.title("Support Shadowbot")
.description(format!("Invitation: {}", invite))
.color(color);
send_embed(ctx, msg, embed).await;
}
pub struct ShadowbotCommand;
pub static COMMAND_DESCRIPTOR: ShadowbotCommand = ShadowbotCommand;
impl crate::commands::command_contract::CommandSpec for ShadowbotCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "shadowbot",
category: "botconfig",
params: "aucun",
description: "Affiche les informations globales et letat du bot.",
examples: &["+shadowbot", "+st", "+help shadowbot"],
default_aliases: &["sbt"],
allow_in_dm: true,
default_permission: 0,
}
}
}
+100
View File
@@ -0,0 +1,100 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::activity::{RotatingActivityKind, parse_status, start_rotation};
use crate::commands::common::send_embed;
use crate::db::DbPoolKey;
pub async fn handle_stream(ctx: &Context, msg: &Message, args: &[&str]) {
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `+playto|+listen|+watch|+compet|+stream <message>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let Some(kind) = RotatingActivityKind::from_command("+stream") else {
return;
};
let joined = args.join(" ");
let messages: Vec<String> = joined
.split(",,")
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
if messages.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Aucun message d'activité valide.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let bot_id = ctx.cache.current_user().id;
let status = {
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
if let Ok(Some(saved)) = crate::db::get_bot_status(&pool, bot_id).await {
parse_status(&saved)
} else {
OnlineStatus::Online
}
} else {
OnlineStatus::Online
}
};
start_rotation(ctx, kind, messages.clone(), status).await;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ =
crate::db::set_bot_activity(&pool, bot_id, kind.as_db(), &messages.join("\n")).await;
}
let embed = CreateEmbed::new()
.title("Activité mise à jour")
.description(format!("{} message(s) configuré(s).", messages.len()))
.field(
"Rotation",
"Les textes alternent toutes les 30 secondes.",
false,
)
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct StreamCommand;
pub static COMMAND_DESCRIPTOR: StreamCommand = StreamCommand;
impl crate::commands::command_contract::CommandSpec for StreamCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "stream",
category: "botconfig",
params: "<texte[, ,texte2,...]>",
description: "Configure la rotation des messages d activite en mode streaming.",
examples: &["+stream", "+sm", "+help stream"],
default_aliases: &["stm"],
allow_in_dm: false,
default_permission: 7,
}
}
}
+63
View File
@@ -0,0 +1,63 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::botconfig_common::parse_color;
use crate::commands::common::send_embed;
use crate::db::{DbPoolKey, set_bot_theme};
pub async fn handle_theme(ctx: &Context, msg: &Message, args: &[&str]) {
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `+theme <couleur>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let value = args.join(" ");
let Some(color) = parse_color(&value) else {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Couleur invalide. Ex: `#5865F2`, `bleu`, `0xFFAA00`.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
};
let bot_id = ctx.cache.current_user().id;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ = set_bot_theme(&pool, bot_id, color).await;
}
let embed = CreateEmbed::new()
.title("Thème mis à jour")
.description(format!("Nouvelle couleur: `#{:06X}`", color))
.color(color);
send_embed(ctx, msg, embed).await;
}
pub struct ThemeCommand;
pub static COMMAND_DESCRIPTOR: ThemeCommand = ThemeCommand;
impl crate::commands::command_contract::CommandSpec for ThemeCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "theme",
category: "botconfig",
params: "<couleur|#hex|0xhex>",
description: "Met a jour la couleur principale des embeds du bot.",
examples: &["+theme", "+te", "+help theme"],
default_aliases: &["thm"],
allow_in_dm: false,
default_permission: 6,
}
}
}
+100
View File
@@ -0,0 +1,100 @@
use serenity::builder::CreateEmbed;
use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::activity::{RotatingActivityKind, parse_status, start_rotation};
use crate::commands::common::send_embed;
use crate::db::DbPoolKey;
pub async fn handle_watch(ctx: &Context, msg: &Message, args: &[&str]) {
if args.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Usage: `+playto|+listen|+watch|+compet|+stream <message>`")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let Some(kind) = RotatingActivityKind::from_command("+watch") else {
return;
};
let joined = args.join(" ");
let messages: Vec<String> = joined
.split(",,")
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
if messages.is_empty() {
let embed = CreateEmbed::new()
.title("Erreur")
.description("Aucun message d'activité valide.")
.color(0xED4245);
send_embed(ctx, msg, embed).await;
return;
}
let bot_id = ctx.cache.current_user().id;
let status = {
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
if let Ok(Some(saved)) = crate::db::get_bot_status(&pool, bot_id).await {
parse_status(&saved)
} else {
OnlineStatus::Online
}
} else {
OnlineStatus::Online
}
};
start_rotation(ctx, kind, messages.clone(), status).await;
let pool = {
let data = ctx.data.read().await;
data.get::<DbPoolKey>().cloned()
};
if let Some(pool) = pool {
let _ =
crate::db::set_bot_activity(&pool, bot_id, kind.as_db(), &messages.join("\n")).await;
}
let embed = CreateEmbed::new()
.title("Activité mise à jour")
.description(format!("{} message(s) configuré(s).", messages.len()))
.field(
"Rotation",
"Les textes alternent toutes les 30 secondes.",
false,
)
.color(0x57F287);
send_embed(ctx, msg, embed).await;
}
pub struct WatchCommand;
pub static COMMAND_DESCRIPTOR: WatchCommand = WatchCommand;
impl crate::commands::command_contract::CommandSpec for WatchCommand {
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
crate::commands::command_contract::CommandMetadata {
name: "watch",
category: "botconfig",
params: "<texte[, ,texte2,...]>",
description: "Configure la rotation des messages d activite en mode watching.",
examples: &["+watch", "+wh", "+help watch"],
default_aliases: &["wtc"],
allow_in_dm: false,
default_permission: 7,
}
}
}