Make lines less wide, add TODOs, modify comments

This commit is contained in:
2022-03-18 02:35:18 +01:00
parent 405dcbc907
commit e6fedbb7e7

View File

@ -37,7 +37,7 @@ def calc_countdown(job) -> str:
Days/Minutes will not be included if 0. Days/Minutes will not be included if 0.
Args: Args:
job ([type]): The job. Can be cron, interval or normal. job: The job. Can be cron, interval or normal.
Returns: Returns:
str: Returns days, hours and minutes till reminder. Returns str: Returns days, hours and minutes till reminder. Returns
@ -50,6 +50,7 @@ def calc_countdown(job) -> str:
# Get_job() returns None when it can't find a job with that id. # Get_job() returns None when it can't find a job with that id.
if trigger_time is None: if trigger_time is None:
# TODO: Change this to None and send this text where needed.
return "Failed to calculate time" return "Failed to calculate time"
# Get time and date the job will run and calculate how many days, # Get time and date the job will run and calculate how many days,
@ -61,6 +62,8 @@ def calc_countdown(job) -> str:
countdown.seconds // 3600, countdown.seconds // 3600,
countdown.seconds // 60 % 60, countdown.seconds // 60 % 60,
) )
# TODO: Explain this.
return ", ".join( return ", ".join(
f"{x} {y}{'s'*(x!=1)}" f"{x} {y}{'s'*(x!=1)}"
for x, y in ( for x, y in (
@ -74,25 +77,20 @@ def calc_countdown(job) -> str:
@bot.event @bot.event
async def on_slash_command_error(ctx: SlashContext, ex: Exception): async def on_slash_command_error(ctx: SlashContext, ex: Exception):
"""Send message to Discord when slash command fails.
Args:
ctx (SlashContext): Context. The meta data about the slash command.
ex (Exception): Exception that raised.
https://discord-py-slash-command.readthedocs.io/en/latest/discord_slash.error.html
"""
logging.error( logging.error(
f'Error occurred during the execution of "/{ctx.name} {ctx.subcommand_name}" by {ctx.author}: {ex}' "Error occurred during the execution of"
f' "/{ctx.name} {ctx.subcommand_name}" by {ctx.author}: {ex}'
) )
if ex == RequestFailure: if ex == RequestFailure:
message = f"Request to Discord API failed: {ex}" message = f"Request to Discord API failed: {ex}"
elif ex == IncorrectFormat: elif ex == IncorrectFormat:
message = f"Incorrect format: {ex}" message = f"Incorrect format: {ex}"
elif ex == NotFound: elif ex == NotFound:
message = f"I couldn't find the interaction or it took me longer than 3 seconds to respond: {ex}" message = "I couldn't find the interaction or it took me longer than"
f" 3 seconds to respond: {ex}"
else: else:
message = f"Error occurred during the execution of '/{ctx.name} {ctx.subcommand_name}': {ex}" message = "Error occurred during the execution of "
f"'/{ctx.name} {ctx.subcommand_name}': {ex}"
await ctx.send( await ctx.send(
f"{message}\nIf this persists, please make an issue on the" f"{message}\nIf this persists, please make an issue on the"
@ -127,24 +125,29 @@ async def command_modify(ctx: SlashContext, time_or_message: str):
"""Modify a reminder. You can change time or message. """Modify a reminder. You can change time or message.
Args: Args:
ctx (SlashContext): Context. The meta data about the slash command.
time_or_message (str): Choose between modifying the message or time. time_or_message (str): Choose between modifying the message or time.
Returns:
[type]: Send message to Discord.
""" """
# TODO: Reduce complexity.
# Only make a list with normal reminders.
list_embed, jobs_dict = make_list(ctx, skip_cron_or_interval=True) list_embed, jobs_dict = make_list(ctx, skip_cron_or_interval=True)
date_or_message = "the date" if time_or_message == "date" else "the message" if time_or_message == "date":
date_or_message = "the date"
else:
date_or_message = "the message"
# The empty embed has 76 characters # The empty embed has 76 characters
# TODO: This is a hack. Fix it.
# TODO: Move this to a function.
if len(list_embed) <= 76: if len(list_embed) <= 76:
await ctx.send(f"{ctx.guild.name} has no reminders.") await ctx.send(f"{ctx.guild.name} has no reminders.")
else: else:
await ctx.send(embed=list_embed) await ctx.send(embed=list_embed)
await ctx.channel.send( await ctx.channel.send(
f"Type the corresponding number to the reminder were you wish to change {date_or_message}. " "Type the corresponding number to the reminder were you wish to"
"Does not work with cron or interval. Type Exit to exit." f" change {date_or_message}. Does not work with cron or interval."
" Type Exit to exit."
) )
# Only check for response from the original user and in the # Only check for response from the original user and in the
@ -152,9 +155,10 @@ async def command_modify(ctx: SlashContext, time_or_message: str):
def check(m): def check(m):
return m.author == ctx.author and m.channel == ctx.channel return m.author == ctx.author and m.channel == ctx.channel
# TODO: Add timeout
response_message = await bot.wait_for("message", check=check) response_message = await bot.wait_for("message", check=check)
if response_message.clean_content == "Exit": if response_message.clean_content == "Exit":
return await ctx.channel.send("Exited.") return await ctx.channel.send(exit_message)
for num, job_from_dict in jobs_dict.items(): for num, job_from_dict in jobs_dict.items():
if int(response_message.clean_content) == num: if int(response_message.clean_content) == num:
@ -163,17 +167,27 @@ async def command_modify(ctx: SlashContext, time_or_message: str):
# Get_job() returns None when it can't find a job with that id. # Get_job() returns None when it can't find a job with that id.
if job is None: if job is None:
await ctx.send(f"No reminder with that ID ({job_from_dict}).") await ctx.send(f"No reminder with ID ({job_from_dict}).")
return return
message = job.kwargs.get("message") message = job.kwargs.get("message")
the_final_countdown_old = calc_countdown(job) old_time = calc_countdown(job)
channel_name = bot.get_channel(int(job.kwargs.get("channel_id"))) channel_name = bot.get_channel(
int(job.kwargs.get("channel_id")),
)
msg = f"**Modified** {job_from_dict} in #{channel_name}\n" msg = f"**Modified** {job_from_dict} in #{channel_name}\n"
if time_or_message == "message": if time_or_message == "message":
await ctx.channel.send("Type the new message. Type Exit to exit.") await ctx.channel.send(
response_new_message = await bot.wait_for("message", check=check) "Type the new message. Type Exit to exit.",
)
# TODO: Add timeout
response_new_message = await bot.wait_for(
"message",
check=check,
)
if response_new_message.clean_content == "Exit": if response_new_message.clean_content == "Exit":
return await ctx.channel.send(exit_message) return await ctx.channel.send(exit_message)
@ -185,11 +199,21 @@ async def command_modify(ctx: SlashContext, time_or_message: str):
"author_id": job.kwargs.get("author_id"), "author_id": job.kwargs.get("author_id"),
}, },
) )
msg += f"**Old message**: {message}\n**New message**: {response_new_message.clean_content}\n" msg += (
f"**Old message**: {message}\n"
f"**New message**: {response_new_message.clean_content}\n"
)
else: else:
await ctx.channel.send("Type the new date. Type Exit to exit.") await ctx.channel.send(
response_new_date = await bot.wait_for("message", check=check) "Type the new date. Type Exit to exit.",
)
# TODO: Add timeout
response_new_date = await bot.wait_for(
"message",
check=check,
)
if response_new_date.clean_content == "Exit": if response_new_date.clean_content == "Exit":
return await ctx.channel.send(exit_message) return await ctx.channel.send(exit_message)
@ -200,36 +224,29 @@ async def command_modify(ctx: SlashContext, time_or_message: str):
"TO_TIMEZONE": f"{config_timezone}", "TO_TIMEZONE": f"{config_timezone}",
}, },
) )
remove_timezone_from_date = parsed_date.strftime( date_new = parsed_date.strftime("%Y-%m-%d %H:%M:%S")
"%Y-%m-%d %H:%M:%S"
)
job = scheduler.reschedule_job( job = scheduler.reschedule_job(job_from_dict, run_date=date_new)
job_from_dict, run_date=remove_timezone_from_date
)
remove_timezone_from_date_old = job.trigger.run_date.strftime( date_old = job.trigger.run_date.strftime("%Y-%m-%d %H:%M")
"%Y-%m-%d %H:%M" new_time = calc_countdown(job_from_dict)
)
the_final_countdown_new = calc_countdown(job_from_dict)
msg += ( msg += (
f"**Old date**: {remove_timezone_from_date_old} (in {the_final_countdown_old})\n" f"**Old date**: {date_old} (in {old_time})\n"
f"**New date**: {remove_timezone_from_date} (in {the_final_countdown_new})" f"**New date**: {date_new} (in {new_time})"
) )
await ctx.send(msg) await ctx.send(msg)
@slash.subcommand(base="remind", name="remove", description="Remove a reminder.") @slash.subcommand(
base="remind",
name="remove",
description="Remove a reminder",
)
async def remind_remove(ctx: SlashContext): async def remind_remove(ctx: SlashContext):
"""Select reminder from list that you want to remove. """Select reminder from list that you want to remove."""
# TODO: Reduce complexity
Args:
ctx (SlashContext): Context. The meta data about the slash command.
Returns:
[type]: Send message to Discord.
"""
list_embed, jobs_dict = make_list(ctx) list_embed, jobs_dict = make_list(ctx)
# The empty embed has 76 characters # The empty embed has 76 characters
@ -238,7 +255,8 @@ async def remind_remove(ctx: SlashContext):
else: else:
await ctx.send(embed=list_embed) await ctx.send(embed=list_embed)
await ctx.channel.send( await ctx.channel.send(
"Type the corresponding number to the reminder you wish to remove. Type Exit to exit." "Type the corresponding number to the reminder you wish to remove."
" Type Exit to exit."
) )
# Only check for response from the original user and in the # Only check for response from the original user and in the
@ -246,6 +264,7 @@ async def remind_remove(ctx: SlashContext):
def check(m): def check(m):
return m.author == ctx.author and m.channel == ctx.channel return m.author == ctx.author and m.channel == ctx.channel
# TODO: Add timeout
response_message = await bot.wait_for("message", check=check) response_message = await bot.wait_for("message", check=check)
if response_message.clean_content == "Exit": if response_message.clean_content == "Exit":
return await ctx.channel.send(exit_message) return await ctx.channel.send(exit_message)
@ -276,7 +295,10 @@ async def remind_remove(ctx: SlashContext):
else: else:
trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job)})' trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job)})'
msg = f"**Removed** {message} in #{channel_name}.\n**Time**: {trigger_value}" msg = (
f"**Removed** {message} in #{channel_name}.\n"
f"**Time**: {trigger_value}"
)
scheduler.remove_job(job_from_dict) scheduler.remove_job(job_from_dict)
@ -287,7 +309,6 @@ def make_list(ctx, skip_datetriggers=False, skip_cron_or_interval=False):
"""Create a list of reminders. """Create a list of reminders.
Args: Args:
ctx (SlashContext): Context. The meta data about the slash command.
skip_datetriggers (bool, optional): Only show cron jobs and interval reminders. skip_datetriggers (bool, optional): Only show cron jobs and interval reminders.
skip_cron_or_interval (bool, optional): Only show normal reminders. skip_cron_or_interval (bool, optional): Only show normal reminders.
@ -356,15 +377,12 @@ def make_list(ctx, skip_datetriggers=False, skip_cron_or_interval=False):
description="Show reminders.", description="Show reminders.",
) )
async def remind_list(ctx: SlashContext): async def remind_list(ctx: SlashContext):
"""Send a list of reminders to Discord. """Send a list of reminders to Discord."""
Args:
ctx (SlashContext): Context. The meta data about the slash command.
"""
list_embed, _ = make_list(ctx) list_embed, _ = make_list(ctx)
# The empty embed has 76 characters # The empty embed has 76 characters
# TODO: This is a hack. Fix it. # TODO: This is a hack. Fix it.
# TODO: Move this to a function.
if len(list_embed) <= 76: if len(list_embed) <= 76:
await ctx.send(f"{ctx.guild.name} has no reminders.") await ctx.send(f"{ctx.guild.name} has no reminders.")
else: else:
@ -382,6 +400,7 @@ async def remind_pause(ctx: SlashContext):
# The empty embed has 76 characters # The empty embed has 76 characters
# TODO: This is a hack. Fix it. # TODO: This is a hack. Fix it.
# TODO: Move this to a function.
if len(list_embed) <= 76: if len(list_embed) <= 76:
await ctx.send(f"{ctx.guild.name} has no reminders.") await ctx.send(f"{ctx.guild.name} has no reminders.")
else: else:
@ -396,6 +415,7 @@ async def remind_pause(ctx: SlashContext):
def check(m): def check(m):
return m.author == ctx.author and m.channel == ctx.channel return m.author == ctx.author and m.channel == ctx.channel
# TODO: Add timeout
response_reminder = await bot.wait_for("message", check=check) response_reminder = await bot.wait_for("message", check=check)
if response_reminder.clean_content == "Exit": if response_reminder.clean_content == "Exit":
return await ctx.channel.send(exit_message) return await ctx.channel.send(exit_message)
@ -424,7 +444,10 @@ async def remind_pause(ctx: SlashContext):
trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job)})' trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job)})'
msg = f"**Paused** {message} in #{channel_name}.\n**Time**: {trigger_value}" msg = (
f"**Paused** {message} in #{channel_name}.\n"
f"**Time**: {trigger_value}"
)
scheduler.pause_job(job_from_dict) scheduler.pause_job(job_from_dict)
print(f"Paused {job_from_dict} in #{channel_name}") print(f"Paused {job_from_dict} in #{channel_name}")
@ -437,24 +460,20 @@ async def remind_pause(ctx: SlashContext):
description="Resume paused reminder. For cron or interval.", description="Resume paused reminder. For cron or interval.",
) )
async def remind_resume(ctx: SlashContext): async def remind_resume(ctx: SlashContext):
"""Send a list of reminders to pause to Discord. """Send a list of reminders to pause to Discord."""
Args:
ctx (SlashContext): Context. The meta data about the slash command.
Returns:
[type]: Sends message to Discord.
"""
# TODO: Reduce the complexity of this function # TODO: Reduce the complexity of this function
list_embed, jobs_dict = make_list(ctx, skip_datetriggers=True) list_embed, jobs_dict = make_list(ctx, skip_datetriggers=True)
# The empty embed has 76 characters # The empty embed has 76 characters
# TODO: This is a hack. Fix it.
# TODO: Move this to a function.
if len(list_embed) <= 76: if len(list_embed) <= 76:
await ctx.send(f"{ctx.guild.name} has no reminders.") await ctx.send(f"{ctx.guild.name} has no reminders.")
else: else:
await ctx.send(embed=list_embed) await ctx.send(embed=list_embed)
await ctx.channel.send( await ctx.channel.send(
"Type the corresponding number to the reminder you wish to pause. Type Exit to exit." "Type the corresponding number to the reminder you wish to pause."
" Type Exit to exit."
) )
# Only check for response from the original user and in the # Only check for response from the original user and in the
@ -462,6 +481,7 @@ async def remind_resume(ctx: SlashContext):
def check(m): def check(m):
return m.author == ctx.author and m.channel == ctx.channel return m.author == ctx.author and m.channel == ctx.channel
# TODO: Add timeout
response_message = await bot.wait_for("message", check=check) response_message = await bot.wait_for("message", check=check)
if response_message.clean_content == "Exit": if response_message.clean_content == "Exit":
return await ctx.channel.send(exit_message) return await ctx.channel.send(exit_message)
@ -470,7 +490,9 @@ async def remind_resume(ctx: SlashContext):
if int(response_message.clean_content) == num: if int(response_message.clean_content) == num:
job = scheduler.get_job(job_from_dict) job = scheduler.get_job(job_from_dict)
if job is None: if job is None:
await ctx.send(f"No reminder with that ID ({job_from_dict}).") await ctx.send(
f"No reminder with that ID ({job_from_dict}).",
)
return return
channel_id = job.kwargs.get("channel_id") channel_id = job.kwargs.get("channel_id")
@ -495,7 +517,10 @@ async def remind_resume(ctx: SlashContext):
else: else:
trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job)})' trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job)})'
msg = f"**Resumed** {message} in #{channel_name}.\n**Time**: {trigger_value}\n" msg = (
f"**Resumed** {message} in #{channel_name}.\n"
f"**Time**: {trigger_value}\n"
)
await ctx.send(msg) await ctx.send(msg)
@ -534,7 +559,6 @@ async def remind_add(
"""Add a new reminder. You can add a date and message. """Add a new reminder. You can add a date and message.
Args: Args:
ctx (SlashContext): Context. The meta data about the slash command.
message_date (str): The date or time that will get parsed. message_date (str): The date or time that will get parsed.
message_reason (str): The message the bot should write when the reminder is triggered. message_reason (str): The message the bot should write when the reminder is triggered.
different_channel (str): The channel the reminder should be sent to. different_channel (str): The channel the reminder should be sent to.
@ -543,11 +567,16 @@ async def remind_add(
f"{message_date}", f"{message_date}",
settings={ settings={
"PREFER_DATES_FROM": "future", "PREFER_DATES_FROM": "future",
# TODO: Is timezones even working? Timezones confuse me.
"TO_TIMEZONE": f"{config_timezone}", "TO_TIMEZONE": f"{config_timezone}",
}, },
) )
channel_id = different_channel.id if different_channel else ctx.channel.id channel_id = ctx.channel.id
# If we should send the message to a different channel
if different_channel:
channel_id = different_channel.id
run_date = parsed_date.strftime("%Y-%m-%d %H:%M:%S") run_date = parsed_date.strftime("%Y-%m-%d %H:%M:%S")
reminder = scheduler.add_job( reminder = scheduler.add_job(
@ -561,9 +590,11 @@ async def remind_add(
) )
message = ( message = (
f"Hello {ctx.author.display_name}, I will notify you in <#{channel_id}> at:\n" f"Hello {ctx.author.display_name},"
f" I will notify you in <#{channel_id}> at:\n"
f"**{run_date}** (in {calc_countdown(reminder)})\n" f"**{run_date}** (in {calc_countdown(reminder)})\n"
f"With the message:\n**{message_reason}**." f"With the message:\n"
f"**{message_reason}**."
) )
await ctx.send(message) await ctx.send(message)
@ -683,25 +714,27 @@ async def remind_cron(
Args that are None will be defaulted to *. Args that are None will be defaulted to *.
Args: Args:
ctx (SlashContext): Context. The meta data about the slash command.
message_reason (str): The message the bot should send everytime cron job triggers. message_reason (str): The message the bot should send everytime cron job triggers.
year (int, optional): 4-digit year. year (int): 4-digit year.
month (int, optional): Month (1-12). month (int): Month (1-12).
day (int, optional): Day of month (1-31). day (int): Day of month (1-31).
week (int, optional): ISO week (1-53). week (int): ISO week (1-53).
day_of_week (str, optional): Number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun). day_of_week (str): Number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun).
hour (int, optional): Hour (0-23). hour (int): Hour (0-23).
minute (int, optional): Minute (0-59). minute (int): Minute (0-59).
second (int, optional): Second (0-59). second (int): Second (0-59).
start_date (str, optional): Earliest possible date/time to trigger on (inclusive). start_date (str): Earliest possible date/time to trigger on (inclusive).
end_date (str, optional): Latest possible date/time to trigger on (inclusive). end_date (str): Latest possible date/time to trigger on (inclusive).
timezone (str, optional): Time zone to use for the date/time calculations Defaults to scheduler timezone. timezone (str): Time zone to use for the date/time calculations Defaults to scheduler timezone.
jitter (int, optional): Delay the job execution by jitter seconds at most. jitter (int): Delay the job execution by jitter seconds at most.
https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html#module-apscheduler.triggers.cron https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html#module-apscheduler.triggers.cron
""" """
channel_id = ctx.channel.id
channel_id = different_channel.id if different_channel else ctx.channel.id # If we should send the message to a different channel
if different_channel:
channel_id = different_channel.id
job = scheduler.add_job( job = scheduler.add_job(
send_to_discord, send_to_discord,
@ -725,10 +758,12 @@ async def remind_cron(
}, },
) )
# TODO: Add arguments # TODO: Add what arguments we used in the job to the message
message = ( message = (
f"Hello {ctx.author.display_name}, I will send messages to <#{channel_id}>.\n" f"Hello {ctx.author.display_name},"
f"First run in {calc_countdown(job)} with the message:\n**{message_reason}**." f" I will send messages to <#{channel_id}>.\n"
f"First run in {calc_countdown(job)} with the message:\n"
f"**{message_reason}**."
) )
await ctx.send(message) await ctx.send(message)
@ -823,17 +858,16 @@ async def remind_interval(
"""Create new reminder that triggers based on a interval. """Create new reminder that triggers based on a interval.
Args: Args:
ctx (SlashContext): Context. The meta data about the slash command.
message_reason (str): The message we should write when triggered. message_reason (str): The message we should write when triggered.
weeks (int, optional): Number of weeks to wait. weeks (int): Number of weeks to wait.
days (int, optional): Number of days to wait. days (int): Number of days to wait.
hours (int, optional): Number of hours to wait. hours (int): Number of hours to wait.
minutes (int, optional): Number of minutes to wait. minutes (int): Number of minutes to wait.
seconds (int, optional): Number of seconds to wait. seconds (int): Number of seconds to wait.
start_date (str, optional): Starting point for the interval calculation. start_date (str): Starting point for the interval calculation.
end_date (str, optional): Latest possible date/time to trigger on. end_date (str): Latest possible date/time to trigger on.
timezone (str, optional): Time zone to use for the date/time calculations. timezone (str): Time zone to use for the date/time calculations.
jitter (int, optional): Delay the job execution by jitter seconds at most. jitter (int): Delay the job execution by jitter seconds at most.
""" """
channel_id = different_channel.id if different_channel else ctx.channel.id channel_id = different_channel.id if different_channel else ctx.channel.id
@ -857,10 +891,11 @@ async def remind_interval(
}, },
) )
# TODO: Add arguments # TODO: Add what arguments we used in the job to the message
message = ( message = (
f"Hello {ctx.author.display_name}, I will send messages to <#{channel_id}>.\n" f"Hello {ctx.author.display_name}, I will send messages to <#{channel_id}>.\n"
f"First run in {calc_countdown(job)} with the message:\n**{message_reason}**." f"First run in {calc_countdown(job)} with the message:\n"
f"**{message_reason}**."
) )
await ctx.send(message) await ctx.send(message)
@ -881,6 +916,8 @@ async def send_to_discord(channel_id: int, message: str, author_id: int):
def start(): def start():
"""Start scheduler and log in to Discord.""" """Start scheduler and log in to Discord."""
# TODO: Add how many reminders are scheduled.
# TODO: Make backup of jobs.sqlite before running the bot.
logging.basicConfig(level=logging.getLevelName(log_level)) logging.basicConfig(level=logging.getLevelName(log_level))
logging.info( logging.info(
f"\nsqlite_location = {sqlite_location}\n" f"\nsqlite_location = {sqlite_location}\n"