From bf767b622a547209dde717a965c7ea79a7debdca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Hells=C3=A9n?= Date: Sun, 30 Oct 2022 19:24:23 +0100 Subject: [PATCH] Add a new function for parsing time from a string --- discord_reminder_bot/main.py | 114 +++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 45 deletions(-) diff --git a/discord_reminder_bot/main.py b/discord_reminder_bot/main.py index f0d83f7..1ec1f22 100644 --- a/discord_reminder_bot/main.py +++ b/discord_reminder_bot/main.py @@ -1,4 +1,6 @@ +import dataclasses import logging +from datetime import datetime from typing import List import dateparser @@ -6,7 +8,7 @@ import interactions from apscheduler.jobstores.base import JobLookupError from apscheduler.triggers.date import DateTrigger from dateparser.conf import SettingValidationError -from interactions import CommandContext, Embed, Option, OptionType, autodefer +from interactions import CommandContext, Embed, Option, OptionType from interactions.ext.paginator import Paginator from discord_reminder_bot.countdown import calculate @@ -30,6 +32,55 @@ async def base_command(ctx: interactions.CommandContext): pass +@dataclasses.dataclass +class ParsedTime: + """ + This is used when parsing a time or date from a string. + + We use this when adding a job with /reminder add. + + Attributes: + date_to_parse: The string we parsed the time from. + err: True if an error was raised when parsing the time. + err_msg: The error message. + parsed_time: The parsed time we got from the string. + """ + date_to_parse: str = None + err: bool = False + err_msg: str = "" + parsed_time: datetime = None + + +def parse_time(date_to_parse: str, timezone: str = config_timezone) -> ParsedTime: + """Parse the datetime from a string. + + Args: + date_to_parse: The string we want to parse. + timezone: The timezone to use when parsing. This will be used when typing things like "22:00". + + Returns: + ParsedTime + """ + try: + parsed_date = dateparser.parse( + f"{date_to_parse}", + settings={ + "PREFER_DATES_FROM": "future", + "TIMEZONE": f"{timezone}", + "TO_TIMEZONE": f"{timezone}", + }, + ) + except SettingValidationError as e: + return ParsedTime(err=True, err_msg=f"Timezone is possible wrong?: {e}", date_to_parse=date_to_parse) + except ValueError as e: + return ParsedTime(err=True, err_msg=f"Failed to parse date. Unknown language: {e}", date_to_parse=date_to_parse) + + if not parsed_date: + return ParsedTime(err=True, err_msg=f"Could not parse the date.", date_to_parse=date_to_parse) + + return ParsedTime(parsed_time=parsed_date, date_to_parse=date_to_parse) + + @bot.modal("edit_modal") async def modal_response_edit(ctx: CommandContext, *response: str): """This is what gets triggerd when the user clicks the Edit button in /reminder list. @@ -84,34 +135,22 @@ async def modal_response_edit(ctx: CommandContext, *response: str): msg = f"Modified job {job_id}.\n" if old_date is not None: if new_date: - try: - parsed_date = dateparser.parse( - f"{new_date}", - settings={ - "PREFER_DATES_FROM": "future", - "TIMEZONE": f"{config_timezone}", - "TO_TIMEZONE": f"{config_timezone}", - }, - ) - except SettingValidationError as e: - return await ctx.send( - f"Timezone is possible wrong?: {e}", ephemeral=True - ) - except ValueError as e: - return await ctx.send( - f"Failed to parse date. Unknown language: {e}", ephemeral=True - ) - - if not parsed_date: - return await ctx.send("Could not parse the date.", ephemeral=True) - + # Parse the time/date we got from the command. + parsed = parse_time(date_to_parse=new_date) + if parsed.err: + return await ctx.send(parsed.err_msg) + parsed_date = parsed.parsed_time date_new = parsed_date.strftime("%Y-%m-%d %H:%M:%S") new_job = scheduler.reschedule_job(job.id, run_date=date_new) new_time = calculate(new_job) + # TODO: old_date and date_new has different precision. + # Old date: 2032-09-18 00:07 + # New date: 2032-09-18 00:07:13 msg += ( - f"**Old date**: {old_date}\n**New date**: {date_new} (in {new_time})\n" + f"**Old date**: {old_date}\n" + f"**New date**: {date_new} (in {new_time})\n" ) if old_message is not None: @@ -205,31 +244,17 @@ async def command_add( message_reason: The message the bot should write when the reminder is triggered. different_channel: The channel the reminder should be sent to. """ - try: - parsed_date = dateparser.parse( - f"{message_date}", - settings={ - "PREFER_DATES_FROM": "future", - "TIMEZONE": f"{config_timezone}", - "TO_TIMEZONE": f"{config_timezone}", - }, - ) - except SettingValidationError as e: - return await ctx.send(f"Timezone is possible wrong?: {e}", ephemeral=True) - except ValueError as e: - return await ctx.send( - f"Failed to parse date. Unknown language: {e}", ephemeral=True - ) - if not parsed_date: - return await ctx.send("Could not parse the date.", ephemeral=True) - - channel_id = int(ctx.channel_id) + # Parse the time/date we got from the command. + parsed = parse_time(date_to_parse=message_date) + if parsed.err: + return await ctx.send(parsed.err_msg) + parsed_date = parsed.parsed_time + run_date = parsed_date.strftime("%Y-%m-%d %H:%M:%S") # If we should send the message to a different channel + channel_id = int(ctx.channel_id) if different_channel: channel_id = int(different_channel.id) - - run_date = parsed_date.strftime("%Y-%m-%d %H:%M:%S") try: reminder = scheduler.add_job( send_to_discord, @@ -497,7 +522,6 @@ async def remind_cron( ), ], ) -@autodefer() async def remind_interval( ctx: interactions.CommandContext, message_reason: str,