From f0e20486c4c07a791bc29e59fc6371ce671e6294 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Mon, 27 Feb 2023 21:26:39 -0600 Subject: [PATCH 01/11] Undeprecate Bookmark Command --- bot/exts/utilities/bookmark.py | 141 ++++++++++++++++++++++++++------- 1 file changed, 113 insertions(+), 28 deletions(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 65a32203ad..d70ccb39af 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -1,16 +1,78 @@ import logging import random -from typing import Optional +from typing import Awaitable, Callable, Optional, Union import discord from discord.ext import commands from bot.bot import Bot from bot.constants import Colours, ERROR_REPLIES, Icons, Roles +from bot.utils.converters import WrappedMessageConverter from bot.utils.decorators import whitelist_override log = logging.getLogger(__name__) +MESSAGE_NOT_FOUND_ERROR = ( + "You must either provide a reference to a valid message, or reply to one." + "\n\nThe lookup strategy for a message is as follows (in order):" + "\n1. Lookup by '{channel ID}-{message ID}' (retrieved by shift-clicking on 'Copy ID')" + "\n2. Lookup by message ID (the message **must** be in the current channel)" + "\n3. Lookup by message URL" +) + + +async def dm_bookmark( + target_user: Union[discord.Member, discord.User], + target_message: discord.Message, + title: str, +) -> None: + """ + Sends the `target_message` as a bookmark to the `target_user` DMs, with `title` as the embed title.. + + Raises ``discord.Forbidden`` if the user's DMs are closed. + """ + embed = Bookmark.build_bookmark_dm(target_message, title) + message_url_view = discord.ui.View().add_item( + discord.ui.Button(label="View Message", url=target_message.jump_url) + ) + await target_user.send(embed=embed, view=message_url_view) + log.info(f"{target_user} bookmarked {target_message.jump_url} with title {title!r}") + + +class SendBookmark(discord.ui.View): + """The button that sends the bookmark to other users.""" + + def __init__( + self, + action_bookmark_function: + Callable[[Union[discord.Member, discord.User], discord.Message, str], Awaitable[None]], + author: discord.Member, + channel: discord.TextChannel, + target_message: discord.Message, + title: str, + ): + super().__init__() + + self.action_bookmark_function = action_bookmark_function + self.clicked = [author.id] + self.channel = channel + self.target_message = target_message + self.title = title + + @discord.ui.button(label="Receive Bookmark", style=discord.ButtonStyle.green) + async def button_callback(self, interaction: discord.Interaction, button: discord.ui.Button) -> None: + """The button callback.""" + if interaction.user.id in self.clicked: + await interaction.response.send_message( + "You have already received a bookmark to that message.", + ephemeral=True, + ) + return + + self.clicked.append(interaction.user.id) + await self.action_bookmark_function(interaction.user, self.target_message, self.title) + await interaction.response.send_message("You have received a bookmark to that message.", ephemeral=True) + class BookmarkForm(discord.ui.Modal): """The form where a user can fill in a custom title for their bookmark & submit it.""" @@ -32,7 +94,7 @@ async def on_submit(self, interaction: discord.Interaction) -> None: """Sends the bookmark embed to the user with the newly chosen title.""" title = self.bookmark_title.value or self.bookmark_title.default try: - await self.dm_bookmark(interaction, self.message, title) + await dm_bookmark(interaction.user, self.message, title) except discord.Forbidden: await interaction.response.send_message( embed=Bookmark.build_error_embed("Enable your DMs to receive the bookmark."), @@ -45,24 +107,6 @@ async def on_submit(self, interaction: discord.Interaction) -> None: ephemeral=True, ) - async def dm_bookmark( - self, - interaction: discord.Interaction, - target_message: discord.Message, - title: str, - ) -> None: - """ - Sends the target_message as a bookmark to the interaction user's DMs. - - Raises ``discord.Forbidden`` if the user's DMs are closed. - """ - embed = Bookmark.build_bookmark_dm(target_message, title) - message_url_view = discord.ui.View().add_item( - discord.ui.Button(label="View Message", url=target_message.jump_url) - ) - await interaction.user.send(embed=embed, view=message_url_view) - log.info(f"{interaction.user} bookmarked {target_message.jump_url} with title {title!r}") - class Bookmark(commands.Cog): """Creates personal bookmarks by relaying a message link to the user's DMs.""" @@ -105,6 +149,17 @@ def build_error_embed(message: str) -> discord.Embed: colour=Colours.soft_red, ) + @staticmethod + def build_bookmark_embed(target_message: discord.Message) -> discord.Embed: + """Build the channel embed to the bookmark requester.""" + return discord.Embed( + description=( + f"Click the button to be sent your very own bookmark to" + f"[this message]({target_message.jump_url})." + ), + colour=Colours.soft_green, + ) + async def _bookmark_context_menu_callback(self, interaction: discord.Interaction, message: discord.Message) -> None: """The callback that will be invoked upon using the bookmark's context menu command.""" permissions = interaction.channel.permissions_for(interaction.user) @@ -123,15 +178,45 @@ async def _bookmark_context_menu_callback(self, interaction: discord.Interaction @commands.guild_only() @whitelist_override(roles=(Roles.everyone,)) @commands.cooldown(1, 30, commands.BucketType.channel) - async def bookmark(self, ctx: commands.Context) -> None: - """Teach the invoker how to use the new context-menu based command for a smooth migration.""" - await ctx.send( - embed=self.build_error_embed( - "The bookmark text command has been replaced with a context menu command!\n\n" - "To bookmark a message simply right-click (press and hold on mobile) " - "on a message, open the 'Apps' menu, and click 'Bookmark'." + async def bookmark( + self, + ctx: commands.Context, + target_message: Optional[WrappedMessageConverter], + *, + title: str = "Bookmark", + ) -> None: + """ + Send the author a link to the specified message via DMs. + + Members can either give a message as an argument, or reply to a message. + + Bookmarks can subsequently be deleted by using the `bookmark delete` command in DMs. + """ + target_message: Optional[discord.Message] = target_message or getattr(ctx.message.reference, "resolved", None) + if target_message is None: + raise commands.UserInputError(MESSAGE_NOT_FOUND_ERROR) + + permissions = ctx.channel.permissions_for(ctx.author) + if not permissions.read_messages: + log.info(f"{ctx.author} tried to bookmark a message in #{ctx.channel} but has no permissions.") + embed = Bookmark.build_error_embed("You don't have permission to view this channel.") + await ctx.send(embed=embed) + return + + try: + await dm_bookmark(ctx.author, target_message, title) + except discord.Forbidden: + error_embed = self.build_error_embed( + f"{ctx.author.mention}, please enable your DMs to receive the bookmark." ) - ) + await ctx.send(embed=error_embed) + else: + log.info(f"{ctx.author.mention} bookmarked {target_message.jump_url} with title '{title}'") + + view = SendBookmark(dm_bookmark, ctx.author, ctx.channel, target_message, title) + embed = self.build_bookmark_embed(target_message) + + await ctx.send(embed=embed, view=view) @bookmark.command(name="delete", aliases=("del", "rm"), root_aliases=("unbm", "unbookmark", "dmdelete", "dmdel")) @whitelist_override(bypass_defaults=True, allow_dm=True) From d4976e3499527d331e37f20778a72de5a6934013 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Fri, 3 Mar 2023 12:04:42 -0600 Subject: [PATCH 02/11] Remove typing.Union import --- bot/exts/utilities/bookmark.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index d70ccb39af..ab457887b3 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -1,6 +1,6 @@ import logging import random -from typing import Awaitable, Callable, Optional, Union +from typing import Awaitable, Callable, Optional import discord from discord.ext import commands @@ -22,7 +22,7 @@ async def dm_bookmark( - target_user: Union[discord.Member, discord.User], + target_user: discord.Member | discord.User, target_message: discord.Message, title: str, ) -> None: @@ -45,7 +45,7 @@ class SendBookmark(discord.ui.View): def __init__( self, action_bookmark_function: - Callable[[Union[discord.Member, discord.User], discord.Message, str], Awaitable[None]], + Callable[[discord.Member | discord.User, discord.Message, str], Awaitable[None]], author: discord.Member, channel: discord.TextChannel, target_message: discord.Message, From 244be238d8d6c6bbfca29b0a2033ed23d0469f96 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Fri, 3 Mar 2023 12:06:59 -0600 Subject: [PATCH 03/11] Fix build_bookmark_embed formatting issue --- bot/exts/utilities/bookmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index ab457887b3..1af716bc7d 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -154,7 +154,7 @@ def build_bookmark_embed(target_message: discord.Message) -> discord.Embed: """Build the channel embed to the bookmark requester.""" return discord.Embed( description=( - f"Click the button to be sent your very own bookmark to" + f"Click the button to be sent your very own bookmark to " f"[this message]({target_message.jump_url})." ), colour=Colours.soft_green, From 84e2de31e21c824ed06ba23734983c32b476d645 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Sat, 18 Mar 2023 22:30:21 -0500 Subject: [PATCH 04/11] Use function --- bot/exts/utilities/bookmark.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 1af716bc7d..8d62826d93 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -1,6 +1,6 @@ import logging import random -from typing import Awaitable, Callable, Optional +from typing import Optional import discord from discord.ext import commands @@ -44,8 +44,6 @@ class SendBookmark(discord.ui.View): def __init__( self, - action_bookmark_function: - Callable[[discord.Member | discord.User, discord.Message, str], Awaitable[None]], author: discord.Member, channel: discord.TextChannel, target_message: discord.Message, @@ -53,7 +51,6 @@ def __init__( ): super().__init__() - self.action_bookmark_function = action_bookmark_function self.clicked = [author.id] self.channel = channel self.target_message = target_message @@ -70,7 +67,7 @@ async def button_callback(self, interaction: discord.Interaction, button: discor return self.clicked.append(interaction.user.id) - await self.action_bookmark_function(interaction.user, self.target_message, self.title) + await dm_bookmark(interaction.user, self.target_message, self.title) await interaction.response.send_message("You have received a bookmark to that message.", ephemeral=True) @@ -213,7 +210,7 @@ async def bookmark( else: log.info(f"{ctx.author.mention} bookmarked {target_message.jump_url} with title '{title}'") - view = SendBookmark(dm_bookmark, ctx.author, ctx.channel, target_message, title) + view = SendBookmark(ctx.author, ctx.channel, target_message, title) embed = self.build_bookmark_embed(target_message) await ctx.send(embed=embed, view=view) From 6edb2b01278386c757d7994c7388094512407e28 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Sat, 18 Mar 2023 22:35:32 -0500 Subject: [PATCH 05/11] Delete message after timeout --- bot/exts/utilities/bookmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 8d62826d93..6dd93502f4 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -213,7 +213,7 @@ async def bookmark( view = SendBookmark(ctx.author, ctx.channel, target_message, title) embed = self.build_bookmark_embed(target_message) - await ctx.send(embed=embed, view=view) + await ctx.send(embed=embed, view=view, delete_after=180) @bookmark.command(name="delete", aliases=("del", "rm"), root_aliases=("unbm", "unbookmark", "dmdelete", "dmdel")) @whitelist_override(bypass_defaults=True, allow_dm=True) From 97696a296a240175be4d83de3ff8bd5c9082ac74 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Sat, 18 Mar 2023 22:42:05 -0500 Subject: [PATCH 06/11] Handle DM closed situation --- bot/exts/utilities/bookmark.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 6dd93502f4..608d681697 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -66,9 +66,17 @@ async def button_callback(self, interaction: discord.Interaction, button: discor ) return - self.clicked.append(interaction.user.id) - await dm_bookmark(interaction.user, self.target_message, self.title) - await interaction.response.send_message("You have received a bookmark to that message.", ephemeral=True) + try: + self.clicked.append(interaction.user.id) + await dm_bookmark(interaction.user, self.target_message, self.title) + except discord.Forbidden: + await interaction.response.send_message( + embed=Bookmark.build_error_embed("Enable your DMs to receive the bookmark."), + ephemeral=True, + ) + else: + self.clicked.append(interaction.user.id) + await interaction.response.send_message("You have received a bookmark to that message.", ephemeral=True) class BookmarkForm(discord.ui.Modal): From 62f4e52e5ff7bf2875ea768c48bf276d614c5f6f Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Sat, 18 Mar 2023 22:43:04 -0500 Subject: [PATCH 07/11] Use instead of full class name --- bot/exts/utilities/bookmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 608d681697..46c00438fd 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -204,7 +204,7 @@ async def bookmark( permissions = ctx.channel.permissions_for(ctx.author) if not permissions.read_messages: log.info(f"{ctx.author} tried to bookmark a message in #{ctx.channel} but has no permissions.") - embed = Bookmark.build_error_embed("You don't have permission to view this channel.") + embed = self.build_error_embed("You don't have permission to view this channel.") await ctx.send(embed=embed) return From b442cae9973535c31dd4b8c6bd2293b178ab0145 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Wed, 26 Apr 2023 19:07:27 -0500 Subject: [PATCH 08/11] Append only on else block --- bot/exts/utilities/bookmark.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 46c00438fd..0c1607bd8c 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -67,7 +67,6 @@ async def button_callback(self, interaction: discord.Interaction, button: discor return try: - self.clicked.append(interaction.user.id) await dm_bookmark(interaction.user, self.target_message, self.title) except discord.Forbidden: await interaction.response.send_message( From d1702b5f7618402d308a020d9cb8c04e399c49d4 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Wed, 26 Apr 2023 19:17:37 -0500 Subject: [PATCH 09/11] nit --- bot/exts/utilities/bookmark.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 0c1607bd8c..0b7ce4295a 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -27,9 +27,9 @@ async def dm_bookmark( title: str, ) -> None: """ - Sends the `target_message` as a bookmark to the `target_user` DMs, with `title` as the embed title.. + Sends the `target_message` as a bookmark to the `target_user` DMs, with `title` as the embed title. - Raises ``discord.Forbidden`` if the user's DMs are closed. + Raises `discord.Forbidden` if the user's DMs are closed. """ embed = Bookmark.build_bookmark_dm(target_message, title) message_url_view = discord.ui.View().add_item( @@ -40,7 +40,7 @@ async def dm_bookmark( class SendBookmark(discord.ui.View): - """The button that sends the bookmark to other users.""" + """The button that sends a bookmark to other users.""" def __init__( self, From 0e269cb5cb2b9f1b426c551249dd190a806f888c Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Wed, 24 May 2023 15:57:52 -0500 Subject: [PATCH 10/11] Fix bug where command registers success even with DMs disabled --- bot/exts/utilities/bookmark.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index a2d1d1d48b..f6bd47cca6 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -50,7 +50,7 @@ def __init__( ): super().__init__() - self.clicked = [author.id] + self.clicked = [] self.channel = channel self.target_message = target_message self.title = title @@ -184,7 +184,7 @@ async def _bookmark_context_menu_callback(self, interaction: discord.Interaction async def bookmark( self, ctx: commands.Context, - target_message: Optional[WrappedMessageConverter], + target_message: WrappedMessageConverter | None, *, title: str = "Bookmark", ) -> None: @@ -195,7 +195,7 @@ async def bookmark( Bookmarks can subsequently be deleted by using the `bookmark delete` command in DMs. """ - target_message: Optional[discord.Message] = target_message or getattr(ctx.message.reference, "resolved", None) + target_message: discord.Message | None = target_message or getattr(ctx.message.reference, "resolved", None) if target_message is None: raise commands.UserInputError(MESSAGE_NOT_FOUND_ERROR) @@ -206,6 +206,7 @@ async def bookmark( await ctx.send(embed=embed) return + view = SendBookmark(ctx.author, ctx.channel, target_message, title) try: await dm_bookmark(ctx.author, target_message, title) except discord.Forbidden: @@ -214,9 +215,9 @@ async def bookmark( ) await ctx.send(embed=error_embed) else: + view.clicked.append(ctx.author.id) log.info(f"{ctx.author.mention} bookmarked {target_message.jump_url} with title '{title}'") - view = SendBookmark(ctx.author, ctx.channel, target_message, title) embed = self.build_bookmark_embed(target_message) await ctx.send(embed=embed, view=view, delete_after=180) From 9a9528b831ede7bae4ad311717c6b02ebf2ad8b9 Mon Sep 17 00:00:00 2001 From: Robin5605 Date: Sun, 9 Jul 2023 18:42:11 -0500 Subject: [PATCH 11/11] Fix incorrect permissions target --- bot/exts/utilities/bookmark.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index f6bd47cca6..22801d1433 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -199,9 +199,9 @@ async def bookmark( if target_message is None: raise commands.UserInputError(MESSAGE_NOT_FOUND_ERROR) - permissions = ctx.channel.permissions_for(ctx.author) + permissions = target_message.channel.permissions_for(ctx.author) if not permissions.read_messages: - log.info(f"{ctx.author} tried to bookmark a message in #{ctx.channel} but has no permissions.") + log.info(f"{ctx.author} tried to bookmark a message in #{target_message.channel} but has no permissions.") embed = self.build_error_embed("You don't have permission to view this channel.") await ctx.send(embed=embed) return