aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar hedy <[email protected]>2024-03-26 11:48:30 +0800
committerGravatar hedy <[email protected]>2024-03-26 14:29:59 +0800
commite753586ee59b9ae4f7c4a42c5b51422c158dc50d (patch)
tree6e508192268a41bde2a2b2fe6f37946c48a6b35d
parentReminders: More robust implementation of mention opt-in button (diff)
Reminders: Refactor all opt-in button related logic into View class
- More resilient handling of API errors. - Don't rely on string manipulation to disable the button.
-rw-r--r--bot/exts/utils/reminders.py78
1 files changed, 37 insertions, 41 deletions
diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py
index 277d8a3af..eafe70484 100644
--- a/bot/exts/utils/reminders.py
+++ b/bot/exts/utils/reminders.py
@@ -82,45 +82,55 @@ class ModifyReminderConfirmationView(discord.ui.View):
class OptInReminderMentionView(discord.ui.View):
"""A button to opt-in to get notified of someone else's reminder."""
- def __init__(self, cog: "Reminders", reminder: dict):
+ def __init__(self, cog: "Reminders", reminder: dict, expiration: Duration):
super().__init__()
+
self.cog = cog
self.reminder = reminder
- async def get_embed_description(self) -> str:
- """Return a string for use in the embed that shows the button."""
+ self.timeout = min(
+ (expiration - datetime.now(UTC)).total_seconds(),
+ REMINDER_MENTION_BUTTON_TIMEOUT
+ )
+ async def get_embed_description(
+ self,
+ message: str = "Click on the button to add yourself to the list of mentions."
+ ) -> str:
+ """Return a string for use in the embed that shows the button."""
description = "The following user(s) will be notified when the reminder arrives:\n"
description += " ".join([
mentionable.mention async for mentionable in self.cog.get_mentionables(
[self.reminder["author"]] + self.reminder["mentions"]
)
])
- description += "\n\nClick on the button to add yourself to the list of mentions."
+ if message:
+ description += f"\n\n{message}"
return description
@discord.ui.button(emoji="🔔", label="Notify me", style=discord.ButtonStyle.green)
- async def button_callback(self, interaction: discord.Interaction, button: discord.ui.Button) -> None:
+ async def button_callback(self, interaction: Interaction, button: discord.ui.Button) -> None:
"""The button callback."""
-
# This is required in case the reminder was edited/deleted between
# creation and the opt-in button click.
try:
- self.reminder = await self.cog.bot.api_client.get(f"bot/reminders/{self.reminder['id']}")
+ api_response = await self.cog.bot.api_client.get(f"bot/reminders/{self.reminder['id']}")
except ResponseCodeError as e:
await self.handle_api_error(interaction, button, e)
return
+ self.reminder = api_response
+
# Check whether the user should be added.
- if interaction.user.id == self.reminder['author']:
+ if interaction.user.id == self.reminder["author"]:
await interaction.response.send_message(
"As the author of that reminder, you will already be notified when the reminder arrives.",
ephemeral=True,
)
return
- if interaction.user.id in self.reminder['mentions']:
+ if interaction.user.id in self.reminder["mentions"]:
await interaction.response.send_message(
"You are already in the list of mentions for that reminder.",
ephemeral=True,
@@ -128,7 +138,7 @@ class OptInReminderMentionView(discord.ui.View):
)
return
- if len(self.reminder['mentions']) >= MAXIMUM_REMINDER_MENTION_OPT_INS:
+ if len(self.reminder["mentions"]) >= MAXIMUM_REMINDER_MENTION_OPT_INS:
await interaction.response.send_message(
"Sorry, this reminder has reached the maximum number of allowed mentions.",
ephemeral=True,
@@ -139,11 +149,13 @@ class OptInReminderMentionView(discord.ui.View):
# Add the user to the list of mentions.
try:
- self.reminder = await self.cog.add_mention_opt_in(self.reminder, interaction.user.id)
+ api_response = await self.cog.add_mention_opt_in(self.reminder, interaction.user.id)
except ResponseCodeError as e:
await self.handle_api_error(interaction, button, e)
return
+ self.reminder = api_response
+
# Confirm that it was successful.
await interaction.response.send_message(
"You were successfully added to the list of mentions for that reminder.",
@@ -156,17 +168,16 @@ class OptInReminderMentionView(discord.ui.View):
embed = interaction.message.embeds[0]
embed.description = await self.get_embed_description()
await interaction.message.edit(embed=embed)
- except:
+ except Exception:
log.trace(f"Unable to edit the interaction message for reminder #{self.reminder['id']}.")
async def handle_api_error(
self,
- interaction: discord.Interaction,
+ interaction: Interaction,
button: discord.ui.Button,
error: ResponseCodeError
) -> None:
"""Handle a ResponseCodeError from the API responsibly."""
-
log.trace(f"API returned {error.status} for reminder #{self.reminder['id']}.")
if error.status == 404:
@@ -194,29 +205,19 @@ class OptInReminderMentionView(discord.ui.View):
"An unexpected error occurred when attempting to add users."
)
- async def disable(
- self,
- interaction: discord.Interaction,
- button: discord.ui.Button,
- reason: str | None = None,
- ) -> None:
+ async def disable(self, interaction: Interaction, button: discord.ui.Button, reason: str = "") -> None:
"""Disable the button and add an optional reason to the original interaction message."""
-
button.disabled = True
embeds = interaction.message.embeds
try:
embed = embeds[0]
- embed.description = embed.description.split("\n\n", maxsplit=2)[0]
- if reason:
- embed.description += "\n\n" + reason
-
+ embed.description = await self.get_embed_description(reason)
await interaction.message.edit(embed=embed, view=self)
-
- except:
+ except Exception:
log.trace("Unable to disable the reminder notification button.")
- await interaction.message.edit(embeds=embeds, view=None)
+ await interaction.message.edit(embeds=[], view=None)
class Reminders(Cog):
@@ -354,12 +355,11 @@ class Reminders(Cog):
@lock_arg(LOCK_NAMESPACE, "reminder", itemgetter("id"), raise_error=True)
async def add_mention_opt_in(self, reminder: dict, user_id: int) -> dict:
"""Add an opt-in user to a reminder's mentions and return the edited reminder."""
-
- if user_id in reminder['mentions'] or user_id == reminder['author']:
+ if user_id in reminder["mentions"] or user_id == reminder["author"]:
return reminder
- reminder['mentions'].append(user_id)
- reminder = await self._edit_reminder(reminder['id'], {'mentions': reminder['mentions']})
+ reminder["mentions"].append(user_id)
+ reminder = await self._edit_reminder(reminder["id"], {"mentions": reminder["mentions"]})
await self._reschedule_reminder(reminder)
return reminder
@@ -534,16 +534,12 @@ class Reminders(Cog):
)
# Add a button for others to also get notified.
- view = OptInReminderMentionView(self, reminder)
-
- button_embed = discord.Embed(
- description=await view.get_embed_description(),
- )
- button_timeout = min(
- (expiration - datetime.now(UTC)).total_seconds(),
- REMINDER_MENTION_BUTTON_TIMEOUT
+ view = OptInReminderMentionView(self, reminder, expiration)
+ await ctx.send(
+ view=view,
+ delete_after=view.timeout,
+ embed=discord.Embed(description=await view.get_embed_description())
)
- await ctx.send(embed=button_embed, view=view, delete_after=button_timeout)
self.schedule_reminder(reminder)