diff options
| -rw-r--r-- | bot/cogs/reminders.py | 228 |
1 files changed, 73 insertions, 155 deletions
diff --git a/bot/cogs/reminders.py b/bot/cogs/reminders.py index f6ed111dc..78f1cd73b 100644 --- a/bot/cogs/reminders.py +++ b/bot/cogs/reminders.py @@ -1,8 +1,9 @@ import asyncio -import datetime import logging import random import textwrap +from datetime import datetime +from operator import itemgetter from aiohttp import ClientResponseError from dateutil.relativedelta import relativedelta @@ -13,6 +14,7 @@ from bot.constants import ( Channels, Icons, Keys, NEGATIVE_REPLIES, POSITIVE_REPLIES, Roles, URLs ) +from bot.converters import ExpirationDate from bot.pagination import LinePaginator from bot.utils.scheduling import Scheduler from bot.utils.time import humanize_delta, parse_rfc1123, wait_until @@ -28,24 +30,20 @@ class Reminders(Scheduler): def __init__(self, bot: Bot): self.bot = bot - self.headers = {"X-API-Key": Keys.site_api} super().__init__() async def on_ready(self): # Get all the current reminders for re-scheduling - response = await self.bot.http_session.get( - url=URLs.site_reminders_api, - headers=self.headers + response = await self.bot.api_client.get( + 'bot/reminders', + params={'active': 'true'} ) - response_data = await response.json() - - # Find the current time, timezone-aware. - now = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) + now = datetime.utcnow() loop = asyncio.get_event_loop() - for reminder in response_data["reminders"]: - remind_at = parse_rfc1123(reminder["remind_at"]) + for reminder in response: + remind_at = datetime.fromisoformat(reminder['expiration'][:-1]) # If the reminder is already overdue ... if remind_at < now: @@ -56,32 +54,16 @@ class Reminders(Scheduler): self.schedule_task(loop, reminder["id"], reminder) @staticmethod - async def _send_confirmation(ctx: Context, response: dict, on_success: str): + async def _send_confirmation(ctx: Context, on_success: str): """ - Send an embed confirming whether or not a change was made successfully. - - :return: A Boolean value indicating whether it failed (True) or passed (False) + Send an embed confirming the change was made successfully. """ embed = Embed() - - if not response.get("success"): - embed.colour = Colour.red() - embed.title = random.choice(NEGATIVE_REPLIES) - embed.description = response.get("error_message", "An unexpected error occurred.") - - log.warn(f"Unable to create/edit/delete a reminder. Response: {response}") - failed = True - - else: - embed.colour = Colour.green() - embed.title = random.choice(POSITIVE_REPLIES) - embed.description = on_success - - failed = False - + embed.colour = Colour.green() + embed.title = random.choice(POSITIVE_REPLIES) + embed.description = on_success await ctx.send(embed=embed) - return failed async def _scheduled_task(self, reminder: dict): """ @@ -92,7 +74,7 @@ class Reminders(Scheduler): """ reminder_id = reminder["id"] - reminder_datetime = parse_rfc1123(reminder["remind_at"]) + reminder_datetime = datetime.fromisoformat(reminder['expiration'][:-1]) # Send the reminder message once the desired duration has passed await wait_until(reminder_datetime) @@ -111,18 +93,7 @@ class Reminders(Scheduler): :param reminder_id: The ID of the reminder. """ - # The API requires a list, so let's give it one :) - json_data = { - "reminders": [ - reminder_id - ] - } - - await self.bot.http_session.delete( - url=URLs.site_reminders_api, - headers=self.headers, - json=json_data - ) + await self.bot.api_client.delete('bot/reminders/' + str(reminder_id)) # Now we can remove it from the schedule list self.cancel_task(reminder_id) @@ -147,8 +118,8 @@ class Reminders(Scheduler): :param late: How late the reminder is (if at all) """ - channel = self.bot.get_channel(int(reminder["channel_id"])) - user = self.bot.get_user(int(reminder["user_id"])) + channel = self.bot.get_channel(reminder["channel_id"]) + user = self.bot.get_user(reminder["author"]) embed = Embed() embed.colour = Colour.blurple() @@ -173,15 +144,15 @@ class Reminders(Scheduler): await self._delete_reminder(reminder["id"]) @group(name="remind", aliases=("reminder", "reminders"), invoke_without_command=True) - async def remind_group(self, ctx: Context, duration: str, *, content: str): + async def remind_group(self, ctx: Context, expiration: ExpirationDate, *, content: str): """ Commands for managing your reminders. """ - await ctx.invoke(self.new_reminder, duration=duration, content=content) + await ctx.invoke(self.new_reminder, expiration=expiration, content=content) @remind_group.command(name="new", aliases=("add", "create")) - async def new_reminder(self, ctx: Context, duration: str, *, content: str): + async def new_reminder(self, ctx: Context, expiration: ExpirationDate, *, content: str): """ Set yourself a simple reminder. """ @@ -200,13 +171,13 @@ class Reminders(Scheduler): return await ctx.send(embed=embed) # Get their current active reminders - response = await self.bot.http_session.get( - url=URLs.site_reminders_user_api.format(user_id=ctx.author.id), - headers=self.headers + active_reminders = await self.bot.api_client.get( + 'bot/reminders', + params={ + 'user__id': str(ctx.author.id) + } ) - active_reminders = await response.json() - # Let's limit this, so we don't get 10 000 # reminders from kip or something like that :P if len(active_reminders) > MAXIMUM_REMINDERS: @@ -217,45 +188,23 @@ class Reminders(Scheduler): return await ctx.send(embed=embed) # Now we can attempt to actually set the reminder. - try: - response = await self.bot.http_session.post( - url=URLs.site_reminders_api, - headers=self.headers, - json={ - "user_id": str(ctx.author.id), - "duration": duration, - "content": content, - "channel_id": str(ctx.channel.id) - } - ) - - response_data = await response.json() - - # AFAIK only happens if the user enters, like, a quintillion weeks - except ClientResponseError: - embed.colour = Colour.red() - embed.title = random.choice(NEGATIVE_REPLIES) - embed.description = ( - "An error occurred while adding your reminder to the database. " - "Did you enter a reasonable duration?" - ) - - log.warn(f"User {ctx.author} attempted to create a reminder for {duration}, but failed.") - - return await ctx.send(embed=embed) - - # Confirm to the user whether or not it worked. - failed = await self._send_confirmation( - ctx, response_data, - on_success="Your reminder has been created successfully!" + reminder = await self.bot.api_client.post( + 'bot/reminders', + json={ + 'author': ctx.author.id, + 'channel_id': ctx.message.channel.id, + 'content': content, + 'expiration': expiration.isoformat() + } ) - # If it worked, schedule the reminder. - if not failed: - loop = asyncio.get_event_loop() - reminder = response_data["reminder"] + # Confirm to the user that it worked. + await self._send_confirmation( + ctx, on_success="Your reminder has been created successfully!" + ) - self.schedule_task(loop, reminder["id"], reminder) + loop = asyncio.get_event_loop() + self.schedule_task(loop, reminder["id"], reminder) @remind_group.command(name="list") async def list_reminders(self, ctx: Context): @@ -264,31 +213,31 @@ class Reminders(Scheduler): """ # Get all the user's reminders from the database. - response = await self.bot.http_session.get( - url=URLs.site_reminders_user_api, - params={"user_id": str(ctx.author.id)}, - headers=self.headers + data = await self.bot.api_client.get( + 'bot/reminders', + params={'user__id': str(ctx.author.id)} ) - data = await response.json() - now = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) + now = datetime.utcnow() # Make a list of tuples so it can be sorted by time. - reminders = [ - (rem["content"], rem["remind_at"], rem["friendly_id"]) for rem in data["reminders"] - ] - - reminders.sort(key=lambda rem: rem[1]) + reminders = sorted( + ( + (rem['content'], rem['expiration'], rem['id']) + for rem in data + ), + key=itemgetter(1) + ) lines = [] - for index, (content, remind_at, friendly_id) in enumerate(reminders): + for content, remind_at, id_ in reminders: # Parse and humanize the time, make it pretty :D - remind_datetime = parse_rfc1123(remind_at) + remind_datetime = datetime.fromisoformat(remind_at[:-1]) time = humanize_delta(relativedelta(remind_datetime, now)) text = textwrap.dedent(f""" - **Reminder #{index}:** *expires in {time}* (ID: {friendly_id}) + **Reminder #{id_}:** *expires in {time}* (ID: {id_}) {content} """).strip() @@ -322,84 +271,53 @@ class Reminders(Scheduler): await ctx.invoke(self.bot.get_command("help"), "reminders", "edit") @edit_reminder_group.command(name="duration", aliases=("time",)) - async def edit_reminder_duration(self, ctx: Context, friendly_id: str, duration: str): + async def edit_reminder_duration(self, ctx: Context, id_: int, expiration: ExpirationDate): """ - Edit one of your reminders' duration. + Edit one of your reminders' expiration. """ # Send the request to update the reminder in the database - response = await self.bot.http_session.patch( - url=URLs.site_reminders_user_api, - headers=self.headers, - json={ - "user_id": str(ctx.author.id), - "friendly_id": friendly_id, - "duration": duration - } + reminder = await self.bot.http_session.patch( + 'bot/reminders/' + str(id_), + json={'expiration': expiration.isoformat()} ) # Send a confirmation message to the channel - response_data = await response.json() - failed = await self._send_confirmation( - ctx, response_data, - on_success="That reminder has been edited successfully!" + await self._send_confirmation( + ctx, on_success="That reminder has been edited successfully!" ) - if not failed: - await self._reschedule_reminder(response_data["reminder"]) + await self._reschedule_reminder(reminder) @edit_reminder_group.command(name="content", aliases=("reason",)) - async def edit_reminder_content(self, ctx: Context, friendly_id: str, *, content: str): + async def edit_reminder_content(self, ctx: Context, id_: int, *, content: str): """ Edit one of your reminders' content. """ # Send the request to update the reminder in the database - response = await self.bot.http_session.patch( - url=URLs.site_reminders_user_api, - headers=self.headers, - json={ - "user_id": str(ctx.author.id), - "friendly_id": friendly_id, - "content": content - } + reminder = await self.bot.http_session.patch( + 'bot/reminders/' + str(id_), + json={'content': content} ) # Send a confirmation message to the channel - response_data = await response.json() - failed = await self._send_confirmation( - ctx, response_data, - on_success="That reminder has been edited successfully!" + await self._send_confirmation( + ctx, on_success="That reminder has been edited successfully!" ) - - if not failed: - await self._reschedule_reminder(response_data["reminder"]) + await self._reschedule_reminder(reminder) @remind_group.command("delete", aliases=("remove",)) - async def delete_reminder(self, ctx: Context, friendly_id: str): + async def delete_reminder(self, ctx: Context, id_: int): """ Delete one of your active reminders. """ - # Send the request to delete the reminder from the database - response = await self.bot.http_session.delete( - url=URLs.site_reminders_user_api, - headers=self.headers, - json={ - "user_id": str(ctx.author.id), - "friendly_id": friendly_id - } - ) - - response_data = await response.json() - failed = await self._send_confirmation( - ctx, response_data, - on_success="That reminder has been deleted successfully!" + await self._delete_reminder(id_) + await self._send_confirmation( + ctx, on_success="That reminder has been deleted successfully!" ) - if not failed: - self.cancel_reminder(response_data["reminder_id"]) - def setup(bot: Bot): bot.add_cog(Reminders(bot)) |