diff options
Diffstat (limited to '')
| -rw-r--r-- | bot/exts/utilities/bookmark.py | 131 | 
1 files changed, 77 insertions, 54 deletions
| diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 2e3458d8..3c57aa09 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -1,7 +1,6 @@ -import asyncio  import logging  import random -from typing import Optional +from typing import Callable, Optional  import discord  from discord.ext import commands @@ -15,7 +14,6 @@ log = logging.getLogger(__name__)  # Number of seconds to wait for other users to bookmark the same message  TIMEOUT = 120 -BOOKMARK_EMOJI = "📌"  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):" @@ -25,6 +23,54 @@ MESSAGE_NOT_FOUND_ERROR = (  ) +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, +        bookmark_function: Callable[ +            [discord.TextChannel, discord.Member, discord.Message, str], None +        ], +        author: discord.Member, +        channel: discord.TextChannel, +        target_message: discord.Message, +    ): +        super().__init__() + +        self.bookmark_function = bookmark_function # The function is the 'action_bookmark' +        self.clicked: list[int] = [author.id] +        self.channel = channel +        self.target_message = target_message + +     +    @discord.ui.button(label="Receive Bookmark", style=discord.ButtonStyle.green) +    async def button_callback(self, button: discord.Button, interaction: discord.Interaction) -> None: +        """The button callback.""" +        if interaction.user.id in self.clicked: +            return await interaction.response.send_message( +                "You have already received a bookmark to that message.", ephemeral=True +            ) + +        await self.bookmark_function( +            self.channel, interaction.user, self.target_message +        ) +        await interaction.response.send_message( +            "You have received a bookmark to that message.", ephemeral=True +        ) +        self.clicked.append(interaction.user.id) + +  class Bookmark(commands.Cog):      """Creates personal bookmarks by relaying a message link to the user's DMs.""" @@ -35,17 +81,13 @@ class Bookmark(commands.Cog):      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 +            title=title, description=target_message.content, colour=Colours.soft_green          ) -        embed.add_field( -            name="Wanna give it a visit?", -            value=f"[Visit original message]({target_message.jump_url})" +        embed.set_author( +            name=target_message.author, +            icon_url=target_message.author.display_avatar.url,          ) -        embed.set_author(name=target_message.author, icon_url=target_message.author.display_avatar.url)          embed.set_thumbnail(url=Icons.bookmark) -          return embed      @staticmethod @@ -57,6 +99,17 @@ class Bookmark(commands.Cog):              colour=Colours.soft_red          ) +    @staticmethod +    def create_button_embed(target_message: discord.Message) -> discord.Embed: +        """Generates the embed which is sent with the button, so other users can receive the bookmark too.""" +        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 action_bookmark(          self,          channel: discord.TextChannel, @@ -71,7 +124,7 @@ class Bookmark(commands.Cog):          """          embed = self.build_bookmark_dm(target_message, title)          try: -            await member.send(embed=embed) +            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) @@ -102,53 +155,23 @@ class Bookmark(commands.Cog):          # Prevent users from bookmarking a message in a channel they don't have access to          permissions = target_message.channel.permissions_for(ctx.author)          if not permissions.read_messages: -            log.info(f"{ctx.author} tried to bookmark a message in #{target_message.channel} but has no permissions.") -            embed = self.build_error_embed(f"{ctx.author.mention} You don't have permission to view this channel.") +            log.info( +                f"{ctx.author} tried to bookmark a message in #{target_message.channel} but has no permissions." +            ) +            embed = discord.Embed( +                title=random.choice(ERROR_REPLIES), +                color=Colours.soft_red, +                description="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) -        # Keep track of who has already bookmarked, so users can't spam reactions and cause loads of DMs -        bookmarked_users = [ctx.author.id] - -        reaction_embed = discord.Embed( -            description=( -                f"React with {BOOKMARK_EMOJI} to be sent your very own bookmark to " -                f"[this message]({ctx.message.jump_url})." -            ), -            colour=Colours.soft_green -        ) -        reaction_message = await ctx.send(embed=reaction_embed) -        await reaction_message.add_reaction(BOOKMARK_EMOJI) - -        def event_check(reaction: discord.Reaction, user: discord.Member) -> bool: -            """Make sure that this reaction is what we want to operate on.""" -            return ( -                # Conditions for a successful pagination: -                all(( -                    # Reaction is on this message -                    reaction.message.id == reaction_message.id, -                    # User has not already bookmarked this message -                    user.id not in bookmarked_users, -                    # Reaction is the `BOOKMARK_EMOJI` emoji -                    str(reaction.emoji) == BOOKMARK_EMOJI, -                    # Reaction was not made by the Bot -                    user.id != self.bot.user.id -                )) -            ) - -        while True: -            try: -                _, user = await self.bot.wait_for("reaction_add", timeout=TIMEOUT, check=event_check) -            except asyncio.TimeoutError: -                log.debug("Timed out waiting for a reaction") -                break -            log.trace(f"{user} has successfully bookmarked from a reaction, attempting to DM them.") -            await self.action_bookmark(ctx.channel, user, target_message, title) -            bookmarked_users.append(user.id) - -        await reaction_message.delete() +        view = SendBookmark(self.action_bookmark, ctx.author, ctx.channel, target_message) +         +        embed = self.create_button_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) | 
