221 lines
10 KiB
Python
221 lines
10 KiB
Python
|
|
import discord
|
|||
|
|
from discord import app_commands
|
|||
|
|
from discord.ext import commands, tasks
|
|||
|
|
import dateparser
|
|||
|
|
from datetime import datetime, timezone
|
|||
|
|
|
|||
|
|
ROLE_PING_ID = 1278319901651632138 # ID du rôle citoyen # Rôle pour l'annonce principale
|
|||
|
|
REMINDER_ROLE_ID = 1303750986900439151 # ID du rôle rappels sessions # Rôle pour les rappels (à adapter !)
|
|||
|
|
|
|||
|
|
presence_data = {}
|
|||
|
|
|
|||
|
|
class PresenceView(discord.ui.View):
|
|||
|
|
def __init__(self, message_id):
|
|||
|
|
super().__init__(timeout=None)
|
|||
|
|
self.message_id = message_id
|
|||
|
|
|
|||
|
|
async def update_message(self, interaction, state):
|
|||
|
|
user_id = interaction.user.id
|
|||
|
|
if self.message_id not in presence_data:
|
|||
|
|
presence_data[self.message_id] = {
|
|||
|
|
"present": set(), "absent": set(), "retard": set(),
|
|||
|
|
"date": None, "sent_dm": False,
|
|||
|
|
"reminder1": None, "reminder2": None,
|
|||
|
|
"reminder1_sent": False, "reminder2_sent": False,
|
|||
|
|
"channel_id": None, "guild_id": None
|
|||
|
|
}
|
|||
|
|
for key in ["present", "absent", "retard"]:
|
|||
|
|
presence_data[self.message_id][key].discard(user_id)
|
|||
|
|
presence_data[self.message_id][state].add(user_id)
|
|||
|
|
n_present = len(presence_data[self.message_id]["present"])
|
|||
|
|
n_absent = len(presence_data[self.message_id]["absent"])
|
|||
|
|
n_retard = len(presence_data[self.message_id]["retard"])
|
|||
|
|
msg = await interaction.channel.fetch_message(self.message_id)
|
|||
|
|
lines = msg.content.split('\n')
|
|||
|
|
# On modifie uniquement les lignes de présence
|
|||
|
|
for i, line in enumerate(lines):
|
|||
|
|
if line.startswith("> - Je serai présent"):
|
|||
|
|
lines[i] = f"> - Je serai présent : <:check:1297296859206778911> **({n_present})**"
|
|||
|
|
elif line.startswith("> - Je serai absent"):
|
|||
|
|
lines[i] = f"> - Je serai absent : <:uncheck:1297296882778902598> **({n_absent})**"
|
|||
|
|
elif line.startswith("> - Je serai en retard"):
|
|||
|
|
lines[i] = f"> - Je serai en retard : ⏰ **({n_retard})**"
|
|||
|
|
new_content = '\n'.join(lines)
|
|||
|
|
await msg.edit(content=new_content, view=self)
|
|||
|
|
|
|||
|
|
@discord.ui.button(label="Présent", style=discord.ButtonStyle.success, emoji="✅", custom_id="presence_present")
|
|||
|
|
async def present(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|||
|
|
await self.update_message(interaction, "present")
|
|||
|
|
await interaction.response.send_message("Merci, tu as été noté comme **présent** à la session RP !", ephemeral=True)
|
|||
|
|
|
|||
|
|
@discord.ui.button(label="Absent", style=discord.ButtonStyle.danger, emoji="❌", custom_id="presence_absent")
|
|||
|
|
async def absent(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|||
|
|
await self.update_message(interaction, "absent")
|
|||
|
|
await interaction.response.send_message("Merci, tu as été noté comme **absent** à la session RP.", ephemeral=True)
|
|||
|
|
|
|||
|
|
@discord.ui.button(label="En retard", style=discord.ButtonStyle.primary, emoji="⏰", custom_id="presence_retard")
|
|||
|
|
async def retard(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|||
|
|
await self.update_message(interaction, "retard")
|
|||
|
|
await interaction.response.send_message("Merci, tu as été noté comme **en retard** pour la session RP.", ephemeral=True)
|
|||
|
|
|
|||
|
|
class AnnonceSession(commands.Cog):
|
|||
|
|
def __init__(self, bot):
|
|||
|
|
self.bot = bot
|
|||
|
|
self.check_sessions.start()
|
|||
|
|
|
|||
|
|
def cog_unload(self):
|
|||
|
|
self.check_sessions.cancel()
|
|||
|
|
|
|||
|
|
@app_commands.command(
|
|||
|
|
name="annonce_session",
|
|||
|
|
description="Annonce une session RP avec image, rappels et boutons de présence."
|
|||
|
|
)
|
|||
|
|
@app_commands.describe(
|
|||
|
|
date="Date de la session (ex: Vendredi 20 Juin à 20h45)",
|
|||
|
|
reminder1="Date/heure du 1er rappel (ex: Jeudi 19 Juin à 19h)",
|
|||
|
|
reminder2="Date/heure du 2e rappel (ex: Vendredi 20 Juin à 15h)",
|
|||
|
|
image="Image à joindre (obligatoire)"
|
|||
|
|
)
|
|||
|
|
async def annonce_session(
|
|||
|
|
self,
|
|||
|
|
interaction: discord.Interaction,
|
|||
|
|
date: str,
|
|||
|
|
reminder1: str,
|
|||
|
|
reminder2: str,
|
|||
|
|
image: discord.Attachment
|
|||
|
|
):
|
|||
|
|
if not image.content_type or not image.content_type.startswith("image/"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Le fichier joint doit être une image valide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# On parse toutes les dates en Europe/Paris
|
|||
|
|
session_date = dateparser.parse(
|
|||
|
|
date, languages=['fr'],
|
|||
|
|
settings={"TIMEZONE": "Europe/Paris", "RETURN_AS_TIMEZONE_AWARE": True}
|
|||
|
|
)
|
|||
|
|
reminder1_date = dateparser.parse(
|
|||
|
|
reminder1, languages=['fr'],
|
|||
|
|
settings={"TIMEZONE": "Europe/Paris", "RETURN_AS_TIMEZONE_AWARE": True}
|
|||
|
|
)
|
|||
|
|
reminder2_date = dateparser.parse(
|
|||
|
|
reminder2, languages=['fr'],
|
|||
|
|
settings={"TIMEZONE": "Europe/Paris", "RETURN_AS_TIMEZONE_AWARE": True}
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if not session_date or not reminder1_date or not reminder2_date:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Une des dates n'a pas été comprise. Vérifie le format.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
session_date = session_date.astimezone(timezone.utc)
|
|||
|
|
reminder1_date = reminder1_date.astimezone(timezone.utc)
|
|||
|
|
reminder2_date = reminder2_date.astimezone(timezone.utc)
|
|||
|
|
|
|||
|
|
message = (
|
|||
|
|
"# <:VV:1339237574593609780> - **SESSION VICTORIA’S VICE**\n"
|
|||
|
|
"\n"
|
|||
|
|
"```📅 - HORAIRE DE LA SESSION```\n"
|
|||
|
|
f"> - Nous vous donnons rendez-vous le **{date}** pour une **session officielle** sur Victoria’s Vice. 🗓️\n"
|
|||
|
|
"---\n"
|
|||
|
|
"```🤔 - COMMENT REJOINDRE LA SESSION ?```\n"
|
|||
|
|
"> - Pour lancer la Map, veuillez entrer le code ci-dessous sur la barre de recherche de Fortnite, par la suite lancer la Map en **public** afin de pouvoir nous rejoindre.\n"
|
|||
|
|
"> - **`CODE DE LA MAP`** <:arrow:1297491509201080362> [0986-1836-1625]\n"
|
|||
|
|
"> - **`LIEN DIRECT DE LA MAP`** <:arrow:1297491509201080362> <https://play.fn.gg/island/0986-1836-1625>\n"
|
|||
|
|
"---\n"
|
|||
|
|
"```🖐 - SEREZ-VOUS PRÉSENT(E) EN SESSION ?```\n"
|
|||
|
|
"> - Je serai présent : <:check:1297296859206778911> **(0)**\n"
|
|||
|
|
"> - Je serai absent : <:uncheck:1297296882778902598> **(0)**\n"
|
|||
|
|
"> - Je serai en retard : ⏰ **(0)**\n"
|
|||
|
|
"---"
|
|||
|
|
f"> - **`PING`** : <@&{ROLE_PING_ID}>"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
content=message,
|
|||
|
|
files=[await image.to_file()]
|
|||
|
|
)
|
|||
|
|
msg = await interaction.original_response()
|
|||
|
|
presence_data[msg.id] = {
|
|||
|
|
"present": set(),
|
|||
|
|
"absent": set(),
|
|||
|
|
"retard": set(),
|
|||
|
|
"date": session_date,
|
|||
|
|
"sent_dm": False,
|
|||
|
|
"reminder1": reminder1_date,
|
|||
|
|
"reminder2": reminder2_date,
|
|||
|
|
"reminder1_sent": False,
|
|||
|
|
"reminder2_sent": False,
|
|||
|
|
"channel_id": msg.channel.id,
|
|||
|
|
"guild_id": msg.guild.id
|
|||
|
|
}
|
|||
|
|
await msg.edit(view=PresenceView(msg.id))
|
|||
|
|
|
|||
|
|
@app_commands.command(
|
|||
|
|
name="liste_presence",
|
|||
|
|
description="Liste les présences pour une session RP."
|
|||
|
|
)
|
|||
|
|
@app_commands.describe(
|
|||
|
|
message_id="ID du message d'annonce"
|
|||
|
|
)
|
|||
|
|
async def liste_presence(self, interaction: discord.Interaction, message_id: str):
|
|||
|
|
try:
|
|||
|
|
mid = int(message_id)
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message("ID de message invalide.", ephemeral=True)
|
|||
|
|
return
|
|||
|
|
if mid not in presence_data:
|
|||
|
|
await interaction.response.send_message("Aucune donnée de présence pour ce message.", ephemeral=True)
|
|||
|
|
return
|
|||
|
|
data = presence_data[mid]
|
|||
|
|
def mentions(ids):
|
|||
|
|
return ', '.join(f"<@{uid}>" for uid in ids) if ids else "Aucun"
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"**Présents ({len(data['present'])})** : {mentions(data['present'])}\n"
|
|||
|
|
f"**Absents ({len(data['absent'])})** : {mentions(data['absent'])}\n"
|
|||
|
|
f"**En retard ({len(data['retard'])})** : {mentions(data['retard'])}",
|
|||
|
|
ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
@tasks.loop(seconds=30)
|
|||
|
|
async def check_sessions(self):
|
|||
|
|
now = datetime.now(timezone.utc)
|
|||
|
|
for msg_id, data in list(presence_data.items()):
|
|||
|
|
# Premier rappel
|
|||
|
|
if data.get("reminder1") and not data.get("reminder1_sent", False) and now >= data["reminder1"]:
|
|||
|
|
await self.send_reminder(data, msg_id, "Premier rappel !")
|
|||
|
|
data["reminder1_sent"] = True
|
|||
|
|
# Deuxième rappel
|
|||
|
|
if data.get("reminder2") and not data.get("reminder2_sent", False) and now >= data["reminder2"]:
|
|||
|
|
await self.send_reminder(data, msg_id, "Deuxième rappel !")
|
|||
|
|
data["reminder2_sent"] = True
|
|||
|
|
# Envoi du MP à l'heure de la session
|
|||
|
|
if data["date"] and not data.get("sent_dm", False) and now >= data["date"]:
|
|||
|
|
for user_id in data["present"]:
|
|||
|
|
try:
|
|||
|
|
user = await self.bot.fetch_user(user_id)
|
|||
|
|
channel = self.bot.get_channel(data["channel_id"])
|
|||
|
|
if channel:
|
|||
|
|
msg = await channel.fetch_message(msg_id)
|
|||
|
|
await user.send(f"La session RP commence ! Voici le lien de l'annonce : {msg.jump_url}")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"Erreur lors de l'envoi du DM à {user_id} : {e}")
|
|||
|
|
data["sent_dm"] = True
|
|||
|
|
|
|||
|
|
async def send_reminder(self, data, msg_id, label):
|
|||
|
|
channel = self.bot.get_channel(data["channel_id"])
|
|||
|
|
if channel:
|
|||
|
|
msg = await channel.fetch_message(msg_id)
|
|||
|
|
await channel.send(
|
|||
|
|
f"<@&{REMINDER_ROLE_ID}> ⏰ **{label}**\nLa session RP approche !\nAnnonce : {msg.jump_url}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
@check_sessions.before_loop
|
|||
|
|
async def before_check_sessions(self):
|
|||
|
|
await self.bot.wait_until_ready()
|
|||
|
|
|
|||
|
|
async def setup(bot):
|
|||
|
|
await bot.add_cog(AnnonceSession(bot))
|