From d8b2f06f863229688b01b1f329d2a3aa15ac1bbb Mon Sep 17 00:00:00 2001 From: Mathis Date: Sat, 16 May 2026 20:02:53 +0200 Subject: [PATCH] =?UTF-8?q?Mise=20=C3=A0=20jour=20du=20syst=C3=A8me=20d'ab?= =?UTF-8?q?sence=20staff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commandes/absence_staff.py | 179 +++++++++++++++++++-------------- commandes/whitelist_monitor.py | 22 +--- data/absences.json | 12 +-- 3 files changed, 108 insertions(+), 105 deletions(-) diff --git a/commandes/absence_staff.py b/commandes/absence_staff.py index f9244f9..b3e30fe 100755 --- a/commandes/absence_staff.py +++ b/commandes/absence_staff.py @@ -152,23 +152,30 @@ class AbsenceModal(disnake.ui.Modal): now = get_paris_now() etat = "à venir" if debut > now else "en cours" - # Message dans le salon - absence_message = await channel.send( - f"# ABSENCE STAFF :\n" - f"- **Pseudo Discord** : {interaction.user.mention}\n" - f"- **Durée prévue** : {duree_str}\n" - f"- **Débute le** : {self.date_debut.value} (Paris)\n" - f"- **Termine le** : {self.date_fin.value} (Paris)\n" - f"- **Motif** : {self.motif.value}\n" - f"- **Mention du supérieur hiérarchique** : {self.superieur.mention if self.superieur else 'Aucun'}" - ) + # Message dans le salon avec V2 Components + components = [ + disnake.ui.Container( + disnake.ui.Section( + f"# ABSENCE STAFF\n**👤 Membre** : {interaction.user.mention}", + accessory=disnake.ui.Thumbnail(interaction.user.display_avatar.url) + ), + disnake.ui.Separator(), + disnake.ui.TextDisplay(f"**⏳ Durée** : {duree_str}"), + disnake.ui.TextDisplay(f"**📅 Période** : `{val_debut}` ➔ `{val_fin}`"), + disnake.ui.TextDisplay(f"**📝 Motif** : {motif}"), + disnake.ui.TextDisplay(f"**🛡️ Supérieur** : {self.superieur.mention if self.superieur else 'Aucun'}") + ) + ] + absence_message = await channel.send(components=components) # Enregistrement guild_abs[str(interaction.user.id)] = { "pseudo": interaction.user.name, - "debut": self.date_debut.value, - "fin": self.date_fin.value, - "motif": self.motif.value, + "avatar_url": interaction.user.display_avatar.url, + "debut": val_debut, + "fin": val_fin, + "duree": duree_str, + "motif": motif, "superieur": self.superieur.mention if self.superieur else "Aucun", "message_id": absence_message.id, "etat": etat @@ -190,63 +197,55 @@ class AbsenceModal(disnake.ui.Modal): await interaction.response.send_message("✅ Absence enregistrée avec succès !", ephemeral=True) class AbsenceConfigView(disnake.ui.View): - def __init__(self, guild_id: int): - super().__init__(timeout=60) + def __init__(self, guild_id: int, bot): + super().__init__(timeout=300) self.guild_id = guild_id + self.bot = bot - @disnake.ui.button(label="Définir le Salon", style=disnake.ButtonStyle.primary, emoji="📁") - 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) + @disnake.ui.channel_select(placeholder="Sélectionnez le salon d'affichage", min_values=1, max_values=1) + async def select_channel(self, select: disnake.ui.ChannelSelect, interaction: disnake.MessageInteraction): + channel = select.values[0] + settings = load_settings(self.guild_id) + settings["absence_channel_id"] = channel.id + save_settings(self.guild_id, settings) - def check(m): - return m.author == interaction.user and m.channel == interaction.channel + # Update the original message with new settings + embed = self._get_updated_embed(settings, interaction.guild) + await interaction.response.edit_message(embed=embed, view=self) + await interaction.followup.send(f"✅ Salon d'absence configuré sur {channel.mention}", ephemeral=True) - try: - msg = await interaction.bot.wait_for('message', check=check, timeout=30) - channel = None - if msg.channel_mentions: - channel = msg.channel_mentions[0] - elif msg.content.isdigit(): - channel = interaction.guild.get_channel(int(msg.content)) - - if not channel: - return await interaction.followup.send("❌ Salon invalide.", ephemeral=True) - - settings = load_settings(self.guild_id) - settings["absence_channel_id"] = channel.id - save_settings(self.guild_id, settings) - await interaction.followup.send(f"✅ Salon d'absence configuré sur {channel.mention}", ephemeral=True) - try: await msg.delete() - except: pass - except asyncio.TimeoutError: - 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, button: disnake.ui.Button, interaction: disnake.Interaction): - await interaction.response.send_message("Mentionne le rôle ici (ou envoie son ID) :", ephemeral=True) + @disnake.ui.role_select(placeholder="Sélectionnez le rôle d'absence", min_values=1, max_values=1) + async def select_role(self, select: disnake.ui.RoleSelect, interaction: disnake.MessageInteraction): + role = select.values[0] + settings = load_settings(self.guild_id) + settings["absence_role_id"] = role.id + save_settings(self.guild_id, settings) - def check(m): - return m.author == interaction.user and m.channel == interaction.channel + # Update the original message with new settings + embed = self._get_updated_embed(settings, interaction.guild) + await interaction.response.edit_message(embed=embed, view=self) + await interaction.followup.send(f"✅ Rôle d'absence configuré sur **{role.name}**", ephemeral=True) - try: - msg = await interaction.bot.wait_for('message', check=check, timeout=30) - role = None - if msg.role_mentions: - role = msg.role_mentions[0] - elif msg.content.isdigit(): - role = interaction.guild.get_role(int(msg.content)) - - if not role: - return await interaction.followup.send("❌ Rôle invalide.", ephemeral=True) - - settings = load_settings(self.guild_id) - settings["absence_role_id"] = role.id - save_settings(self.guild_id, settings) - await interaction.followup.send(f"✅ Rôle d'absence configuré sur **{role.name}**", ephemeral=True) - try: await msg.delete() - except: pass - except asyncio.TimeoutError: - await interaction.followup.send("❌ Temps écoulé.", ephemeral=True) + def _get_updated_embed(self, settings, guild): + channel_id = settings.get("absence_channel_id") + role_id = settings.get("absence_role_id") + + embed = disnake.Embed( + title="⚙️ Configuration des Absences Staff", + description="Utilisez les menus déroulants ci-dessous pour configurer le système.", + color=disnake.Color.blue() + ) + embed.add_field( + name="📁 Salon d'affichage", + value=f"<#{channel_id}>" if channel_id else "❌ Non configuré", + inline=True + ) + embed.add_field( + name="🎭 Rôle d'absence", + value=f"<@&{role_id}>" if role_id else "❌ Non configuré", + inline=True + ) + return embed class Absence(commands.Cog): def __init__(self, bot): @@ -285,29 +284,55 @@ class Absence(commands.Cog): inline=True ) - await interaction.response.send_message(embed=embed, view=AbsenceConfigView(interaction.guild.id), ephemeral=True) + await interaction.response.send_message(embed=embed, view=AbsenceConfigView(interaction.guild.id, self.bot), ephemeral=True) - async def strike_absence_message(self, guild: disnake.Guild, channel_id: int, message_id: int): + async def strike_absence_message(self, guild: disnake.Guild, channel_id: int, message_id: int, info: dict = None): """Modifie le message d'absence pour le barrer au lieu de le supprimer""" channel = guild.get_channel(channel_id) if not channel: - try: - channel = await guild.fetch_channel(channel_id) - except: - return + try: channel = await guild.fetch_channel(channel_id) + except: return try: msg = await channel.fetch_message(message_id) - content = msg.content - if "~~" in content: # Déjà barré - return + # Gestion des Rich Components V2 + if info: + avatar_url = info.get("avatar_url") + if avatar_url: + header_component = disnake.ui.Section( + f"## ~~ABSENCE STAFF [TERMINÉ]~~\n~~**👤 Membre** : {info.get('pseudo', 'Inconnu')}~~", + accessory=disnake.ui.Thumbnail(avatar_url) + ) + else: + header_component = disnake.ui.TextDisplay(f"## ~~ABSENCE STAFF [TERMINÉ]~~\n~~**👤 Membre** : {info.get('pseudo', 'Inconnu')}~~") + + components = [ + disnake.ui.Container( + header_component, + disnake.ui.Separator(), + disnake.ui.TextDisplay(f"~~**⏳ Durée** : {info.get('duree', 'N/A')}~~"), + disnake.ui.TextDisplay(f"~~**📅 Période** : {info.get('debut')} ➔ {info.get('fin')}~~"), + disnake.ui.TextDisplay(f"~~**📝 Motif** : {info.get('motif')}~~"), + disnake.ui.TextDisplay(f"~~**🛡️ Supérieur** : {info.get('superieur', 'Aucun')}~~") + ) + ] + print(f"[DEBUG] Tentative d'édition du message V2 {message_id}") + try: + await msg.edit(components=components) + print(f"[DEBUG] Succès édition V2") + except Exception as e: + print(f"[DEBUG] Erreur édition V2: {e}") + return + + # Ancien format (Texte simple) - fallback + content = msg.content + if not content or "~~" in content: return lines = content.split("\n") new_lines = [] for line in lines: if line.startswith("# "): - # Conserver le style header mais barrer le texte new_lines.append(f"# ~~{line[2:].strip()}~~ [TERMINÉ]") elif line.strip(): new_lines.append(f"~~{line}~~") @@ -335,7 +360,7 @@ class Absence(commands.Cog): channel_id = settings.get("absence_channel_id") if channel_id and message_id: - await self.strike_absence_message(interaction.guild, int(channel_id), int(message_id)) + await self.strike_absence_message(interaction.guild, int(channel_id), int(message_id), info) # Retrait du rôle role_id = settings.get("absence_role_id") @@ -470,7 +495,7 @@ class Absence(commands.Cog): message_id = info.get("message_id") channel_id = settings.get("absence_channel_id") if channel_id and message_id: - await self.strike_absence_message(guild, int(channel_id), int(message_id)) + await self.strike_absence_message(guild, int(channel_id), int(message_id), info) to_remove.append(user_id_str) changed = True @@ -507,7 +532,7 @@ class Absence(commands.Cog): settings = load_settings(message.guild.id) channel_id = settings.get("absence_channel_id") - absence_url = f"https://disnake.com/channels/{message.guild.id}/{channel_id}/{msg_id}" if channel_id and msg_id else "" + absence_url = f"https://discord.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: diff --git a/commandes/whitelist_monitor.py b/commandes/whitelist_monitor.py index fc00150..df4637e 100755 --- a/commandes/whitelist_monitor.py +++ b/commandes/whitelist_monitor.py @@ -14,18 +14,9 @@ class WhitelistMonitor(commands.Cog): self.whitelist_file = "data/whitelist.json" self.persistent_views_added = False self.big_permissions = [ - disnake.Permissions.administrator, - disnake.Permissions.manage_guild, - disnake.Permissions.manage_roles, - disnake.Permissions.manage_channels, - disnake.Permissions.kick_members, - disnake.Permissions.ban_members, - disnake.Permissions.manage_messages, - disnake.Permissions.moderate_members, - disnake.Permissions.manage_nicknames, - disnake.Permissions.manage_emojis, - disnake.Permissions.manage_webhooks, - disnake.Permissions.view_audit_log + "administrator", "manage_guild", "manage_roles", "manage_channels", + "kick_members", "ban_members", "manage_messages", "moderate_members", + "manage_nicknames", "manage_emojis", "manage_webhooks", "view_audit_log" ] def load_whitelist(self) -> Dict[str, List[str]]: @@ -72,11 +63,8 @@ class WhitelistMonitor(commands.Cog): def has_big_permissions(self, role: disnake.Role) -> bool: """Check if role has significant permissions.""" - permissions = role.permissions - for perm in self.big_permissions: - if permissions.administrator or getattr(permissions, perm.name, False): - return True - return False + perms = role.permissions + return any(getattr(perms, p, False) for p in self.big_permissions) async def send_whitelist_notification(self, member: disnake.Member, removed_roles: List[disnake.Role]): """Send DM notification to user about whitelist member losing roles.""" diff --git a/data/absences.json b/data/absences.json index 38d18ec..8550aa8 100644 --- a/data/absences.json +++ b/data/absences.json @@ -1,13 +1,3 @@ { - "1369669999345537145": { - "971446412690722826": { - "pseudo": "gameurpro12", - "debut": null, - "fin": null, - "motif": null, - "superieur": "<@353942721997832195>", - "message_id": 1505246281935618138, - "etat": "à venir" - } - } + "1369669999345537145": {} } \ No newline at end of file