Пример #1
0
    def __init__(self, client: AsyncClient):
        """Setup the database

        Runs an initial setup or migrations depending on whether a database file has already
        been created

        Args:
            client: The matrix client
        """
        # Check which type of database has been configured
        self.client = client
        self.conn = self._get_database_connection(
            CONFIG.database.type, CONFIG.database.connection_string)
        self.cursor = self.conn.cursor()
        self.db_type = CONFIG.database.type

        # Try to check the current migration version
        migration_level = 0
        try:
            self._execute("SELECT version FROM migration_version")
            row = self.cursor.fetchone()
            migration_level = row[0]
        except Exception:
            self._initial_db_setup()
        finally:
            if migration_level < latest_migration_version:
                self._run_db_migrations(migration_level)

        # Load reminders from the db
        REMINDERS.update(self._load_reminders())

        logger.info(
            f"Database initialization of type '{self.db_type}' complete")
    async def _list_reminders(self):
        """Format and show known reminders for the current room

        Sends a message listing them in the following format:

            Reminders for this room:

            <start time>: <reminder text> [(every <recurring time>)] [(has alarm)]

        or if there are no reminders set:

            There are no reminders for this room.
        """
        reminders = []
        for reminder in REMINDERS.values():
            # Filter out reminders that don't belong to this room
            if reminder.room_id != self.room.room_id:
                continue

            # If this is a cron-style reminder, just print the cron tab
            if reminder.cron_tab:
                line = f"`{reminder.cron_tab}`: {reminder.reminder_text}"
                reminders.append(line)
                continue

            # Format the start time into something readable
            human_readable_start_time = reminder.start_time.strftime("%b %d %Y, %H:%M")

            line = f"{human_readable_start_time}: {reminder.reminder_text}"

            # Display a recurring time if available
            if reminder.recurse_timedelta:
                # Get a nice, human-readable version to print
                line += f" (every {readabledelta(reminder.recurse_timedelta)})"

            # Note that an alarm exists if available
            if reminder.alarm:
                line += " (has alarm)"

            reminders.append(line)

        if reminders:
            text = "Reminders for this room:\n\n"
            text += "\n\n".join(reminders)
        else:
            text = "There are no reminders for this room."

        await send_text_to_room(self.client, self.room.room_id, text)
    async def _silence(self):
        """Silences an ongoing alarm"""
        alarm_job = None

        # Attempt to find a reminder with an alarm currently going off
        reminder_text = " ".join(self.args)
        if reminder_text:
            # Find the alarm job via its reminder text
            alarm_job = ALARMS.get((self.room.room_id, reminder_text.upper()))

            if alarm_job:
                await self._remove_and_silence_alarm(alarm_job, reminder_text)
                text = f"Alarm '{reminder_text}' silenced."
            else:
                # We didn't find an alarm with that reminder text
                #
                # Be helpful and check if this is a known reminder without an alarm
                # currently going off
                reminder = REMINDERS.get((self.room.room_id, reminder_text.upper()))
                if reminder:
                    text = (
                        f"The reminder '{reminder_text}' does not currently have an "
                        f"alarm going off."
                    )
                else:
                    # Nope, can't find it
                    text = f"Unknown alarm or reminder '{reminder_text}'."

        else:
            # No reminder text provided. Check if there's a reminder currently firing
            # in the room instead then
            for alarm_info, job in ALARMS.items():
                if alarm_info[0] == self.room.room_id:
                    # Found one!
                    reminder_text = alarm_info[
                        1
                    ].capitalize()  # normalize the text a bit

                    await self._remove_and_silence_alarm(job, reminder_text)
                    text = f"Alarm '{reminder_text}' silenced."

                    # Prevent the `else` clause from being triggered
                    break
            else:
                # If we didn't find any alarms...
                text = "No alarms are currently firing in this room."

        await send_text_to_room(self.client, self.room.room_id, text)
Пример #4
0
    async def _delete_reminder(self):
        """Delete a reminder via its reminder text"""
        reminder_text = " ".join(self.args)
        if not reminder_text:
            raise CommandSyntaxError()

        logger.debug("Known reminders: %s", REMINDERS)
        logger.debug("Deleting reminder in room %s: %s", self.room.room_id,
                     reminder_text)

        reminder = REMINDERS.get((self.room.room_id, reminder_text.upper()))
        if reminder:
            # Cancel the reminder and associated alarms
            reminder.cancel()

            text = "Reminder cancelled."
        else:
            text = f"Unknown reminder '{reminder_text}'."

        await send_text_to_room(self.client, self.room.room_id, text)
Пример #5
0
    async def _list_reminders(self):
        """Format and show known reminders for the current room

        Sends a message listing them in the following format, using the alarm clock emoji ⏰ to indicate an alarm:

            1️⃣ One-time Reminders

            * [⏰] <start time>: <reminder text>

            📅 Cron Reminders

            * [⏰] m h d M wd (`m h d M wd`); next run in <rounded next time>; <reminder text>

            🔁 Repeating Reminders

            * [⏰] every <recurring time>; next run in <rounded next time>; <reminder text>

        or if there are no reminders set:

            There are no reminders for this room.
        """
        output = ""

        cron_reminder_lines = []
        one_shot_reminder_lines = []
        interval_reminder_lines = []

        # Sort the reminder types
        for reminder in REMINDERS.values():
            # Filter out reminders that don't belong to this room
            if reminder.room_id != self.room.room_id:
                continue

            # Organise alarms into markdown lists
            line = "- "
            if reminder.alarm:
                # Note that an alarm exists if available
                alarm_clock_emoji = "⏰"
                line += alarm_clock_emoji + " "

            # Print the duration before (next) execution
            next_execution = reminder.job.next_run_time
            next_execution = arrow.get(next_execution)

            # Cron-based reminders
            if isinstance(reminder.job.trigger, CronTrigger):
                # A human-readable cron tab, in addition to the actual tab
                line += f"{prettify_cron(reminder.cron_tab)} (`{reminder.cron_tab}`); next run {next_execution.humanize()}"

            # One-time reminders
            elif isinstance(reminder.job.trigger, DateTrigger):
                # Just print when the reminder will go off
                line += f"{next_execution.humanize()}"

            # Repeat reminders
            elif isinstance(reminder.job.trigger, IntervalTrigger):
                # Print the interval, and when it will next go off
                line += f"every {readabledelta(reminder.recurse_timedelta)}; next run {next_execution.humanize()}"

            # Add the reminder's text
            line += f'; *"{reminder.reminder_text}"*'

            # Output the status of each reminder. We divide up the reminders by type in order
            # to show them in separate sections, and display them differently
            if isinstance(reminder.job.trigger, CronTrigger):
                cron_reminder_lines.append(line)
            elif isinstance(reminder.job.trigger, DateTrigger):
                one_shot_reminder_lines.append(line)
            elif isinstance(reminder.job.trigger, IntervalTrigger):
                interval_reminder_lines.append(line)

        if (not one_shot_reminder_lines and not cron_reminder_lines
                and not interval_reminder_lines):
            await send_text_to_room(
                self.client,
                self.room.room_id,
                "*There are no reminders for this room.*",
            )
            return

        if one_shot_reminder_lines:
            output += "\n\n" + "**1️⃣ One-time Reminders**" + "\n\n"
            output += "\n".join(one_shot_reminder_lines)

        if cron_reminder_lines:
            output += "\n\n" + "**📅 Cron Reminders**" + "\n\n"
            output += "\n".join(cron_reminder_lines)

        if interval_reminder_lines:
            output += "\n\n" + "**🔁 Repeating Reminders**" + "\n\n"
            output += "\n".join(interval_reminder_lines)

        await send_text_to_room(self.client, self.room.room_id, output)