feat(moderation): add commands for anti-raid reset, mute role setting, spam overrides, strikes management, and timeout toggling

- Implemented `resetantiraide` command to reset anti-raid protections to default settings.
- Added `set_muterole` command to define the mute role when timeout mode is disabled.
- Created `spam` command to manage spam moderation channel overrides (allow, deny, reset).
- Developed `strikes` command to display and modify strike rules for various triggers.
- Introduced `timeout` command to toggle the use of Discord timeout for mutes.

feat(outils): add piconly command to manage photo-only channels

- Implemented `piconly` command to define or remove channels where only photos can be sent.
- Added functionality to enforce photo-only rules in designated channels.

feat(roles): add ancien and noderank commands for role management

- Created `ancien` command to set up a role for members after a specified delay.
- Implemented `noderank` command to manage protected roles that are not removed by derank actions.
This commit is contained in:
Puechberty Arthur
2026-04-10 15:04:10 +02:00
parent f945f3f378
commit e0f40e9190
35 changed files with 6353 additions and 227 deletions
+45 -9
View File
@@ -6,7 +6,7 @@ use serenity::model::prelude::*;
use serenity::prelude::*;
use crate::commands::admin_common::parse_user_id;
use crate::db::DbPoolKey;
use crate::db::{self, DbPoolKey};
pub fn duration_from_input(input: &str) -> Option<Duration> {
let raw = input.trim().to_lowercase();
@@ -95,20 +95,56 @@ pub async fn handle_timeout(
users: &[UserId],
expires: Option<chrono::DateTime<Utc>>,
) -> usize {
let settings = if let Some(pool) = pool(ctx).await {
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()
} else {
None
};
let mute_role_id = settings
.as_ref()
.and_then(|s| s.mute_role_id)
.and_then(|raw| u64::try_from(raw).ok())
.map(RoleId::new);
let use_timeout = settings
.as_ref()
.map(|s| s.use_timeout || s.mute_role_id.is_none())
.unwrap_or(true);
let mut done = 0usize;
for user_id in users {
if let Ok(mut member) = guild_id.member(&ctx.http, *user_id).await {
let mut builder = EditMember::new();
if let Some(ts) = expires {
if let Ok(discord_ts) = Timestamp::from_unix_timestamp(ts.timestamp()) {
builder = builder.disable_communication_until_datetime(discord_ts);
if use_timeout {
let mut builder = EditMember::new();
if let Some(ts) = expires {
if let Ok(discord_ts) = Timestamp::from_unix_timestamp(ts.timestamp()) {
builder = builder.disable_communication_until_datetime(discord_ts);
}
} else {
builder = builder.enable_communication();
}
if member.edit(&ctx.http, builder).await.is_ok() {
done += 1;
}
} else {
builder = builder.enable_communication();
}
let Some(role_id) = mute_role_id else {
continue;
};
if member.edit(&ctx.http, builder).await.is_ok() {
done += 1;
let result = if expires.is_some() {
member.add_role(&ctx.http, role_id).await
} else {
member.remove_role(&ctx.http, role_id).await
};
if result.is_ok() {
done += 1;
}
}
}
}