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 sys
from dotenv import load_dotenv
# Charger les variables d'environnement AVANT tout le reste
@ -13,7 +14,6 @@ from src.logger import kuby_logger, log_performance
import logging
from src.advanced_logger import AdvancedLogger
import subprocess
import sys
# Récupération et validation de l'ID d'application
application_id_raw = os.getenv("APPLICATION_ID")
@ -41,9 +41,6 @@ class MyBot(commands.Bot):
application_id=application_id,
)
kuby_logger.info("MyBot instance created successfully")
async def setup_hook(self):
kuby_logger.info("🚀 Démarrage du bot Kuby...")
# Initialize advanced logger
self.advanced_logger = AdvancedLogger(self)
@ -54,8 +51,6 @@ class MyBot(commands.Bot):
try:
flask_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "serveur_flask.py")
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(
[sys.executable, flask_path],
stdout=subprocess.DEVNULL,
@ -68,6 +63,11 @@ class MyBot(commands.Bot):
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...")
# Charger les extensions
extensions = [
"commandes.whitelist",
@ -95,62 +95,43 @@ class MyBot(commands.Bot):
for extension in extensions:
try:
await self.load_extension(extension)
self.load_extension(extension)
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 (CORRIGÉ POUR ÉVITER LES ERREURS) ---
@self.check
async def whitelist_check(ctx):
# --- SYSTÈME DE WHITELIST (DÉDIÉ SLASH COMMANDS) ---
async def global_slash_whitelist_check(inter: disnake.ApplicationCommandInteraction):
try:
# 1. Bypass pour le propriétaire (Owner)
if await self.is_owner(ctx.author):
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"]:
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")
if not whitelist_cog:
kuby_logger.warning("WhitelistMonitor cog not found, allowing all commands")
return True
is_whitelisted = whitelist_cog.is_whitelisted(ctx.guild.id, ctx.author.id)
is_whitelisted = whitelist_cog.is_whitelisted(inter.guild.id, inter.author.id)
if not is_whitelisted:
kuby_logger.info(f"User {ctx.author} (ID: {ctx.author.id}) attempted to use command but is not whitelisted")
# Réponse adaptée (Slash vs Message)
kuby_logger.info(f"🚫 [Check] Accès refusé : {inter.author} sur /{command_name}")
msg = "❌ Vous n'êtes pas autorisé à utiliser cette commande. Veuillez demander à être ajouté à la whitelist."
if ctx.interaction:
await ctx.send(msg, ephemeral=True)
else:
await ctx.send(msg)
if not inter.response.is_done():
await inter.response.send_message(msg, ephemeral=True)
return False
return True
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
# Sync slash commands
try:
# Disnake handles syncing automatically by default
kuby_logger.info("✅ Commandes slash prêtes avec Disnake")
except Exception as e:
kuby_logger.error(f"❌ Erreur lors de la synchronisation des commandes slash : {e}", exc_info=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")
async def close(self):
if hasattr(self, 'flask_process') and self.flask_process:
@ -163,22 +144,12 @@ class MyBot(commands.Bot):
await super().close()
# --- É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)}")
# Log intents status
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é ! Les événements de join/leave et les DMs pourraient ne pas fonctionner correctement.")
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.warning("⚠️ L'intent MEMBERS est désactivé !")
kuby_logger.info("✅ Bot prêt et opérationnel !")
async def on_guild_join(self, guild):
@ -209,7 +180,6 @@ class MyBot(commands.Bot):
kuby_logger.info(f"👋 {member} left {member.guild.name}")
if hasattr(self, 'advanced_logger'):
self.advanced_logger.log_member_leave(member)
# Notification de départ
try:
from commandes.security import load_settings
settings = load_settings(member.guild.id)
@ -246,7 +216,7 @@ class MyBot(commands.Bot):
async def on_command_error(self, ctx, error):
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)
bot = MyBot()

View file

@ -1,6 +1,6 @@
import discord
from discord import app_commands
from discord.ext import commands
from disnake.ext import commands
import json
import os
@ -38,7 +38,7 @@ class Blacklist(commands.Cog):
# ---------- Slash Commands ----------
@app_commands.command(name="blacklist", description="Blacklist un utilisateur")
@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):
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.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):
return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True)
@ -81,13 +81,13 @@ class Blacklist(commands.Cog):
pass
# --------- Boutons ----------
class TicketButton(discord.ui.View):
class TicketButton(disnake.ui.View):
def __init__(self, user_id: int):
super().__init__(timeout=None)
self.user_id = user_id
@discord.ui.button(label="📩 Ouvrir une demande de déblacklist", style=discord.ButtonStyle.danger)
async def open_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
@disnake.ui.button(label="📩 Ouvrir une demande de déblacklist", style=disnake.ButtonStyle.danger)
async def open_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
if interaction.user.id != self.user_id:
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)
class CloseTicketView(discord.ui.View):
class CloseTicketView(disnake.ui.View):
def __init__(self, user_id: int):
super().__init__(timeout=None)
self.user_id = user_id
@discord.ui.button(label="❌ Fermer le ticket", style=discord.ButtonStyle.danger)
async def close_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
@disnake.ui.button(label="❌ Fermer le ticket", style=disnake.ButtonStyle.danger)
async def close_ticket(self, button: disnake.ui.Button, interaction: disnake.Interaction):
agents = load_json(AGENTS_FILE, {"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)
@ -124,13 +124,13 @@ class CloseTicketView(discord.ui.View):
view = ConfirmCloseView(self.user_id)
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):
super().__init__(timeout=30)
self.user_id = user_id
@discord.ui.button(label="✅ Oui", style=discord.ButtonStyle.success)
async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button):
@disnake.ui.button(label="✅ Oui", style=disnake.ButtonStyle.success)
async def confirm(self, button: disnake.ui.Button, interaction: disnake.Interaction):
agents = load_json(AGENTS_FILE, {"agents": []})
if str(interaction.user.id) not in agents["agents"]:
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.delete()
@discord.ui.button(label="❌ Non", style=discord.ButtonStyle.secondary)
async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
@disnake.ui.button(label="❌ Non", style=disnake.ButtonStyle.secondary)
async def cancel(self, button: disnake.ui.Button, interaction: disnake.Interaction):
await interaction.response.send_message("❌ Fermeture annulée.", ephemeral=True)
# --------- Setup Cog ----------
async def setup(bot: commands.Bot):
def setup(bot: commands.Bot):
cog = Blacklist(bot)
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):
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
motif = disnake.ui.TextInput(
label="Motif de l'absence",
style=disnake.TextStyle.paragraph,
style=disnake.TextInputStyle.paragraph,
placeholder="Ex: Vacances, Raisons personnelles, Travail...",
required=True,
max_length=500
@ -187,7 +187,7 @@ class AbsenceConfigView(disnake.ui.View):
self.guild_id = guild_id
@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)
def check(m):
@ -214,7 +214,7 @@ class AbsenceConfigView(disnake.ui.View):
await interaction.followup.send("❌ Temps écoulé.", ephemeral=True)
@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)
def check(m):
@ -499,7 +499,7 @@ class Absence(commands.Cog):
settings = load_settings(message.guild.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."
if absence_url:
@ -507,5 +507,5 @@ class Absence(commands.Cog):
await message.reply(reply_text, delete_after=30)
async def setup(bot):
await bot.add_cog(Absence(bot))
def setup(bot):
bot.add_cog(Absence(bot))

View file

@ -268,5 +268,5 @@ class Backup(commands.Cog):
await interaction.followup.send(embed=embed,ephemeral=True)
async def setup(bot: commands.Bot):
await bot.add_cog(Backup(bot))
def setup(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):
return await self.element_autocomplete(interaction, current)
async def setup(bot: commands.Bot):
await bot.add_cog(BackupRestore(bot))
def setup(bot):
bot.add_cog(BackupRestore(bot))

View file

@ -200,7 +200,7 @@ class TicketButton(disnake.ui.View):
self.user_id = user_id
@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:
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
@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):
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
@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):
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)
@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)
# --------- Setup ---------
async def setup(bot: commands.Bot):
await bot.add_cog(Blacklist(bot))
def setup(bot):
bot.add_cog(Blacklist(bot))

View file

@ -34,7 +34,7 @@ def save_report(issue_iid, user_id):
class BugReportModal(disnake.ui.Modal):
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
bug_title = disnake.ui.TextInput(
@ -46,7 +46,7 @@ class BugReportModal(disnake.ui.Modal):
description = disnake.ui.TextInput(
label="Description détaillée",
style=disnake.TextStyle.paragraph,
style=disnake.TextInputStyle.paragraph,
placeholder="Que s'est-il passé ? Comment reproduire le bug ?",
required=True,
max_length=1000
@ -77,7 +77,7 @@ class BugReportModal(disnake.ui.Modal):
class FeatureSuggestionModal(disnake.ui.Modal):
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(
label="Titre de la suggestion",
@ -88,7 +88,7 @@ class FeatureSuggestionModal(disnake.ui.Modal):
description = disnake.ui.TextInput(
label="Détails de la fonctionnalité",
style=disnake.TextStyle.paragraph,
style=disnake.TextInputStyle.paragraph,
placeholder="Décrivez comment cela devrait fonctionner...",
required=True,
max_length=1000
@ -334,5 +334,5 @@ class BugReport(commands.Cog):
async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction):
await interaction.response.send_modal(FeatureSuggestionModal())
async def setup(bot):
await bot.add_cog(BugReport(bot))
def setup(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)
async def setup(bot):
await bot.add_cog(Convocation(bot))
def setup(bot):
bot.add_cog(Convocation(bot))

View file

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

View file

@ -7,7 +7,7 @@ import re
class ModReasonModal(disnake.ui.Modal):
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.action_type = action_type
@ -17,7 +17,7 @@ class ModReasonModal(disnake.ui.Modal):
required=True,
max_length=500
)
self.add_item(self.reason)
self.append_component(self.reason)
if action_type == "TIMEOUT":
self.duration = disnake.ui.TextInput(
@ -26,7 +26,7 @@ class ModReasonModal(disnake.ui.Modal):
required=True,
max_length=10
)
self.add_item(self.duration)
self.append_component(self.duration)
async def callback(self, interaction: disnake.Interaction):
reason = self.reason.value
@ -78,43 +78,43 @@ class ModPanelView(disnake.ui.View):
await interaction.edit_original_response(embed=embed, view=self)
@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"))
@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"))
@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"))
@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"))
@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")
await cog.history(interaction, self.member)
@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")
await cog.clearwarns(interaction, self.member, reason="Nettoyage via Panel")
await self.update_panel(interaction)
class ModConfigModal(disnake.ui.Modal):
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.input = disnake.ui.TextInput(
label=field_name,
default=str(current_value),
value=str(current_value),
placeholder="Entrez une valeur numérique...",
required=True
)
self.add_item(self.input)
self.append_component(self.input)
async def callback(self, interaction: disnake.Interaction):
value = self.input.value
@ -146,7 +146,7 @@ class ModConfigView(disnake.ui.View):
self.db_path = db_path
@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()
select = disnake.ui.ChannelSelect(
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)
@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)
cursor = conn.cursor()
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)
@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)
cursor = conn.cursor()
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)
else: await interaction.followup.send(f"✅ Warns de {member.name} effacés.", ephemeral=True)
async def setup(bot):
await bot.add_cog(Moderation(bot))
def setup(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)
await channel.send(embed=embed)
async def setup(bot):
await bot.add_cog(AntiRaid(bot))
def setup(bot):
bot.add_cog(AntiRaid(bot))

View file

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

View file

@ -58,5 +58,5 @@ class LogsManager(commands.Cog):
)
await log_chan.send(embed=embed)
async def setup(bot):
await bot.add_cog(LogsManager(bot))
def setup(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) ---
class RulesTitleModal(disnake.ui.Modal, title="📜 Titre du Règlement"):
class RulesTitleModal(disnake.ui.Modal):
"""Modal pour configurer le titre du règlement"""
title_input = disnake.ui.TextInput(
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):
super().__init__()
super().__init__(title="📜 Titre du Règlement", components=[self.title_input])
self.guild_id = guild_id
self.settings = settings
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
save_settings(self.guild_id, self.settings)
@ -77,24 +77,24 @@ class RulesTitleModal(disnake.ui.Modal, title="📜 Titre du Règlement"):
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"""
content_input = disnake.ui.TextInput(
label="Contenu du règlement",
placeholder="Entrez les règles de votre serveur...",
style=disnake.TextStyle.paragraph,
style=disnake.TextInputStyle.paragraph,
min_length=10,
max_length=4000,
required=True
)
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.settings = settings
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
save_settings(self.guild_id, self.settings)
@ -117,7 +117,7 @@ class RulesContentModal(disnake.ui.Modal, title="📝 Contenu du Règlement"):
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"""
channel_input = disnake.ui.TextInput(
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):
super().__init__()
super().__init__(title="📌 Salon du Règlement", components=[self.channel_input])
self.guild_id = guild_id
self.settings = settings
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():
return await interaction.response.send_message(
"❌ Erreur : ID invalide.",
@ -171,7 +171,7 @@ class RulesChannelModal(disnake.ui.Modal, title="📌 Salon du Règlement"):
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"""
role_input = disnake.ui.TextInput(
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):
super().__init__()
super().__init__(title="✅ Rôle d'Acceptation", components=[self.role_input])
self.guild_id = guild_id
self.settings = settings
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():
return await interaction.response.send_message(
"❌ Erreur : ID invalide.",
@ -225,7 +225,7 @@ class RulesRoleModal(disnake.ui.Modal, title="✅ Rôle d'Acceptation"):
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"""
message_type = disnake.ui.TextInput(
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):
super().__init__()
super().__init__(title="📝 Type de Message", components=[self.message_type])
self.guild_id = guild_id
self.settings = settings
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()
if msg_type not in ["embed", "simple"]:
@ -323,13 +323,13 @@ class RulesAcceptButton(disnake.ui.View):
self.guild_id = guild_id
self.accept_role_id = accept_role_id
@discord.ui.button(
@disnake.ui.button(
label="J'accepte le règlement",
emoji="",
style=disnake.ButtonStyle.green,
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"""
guild = interaction.guild
@ -495,8 +495,8 @@ class RulesCog(commands.Cog):
return title, content
async def setup(bot):
def setup(bot):
"""Setup du cog de règlement"""
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}")
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(NoLink(bot))
def setup(bot: commands.Bot) -> None:
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']}`")
async def setup(bot: commands.Bot):
await bot.add_cog(Scan(bot))
def setup(bot):
bot.add_cog(Scan(bot))

View file

@ -69,7 +69,7 @@ def is_immune(guild, user) -> bool:
# --- MODALS DE CONFIGURATION ---
class SpamThresholdModal(disnake.ui.Modal, title="🛡️ Seuil Anti-Spam"):
class SpamThresholdModal(disnake.ui.Modal):
"""Modal pour configurer le seuil anti-spam"""
threshold_input = disnake.ui.TextInput(
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'):
super().__init__()
super().__init__(title="🛡️ Seuil Anti-Spam", components=[self.threshold_input])
self.guild_id = guild_id
self.settings = settings
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():
return await interaction.response.send_message(
"❌ Erreur : Veuillez entrer un nombre entier.",
@ -110,7 +110,7 @@ class SpamThresholdModal(disnake.ui.Modal, title="🛡️ Seuil Anti-Spam"):
ephemeral=True
)
class RaidThresholdModal(disnake.ui.Modal, title="⚔️ Seuil Anti-Raid"):
class RaidThresholdModal(disnake.ui.Modal):
"""Modal pour configurer le seuil anti-raid"""
threshold_input = disnake.ui.TextInput(
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'):
super().__init__()
super().__init__(title="⚔️ Seuil Anti-Raid", components=[self.threshold_input])
self.guild_id = guild_id
self.settings = settings
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():
return await interaction.response.send_message(
"❌ Erreur : Veuillez entrer un nombre entier.",
@ -153,7 +153,7 @@ class RaidThresholdModal(disnake.ui.Modal, title="⚔️ Seuil Anti-Raid"):
# --- 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"""
user_input = disnake.ui.TextInput(
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'):
super().__init__()
super().__init__(title="👤 Ajouter à la Whitelist", components=[self.user_input])
self.guild_id = guild_id
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():
return await interaction.response.send_message(
"❌ Erreur : ID invalide.",
@ -873,7 +873,7 @@ class MainCategorySelect(disnake.ui.Select):
class WhitelistSelect(disnake.ui.Select):
"""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.parent_view = view
whitelist = load_whitelist(guild.id)
@ -950,11 +950,11 @@ class Security(commands.Cog):
def __init__(self, bot):
self.bot = bot
@app_commands.command(
@commands.slash_command(
name="security",
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é.
Accessible uniquement aux administrateurs et propriétaires whitelistés.
@ -989,12 +989,12 @@ class Security(commands.Cog):
)
@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"""
# 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
if isinstance(error, app_commands.MissingPermissions):
if isinstance(error, commands.MissingPermissions):
await send_method(
"❌ Permissions insuffisantes.",
ephemeral=True
@ -1006,7 +1006,7 @@ class Security(commands.Cog):
)
async def setup(bot):
def setup(bot):
"""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:
await interaction.response.send_message(f"❌ Une erreur est survenue : {e}", ephemeral=True)
async def setup(bot):
await bot.add_cog(SentBotMessages(bot))
def setup(bot):
bot.add_cog(SentBotMessages(bot))

View file

@ -109,5 +109,5 @@ class SnipeCommands(commands.Cog):
ephemeral=True
)
async def setup(bot):
await bot.add_cog(SnipeCommands(bot))
def setup(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)
async def setup(bot):
await bot.add_cog(StaffLeaderboard(bot))
def setup(bot):
bot.add_cog(StaffLeaderboard(bot))

View file

@ -133,5 +133,5 @@ class StaffRatings(commands.Cog):
return buf
async def setup(bot):
await bot.add_cog(StaffRatings(bot))
def setup(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)
async def setup(bot):
def setup(bot):
"""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())
@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))
@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:
await interaction.response.send_message("❌ Veuillez sélectionner une note avant d'envoyer.", ephemeral=True)
return
@ -128,17 +128,17 @@ class RatingSelect(disnake.ui.Select):
class FeedbackModal(disnake.ui.Modal):
def __init__(self, view):
super().__init__(title="Votre avis")
super().__init__(components=[], title="Votre avis")
self.view = view
self.comment = disnake.ui.TextInput(
label="Commentaire",
style=disnake.TextStyle.paragraph,
style=disnake.TextInputStyle.paragraph,
placeholder="Dites-nous ce que vous avez pensé du support...",
required=True,
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
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
@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"""
if self.current_step == 1:
await interaction.response.send_modal(TicketStep2Part1(self.step1_data))
@ -414,7 +414,7 @@ class TicketManagementView(disnake.ui.View):
return None
@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"""
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)
@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"""
await interaction.response.defer(ephemeral=False)
@ -490,7 +490,7 @@ class ClosedTicketView(disnake.ui.View):
return None
@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"""
await interaction.response.defer(ephemeral=True)
@ -526,15 +526,15 @@ class ReopenStatusView(disnake.ui.View):
self.owner = owner
@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")
@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")
@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é")
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)
@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"""
await interaction.response.defer(ephemeral=True)
@ -611,7 +611,7 @@ class TicketView(disnake.ui.View):
super().__init__(timeout=None)
@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"""
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)
await message.channel.send(f"❌ Une erreur système est survenue : {e}")
async def setup(bot):
await bot.add_cog(Ticket(bot))
def setup(bot):
bot.add_cog(Ticket(bot))
bot.add_view(TicketView())
bot.add_view(TicketManagementView())
bot.add_view(ClosedTicketView())

View file

@ -455,6 +455,6 @@ class WebsiteSync(commands.Cog, name="Website Sync"):
# ─── Setup ───────────────────────────────────────────────────────────────────
async def setup(bot: commands.Bot):
await bot.add_cog(WebsiteSync(bot))
def setup(bot):
bot.add_cog(WebsiteSync(bot))
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])
await interaction.response.send_message(f"✅ Configuration de bienvenida enregistrée !\nFond utilisé: {bg_used}", ephemeral=True)
async def setup(bot):
await bot.add_cog(Welcome(bot))
def setup(bot):
bot.add_cog(Welcome(bot))

View file

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

View file

@ -293,5 +293,5 @@ class WhitelistRemovalView(View):
ephemeral=True
)
async def setup(bot):
await bot.add_cog(WhitelistMonitor(bot))
def setup(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",
"serversCount": 1,
"membersCount": 12,
@ -9,7 +9,7 @@
"success": true
},
{
"date": "2026-05-01T14:34:33.777534+00:00",
"date": "2026-05-09T16:24:58.475866+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -18,7 +18,7 @@
"success": true
},
{
"date": "2026-05-01T14:31:01.918316+00:00",
"date": "2026-05-09T16:21:25.813131+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -27,7 +27,7 @@
"success": true
},
{
"date": "2026-05-01T14:11:08.947818+00:00",
"date": "2026-05-09T16:18:53.874797+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -36,7 +36,7 @@
"success": true
},
{
"date": "2026-05-01T13:48:18.180388+00:00",
"date": "2026-05-09T16:15:46.234991+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -45,7 +45,7 @@
"success": true
},
{
"date": "2026-05-01T13:36:45.397039+00:00",
"date": "2026-05-09T16:11:35.632086+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -54,7 +54,7 @@
"success": true
},
{
"date": "2026-05-01T13:20:32.058899+00:00",
"date": "2026-05-09T16:07:40.809724+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -63,7 +63,7 @@
"success": true
},
{
"date": "2026-04-23T14:35:15.364216+00:00",
"date": "2026-05-09T16:05:50.275892+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -72,7 +72,7 @@
"success": true
},
{
"date": "2026-04-23T13:35:15.351819+00:00",
"date": "2026-05-09T16:03:53.916964+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -81,7 +81,7 @@
"success": true
},
{
"date": "2026-04-23T12:35:15.324906+00:00",
"date": "2026-05-09T16:02:51.029940+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -90,7 +90,7 @@
"success": true
},
{
"date": "2026-04-23T11:35:15.210303+00:00",
"date": "2026-05-09T15:51:13.568534+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -99,7 +99,7 @@
"success": true
},
{
"date": "2026-04-23T10:35:15.338465+00:00",
"date": "2026-05-09T15:38:58.554617+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -108,7 +108,7 @@
"success": true
},
{
"date": "2026-04-23T10:28:55.984163+00:00",
"date": "2026-05-09T15:30:32.050849+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -117,7 +117,7 @@
"success": true
},
{
"date": "2026-04-02T17:03:30.870748+00:00",
"date": "2026-05-09T15:28:00.677254+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -126,7 +126,7 @@
"success": true
},
{
"date": "2026-04-01T14:00:13.276907+00:00",
"date": "2026-05-09T15:27:08.221370+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -135,7 +135,7 @@
"success": true
},
{
"date": "2026-04-01T13:19:44.954622+00:00",
"date": "2026-05-09T15:25:53.264798+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -144,7 +144,7 @@
"success": true
},
{
"date": "2026-04-01T13:17:23.537128+00:00",
"date": "2026-05-09T15:19:10.836829+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -153,7 +153,7 @@
"success": true
},
{
"date": "2026-04-01T13:15:14.389369+00:00",
"date": "2026-05-09T15:15:08.978927+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -162,7 +162,7 @@
"success": true
},
{
"date": "2026-04-01T13:08:00.124432+00:00",
"date": "2026-05-09T15:12:59.706120+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,
@ -171,7 +171,7 @@
"success": true
},
{
"date": "2026-04-01T13:03:42.601666+00:00",
"date": "2026-05-09T14:59:44.423282+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 12,

View file

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

View file

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

View file

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