コード例 #1
0
    async def post_formatted_message(
        self,
        actor: User,
        action: str,
        *,
        body: Optional[str] = None,
        link: Optional[str] = None,
        colour: int = Colours.green,
    ) -> None:
        """Format and post a message to the #log channel."""
        logger.trace(f'Creating log "{actor.id} {action}"')

        embed = Embed(
            title=(
                f"{actor} "
                f"{f'({actor.display_name}) ' if actor.display_name != actor.name else ''}"
                f"({actor.id}) {action}"
            ),
            description=body or "<no additional information provided>",
            colour=colour,
            timestamp=datetime.utcnow(),
        ).set_thumbnail(url=actor.display_avatar.url)

        if link:
            embed.url = link

        await self.post_message(embed=embed)
コード例 #2
0
    async def paginate(
        cls,
        lines: t.List[str],
        ctx: Context,
        embed: disnake.Embed,
        prefix: str = "",
        suffix: str = "",
        max_lines: t.Optional[int] = None,
        max_size: int = 500,
        scale_to_size: int = 2000,
        empty: bool = False,
        restrict_to_user: User = None,
        timeout: int = 300,
        footer_text: str = None,
        url: str = None,
        allow_empty_lines: bool = False,
    ) -> t.Optional[disnake.Message]:
        """
        Use a paginator and set of reactions to provide pagination over a set of lines.

        When used, this will send a message using `ctx.send()` and apply the pagination reactions,
        to control the embed.

        Pagination will also be removed automatically if no reaction is added for `timeout` seconds.

        The interaction will be limited to `restrict_to_user` (ctx.author by default) or
        to any user with a moderation role.

        Example:
        >>> people = ["Guido van Rossum", "Linus Torvalds", "Gurkbot", "Bjarne Stroustrup"]
        >>> e = disnake.Embed()
        >>> e.set_author(name="Ain't these people just awesome?")
        >>> await LinePaginator.paginate(people, ctx, e)
        """
        def event_check(reaction_: disnake.Reaction,
                        user_: disnake.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 == message.id,
                    # Reaction is one of the pagination emotes
                    str(reaction_.emoji) in PAGINATION_EMOJI,
                    # Reaction was not made by the Bot
                    user_.id != ctx.bot.user.id,
                    # The reaction was by a whitelisted user
                    user_.id == restrict_to_user.id,
                )))

        paginator = cls(
            prefix=prefix,
            suffix=suffix,
            max_size=max_size,
            max_lines=max_lines,
            scale_to_size=scale_to_size,
        )
        current_page = 0

        # If the `restrict_to_user` is empty then set it to the original message author.
        restrict_to_user = restrict_to_user or ctx.author

        if not lines:
            if not allow_empty_lines:
                logger.exception(
                    "`Empty lines found, raising error as `allow_empty_lines` is `False`."
                )
                raise EmptyPaginatorEmbed("No lines to paginate.")

            logger.debug(
                "Empty lines found, `allow_empty_lines` is `True`, adding 'nothing to display' as content."
            )
            lines.append("(nothing to display)")

        for line in lines:
            try:
                paginator.add_line(line, empty=empty)
            except Exception:
                logger.exception(f"Failed to add line to paginator: '{line}'.")
                raise

        logger.debug(f"Paginator created with {len(paginator.pages)} pages.")

        # Set embed description to content of current page.
        embed.description = paginator.pages[current_page]

        if len(paginator.pages) <= 1:
            if footer_text:
                embed.set_footer(text=footer_text)

            if url:
                embed.url = url

            logger.debug("Less than two pages, skipping pagination.")
            await ctx.send(embed=embed)
            return
        else:
            if footer_text:
                embed.set_footer(
                    text=
                    f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})"
                )
            else:
                embed.set_footer(
                    text=f"Page {current_page + 1}/{len(paginator.pages)}")

            if url:
                embed.url = url

            message = await ctx.send(embed=embed)

        logger.debug("Adding emoji reactions to message...")

        for emoji in PAGINATION_EMOJI:
            # Add all the applicable emoji to the message
            await message.add_reaction(emoji)

        logger.debug("Successfully added all pagination emojis to message.")

        while True:
            try:
                reaction, user = await ctx.bot.wait_for("reaction_add",
                                                        timeout=timeout,
                                                        check=event_check)
                logger.trace(f"Got reaction: {reaction}.")
            except asyncio.TimeoutError:
                logger.debug("Timed out waiting for a reaction.")
                break  # We're done, no reactions for the last 5 minutes

            if str(reaction.emoji) == DELETE_EMOJI:
                logger.debug("Got delete reaction.")
                await message.delete()
                return

            if reaction.emoji == FIRST_EMOJI:
                await message.remove_reaction(reaction.emoji, user)
                current_page = 0

                logger.debug(
                    f"Got first page reaction - changing to page 1/{len(paginator.pages)}."
                )

                embed.description = paginator.pages[current_page]
                if footer_text:
                    # Current page is zero index based.
                    embed.set_footer(
                        text=
                        f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})"
                    )
                else:
                    embed.set_footer(
                        text=f"Page {current_page + 1}/{len(paginator.pages)}")
                await message.edit(embed=embed)

            if reaction.emoji == LAST_EMOJI:
                await message.remove_reaction(reaction.emoji, user)
                current_page = len(paginator.pages) - 1

                logger.debug(
                    f"Got last page reaction - changing to page {current_page + 1}/{len(paginator.pages)}"
                )

                embed.description = paginator.pages[current_page]
                if footer_text:
                    embed.set_footer(
                        text=
                        f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})"
                    )
                else:
                    embed.set_footer(
                        text=f"Page {current_page + 1}/{len(paginator.pages)}")
                await message.edit(embed=embed)

            if reaction.emoji == LEFT_EMOJI:
                await message.remove_reaction(reaction.emoji, user)

                if current_page <= 0:
                    logger.debug(
                        "Got previous page reaction while they are on the first page, ignoring."
                    )
                    continue

                current_page -= 1
                logger.debug(
                    f"Got previous page reaction - changing to page {current_page + 1}/{len(paginator.pages)}"
                )

                embed.description = paginator.pages[current_page]

                if footer_text:
                    embed.set_footer(
                        text=
                        f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})"
                    )
                else:
                    embed.set_footer(
                        text=f"Page {current_page + 1}/{len(paginator.pages)}")
                await message.edit(embed=embed)

            if reaction.emoji == RIGHT_EMOJI:
                await message.remove_reaction(reaction.emoji, user)

                if current_page >= len(paginator.pages) - 1:
                    logger.debug(
                        "Got next page reaction while they are on the last page, ignoring."
                    )
                    continue

                current_page += 1
                logger.debug(
                    f"Got next page reaction - changing to page {current_page + 1}/{len(paginator.pages)}"
                )

                embed.description = paginator.pages[current_page]

                if footer_text:
                    embed.set_footer(
                        text=
                        f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})"
                    )
                else:
                    embed.set_footer(
                        text=f"Page {current_page + 1}/{len(paginator.pages)}")
                await message.edit(embed=embed)

        logger.debug("Ending pagination and clearing reactions.")
        with suppress(disnake.NotFound):
            await message.clear_reactions()