From 5181f85a251937b3baaab9aa771e754c58e90dde Mon Sep 17 00:00:00 2001
From: MxMarx <ruby.e.marx@gmail.com>
Date: Wed, 13 Sep 2023 22:04:38 -0700
Subject: [PATCH] cleaned up documentation

---
 README.md        | 17 ++++++------
 base-config.yaml |  8 +++++-
 reminder/bot.py  | 67 +++++++++++++++++++++++++++++-------------------
 reminder/util.py | 27 ++++++++-----------
 4 files changed, 67 insertions(+), 52 deletions(-)

diff --git a/README.md b/README.md
index 7242336..5b3aab7 100644
--- a/README.md
+++ b/README.md
@@ -30,13 +30,12 @@ This is pretty easy to use with the [ansible deployment](https://github.com/span
 
 ## Usage
 ### Creating optionally recurring reminders:
-`!remind <message containing date>` Adds a reminder by extracting the date from the text
-* `!remind abolish closed-access journals at 3pm tomorrow`
+`!remind|remindme|r <date> <message>` Adds a reminder
 * `!remind 8 hours buy more pumpkins`
 * `!remind 2023-11-30 15:00 befriend rats`
-
-`!remind <date>; <message>` Bypasses text parsing by explicitly specifying the date
-* `!remind 2 days 4 hours; do something`
+* `!remind abolish closed-access journals at 3pm tomorrow`
+* `July 2`, `tuesday at 2pm`, `8pm`, `20 days`, `4d`, `2wk`, ...
+* Dates doesn't need to be at the beginning of the string, but parsing works better if they are.
 
 `!remind [room] [every] ...`
 * `[room]` pings the whole room
@@ -46,7 +45,7 @@ This is pretty easy to use with the [ansible deployment](https://github.com/span
 * `!remind cron 30 9 * * mon-fri do something` sets reminders for 9:30am, Monday through Friday.
 * `!remind cron` lists more examples
 
-You can also reply to any message with `!remind ...` to get reminded about that message.\\
+You can also reply to any message with `!remind ...` to get reminded about that message.\
 To get pinged by someone else's reminder, react to their message with 👍.
 
 ### Creating agenda items
@@ -59,10 +58,10 @@ To get pinged by someone else's reminder, react to their message with 👍.
 * `subscribed` lists only reminders you are subscribed to
 
 ### Deleting reminders
-Cancel reminders by removing the message creating it, unsubscribe by removing your upvote.\\
-Cancel recurring reminders by replying to the ping with `!remind cancel|delete` 
+Cancel reminders by removing the message creating it, unsubscribe by removing your upvote.\
+Cancel recurring reminders by replying with `!remind cancel|delete` 
 * `!remind cancel|delete <ID>` deletes a reminder matching the 4 letter ID shown by `list`
-* `!remind cancel|delete <message>` deletes a reminder *beginning with* <message>
+* `!remind cancel|delete <message>` deletes a reminder **beginning with** <message>
     * e.g. `!remind delete buy more` would delete the reminder `buy more pumpkins`
 
 ### Rescheduling
diff --git a/base-config.yaml b/base-config.yaml
index 22a4eb6..e44fc98 100644
--- a/base-config.yaml
+++ b/base-config.yaml
@@ -14,9 +14,15 @@ base_command:
 - remind
 - remindme
 
-# Alias used to create an agenda items
+# subcommands used to create an agenda items
 agenda_command:
 - agenda
+- todo
+
+# subcommands used to cancel reminders
+cancel_command:
+- cancel
+- delete
 
 
 # If verbose is true, display full confirmation messages. If false, confirm by reacting with :thumbs-up:
diff --git a/reminder/bot.py b/reminder/bot.py
index dbd7872..3aad7f2 100644
--- a/reminder/bot.py
+++ b/reminder/bot.py
@@ -27,7 +27,7 @@ from mautrix.util.config import BaseProxyConfig, ConfigUpdateHelper
 
 from .migrations import upgrade_table
 from .db import ReminderDatabase
-from .util import validate_locale, validate_timezone, CommandSyntaxError, parse_date, CommandSyntax
+from .util import validate_locale, validate_timezone, CommandSyntaxError, parse_date, CommandSyntax, make_pill
 from .reminder import Reminder
 from apscheduler.schedulers.asyncio import AsyncIOScheduler
 
@@ -39,15 +39,16 @@ class Config(BaseProxyConfig):
         helper.copy("default_locale")
         helper.copy("base_command")
         helper.copy("agenda_command")
+        helper.copy("cancel_command")
         helper.copy("rate_limit_minutes")
         helper.copy("rate_limit")
         helper.copy("verbose")
         helper.copy("admin_power_level")
 
 class ReminderBot(Plugin):
-    base_command: str
-    base_aliases: Tuple[str, ...]
+    base_command: Tuple[str, ...]
     agenda_command: Tuple[str, ...]
+    cancel_command: Tuple[str, ...]
     default_timezone: pytz.timezone
     scheduler: AsyncIOScheduler
     reminders: Dict[EventID, Reminder]
@@ -73,12 +74,14 @@ class ReminderBot(Plugin):
         self.reminders = await self.db.load_all(self)
 
     def on_external_config_update(self) -> None:
+
         self.config.load_and_update()
-        bc = self.config["base_command"]
-        ac = self.config["agenda_command"]
-        self.base_command = bc[0] if isinstance(bc, list) else bc
-        self.base_aliases = tuple(bc) if isinstance(bc, list) else (bc,)
-        self.agenda_command = tuple(ac) if isinstance(ac, list) else (ac,)
+
+        def config_to_tuple(list_or_str: List | str):
+            return tuple(list_or_str) if isinstance(list_or_str, list) else (list_or_str,)
+        self.base_command = config_to_tuple(self.config["base_command"])
+        self.agenda_command = config_to_tuple(self.config["agenda_command"])
+        self.cancel_command = config_to_tuple(self.config["cancel_command"])
 
         # If the locale or timezone is invalid, use default one
         self.db.defaults.locale = self.config["default_locale"]
@@ -96,8 +99,8 @@ class ReminderBot(Plugin):
 
 
 
-    @command.new(name=lambda self: self.base_command,
-                 aliases=lambda self, alias: alias in self.base_aliases + self.agenda_command,
+    @command.new(name=lambda self: self.base_command[0],
+                 aliases=lambda self, alias: alias in self.base_command + self.agenda_command,
                  help="Create a reminder", require_subcommand=False, arg_fallthrough=False)
     @command.argument("room", matches="room", required=False)
     @command.argument("every", matches="every", required=False)
@@ -114,9 +117,9 @@ class ReminderBot(Plugin):
         """Create a reminder or an alarm with a given target
         Args:
             evt:
-            room:
-            cron:
-            every:
+            room: if true, ping the whole room
+            cron: crontab syntax
+            every: is the reminder recurring?
             start_time:
             message:
             again:
@@ -230,7 +233,9 @@ class ReminderBot(Plugin):
 
 
     # @command.new("cancel", help="Cancel a recurring reminder", aliases=("delete",))
-    @create_reminder.subcommand("cancel", help="Cancel a recurring reminder", aliases=("delete",))
+    @create_reminder.subcommand(name=lambda self: self.cancel_command[0],
+                                help="Cancel a recurring reminder",
+                                aliases=lambda self, alias: alias in self.cancel_command)
     @command.argument("search_text", pass_raw=True, required=False)
     async def cancel_reminder(self, evt: MessageEvent, search_text: str) -> None:
         """Cancel a reminder by replying to a reminder, or searching by either message or event ID"""
@@ -251,7 +256,9 @@ class ReminderBot(Plugin):
                     reminder = rem
                     break
         else: # Display the help message
-            await evt.reply(CommandSyntax.REMINDER_CANCEL.value)
+            await evt.reply(CommandSyntax.REMINDER_CANCEL.value.format(base_command=self.base_command[0],
+                                            cancel_command=self.cancel_command[0],
+                                            cancel_aliases="|".join(self.cancel_command)))
             return
 
         if not reminder:
@@ -313,7 +320,11 @@ class ReminderBot(Plugin):
                     category = "**1️⃣ One-time reminders**"
                 else:
                     category = "**📜 Agenda items**"
-                categories[category].append(f"* {short_event_id} {next_run}  **{message}**")
+
+                room_link = f"https://matrix.to/#/{reminder.room_id}" if all else ""
+                # creator_link = await make_pill(reminder.creator) if not my else ""
+
+                categories[category].append(f"* {short_event_id + room_link} {next_run}  **{message}**")
 
         # Upack the nested dict into a flat list of reminders seperated by category
         in_room_msg = " in this room" if room_id else ""
@@ -326,8 +337,10 @@ class ReminderBot(Plugin):
         output = "\n".join(output)
 
         if not output:
-            output = f"You have no upcoming reminders{in_room_msg} :("
-        await evt.reply(output)
+            await evt.reply(f"You have no upcoming reminders{in_room_msg} :(")
+
+        await evt.reply(output + f"\n\n`!{self.base_command[0]} list [all] [my] [subscribed]`\\"
+                                 f"\n`!{self.base_command[0]} {self.cancel_command[0]} [4-letter ID or start of message]`")
 
 
 
@@ -395,30 +408,32 @@ class ReminderBot(Plugin):
 
     def _help_message(self) -> str:
         return f"""
-**⏰ Maubot [Reminder](https://github.com/maubot/reminder) plugin**\\
-TLDR: `!remind every friday 3pm take out the trash` `!remind cancel take out the trash`\\
-All commands can be called with `!{"|".join(self.base_aliases)}`
+**⏰ Maubot [Reminder](https://github.com/MxMarx/reminder) plugin**\\
+TLDR: `!{self.base_command[0]} every friday 3pm take out the trash` `!{self.base_command[0]} {self.cancel_command[0]} take out the trash`
 
 **Creating optionally recurring reminders:**
-{CommandSyntax.REMINDER_CREATE.value.format(base_command=self.base_command)}
+{CommandSyntax.REMINDER_CREATE.value.format(base_command=self.base_command[0],
+                                            base_aliases="|".join(self.base_command))}
 
 **Creating agenda items**
 {CommandSyntax.AGENDA_CREATE.value.format(agenda_command="|".join(self.agenda_command))}
 
 **Listing active reminders**
-{CommandSyntax.REMINDER_LIST.value.format(base_command=self.base_command)}
+{CommandSyntax.REMINDER_LIST.value.format(base_command=self.base_command[0])}
 
 **Deleting reminders**
 
-{CommandSyntax.REMINDER_CANCEL.value.format(base_command=self.base_command)}
+{CommandSyntax.REMINDER_CANCEL.value.format(base_command=self.base_command[0],
+                                            cancel_command=self.cancel_command[0],
+                                            cancel_aliases="|".join(self.cancel_command))}
 
 **Rescheduling**
 
-{CommandSyntax.REMINDER_RESCHEDULE.value.format(base_command=self.base_command)}
+{CommandSyntax.REMINDER_RESCHEDULE.value.format(base_command=self.base_command[0])}
 
 **Settings**
 
-{CommandSyntax.REMINDER_SETTINGS.value.format(base_command=self.base_command,
+{CommandSyntax.REMINDER_SETTINGS.value.format(base_command=self.base_command[0],
                                               default_tz=self.db.defaults.timezone,
                                               default_locale=self.db.defaults.locale)}
 """
\ No newline at end of file
diff --git a/reminder/util.py b/reminder/util.py
index 7252a99..76d9855 100644
--- a/reminder/util.py
+++ b/reminder/util.py
@@ -40,13 +40,12 @@ logger = logging.getLogger(__name__)
 
 class CommandSyntax(Enum):
     REMINDER_CREATE = """
-`!{base_command} <message containing date>` Adds a reminder by extracting the date from the text
-* `!{base_command} abolish closed-access journals at 3pm tomorrow`
+`!{base_aliases} <date> <message>` Adds a reminder
 * `!{base_command} 8 hours buy more pumpkins`
 * `!{base_command} 2023-11-30 15:00 befriend rats`
-
-`!{base_command} <date>; <message>` Bypasses text parsing by explicitly specifying the date
-* `!{base_command} 2 days 4 hours; do something`
+* `!{base_command} abolish closed-access journals at 3pm tomorrow`
+* `July 2`, `tuesday at 2pm`, `8pm`, `20 days`, `4d`, `2wk`, ...
+* Dates doesn't need to be at the beginning of the string, but parsing works better if they are.
 
 `!{base_command} [room] [every] ...`
 * `[room]` pings the whole room
@@ -73,14 +72,14 @@ To get pinged by someone else's reminder, react to their message with 👍.
 
     REMINDER_CANCEL = """
 Cancel reminders by removing the message creating it, unsubscribe by removing your upvote.\\
-Cancel recurring reminders by replying to the ping with `!{base_command} cancel|delete` 
-* `!{base_command} cancel|delete <ID>` deletes a reminder matching the 4 letter ID shown by `list`
-* `!{base_command} cancel|delete <message>` deletes a reminder *beginning with* <message>
-    * e.g. `!remind delete buy more` would delete the reminder `buy more pumpkins`
+Cancel recurring reminders by replying with `!{base_command} {cancel_aliases}` 
+* `!{base_command} {cancel_aliases} <ID>` deletes a reminder matching the 4 letter ID shown by `list`
+* `!{base_command} {cancel_aliases} <message>` deletes a reminder **beginning with** <message>
+    * e.g. `!remind {cancel_command} buy more` would delete the reminder `buy more pumpkins`
 """
 
     REMINDER_RESCHEDULE = """
-Reminders can be rescheduled after they have fired by replying with `!{base_command} <new date>`
+Reminders can be rescheduled by replying to the ping with `!{base_command} <new_date>`
 """
 
     REMINDER_SETTINGS = """
@@ -90,11 +89,7 @@ Defaults are `{default_tz}` and `{default_locale}`
 * `!{base_command} locale [new-locale]` view or set your locale
 """
 
-    SEARCH_DATE_EXAMPLES = "Example: `abolish closed-access journals at 11am on wednesday`, `8 hours buy more pumpkins`, `2023-11-30 15:00 befriend rats`"
-    PARSE_DATE_EXAMPLES = "Examples: `Tuesday at noon`, `8 hours`, `2023-11-30 10:15 pm`"
-
-
-    "Cancel a reminder by either redacting the message, using `!cancel <message>`, or replying to a recurring reminder with `!cancel`"
+    PARSE_DATE_EXAMPLES = "Examples: `Tuesday at noon`, `2023-11-30 10:15 pm`, `July 2`, `6 hours`, `8pm`, `4d`, `2wk`"
 
     CRON_EXAMPLE = """
 ```
@@ -205,7 +200,7 @@ def parse_date(str_with_time: str, user_info: UserInfo, search_text: bool=False)
         if not date:
             results = search_dates(str_with_time, languages=[user_info.locale.split('-')[0]], settings=settings)
             if not results:
-                raise CommandSyntaxError("Unable to extract date from string", CommandSyntax.SEARCH_DATE_EXAMPLES)
+                raise CommandSyntaxError("Unable to extract date from string", CommandSyntax.PARSE_DATE_EXAMPLES)
             date_str, date = results[0]
     else:
         date = dateparser.parse(str_with_time, locales=[user_info.locale], settings=settings)
-- 
GitLab