Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
Binary file not shown.
BIN
commandes/autres/__pycache__/config.cpython-313.pyc
Normal file
BIN
commandes/autres/__pycache__/config.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
commandes/autres/__pycache__/logger.cpython-313.pyc
Normal file
BIN
commandes/autres/__pycache__/logger.cpython-313.pyc
Normal file
Binary file not shown.
|
|
@ -41,13 +41,16 @@ class ActionLogger:
|
|||
|
||||
def log_message(self, level: str, message: str):
|
||||
"""Log a general message."""
|
||||
if level.casefold() == 'info':
|
||||
if not level or not message:
|
||||
return
|
||||
level_lower = level.casefold()
|
||||
if level_lower == 'info':
|
||||
self.logger.info(message)
|
||||
elif level.casefold() == 'warning':
|
||||
elif level_lower == 'warning':
|
||||
self.logger.warning(message)
|
||||
elif level.casefold() == 'error':
|
||||
elif level_lower == 'error':
|
||||
self.logger.error(message)
|
||||
elif level.casefold() == 'debug':
|
||||
elif level_lower == 'debug':
|
||||
self.logger.debug(message)
|
||||
|
||||
# Global logger instance
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ from .config import config
|
|||
|
||||
async def execute(bot, params, message):
|
||||
channel_name = params.get('channel_name')
|
||||
if not channel_name:
|
||||
await message.channel.send("Veuillez spécifier un nom de salon.")
|
||||
return
|
||||
guild = message.guild
|
||||
channel = discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
if not channel:
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ from .config import config
|
|||
|
||||
async def execute(bot, params, message):
|
||||
channel_name = params.get('channel_name')
|
||||
if not channel_name:
|
||||
await message.channel.send("Veuillez spécifier un nom de salon.")
|
||||
return
|
||||
guild = message.guild
|
||||
channel = discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
if not channel:
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -9,6 +9,9 @@ async def execute(bot, params, message):
|
|||
created_count = 0
|
||||
for category_params in categories:
|
||||
category_name = category_params.get('category_name')
|
||||
if not category_name:
|
||||
await message.channel.send("Nom de catégorie requis pour la création.")
|
||||
continue
|
||||
try:
|
||||
category = await guild.create_category(category_name)
|
||||
created_count += 1
|
||||
|
|
|
|||
|
|
@ -1,5 +1,22 @@
|
|||
import discord
|
||||
|
||||
async def _find_category(guild, category_params):
|
||||
"""Find a category by ID first, then by name (case-insensitive)."""
|
||||
category_id = category_params.get('category_id')
|
||||
if category_id:
|
||||
try:
|
||||
cat = guild.get_channel(int(category_id))
|
||||
if cat and isinstance(cat, discord.CategoryChannel):
|
||||
return cat
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
category_name = category_params.get('category_name')
|
||||
if not category_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda cat: cat.name.casefold() == category_name.casefold(), guild.categories)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
categories = params.get('categories', [])
|
||||
if not categories:
|
||||
|
|
@ -10,14 +27,17 @@ async def execute(bot, params, message):
|
|||
for category_params in categories:
|
||||
category_name = category_params.get('category_name')
|
||||
position = category_params.get('position')
|
||||
category = discord.utils.find(lambda cat: cat.name.casefold() == category_name.casefold(), guild.categories)
|
||||
|
||||
category = await _find_category(guild, category_params)
|
||||
if not category:
|
||||
await message.channel.send(f"Catégorie '{category_name}' introuvable.")
|
||||
label = category_name or category_params.get('category_id', 'inconnue')
|
||||
await message.channel.send(f"Catégorie '{label}' introuvable.")
|
||||
continue
|
||||
try:
|
||||
await category.edit(position=position)
|
||||
moved_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour déplacer la catégorie '{category_name}'.")
|
||||
label = category_name or category_params.get('category_id', 'inconnue')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour déplacer la catégorie '{label}'.")
|
||||
if moved_count > 0:
|
||||
await message.channel.send(f"{moved_count} catégorie(s) déplacée(s).")
|
||||
await message.channel.send(f"{moved_count} catégorie(s) déplacée(s).")
|
||||
|
|
@ -1,5 +1,22 @@
|
|||
import discord
|
||||
|
||||
async def _find_category(guild, category_params):
|
||||
"""Find a category by ID first, then by name (case-insensitive)."""
|
||||
category_id = category_params.get('category_id')
|
||||
if category_id:
|
||||
try:
|
||||
cat = guild.get_channel(int(category_id))
|
||||
if cat and isinstance(cat, discord.CategoryChannel):
|
||||
return cat
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
category_name = category_params.get('category_name')
|
||||
if not category_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda cat: cat.name.casefold() == category_name.casefold(), guild.categories)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
categories = params.get('categories', [])
|
||||
if not categories:
|
||||
|
|
@ -10,14 +27,17 @@ async def execute(bot, params, message):
|
|||
for category_params in categories:
|
||||
category_name = category_params.get('category_name')
|
||||
new_name = category_params.get('new_name')
|
||||
category = discord.utils.find(lambda cat: cat.name.casefold() == category_name.casefold(), guild.categories)
|
||||
|
||||
category = await _find_category(guild, category_params)
|
||||
if not category:
|
||||
await message.channel.send(f"Catégorie '{category_name}' introuvable.")
|
||||
label = category_name or category_params.get('category_id', 'inconnue')
|
||||
await message.channel.send(f"Catégorie '{label}' introuvable.")
|
||||
continue
|
||||
try:
|
||||
await category.edit(name=new_name)
|
||||
renamed_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour renommer la catégorie '{category_name}'.")
|
||||
label = category_name or category_params.get('category_id', 'inconnue')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour renommer la catégorie '{label}'.")
|
||||
if renamed_count > 0:
|
||||
await message.channel.send(f"{renamed_count} catégorie(s) renommée(s).")
|
||||
await message.channel.send(f"{renamed_count} catégorie(s) renommée(s).")
|
||||
|
|
@ -10,9 +10,22 @@ async def execute(bot, params, message):
|
|||
for assignment in role_assignments:
|
||||
target_mention = assignment.get('target_user_mention')
|
||||
role_name = assignment.get('role_name')
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), message.guild.roles)
|
||||
|
||||
# Try by role_id first if available
|
||||
role = None
|
||||
role_id = assignment.get('role_id')
|
||||
if role_id:
|
||||
try:
|
||||
role = message.guild.get_role(int(role_id))
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if not role and role_name:
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), message.guild.roles)
|
||||
|
||||
if not role:
|
||||
await message.channel.send(f"Rôle '{role_name}' introuvable.")
|
||||
label = role_name or assignment.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Rôle '{label}' introuvable.")
|
||||
continue
|
||||
|
||||
# Check for bulk assignment
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ async def execute(bot, params, message):
|
|||
created_count = 0
|
||||
for role_params in roles:
|
||||
role_name = role_params.get('role_name')
|
||||
if not role_name:
|
||||
await message.channel.send("Nom de rôle requis pour la création.")
|
||||
continue
|
||||
color = role_params.get('color', '#ffffff')
|
||||
permissions_str = role_params.get('permissions', '')
|
||||
# Parse color
|
||||
|
|
|
|||
|
|
@ -1,5 +1,22 @@
|
|||
import discord
|
||||
|
||||
async def _find_role(guild, role_params):
|
||||
"""Find a role by ID first, then by name (case-insensitive)."""
|
||||
role_id = role_params.get('role_id')
|
||||
if role_id:
|
||||
try:
|
||||
r = guild.get_role(int(role_id))
|
||||
if r:
|
||||
return r
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
role_name = role_params.get('role_name')
|
||||
if not role_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
roles = params.get('roles', [])
|
||||
if not roles:
|
||||
|
|
@ -10,14 +27,17 @@ async def execute(bot, params, message):
|
|||
for role_params in roles:
|
||||
role_name = role_params.get('role_name')
|
||||
position = role_params.get('position')
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
role = await _find_role(guild, role_params)
|
||||
if not role:
|
||||
await message.channel.send(f"Rôle '{role_name}' introuvable.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Rôle '{label}' introuvable.")
|
||||
continue
|
||||
try:
|
||||
await role.edit(position=position)
|
||||
moved_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour déplacer le rôle '{role_name}'.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour déplacer le rôle '{label}'.")
|
||||
if moved_count > 0:
|
||||
await message.channel.send(f"{moved_count} rôle(s) déplacé(s).")
|
||||
await message.channel.send(f"{moved_count} rôle(s) déplacé(s).")
|
||||
|
|
@ -1,5 +1,22 @@
|
|||
import discord
|
||||
|
||||
async def _find_role(guild, role_params):
|
||||
"""Find a role by ID first, then by name (case-insensitive)."""
|
||||
role_id = role_params.get('role_id')
|
||||
if role_id:
|
||||
try:
|
||||
r = guild.get_role(int(role_id))
|
||||
if r:
|
||||
return r
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
role_name = role_params.get('role_name')
|
||||
if not role_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
roles = params.get('roles', [])
|
||||
if not roles:
|
||||
|
|
@ -10,14 +27,17 @@ async def execute(bot, params, message):
|
|||
for role_params in roles:
|
||||
role_name = role_params.get('role_name')
|
||||
new_name = role_params.get('new_name')
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
role = await _find_role(guild, role_params)
|
||||
if not role:
|
||||
await message.channel.send(f"Rôle '{role_name}' introuvable.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Rôle '{label}' introuvable.")
|
||||
continue
|
||||
try:
|
||||
await role.edit(name=new_name)
|
||||
modified_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour modifier le rôle '{role_name}'.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour modifier le rôle '{label}'.")
|
||||
if modified_count > 0:
|
||||
await message.channel.send(f"{modified_count} rôle(s) modifié(s).")
|
||||
await message.channel.send(f"{modified_count} rôle(s) modifié(s).")
|
||||
|
|
@ -10,13 +10,26 @@ async def execute(bot, params, message):
|
|||
for removal in role_removals:
|
||||
target_mention = removal.get('target_user_mention')
|
||||
role_name = removal.get('role_name')
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), message.guild.roles)
|
||||
|
||||
# Try by role_id first if available
|
||||
role = None
|
||||
role_id = removal.get('role_id')
|
||||
if role_id:
|
||||
try:
|
||||
role = message.guild.get_role(int(role_id))
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if not role and role_name:
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), message.guild.roles)
|
||||
|
||||
if not role:
|
||||
await message.channel.send(f"Rôle '{role_name}' introuvable.")
|
||||
label = role_name or removal.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Rôle '{label}' introuvable.")
|
||||
continue
|
||||
|
||||
# Check for bulk removal
|
||||
if target_mention.lower() in ['@everyone', 'everyone', 'all', 'tous']:
|
||||
if target_mention and target_mention.lower() in ['@everyone', 'everyone', 'all', 'tous']:
|
||||
total_members = 0
|
||||
removed_count = 0
|
||||
await message.channel.send(f"Retrait du rôle '{role.name}' de tous les membres... (Cela peut prendre du temps)")
|
||||
|
|
@ -39,6 +52,10 @@ async def execute(bot, params, message):
|
|||
await message.channel.send(f"Rôle '{role.name}' retiré à {removed_count} membres (bots exclus).")
|
||||
continue
|
||||
|
||||
if not target_mention:
|
||||
await message.channel.send("Mention utilisateur requise.")
|
||||
continue
|
||||
|
||||
# Single user removal
|
||||
if target_mention.startswith('<@') and target_mention.endswith('>'):
|
||||
user_id = int(target_mention[2:-1])
|
||||
|
|
@ -68,4 +85,4 @@ async def execute(bot, params, message):
|
|||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour retirer le rôle {role.name} de {member.mention}.")
|
||||
if removed_count > 0 and not total_members:
|
||||
await message.channel.send(f"{removed_count} rôle(s) retiré(s).")
|
||||
await message.channel.send(f"{removed_count} rôle(s) retiré(s).")
|
||||
|
|
@ -1,5 +1,22 @@
|
|||
import discord
|
||||
|
||||
async def _find_role(guild, role_params):
|
||||
"""Find a role by ID first, then by name (case-insensitive)."""
|
||||
role_id = role_params.get('role_id')
|
||||
if role_id:
|
||||
try:
|
||||
r = guild.get_role(int(role_id))
|
||||
if r:
|
||||
return r
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
role_name = role_params.get('role_name')
|
||||
if not role_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
roles = params.get('roles', [])
|
||||
if not roles:
|
||||
|
|
@ -10,14 +27,17 @@ async def execute(bot, params, message):
|
|||
for role_params in roles:
|
||||
role_name = role_params.get('role_name')
|
||||
new_name = role_params.get('new_name')
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
role = await _find_role(guild, role_params)
|
||||
if not role:
|
||||
await message.channel.send(f"Rôle '{role_name}' introuvable.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Rôle '{label}' introuvable.")
|
||||
continue
|
||||
try:
|
||||
await role.edit(name=new_name)
|
||||
renamed_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour renommer le rôle '{role_name}'.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour renommer le rôle '{label}'.")
|
||||
if renamed_count > 0:
|
||||
await message.channel.send(f"{renamed_count} rôle(s) renommé(s).")
|
||||
await message.channel.send(f"{renamed_count} rôle(s) renommé(s).")
|
||||
|
|
@ -1,5 +1,22 @@
|
|||
import discord
|
||||
|
||||
async def _find_role(guild, role_params):
|
||||
"""Find a role by ID first, then by name (case-insensitive)."""
|
||||
role_id = role_params.get('role_id')
|
||||
if role_id:
|
||||
try:
|
||||
r = guild.get_role(int(role_id))
|
||||
if r:
|
||||
return r
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
role_name = role_params.get('role_name')
|
||||
if not role_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
roles = params.get('roles', [])
|
||||
if not roles:
|
||||
|
|
@ -9,14 +26,17 @@ async def execute(bot, params, message):
|
|||
deleted_count = 0
|
||||
for role_params in roles:
|
||||
role_name = role_params.get('role_name')
|
||||
role = discord.utils.find(lambda r: r.name.casefold() == role_name.casefold(), guild.roles)
|
||||
|
||||
role = await _find_role(guild, role_params)
|
||||
if not role:
|
||||
await message.channel.send(f"Rôle '{role_name}' introuvable.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Rôle '{label}' introuvable.")
|
||||
continue
|
||||
try:
|
||||
await role.delete(reason="Supprimé par le Superviseur")
|
||||
deleted_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour supprimer le rôle '{role_name}'.")
|
||||
label = role_name or role_params.get('role_id', 'inconnu')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour supprimer le rôle '{label}'.")
|
||||
if deleted_count > 0:
|
||||
await message.channel.send(f"{deleted_count} rôle(s) supprimé(s).")
|
||||
await message.channel.send(f"{deleted_count} rôle(s) supprimé(s).")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -9,8 +9,14 @@ async def execute(bot, params, message):
|
|||
created_count = 0
|
||||
for channel_params in channels:
|
||||
channel_name = channel_params.get('channel_name')
|
||||
if not channel_name:
|
||||
await message.channel.send("Nom de salon requis pour la création.")
|
||||
continue
|
||||
|
||||
category_name = channel_params.get('category_name')
|
||||
channel_type = channel_params.get('channel_type', 'textuel')
|
||||
channel_type = (channel_params.get('channel_type') or 'textuel').casefold()
|
||||
|
||||
category = None
|
||||
if category_name:
|
||||
# Recherche flexible : trouver une catégorie dont le nom contient le terme recherché
|
||||
category = discord.utils.find(
|
||||
|
|
@ -25,12 +31,11 @@ async def execute(bot, params, message):
|
|||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour créer la catégorie '{category_name}'.")
|
||||
continue
|
||||
else:
|
||||
category = None
|
||||
|
||||
try:
|
||||
if channel_type.casefold() == 'textuel':
|
||||
if channel_type == 'textuel':
|
||||
channel = await guild.create_text_channel(channel_name, category=category)
|
||||
elif channel_type.casefold() == 'vocal':
|
||||
elif channel_type == 'vocal':
|
||||
channel = await guild.create_voice_channel(channel_name, category=category)
|
||||
else:
|
||||
await message.channel.send(f"Type de salon invalide pour '{channel_name}'. Utilisez 'textuel' ou 'vocal'.")
|
||||
|
|
@ -39,4 +44,4 @@ async def execute(bot, params, message):
|
|||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour créer le salon '{channel_name}'.")
|
||||
if created_count > 0:
|
||||
await message.channel.send(f"{created_count} salon(s) créé(s).")
|
||||
await message.channel.send(f"{created_count} salon(s) créé(s).")
|
||||
|
|
@ -1,5 +1,40 @@
|
|||
import discord
|
||||
|
||||
async def _find_channel(guild, channel_params):
|
||||
"""Find a channel by ID first, then by name (case-insensitive)."""
|
||||
channel_id = channel_params.get('channel_id')
|
||||
if channel_id:
|
||||
try:
|
||||
ch = guild.get_channel(int(channel_id))
|
||||
if ch:
|
||||
return ch
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
channel_name = channel_params.get('channel_name')
|
||||
if not channel_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
|
||||
async def _find_category(guild, category_params):
|
||||
"""Find a category by ID first, then by name (case-insensitive)."""
|
||||
# Support both 'category_id' and 'new_category_id'
|
||||
category_id = category_params.get('new_category_id') or category_params.get('category_id')
|
||||
if category_id:
|
||||
try:
|
||||
cat = guild.get_channel(int(category_id))
|
||||
if cat and isinstance(cat, discord.CategoryChannel):
|
||||
return cat
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
category_name = category_params.get('new_category_name') or category_params.get('category_name')
|
||||
if not category_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda cat: cat.name.casefold() == category_name.casefold(), guild.categories)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
channels = params.get('channels', [])
|
||||
if not channels:
|
||||
|
|
@ -10,18 +45,26 @@ async def execute(bot, params, message):
|
|||
for channel_params in channels:
|
||||
channel_name = channel_params.get('channel_name')
|
||||
new_category_name = channel_params.get('new_category_name')
|
||||
channel = discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
|
||||
channel = await _find_channel(guild, channel_params)
|
||||
if not channel:
|
||||
await message.channel.send(f"Salon '{channel_name}' introuvable.")
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Salon '{label}' introuvable.")
|
||||
continue
|
||||
category = discord.utils.find(lambda cat: cat.name.casefold() == new_category_name.casefold(), guild.categories)
|
||||
|
||||
category = await _find_category(guild, channel_params)
|
||||
if not category:
|
||||
await message.channel.send(f"Catégorie '{new_category_name}' introuvable.")
|
||||
continue
|
||||
has_category_param = any(k in channel_params for k in ['new_category_id', 'new_category_name', 'category_id', 'category_name'])
|
||||
if has_category_param:
|
||||
label = new_category_name or channel_params.get('new_category_id') or channel_params.get('category_id', 'inconnue')
|
||||
await message.channel.send(f"Catégorie '{label}' introuvable.")
|
||||
continue
|
||||
|
||||
try:
|
||||
await channel.edit(category=category)
|
||||
moved_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour déplacer le salon '{channel_name}'.")
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour déplacer le salon '{label}'.")
|
||||
if moved_count > 0:
|
||||
await message.channel.send(f"{moved_count} salon(s) déplacé(s).")
|
||||
await message.channel.send(f"{moved_count} salon(s) déplacé(s).")
|
||||
|
|
@ -1,5 +1,39 @@
|
|||
import discord
|
||||
|
||||
async def _find_channel(guild, channel_params):
|
||||
"""Find a channel by ID first, then by name (case-insensitive)."""
|
||||
channel_id = channel_params.get('channel_id')
|
||||
if channel_id:
|
||||
try:
|
||||
ch = guild.get_channel(int(channel_id))
|
||||
if ch:
|
||||
return ch
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
channel_name = channel_params.get('channel_name')
|
||||
if not channel_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
|
||||
async def _find_category(guild, category_params):
|
||||
"""Find a category by ID first, then by name (case-insensitive)."""
|
||||
category_id = category_params.get('new_category_id') or category_params.get('category_id')
|
||||
if category_id:
|
||||
try:
|
||||
cat = guild.get_channel(int(category_id))
|
||||
if cat and isinstance(cat, discord.CategoryChannel):
|
||||
return cat
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
category_name = category_params.get('new_category_name') or category_params.get('category_name')
|
||||
if not category_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda cat: cat.name.casefold() == category_name.casefold(), guild.categories)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
channels = params.get('channels', [])
|
||||
if not channels:
|
||||
|
|
@ -9,15 +43,43 @@ async def execute(bot, params, message):
|
|||
modified_count = 0
|
||||
for channel_params in channels:
|
||||
channel_name = channel_params.get('channel_name')
|
||||
new_name = channel_params.get('new_name')
|
||||
channel = discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
# Support both 'new_name' and 'new_channel_name' variants
|
||||
new_name = channel_params.get('new_name') or channel_params.get('new_channel_name')
|
||||
new_category_id = channel_params.get('new_category_id')
|
||||
new_category_name = channel_params.get('new_category_name')
|
||||
|
||||
channel = await _find_channel(guild, channel_params)
|
||||
if not channel:
|
||||
await message.channel.send(f"Salon '{channel_name}' introuvable.")
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Salon '{label}' introuvable.")
|
||||
continue
|
||||
|
||||
# Build edit kwargs based on what params are provided
|
||||
edit_kwargs = {}
|
||||
if new_name:
|
||||
edit_kwargs['name'] = new_name
|
||||
|
||||
if new_category_id or new_category_name:
|
||||
category = await _find_category(guild, channel_params)
|
||||
if category:
|
||||
edit_kwargs['category'] = category
|
||||
else:
|
||||
cat_label = new_category_name or new_category_id or 'inconnue'
|
||||
await message.channel.send(f"Catégorie '{cat_label}' introuvable.")
|
||||
continue
|
||||
|
||||
if not edit_kwargs:
|
||||
await message.channel.send("Aucune modification à appliquer (ni nom, ni catégorie spécifiés).")
|
||||
continue
|
||||
|
||||
try:
|
||||
await channel.edit(name=new_name)
|
||||
await channel.edit(**edit_kwargs)
|
||||
modified_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour modifier le salon '{channel_name}'.")
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour modifier le salon '{label}'.")
|
||||
except Exception as e:
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Erreur lors de la modification du salon '{label}': {e}")
|
||||
if modified_count > 0:
|
||||
await message.channel.send(f"{modified_count} salon(s) modifié(s).")
|
||||
await message.channel.send(f"{modified_count} salon(s) modifié(s).")
|
||||
|
|
@ -1,5 +1,22 @@
|
|||
import discord
|
||||
|
||||
async def _find_channel(guild, channel_params):
|
||||
"""Find a channel by ID first, then by name (case-insensitive)."""
|
||||
channel_id = channel_params.get('channel_id')
|
||||
if channel_id:
|
||||
try:
|
||||
ch = guild.get_channel(int(channel_id))
|
||||
if ch:
|
||||
return ch
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
channel_name = channel_params.get('channel_name')
|
||||
if not channel_name:
|
||||
return None
|
||||
|
||||
return discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
|
||||
async def execute(bot, params, message):
|
||||
channels = params.get('channels', [])
|
||||
if not channels:
|
||||
|
|
@ -9,15 +26,27 @@ async def execute(bot, params, message):
|
|||
renamed_count = 0
|
||||
for channel_params in channels:
|
||||
channel_name = channel_params.get('channel_name')
|
||||
new_name = channel_params.get('new_name')
|
||||
channel = discord.utils.find(lambda c: c.name.casefold() == channel_name.casefold(), guild.channels)
|
||||
# Support both 'new_name' and 'new_channel_name' variants
|
||||
new_name = channel_params.get('new_name') or channel_params.get('new_channel_name')
|
||||
|
||||
channel = await _find_channel(guild, channel_params)
|
||||
if not channel:
|
||||
await message.channel.send(f"Salon '{channel_name}' introuvable.")
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Salon '{label}' introuvable.")
|
||||
continue
|
||||
|
||||
if not new_name:
|
||||
await message.channel.send("Aucun nouveau nom spécifié pour le renommage.")
|
||||
continue
|
||||
|
||||
try:
|
||||
await channel.edit(name=new_name)
|
||||
renamed_count += 1
|
||||
except discord.Forbidden:
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour renommer le salon '{channel_name}'.")
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Je n'ai pas les permissions pour renommer le salon '{label}'.")
|
||||
except Exception as e:
|
||||
label = channel_name or channel_params.get('channel_id', 'inconnu')
|
||||
await message.channel.send(f"Erreur lors du renommage du salon '{label}': {e}")
|
||||
if renamed_count > 0:
|
||||
await message.channel.send(f"{renamed_count} salon(s) renommé(s).")
|
||||
await message.channel.send(f"{renamed_count} salon(s) renommé(s).")
|
||||
Binary file not shown.
BIN
commandes/security/__pycache__/auto_moderation.cpython-313.pyc
Normal file
BIN
commandes/security/__pycache__/auto_moderation.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,198 +0,0 @@
|
|||
"""
|
||||
Module de modération automatique pour Superviseur Bot
|
||||
Gère la détection et sanction des messages inappropriés automatiquement sur tous les messages
|
||||
"""
|
||||
|
||||
import discord
|
||||
import aiohttp
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
WARNINGS_FILE = 'data/warnings.json'
|
||||
|
||||
def load_warnings():
|
||||
"""Charge les avertissements depuis le fichier JSON"""
|
||||
if os.path.exists(WARNINGS_FILE):
|
||||
with open(WARNINGS_FILE, 'r', encoding='utf-8') as f:
|
||||
content = f.read().strip()
|
||||
if content:
|
||||
return json.loads(content)
|
||||
return {}
|
||||
|
||||
def save_warnings(warnings):
|
||||
"""Sauvegarde les avertissements dans le fichier JSON"""
|
||||
with open(WARNINGS_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(warnings, f, indent=4, ensure_ascii=False)
|
||||
|
||||
|
||||
async def check_message_content_global(bot, content):
|
||||
"""
|
||||
Vérifie le contenu d'un message pour tout contenu inapproprié
|
||||
Utilise une liste locale de mots inappropriés pour performance optimale
|
||||
"""
|
||||
# Liste optimisée de mots inappropriés (mots-clés critiques seulement pour performance)
|
||||
bad_words = {
|
||||
# Mots critiques (haute sévérité)
|
||||
'nigger', 'nigga', 'pédé', 'bougnoul', 'viol', 'pédophile', 'inceste', 'naziste', 'hitler',
|
||||
'suicide', 'se tuer', 'se suicider', 'tuer', 'assassiner', 'meurtre',
|
||||
# Gros mots courants
|
||||
'fuck', 'shit', 'asshole', 'bitch', 'dick', 'pussy', 'cunt', 'motherfucker',
|
||||
'merde', 'putain', 'salope', 'connard', 'enculé', 'bordel', 'emmerde',
|
||||
'ta gueule', 'va te faire foutre', 'va te faire enculer', 'va chier', 'crève',
|
||||
'branleur', 'sucer', 'pipe', 'pétasse', 'garce', 'traînée', 'salopard', 'ordure',
|
||||
'fumier', 'pourri', 'dégueulasse', 'gueule', 'gueuler',
|
||||
# Insultes
|
||||
'con', 'abruti', 'débile', 'crétin', 'imbécile', 'loser', 'nullos', 'naze',
|
||||
'ridicule', 'pathétique', 'minable', 'nul', 'inutile', 'incapable', 'bon à rien',
|
||||
# NSFW/sexuel
|
||||
'sexe', 'porn', 'porno', 'bite', 'seins', 'sodomie', 'agression sexuelle',
|
||||
'harceleur', 'stalker',
|
||||
# Discrimination
|
||||
'raciste', 'antisémite', 'fasciste', 'gay', 'homo', 'féminin',
|
||||
# Drogues
|
||||
'drogue', 'cocaine', 'héroine', 'cannabis', 'ecstasy', 'lsd', 'crack', 'speed',
|
||||
'amphétamine', 'steroide', 'anabolisant',
|
||||
# Autres
|
||||
'cancer', 'maladie grave', 'crever', 'mourir'
|
||||
}
|
||||
|
||||
content_lower = content.lower()
|
||||
detected_bad_words = []
|
||||
|
||||
# Recherche rapide avec set pour performance
|
||||
for bad_word in bad_words:
|
||||
bad_word_lower = bad_word.lower()
|
||||
# Recherche insensible à la casse avec délimiteurs pour éviter faux positifs
|
||||
if f" {bad_word_lower} " in f" {content_lower} " or content_lower == bad_word_lower:
|
||||
detected_bad_words.append(bad_word)
|
||||
# Continue pour lister tous les mots détectés, mais limite à 3 pour performance
|
||||
if len(detected_bad_words) >= 3:
|
||||
break
|
||||
|
||||
if detected_bad_words:
|
||||
severity = "high" if any(word in ['nigger', 'nigga', 'pédé', 'bougnoul', 'viol', 'pédophile', 'inceste', 'naziste', 'hitler', 'suicide', 'se tuer', 'tuer', 'assassiner', 'meurtre'] for word in detected_bad_words) else "medium"
|
||||
return {
|
||||
"inappropriate": True,
|
||||
"severity": severity,
|
||||
"reason": f"Mots inappropriés détectés: {', '.join(detected_bad_words[:3])}",
|
||||
"bad_words": detected_bad_words[:3]
|
||||
}
|
||||
|
||||
return {"inappropriate": False}
|
||||
|
||||
|
||||
async def warn_and_check_ban_global(message, reason, message_deleted=False):
|
||||
"""
|
||||
Émet un avertissement et vérifie si l'utilisateur doit être banni (3+ avertissements)
|
||||
"""
|
||||
guild_id = str(message.guild.id)
|
||||
all_warnings = load_warnings()
|
||||
|
||||
if guild_id not in all_warnings:
|
||||
all_warnings[guild_id] = {}
|
||||
|
||||
user_id_str = str(message.author.id)
|
||||
if user_id_str not in all_warnings[guild_id]:
|
||||
all_warnings[guild_id][user_id_str] = []
|
||||
|
||||
# Ajouter l'avertissement
|
||||
all_warnings[guild_id][user_id_str].append({
|
||||
'reason': reason,
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'issued_by': 'AUTOMATIC_MODERATION'
|
||||
})
|
||||
|
||||
warning_count = len(all_warnings[guild_id][user_id_str])
|
||||
save_warnings(all_warnings)
|
||||
|
||||
from commandes.autres.logger import action_logger
|
||||
action_logger.log_action('AUTOMATIC_MODERATION', str(message.author), str(message.guild), {
|
||||
'reason': reason,
|
||||
'warning_count': warning_count,
|
||||
'original_message': message.content
|
||||
}, True)
|
||||
|
||||
# Vérifier si bannissement automatique nécessaire
|
||||
if warning_count >= 3:
|
||||
try:
|
||||
await message.author.ban(reason=f"Bannissement automatique: 3 avertissements accumulés. Dernière raison: {reason}")
|
||||
embed = discord.Embed(
|
||||
title="🚫 Bannissement automatique",
|
||||
description=f"{message.author.mention}, vous avez été banni pour accumulation d'avertissements (3+ avertissements).\n**Dernière raison:** {reason}",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
embed.set_footer(text=f"Total d'avertissements: {warning_count}")
|
||||
await message.channel.send(embed=embed)
|
||||
return True # Utilisateur banni
|
||||
except discord.Forbidden:
|
||||
embed = discord.Embed(
|
||||
title="Ban requis",
|
||||
description=f"❌ {message.author.mention} a 3+ avertissements, mais le bot n'a pas les permissions de bannir.\n**Agissez manuellement!**",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
embed.set_footer(text=f"Total d'avertissements: {warning_count}")
|
||||
await message.channel.send(embed=embed)
|
||||
return False
|
||||
else:
|
||||
# Envoyer message d'avertissement
|
||||
deletion_text = "Votre message a été supprimé pour contenu inapproprié." if message_deleted else "Mots inappropriés détectés dans votre message."
|
||||
warning_message = f"⚠️ **Avertissement automatique** {message.author.mention}\n{deletion_text}\n**Raison:** {reason}\n**Avertissements totaux:** {warning_count}\n**Avant bannissement:** {3 - warning_count} avertissement(s)\n*Modération automatique par IA*"
|
||||
await message.channel.send(warning_message)
|
||||
return False
|
||||
|
||||
|
||||
async def moderate_message(bot, message):
|
||||
"""
|
||||
Fonction principale de modération automatique d'un message
|
||||
Retourne True si le message a été modéré (et donc supprimé), False sinon
|
||||
"""
|
||||
# Préparer le contenu à analyser
|
||||
content_to_check = message.content
|
||||
if message.attachments:
|
||||
for attachment in message.attachments:
|
||||
if attachment.content_type and attachment.content_type.startswith('image/'):
|
||||
if not content_to_check.strip():
|
||||
content_to_check = f"[Image: {attachment.filename}]"
|
||||
else:
|
||||
content_to_check += f" [Image: {attachment.filename}]"
|
||||
|
||||
# Analyser le contenu
|
||||
if content_to_check.strip():
|
||||
print(f"[MODERATION] Analysing message from {message.author}: '{content_to_check}'")
|
||||
moderation_result = await check_message_content_global(bot, content_to_check)
|
||||
print(f"[MODERATION] Result: {moderation_result}")
|
||||
|
||||
bad_words = moderation_result.get('bad_words', [])
|
||||
inappropriate = moderation_result.get('inappropriate', False)
|
||||
print(f"[MODERATION] bad_words: {bad_words}, inappropriate: {inappropriate}")
|
||||
|
||||
# Toujours donner un avertissement si des mots inappropriés sont détectés
|
||||
if bad_words:
|
||||
reason = f"Mots inappropriés détectés: {', '.join(bad_words[:5])}"
|
||||
print(f"[MODERATION] Processing bad words, reason: {reason}")
|
||||
if inappropriate:
|
||||
print(f"[MODERATION] Message inappropriate, deleting...")
|
||||
try:
|
||||
await message.delete()
|
||||
print(f"[MODERATION] Message deleted successfully")
|
||||
except discord.Forbidden:
|
||||
print(f"[MODERATION] Forbidden to delete message")
|
||||
pass # Impossible de supprimer
|
||||
except Exception as e:
|
||||
print(f"[MODERATION] Error deleting message: {e}")
|
||||
await warn_and_check_ban_global(message, reason, message_deleted=True)
|
||||
print(f"[MODERATION] Warning sent and ban checked, returning True")
|
||||
return True # Message modéré
|
||||
else:
|
||||
print(f"[MODERATION] Not inappropriate, sending warning without deletion")
|
||||
await warn_and_check_ban_global(message, reason, message_deleted=False)
|
||||
|
||||
return False # Message autorisé
|
||||
|
||||
|
||||
# Test function pour vérifier la fonctionnalité
|
||||
async def test_auto_moderation():
|
||||
"""Fonction de test pour vérifier que les avertissements sont toujours donnés"""
|
||||
print("Test auto-moderation: vérification que les avertissements sont donnés pour les mots inappropriés")
|
||||
# Cette fonction peut être appelée pour tester manuellement si nécessaire
|
||||
Loading…
Add table
Add a link
Reference in a new issue