From 9045b374fa43dd4052f812c053df4a3f597514b5 Mon Sep 17 00:00:00 2001 From: Mathis Date: Sat, 28 Mar 2026 22:17:17 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20stabilisation=20des=20boutons=20de=20ges?= =?UTF-8?q?tion=20de=20ticket=20(Fermer,=20R=C3=A9ouvrir,=20Claim)=20avec?= =?UTF-8?q?=20defer()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commandes/ticket_whitelist.py | 134 ++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 46 deletions(-) diff --git a/commandes/ticket_whitelist.py b/commandes/ticket_whitelist.py index 55f8d9b..9a3b953 100644 --- a/commandes/ticket_whitelist.py +++ b/commandes/ticket_whitelist.py @@ -313,23 +313,23 @@ class TicketStep3(discord.ui.Modal, title="📋 Développement du Personnage"): except discord.errors.NotFound: await interaction.followup.send(f"✅ Ticket ouvert : {ticket_channel.mention}", ephemeral=True) -class TicketManagementView(discord.ui.View): +class TicketManagementView(discord.ui.view.View): """Vue pour gérer le ticket avec les boutons Fermer, Réouvrir, Claim et Supprimer""" def __init__(self): super().__init__(timeout=None) - self.claimed_by = None # Stocke le staff qui claim le ticket async def get_ticket_owner(self, interaction: discord.Interaction): - """Récupère le propriétaire du ticket via le topic du salon""" - if interaction.channel.topic and interaction.channel.topic.startswith("Ticket de "): + """Récupère le propriétaire du ticket via le topic du salon (robuste)""" + if interaction.channel.topic and "Ticket de" in interaction.channel.topic: try: - owner_id = int(interaction.channel.topic.split("Ticket de ")[1]) + user_id_str = interaction.channel.topic.replace("Ticket de ", "").strip() + owner_id = int(user_id_str) member = interaction.guild.get_member(owner_id) if not member: try: member = await interaction.guild.fetch_member(owner_id) - except discord.NotFound: + except (discord.NotFound, discord.HTTPException): return None return member except (ValueError, IndexError): @@ -339,58 +339,74 @@ class TicketManagementView(discord.ui.View): @discord.ui.button(label="🔒 Fermer le Ticket", style=discord.ButtonStyle.red, custom_id="close_ticket") async def close_ticket(self, interaction: discord.Interaction, button: discord.ui.Button): """Ferme le ticket en désactivant l'envoi de messages pour le membre""" + await interaction.response.defer(ephemeral=True) + settings = load_settings(interaction.guild.id) staff_role_id = settings.get("staff_role_id") - if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator: - return await interaction.response.send_message("❌ Seuls les staffs peuvent fermer un ticket.", ephemeral=True) + is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False + if not is_staff and not interaction.user.guild_permissions.administrator: + return await interaction.followup.send("❌ Seuls les staffs peuvent fermer un ticket.", ephemeral=True) owner = await self.get_ticket_owner(interaction) if not owner: - return await interaction.response.send_message("❌ Impossible de trouver le propriétaire du ticket à fermer.", ephemeral=True) + return await interaction.followup.send("❌ Impossible de trouver le propriétaire du ticket à fermer.", ephemeral=True) - await interaction.channel.set_permissions(owner, read_messages=False, send_messages=False) - await interaction.channel.edit(name="ticket-fermé") - await interaction.response.send_message("🔒 Le ticket a été fermé. Vous ne pouvez plus le voir.", ephemeral=True) + try: + await interaction.channel.set_permissions(owner, read_messages=False, send_messages=False) + await interaction.channel.edit(name=f"fermé-{owner.display_name}".replace(" ", "-").lower()[:100]) + + # Envoi du message de fermeture dans le salon + new_view = ClosedTicketView() + await interaction.channel.send(f"🔒 Ce ticket a été fermé par {interaction.user.mention}.", view=new_view) + await interaction.followup.send("✅ Ticket fermé avec succès.", ephemeral=True) + except Exception as e: + kuby_logger.error(f"Erreur lors de la fermeture du ticket: {e}") + await interaction.followup.send(f"❌ Erreur lors de la fermeture : {e}", ephemeral=True) - # Mettre à jour la vue pour afficher uniquement les boutons Réouvrir et Supprimer - new_view = ClosedTicketView() - await interaction.channel.send("Le ticket a été fermé.", view=new_view) - - @discord.ui.button(label="👤 Prendre en charge le Ticket", style=discord.ButtonStyle.blurple, custom_id="claim_ticket") + @discord.ui.button(label="👤 Claim le Ticket", style=discord.ButtonStyle.blurple, custom_id="claim_ticket") async def claim_ticket(self, interaction: discord.Interaction, button: discord.ui.Button): """Un staff prend en charge le ticket""" + await interaction.response.defer(ephemeral=False) + settings = load_settings(interaction.guild.id) staff_role_id = settings.get("staff_role_id") - if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator: - return await interaction.response.send_message("❌ Seuls les staffs peuvent claim un ticket.", ephemeral=True) - - staff_role = discord.utils.get(interaction.guild.roles, id=int(staff_role_id)) if staff_role_id else None - - claimed_by = interaction.user - if staff_role: - await interaction.channel.set_permissions(staff_role, send_messages=False, read_messages=True) - - await interaction.channel.set_permissions(claimed_by, read_messages=True, send_messages=True) - await interaction.response.send_message(f"👤 {claimed_by.mention} a claim ce ticket.", ephemeral=False) + is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False + if not is_staff and not interaction.user.guild_permissions.administrator: + return await interaction.followup.send("❌ Seuls les staffs peuvent claim un ticket.") -class ClosedTicketView(discord.ui.View): + try: + staff_role = interaction.guild.get_role(int(staff_role_id)) if staff_role_id else None + + # Retrait des permissions du rôle staff pour forcer le claimer à parler seul + if staff_role: + await interaction.channel.set_permissions(staff_role, send_messages=False, read_messages=True) + + # Donner les permissions au claimer + await interaction.channel.set_permissions(interaction.user, read_messages=True, send_messages=True) + await interaction.followup.send(f"👥 {interaction.user.mention} a pris en charge ce ticket.") + except Exception as e: + kuby_logger.error(f"Erreur lors du claim du ticket: {e}") + await interaction.followup.send(f"❌ Erreur lors du claim : {e}") + +class ClosedTicketView(discord.ui.view.View): """Vue pour les tickets fermés avec les boutons Réouvrir et Supprimer""" def __init__(self): super().__init__(timeout=None) async def get_ticket_owner(self, interaction: discord.Interaction): - """Récupère le propriétaire du ticket via le topic du salon""" - if interaction.channel.topic and interaction.channel.topic.startswith("Ticket de "): + """Récupère le propriétaire du ticket via le topic du salon (robuste)""" + if interaction.channel.topic and "Ticket de" in interaction.channel.topic: try: - owner_id = int(interaction.channel.topic.split("Ticket de ")[1]) + user_id_str = interaction.channel.topic.replace("Ticket de ", "").strip() + owner_id = int(user_id_str) member = interaction.guild.get_member(owner_id) if not member: try: member = await interaction.guild.fetch_member(owner_id) - except discord.NotFound: + except (discord.NotFound, discord.HTTPException): return None return member except (ValueError, IndexError): @@ -400,34 +416,60 @@ class ClosedTicketView(discord.ui.View): @discord.ui.button(label="♻ Réouvrir le Ticket", style=discord.ButtonStyle.green, custom_id="reopen_ticket") async def reopen_ticket(self, interaction: discord.Interaction, button: discord.ui.Button): """Réouvre le ticket pour le membre""" + await interaction.response.defer(ephemeral=True) + settings = load_settings(interaction.guild.id) staff_role_id = settings.get("staff_role_id") - if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator: - return await interaction.response.send_message("❌ Seuls les staffs peuvent réouvrir un ticket.", ephemeral=True) + is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False + if not is_staff and not interaction.user.guild_permissions.administrator: + return await interaction.followup.send("❌ Seuls les staffs peuvent réouvrir un ticket.", ephemeral=True) owner = await self.get_ticket_owner(interaction) if not owner: - return await interaction.response.send_message("❌ Impossible de trouver le propriétaire du ticket à réouvrir.", ephemeral=True) + return await interaction.followup.send("❌ Impossible de trouver le propriétaire du ticket à réouvrir.", ephemeral=True) - await interaction.channel.set_permissions(owner, read_messages=True, send_messages=True) - await interaction.response.send_message("✅ Le ticket a été réouvert.", ephemeral=True) - - # Mettre à jour la vue pour afficher tous les boutons - new_view = TicketManagementView() - await interaction.channel.send("Le ticket a été réouvert.", view=new_view) + try: + await interaction.channel.set_permissions(owner, read_messages=True, send_messages=True) + + # Rétablir le nom original en se basant sur la validation + citoyen_role_id = settings.get("citoyen_role_id") + attente_oral_role_id = settings.get("attente_oral_role_id") + + prefix = "ouvert" + if citoyen_role_id and any(r.id == int(citoyen_role_id) for r in owner.roles): + prefix = "accepté" + elif attente_oral_role_id and any(r.id == int(attente_oral_role_id) for r in owner.roles): + prefix = "oral-à-faire" + + await interaction.channel.edit(name=f"{prefix}-{owner.display_name}".replace(" ", "-").lower()[:100]) + + new_view = TicketManagementView() + await interaction.channel.send(f"✅ Ticket réouvert par {interaction.user.mention}.", view=new_view) + await interaction.followup.send("✅ Ticket réouvert.", ephemeral=True) + except Exception as e: + kuby_logger.error(f"Erreur lors de la réouverture du ticket: {e}") + await interaction.followup.send(f"❌ Erreur lors de la réouverture : {e}", ephemeral=True) @discord.ui.button(label="❌ Supprimer le Ticket", style=discord.ButtonStyle.danger, custom_id="delete_ticket") async def delete_ticket(self, interaction: discord.Interaction, button: discord.ui.Button): """Supprime le salon du ticket""" + await interaction.response.defer(ephemeral=True) + settings = load_settings(interaction.guild.id) staff_role_id = settings.get("staff_role_id") - if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator: - return await interaction.response.send_message("❌ Seuls les staffs peuvent supprimer un ticket.", ephemeral=True) + is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False + if not is_staff and not interaction.user.guild_permissions.administrator: + return await interaction.followup.send("❌ Seuls les staffs peuvent supprimer un ticket.", ephemeral=True) - await interaction.response.send_message("❌ Suppression du ticket...", ephemeral=True) - await interaction.channel.delete() + try: + await interaction.followup.send("❌ Suppression du ticket...", ephemeral=True) + await interaction.channel.delete() + except Exception as e: + kuby_logger.error(f"Erreur lors de la suppression du ticket: {e}") + try: await interaction.followup.send(f"❌ Erreur lors de la suppression : {e}", ephemeral=True) + except: pass class TicketView(discord.ui.View): """Vue avec le bouton pour ouvrir le ticket"""