diff options
Diffstat (limited to 'bot')
| -rw-r--r-- | bot/exts/utilities/bookmark.py | 206 | 
1 files changed, 53 insertions, 153 deletions
| diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 511a3eff..65a32203 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -1,34 +1,19 @@  import logging  import random -from typing import Callable, Optional +from typing import Optional  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__) -# Number of seconds to wait for other users to bookmark the same message -TIMEOUT = 120 -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" -) - -class BookmarkTitleSelectionForm(discord.ui.Modal): -    """ -    The form where a user can fill in a custom title for their bookmark & submit it. - -    This form is only available when the command is invoked from a context menu. -    """ +class BookmarkForm(discord.ui.Modal): +    """The form where a user can fill in a custom title for their bookmark & submit it."""      bookmark_title = discord.ui.TextInput(          label="Choose a title for your bookmark (optional)", @@ -36,67 +21,47 @@ class BookmarkTitleSelectionForm(discord.ui.Modal):          default="Bookmark",          max_length=50,          min_length=0, -        required=False +        required=False,      ) -    def __init__( -            self, -            message: discord.Message, -            action_bookmark_function: Callable[[discord.TextChannel, discord.Member, discord.Message, str], None], -    ): +    def __init__(self, message: discord.Message):          super().__init__(timeout=1000, title="Name your bookmark")          self.message = message -        self.action_bookmark = action_bookmark_function      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 -        await self.action_bookmark(interaction.channel, interaction.user, self.message, title) -        embed = Bookmark.build_ephemeral_bookmark_embed(self.message) -        await interaction.response.send_message(embed=embed, ephemeral=True) - - -class LinkTargetMessage(discord.ui.View): -    """The button that relays the user to the bookmarked message.""" - -    def __init__(self, target_message: discord.Message): -        super().__init__() -        self.add_item(discord.ui.Button(label="View Message", url=target_message.jump_url)) - - -class SendBookmark(discord.ui.View): -    """The button that sends the bookmark to other users.""" - -    def __init__( -        self, -        action_bookmark_function: Callable[[discord.TextChannel, discord.Member, discord.Message, str], None], -        author: discord.Member, -        channel: discord.TextChannel, -        target_message: discord.Message, -        title: str -    ): -        super().__init__() - -        self.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.Button) -> None: -        """The button callback.""" -        if interaction.user.id in self.clicked: +        try: +            await self.dm_bookmark(interaction, self.message, title) +        except discord.Forbidden:              await interaction.response.send_message( -                "You have already received a bookmark to that message.", +                embed=Bookmark.build_error_embed("Enable your DMs to receive the bookmark."),                  ephemeral=True,              )              return -        self.clicked.append(interaction.user.id) -        await self.bookmark_function(self.channel, interaction.user, self.target_message, self.title) +        await interaction.response.send_message( +            embed=Bookmark.build_success_reply_embed(self.message), +            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. -        await interaction.response.send_message("You have received a bookmark to that message.", ephemeral=True) +        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): @@ -106,40 +71,24 @@ class Bookmark(commands.Cog):          self.bot = bot          self.book_mark_context_menu = discord.app_commands.ContextMenu(              name="Bookmark", -            callback=self._bookmark_context_menu_callback +            callback=self._bookmark_context_menu_callback,          ) -        self.bot.tree.add_command(self.book_mark_context_menu) +        self.bot.tree.add_command(self.book_mark_context_menu, guild=discord.Object(bot.guild_id))      @staticmethod -    def build_bookmark_embed(target_message: discord.Message) -> discord.Embed: -        """Build the channel embed to the bookmark requester.""" +    def build_success_reply_embed(target_message: discord.Message) -> discord.Embed: +        """Build the ephemeral reply 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, -        ) - -    @staticmethod -    def build_ephemeral_bookmark_embed(target_message: discord.Message) -> discord.Embed: -        """Build the ephemeral embed to the bookmark requester.""" -        return discord.Embed( -            description=( -                f"A bookmark for [this message]({target_message.jump_url}) " -                f"has been successfully sent your way.\n" +                f"A bookmark for [this message]({target_message.jump_url}) has been successfully sent your way."              ),              colour=Colours.soft_green,          )      @staticmethod      def build_bookmark_dm(target_message: discord.Message, title: str) -> discord.Embed: -        """Build the embed to DM the bookmark requester.""" -        embed = discord.Embed( -            title=title, -            description=target_message.content, -            colour=Colours.soft_green -        ) +        """Build the embed that is DM'd to the bookmark requester.""" +        embed = discord.Embed(title=title, description=target_message.content, colour=Colours.soft_green)          embed.set_author(              name=target_message.author,              icon_url=target_message.author.display_avatar.url, @@ -153,85 +102,36 @@ class Bookmark(commands.Cog):          return discord.Embed(              title=random.choice(ERROR_REPLIES),              description=message, -            colour=Colours.soft_red +            colour=Colours.soft_red,          ) -    async def action_bookmark( -        self, -        channel: discord.TextChannel, -        member: discord.Member, -        target_message: discord.Message, -        title: str -    ) -> None: -        """ -        Sends the given target_message as a bookmark to the member in DMs to the user. - -        Send an error embed instead if the member has DMs disabled. -        """ -        embed = self.build_bookmark_dm(target_message, title) -        try: -            await member.send(embed=embed, view=LinkTargetMessage(target_message)) -        except discord.Forbidden: -            error_embed = self.build_error_embed(f"{member.mention}, please enable your DMs to receive the bookmark.") -            await channel.send(embed=error_embed) -        else: -            log.info(f"{member} bookmarked {target_message.jump_url} with title '{title}'") -      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) -        if not interaction.channel.guild: -            embed = Bookmark.build_error_embed("This command cannot be used in DMs.") -            await interaction.response.send_message(embed=embed) -            return -          if not permissions.read_messages: -            log.info(f"{interaction.user} tried to bookmark a message in #{interaction.channel}" -                     f"but has no permissions.") -            embed = Bookmark.build_error_embed("You don't have permission to view this channel.") +            log.info( +                f"{interaction.user} tried to bookmark a message in #{interaction.channel} but doesn't have permission." +            ) +            embed = self.build_error_embed("You don't have permission to view this channel.")              await interaction.response.send_message(embed=embed)              return -        bookmark_title_form = BookmarkTitleSelectionForm( -            message=message, -            action_bookmark_function=self.action_bookmark -        ) +        bookmark_title_form = BookmarkForm(message=message)          await interaction.response.send_modal(bookmark_title_form)      @commands.group(name="bookmark", aliases=("bm", "pin"), invoke_without_command=True)      @commands.guild_only()      @whitelist_override(roles=(Roles.everyone,)) -    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 - -        await self.action_bookmark(ctx.channel, ctx.author, target_message, title) - -        view = SendBookmark(self.action_bookmark, ctx.author, ctx.channel, target_message, title) -        embed = self.build_bookmark_embed(target_message) - -        await ctx.send(embed=embed, view=view) +    @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'." +            ) +        )      @bookmark.command(name="delete", aliases=("del", "rm"), root_aliases=("unbm", "unbookmark", "dmdelete", "dmdel"))      @whitelist_override(bypass_defaults=True, allow_dm=True) | 
