Kuby/bot.py

222 lines
9.7 KiB
Python
Raw Normal View History

import os
import sys
from dotenv import load_dotenv
# Charger les variables d'environnement AVANT tout le reste
load_dotenv()
2026-05-06 17:07:09 +02:00
import disnake
2026-01-14 21:32:20 +01:00
from commandes.ticket.utils.permissions import can_access_config
from commandes.ticket.data.storage import get_storage
2026-05-06 17:07:09 +02:00
from disnake.ext import commands
2026-01-01 18:48:25 +01:00
import asyncio
from src.logger import kuby_logger, log_performance
import logging
from src.advanced_logger import AdvancedLogger
import subprocess
2026-01-01 18:48:25 +01:00
# Récupération et validation de l'ID d'application
application_id_raw = os.getenv("APPLICATION_ID")
kuby_logger.debug(f"Raw APPLICATION_ID: {application_id_raw}")
try:
application_id = int(application_id_raw) if application_id_raw else None
kuby_logger.info(f"✅ APPLICATION_ID loaded successfully: {application_id}")
except ValueError:
kuby_logger.error(f"❌ APPLICATION_ID invalide : {application_id_raw}")
application_id = None
2026-05-06 17:07:09 +02:00
# Configuration des intents Disnake
intents = disnake.Intents.default()
2026-01-01 18:48:25 +01:00
intents.message_content = True
intents.members = True
intents.voice_states = True
2026-05-06 17:07:09 +02:00
kuby_logger.debug(f"Disnake intents configured: {intents}")
2026-01-01 18:48:25 +01:00
class MyBot(commands.Bot):
def __init__(self):
kuby_logger.debug("Initializing MyBot class")
super().__init__(
command_prefix="!",
2026-01-01 18:48:25 +01:00
intents=intents,
application_id=application_id,
)
kuby_logger.info("MyBot instance created successfully")
# Initialize advanced logger
self.advanced_logger = AdvancedLogger(self)
kuby_logger.info("✅ Advanced logger initialized")
# Start the Flask Webhook Server
self.flask_process = None
try:
flask_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "serveur_flask.py")
if os.path.exists(flask_path):
self.flask_process = subprocess.Popen(
[sys.executable, flask_path],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
cwd=os.path.dirname(flask_path)
)
kuby_logger.info(f"✅ Serveur Flask démarré (PID: {self.flask_process.pid})")
else:
kuby_logger.warning(f"⚠️ Fichier serveur_flask.py introuvable")
except Exception as e:
kuby_logger.error(f"❌ Impossible de démarrer le serveur Flask: {e}")
async def do_async_setup(self):
# --- INITIALIZATION LOGIC (Called before start() in kuby.py) ---
kuby_logger.info("🚀 Configuration initiale du bot Kuby...")
2026-01-01 18:48:25 +01:00
# Charger les extensions
extensions = [
"commandes.whitelist",
"commandes.whitelist_monitor",
"commandes.sendbotmessages",
"commandes.goodbye",
"commandes.welcome",
"commandes.security",
"commandes.snipe",
"commandes.scan",
"commandes.no_link",
"commandes.blacklist",
"commandes.ticket",
"commandes.modules_security.antispam",
"commandes.modules_security.antiraid",
"commandes.modules_security.logs_manager",
"commandes.modules_security.rules",
"commandes.ticket_whitelist",
2026-02-27 14:18:01 +01:00
"commandes.bug_report",
"commandes.convocation",
"commandes.absence_staff",
"commandes.website_sync",
"commandes.moderation",
2026-01-01 18:48:25 +01:00
]
for extension in extensions:
try:
self.load_extension(extension)
2026-01-01 18:48:25 +01:00
kuby_logger.info(f"✅ Extension chargée : {extension}")
except Exception as e:
kuby_logger.error(f"❌ Erreur lors du chargement de {extension} : {e}", exc_info=True)
# --- SYSTÈME DE WHITELIST (DÉDIÉ SLASH COMMANDS) ---
async def global_slash_whitelist_check(inter: disnake.ApplicationCommandInteraction):
2026-01-01 18:48:25 +01:00
try:
if await self.is_owner(inter.author):
return True
command_name = inter.data.name
if command_name in ["ticketconfig", "ticketpanel", "ticket_config", "ticket_panel", "ticket_whitelist_config"]:
2026-01-01 18:48:25 +01:00
return True
whitelist_cog = self.get_cog("WhitelistMonitor")
if not whitelist_cog:
return True
is_whitelisted = whitelist_cog.is_whitelisted(inter.guild.id, inter.author.id)
2026-01-01 18:48:25 +01:00
if not is_whitelisted:
kuby_logger.info(f"🚫 [Check] Accès refusé : {inter.author} sur /{command_name}")
2026-01-01 18:48:25 +01:00
msg = "❌ Vous n'êtes pas autorisé à utiliser cette commande. Veuillez demander à être ajouté à la whitelist."
if not inter.response.is_done():
await inter.response.send_message(msg, ephemeral=True)
2026-01-01 18:48:25 +01:00
return False
return True
except Exception as e:
kuby_logger.error(f"⚠️ [Check] Erreur critique: {e}", exc_info=True)
2026-01-01 18:48:25 +01:00
return True
self.add_app_command_check(global_slash_whitelist_check)
# --- LOGGING DES INTERACTIONS ---
@self.listen("on_interaction")
async def log_interaction(inter: disnake.Interaction):
if inter.type == disnake.InteractionType.application_command:
kuby_logger.info(f"⚡ Interaction reçue : /{inter.data.name} par {inter.user}")
kuby_logger.info("✅ Configuration terminée")
2026-01-01 18:48:25 +01:00
async def close(self):
if hasattr(self, 'flask_process') and self.flask_process:
kuby_logger.info("Arrêt du serveur Flask interne...")
self.flask_process.terminate()
try:
self.flask_process.wait(timeout=5)
except subprocess.TimeoutExpired:
self.flask_process.kill()
await super().close()
2026-01-01 18:48:25 +01:00
# --- ÉVÉNEMENTS RESTAURÉS ---
async def on_ready(self):
kuby_logger.info(f"🤖 Bot connecté : {self.user} (ID : {self.user.id})")
kuby_logger.info(f"📊 Serveurs : {len(self.guilds)}")
kuby_logger.info(f"🔍 Intents Status - Members: {self.intents.members}, Presences: {self.intents.presences}, Core: {self.intents.message_content}")
if not self.intents.members:
kuby_logger.warning("⚠️ L'intent MEMBERS est désactivé !")
2026-01-01 18:48:25 +01:00
kuby_logger.info("✅ Bot prêt et opérationnel !")
async def on_guild_join(self, guild):
kuby_logger.info(f"🆕 Bot joined new guild: {guild.name} (ID: {guild.id})")
kuby_logger.audit(f"Bot added to guild: {guild.name}")
async def on_guild_remove(self, guild):
kuby_logger.info(f"🚪 Bot removed from guild: {guild.name}")
kuby_logger.audit(f"Bot removed from guild: {guild.name}")
async def on_member_join(self, member):
kuby_logger.info(f"👋 {member} joined {member.guild.name}")
if hasattr(self, 'advanced_logger'):
self.advanced_logger.log_member_join(member)
previous_roles = self.advanced_logger.check_previous_roles(member.id)
if previous_roles:
guild = member.guild
roles_to_add = [guild.get_role(rid) for rid in previous_roles.get("role_ids", [])]
roles_to_add = [r for r in roles_to_add if r and r < guild.me.top_role]
if roles_to_add:
try:
await member.add_roles(*roles_to_add)
kuby_logger.info(f"Restored {len(roles_to_add)} roles for {member}")
except Exception as e:
kuby_logger.error(f"Failed to restore roles: {e}")
async def on_member_remove(self, member):
kuby_logger.info(f"👋 {member} left {member.guild.name}")
if hasattr(self, 'advanced_logger'):
self.advanced_logger.log_member_leave(member)
try:
from commandes.security import load_settings
settings = load_settings(member.guild.id)
log_channel_id = settings.get("log_channel_id")
if log_channel_id:
log_channel = member.guild.get_channel(log_channel_id)
if log_channel:
await self.advanced_logger.send_leave_notification(member, log_channel)
except Exception as e:
kuby_logger.error(f"Error in leave notification: {e}")
async def on_message_delete(self, message):
if message.author.bot: return
if hasattr(self, 'advanced_logger'):
self.advanced_logger.log_message_event(message, "deleted")
async def on_message_edit(self, before, after):
if before.author.bot or before.content == after.content: return
if hasattr(self, 'advanced_logger'):
self.advanced_logger.log_message_event(before, "edited", {
"before_content": before.content, "after_content": after.content
})
async def on_voice_state_update(self, member, before, after):
if member.bot: return
if before.channel != after.channel and hasattr(self, 'advanced_logger'):
if before.channel is None:
self.advanced_logger.log_voice_event(member, after.channel, "joined")
elif after.channel is None:
self.advanced_logger.log_voice_event(member, before.channel, "left")
else:
self.advanced_logger.log_voice_event(member, before.channel, "moved_from")
self.advanced_logger.log_voice_event(member, after.channel, "moved_to")
async def on_command_error(self, ctx, error):
if isinstance(error, commands.CheckFailure):
return
2026-01-01 18:48:25 +01:00
kuby_logger.error(f"Command error in {ctx.command}: {str(error)}", exc_info=True)
2026-01-14 21:32:20 +01:00
bot = MyBot()