Removed remind_id from pause and resume command

This commit is contained in:
2021-05-07 02:30:06 +02:00
parent 79bcceb1d3
commit 59652214ed

287
main.py
View File

@ -8,11 +8,11 @@ import pytz
from apscheduler.jobstores.base import JobLookupError from apscheduler.jobstores.base import JobLookupError
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.date import DateTrigger from apscheduler.triggers.date import DateTrigger
from apscheduler.triggers.interval import IntervalTrigger from discord.errors import NotFound
from discord.ext import commands from discord.ext import commands
from discord_slash import SlashCommand, SlashContext from discord_slash import SlashCommand, SlashContext
from discord_slash.error import IncorrectFormat, RequestFailure
from discord_slash.model import SlashCommandOptionType from discord_slash.model import SlashCommandOptionType
from discord_slash.utils.manage_commands import create_option from discord_slash.utils.manage_commands import create_option
from dotenv import load_dotenv from dotenv import load_dotenv
@ -30,14 +30,14 @@ def calc_countdown(remind_id: str) -> str:
job = scheduler.get_job(remind_id) job = scheduler.get_job(remind_id)
# 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:
print(f"No reminder with that ID ({remind_id}).")
return "0 days, 0 hours, 0 minutes"
if type(job.trigger) is DateTrigger: if type(job.trigger) is DateTrigger:
trigger_time = job.trigger.run_date trigger_time = job.trigger.run_date
if type(job.trigger) is IntervalTrigger or CronTrigger: else:
trigger_time = job.next_run_time trigger_time = job.next_run_time
if trigger_time is None:
return "Failed to calculate time"
# Get time and date the job will run and calculate how many days, hours and seconds. # Get time and date the job will run and calculate how many days, hours and seconds.
countdown = trigger_time - datetime.datetime.now(tz=pytz.timezone(config_timezone)) countdown = trigger_time - datetime.datetime.now(tz=pytz.timezone(config_timezone))
@ -58,21 +58,27 @@ def calc_countdown(remind_id: str) -> str:
return the_final_countdown return the_final_countdown
@bot.event
async def on_error(event, *args, **kwargs):
logging.error(f"{event}")
@bot.event @bot.event
async def on_slash_command_error(ctx, ex): async def on_slash_command_error(ctx, ex):
logging.error(f"{ex}") logging.error(
f'Error occurred during the execution of "/{ctx.name} {ctx.subcommand_name}" by {ctx.author}: {ex}'
)
if ex == RequestFailure:
message = (f"Request to Discord API failed: {ex}",)
elif ex == IncorrectFormat:
message = (f"Incorrect format: {ex}",)
elif ex == NotFound:
message = (
f"404 Not Found - I couldn't find the interaction or it took me longer than 3 seconds to respond: {ex}",
)
else:
message = f"Error occurred during the execution of '/{ctx.name} {ctx.subcommand_name}': {ex}"
await ctx.send(
@bot.event message + "\nIf this persists, please make an issue on "
async def on_command_error(ctx, error): "[the GitHub repo](https://github.com/TheLovinator1/discord-reminder-bot/issues) or contact TheLovinator#9276",
if isinstance(error, commands.CommandNotFound): hidden=True,
return )
await ctx.send(error)
@bot.event @bot.event
@ -175,7 +181,7 @@ 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 the corresponding number to the reminder you wish to remove. Type Exit to exit."
) )
def check(m): def check(m):
@ -184,7 +190,9 @@ async def remind_remove(ctx: SlashContext):
try: try:
response_message = await bot.wait_for("message", check=check, timeout=60) response_message = await bot.wait_for("message", check=check, timeout=60)
except TimeoutError: except TimeoutError:
return await ctx.send("Timed out, try again.") return await ctx.channel.send("Timed out, try again.")
if response_message.clean_content == "Exit":
return await ctx.channel.send("Exited.")
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:
@ -199,26 +207,22 @@ async def remind_remove(ctx: SlashContext):
channel_name = bot.get_channel(int(channel_id)) channel_name = bot.get_channel(int(channel_id))
message = job.kwargs.get("message") message = job.kwargs.get("message")
try: # Only normal reminders have trigger.run_date, cron and interval has next_run_time
if type(job.trigger) is DateTrigger:
trigger_time = job.trigger.run_date trigger_time = job.trigger.run_date
msg = ( else:
f"**Removed** {job_from_dict}.\n" trigger_time = job.next_run_time
f"**Time**: {trigger_time.strftime('%Y-%m-%d %H:%M')} (in {calc_countdown(job_from_dict)})\n"
f"**Channel**: #{channel_name}\n"
f"**Message**: {message}"
)
# TODO: Add countdown # Paused reminders returns None
except AttributeError: if trigger_time is None:
next_run = job.next_run_time trigger_value = "Paused - can be resumed with '/remind resume'"
msg = ( else:
f"**Removed** {job_from_dict}.\n" trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job.id)})'
f"**Next run**: {next_run.strftime('%Y-%m-%d %H:%M')}\n"
f"**Channel**: #{channel_name}\n" msg = (
f"**Message**: {message}" f"**Removed** {message} in #{channel_name}.\n"
) f"**Time**: {trigger_value}"
except Exception as e: )
await ctx.channel.send(e)
try: try:
scheduler.remove_job(job_from_dict) scheduler.remove_job(job_from_dict)
@ -228,7 +232,7 @@ async def remind_remove(ctx: SlashContext):
await ctx.channel.send(msg) await ctx.channel.send(msg)
def make_list(ctx): def make_list(ctx, skip_datetriggers=False):
jobs_dict = {} jobs_dict = {}
job_number = 0 job_number = 0
embed = discord.Embed( embed = discord.Embed(
@ -247,21 +251,26 @@ def make_list(ctx):
job_number += 1 job_number += 1
jobs_dict[job_number] = job.id jobs_dict[job_number] = job.id
message = job.kwargs.get("message") message = job.kwargs.get("message")
# Only normal reminders have trigger.run_date, cron and interval has next_run_time
if type(job.trigger) is DateTrigger: if type(job.trigger) is DateTrigger:
trigger_time = job.trigger.run_date trigger_time = job.trigger.run_date
embed.add_field( if skip_datetriggers:
name=f"{job_number}) {message} in #{channel_name}", continue
value=f"{trigger_time.strftime('%Y-%m-%d %H:%M')} (in {calc_countdown(job.id)})", else:
inline=False, trigger_time = job.next_run_time
)
if type(job.trigger) is IntervalTrigger or CronTrigger: # Paused reminders returns None
next_run = job.next_run_time if trigger_time is None:
embed.add_field( trigger_value = "Paused - can be resumed with '/remind resume'"
name=f"{job_number}) {message} in #{channel_name}", else:
# TODO: Fix countdown trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job.id)})'
value=f"{next_run.strftime('%Y-%m-%d %H:%M')} (in {calc_countdown(job.id)})",
inline=False, embed.add_field(
) name=f"{job_number}) {message} in #{channel_name}",
value=f"{trigger_value}",
inline=False,
)
return embed, jobs_dict return embed, jobs_dict
@ -285,39 +294,61 @@ async def remind_list(ctx: SlashContext):
name="pause", name="pause",
description="Pause reminder. For cron or interval.", description="Pause reminder. For cron or interval.",
) )
async def remind_pause(ctx: SlashContext, remind_id: str): async def remind_pause(ctx: SlashContext):
job = scheduler.get_job(remind_id) list_embed, jobs_dict = make_list(ctx, skip_datetriggers=True)
if job is None:
await ctx.send(f"No reminder with that ID ({remind_id}).")
return
channel_id = job.kwargs.get("channel_id") # The empty embed has 76 characters
channel_name = bot.get_channel(int(channel_id)) if len(list_embed) <= 76:
message = job.kwargs.get("message") await ctx.send(f"{ctx.guild.name} has no reminders.")
else:
try: await ctx.send(embed=list_embed)
scheduler.pause_job(remind_id) await ctx.channel.send(
except Exception as e: "Type the corresponding number to the reminder you wish to pause. Type Exit to exit."
await ctx.send(e)
try:
trigger_time = job.trigger.run_date
msg = (
f"**Paused** {remind_id}.\n"
f"**Time**: {trigger_time.strftime('%Y-%m-%d %H:%M')} (in {calc_countdown(remind_id)})\n"
f"**Channel**: #{channel_name}\n"
f"**Message**: {message}"
) )
except AttributeError:
msg = (
f"**Paused** {remind_id}.\n"
f"**Time**: Cronjob\n"
f"**Channel**: #{channel_name}\n"
f"**Message**: {message}"
)
except Exception as e:
await ctx.send(e)
await ctx.send(msg) def check(m):
return m.author == ctx.author and m.channel == ctx.channel
try:
response_message = await bot.wait_for("message", check=check, timeout=60)
except TimeoutError:
return await ctx.channel.send("Timed out, try again.")
if response_message.clean_content == "Exit":
return await ctx.channel.send("Exited.")
for num, job_from_dict in jobs_dict.items():
if int(response_message.clean_content) == num:
job = scheduler.get_job(job_from_dict)
channel_id = job.kwargs.get("channel_id")
channel_name = bot.get_channel(int(channel_id))
message = job.kwargs.get("message")
# Only normal reminders have trigger.run_date, cron and interval has next_run_time
if type(job.trigger) is DateTrigger:
trigger_time = job.trigger.run_date
else:
trigger_time = job.next_run_time
# Paused reminders returns None
if trigger_time is None:
return await ctx.channel.send(
f"{response_message.clean_content} | {message} in #{channel_name} is already paused."
)
else:
trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job.id)})'
msg = (
f"**Paused** {message} in #{channel_name}.\n"
f"**Time**: {trigger_value}"
)
try:
print("Paused")
scheduler.pause_job(job_from_dict)
except Exception as e:
await ctx.channel.send(e)
await ctx.channel.send(msg)
@slash.subcommand( @slash.subcommand(
@ -325,39 +356,62 @@ async def remind_pause(ctx: SlashContext, remind_id: str):
name="resume", name="resume",
description="Resume paused reminder. For cron or interval.", description="Resume paused reminder. For cron or interval.",
) )
async def remind_resume(ctx: SlashContext, remind_id: str): async def remind_resume(ctx: SlashContext):
job = scheduler.get_job(remind_id) list_embed, jobs_dict = make_list(ctx, skip_datetriggers=True)
if job is None:
await ctx.send(f"No reminder with that ID ({remind_id}).")
return
channel_id = job.kwargs.get("channel_id") # The empty embed has 76 characters
channel_name = bot.get_channel(int(channel_id)) if len(list_embed) <= 76:
message = job.kwargs.get("message") await ctx.send(f"{ctx.guild.name} has no reminders.")
else:
try: await ctx.send(embed=list_embed)
scheduler.resume_job(remind_id) await ctx.channel.send(
except Exception as e: "Type the corresponding number to the reminder you wish to pause. Type Exit to exit."
await ctx.send(e)
try:
trigger_time = job.trigger.run_date
msg = (
f"**Resumed** {remind_id}.\n"
f"**Time**: {trigger_time.strftime('%Y-%m-%d %H:%M')} (in {calc_countdown(remind_id)})\n"
f"**Channel**: #{channel_name}\n"
f"**Message**: {message}"
) )
except AttributeError:
msg = (
f"**Resumed** {remind_id}.\n"
f"**Time**: Cronjob\n"
f"**Channel**: #{channel_name}\n"
f"**Message**: {message}"
)
except Exception as e:
await ctx.send(e)
await ctx.send(msg) def check(m):
return m.author == ctx.author and m.channel == ctx.channel
try:
response_message = await bot.wait_for("message", check=check, timeout=60)
except TimeoutError:
return await ctx.channel.send("Timed out, try again.")
if response_message == "Exit":
return await ctx.channel.send("Exited.")
for num, job_from_dict in jobs_dict.items():
if int(response_message.clean_content) == num:
job = scheduler.get_job(job_from_dict)
if job is None:
await ctx.send(f"No reminder with that ID ({job_from_dict}).")
return
channel_id = job.kwargs.get("channel_id")
channel_name = bot.get_channel(int(channel_id))
message = job.kwargs.get("message")
try:
scheduler.resume_job(job_from_dict)
except Exception as e:
await ctx.send(e)
# Only normal reminders have trigger.run_date, cron and interval has next_run_time
if type(job.trigger) is DateTrigger:
trigger_time = job.trigger.run_date
else:
trigger_time = job.next_run_time
# Paused reminders returns None
if trigger_time is None:
trigger_value = "Paused - can be resumed with '/remind resume'"
else:
trigger_value = f'{trigger_time.strftime("%Y-%m-%d %H:%M")} (in {calc_countdown(job.id)})'
msg = (
f"**Resumed** {message} in #{channel_name}.\n"
f"**Time**: {trigger_value}\n"
)
await ctx.send(msg)
@slash.subcommand( @slash.subcommand(
@ -510,7 +564,7 @@ async def remind_cron(
timezone=None, timezone=None,
jitter=None, jitter=None,
): ):
scheduler.add_job( job = scheduler.add_job(
send_to_discord, send_to_discord,
"cron", "cron",
year=year, year=year,
@ -533,9 +587,8 @@ async def remind_cron(
) )
# TODO: Add arguments # TODO: Add arguments
# TODO: Fix countdown
message = ( message = (
f"Hello {ctx.author.display_name}, first run in [TODO: Fix this]\n" f"Hello {ctx.author.display_name}, first run in {calc_countdown(job.id)}\n"
f"With the message:\n**{message_reason}**." f"With the message:\n**{message_reason}**."
) )
@ -622,7 +675,7 @@ async def remind_interval(
timezone=None, timezone=None,
jitter=None, jitter=None,
): ):
scheduler.add_job( job = scheduler.add_job(
send_to_discord, send_to_discord,
"interval", "interval",
weeks=weeks, weeks=weeks,
@ -643,7 +696,7 @@ async def remind_interval(
# TODO: Add arguments # TODO: Add arguments
message = ( message = (
f"Hello {ctx.author.display_name}, first run in [TODO: Fix this]\n" f"Hello {ctx.author.display_name}, first run in {calc_countdown(job.id)})\n"
f"With the message:\n**{message_reason}**." f"With the message:\n**{message_reason}**."
) )