Mise à jour du système d'absence staff

This commit is contained in:
Mathis 2026-05-16 20:02:53 +02:00
parent ae2347c7ce
commit d8b2f06f86
3 changed files with 108 additions and 105 deletions

View file

@ -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))
@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)
if not channel:
return await interaction.followup.send("❌ Salon invalide.", ephemeral=True)
# 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)
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)
def _get_updated_embed(self, settings, guild):
channel_id = settings.get("absence_channel_id")
role_id = settings.get("absence_role_id")
@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)
def check(m):
return m.author == interaction.user and m.channel == interaction.channel
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)
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é
# 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:

View file

@ -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."""

View file

@ -1,13 +1,3 @@
{
"1369669999345537145": {
"971446412690722826": {
"pseudo": "gameurpro12",
"debut": null,
"fin": null,
"motif": null,
"superieur": "<@353942721997832195>",
"message_id": 1505246281935618138,
"etat": "à venir"
}
}
"1369669999345537145": {}
}