-
-
Notifications
You must be signed in to change notification settings - Fork 750
Fix off-by-one errors and silent reminder deletion in reminders.py #3509
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| from discord.ext.commands import Cog, Context, Greedy, group | ||
| from pydis_core.site_api import ResponseCodeError | ||
| from pydis_core.utils import scheduling | ||
| from pydis_core.utils.channel import get_or_fetch_channel | ||
| from pydis_core.utils.members import get_or_fetch_member | ||
| from pydis_core.utils.scheduling import Scheduler | ||
|
|
||
|
|
@@ -232,7 +233,7 @@ async def cog_load(self) -> None: | |
| now = datetime.now(UTC) | ||
|
|
||
| for reminder in response: | ||
| is_valid, *_ = self.ensure_valid_reminder(reminder) | ||
| is_valid, *_ = await self.ensure_valid_reminder(reminder) | ||
| if not is_valid: | ||
| continue | ||
|
|
||
|
|
@@ -244,19 +245,28 @@ async def cog_load(self) -> None: | |
| else: | ||
| self.schedule_reminder(reminder) | ||
|
|
||
| def ensure_valid_reminder(self, reminder: dict) -> tuple[bool, discord.TextChannel]: | ||
| """Ensure reminder channel can be fetched otherwise delete the reminder.""" | ||
| channel = self.bot.get_channel(reminder["channel_id"]) | ||
| is_valid = True | ||
| async def ensure_valid_reminder(self, reminder: dict) -> tuple[bool, discord.TextChannel | None]: | ||
| """Ensure reminder channel can be fetched otherwise notify the user and delete the reminder.""" | ||
| try: | ||
| channel = await get_or_fetch_channel(self.bot, reminder["channel_id"]) | ||
| except discord.HTTPException: | ||
| channel = None | ||
|
|
||
| if not channel: | ||
| is_valid = False | ||
| log.info( | ||
| f"Reminder {reminder['id']} invalid: " | ||
| f"Channel {reminder['channel_id']}={channel}." | ||
| f"Channel {reminder['channel_id']} could not be fetched." | ||
| ) | ||
| user = self.bot.get_user(reminder["author"]) | ||
| if user: | ||
| await user.send( | ||
| f"Your reminder could not be delivered because the channel it was set in " | ||
| f"is no longer accessible.\n**Reminder content:** {reminder['content']}" | ||
| ) | ||
|
Comment on lines
+260
to
+265
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also be attempting to DM people that were also scheduled to be mentioned in the reminder? (in reminder['mentions']`)? |
||
| scheduling.create_task(self.bot.api_client.delete(f"bot/reminders/{reminder['id']}")) | ||
| return False, None | ||
|
|
||
| return is_valid, channel | ||
| return True, channel | ||
|
|
||
| @staticmethod | ||
| async def _send_confirmation( | ||
|
|
@@ -357,7 +367,7 @@ async def add_mention_opt_in(self, reminder: dict, user_id: int) -> dict: | |
| @lock_arg(LOCK_NAMESPACE, "reminder", itemgetter("id"), raise_error=True) | ||
| async def send_reminder(self, reminder: dict, expected_time: time.Timestamp | None = None) -> None: | ||
| """Send the reminder.""" | ||
| is_valid, channel = self.ensure_valid_reminder(reminder) | ||
| is_valid, channel = await self.ensure_valid_reminder(reminder) | ||
| if not is_valid: | ||
| # No need to cancel the task too; it'll simply be done once this coroutine returns. | ||
| return | ||
|
|
@@ -475,7 +485,7 @@ async def new_reminder( | |
|
|
||
| # Let's limit this, so we don't get 10 000 | ||
| # reminders from kip or something like that :P | ||
| if len(active_reminders) > MAXIMUM_REMINDERS: | ||
| if len(active_reminders) >= MAXIMUM_REMINDERS: | ||
| await send_denial(ctx, "You have too many active reminders!") | ||
| return | ||
|
|
||
|
|
@@ -659,7 +669,7 @@ async def _delete_reminder(self, ctx: Context, id_: int) -> bool: | |
| @remind_group.command("delete", aliases=("remove", "cancel")) | ||
| async def delete_reminder(self, ctx: Context, ids: Greedy[int]) -> None: | ||
| """Delete up to (and including) 5 of your active reminders.""" | ||
| if len(ids) > 5: | ||
| if len(ids) >= 5: | ||
| await send_denial(ctx, "You can only delete a maximum of 5 reminders at once.") | ||
| return | ||
|
Comment on lines
671
to
674
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, surely this change is wrong... If you can delete up to 5 reminders, you only deny if there are |
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should be more specific about the exceptions we catch here, e.g. just notfound and forbidden, to try and avoid cancelling reminders in the case of a discord outage.