Initial commit: bot Discord Vicy V1.8
This commit is contained in:
commit
56958c5832
70 changed files with 8469 additions and 0 deletions
224
commandes/absence_staff.py
Normal file
224
commandes/absence_staff.py
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
from discord.ext import commands, tasks
|
||||
from discord import app_commands, ui
|
||||
import discord
|
||||
import json
|
||||
import asyncio
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
ABSENCE_CHANNEL_ID = 1369669999677145099
|
||||
ABSENCE_FILE = "absences.json"
|
||||
ABSENCE_FILE_TMP = "absences.json.tmp"
|
||||
file_lock = asyncio.Lock()
|
||||
|
||||
async def load_absences():
|
||||
async with file_lock:
|
||||
try:
|
||||
with open(ABSENCE_FILE, "r") as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
return {}
|
||||
|
||||
async def save_absences(data):
|
||||
async with file_lock:
|
||||
with open(ABSENCE_FILE_TMP, "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
os.replace(ABSENCE_FILE_TMP, ABSENCE_FILE)
|
||||
|
||||
class Absence(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.check_absences.start()
|
||||
|
||||
@commands.hybrid_command(name="absence", with_app_command=True)
|
||||
async def absence(self, ctx, motif: str, date_debut: str, date_fin: str, superieur: discord.Member = None):
|
||||
try:
|
||||
debut = datetime.strptime(date_debut, "%d/%m/%Y")
|
||||
fin = datetime.strptime(date_fin, "%d/%m/%Y")
|
||||
except ValueError:
|
||||
return await ctx.send("❌ Format de date invalide. Utilise JJ/MM/AAAA.", ephemeral=True)
|
||||
|
||||
if debut > fin:
|
||||
return await ctx.send("❌ La date de début doit précéder la date de fin.", ephemeral=True)
|
||||
|
||||
abs_data = await load_absences()
|
||||
if str(ctx.author.id) in abs_data:
|
||||
return await ctx.send("❌ Tu as déjà déclaré une absence. Utilise `/fin_absence` pour la terminer.", ephemeral=True)
|
||||
|
||||
duree = (fin - debut).days + 1
|
||||
etat = "à venir" if debut > datetime.today() else "en cours"
|
||||
|
||||
abs_data[str(ctx.author.id)] = {
|
||||
"pseudo": ctx.author.name,
|
||||
"debut": date_debut,
|
||||
"fin": date_fin,
|
||||
"motif": motif,
|
||||
"superieur": superieur.mention if superieur else "Aucun",
|
||||
"message_id": None,
|
||||
"etat": etat
|
||||
}
|
||||
await save_absences(abs_data)
|
||||
|
||||
channel = self.bot.get_channel(ABSENCE_CHANNEL_ID)
|
||||
if not channel:
|
||||
return await ctx.send("❌ Salon d'absence introuvable. Vérifie l'ID.", ephemeral=True)
|
||||
|
||||
absence_message = await channel.send(
|
||||
f"# ABSENCE STAFF :\n"
|
||||
f"- **Pseudo Discord** : {ctx.author.mention}\n"
|
||||
f"- **Durée** : {duree} jours\n"
|
||||
f"- **Débute le** : {date_debut}\n"
|
||||
f"- **Termine le** : {date_fin}\n"
|
||||
f"- **Motif** : {motif}\n"
|
||||
f"- **Mention du supérieur hiérarchique** : {superieur.mention if superieur else 'Aucun'}"
|
||||
)
|
||||
|
||||
abs_data[str(ctx.author.id)]["message_id"] = absence_message.id
|
||||
await save_absences(abs_data)
|
||||
|
||||
await ctx.send("✅ Absence enregistrée avec succès !", ephemeral=True)
|
||||
|
||||
@commands.hybrid_command(name="fin_absence", with_app_command=True)
|
||||
async def fin_absence(self, ctx):
|
||||
abs_data = await load_absences()
|
||||
user_id = str(ctx.author.id)
|
||||
|
||||
if user_id not in abs_data:
|
||||
return await ctx.send("❌ Tu n'as pas d'absence en cours.", ephemeral=True)
|
||||
|
||||
message_id = abs_data[user_id].get("message_id")
|
||||
channel = self.bot.get_channel(ABSENCE_CHANNEL_ID)
|
||||
if message_id and channel:
|
||||
try:
|
||||
msg = await channel.fetch_message(message_id)
|
||||
await msg.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
del abs_data[user_id]
|
||||
await save_absences(abs_data)
|
||||
await ctx.send("✅ Ton absence a été retirée.", ephemeral=True)
|
||||
|
||||
@commands.hybrid_command(name="liste_absences", with_app_command=True)
|
||||
async def liste_absences(self, ctx):
|
||||
abs_data = await load_absences()
|
||||
absences = [
|
||||
(user_id, info) for user_id, info in abs_data.items()
|
||||
if info.get("etat") == "en cours"
|
||||
]
|
||||
|
||||
if not absences:
|
||||
return await ctx.send("Aucune absence staff en cours.", ephemeral=True)
|
||||
|
||||
per_page = 3
|
||||
pages = [absences[i:i + per_page] for i in range(0, len(absences), per_page)]
|
||||
|
||||
def create_embed(page_index: int) -> discord.Embed:
|
||||
embed = discord.Embed(
|
||||
title=f"📋 Absences staff en cours (Page {page_index + 1}/{len(pages)})",
|
||||
color=discord.Color.orange()
|
||||
)
|
||||
for _, info in pages[page_index]:
|
||||
embed.add_field(
|
||||
name=info["pseudo"],
|
||||
value=(
|
||||
f"**Début** : {info['debut']}\n"
|
||||
f"**Fin** : {info['fin']}\n"
|
||||
f"**Motif** : {info['motif']}\n"
|
||||
f"**Supérieur** : {info['superieur']}"
|
||||
),
|
||||
inline=False
|
||||
)
|
||||
embed.set_footer(text="Gestion des absences du staff")
|
||||
return embed
|
||||
|
||||
class PaginatorView(ui.View):
|
||||
def __init__(self):
|
||||
super().__init__(timeout=60)
|
||||
self.page = 0
|
||||
|
||||
@ui.button(label="⬅️ Précédent", style=discord.ButtonStyle.secondary, disabled=True)
|
||||
async def previous(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
self.page -= 1
|
||||
await interaction.response.edit_message(embed=create_embed(self.page), view=self)
|
||||
self.update_buttons()
|
||||
|
||||
@ui.button(label="➡️ Suivant", style=discord.ButtonStyle.secondary, disabled=len(pages) == 1)
|
||||
async def next(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
self.page += 1
|
||||
await interaction.response.edit_message(embed=create_embed(self.page), view=self)
|
||||
self.update_buttons()
|
||||
|
||||
def update_buttons(self):
|
||||
self.children[0].disabled = self.page == 0
|
||||
self.children[1].disabled = self.page >= len(pages) - 1
|
||||
|
||||
view = PaginatorView()
|
||||
await ctx.send(embed=create_embed(0), view=view, ephemeral=True)
|
||||
|
||||
@tasks.loop(minutes=1)
|
||||
async def check_absences(self):
|
||||
abs_data = await load_absences()
|
||||
today = datetime.today()
|
||||
to_remove = []
|
||||
|
||||
for user_id, info in abs_data.items():
|
||||
debut = datetime.strptime(info["debut"], "%d/%m/%Y")
|
||||
fin = datetime.strptime(info["fin"], "%d/%m/%Y")
|
||||
etat = info.get("etat", "en cours")
|
||||
|
||||
if etat == "à venir" and debut <= today:
|
||||
for guild in self.bot.guilds:
|
||||
member = guild.get_member(int(user_id))
|
||||
if member:
|
||||
await self.deactivate_mentions(member)
|
||||
abs_data[user_id]["etat"] = "en cours"
|
||||
|
||||
if etat == "en cours" and fin < today:
|
||||
for guild in self.bot.guilds:
|
||||
member = guild.get_member(int(user_id))
|
||||
if member:
|
||||
await self.activate_mentions(member)
|
||||
to_remove.append(user_id)
|
||||
|
||||
for user_id in to_remove:
|
||||
abs_data.pop(user_id, None)
|
||||
|
||||
await save_absences(abs_data)
|
||||
|
||||
async def deactivate_mentions(self, member):
|
||||
role = discord.utils.get(member.guild.roles, name="Absence")
|
||||
if not role:
|
||||
role = await member.guild.create_role(name="Absence", reason="Gestion des absences staff")
|
||||
await member.add_roles(role, reason="Début d'absence staff")
|
||||
|
||||
async def activate_mentions(self, member):
|
||||
role = discord.utils.get(member.guild.roles, name="Absence")
|
||||
if role:
|
||||
await member.remove_roles(role, reason="Fin d'absence staff")
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
abs_data = await load_absences()
|
||||
absent_ids = {k for k, v in abs_data.items() if v.get("etat") == "en cours"}
|
||||
|
||||
if str(message.author.id) in absent_ids:
|
||||
await message.channel.send(
|
||||
f"{message.author.mention}, tu es actuellement déclaré absent. Merci de prévenir si tu es de retour !",
|
||||
delete_after=30
|
||||
)
|
||||
|
||||
for user_id in absent_ids:
|
||||
if f"<@{user_id}>" in message.content or f"<@!{user_id}>" in message.content:
|
||||
msg_id = abs_data[user_id].get("message_id")
|
||||
absence_url = f"https://discord.com/channels/{message.guild.id}/{ABSENCE_CHANNEL_ID}/{msg_id}" if msg_id else ""
|
||||
await message.reply(
|
||||
f"{message.author.mention}, cet utilisateur est absent. Plus d'infos : {absence_url}",
|
||||
delete_after=60
|
||||
)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Absence(bot))
|
||||
Loading…
Add table
Add a link
Reference in a new issue