Migration vers Disnake et ajout des components V2

This commit is contained in:
Mathis 2026-05-09 18:42:42 +02:00
parent c8c579eefe
commit 98f7501e07
47 changed files with 1196 additions and 722 deletions

View file

@ -0,0 +1,30 @@
import disnake
from disnake.ui import View, Button
import asyncio
class MyView(View):
def __init__(self):
super().__init__(timeout=None)
@disnake.ui.button(label="Test")
async def my_btn(self, arg1, arg2):
print(f"Arg1 type: {type(arg1)}")
print(f"Arg2 type: {type(arg2)}")
async def main():
view = MyView()
btn = view.children[0]
print(f"Button: {btn}")
# Mock an interaction
class MockInteraction:
pass
try:
await btn.callback(MockInteraction())
except Exception as e:
print(f"Error during callback: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())

View file

@ -0,0 +1,4 @@
import disnake
import disnake.ext.commands as commands
bot = commands.Bot(command_prefix="!")
print(f"Check methods: {[m for m in dir(bot) if 'check' in m]}")

View file

@ -0,0 +1,19 @@
import disnake
import disnake.ext.commands as commands
import asyncio
print(f"Disnake version: {disnake.__version__}")
bot = commands.Bot(command_prefix="!")
print(f"Bot has setup_hook: {hasattr(bot, 'setup_hook')}")
async def test():
print("Testing setup_hook call...")
class TestBot(commands.Bot):
async def setup_hook(self):
print("setup_hook CALLED!")
tbot = TestBot(command_prefix="!")
# We won't start it because we don't have a token here,
# but we can check if the library expects it.
asyncio.run(test())

View file

@ -0,0 +1,7 @@
import disnake
import disnake.ext.commands as commands
import asyncio
bot = commands.Bot(command_prefix="!")
print(f"Bot methods: {[m for m in dir(bot) if 'setup' in m or 'load' in m]}")
print(f"Is context manager: {hasattr(bot, '__aenter__')}")

View file

@ -0,0 +1,6 @@
import disnake
import disnake.ext.commands as commands
import inspect
bot = commands.Bot(command_prefix="!")
print(f"load_extension is coroutine: {inspect.iscoroutinefunction(bot.load_extension)}")

View file

@ -0,0 +1,8 @@
import disnake
print(f"disnake.TextStyle: {hasattr(disnake, 'TextStyle')}")
print(f"disnake.TextInputStyle: {hasattr(disnake, 'TextInputStyle')}")
try:
import disnake.ui
print(f"disnake.ui.TextInputStyle: {hasattr(disnake.ui, 'TextInputStyle')}")
except:
pass

View file

@ -0,0 +1,52 @@
import os
import re
def fix_file(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# Split by class to be surgical
classes = re.split(r'^(class\s+.*)$', content, flags=re.MULTILINE)
new_content = []
if len(classes) > 0:
new_content.append(classes[0]) # Header
for i in range(1, len(classes), 2):
class_header = classes[i]
class_body = classes[i+1] if i+1 < len(classes) else ""
# Determine if it's a View or a Modal
is_view = "disnake.ui.View" in class_header or "(disnake.ui.View)" in class_header or "super().__init__(timeout=" in class_body
is_modal = "disnake.ui.Modal" in class_header or "(disnake.ui.Modal)" in class_header or "super().__init__(title=" in class_body
if is_view:
# Views use add_item
class_body = class_body.replace("self.append_component(", "self.add_item(")
# Ensure super().__init__ doesn't have components=[] if it's a view
class_body = class_body.replace("super().__init__(components=[],", "super().__init__(")
class_body = class_body.replace("super().__init__(components=[], ", "super().__init__(")
if is_modal:
# Modals use append_component
class_body = class_body.replace("self.add_item(", "self.append_component(")
# Modals MUST have components=[] in super().__init__ if not already there
# (My previous sed might have added it correctly)
pass
new_content.append(class_header)
new_content.append(class_body)
final_content = "".join(new_content)
if final_content != content:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(final_content)
return True
return False
for root, dirs, files in os.walk('commandes'):
for file in files:
if file.endswith('.py'):
path = os.path.join(root, file)
if fix_file(path):
print(f"Fixed {path}")

View file

@ -0,0 +1,36 @@
import os
import re
def fix_text_input_default(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# Match TextInput( followed by anything including newlines, until )
# This is a bit risky but we can refine it.
# We look for default= inside the arguments of TextInput
def replace_default(match):
args = match.group(2)
new_args = args.replace("default=", "value=")
return f"{match.group(1)}{new_args})"
# Regex: (disnake\.ui\.TextInput\(|ui\.TextInput\(|TextInput\() (.*? \))
# We need to handle nested parentheses if any, but TextInput usually doesn't have them in args.
new_content = re.sub(r'((?:disnake\.ui\.|ui\.|)TextInput\()(.*?\))', replace_default, content, flags=re.DOTALL)
if new_content != content:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(new_content)
return True
return False
files_to_check = [
"commandes/moderation.py",
"commandes/ticket/__init__.py"
]
for path in files_to_check:
if os.path.exists(path):
if fix_text_input_default(path):
print(f"Fixed {path}")

View file

@ -0,0 +1,7 @@
import disnake
import inspect
try:
print(f"Modal init signature: {inspect.signature(disnake.ui.Modal.__init__)}")
except Exception as e:
print(f"Error inspecting Modal: {e}")

View file

@ -0,0 +1,7 @@
import disnake
import inspect
try:
print(f"Section init signature: {inspect.signature(disnake.ui.Section.__init__)}")
except Exception as e:
print(f"Error inspecting Section: {e}")

View file

@ -0,0 +1,3 @@
import disnake
print(disnake.ui.Container)
print(disnake.ui.TextDisplay)

View file

@ -0,0 +1,17 @@
import disnake
import asyncio
async def main():
class DummyResponse:
async def edit_message(self, *args, **kwargs):
print(kwargs)
inter = type('DummyInter', (), {'response': DummyResponse()})()
container = disnake.ui.Container()
try:
await inter.response.edit_message(components=[container])
print("Success")
except Exception as e:
print(f"Error: {e}")
asyncio.run(main())

88
bot.py
View file

@ -1,4 +1,5 @@
import os import os
import sys
from dotenv import load_dotenv from dotenv import load_dotenv
# Charger les variables d'environnement AVANT tout le reste # Charger les variables d'environnement AVANT tout le reste
@ -13,7 +14,6 @@ from src.logger import kuby_logger, log_performance
import logging import logging
from src.advanced_logger import AdvancedLogger from src.advanced_logger import AdvancedLogger
import subprocess import subprocess
import sys
# Récupération et validation de l'ID d'application # Récupération et validation de l'ID d'application
application_id_raw = os.getenv("APPLICATION_ID") application_id_raw = os.getenv("APPLICATION_ID")
@ -42,9 +42,6 @@ class MyBot(commands.Bot):
) )
kuby_logger.info("MyBot instance created successfully") kuby_logger.info("MyBot instance created successfully")
async def setup_hook(self):
kuby_logger.info("🚀 Démarrage du bot Kuby...")
# Initialize advanced logger # Initialize advanced logger
self.advanced_logger = AdvancedLogger(self) self.advanced_logger = AdvancedLogger(self)
kuby_logger.info("✅ Advanced logger initialized") kuby_logger.info("✅ Advanced logger initialized")
@ -54,8 +51,6 @@ class MyBot(commands.Bot):
try: try:
flask_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "serveur_flask.py") flask_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "serveur_flask.py")
if os.path.exists(flask_path): if os.path.exists(flask_path):
# On utilise DEVNULL car PM2 ou Nohup gèrent déjà les logs globaux
# et ça évite que le pipe se remplisse et bloque le serveur Flask
self.flask_process = subprocess.Popen( self.flask_process = subprocess.Popen(
[sys.executable, flask_path], [sys.executable, flask_path],
stdout=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
@ -68,6 +63,11 @@ class MyBot(commands.Bot):
except Exception as e: except Exception as e:
kuby_logger.error(f"❌ Impossible de démarrer le serveur Flask: {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...")
# Charger les extensions # Charger les extensions
extensions = [ extensions = [
"commandes.whitelist", "commandes.whitelist",
@ -95,62 +95,43 @@ class MyBot(commands.Bot):
for extension in extensions: for extension in extensions:
try: try:
await self.load_extension(extension) self.load_extension(extension)
kuby_logger.info(f"✅ Extension chargée : {extension}") kuby_logger.info(f"✅ Extension chargée : {extension}")
except Exception as e: except Exception as e:
kuby_logger.error(f"❌ Erreur lors du chargement de {extension} : {e}", exc_info=True) kuby_logger.error(f"❌ Erreur lors du chargement de {extension} : {e}", exc_info=True)
# --- SYSTÈME DE WHITELIST (CORRIGÉ POUR ÉVITER LES ERREURS) --- # --- SYSTÈME DE WHITELIST (DÉDIÉ SLASH COMMANDS) ---
@self.check async def global_slash_whitelist_check(inter: disnake.ApplicationCommandInteraction):
async def whitelist_check(ctx):
try: try:
# 1. Bypass pour le propriétaire (Owner) if await self.is_owner(inter.author):
if await self.is_owner(ctx.author): return True
command_name = inter.data.name
if command_name in ["ticketconfig", "ticketpanel", "ticket_config", "ticket_panel", "ticket_whitelist_config"]:
return True return True
# 1b. Bypass pour les commandes de config tickets
# Si la commande est une commande ticket et l'utilisateur a les perms ticket
if ctx.command and (ctx.command.name in ["ticketconfig", "ticketsetup", "configticket"]):
try:
storage = get_storage()
config = storage.load_config(ctx.guild.id)
if can_access_config(ctx, config):
return True
except Exception as e:
kuby_logger.error(f"Error checking ticket permissions in global whitelist: {e}")
# Fallthrough to normal whitelist check if error
# 2. Récupération du Cog
whitelist_cog = self.get_cog("WhitelistMonitor") whitelist_cog = self.get_cog("WhitelistMonitor")
if not whitelist_cog: if not whitelist_cog:
kuby_logger.warning("WhitelistMonitor cog not found, allowing all commands")
return True return True
is_whitelisted = whitelist_cog.is_whitelisted(inter.guild.id, inter.author.id)
is_whitelisted = whitelist_cog.is_whitelisted(ctx.guild.id, ctx.author.id)
if not is_whitelisted: if not is_whitelisted:
kuby_logger.info(f"User {ctx.author} (ID: {ctx.author.id}) attempted to use command but is not whitelisted") kuby_logger.info(f"🚫 [Check] Accès refusé : {inter.author} sur /{command_name}")
# Réponse adaptée (Slash vs Message)
msg = "❌ Vous n'êtes pas autorisé à utiliser cette commande. Veuillez demander à être ajouté à la whitelist." msg = "❌ Vous n'êtes pas autorisé à utiliser cette commande. Veuillez demander à être ajouté à la whitelist."
if ctx.interaction: if not inter.response.is_done():
await ctx.send(msg, ephemeral=True) await inter.response.send_message(msg, ephemeral=True)
else:
await ctx.send(msg)
return False return False
return True return True
except Exception as e: except Exception as e:
kuby_logger.error(f"Error in whitelist check: {e}") kuby_logger.error(f"⚠️ [Check] Erreur critique: {e}", exc_info=True)
return True return True
# Sync slash commands self.add_app_command_check(global_slash_whitelist_check)
try:
# Disnake handles syncing automatically by default # --- LOGGING DES INTERACTIONS ---
kuby_logger.info("✅ Commandes slash prêtes avec Disnake") @self.listen("on_interaction")
except Exception as e: async def log_interaction(inter: disnake.Interaction):
kuby_logger.error(f"❌ Erreur lors de la synchronisation des commandes slash : {e}", exc_info=True) 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")
async def close(self): async def close(self):
if hasattr(self, 'flask_process') and self.flask_process: if hasattr(self, 'flask_process') and self.flask_process:
@ -163,22 +144,12 @@ class MyBot(commands.Bot):
await super().close() await super().close()
# --- ÉVÉNEMENTS RESTAURÉS --- # --- ÉVÉNEMENTS RESTAURÉS ---
async def on_ready(self): async def on_ready(self):
kuby_logger.info(f"🤖 Bot connecté : {self.user} (ID : {self.user.id})") kuby_logger.info(f"🤖 Bot connecté : {self.user} (ID : {self.user.id})")
kuby_logger.info(f"📊 Serveurs : {len(self.guilds)}") kuby_logger.info(f"📊 Serveurs : {len(self.guilds)}")
# Log intents status
kuby_logger.info(f"🔍 Intents Status - Members: {self.intents.members}, Presences: {self.intents.presences}, Core: {self.intents.message_content}") kuby_logger.info(f"🔍 Intents Status - Members: {self.intents.members}, Presences: {self.intents.presences}, Core: {self.intents.message_content}")
if not self.intents.members: if not self.intents.members:
kuby_logger.warning("⚠️ L'intent MEMBERS est désactivé ! Les événements de join/leave et les DMs pourraient ne pas fonctionner correctement.") kuby_logger.warning("⚠️ L'intent MEMBERS est désactivé !")
for guild in self.guilds:
kuby_logger.debug(f"Guild: {guild.name} (ID: {guild.id}) - Members: {guild.member_count}")
total_members = sum(guild.member_count for guild in self.guilds)
kuby_logger.info(f"📊 Total members across all guilds: {total_members}")
kuby_logger.info("✅ Bot prêt et opérationnel !") kuby_logger.info("✅ Bot prêt et opérationnel !")
async def on_guild_join(self, guild): async def on_guild_join(self, guild):
@ -209,7 +180,6 @@ class MyBot(commands.Bot):
kuby_logger.info(f"👋 {member} left {member.guild.name}") kuby_logger.info(f"👋 {member} left {member.guild.name}")
if hasattr(self, 'advanced_logger'): if hasattr(self, 'advanced_logger'):
self.advanced_logger.log_member_leave(member) self.advanced_logger.log_member_leave(member)
# Notification de départ
try: try:
from commandes.security import load_settings from commandes.security import load_settings
settings = load_settings(member.guild.id) settings = load_settings(member.guild.id)
@ -246,7 +216,7 @@ class MyBot(commands.Bot):
async def on_command_error(self, ctx, error): async def on_command_error(self, ctx, error):
if isinstance(error, commands.CheckFailure): if isinstance(error, commands.CheckFailure):
return # Déjà géré dans le whitelist_check return
kuby_logger.error(f"Command error in {ctx.command}: {str(error)}", exc_info=True) kuby_logger.error(f"Command error in {ctx.command}: {str(error)}", exc_info=True)
bot = MyBot() bot = MyBot()

View file

@ -1,6 +1,6 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from disnake.ext import commands
import json import json
import os import os
@ -38,7 +38,7 @@ class Blacklist(commands.Cog):
# ---------- Slash Commands ---------- # ---------- Slash Commands ----------
@app_commands.command(name="blacklist", description="Blacklist un utilisateur") @app_commands.command(name="blacklist", description="Blacklist un utilisateur")
@app_commands.describe(user="Utilisateur à blacklister", reason="Raison") @app_commands.describe(user="Utilisateur à blacklister", reason="Raison")
async def blacklist_slash(self, interaction: discord.Interaction, user: discord.User, reason: str = "Aucune raison fournie"): async def blacklist_slash(self, interaction: disnake.Interaction, user: disnake.User, reason: str = "Aucune raison fournie"):
if not self.is_agent(interaction.user.id): if not self.is_agent(interaction.user.id):
return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True) return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True)
@ -55,7 +55,7 @@ class Blacklist(commands.Cog):
@app_commands.command(name="unblacklist", description="Retire un utilisateur de la blacklist") @app_commands.command(name="unblacklist", description="Retire un utilisateur de la blacklist")
@app_commands.describe(user="Utilisateur à retirer") @app_commands.describe(user="Utilisateur à retirer")
async def unblacklist_slash(self, interaction: discord.Interaction, user: discord.User): async def unblacklist_slash(self, interaction: disnake.Interaction, user: disnake.User):
if not self.is_agent(interaction.user.id): if not self.is_agent(interaction.user.id):
return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True) return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True)
@ -81,13 +81,13 @@ class Blacklist(commands.Cog):
pass pass
# --------- Boutons ---------- # --------- Boutons ----------
class TicketButton(discord.ui.View): class TicketButton(disnake.ui.View):
def __init__(self, user_id: int): def __init__(self, user_id: int):
super().__init__(timeout=None) super().__init__(timeout=None)
self.user_id = user_id self.user_id = user_id
@discord.ui.button(label="📩 Ouvrir une demande de déblacklist", style=discord.ButtonStyle.danger) @disnake.ui.button(label="📩 Ouvrir une demande de déblacklist", style=disnake.ButtonStyle.danger)
async def open_ticket(self, interaction: discord.Interaction, button: discord.ui.Button): async def open_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
if interaction.user.id != self.user_id: if interaction.user.id != self.user_id:
return await interaction.response.send_message("❌ Ce bouton ne tappartient pas.", ephemeral=True) return await interaction.response.send_message("❌ Ce bouton ne tappartient pas.", ephemeral=True)
@ -110,13 +110,13 @@ class TicketButton(discord.ui.View):
await interaction.response.send_message("✅ Ton ticket a été créé en MP avec le bot.", ephemeral=True) await interaction.response.send_message("✅ Ton ticket a été créé en MP avec le bot.", ephemeral=True)
class CloseTicketView(discord.ui.View): class CloseTicketView(disnake.ui.View):
def __init__(self, user_id: int): def __init__(self, user_id: int):
super().__init__(timeout=None) super().__init__(timeout=None)
self.user_id = user_id self.user_id = user_id
@discord.ui.button(label="❌ Fermer le ticket", style=discord.ButtonStyle.danger) @disnake.ui.button(label="❌ Fermer le ticket", style=disnake.ButtonStyle.danger)
async def close_ticket(self, interaction: discord.Interaction, button: discord.ui.Button): async def close_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
agents = load_json(AGENTS_FILE, {"agents": []}) agents = load_json(AGENTS_FILE, {"agents": []})
if str(interaction.user.id) not in agents["agents"]: if str(interaction.user.id) not in agents["agents"]:
return await interaction.response.send_message("⛔ Seuls les agents Omega Kube peuvent fermer un ticket.", ephemeral=True) return await interaction.response.send_message("⛔ Seuls les agents Omega Kube peuvent fermer un ticket.", ephemeral=True)
@ -124,13 +124,13 @@ class CloseTicketView(discord.ui.View):
view = ConfirmCloseView(self.user_id) view = ConfirmCloseView(self.user_id)
await interaction.response.send_message("⚠️ Veux-tu vraiment fermer ce ticket ?", view=view, ephemeral=True) await interaction.response.send_message("⚠️ Veux-tu vraiment fermer ce ticket ?", view=view, ephemeral=True)
class ConfirmCloseView(discord.ui.View): class ConfirmCloseView(disnake.ui.View):
def __init__(self, user_id: int): def __init__(self, user_id: int):
super().__init__(timeout=30) super().__init__(timeout=30)
self.user_id = user_id self.user_id = user_id
@discord.ui.button(label="✅ Oui", style=discord.ButtonStyle.success) @disnake.ui.button(label="✅ Oui", style=disnake.ButtonStyle.success)
async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button): async def confirm(self, button: disnake.ui.Button, interaction: disnake.Interaction):
agents = load_json(AGENTS_FILE, {"agents": []}) agents = load_json(AGENTS_FILE, {"agents": []})
if str(interaction.user.id) not in agents["agents"]: if str(interaction.user.id) not in agents["agents"]:
return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True) return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True)
@ -142,12 +142,12 @@ class ConfirmCloseView(discord.ui.View):
await interaction.channel.send("✅ Ticket fermé.") await interaction.channel.send("✅ Ticket fermé.")
await interaction.channel.delete() await interaction.channel.delete()
@discord.ui.button(label="❌ Non", style=discord.ButtonStyle.secondary) @disnake.ui.button(label="❌ Non", style=disnake.ButtonStyle.secondary)
async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button): async def cancel(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_message("❌ Fermeture annulée.", ephemeral=True) await interaction.response.send_message("❌ Fermeture annulée.", ephemeral=True)
# --------- Setup Cog ---------- # --------- Setup Cog ----------
async def setup(bot: commands.Bot): def setup(bot: commands.Bot):
cog = Blacklist(bot) cog = Blacklist(bot)
await bot.add_cog(cog) await bot.add_cog(cog)
await bot.tree.sync(guild=discord.Object(id=MAIN_GUILD_ID)) await bot.tree.sync(guild=disnake.Object(id=MAIN_GUILD_ID))

View file

@ -83,12 +83,12 @@ def parse_date(date_str: str):
class AbsenceModal(disnake.ui.Modal): class AbsenceModal(disnake.ui.Modal):
def __init__(self, superieur: Optional[disnake.Member] = None): def __init__(self, superieur: Optional[disnake.Member] = None):
super().__init__(title="Déclarer une Absence Staff") super().__init__(title="Déclarer une Absence Staff", components=[self.motif, self.date_debut, self.date_fin])
self.superieur = superieur self.superieur = superieur
motif = disnake.ui.TextInput( motif = disnake.ui.TextInput(
label="Motif de l'absence", label="Motif de l'absence",
style=disnake.TextStyle.paragraph, style=disnake.TextInputStyle.paragraph,
placeholder="Ex: Vacances, Raisons personnelles, Travail...", placeholder="Ex: Vacances, Raisons personnelles, Travail...",
required=True, required=True,
max_length=500 max_length=500
@ -187,7 +187,7 @@ class AbsenceConfigView(disnake.ui.View):
self.guild_id = guild_id self.guild_id = guild_id
@disnake.ui.button(label="Définir le Salon", style=disnake.ButtonStyle.primary, emoji="📁") @disnake.ui.button(label="Définir le Salon", style=disnake.ButtonStyle.primary, emoji="📁")
async def set_channel(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def set_channel(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_message("Mentionne le salon ici (ou envoie son ID) :", ephemeral=True) await interaction.response.send_message("Mentionne le salon ici (ou envoie son ID) :", ephemeral=True)
def check(m): def check(m):
@ -214,7 +214,7 @@ class AbsenceConfigView(disnake.ui.View):
await interaction.followup.send("❌ Temps écoulé.", ephemeral=True) await interaction.followup.send("❌ Temps écoulé.", ephemeral=True)
@disnake.ui.button(label="Définir le Rôle", style=disnake.ButtonStyle.primary, emoji="🎭") @disnake.ui.button(label="Définir le Rôle", style=disnake.ButtonStyle.primary, emoji="🎭")
async def set_role(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def set_role(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_message("Mentionne le rôle ici (ou envoie son ID) :", ephemeral=True) await interaction.response.send_message("Mentionne le rôle ici (ou envoie son ID) :", ephemeral=True)
def check(m): def check(m):
@ -499,7 +499,7 @@ class Absence(commands.Cog):
settings = load_settings(message.guild.id) settings = load_settings(message.guild.id)
channel_id = settings.get("absence_channel_id") channel_id = settings.get("absence_channel_id")
absence_url = f"https://discord.com/channels/{message.guild.id}/{channel_id}/{msg_id}" if channel_id and msg_id else "" absence_url = f"https://disnake.com/channels/{message.guild.id}/{channel_id}/{msg_id}" if channel_id and msg_id else ""
reply_text = f"⚠️ {message.author.mention}, cet utilisateur est actuellement absent." reply_text = f"⚠️ {message.author.mention}, cet utilisateur est actuellement absent."
if absence_url: if absence_url:
@ -507,5 +507,5 @@ class Absence(commands.Cog):
await message.reply(reply_text, delete_after=30) await message.reply(reply_text, delete_after=30)
async def setup(bot): def setup(bot):
await bot.add_cog(Absence(bot)) bot.add_cog(Absence(bot))

View file

@ -268,5 +268,5 @@ class Backup(commands.Cog):
await interaction.followup.send(embed=embed,ephemeral=True) await interaction.followup.send(embed=embed,ephemeral=True)
async def setup(bot: commands.Bot): def setup(bot):
await bot.add_cog(Backup(bot)) bot.add_cog(Backup(bot))

View file

@ -198,5 +198,5 @@ class BackupRestore(commands.Cog):
async def element_autocomplete_decorator(self, interaction: disnake.ApplicationCommandInteraction, current: str): async def element_autocomplete_decorator(self, interaction: disnake.ApplicationCommandInteraction, current: str):
return await self.element_autocomplete(interaction, current) return await self.element_autocomplete(interaction, current)
async def setup(bot: commands.Bot): def setup(bot):
await bot.add_cog(BackupRestore(bot)) bot.add_cog(BackupRestore(bot))

View file

@ -200,7 +200,7 @@ class TicketButton(disnake.ui.View):
self.user_id = user_id self.user_id = user_id
@disnake.ui.button(label="📩 Ouvrir une demande de révision", style=disnake.ButtonStyle.primary, custom_id="blacklist_open_ticket") @disnake.ui.button(label="📩 Ouvrir une demande de révision", style=disnake.ButtonStyle.primary, custom_id="blacklist_open_ticket")
async def open_ticket(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def open_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
if interaction.user.id != self.user_id: if interaction.user.id != self.user_id:
return await interaction.response.send_message("❌ Ce bouton ne tappartient pas.", ephemeral=True) return await interaction.response.send_message("❌ Ce bouton ne tappartient pas.", ephemeral=True)
@ -239,7 +239,7 @@ class CloseTicketView(disnake.ui.View):
self.user_id = user_id self.user_id = user_id
@disnake.ui.button(label="❌ Fermer le ticket", style=disnake.ButtonStyle.danger, custom_id="blacklist_close_ticket") @disnake.ui.button(label="❌ Fermer le ticket", style=disnake.ButtonStyle.danger, custom_id="blacklist_close_ticket")
async def close_ticket(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def close_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
if not interaction.bot.get_cog("Blacklist").is_agent(interaction.user.id): if not interaction.bot.get_cog("Blacklist").is_agent(interaction.user.id):
return await interaction.response.send_message("⛔ Seuls les agents peuvent fermer ce ticket.", ephemeral=True) return await interaction.response.send_message("⛔ Seuls les agents peuvent fermer ce ticket.", ephemeral=True)
@ -252,7 +252,7 @@ class ConfirmCloseView(disnake.ui.View):
self.user_id = user_id self.user_id = user_id
@disnake.ui.button(label="✅ Oui", style=disnake.ButtonStyle.success, custom_id="blacklist_confirm_close") @disnake.ui.button(label="✅ Oui", style=disnake.ButtonStyle.success, custom_id="blacklist_confirm_close")
async def confirm(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def confirm(self, button: disnake.ui.Button, interaction: disnake.Interaction):
if not interaction.bot.get_cog("Blacklist").is_agent(interaction.user.id): if not interaction.bot.get_cog("Blacklist").is_agent(interaction.user.id):
return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True) return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True)
@ -290,9 +290,9 @@ class ConfirmCloseView(disnake.ui.View):
await interaction.response.send_message("✅ Ticket fermé avec succès.", ephemeral=True) await interaction.response.send_message("✅ Ticket fermé avec succès.", ephemeral=True)
@disnake.ui.button(label="❌ Non", style=disnake.ButtonStyle.secondary, custom_id="blacklist_cancel_close") @disnake.ui.button(label="❌ Non", style=disnake.ButtonStyle.secondary, custom_id="blacklist_cancel_close")
async def cancel(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def cancel(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_message("❌ Fermeture annulée.", ephemeral=True) await interaction.response.send_message("❌ Fermeture annulée.", ephemeral=True)
# --------- Setup --------- # --------- Setup ---------
async def setup(bot: commands.Bot): def setup(bot):
await bot.add_cog(Blacklist(bot)) bot.add_cog(Blacklist(bot))

View file

@ -34,7 +34,7 @@ def save_report(issue_iid, user_id):
class BugReportModal(disnake.ui.Modal): class BugReportModal(disnake.ui.Modal):
def __init__(self, priority_choice): def __init__(self, priority_choice):
super().__init__(title="Signaler un Bug") super().__init__(title="Signaler un Bug", components=[self.bug_title, self.description])
self.priority_choice = priority_choice self.priority_choice = priority_choice
bug_title = disnake.ui.TextInput( bug_title = disnake.ui.TextInput(
@ -46,7 +46,7 @@ class BugReportModal(disnake.ui.Modal):
description = disnake.ui.TextInput( description = disnake.ui.TextInput(
label="Description détaillée", label="Description détaillée",
style=disnake.TextStyle.paragraph, style=disnake.TextInputStyle.paragraph,
placeholder="Que s'est-il passé ? Comment reproduire le bug ?", placeholder="Que s'est-il passé ? Comment reproduire le bug ?",
required=True, required=True,
max_length=1000 max_length=1000
@ -77,7 +77,7 @@ class BugReportModal(disnake.ui.Modal):
class FeatureSuggestionModal(disnake.ui.Modal): class FeatureSuggestionModal(disnake.ui.Modal):
def __init__(self): def __init__(self):
super().__init__(title="Suggérer une fonctionnalité") super().__init__(title="Suggérer une fonctionnalité", components=[self.suggestion_title, self.description])
suggestion_title = disnake.ui.TextInput( suggestion_title = disnake.ui.TextInput(
label="Titre de la suggestion", label="Titre de la suggestion",
@ -88,7 +88,7 @@ class FeatureSuggestionModal(disnake.ui.Modal):
description = disnake.ui.TextInput( description = disnake.ui.TextInput(
label="Détails de la fonctionnalité", label="Détails de la fonctionnalité",
style=disnake.TextStyle.paragraph, style=disnake.TextInputStyle.paragraph,
placeholder="Décrivez comment cela devrait fonctionner...", placeholder="Décrivez comment cela devrait fonctionner...",
required=True, required=True,
max_length=1000 max_length=1000
@ -334,5 +334,5 @@ class BugReport(commands.Cog):
async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction): async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction):
await interaction.response.send_modal(FeatureSuggestionModal()) await interaction.response.send_modal(FeatureSuggestionModal())
async def setup(bot): def setup(bot):
await bot.add_cog(BugReport(bot)) bot.add_cog(BugReport(bot))

View file

@ -274,5 +274,5 @@ class Convocation(commands.Cog):
await interaction.response.send_message(embed=embed, ephemeral=True) await interaction.response.send_message(embed=embed, ephemeral=True)
async def setup(bot): def setup(bot):
await bot.add_cog(Convocation(bot)) bot.add_cog(Convocation(bot))

View file

@ -218,5 +218,5 @@ class Goodbye(commands.Cog):
await interaction.response.send_message(msg, ephemeral=True) await interaction.response.send_message(msg, ephemeral=True)
async def setup(bot): def setup(bot):
await bot.add_cog(Goodbye(bot)) bot.add_cog(Goodbye(bot))

View file

@ -7,7 +7,7 @@ import re
class ModReasonModal(disnake.ui.Modal): class ModReasonModal(disnake.ui.Modal):
def __init__(self, parent_view, action_type): def __init__(self, parent_view, action_type):
super().__init__(title=f"Raison pour {action_type}") super().__init__(title=f"Raison pour {action_type}", components=[])
self.parent_view = parent_view self.parent_view = parent_view
self.action_type = action_type self.action_type = action_type
@ -17,7 +17,7 @@ class ModReasonModal(disnake.ui.Modal):
required=True, required=True,
max_length=500 max_length=500
) )
self.add_item(self.reason) self.append_component(self.reason)
if action_type == "TIMEOUT": if action_type == "TIMEOUT":
self.duration = disnake.ui.TextInput( self.duration = disnake.ui.TextInput(
@ -26,7 +26,7 @@ class ModReasonModal(disnake.ui.Modal):
required=True, required=True,
max_length=10 max_length=10
) )
self.add_item(self.duration) self.append_component(self.duration)
async def callback(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
reason = self.reason.value reason = self.reason.value
@ -78,43 +78,43 @@ class ModPanelView(disnake.ui.View):
await interaction.edit_original_response(embed=embed, view=self) await interaction.edit_original_response(embed=embed, view=self)
@disnake.ui.button(label="Avertir", style=disnake.ButtonStyle.secondary, emoji="⚠️") @disnake.ui.button(label="Avertir", style=disnake.ButtonStyle.secondary, emoji="⚠️")
async def warn_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def warn_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_modal(ModReasonModal(self, "WARN")) await interaction.response.send_modal(ModReasonModal(self, "WARN"))
@disnake.ui.button(label="Timeout", style=disnake.ButtonStyle.secondary, emoji="") @disnake.ui.button(label="Timeout", style=disnake.ButtonStyle.secondary, emoji="")
async def timeout_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def timeout_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_modal(ModReasonModal(self, "TIMEOUT")) await interaction.response.send_modal(ModReasonModal(self, "TIMEOUT"))
@disnake.ui.button(label="Expulser", style=disnake.ButtonStyle.secondary, emoji="👢") @disnake.ui.button(label="Expulser", style=disnake.ButtonStyle.secondary, emoji="👢")
async def kick_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def kick_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_modal(ModReasonModal(self, "KICK")) await interaction.response.send_modal(ModReasonModal(self, "KICK"))
@disnake.ui.button(label="Bannir", style=disnake.ButtonStyle.danger, emoji="🔨") @disnake.ui.button(label="Bannir", style=disnake.ButtonStyle.danger, emoji="🔨")
async def ban_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def ban_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_modal(ModReasonModal(self, "BAN")) await interaction.response.send_modal(ModReasonModal(self, "BAN"))
@disnake.ui.button(label="Historique", style=disnake.ButtonStyle.primary, emoji="📜") @disnake.ui.button(label="Historique", style=disnake.ButtonStyle.primary, emoji="📜")
async def history_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def history_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
cog = interaction.bot.get_cog("Moderation") cog = interaction.bot.get_cog("Moderation")
await cog.history(interaction, self.member) await cog.history(interaction, self.member)
@disnake.ui.button(label="Clear Warns", style=disnake.ButtonStyle.danger, emoji="🧹") @disnake.ui.button(label="Clear Warns", style=disnake.ButtonStyle.danger, emoji="🧹")
async def clear_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def clear_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
cog = interaction.bot.get_cog("Moderation") cog = interaction.bot.get_cog("Moderation")
await cog.clearwarns(interaction, self.member, reason="Nettoyage via Panel") await cog.clearwarns(interaction, self.member, reason="Nettoyage via Panel")
await self.update_panel(interaction) await self.update_panel(interaction)
class ModConfigModal(disnake.ui.Modal): class ModConfigModal(disnake.ui.Modal):
def __init__(self, field_name, current_value): def __init__(self, field_name, current_value):
super().__init__(title=f"Modifier {field_name}") super().__init__(components=[], title=f"Modifier {field_name}")
self.field_name = field_name self.field_name = field_name
self.input = disnake.ui.TextInput( self.input = disnake.ui.TextInput(
label=field_name, label=field_name,
default=str(current_value), value=str(current_value),
placeholder="Entrez une valeur numérique...", placeholder="Entrez une valeur numérique...",
required=True required=True
) )
self.add_item(self.input) self.append_component(self.input)
async def callback(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
value = self.input.value value = self.input.value
@ -146,7 +146,7 @@ class ModConfigView(disnake.ui.View):
self.db_path = db_path self.db_path = db_path
@disnake.ui.button(label="Log Channel", style=disnake.ButtonStyle.primary, emoji="📁") @disnake.ui.button(label="Log Channel", style=disnake.ButtonStyle.primary, emoji="📁")
async def log_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def log_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
view = disnake.ui.View() view = disnake.ui.View()
select = disnake.ui.ChannelSelect( select = disnake.ui.ChannelSelect(
placeholder="Sélectionnez le salon de logs...", placeholder="Sélectionnez le salon de logs...",
@ -166,7 +166,7 @@ class ModConfigView(disnake.ui.View):
await interaction.response.send_message("Choisissez le salon de logs :", view=view, ephemeral=True) await interaction.response.send_message("Choisissez le salon de logs :", view=view, ephemeral=True)
@disnake.ui.button(label="Paliers Warns", style=disnake.ButtonStyle.secondary, emoji="⚖️") @disnake.ui.button(label="Paliers Warns", style=disnake.ButtonStyle.secondary, emoji="⚖️")
async def limits_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def limits_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute("SELECT warn_limit_timeout, warn_limit_kick, warn_limit_ban FROM mod_config WHERE guild_id = ?", (self.guild_id,)) cursor.execute("SELECT warn_limit_timeout, warn_limit_kick, warn_limit_ban FROM mod_config WHERE guild_id = ?", (self.guild_id,))
@ -187,7 +187,7 @@ class ModConfigView(disnake.ui.View):
await interaction.response.send_message("Quelle limite modifier ?", view=view, ephemeral=True) await interaction.response.send_message("Quelle limite modifier ?", view=view, ephemeral=True)
@disnake.ui.button(label="Durée Timeout", style=disnake.ButtonStyle.secondary, emoji="⏱️") @disnake.ui.button(label="Durée Timeout", style=disnake.ButtonStyle.secondary, emoji="⏱️")
async def duration_btn(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def duration_btn(self, button: disnake.ui.Button, interaction: disnake.Interaction):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute("SELECT timeout_duration FROM mod_config WHERE guild_id = ?", (self.guild_id,)) cursor.execute("SELECT timeout_duration FROM mod_config WHERE guild_id = ?", (self.guild_id,))
@ -320,5 +320,5 @@ class Moderation(commands.Cog):
if not interaction.response.is_done(): await interaction.response.send_message(f"✅ Warns de {member.name} effacés.", ephemeral=True) if not interaction.response.is_done(): await interaction.response.send_message(f"✅ Warns de {member.name} effacés.", ephemeral=True)
else: await interaction.followup.send(f"✅ Warns de {member.name} effacés.", ephemeral=True) else: await interaction.followup.send(f"✅ Warns de {member.name} effacés.", ephemeral=True)
async def setup(bot): def setup(bot):
await bot.add_cog(Moderation(bot)) bot.add_cog(Moderation(bot))

View file

@ -56,5 +56,5 @@ class AntiRaid(commands.Cog):
embed = disnake.Embed(title="🚨 ALERTE RAID", description=f"Vague de {len(self.join_cache[guild.id])} membres !", color=0xFF0000) embed = disnake.Embed(title="🚨 ALERTE RAID", description=f"Vague de {len(self.join_cache[guild.id])} membres !", color=0xFF0000)
await channel.send(embed=embed) await channel.send(embed=embed)
async def setup(bot): def setup(bot):
await bot.add_cog(AntiRaid(bot)) bot.add_cog(AntiRaid(bot))

View file

@ -13,7 +13,7 @@ WHITELIST_FILE = "data/whitelist.json"
CACHE_TTL = 5 CACHE_TTL = 5
# Triggers pour détection de liens # Triggers pour détection de liens
LINK_TRIGGERS = ("discord.gg/", "http://", "https://", "www.") LINK_TRIGGERS = ("disnake.gg/", "http://", "https://", "www.")
class AntiSpam(commands.Cog): class AntiSpam(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
@ -181,5 +181,5 @@ class AntiSpam(commands.Cog):
except Exception as e: except Exception as e:
print(f"Erreur lors de la sanction : {e}") print(f"Erreur lors de la sanction : {e}")
async def setup(bot): def setup(bot):
await bot.add_cog(AntiSpam(bot)) bot.add_cog(AntiSpam(bot))

View file

@ -58,5 +58,5 @@ class LogsManager(commands.Cog):
) )
await log_chan.send(embed=embed) await log_chan.send(embed=embed)
async def setup(bot): def setup(bot):
await bot.add_cog(LogsManager(bot)) bot.add_cog(LogsManager(bot))

View file

@ -38,7 +38,7 @@ def save_settings(guild_id: int, settings: dict) -> None:
# --- MODALS DE CONFIGURATION DU RÈGLEMENT (BACK-END) --- # --- MODALS DE CONFIGURATION DU RÈGLEMENT (BACK-END) ---
class RulesTitleModal(disnake.ui.Modal, title="📜 Titre du Règlement"): class RulesTitleModal(disnake.ui.Modal):
"""Modal pour configurer le titre du règlement""" """Modal pour configurer le titre du règlement"""
title_input = disnake.ui.TextInput( title_input = disnake.ui.TextInput(
label="Titre du règlement", label="Titre du règlement",
@ -49,12 +49,12 @@ class RulesTitleModal(disnake.ui.Modal, title="📜 Titre du Règlement"):
) )
def __init__(self, guild_id: int, settings: dict, on_update_callback=None): def __init__(self, guild_id: int, settings: dict, on_update_callback=None):
super().__init__() super().__init__(title="📜 Titre du Règlement", components=[self.title_input])
self.guild_id = guild_id self.guild_id = guild_id
self.settings = settings self.settings = settings
self.on_update_callback = on_update_callback self.on_update_callback = on_update_callback
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
self.settings["rules_title"] = self.title_input.value self.settings["rules_title"] = self.title_input.value
save_settings(self.guild_id, self.settings) save_settings(self.guild_id, self.settings)
@ -77,24 +77,24 @@ class RulesTitleModal(disnake.ui.Modal, title="📜 Titre du Règlement"):
return view return view
class RulesContentModal(disnake.ui.Modal, title="📝 Contenu du Règlement"): class RulesContentModal(disnake.ui.Modal):
"""Modal pour configurer le contenu du règlement""" """Modal pour configurer le contenu du règlement"""
content_input = disnake.ui.TextInput( content_input = disnake.ui.TextInput(
label="Contenu du règlement", label="Contenu du règlement",
placeholder="Entrez les règles de votre serveur...", placeholder="Entrez les règles de votre serveur...",
style=disnake.TextStyle.paragraph, style=disnake.TextInputStyle.paragraph,
min_length=10, min_length=10,
max_length=4000, max_length=4000,
required=True required=True
) )
def __init__(self, guild_id: int, settings: dict, on_update_callback=None): def __init__(self, guild_id: int, settings: dict, on_update_callback=None):
super().__init__() super().__init__(title="📝 Contenu du Règlement", components=[self.content_input])
self.guild_id = guild_id self.guild_id = guild_id
self.settings = settings self.settings = settings
self.on_update_callback = on_update_callback self.on_update_callback = on_update_callback
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
self.settings["rules_content"] = self.content_input.value self.settings["rules_content"] = self.content_input.value
save_settings(self.guild_id, self.settings) save_settings(self.guild_id, self.settings)
@ -117,7 +117,7 @@ class RulesContentModal(disnake.ui.Modal, title="📝 Contenu du Règlement"):
return view return view
class RulesChannelModal(disnake.ui.Modal, title="📌 Salon du Règlement"): class RulesChannelModal(disnake.ui.Modal):
"""Modal pour sélectionner le salon du règlement""" """Modal pour sélectionner le salon du règlement"""
channel_input = disnake.ui.TextInput( channel_input = disnake.ui.TextInput(
label="ID du salon", label="ID du salon",
@ -128,12 +128,12 @@ class RulesChannelModal(disnake.ui.Modal, title="📌 Salon du Règlement"):
) )
def __init__(self, guild_id: int, settings: dict, on_update_callback=None): def __init__(self, guild_id: int, settings: dict, on_update_callback=None):
super().__init__() super().__init__(title="📌 Salon du Règlement", components=[self.channel_input])
self.guild_id = guild_id self.guild_id = guild_id
self.settings = settings self.settings = settings
self.on_update_callback = on_update_callback self.on_update_callback = on_update_callback
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
if not self.channel_input.value.isdigit(): if not self.channel_input.value.isdigit():
return await interaction.response.send_message( return await interaction.response.send_message(
"❌ Erreur : ID invalide.", "❌ Erreur : ID invalide.",
@ -171,7 +171,7 @@ class RulesChannelModal(disnake.ui.Modal, title="📌 Salon du Règlement"):
return view return view
class RulesRoleModal(disnake.ui.Modal, title="✅ Rôle d'Acceptation"): class RulesRoleModal(disnake.ui.Modal):
"""Modal pour configurer le rôle attribué à l'acceptation""" """Modal pour configurer le rôle attribué à l'acceptation"""
role_input = disnake.ui.TextInput( role_input = disnake.ui.TextInput(
label="ID du rôle", label="ID du rôle",
@ -182,12 +182,12 @@ class RulesRoleModal(disnake.ui.Modal, title="✅ Rôle d'Acceptation"):
) )
def __init__(self, guild_id: int, settings: dict, on_update_callback=None): def __init__(self, guild_id: int, settings: dict, on_update_callback=None):
super().__init__() super().__init__(title="✅ Rôle d'Acceptation", components=[self.role_input])
self.guild_id = guild_id self.guild_id = guild_id
self.settings = settings self.settings = settings
self.on_update_callback = on_update_callback self.on_update_callback = on_update_callback
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
if not self.role_input.value.isdigit(): if not self.role_input.value.isdigit():
return await interaction.response.send_message( return await interaction.response.send_message(
"❌ Erreur : ID invalide.", "❌ Erreur : ID invalide.",
@ -225,7 +225,7 @@ class RulesRoleModal(disnake.ui.Modal, title="✅ Rôle d'Acceptation"):
return view return view
class RulesMessageTypeModal(disnake.ui.Modal, title="📝 Type de Message"): class RulesMessageTypeModal(disnake.ui.Modal):
"""Modal pour choisir le type de message du règlement""" """Modal pour choisir le type de message du règlement"""
message_type = disnake.ui.TextInput( message_type = disnake.ui.TextInput(
label="Type de message", label="Type de message",
@ -236,12 +236,12 @@ class RulesMessageTypeModal(disnake.ui.Modal, title="📝 Type de Message"):
) )
def __init__(self, guild_id: int, settings: dict, on_update_callback=None): def __init__(self, guild_id: int, settings: dict, on_update_callback=None):
super().__init__() super().__init__(title="📝 Type de Message", components=[self.message_type])
self.guild_id = guild_id self.guild_id = guild_id
self.settings = settings self.settings = settings
self.on_update_callback = on_update_callback self.on_update_callback = on_update_callback
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
msg_type = self.message_type.value.lower().strip() msg_type = self.message_type.value.lower().strip()
if msg_type not in ["embed", "simple"]: if msg_type not in ["embed", "simple"]:
@ -323,13 +323,13 @@ class RulesAcceptButton(disnake.ui.View):
self.guild_id = guild_id self.guild_id = guild_id
self.accept_role_id = accept_role_id self.accept_role_id = accept_role_id
@discord.ui.button( @disnake.ui.button(
label="J'accepte le règlement", label="J'accepte le règlement",
emoji="", emoji="",
style=disnake.ButtonStyle.green, style=disnake.ButtonStyle.green,
custom_id="rules_accept_button" custom_id="rules_accept_button"
) )
async def accept_rules(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def accept_rules(self, button: disnake.ui.Button, interaction: disnake.Interaction):
"""Gère le clic sur le bouton d'acceptation""" """Gère le clic sur le bouton d'acceptation"""
guild = interaction.guild guild = interaction.guild
@ -495,8 +495,8 @@ class RulesCog(commands.Cog):
return title, content return title, content
async def setup(bot): def setup(bot):
"""Setup du cog de règlement""" """Setup du cog de règlement"""
cog = RulesCog(bot) cog = RulesCog(bot)
await bot.add_cog(cog) bot.add_cog(cog)

View file

@ -47,5 +47,5 @@ class NoLink(commands.Cog):
print(f"Erreur lors de la suppression du message : {exc}") print(f"Erreur lors de la suppression du message : {exc}")
async def setup(bot: commands.Bot) -> None: def setup(bot: commands.Bot) -> None:
await bot.add_cog(NoLink(bot)) bot.add_cog(NoLink(bot))

View file

@ -77,5 +77,5 @@ class Scan(commands.Cog):
await interaction.followup.send(f"✅ Fichier sain.\nHash : `{result['hash']}`") await interaction.followup.send(f"✅ Fichier sain.\nHash : `{result['hash']}`")
async def setup(bot: commands.Bot): def setup(bot):
await bot.add_cog(Scan(bot)) bot.add_cog(Scan(bot))

View file

@ -69,7 +69,7 @@ def is_immune(guild, user) -> bool:
# --- MODALS DE CONFIGURATION --- # --- MODALS DE CONFIGURATION ---
class SpamThresholdModal(disnake.ui.Modal, title="🛡️ Seuil Anti-Spam"): class SpamThresholdModal(disnake.ui.Modal):
"""Modal pour configurer le seuil anti-spam""" """Modal pour configurer le seuil anti-spam"""
threshold_input = disnake.ui.TextInput( threshold_input = disnake.ui.TextInput(
label="Messages max autorisés", label="Messages max autorisés",
@ -80,12 +80,12 @@ class SpamThresholdModal(disnake.ui.Modal, title="🛡️ Seuil Anti-Spam"):
) )
def __init__(self, guild_id: int, settings: dict, view: 'SecurityView'): def __init__(self, guild_id: int, settings: dict, view: 'SecurityView'):
super().__init__() super().__init__(title="🛡️ Seuil Anti-Spam", components=[self.threshold_input])
self.guild_id = guild_id self.guild_id = guild_id
self.settings = settings self.settings = settings
self.parent_view = view self.parent_view = view
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
if not self.threshold_input.value.isdigit(): if not self.threshold_input.value.isdigit():
return await interaction.response.send_message( return await interaction.response.send_message(
"❌ Erreur : Veuillez entrer un nombre entier.", "❌ Erreur : Veuillez entrer un nombre entier.",
@ -110,7 +110,7 @@ class SpamThresholdModal(disnake.ui.Modal, title="🛡️ Seuil Anti-Spam"):
ephemeral=True ephemeral=True
) )
class RaidThresholdModal(disnake.ui.Modal, title="⚔️ Seuil Anti-Raid"): class RaidThresholdModal(disnake.ui.Modal):
"""Modal pour configurer le seuil anti-raid""" """Modal pour configurer le seuil anti-raid"""
threshold_input = disnake.ui.TextInput( threshold_input = disnake.ui.TextInput(
label="Joins max en 10 secondes", label="Joins max en 10 secondes",
@ -121,12 +121,12 @@ class RaidThresholdModal(disnake.ui.Modal, title="⚔️ Seuil Anti-Raid"):
) )
def __init__(self, guild_id: int, settings: dict, view: 'SecurityView'): def __init__(self, guild_id: int, settings: dict, view: 'SecurityView'):
super().__init__() super().__init__(title="⚔️ Seuil Anti-Raid", components=[self.threshold_input])
self.guild_id = guild_id self.guild_id = guild_id
self.settings = settings self.settings = settings
self.parent_view = view self.parent_view = view
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
if not self.threshold_input.value.isdigit(): if not self.threshold_input.value.isdigit():
return await interaction.response.send_message( return await interaction.response.send_message(
"❌ Erreur : Veuillez entrer un nombre entier.", "❌ Erreur : Veuillez entrer un nombre entier.",
@ -153,7 +153,7 @@ class RaidThresholdModal(disnake.ui.Modal, title="⚔️ Seuil Anti-Raid"):
# --- MODALS DE CONFIGURATION WHITELIST --- # --- MODALS DE CONFIGURATION WHITELIST ---
class WhitelistModal(disnake.ui.Modal, title="👤 Ajouter à la Whitelist"): class WhitelistModal(disnake.ui.Modal):
"""Modal pour ajouter un utilisateur à la whitelist""" """Modal pour ajouter un utilisateur à la whitelist"""
user_input = disnake.ui.TextInput( user_input = disnake.ui.TextInput(
label="ID de l'utilisateur", label="ID de l'utilisateur",
@ -164,11 +164,11 @@ class WhitelistModal(disnake.ui.Modal, title="👤 Ajouter à la Whitelist"):
) )
def __init__(self, guild_id: int, view: 'SecurityView'): def __init__(self, guild_id: int, view: 'SecurityView'):
super().__init__() super().__init__(title="👤 Ajouter à la Whitelist", components=[self.user_input])
self.guild_id = guild_id self.guild_id = guild_id
self.parent_view = view self.parent_view = view
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
if not self.user_input.value.isdigit(): if not self.user_input.value.isdigit():
return await interaction.response.send_message( return await interaction.response.send_message(
"❌ Erreur : ID invalide.", "❌ Erreur : ID invalide.",
@ -873,7 +873,7 @@ class MainCategorySelect(disnake.ui.Select):
class WhitelistSelect(disnake.ui.Select): class WhitelistSelect(disnake.ui.Select):
"""Menu dropdown pour voir et gérer les utilisateurs whitelistés""" """Menu dropdown pour voir et gérer les utilisateurs whitelistés"""
def __init__(self, guild: discord.Guild, view: 'SecurityView'): def __init__(self, guild: disnake.Guild, view: 'SecurityView'):
self.guild = guild self.guild = guild
self.parent_view = view self.parent_view = view
whitelist = load_whitelist(guild.id) whitelist = load_whitelist(guild.id)
@ -950,11 +950,11 @@ class Security(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@app_commands.command( @commands.slash_command(
name="security", name="security",
description="🛡️ Ouvrir le panneau de sécurité Kuby" description="🛡️ Ouvrir le panneau de sécurité Kuby"
) )
async def security(self, interaction: disnake.Interaction): async def security(self, interaction: disnake.ApplicationCommandInteraction):
""" """
Commande principale pour ouvrir l'interface de sécurité. Commande principale pour ouvrir l'interface de sécurité.
Accessible uniquement aux administrateurs et propriétaires whitelistés. Accessible uniquement aux administrateurs et propriétaires whitelistés.
@ -989,12 +989,12 @@ class Security(commands.Cog):
) )
@security.error @security.error
async def security_error(self, interaction: disnake.Interaction, error: app_commands.AppCommandError): async def security_error(self, interaction: disnake.Interaction, error: Exception):
"""Gestion des erreurs de la commande security""" """Gestion des erreurs de la commande security"""
# Utilisation de followup si l'interaction est déjà différée ou répondue # Utilisation de followup si l'interaction est déjà différée ou répondue
send_method = interaction.followup.send if interaction.response.is_done() else interaction.response.send_message send_method = interaction.followup.send if interaction.response.is_done() else interaction.response.send_message
if isinstance(error, app_commands.MissingPermissions): if isinstance(error, commands.MissingPermissions):
await send_method( await send_method(
"❌ Permissions insuffisantes.", "❌ Permissions insuffisantes.",
ephemeral=True ephemeral=True
@ -1006,7 +1006,7 @@ class Security(commands.Cog):
) )
async def setup(bot): def setup(bot):
"""Setup du cog de sécurité""" """Setup du cog de sécurité"""
await bot.add_cog(Security(bot)) bot.add_cog(Security(bot))

View file

@ -20,6 +20,6 @@ class SentBotMessages(commands.Cog):
except Exception as e: except Exception as e:
await interaction.response.send_message(f"❌ Une erreur est survenue : {e}", ephemeral=True) await interaction.response.send_message(f"❌ Une erreur est survenue : {e}", ephemeral=True)
async def setup(bot): def setup(bot):
await bot.add_cog(SentBotMessages(bot)) bot.add_cog(SentBotMessages(bot))

View file

@ -109,5 +109,5 @@ class SnipeCommands(commands.Cog):
ephemeral=True ephemeral=True
) )
async def setup(bot): def setup(bot):
await bot.add_cog(SnipeCommands(bot)) bot.add_cog(SnipeCommands(bot))

View file

@ -68,5 +68,5 @@ class StaffLeaderboard(commands.Cog):
await interaction.followup.send("Une erreur est survenue lors de la génération du classement.", ephemeral=True) await interaction.followup.send("Une erreur est survenue lors de la génération du classement.", ephemeral=True)
async def setup(bot): def setup(bot):
await bot.add_cog(StaffLeaderboard(bot)) bot.add_cog(StaffLeaderboard(bot))

View file

@ -133,5 +133,5 @@ class StaffRatings(commands.Cog):
return buf return buf
async def setup(bot): def setup(bot):
await bot.add_cog(StaffRatings(bot)) bot.add_cog(StaffRatings(bot))

File diff suppressed because it is too large Load diff

View file

@ -490,6 +490,6 @@ class TicketAnalytics(commands.Cog):
await interaction.followup.send(embed=feedback_embed, ephemeral=True) await interaction.followup.send(embed=feedback_embed, ephemeral=True)
async def setup(bot): def setup(bot):
"""Setup function for the analytics cog""" """Setup function for the analytics cog"""
await bot.add_cog(TicketAnalytics(bot)) bot.add_cog(TicketAnalytics(bot))

View file

@ -15,11 +15,11 @@ class FeedbackView(disnake.ui.View):
self.add_item(RatingSelect()) self.add_item(RatingSelect())
@disnake.ui.button(label="📝 Laisser un commentaire", style=disnake.ButtonStyle.secondary, custom_id="feedback_comment", row=1) @disnake.ui.button(label="📝 Laisser un commentaire", style=disnake.ButtonStyle.secondary, custom_id="feedback_comment", row=1)
async def comment_button(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def comment_button(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_modal(FeedbackModal(self)) await interaction.response.send_modal(FeedbackModal(self))
@disnake.ui.button(label="✅ Envoyer", style=disnake.ButtonStyle.green, custom_id="feedback_submit", row=1) @disnake.ui.button(label="✅ Envoyer", style=disnake.ButtonStyle.green, custom_id="feedback_submit", row=1)
async def submit_button(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def submit_button(self, button: disnake.ui.Button, interaction: disnake.Interaction):
if self.rating == 0: if self.rating == 0:
await interaction.response.send_message("❌ Veuillez sélectionner une note avant d'envoyer.", ephemeral=True) await interaction.response.send_message("❌ Veuillez sélectionner une note avant d'envoyer.", ephemeral=True)
return return
@ -128,17 +128,17 @@ class RatingSelect(disnake.ui.Select):
class FeedbackModal(disnake.ui.Modal): class FeedbackModal(disnake.ui.Modal):
def __init__(self, view): def __init__(self, view):
super().__init__(title="Votre avis") super().__init__(components=[], title="Votre avis")
self.view = view self.view = view
self.comment = disnake.ui.TextInput( self.comment = disnake.ui.TextInput(
label="Commentaire", label="Commentaire",
style=disnake.TextStyle.paragraph, style=disnake.TextInputStyle.paragraph,
placeholder="Dites-nous ce que vous avez pensé du support...", placeholder="Dites-nous ce que vous avez pensé du support...",
required=True, required=True,
max_length=1000 max_length=1000
) )
self.add_item(self.comment) self.append_component(self.comment)
async def on_submit(self, interaction: disnake.Interaction): async def callback(self, interaction: disnake.Interaction):
self.view.comment = self.comment.value self.view.comment = self.comment.value
await interaction.response.send_message("Commentaire enregistré ! N'oubliez pas de valider avec 'Envoyer'.", ephemeral=True) await interaction.response.send_message("Commentaire enregistré ! N'oubliez pas de valider avec 'Envoyer'.", ephemeral=True)

View file

@ -195,7 +195,7 @@ class ContinueFormView(disnake.ui.View):
self.step2_part2_data = step2_part2_data self.step2_part2_data = step2_part2_data
@disnake.ui.button(label="📋 Continuer le formulaire", style=disnake.ButtonStyle.green, custom_id="continue_form") @disnake.ui.button(label="📋 Continuer le formulaire", style=disnake.ButtonStyle.green, custom_id="continue_form")
async def continue_form(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def continue_form(self, button: disnake.ui.Button, interaction: disnake.Interaction):
"""Passe à l'étape suivante du formulaire""" """Passe à l'étape suivante du formulaire"""
if self.current_step == 1: if self.current_step == 1:
await interaction.response.send_modal(TicketStep2Part1(self.step1_data)) await interaction.response.send_modal(TicketStep2Part1(self.step1_data))
@ -414,7 +414,7 @@ class TicketManagementView(disnake.ui.View):
return None return None
@disnake.ui.button(label="🔒 Fermer le Ticket", style=disnake.ButtonStyle.red, custom_id="close_ticket") @disnake.ui.button(label="🔒 Fermer le Ticket", style=disnake.ButtonStyle.red, custom_id="close_ticket")
async def close_ticket(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def close_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
"""Ferme le ticket en désactivant l'envoi de messages pour le membre""" """Ferme le ticket en désactivant l'envoi de messages pour le membre"""
await interaction.response.defer(ephemeral=True) await interaction.response.defer(ephemeral=True)
@ -445,7 +445,7 @@ class TicketManagementView(disnake.ui.View):
await interaction.followup.send(f"❌ Erreur lors de la fermeture : {e}", ephemeral=True) await interaction.followup.send(f"❌ Erreur lors de la fermeture : {e}", ephemeral=True)
@disnake.ui.button(label="👤 Claim le Ticket", style=disnake.ButtonStyle.blurple, custom_id="claim_ticket") @disnake.ui.button(label="👤 Claim le Ticket", style=disnake.ButtonStyle.blurple, custom_id="claim_ticket")
async def claim_ticket(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def claim_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
"""Un staff prend en charge le ticket""" """Un staff prend en charge le ticket"""
await interaction.response.defer(ephemeral=False) await interaction.response.defer(ephemeral=False)
@ -490,7 +490,7 @@ class ClosedTicketView(disnake.ui.View):
return None return None
@disnake.ui.button(label="♻ Réouvrir le Ticket", style=disnake.ButtonStyle.green, custom_id="reopen_ticket") @disnake.ui.button(label="♻ Réouvrir le Ticket", style=disnake.ButtonStyle.green, custom_id="reopen_ticket")
async def reopen_ticket(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def reopen_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
"""Réouvre le ticket pour le membre""" """Réouvre le ticket pour le membre"""
await interaction.response.defer(ephemeral=True) await interaction.response.defer(ephemeral=True)
@ -526,15 +526,15 @@ class ReopenStatusView(disnake.ui.View):
self.owner = owner self.owner = owner
@disnake.ui.button(label="Écrit (Ouvert)", style=disnake.ButtonStyle.secondary) @disnake.ui.button(label="Écrit (Ouvert)", style=disnake.ButtonStyle.secondary)
async def set_written(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def set_written(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await self.apply_status(interaction, "ouvert") await self.apply_status(interaction, "ouvert")
@disnake.ui.button(label="Oral (À faire)", style=disnake.ButtonStyle.primary) @disnake.ui.button(label="Oral (À faire)", style=disnake.ButtonStyle.primary)
async def set_oral(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def set_oral(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await self.apply_status(interaction, "oral-à-faire") await self.apply_status(interaction, "oral-à-faire")
@disnake.ui.button(label="Accepté", style=disnake.ButtonStyle.success) @disnake.ui.button(label="Accepté", style=disnake.ButtonStyle.success)
async def set_accepted(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def set_accepted(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await self.apply_status(interaction, "accepté") await self.apply_status(interaction, "accepté")
async def apply_status(self, interaction: disnake.Interaction, prefix: str): async def apply_status(self, interaction: disnake.Interaction, prefix: str):
@ -585,7 +585,7 @@ class ReopenStatusView(disnake.ui.View):
await interaction.followup.send(f"❌ Erreur système : {e}", ephemeral=True) await interaction.followup.send(f"❌ Erreur système : {e}", ephemeral=True)
@disnake.ui.button(label="❌ Supprimer le Ticket", style=disnake.ButtonStyle.danger, custom_id="delete_ticket") @disnake.ui.button(label="❌ Supprimer le Ticket", style=disnake.ButtonStyle.danger, custom_id="delete_ticket")
async def delete_ticket(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def delete_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
"""Supprime le salon du ticket""" """Supprime le salon du ticket"""
await interaction.response.defer(ephemeral=True) await interaction.response.defer(ephemeral=True)
@ -611,7 +611,7 @@ class TicketView(disnake.ui.View):
super().__init__(timeout=None) super().__init__(timeout=None)
@disnake.ui.button(label="📑 Ouvrir un Ticket Whitelist", style=disnake.ButtonStyle.red, custom_id="open_ticket") @disnake.ui.button(label="📑 Ouvrir un Ticket Whitelist", style=disnake.ButtonStyle.red, custom_id="open_ticket")
async def open_ticket(self, interaction: disnake.Interaction, button: disnake.ui.Button): async def open_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
"""Affiche le premier formulaire""" """Affiche le premier formulaire"""
await interaction.response.send_modal(TicketStep1()) await interaction.response.send_modal(TicketStep1())
@ -799,8 +799,8 @@ class Ticket(commands.Cog):
kuby_logger.error(f"Erreur lors de la validation du ticket: {e}", exc_info=True) kuby_logger.error(f"Erreur lors de la validation du ticket: {e}", exc_info=True)
await message.channel.send(f"❌ Une erreur système est survenue : {e}") await message.channel.send(f"❌ Une erreur système est survenue : {e}")
async def setup(bot): def setup(bot):
await bot.add_cog(Ticket(bot)) bot.add_cog(Ticket(bot))
bot.add_view(TicketView()) bot.add_view(TicketView())
bot.add_view(TicketManagementView()) bot.add_view(TicketManagementView())
bot.add_view(ClosedTicketView()) bot.add_view(ClosedTicketView())

View file

@ -455,6 +455,6 @@ class WebsiteSync(commands.Cog, name="Website Sync"):
# ─── Setup ─────────────────────────────────────────────────────────────────── # ─── Setup ───────────────────────────────────────────────────────────────────
async def setup(bot: commands.Bot): def setup(bot):
await bot.add_cog(WebsiteSync(bot)) bot.add_cog(WebsiteSync(bot))
logger.info("Cog WebsiteSync chargé.") logger.info("Cog WebsiteSync chargé.")

View file

@ -243,6 +243,6 @@ class Welcome(commands.Cog):
bg_used = "background_template.png" if not banner_path else (banner_path.split('/')[-1]) bg_used = "background_template.png" if not banner_path else (banner_path.split('/')[-1])
await interaction.response.send_message(f"✅ Configuration de bienvenida enregistrée !\nFond utilisé: {bg_used}", ephemeral=True) await interaction.response.send_message(f"✅ Configuration de bienvenida enregistrée !\nFond utilisé: {bg_used}", ephemeral=True)
async def setup(bot): def setup(bot):
await bot.add_cog(Welcome(bot)) bot.add_cog(Welcome(bot))

View file

@ -95,5 +95,5 @@ class Whitelist(commands.Cog):
return self._get_guild_whitelist(guild_id).copy() return self._get_guild_whitelist(guild_id).copy()
async def setup(bot): def setup(bot):
await bot.add_cog(Whitelist(bot)) bot.add_cog(Whitelist(bot))

View file

@ -293,5 +293,5 @@ class WhitelistRemovalView(View):
ephemeral=True ephemeral=True
) )
async def setup(bot): def setup(bot):
await bot.add_cog(WhitelistMonitor(bot)) bot.add_cog(WhitelistMonitor(bot))

View file

@ -1,6 +1,6 @@
[ [
{ {
"date": "2026-05-01T14:42:53.534230+00:00", "date": "2026-05-09T16:29:01.039153+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -9,7 +9,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-05-01T14:34:33.777534+00:00", "date": "2026-05-09T16:24:58.475866+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -18,7 +18,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-05-01T14:31:01.918316+00:00", "date": "2026-05-09T16:21:25.813131+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -27,7 +27,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-05-01T14:11:08.947818+00:00", "date": "2026-05-09T16:18:53.874797+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -36,7 +36,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-05-01T13:48:18.180388+00:00", "date": "2026-05-09T16:15:46.234991+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -45,7 +45,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-05-01T13:36:45.397039+00:00", "date": "2026-05-09T16:11:35.632086+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -54,7 +54,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-05-01T13:20:32.058899+00:00", "date": "2026-05-09T16:07:40.809724+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -63,7 +63,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-23T14:35:15.364216+00:00", "date": "2026-05-09T16:05:50.275892+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -72,7 +72,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-23T13:35:15.351819+00:00", "date": "2026-05-09T16:03:53.916964+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -81,7 +81,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-23T12:35:15.324906+00:00", "date": "2026-05-09T16:02:51.029940+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -90,7 +90,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-23T11:35:15.210303+00:00", "date": "2026-05-09T15:51:13.568534+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -99,7 +99,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-23T10:35:15.338465+00:00", "date": "2026-05-09T15:38:58.554617+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -108,7 +108,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-23T10:28:55.984163+00:00", "date": "2026-05-09T15:30:32.050849+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -117,7 +117,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-02T17:03:30.870748+00:00", "date": "2026-05-09T15:28:00.677254+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -126,7 +126,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-01T14:00:13.276907+00:00", "date": "2026-05-09T15:27:08.221370+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -135,7 +135,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-01T13:19:44.954622+00:00", "date": "2026-05-09T15:25:53.264798+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -144,7 +144,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-01T13:17:23.537128+00:00", "date": "2026-05-09T15:19:10.836829+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -153,7 +153,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-01T13:15:14.389369+00:00", "date": "2026-05-09T15:15:08.978927+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -162,7 +162,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-01T13:08:00.124432+00:00", "date": "2026-05-09T15:12:59.706120+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,
@ -171,7 +171,7 @@
"success": true "success": true
}, },
{ {
"date": "2026-04-01T13:03:42.601666+00:00", "date": "2026-05-09T14:59:44.423282+00:00",
"trigger": "auto", "trigger": "auto",
"serversCount": 1, "serversCount": 1,
"membersCount": 12, "membersCount": 12,

View file

@ -3,7 +3,7 @@
"guild_id": 1369669999345537145, "guild_id": 1369669999345537145,
"user_id": 971446412690722826, "user_id": 971446412690722826,
"category_id": "3b0b9bc1", "category_id": "3b0b9bc1",
"status": "open", "status": "closed",
"priority": "normal", "priority": "normal",
"created_at": "2026-01-10T15:57:24.973539", "created_at": "2026-01-10T15:57:24.973539",
"closed_at": null, "closed_at": null,

View file

@ -3,7 +3,7 @@
"guild_id": 1369669999345537145, "guild_id": 1369669999345537145,
"user_id": 971446412690722826, "user_id": 971446412690722826,
"category_id": "91522e2c", "category_id": "91522e2c",
"status": "open", "status": "closed",
"priority": "normal", "priority": "normal",
"created_at": "2026-01-16T18:43:42.737852", "created_at": "2026-01-16T18:43:42.737852",
"closed_at": null, "closed_at": null,

View file

@ -28,6 +28,7 @@ kuby_logger.info("✅ Token Discord chargé avec succès")
async def main(): async def main():
kuby_logger.info("🔄 Démarrage de la connexion Discord...") kuby_logger.info("🔄 Démarrage de la connexion Discord...")
try: try:
await bot.do_async_setup()
kuby_logger.info("🔗 Connexion établie avec Discord...") kuby_logger.info("🔗 Connexion établie avec Discord...")
await bot.start(TOKEN) await bot.start(TOKEN)
except KeyboardInterrupt: except KeyboardInterrupt: