From 4d1af71165b62d6e85156e8adc600ce31fe0b25d Mon Sep 17 00:00:00 2001 From: Alexander Terry Date: Tue, 25 Jun 2024 18:45:20 -0800 Subject: [PATCH] add auto react option to reminders --- ...a55af340_add_auto_reaction_to_reminders.py | 39 +++++++++++++++++++ alexBot/cogs/reminders.py | 20 ++++++---- alexBot/database.py | 1 + 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 alembic/versions/c4f9a55af340_add_auto_reaction_to_reminders.py diff --git a/alembic/versions/c4f9a55af340_add_auto_reaction_to_reminders.py b/alembic/versions/c4f9a55af340_add_auto_reaction_to_reminders.py new file mode 100644 index 0000000..be22b1a --- /dev/null +++ b/alembic/versions/c4f9a55af340_add_auto_reaction_to_reminders.py @@ -0,0 +1,39 @@ +"""add auto reaction to reminders + +Revision ID: c4f9a55af340 +Revises: 5bee6f5c272e +Create Date: 2024-06-25 17:19:59.919372 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'c4f9a55af340' +down_revision: Union[str, None] = '5bee6f5c272e' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + 'reminders', + sa.Column( + 'auto_react', + sa.Boolean(), + nullable=False, + server_default=sa.text('false'), + ), + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('reminders', 'auto_react') + # ### end Alembic commands ### diff --git a/alexBot/cogs/reminders.py b/alexBot/cogs/reminders.py index 6cef80e..ed6dd3f 100644 --- a/alexBot/cogs/reminders.py +++ b/alexBot/cogs/reminders.py @@ -51,7 +51,7 @@ async def cog_unload(self) -> None: async def reminder_loop(self): while True: async with db.async_session() as session: - time_soon = datetime.datetime.utcnow() + datetime.timedelta(minutes=2) + time_soon = datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=2) stmt = select(Reminder).where( and_(Reminder.next_remind <= time_soon, Reminder.id.not_in(self.tasks.keys())) ) @@ -64,7 +64,7 @@ async def reminder_loop(self): async def remind(self, reminder: Reminder): try: # wait for the reminder time - now = datetime.datetime.utcnow() + now = datetime.datetime.now(datetime.UTC) if now > reminder.next_remind: log.warning(f"reminder {reminder} is overdue") if reminder.frequency: @@ -127,7 +127,8 @@ async def remind(self, reminder: Reminder): if reminder.require_clearing: v = ClearReminderView() dis_message = await target.send(message, view=v, allowed_mentions=allowedMentions) - + if reminder.auto_react: + await dis_message.add_reaction("<:greentick:1255344157761867816>") while v.waiting and v.times < 8: # 8 * 5 minutes = 40 minutes msg = None try: @@ -147,7 +148,9 @@ async def remind(self, reminder: Reminder): await dis_message.reply("reminder!") else: - await target.send(message, allowed_mentions=allowedMentions) + msg = await target.send(message, allowed_mentions=allowedMentions) + if reminder.auto_react: + await msg.add_reaction("<:greentick:1255344157761867816>") if reminder.frequency: # reschedule the reminder for later @@ -185,6 +188,7 @@ async def remind(self, reminder: Reminder): time="when to schedule the reminder, from now in the format xhym", require_clearing="if the reminder requires clearing to stop. you can not use this in a guild unless you have the manage guild permission", frequency="how often to repeat the reminder, in the format xhym. you can not use this in a guild unless you have the manage guild permission", + auto_react="if the reminder should auto react with a checkmark", ) async def add_reminder( self, @@ -193,6 +197,7 @@ async def add_reminder( time: str, require_clearing: bool = False, frequency: Optional[str] = None, + auto_react: bool = False, ): # check limits / validate input if interaction.guild and not interaction.user.guild_permissions.manage_guild: @@ -214,7 +219,7 @@ async def add_reminder( try: td = resolve_duration(time) assert td.total_seconds() >= 120 - next_remind = datetime.datetime.utcnow() + td + next_remind = datetime.datetime.now(datetime.UTC) + td except KeyError: return await interaction.response.send_message("Invalid time format", ephemeral=True) except AssertionError: @@ -241,6 +246,7 @@ async def add_reminder( next_remind=next_remind.replace(microsecond=0, second=0), frequency=freq, require_clearing=require_clearing, + auto_react=auto_react, ) session.add(reminder) await session.commit() @@ -279,12 +285,12 @@ async def autocomplete_time(self, interaction: discord.Interaction, time: str): # validate the time field and return the time, if we have the user's timezone, otherwise UTC time try: td = resolve_duration(time) - dt = datetime.datetime.utcnow() + td + dt = datetime.datetime.now(datetime.UTC) + td except KeyError: return [discord.app_commands.Choice(name="Invalid time format", value="Invalid time format")] return [ discord.app_commands.Choice( - name=f"reminder at {dt.replace(tzinfo=None).replace(microsecond=0)}", value=time + name=f"reminder at {dt.replace(tzinfo=None).replace(microsecond=0)} UTC", value=time ) ] diff --git a/alexBot/database.py b/alexBot/database.py index df0c42f..fbcdf7a 100644 --- a/alexBot/database.py +++ b/alexBot/database.py @@ -56,6 +56,7 @@ class Reminder(Base): next_remind: Mapped[datetime.datetime] = mapped_column(DateTime(), nullable=False) frequency: Mapped[Optional[datetime.timedelta]] = mapped_column(Interval(), nullable=True) require_clearing: Mapped[bool] = mapped_column(Boolean(), default=False) + auto_react: Mapped[bool] = mapped_column(Boolean(), default=False) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default_factory=uuid.uuid4) @time_cache(300)