mirror of
https://github.com/arthur-pbty/shadowbot.git
synced 2026-06-03 23:36:25 +02:00
chore(commands): reorganize command files by metadata categories
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{add_sanction, parse_targets};
|
||||
|
||||
pub async fn handle_ban(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let reason = if args.len() > 1 {
|
||||
args[1..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
let mut done = 0usize;
|
||||
for uid in &targets {
|
||||
if guild_id
|
||||
.ban_with_reason(&ctx.http, *uid, 0, &reason)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
done += 1;
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"ban",
|
||||
&reason,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Ban")
|
||||
.description(format!("{} membre(s) banni(s).", done))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct BanCommand;
|
||||
pub static COMMAND_DESCRIPTOR: BanCommand = BanCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for BanCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "ban",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> [raison]",
|
||||
description: "Ban un ou plusieurs membres.",
|
||||
examples: &["+ban @User"],
|
||||
default_aliases: &["b"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
|
||||
pub async fn handle_banlist(ctx: &Context, msg: &Message) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bans = guild_id
|
||||
.bans(&ctx.http, None, None)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
let desc = if bans.is_empty() {
|
||||
"Aucun ban en cours.".to_string()
|
||||
} else {
|
||||
bans.into_iter()
|
||||
.map(|ban| format!("- <@{}> ({})", ban.user.id.get(), ban.user.tag()))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("BanList")
|
||||
.description(desc)
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct BanlistCommand;
|
||||
pub static COMMAND_DESCRIPTOR: BanlistCommand = BanlistCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for BanlistCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "banlist",
|
||||
category: "mod",
|
||||
params: "aucun",
|
||||
description: "Affiche la liste des bannissements en cours.",
|
||||
examples: &["+banlist"],
|
||||
default_aliases: &["bls"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{parse_channel_id, send_embed, theme_color};
|
||||
|
||||
pub async fn handle_cleanup(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(channel_raw) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let Some(channel_id) = parse_channel_id(channel_raw) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let user_ids = {
|
||||
let Some(guild) = guild_id.to_guild_cached(&ctx.cache) else {
|
||||
return;
|
||||
};
|
||||
|
||||
guild
|
||||
.voice_states
|
||||
.iter()
|
||||
.filter_map(|(uid, state)| {
|
||||
if state.channel_id == Some(channel_id) {
|
||||
Some(*uid)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let mut kicked = 0usize;
|
||||
for user_id in user_ids {
|
||||
if guild_id.disconnect_member(&ctx.http, user_id).await.is_ok() {
|
||||
kicked += 1;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Cleanup")
|
||||
.description(format!("{} utilisateurs déconnectés.", kicked))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct CleanupCommand;
|
||||
pub static COMMAND_DESCRIPTOR: CleanupCommand = CleanupCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for CleanupCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "cleanup",
|
||||
category: "mod",
|
||||
params: "<salon_vocal>",
|
||||
description: "Deconnecte tous les utilisateurs presents dans un salon vocal cible.",
|
||||
examples: &["+cleanup #General"],
|
||||
default_aliases: &["vclean", "vcleanup"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::db::DbPoolKey;
|
||||
|
||||
pub async fn handle_clear_all_sanctions(ctx: &Context, msg: &Message) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let pool = {
|
||||
let data = ctx.data.read().await;
|
||||
data.get::<DbPoolKey>().cloned()
|
||||
};
|
||||
let Some(pool) = pool else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
let removed = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM bot_sanctions
|
||||
WHERE bot_id = $1 AND guild_id = $2;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.ok()
|
||||
.map(|r| r.rows_affected())
|
||||
.unwrap_or(0);
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Sanctions")
|
||||
.description(format!(
|
||||
"{} sanction(s) supprimée(s) sur le serveur.",
|
||||
removed
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct ClearAllSanctionsCommand;
|
||||
pub static COMMAND_DESCRIPTOR: ClearAllSanctionsCommand = ClearAllSanctionsCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for ClearAllSanctionsCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "clear_all_sanctions",
|
||||
category: "mod",
|
||||
params: "aucun",
|
||||
description: "Efface toutes les sanctions de tous les membres du serveur.",
|
||||
examples: &["+clear all sanctions"],
|
||||
default_aliases: &["casanctions"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::automod_service::pool;
|
||||
use crate::commands::common::send_embed;
|
||||
use crate::db;
|
||||
|
||||
pub async fn handle_clear_badwords(ctx: &Context, msg: &Message, _args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bot_id = ctx.cache.current_user().id.get() as i64;
|
||||
let cleared = db::clear_badwords(&pool, bot_id, guild_id.get() as i64)
|
||||
.await
|
||||
.unwrap_or(0);
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Clear BadWords")
|
||||
.description(format!("{} mot(s) interdit(s) supprime(s).", cleared))
|
||||
.color(0x57F287),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct ClearBadwordsCommand;
|
||||
pub static COMMAND_DESCRIPTOR: ClearBadwordsCommand = ClearBadwordsCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for ClearBadwordsCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "clear_badwords",
|
||||
category: "mod",
|
||||
params: "badwords",
|
||||
description: "Supprime l ensemble des mots interdits enregistres.",
|
||||
examples: &["+clear badwords", "+help clear badwords"],
|
||||
default_aliases: &["cbw"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::automod_service::pool;
|
||||
use crate::commands::common::send_embed;
|
||||
use crate::db;
|
||||
|
||||
pub async fn handle_clear_limit(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(raw_value) = args.get(1) else {
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Clear Limit")
|
||||
.description("Usage: +clear limit <nombre>")
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(value) = raw_value.parse::<i32>() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let clamped = value.clamp(1, 1_000);
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bot_id = ctx.cache.current_user().id.get() as i64;
|
||||
if db::set_clear_limit(&pool, bot_id, guild_id.get() as i64, clamped)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Clear Limit")
|
||||
.description(format!(
|
||||
"Limite de suppression definie a **{}** message(s) par commande clear.",
|
||||
clamped
|
||||
))
|
||||
.color(0x57F287),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct ClearLimitCommand;
|
||||
pub static COMMAND_DESCRIPTOR: ClearLimitCommand = ClearLimitCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for ClearLimitCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "clear_limit",
|
||||
category: "mod",
|
||||
params: "limit <nombre>",
|
||||
description: "Definit la limite max de messages supprimables avec +clear.",
|
||||
examples: &["+clear limit 100", "+help clear limit"],
|
||||
default_aliases: &["climit"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
use serenity::builder::{CreateEmbed, GetMessages};
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::admin_common::parse_user_id;
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::db::{self, DbPoolKey};
|
||||
|
||||
pub async fn handle_clear_messages(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Ok(mut amount) = args.first().unwrap_or(&"0").parse::<u64>() else {
|
||||
return;
|
||||
};
|
||||
if amount == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let max_limit = if let Some(guild_id) = msg.guild_id {
|
||||
let pool = {
|
||||
let data = ctx.data.read().await;
|
||||
data.get::<DbPoolKey>().cloned()
|
||||
};
|
||||
|
||||
if let Some(pool) = pool {
|
||||
let bot_id = ctx.cache.current_user().id.get() as i64;
|
||||
db::get_or_create_moderation_settings(&pool, bot_id, guild_id.get() as i64)
|
||||
.await
|
||||
.ok()
|
||||
.map(|settings| settings.clear_limit.max(1) as u64)
|
||||
.unwrap_or(100)
|
||||
} else {
|
||||
100
|
||||
}
|
||||
} else {
|
||||
100
|
||||
};
|
||||
|
||||
amount = amount.clamp(1, max_limit);
|
||||
|
||||
let filter_user = args.get(1).and_then(|raw| parse_user_id(raw));
|
||||
|
||||
let mut deleted = 0usize;
|
||||
if let Ok(messages) = msg
|
||||
.channel_id
|
||||
.messages(&ctx.http, GetMessages::new().limit(amount as u8 + 1))
|
||||
.await
|
||||
{
|
||||
for m in messages {
|
||||
if m.id == msg.id {
|
||||
continue;
|
||||
}
|
||||
if let Some(user_id) = filter_user {
|
||||
if m.author.id != user_id {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if msg.channel_id.delete_message(&ctx.http, m.id).await.is_ok() {
|
||||
deleted += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Clear")
|
||||
.description(format!("{} message(s) supprime(s).", deleted))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct ClearMessagesCommand;
|
||||
pub static COMMAND_DESCRIPTOR: ClearMessagesCommand = ClearMessagesCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for ClearMessagesCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "clear_messages",
|
||||
category: "mod",
|
||||
params: "<nombre> [@membre/ID]",
|
||||
description: "Supprime un nombre de messages, optionnellement filtres par membre.",
|
||||
examples: &["+clear 20", "+clear 20 @User"],
|
||||
default_aliases: &["purge"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::admin_common::parse_user_id;
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::db::DbPoolKey;
|
||||
|
||||
pub async fn handle_clear_sanctions(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.len() < 2 {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(target) = parse_user_id(args[1]) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let pool = {
|
||||
let data = ctx.data.read().await;
|
||||
data.get::<DbPoolKey>().cloned()
|
||||
};
|
||||
let Some(pool) = pool else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
let removed = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM bot_sanctions
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND user_id = $3;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(target.get() as i64)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.ok()
|
||||
.map(|r| r.rows_affected())
|
||||
.unwrap_or(0);
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Sanctions")
|
||||
.description(format!(
|
||||
"{} sanction(s) supprimée(s) pour <@{}>.",
|
||||
removed,
|
||||
target.get()
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct ClearSanctionsCommand;
|
||||
pub static COMMAND_DESCRIPTOR: ClearSanctionsCommand = ClearSanctionsCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for ClearSanctionsCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "clear_sanctions",
|
||||
category: "mod",
|
||||
params: "<@membre/ID>",
|
||||
description: "Efface completement les sanctions d un membre cible.",
|
||||
examples: &["+clear sanctions @User"],
|
||||
default_aliases: &["csanctions"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{
|
||||
add_sanction, channel_mute_users, parse_targets,
|
||||
};
|
||||
|
||||
pub async fn handle_cmute(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let reason = if args.len() > 1 {
|
||||
args[1..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
let affected = channel_mute_users(ctx, msg.channel_id, &targets, true).await;
|
||||
|
||||
for uid in &targets {
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"cmute",
|
||||
&reason,
|
||||
Some(msg.channel_id),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("CMute")
|
||||
.description(format!("{} membre(s) cmute.", affected))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct CmuteCommand;
|
||||
pub static COMMAND_DESCRIPTOR: CmuteCommand = CmuteCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for CmuteCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "cmute",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> [raison]",
|
||||
description: "Mute un membre sur le salon courant.",
|
||||
examples: &["+cmute @User"],
|
||||
default_aliases: &["cm"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::admin_common::parse_user_id;
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::db::DbPoolKey;
|
||||
|
||||
pub async fn handle_del_sanction(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.len() < 3 {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(target) = parse_user_id(args[1]) else {
|
||||
return;
|
||||
};
|
||||
let Ok(index) = args[2].parse::<usize>() else {
|
||||
return;
|
||||
};
|
||||
if index == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let pool = {
|
||||
let data = ctx.data.read().await;
|
||||
data.get::<DbPoolKey>().cloned()
|
||||
};
|
||||
let Some(pool) = pool else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
let rows = sqlx::query_as::<_, (i64,)>(
|
||||
r#"
|
||||
SELECT id
|
||||
FROM bot_sanctions
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND user_id = $3
|
||||
ORDER BY created_at DESC;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(target.get() as i64)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let Some((sanction_id,)) = rows.get(index - 1).copied() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM bot_sanctions
|
||||
WHERE id = $1 AND bot_id = $2 AND guild_id = $3;
|
||||
"#,
|
||||
)
|
||||
.bind(sanction_id)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Sanctions")
|
||||
.description(format!(
|
||||
"Sanction #{} supprimée pour <@{}>.",
|
||||
sanction_id,
|
||||
target.get()
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct DelSanctionCommand;
|
||||
pub static COMMAND_DESCRIPTOR: DelSanctionCommand = DelSanctionCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for DelSanctionCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "del_sanction",
|
||||
category: "mod",
|
||||
params: "<@membre/ID> <nombre>",
|
||||
description: "Supprime une sanction specifique dans l historique d un membre.",
|
||||
examples: &["+del sanction @User 1"],
|
||||
default_aliases: &["delsanction"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{add_sanction, parse_targets};
|
||||
|
||||
pub async fn handle_kick(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let reason = if args.len() > 1 {
|
||||
args[1..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
let mut done = 0usize;
|
||||
for uid in &targets {
|
||||
if guild_id
|
||||
.kick_with_reason(&ctx.http, *uid, &reason)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
done += 1;
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"kick",
|
||||
&reason,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Kick")
|
||||
.description(format!("{} membre(s) expulse(s).", done))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct KickCommand;
|
||||
pub static COMMAND_DESCRIPTOR: KickCommand = KickCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for KickCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "kick",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> [raison]",
|
||||
description: "Kick un ou plusieurs membres.",
|
||||
examples: &["+kick @User"],
|
||||
default_aliases: &["k"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
use chrono::Utc;
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{add_sanction, handle_timeout, parse_targets};
|
||||
|
||||
pub async fn handle_mute(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let expires_at = Some(Utc::now() + chrono::Duration::seconds(28 * 24 * 3600));
|
||||
let reason = if args.len() > 1 {
|
||||
args[1..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
let affected = handle_timeout(ctx, guild_id, &targets, expires_at).await;
|
||||
|
||||
for uid in &targets {
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"mute",
|
||||
&reason,
|
||||
None,
|
||||
expires_at,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Mute")
|
||||
.description(format!("{} membre(s) mute.", affected))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct MuteCommand;
|
||||
pub static COMMAND_DESCRIPTOR: MuteCommand = MuteCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for MuteCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "mute",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> [raison]",
|
||||
description: "Applique un mute a un ou plusieurs membres.",
|
||||
examples: &["+mute @User abus"],
|
||||
default_aliases: &["tmute"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
use chrono::Utc;
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::pool;
|
||||
|
||||
pub async fn handle_mutelist(ctx: &Context, msg: &Message) {
|
||||
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 rows = sqlx::query_as::<_, (i64, String, Option<i64>, Option<chrono::DateTime<Utc>>)>(
|
||||
r#"
|
||||
SELECT user_id, kind, channel_id, expires_at
|
||||
FROM bot_sanctions
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND active = TRUE AND kind IN ('mute','tempmute','cmute','tempcmute')
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 60;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let desc = if rows.is_empty() {
|
||||
"Aucun mute en cours.".to_string()
|
||||
} else {
|
||||
rows.into_iter()
|
||||
.map(|(uid, kind, channel_id, exp)| {
|
||||
let channel = channel_id
|
||||
.map(|c| format!(" dans <#{}>", c))
|
||||
.unwrap_or_default();
|
||||
let until = exp
|
||||
.map(|d| format!(" jusqu'a <t:{}:R>", d.timestamp()))
|
||||
.unwrap_or_default();
|
||||
format!("- <@{}> `{}`{}{}", uid, kind, channel, until)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("MuteList")
|
||||
.description(desc)
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct MutelistCommand;
|
||||
pub static COMMAND_DESCRIPTOR: MutelistCommand = MutelistCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for MutelistCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "mutelist",
|
||||
category: "mod",
|
||||
params: "aucun",
|
||||
description: "Affiche tous les mutes en cours.",
|
||||
examples: &["+mutelist"],
|
||||
default_aliases: &["ml"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
use serenity::builder::{CreateEmbed, EditRole};
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::automod_service::pool;
|
||||
use crate::commands::common::send_embed;
|
||||
use crate::db;
|
||||
|
||||
fn mute_permissions() -> Permissions {
|
||||
Permissions::SEND_MESSAGES | Permissions::ADD_REACTIONS | Permissions::SPEAK
|
||||
}
|
||||
|
||||
pub async fn handle_muterole(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 Ok(settings) =
|
||||
db::get_or_create_moderation_settings(&pool, bot_id, guild_id.get() as i64).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut role_id = settings
|
||||
.mute_role_id
|
||||
.and_then(|raw| u64::try_from(raw).ok())
|
||||
.map(RoleId::new);
|
||||
|
||||
let Ok(partial_guild) = guild_id.to_partial_guild(&ctx.http).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
if role_id.is_none() {
|
||||
role_id = partial_guild
|
||||
.roles
|
||||
.values()
|
||||
.find(|role| role.name.eq_ignore_ascii_case("Muted"))
|
||||
.map(|role| role.id);
|
||||
}
|
||||
|
||||
if role_id.is_none() {
|
||||
let created = guild_id
|
||||
.create_role(
|
||||
&ctx.http,
|
||||
EditRole::new()
|
||||
.name("Muted")
|
||||
.permissions(Permissions::empty()),
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
role_id = created.map(|role| role.id);
|
||||
}
|
||||
|
||||
let Some(role_id) = role_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut failed_channels = Vec::new();
|
||||
if let Ok(channels) = guild_id.channels(&ctx.http).await {
|
||||
for channel in channels.values() {
|
||||
let result = channel
|
||||
.create_permission(
|
||||
&ctx.http,
|
||||
PermissionOverwrite {
|
||||
allow: Permissions::empty(),
|
||||
deny: mute_permissions(),
|
||||
kind: PermissionOverwriteType::Role(role_id),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
if result.is_err() {
|
||||
failed_channels.push(channel.id.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = db::set_mute_role(
|
||||
&pool,
|
||||
bot_id,
|
||||
guild_id.get() as i64,
|
||||
Some(role_id.get() as i64),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut description = format!(
|
||||
"Role muet configure: <@&{}>.\nPermissions appliquees sur les salons du serveur.",
|
||||
role_id.get()
|
||||
);
|
||||
|
||||
if !failed_channels.is_empty() {
|
||||
let list = failed_channels
|
||||
.iter()
|
||||
.take(10)
|
||||
.map(|id| format!("<#{}>", id))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
description.push_str(&format!(
|
||||
"\nErreurs permissions: {} salon(s). {}",
|
||||
failed_channels.len(),
|
||||
list
|
||||
));
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("MuteRole")
|
||||
.description(description)
|
||||
.color(if failed_channels.is_empty() {
|
||||
0x57F287
|
||||
} else {
|
||||
0xFEE75C
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct MuteRoleCommand;
|
||||
pub static COMMAND_DESCRIPTOR: MuteRoleCommand = MuteRoleCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for MuteRoleCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "muterole",
|
||||
category: "mod",
|
||||
params: "aucun",
|
||||
description: "Cree ou met a jour le role muet et tente de corriger les permissions des salons.",
|
||||
examples: &["+muterole", "+help muterole"],
|
||||
default_aliases: &["mr"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::automod_service::{
|
||||
format_duration, parse_duration_to_seconds, parse_sanction, pool,
|
||||
};
|
||||
use crate::commands::common::send_embed;
|
||||
use crate::db;
|
||||
|
||||
fn describe_rule(index: usize, rule: &db::PunishRule) -> String {
|
||||
let sanction = if let Some(duration) = rule.sanction_seconds {
|
||||
format!("{} {}", rule.sanction, format_duration(duration))
|
||||
} else {
|
||||
rule.sanction.clone()
|
||||
};
|
||||
|
||||
format!(
|
||||
"{}. {} strikes / {} -> {}",
|
||||
index,
|
||||
rule.threshold,
|
||||
format_duration(rule.window_seconds),
|
||||
sanction
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn handle_punish(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.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::<Vec<_>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Punish")
|
||||
.description(description)
|
||||
.color(0x5865F2),
|
||||
)
|
||||
.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;
|
||||
}
|
||||
|
||||
if args[0].eq_ignore_ascii_case("add") {
|
||||
if args.len() < 4 {
|
||||
return;
|
||||
}
|
||||
|
||||
let Ok(threshold) = args[1].parse::<i32>() 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::<usize>() 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;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Punish")
|
||||
.description("Usage: +punish | +punish add <nombre> <duree> <sanction> [duree] | +punish del <numero> | +punish setup")
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct PunishCommand;
|
||||
pub static COMMAND_DESCRIPTOR: PunishCommand = PunishCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for PunishCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "punish",
|
||||
category: "mod",
|
||||
params: "[add <nombre> <duree> <sanction> [duree] | del <numero> | setup]",
|
||||
description: "Affiche et gere les sanctions automatiques appliquees selon les strikes.",
|
||||
examples: &["+punish", "+punish add 8 1h mute 30m", "+punish setup"],
|
||||
default_aliases: &["pn"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
use chrono::Utc;
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::admin_common::parse_user_id;
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::db::DbPoolKey;
|
||||
|
||||
pub async fn handle_sanctions(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
let Some(target_raw) = args.first() else {
|
||||
let _ = send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Sanctions")
|
||||
.description("Usage: +sanctions <membre>")
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
let Some(target) = parse_user_id(target_raw) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let pool = {
|
||||
let data = ctx.data.read().await;
|
||||
data.get::<DbPoolKey>().cloned()
|
||||
};
|
||||
let Some(pool) = pool else {
|
||||
return;
|
||||
};
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
|
||||
let rows = sqlx::query_as::<
|
||||
_,
|
||||
(
|
||||
i64,
|
||||
String,
|
||||
String,
|
||||
chrono::DateTime<Utc>,
|
||||
Option<chrono::DateTime<Utc>>,
|
||||
bool,
|
||||
),
|
||||
>(
|
||||
r#"
|
||||
SELECT id, kind, reason, created_at, expires_at, active
|
||||
FROM bot_sanctions
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND user_id = $3
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 30;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(target.get() as i64)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let desc = if rows.is_empty() {
|
||||
"Aucune sanction.".to_string()
|
||||
} else {
|
||||
rows.into_iter()
|
||||
.map(|(id, kind, reason, created_at, expires_at, active)| {
|
||||
let until = expires_at
|
||||
.map(|d| format!(" · jusqu'à <t:{}:R>", d.timestamp()))
|
||||
.unwrap_or_default();
|
||||
format!(
|
||||
"`#{}` `{}` {} · <t:{}:R>{} · {}",
|
||||
id,
|
||||
kind,
|
||||
if active { "(active)" } else { "(inactive)" },
|
||||
created_at.timestamp(),
|
||||
until,
|
||||
reason
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title(format!("Sanctions de <@{}>", target.get()))
|
||||
.description(desc)
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct SanctionsCommand;
|
||||
pub static COMMAND_DESCRIPTOR: SanctionsCommand = SanctionsCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for SanctionsCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "sanctions",
|
||||
category: "mod",
|
||||
params: "<@membre/ID>",
|
||||
description: "Liste l historique des sanctions d un membre.",
|
||||
examples: &["+sanctions @User"],
|
||||
default_aliases: &["sanct"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::automod_service::pool;
|
||||
use crate::commands::common::{parse_role, send_embed};
|
||||
use crate::db;
|
||||
|
||||
pub async fn handle_set_muterole(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(raw_role) = args.get(1) else {
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Set MuteRole")
|
||||
.description("Usage: +set muterole <@role/ID/nom>")
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(guild) = guild_id.to_partial_guild(&ctx.http).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(role) = parse_role(&guild, raw_role) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bot_id = ctx.cache.current_user().id.get() as i64;
|
||||
if db::set_mute_role(
|
||||
&pool,
|
||||
bot_id,
|
||||
guild_id.get() as i64,
|
||||
Some(role.id.get() as i64),
|
||||
)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("MuteRole")
|
||||
.description(format!("Role muet defini sur <@&{}>.", role.id.get()))
|
||||
.color(0x57F287),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct SetMuteRoleCommand;
|
||||
pub static COMMAND_DESCRIPTOR: SetMuteRoleCommand = SetMuteRoleCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for SetMuteRoleCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "set_muterole",
|
||||
category: "mod",
|
||||
params: "muterole <@role/ID/nom>",
|
||||
description: "Definit le role utilise pour le mute lorsque le mode timeout est desactive.",
|
||||
examples: &["+set muterole @Muted", "+help set muterole"],
|
||||
default_aliases: &["smr"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
use chrono::Utc;
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{
|
||||
add_sanction, duration_from_input, parse_targets,
|
||||
};
|
||||
|
||||
pub async fn handle_tempban(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(duration_raw) = args.get(1) else {
|
||||
return;
|
||||
};
|
||||
let Some(duration) = duration_from_input(duration_raw) else {
|
||||
return;
|
||||
};
|
||||
let expires_at = Some(Utc::now() + chrono::Duration::seconds(duration.as_secs() as i64));
|
||||
|
||||
let reason = if args.len() > 2 {
|
||||
args[2..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
let mut done = 0usize;
|
||||
for uid in &targets {
|
||||
if guild_id
|
||||
.ban_with_reason(&ctx.http, *uid, 0, &reason)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
done += 1;
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"tempban",
|
||||
&reason,
|
||||
None,
|
||||
expires_at,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("TempBan")
|
||||
.description(format!("{} membre(s) banni(s).", done))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct TempbanCommand;
|
||||
pub static COMMAND_DESCRIPTOR: TempbanCommand = TempbanCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for TempbanCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "tempban",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> <duree> [raison]",
|
||||
description: "Ban temporairement un ou plusieurs membres.",
|
||||
examples: &["+tempban @User 1d"],
|
||||
default_aliases: &["tb"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
use chrono::Utc;
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{
|
||||
add_sanction, channel_mute_users, duration_from_input, parse_targets,
|
||||
};
|
||||
|
||||
pub async fn handle_tempcmute(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(duration_raw) = args.get(1) else {
|
||||
return;
|
||||
};
|
||||
let Some(duration) = duration_from_input(duration_raw) else {
|
||||
return;
|
||||
};
|
||||
let expires_at = Some(Utc::now() + chrono::Duration::seconds(duration.as_secs() as i64));
|
||||
|
||||
let reason = if args.len() > 2 {
|
||||
args[2..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
let affected = channel_mute_users(ctx, msg.channel_id, &targets, true).await;
|
||||
|
||||
for uid in &targets {
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"tempcmute",
|
||||
&reason,
|
||||
Some(msg.channel_id),
|
||||
expires_at,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("TempCMute")
|
||||
.description(format!("{} membre(s) cmute.", affected))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct TempcmuteCommand;
|
||||
pub static COMMAND_DESCRIPTOR: TempcmuteCommand = TempcmuteCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for TempcmuteCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "tempcmute",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> <duree> [raison]",
|
||||
description: "Mute temporaire sur le salon courant.",
|
||||
examples: &["+tempcmute @User 5m"],
|
||||
default_aliases: &["tcm"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
use chrono::Utc;
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{
|
||||
add_sanction, duration_from_input, handle_timeout, parse_targets,
|
||||
};
|
||||
|
||||
pub async fn handle_tempmute(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(duration_raw) = args.get(1) else {
|
||||
return;
|
||||
};
|
||||
let Some(duration) = duration_from_input(duration_raw) else {
|
||||
return;
|
||||
};
|
||||
let expires_at = Some(Utc::now() + chrono::Duration::seconds(duration.as_secs() as i64));
|
||||
|
||||
let reason = if args.len() > 2 {
|
||||
args[2..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
let affected = handle_timeout(ctx, guild_id, &targets, expires_at).await;
|
||||
|
||||
for uid in &targets {
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"tempmute",
|
||||
&reason,
|
||||
None,
|
||||
expires_at,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("TempMute")
|
||||
.description(format!("{} membre(s) mute.", affected))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct TempmuteCommand;
|
||||
pub static COMMAND_DESCRIPTOR: TempmuteCommand = TempmuteCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for TempmuteCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "tempmute",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> <duree> [raison]",
|
||||
description: "Mute un ou plusieurs membres pour une duree donnee.",
|
||||
examples: &["+tempmute @User 10m"],
|
||||
default_aliases: &["tm"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::automod_service::{parse_on_off, pool};
|
||||
use crate::commands::common::send_embed;
|
||||
use crate::db;
|
||||
|
||||
pub async fn handle_timeout_toggle(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(value) = args.first().and_then(|raw| parse_on_off(raw)) else {
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Timeout")
|
||||
.description("Usage: +timeout <on/off>")
|
||||
.color(0xED4245),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(pool) = pool(ctx).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bot_id = ctx.cache.current_user().id.get() as i64;
|
||||
let Ok(settings) =
|
||||
db::set_use_timeout_for_mute(&pool, bot_id, guild_id.get() as i64, value).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mode = if settings.use_timeout {
|
||||
"Timeout Discord"
|
||||
} else {
|
||||
"Role mute"
|
||||
};
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Timeout")
|
||||
.description(format!(
|
||||
"Mode mute mis a jour: **{}**.\nNote: les timeouts Discord sont limites a 28 jours.",
|
||||
mode
|
||||
))
|
||||
.color(0x57F287),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct TimeoutCommand;
|
||||
pub static COMMAND_DESCRIPTOR: TimeoutCommand = TimeoutCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for TimeoutCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "timeout",
|
||||
category: "mod",
|
||||
params: "<on/off>",
|
||||
description: "Active ou desactive l utilisation du timeout Discord pour les mutes.",
|
||||
examples: &["+timeout on", "+timeout off", "+help timeout"],
|
||||
default_aliases: &["to"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::parse_targets;
|
||||
|
||||
pub async fn handle_unban(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut done = 0usize;
|
||||
for uid in &targets {
|
||||
if guild_id.unban(&ctx.http, *uid).await.is_ok() {
|
||||
done += 1;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("UnBan")
|
||||
.description(format!("{} membre(s) unban.", done))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct UnbanCommand;
|
||||
pub static COMMAND_DESCRIPTOR: UnbanCommand = UnbanCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for UnbanCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "unban",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]>",
|
||||
description: "Unban un ou plusieurs membres.",
|
||||
examples: &["+unban @User"],
|
||||
default_aliases: &["ub"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
|
||||
pub async fn handle_unbanall(ctx: &Context, msg: &Message, _args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bans = guild_id
|
||||
.bans(&ctx.http, None, None)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut unbanned = 0usize;
|
||||
for ban in bans {
|
||||
if guild_id.unban(&ctx.http, ban.user.id).await.is_ok() {
|
||||
unbanned += 1;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("UnbanAll")
|
||||
.description(format!("{} bannissements retirés.", unbanned))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub struct UnbanAllCommand;
|
||||
pub static COMMAND_DESCRIPTOR: UnbanAllCommand = UnbanAllCommand;
|
||||
|
||||
impl crate::commands::command_contract::CommandSpec for UnbanAllCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "unbanall",
|
||||
category: "mod",
|
||||
params: "aucun",
|
||||
description: "Supprime tous les bans du serveur cible.",
|
||||
examples: &["+unbanall"],
|
||||
default_aliases: &["uball", "clearbans"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{channel_mute_users, parse_targets, pool};
|
||||
|
||||
pub async fn handle_uncmute(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let affected = channel_mute_users(ctx, msg.channel_id, &targets, false).await;
|
||||
|
||||
if let Some(pool) = pool(ctx).await {
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
for uid in &targets {
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
UPDATE bot_sanctions
|
||||
SET active = FALSE
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND user_id = $3 AND active = TRUE AND kind IN ('cmute','tempcmute') AND channel_id = $4;
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(uid.get() as i64)
|
||||
.bind(msg.channel_id.get() as i64)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("UnCMute")
|
||||
.description(format!("{} membre(s) uncmute.", affected))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct UncmuteCommand;
|
||||
pub static COMMAND_DESCRIPTOR: UncmuteCommand = UncmuteCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for UncmuteCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "uncmute",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]>",
|
||||
description: "Met fin au mute salon.",
|
||||
examples: &["+uncmute @User"],
|
||||
default_aliases: &["ucm"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{handle_timeout, parse_targets, pool};
|
||||
|
||||
pub async fn handle_unmute(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let affected = handle_timeout(ctx, guild_id, &targets, None).await;
|
||||
|
||||
if let Some(pool) = pool(ctx).await {
|
||||
let bot_id = ctx.cache.current_user().id;
|
||||
for uid in &targets {
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
UPDATE bot_sanctions
|
||||
SET active = FALSE
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND user_id = $3 AND active = TRUE AND kind IN ('mute','tempmute');
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.bind(uid.get() as i64)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("UnMute")
|
||||
.description(format!("{} membre(s) unmute.", affected))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct UnmuteCommand;
|
||||
pub static COMMAND_DESCRIPTOR: UnmuteCommand = UnmuteCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for UnmuteCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "unmute",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]>",
|
||||
description: "Met fin au mute d un ou plusieurs membres.",
|
||||
examples: &["+unmute @User"],
|
||||
default_aliases: &["um"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{channel_mute_users, handle_timeout, pool};
|
||||
|
||||
pub async fn handle_unmuteall(ctx: &Context, msg: &Message) {
|
||||
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 rows = sqlx::query_as::<_, (i64, String, Option<i64>)>(
|
||||
r#"
|
||||
SELECT user_id, kind, channel_id
|
||||
FROM bot_sanctions
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND active = TRUE AND kind IN ('mute','tempmute','cmute','tempcmute');
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut changed = 0usize;
|
||||
for (uid, kind, channel_id) in rows {
|
||||
let user_id = UserId::new(uid as u64);
|
||||
if kind == "mute" || kind == "tempmute" {
|
||||
changed += handle_timeout(ctx, guild_id, &[user_id], None).await;
|
||||
} else if let Some(cid) = channel_id {
|
||||
changed += channel_mute_users(ctx, ChannelId::new(cid as u64), &[user_id], false).await;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = sqlx::query(
|
||||
r#"
|
||||
UPDATE bot_sanctions
|
||||
SET active = FALSE
|
||||
WHERE bot_id = $1 AND guild_id = $2 AND active = TRUE AND kind IN ('mute','tempmute','cmute','tempcmute');
|
||||
"#,
|
||||
)
|
||||
.bind(bot_id.get() as i64)
|
||||
.bind(guild_id.get() as i64)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("UnMuteAll")
|
||||
.description(format!(
|
||||
"{} operation(s) de unmute/cmute annule(es).",
|
||||
changed
|
||||
))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct UnmuteallCommand;
|
||||
pub static COMMAND_DESCRIPTOR: UnmuteallCommand = UnmuteallCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for UnmuteallCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "unmuteall",
|
||||
category: "mod",
|
||||
params: "aucun",
|
||||
description: "Supprime tous les mutes en cours.",
|
||||
examples: &["+unmuteall"],
|
||||
default_aliases: &["uma"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
use serenity::builder::CreateEmbed;
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::commands::common::{send_embed, theme_color};
|
||||
use crate::commands::moderation_sanction_helpers::{add_sanction, parse_targets};
|
||||
|
||||
pub async fn handle_warn(ctx: &Context, msg: &Message, args: &[&str]) {
|
||||
let Some(guild_id) = msg.guild_id else {
|
||||
return;
|
||||
};
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let targets = parse_targets(args[0]).await;
|
||||
if targets.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let reason = if args.len() > 1 {
|
||||
args[1..].join(" ")
|
||||
} else {
|
||||
"Aucune raison".to_string()
|
||||
};
|
||||
|
||||
for uid in &targets {
|
||||
add_sanction(
|
||||
ctx,
|
||||
guild_id,
|
||||
*uid,
|
||||
msg.author.id,
|
||||
"warn",
|
||||
&reason,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
CreateEmbed::new()
|
||||
.title("Warn")
|
||||
.description(format!("{} membre(s) warn.", targets.len()))
|
||||
.color(theme_color(ctx).await),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub struct WarnCommand;
|
||||
pub static COMMAND_DESCRIPTOR: WarnCommand = WarnCommand;
|
||||
impl crate::commands::command_contract::CommandSpec for WarnCommand {
|
||||
fn metadata(&self) -> crate::commands::command_contract::CommandMetadata {
|
||||
crate::commands::command_contract::CommandMetadata {
|
||||
name: "warn",
|
||||
category: "mod",
|
||||
params: "<@membre/ID[,..]> [raison]",
|
||||
description: "Ajoute un warn a un ou plusieurs membres.",
|
||||
examples: &["+warn @User spam"],
|
||||
default_aliases: &["avert"],
|
||||
allow_in_dm: false,
|
||||
default_permission: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user