Skip to content

Commit

Permalink
Add reminder functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
SonOfLope committed Nov 28, 2024
1 parent d8d0d3f commit b4d7385
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 5 deletions.
82 changes: 78 additions & 4 deletions cogs/admin/management.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

from discord import Embed, Color, utils, File
from discord import Embed, Color, Option, utils, File
import discord
from cogs.prompts import\
prompt_user,\
Expand All @@ -10,7 +10,8 @@
make_mention,\
generate_mention_dict
from cogs.utils.discord import\
send_delayed_dm
send_delayed_dm,\
send_reminder
from cogs.admin import is_authorized
import asyncio
import random
Expand Down Expand Up @@ -129,11 +130,12 @@ async def annonce(ctx):
await ctx.author.send('Annonce annulée.')

@trema_bot.command(name="tombola", description="Organiser un tirage au sort")
@is_authorized(trema_db)
async def tombola(ctx):
await ctx.respond("Veuillez vérifier vos messages privés pour des instructions supplémentaires.", ephemeral=True)

mention_dict = generate_mention_dict(ctx.guild)

time_and_date, delay = await prompt_user_with_date(ctx, "Quelle est la date et l'heure du tirage au sort ? (AAAA-MM-JJ HH:MM:SS)", 'Date et heure du tirage')
if not time_and_date:
return
Expand Down Expand Up @@ -223,4 +225,76 @@ async def pick_winner():
await ctx.channel.send(f"Erreur lors du tirage au sort : {e}")

asyncio.create_task(pick_winner())
await ctx.author.send('Tirage au sort organisé avec succès.')
await ctx.author.send('Tirage au sort organisé avec succès.')

@trema_bot.command(name="remindme", description="Set a reminder for a message")
@is_authorized(trema_db)
async def remindme(ctx, message_link: Option(str, "Lien du message à rappeler"), delay: Option(str, "Délai avant le rappel. Ex: '1 week', '3 hours', '4 days'")):
import re
from datetime import datetime, timezone, timedelta

def parse_delay(delay_str):
units = {
'second': 1, 'seconds': 1,
'minute': 60, 'minutes': 60,
'hour': 3600, 'hours': 3600,
'day': 86400, 'days': 86400,
'week': 604800, 'weeks': 604800
}
pattern = r'(\d+)\s*(second|seconds|minute|minutes|hour|hours|day|days|week|weeks)'
match = re.match(pattern, delay_str.lower())
if not match:
return None
amount, unit = match.groups()
return int(amount) * units[unit]

message_link_regex = r"https?://discord(?:app)?\.com/channels/(\d+)/(\d+)/(\d+)"
match = re.match(message_link_regex, message_link)
if not match:
await ctx.respond("Lien du message invalide.", ephemeral=True)
return

guild_id, channel_id, message_id = match.groups()

guild = ctx.guild
if str(guild.id) != guild_id:
await ctx.respond("Le lien du message doit être dans ce serveur.", ephemeral=True)
return

channel = guild.get_channel(int(channel_id))
if not channel:
await ctx.respond("Le canal du message n'a pas été trouvé.", ephemeral=True)
return

try:
message = await channel.fetch_message(int(message_id))
except discord.NotFound:
await ctx.respond("Message introuvable.", ephemeral=True)
return

delay_seconds = parse_delay(delay)
if delay_seconds is None:
await ctx.respond("Format de délai invalide. Utilisez par exemple '1 week', '3 hours', '4 days'.", ephemeral=True)
return

scheduled_time = datetime.now(timezone.utc) + timedelta(seconds=delay_seconds)

confirmation_message = await ctx.channel.send(
f"Rappel programmé pour [ce message]({message_link}) dans {delay}. Réagissez avec ✅ pour vous abonner."
)

await confirmation_message.add_reaction('✅')

await ctx.respond(f"Rappel programmé pour le message: {message.jump_url} dans {delay}.", ephemeral=True)

reminder_data = {
'guild_id': guild.id,
'confirmation_channel_id': ctx.channel.id,
'confirmation_message_id': confirmation_message.id,
'scheduled_time': scheduled_time.timestamp(),
'message_link': message_link,
'creator_id': ctx.author.id,
}
trema_db.add_reminder(reminder_data)

asyncio.create_task(send_reminder(reminder_data, trema_bot, trema_db))
9 changes: 8 additions & 1 deletion cogs/events.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import asyncio
from cogs.utils.discord import\
member_roles_are_default,\
send_delayed_dm
send_delayed_dm,\
send_reminder

from cogs.utils.text_format import\
make_mention,\
Expand Down Expand Up @@ -89,3 +90,9 @@ async def on_ready():
trema_db.register_server(guild)
else:
logger.info(f"Server {guild.name} (ID: {guild.id}) is already registered.")

reminders = trema_db.get_pending_reminders()

for reminder in reminders:
asyncio.create_task(send_reminder(reminder, trema_bot, trema_db))

35 changes: 35 additions & 0 deletions cogs/utils/discord.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,41 @@ async def send_delayed_dm(user, message, delay, condition=None, message_type='te
else:
await user.send(message)

async def send_reminder(reminder_data, trema_bot, trema_db):
try:
from datetime import datetime
scheduled_time = datetime.fromtimestamp(reminder_data['scheduled_time'])
now = datetime.now()
delay_seconds = (scheduled_time - now).total_seconds()
if delay_seconds > 0:
await asyncio.sleep(delay_seconds)
guild = trema_bot.get_guild(reminder_data['guild_id'])
if guild is None:
return
confirmation_channel = guild.get_channel(reminder_data['confirmation_channel_id'])
if confirmation_channel is None:
return
confirmation_message = await confirmation_channel.fetch_message(reminder_data['confirmation_message_id'])
if confirmation_message is None:
return

reaction = discord.utils.get(confirmation_message.reactions, emoji='✅')
if reaction:
users = await reaction.users().flatten()
users = [user for user in users if user.id != trema_bot.user.id]
for user in users:
try:
await user.send(f"Voici votre rappel pour le message: {reminder_data['message_link']}")
except discord.Forbidden:
pass

# send to creator of reminder
creator = await trema_bot.fetch_user(reminder_data['creator_id'])
await creator.send(f"Voici votre rappel pour le message: {reminder_data['message_link']}")
trema_db.update_reminder_status(reminder_data, 'sent')
except Exception as e:
print(f"Erreur lors de l'envoi du rappel: {e}")

def find_role_in_guild(guild, role_name):
"""
Given a guild and a role name, this function returns the role object with
Expand Down
16 changes: 16 additions & 0 deletions db/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,22 @@ def get_server_roles(self, server_id):
if server_doc is None:
return []
return server_doc.get("server_roles", [])

def get_pending_reminders(self):
reminders_collection = self._get_collection("reminders")
reminders = reminders_collection.find({"status": "pending"})
return list(reminders)

def add_reminder(self, reminder):
reminder["_id"] = self.generate_rand_id("reminders")
reminder["status"] = "pending"
self.add_document("reminders", reminder)

def update_reminder_status(self, reminder_id, status):
reminders_collection = self._get_collection("reminders")
query = {"_id": reminder_id}
update = {"$set": {"status": status}}
reminders_collection.update_one(query, update)

mongo_user = os.getenv('MONGO_USER')
mongo_password = os.getenv('MONGO_PASSWORD')
Expand Down
14 changes: 14 additions & 0 deletions db/schemas/reminders.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"type": "object",
"properties": {
"_id": {"type": "number"},
"guild_id": {"type": "number"},
"scheduled_time": {"type": "number"},
"status": {"type": "string", "enum": ["pending", "sent", "cancelled"]},
"confirmation_message_id": {"type": "number"},
"confirmation_channel_id": {"type": "number"},
"message_link": {"type": "string"},
"creator_id": {"type": "number"}
},
"required": ["_id", "guild_id", "scheduled_time", "status", "confirmation_message_id", "confirmation_channel_id", "message_link"]
}
1 change: 1 addition & 0 deletions db/schemas/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Schema(Enum):
WELCOME = "welcome"
webhooks = "webhooks"
MEMBERS = "members"
REMINDERS = "reminders"

@staticmethod
def from_str(a_string):
Expand Down

0 comments on commit b4d7385

Please sign in to comment.