From bcc9b30f4d577125f3d36b0da8600663a468ecea Mon Sep 17 00:00:00 2001 From: Tulir Asokan <tulir@maunium.net> Date: Wed, 25 Mar 2020 21:26:51 +0200 Subject: [PATCH] Add command to reschedule reminders. Fixes #2 --- reminder/bot.py | 49 +++++++++++++++++++++++++++++++++++++++++------- reminder/util.py | 3 ++- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/reminder/bot.py b/reminder/bot.py index bc6d1ee..f9d9f25 100644 --- a/reminder/bot.py +++ b/reminder/bot.py @@ -21,7 +21,7 @@ import asyncio import pytz from mautrix.types import (EventType, RedactionEvent, StateEvent, Format, MessageType, - TextMessageEventContent, ReactionEvent) + TextMessageEventContent, ReactionEvent, UserID) from mautrix.util.config import BaseProxyConfig from maubot import Plugin, MessageEvent from maubot.handlers import command, event @@ -97,6 +97,12 @@ class ReminderBot(Plugin): content = TextMessageEventContent( msgtype=MessageType.TEXT, body=f"{users}: {reminder.message}", format=Format.HTML, formatted_body=f"{users_html}: {escape(reminder.message)}") + content["xyz.maubot.reminder"] = { + "id": reminder.id, + "message": reminder.message, + "targets": list(reminder.users), + "reply_to": reminder.reply_to, + } if reminder.reply_to: content.set_reply(await self.client.get_event(reminder.room_id, reminder.reply_to)) await self.client.send_message(reminder.room_id, content) @@ -114,7 +120,33 @@ class ReminderBot(Plugin): return rem = ReminderInfo(date=date, room_id=evt.room_id, message=message, reply_to=evt.content.get_reply_to(), users={evt.sender: evt.event_id}) - if date == now: + await self._remind(evt, rem, now) + + @remind.subcommand("reschedule", help="Reschedule a reminder you got", aliases=("again",)) + @DateArgument("date", required=True) + async def reschedule(self, evt: MessageEvent, date: datetime) -> None: + reply_to_id = evt.content.get_reply_to() + if not reply_to_id: + await evt.reply("You must reply to a reminder event to reschedule it.") + return + date = date.replace(microsecond=0) + now = datetime.now(tz=pytz.UTC).replace(microsecond=0) + if date < now: + await evt.reply(f"Sorry, {date} is in the past and I don't have a time machine :(") + return + reply_to = await self.client.get_event(evt.room_id, reply_to_id) + try: + reminder_info = reply_to.content["xyz.maubot.reminder"] + rem = ReminderInfo(date=date, room_id=evt.room_id, message=reminder_info["message"], + reply_to=reminder_info["reply_to"], users={evt.sender: evt.event_id}) + except KeyError: + await evt.reply("That doesn't look like a valid reminder event.") + return + await self._remind(evt, rem, now, again=True) + + async def _remind(self, evt: MessageEvent, rem: ReminderInfo, now: datetime, again: bool = False + ) -> None: + if rem.date == now: await self.send_reminder(rem) return remind_type = "remind you " @@ -129,12 +161,14 @@ class ReminderBot(Plugin): else: remind_type = "ping you" rem.message = "ping" - msg = (f"I'll {remind_type} {self.format_time(evt, rem)}.\n\n" + if again: + remind_type += " again" + msg = (f"I'll {remind_type} {self.format_time(evt.sender, rem)}.\n\n" f"(others can \U0001F44D this message to get pinged too)") rem.event_id = await evt.reply(msg) self.db.insert(rem) now = datetime.now(tz=pytz.UTC) - if (date - now).total_seconds() < 60 and now.minute == date.minute: + if (rem.date - now).total_seconds() < 60 and now.minute == rem.date.minute: self.log.debug(f"Reminder {rem} is in less than a minute, scheduling now...") asyncio.ensure_future(self.send_reminder(rem), loop=self.loop) @@ -142,6 +176,7 @@ class ReminderBot(Plugin): async def help(self, evt: MessageEvent) -> None: await evt.reply(f"Maubot [Reminder](https://github.com/maubot/reminder) plugin.\n\n" f"* !{self.base_command} <date> <message> - Add a reminder\n" + f"* !{self.base_command} again <date> - Reply to a reminder to reschedule it\n" f"* !{self.base_command} list - Get a list of your reminders\n" f"* !{self.base_command} tz <timezone> - Set your time zone\n" f"* !{self.base_command} locale <locale> - Set your locale\n" @@ -169,7 +204,7 @@ class ReminderBot(Plugin): else: return f'"{rem.message}"' - reminders_str = "\n".join(f"* {format_rem(reminder)} {self.format_time(evt, reminder)}" + reminders_str = "\n".join(f"* {format_rem(reminder)} {self.format_time(evt.sender, reminder)}" for reminder in self.db.all_for_user(evt.sender, room_id=room_id)) message = "upcoming reminders" if room_id: @@ -179,8 +214,8 @@ class ReminderBot(Plugin): else: await evt.reply(f"Your {message}:\n\n{reminders_str}") - def format_time(self, evt: MessageEvent, reminder: ReminderInfo) -> str: - return format_time(reminder.date.astimezone(self.db.get_timezone(evt.sender))) + def format_time(self, sender: UserID, reminder: ReminderInfo) -> str: + return format_time(reminder.date.astimezone(self.db.get_timezone(sender))) @remind.subcommand("locales", help="List available locales") async def locales(self, evt: MessageEvent) -> None: diff --git a/reminder/util.py b/reminder/util.py index e852fa8..3482f82 100644 --- a/reminder/util.py +++ b/reminder/util.py @@ -78,7 +78,8 @@ class DateArgument(Argument): for locale in use_locales: match = locale.match(val) if match: - return val[match.end:], datetime.now(tz=tz) + relativedelta(**match.params) + date = (datetime.now(tz=tz) + relativedelta(**match.params)).astimezone(pytz.UTC) + return val[match.end:], date return val, None -- GitLab