diff options
| author | 2021-03-28 23:01:55 +0100 | |
|---|---|---|
| committer | 2021-03-28 23:01:55 +0100 | |
| commit | bdfeef5d16ff64a7ca8a9a610d39a654f2e1fb99 (patch) | |
| tree | 040a9aa86c48acf9dc28f1cdfd633759ba8e9d7f /bot/exts | |
| parent | Merge pull request #635 from python-discord/remove-broken-link (diff) | |
Rework bookmark command to allow other users to bookmark the same message.
Diffstat (limited to 'bot/exts')
| -rw-r--r-- | bot/exts/evergreen/bookmark.py | 116 | 
1 files changed, 95 insertions, 21 deletions
| diff --git a/bot/exts/evergreen/bookmark.py b/bot/exts/evergreen/bookmark.py index 5fa05d2e..d26c4845 100644 --- a/bot/exts/evergreen/bookmark.py +++ b/bot/exts/evergreen/bookmark.py @@ -1,14 +1,18 @@ +import asyncio  import logging  import random  import discord  from discord.ext import commands -from bot.constants import Colours, ERROR_REPLIES, Emojis, Icons +from bot.constants import Colours, ERROR_REPLIES, Icons  from bot.utils.converters import WrappedMessageConverter  log = logging.getLogger(__name__) +# Number of seconds to wait for other users to bookmark the same message +TIMEOUT = 120 +  class Bookmark(commands.Cog):      """Creates personal bookmarks by relaying a message link to the user's DMs.""" @@ -16,6 +20,64 @@ class Bookmark(commands.Cog):      def __init__(self, bot: commands.Bot):          self.bot = bot +    @staticmethod +    def build_bookmark_dm(target_message: WrappedMessageConverter, title: str) -> discord.Embed: +        """Builds the embed to DM the bookmark requestor.""" +        embed = discord.Embed( +            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.avatar_url) +        embed.set_thumbnail(url=Icons.bookmark) + +        return embed + +    @staticmethod +    def build_error_embed(user: discord.Member) -> discord.Embed: +        """Builds an error embed for when a bookmark requestor has DMs disabled.""" +        return discord.Embed( +            title=random.choice(ERROR_REPLIES), +            description=f"{user.mention}, please enable your DMs to receive the bookmark", +            colour=Colours.soft_red +        ) + +    async def action_bookmark( +        self, +        channel: discord.TextChannel, +        user: discord.Member, +        target_message: WrappedMessageConverter, +        title: str +    ) -> None: +        """Sends the bookmark DM, or sends an error embed when a user bookmarks a message.""" +        try: +            embed = self.build_bookmark_dm(target_message, title) +            await user.send(embed=embed) +        except discord.Forbidden: +            error_embed = self.build_error_embed(user) +            await channel.send(embed=error_embed) +        else: +            log.info(f"{user} bookmarked {target_message.jump_url} with title '{title}'") + +    @staticmethod +    async def send_reaction_embed( +        channel: discord.TextChannel, +        target_message: WrappedMessageConverter +    ) -> discord.Message: +        """Sends an embed, with a reaction, so users can react to bookmark the message too.""" +        message = await channel.send( +            embed=discord.Embed( +                description=( +                    f"React with 📌 to be sent your very own bookmark to [this message]({target_message.jump_url})." +                ), +                colour=Colours.soft_green +            ) +        ) + +        await message.add_reaction("📌") +        return message +      @commands.command(name="bookmark", aliases=("bm", "pin"))      async def bookmark(          self, @@ -37,27 +99,39 @@ class Bookmark(commands.Cog):              await ctx.send(embed=embed)              return -        embed = discord.Embed( -            title=title, -            colour=Colours.soft_green, -            description=target_message.content -        ) -        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.avatar_url) -        embed.set_thumbnail(url=Icons.bookmark) - -        try: -            await ctx.author.send(embed=embed) -        except discord.Forbidden: -            error_embed = discord.Embed( -                title=random.choice(ERROR_REPLIES), -                description=f"{ctx.author.mention}, please enable your DMs to receive the bookmark", -                colour=Colours.soft_red +        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 📌 emoji +                    str(reaction_.emoji) == "📌", +                    # Reaction was not made by the Bot +                    user_.id != self.bot.user.id +                ))              ) -            await ctx.send(embed=error_embed) -        else: -            log.info(f"{ctx.author} bookmarked {target_message.jump_url} with title '{title}'") -            await ctx.message.add_reaction(Emojis.envelope) +        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_message = await self.send_reaction_embed(ctx.channel, target_message) + +        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  # We're done, no reactions for the last 5 minutes +            log.trace(f"{user} has sucessfully bookmarked from a reaction, attempting to DM them.") +            await self.action_bookmark(ctx.channel, user, target_message, title) +            bookmarked_users.append(user.id) + +        # Delete the message now that we're done with it. +        await reaction_message.delete()  def setup(bot: commands.Bot) -> None: | 
