コード例 #1
0
ファイル: misc.py プロジェクト: pikaninja/travis-bott
    async def discordstatus(self, ctx: utils.CustomContext):
        """Gets the current status of Discord."""

        async with self.bot.session.get(
                "https://discordstatus.com/history.json") as response:
            data = await response.json()
            try:
                current = data["months"][0]["incidents"][0]
            except IndexError:
                embed = Embed.warning(
                    description=
                    "There are no incidents reported this month as of yet.")
                return await ctx.send(embed=embed)
            components = data["components"]

            timestamp = re.sub(
                r"<var data-var='date'>|</var>|<var data-var='time'>", "",
                current["timestamp"])

            embeds = []

            if len(timestamp) < 17:
                main_embed = self.bot.embed(
                    ctx,
                    title="Current Status for Discord.",
                    description=("```\n" + f"Code: {current['code']}\n" +
                                 f"Name: {current['name']}\n" +
                                 f"Message: {current['message']}\n" +
                                 f"Impact: {current['impact']}\n" +
                                 f"Timestamp: {timestamp}\n" + "```"))

                main_embed.url = "https://discordstatus.com/"
                embeds.append(main_embed)

            # Thank you to Cyrus#8315 for this.
            def format_comp(mapping):
                msg = "```py\n"
                longest = None

                for key in mapping:
                    length = len(key["name"])

                    if longest is None or length > longest:
                        longest = length

                for key in mapping:
                    msg += key["name"].rjust(longest, " ") + \
                        " → " + key["status"].title() + "\n"

                msg += "```"
                return msg

            components_embed = self.bot.embed(
                ctx, title="Components", description=format_comp(components))
            embeds.append(components_embed)

            source = utils.EmbedMenu(embeds)
            menu = utils.KalPages(source)
            await menu.start(ctx)
コード例 #2
0
    async def moderations(self, ctx: utils.CustomContext):
        """Gets all of the current active mutes."""

        mutes = await self.bot.pool.fetch(
            "SELECT * FROM guild_mutes WHERE guild_id = $1", ctx.guild.id)

        fmt = []

        for mute in mutes:
            user = ctx.guild.get_member(mute["member_id"])
            dt_obj = dt.fromtimestamp(mute["end_time"])
            humanized = humanize.precisedelta(dt_obj, format="%0.0f")
            fmt.append(f"{user} | {humanized}")

        menu = utils.KalPages(ModerationsMenu(fmt), clear_reactions_after=True)
        await menu.start(ctx)
コード例 #3
0
ファイル: misc.py プロジェクト: pikaninja/travis-bott
    async def lyrics(self, ctx: utils.CustomContext, *, song_name: str):
        """Get the lyrics to any given song, if the song is found."""

        ksoft = ksoftapi.Client(self.bot.settings["keys"]["ksoft_api"])
        try:
            results = await ksoft.music.lyrics(song_name)
        except ksoftapi.NoResults:
            return await ctx.send(f"No lyrics found for {song_name}.")

        await ksoft.close()

        first = results[0]
        lyrics = first.lyrics.splitlines()

        source = LyricsPaginator(lyrics)
        menu = utils.KalPages(source)
        await menu.start(ctx)
コード例 #4
0
ファイル: misc.py プロジェクト: pikaninja/travis-bott
    async def rawmsg(self, ctx: utils.CustomContext, message: discord.Message):
        """Gets the raw JSON data of a message, if you don't know what that is, this command probably isn't for you."""

        async with self.bot.session.get(
                f"https://discord.com/api/v8/channels/{message.channel.id}/messages/{message.id}",
                headers={"Authorization": f"Bot {self.bot.http.token}"}) as r:
            if r.status != 200:
                return await ctx.send(
                    "Something went wrong... I can't really tell you why because I don't know BUT\n"
                    f"What I do know is that the status code is {r.status} so maybe that'd help."
                )

            r = await r.json()

        formatted = json.dumps(r, indent=4)
        lines = [line for line in formatted.splitlines()]

        source = RawMessagePaginator(lines)
        menu = utils.KalPages(source)
        await menu.start(ctx)
コード例 #5
0
ファイル: meta.py プロジェクト: JoJoOnDuty/travis-bott
    async def emoji(self, ctx: utils.CustomContext,
                    *emojis: utils.EmojiConverter):
        """Get's the full image of an emoji and adds some more info."""

        ret = []

        for emoji in emojis:
            embed = self.bot.embed(ctx)

            embed.title = f"Showing for {emoji.name}"
            embed.url = emoji.url
            embed.description = emoji.id or "This is a unicode emoji, therefore no ID."

            embed.set_image(url=emoji.url)
            embed.add_field(name="Animated", value=emoji.animated)

            ret.append(embed)

        source = utils.EmbedMenu(ret)
        menu = utils.KalPages(source)
        await menu.start(ctx)
コード例 #6
0
    async def warns(self, ctx: utils.CustomContext, *, user: discord.Member):
        """Get the current warns of a given user."""

        sql = "SELECT * FROM warns WHERE offender_id = $1;"
        records = await self.bot.pool.fetch(sql, user.id)
        ret = []

        for index, record in enumerate(records, start=1):
            warner = self.bot.get_user(record["moderator_id"])
            warned_at = record["time_warned"]
            warned_date = utils.format_time(warned_at)["date"]
            ret.append(
                f"`{index}` - Warned by: {warner} - Warned at: {warned_date} | {record['reason']}"
            )

        if not ret:
            raise commands.BadArgument("That user has no warns to display.")

        source = WarnsPageSource(ret)
        page = utils.KalPages(source)
        await page.start(ctx)
コード例 #7
0
ファイル: meta.py プロジェクト: JoJoOnDuty/travis-bott
    async def todo_list(self, ctx: utils.CustomContext, flag: str = None):
        """Gives a list of all of your currently set tasks.
        You can also sort them with these flags:
        `--alphabetical` - Sorts all tasks in alphabetical order.
        `--size` - Sorts all tasks by size.
        Note: If you try to delete a task that is in one of these orders you may delete another task by accident!"""

        sql = "SELECT * FROM todos WHERE user_id = $1"

        if flag:
            parser = argparse.ArgumentParser()
            parser.add_argument("--alphabetical", action="store_true")
            parser.add_argument("--size", action="store_true")

            try:
                args = parser.parse_args([flag])
            except SystemExit:
                raise commands.BadArgument(
                    "The only available flags are `--alphabetical` and `--size`."
                )

            if args.alphabetical:
                sql += " ORDER BY task ASC"
            if args.size:
                sql += " ORDER BY CHAR_LENGTH(task) ASC"

        results = await self.bot.pool.fetch(sql, ctx.author.id)

        if not results:
            raise utils.NoTodoItems("You have no to-do items I can show you.")

        todo_list = []

        for item in results:
            todo_list.append(item["task"])

        source = utils.GeneralPageSource(todo_list, per_page=10)
        paginator = utils.KalPages(source)

        await paginator.start(ctx)
コード例 #8
0
ファイル: tags.py プロジェクト: pikaninja/travis-bott
    async def tag_list(self, ctx: utils.CustomContext, *,
                       user: t.Optional[discord.Member]):
        """Gets the list of tags of a current user, or yourself.
        Example: `{prefix}tag list @kal#1806`"""

        user: discord.Member = user or ctx.author
        all_user_tags = await self.bot.pool.fetch(
            'SELECT title FROM tags WHERE author = $1 AND guild = $2', user.id,
            ctx.guild.id)

        if not all_user_tags:
            fmt: str = f'`{user.name}` has no tags to display.'
            return await ctx.send(fmt)

        all_tags = []
        for i, tag in enumerate(all_user_tags):
            all_tags.append(f'`{i + 1}`. {tag["title"]}')

        source = TagsListPageSource(user.name, all_tags)
        menu = utils.KalPages(source)

        await menu.start(ctx)
コード例 #9
0
ファイル: developer.py プロジェクト: JoJoOnDuty/travis-bott
    async def dev_sql(self, ctx: utils.CustomContext, *,
                      query: codeblock_converter):
        """Executes an SQL statement for the bot."""

        async with ctx.timeit:
            """Start timing how long it takes to process the query."""
            query = query.content

            strategy = ctx.db.fetch if query.lower().startswith(
                "select") else ctx.db.execute

            results = await strategy(
                query.format(author=ctx.author, guild=ctx.guild))

            data = []
            if isinstance(results, list):
                for result in results:
                    data.append(repr(result))
            else:
                data.append(repr(results))

            menu = utils.KalPages(SQLListPageSource(data))
            await menu.start(ctx)
コード例 #10
0
class Moderation(commands.Cog, name="moderation"):
    """Moderation Commands"""
    def __init__(self, bot):
        self.bot: utils.MyBot = bot
        self.show_name = "\N{CROSSED SWORDS} Moderation"

        self.logger = utils.create_logger(self.__class__.__name__,
                                          logging.INFO)

    async def get_warn_by_id(self, user_id: int, index: int):
        sql = "SELECT * FROM warns WHERE offender_id = $1;"
        records = await self.bot.pool.fetch(sql, user_id)

        try:
            item = records[index - 1]
        except IndexError:
            raise commands.BadArgument(
                "That user does not have a warn with that ID.")

        return item["id"]

    @commands.Cog.listener("on_member_join")
    async def persistent_mutes(self, member: discord.Member):
        is_user_muted = await self.bot.pool.fetchrow(
            "SELECT * FROM guild_mutes WHERE member_id = $1 AND guild_id = $2",
            member.id, member.guild.id)

        if not is_user_muted:
            return

        mute_role_id = self.bot.config[member.guild.id]["guild_prefix"]
        mute_role = member.guild.get_role(role_id=mute_role_id)
        await member.add_roles(mute_role, reason="Mute Role Persist")

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    async def warn(self,
                   ctx: utils.CustomContext,
                   user: discord.Member,
                   *,
                   reason: str = "No Reason Provided."):
        """Warns a given user for a given reason.
        You can do `{prefix}warns someone#1234` to view their current warns."""

        if len(reason) > 255:
            raise commands.BadArgument(
                "The warn reason must not be greater than 255 characters.")

        sql = "INSERT INTO warns VALUES(default, $1, $2, $3, $4, $5);"
        values = (ctx.guild.id, ctx.author.id, user.id, reason, dt.utcnow())
        await self.bot.pool.execute(sql, *values)

        await ctx.send(
            f"Successfully warned `{user}` for: {reason}. "
            f"Do `{ctx.prefix}warns {user}` to view their current warns.")

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    async def warns(self, ctx: utils.CustomContext, *, user: discord.Member):
        """Get the current warns of a given user."""

        sql = "SELECT * FROM warns WHERE offender_id = $1;"
        records = await self.bot.pool.fetch(sql, user.id)
        ret = []

        for index, record in enumerate(records, start=1):
            warner = self.bot.get_user(record["moderator_id"])
            warned_at = record["time_warned"]
            warned_date = utils.format_time(warned_at)["date"]
            ret.append(
                f"`{index}` - Warned by: {warner} - Warned at: {warned_date} | {record['reason']}"
            )

        if not ret:
            raise commands.BadArgument("That user has no warns to display.")

        source = WarnsPageSource(ret)
        page = utils.KalPages(source)
        await page.start(ctx)

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    async def delwarn(self, ctx: utils.CustomContext, user: discord.Member,
                      warn_id: int):
        """Deletes a warn off a given user."""

        warn_id = await self.get_warn_by_id(user.id, warn_id)

        sql = "DELETE FROM warns WHERE id = $1;"
        await self.bot.pool.execute(sql, warn_id)
        await ctx.send(f"Successfully cleared that warn for `{user}`")

    @commands.command(aliases=["tban"], disabled=True, hidden=True)
    @commands.guild_only()
    @commands.has_permissions(ban_members=True)
    @commands.bot_has_permissions(ban_members=True)
    async def tempban(self, ctx: utils.CustomContext, user: NotStaffMember,
                      how_long: utils.TimeConverter, *, reason: str):
        """Tempbans a user for a certain amount of time.
        e.g. `{prefix}tempban @kal#1806 5d Doing bad things excessively.`"""

        format_time = humanize.naturaldelta(how_long)
        await user.send(
            f"You were temporarily banned by {ctx.author} for the reason: {reason}. This ban expires in {format_time}"
        )

        sql = "INSERT INTO temp_bans VALUES($1, $2, $3, $4, $5, $6);"
        values = (str(uuid.uuid4()), ctx.guild.id, ctx.author.id, user.id,
                  reason, how_long)
        await self.bot.pool.execute(sql, *values)

        await user.ban(reason=reason)

        fmt = f"{user} was banned by {ctx.author} for {format_time} for the reason: {reason}"
        await ctx.send(fmt)

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    @commands.bot_has_permissions(manage_roles=True)
    async def mute(self, ctx: utils.CustomContext, user: NotStaffMember,
                   _time: TimeConverter, *, reason: str):
        """Mutes a given user for an amount of time (e.g. 5s/5m/5h/5d)"""

        if _time < 5:
            return await ctx.send(
                "You must provide a time that is 5 seconds or higher")

        try:
            mute_role_id = self.bot.config[ctx.guild.id]["mute_role_id"]
            mute_role = ctx.guild.get_role(mute_role_id)
        except KeyError:

            def predicate(r):
                return r.name.lower() == "muted"

            mute_role = discord.utils.find(predicate=predicate,
                                           seq=ctx.guild.roles)

            self.bot.config[ctx.guild.id]["mute_role_id"] = mute_role.id

            await self.bot.pool.execute(
                "UPDATE guild_settings SET mute_role_id = $1 WHERE guild_id = $2",
                mute_role.id, ctx.guild.id)

        if mute_role is None:
            mute_role = await ctx.guild.create_role(name="Muted")

            await ctx.channel.set_permissions(mute_role, send_messages=False)

            await self.bot.pool.execute(
                "UPDATE guild_settings SET mute_role_id = $1 WHERE guild_id = $2",
                mute_role.id, ctx.guild.id)

            self.bot.config[ctx.guild.id]["mute_role_id"] = mute_role.id

        await user.add_roles(mute_role, reason=f"Muted by: {ctx.author}")
        await utils.set_mute(bot=self.bot,
                             guild_id=ctx.guild.id,
                             user_id=user.id,
                             _time=_time)

        end_time = int(t() + _time)
        await self.bot.pool.execute(
            "INSERT INTO guild_mutes VALUES($1, $2, $3)", ctx.guild.id,
            user.id, end_time)

        timestamp = t() + _time
        dt_obj = dt.fromtimestamp(timestamp)
        humanized = humanize.precisedelta(dt_obj, format="%0.0f")

        embed = self.bot.embed(ctx)
        embed.description = (
            f"{ctx.author.mention} ({ctx.author}) has muted {user.mention} ({user}) for {humanized} for the reason: "
            f"{reason}")

        await ctx.send(embed=embed)

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    @commands.bot_has_permissions(manage_roles=True)
    async def unmute(self, ctx: utils.CustomContext, user: discord.Member):
        """Unmutes a given user if they have the guilds set muted role."""

        try:
            mute_role_id = self.bot.config[ctx.guild.id]["mute_role_id"]
            mute_role = ctx.guild.get_role(mute_role_id)
        except KeyError:

            def predicate(r):
                return r.name.lower() == "muted"

            mute_role = discord.utils.find(predicate=predicate,
                                           seq=ctx.guild.roles)

            self.bot.config[ctx.guild.id]["mute_role_id"] = mute_role.id

            await self.bot.pool.execute(
                "UPDATE guild_settings SET mute_role_id = $1 WHERE guild_id = $2",
                mute_role.id, ctx.guild.id)

        if mute_role not in user.roles:
            return await ctx.send(
                "That user does not have the guilds set muted role.")

        await user.remove_roles(mute_role, reason=f"Unmuted by: {ctx.author}")
        embed = self.bot.embed(ctx)
        embed.description = f"{ctx.author.mention} ({ctx.author}) unmuted {user.mention} ({user})"

        await ctx.send(embed=embed)

    @commands.command()
    @commands.has_permissions(manage_messages=True)
    @commands.bot_has_permissions(send_messages=True)
    async def moderations(self, ctx: utils.CustomContext):
        """Gets all of the current active mutes."""

        mutes = await self.bot.pool.fetch(
            "SELECT * FROM guild_mutes WHERE guild_id = $1", ctx.guild.id)

        fmt = []

        for mute in mutes:
            user = ctx.guild.get_member(mute["member_id"])
            dt_obj = dt.fromtimestamp(mute["end_time"])
            humanized = humanize.precisedelta(dt_obj, format="%0.0f")
            fmt.append(f"{user} | {humanized}")

        menu = utils.KalPages(ModerationsMenu(fmt), clear_reactions_after=True)
        await menu.start(ctx)

    @commands.command(aliases=["unbanall"])
    @commands.guild_only()
    @commands.has_permissions(manage_guild=True)
    @commands.bot_has_permissions(ban_members=True)
    async def massunban(self, ctx: utils.CustomContext):
        """Gives a prompt to unban everyone.
        Permissions needed: `Manage Server`"""
        def check(m):
            return m.author == ctx.author and m.channel == ctx.channel

        await ctx.send(
            "Are you sure you would like to unban everyone? (10 Seconds)")
        try:
            user_input = await self.bot.wait_for("message",
                                                 timeout=10.0,
                                                 check=check)
        except asyncio.TimeoutError:
            return await ctx.send(
                f"{ctx.author.mention} you did not reply in time.")
        else:
            user_reply = user_input.content.lower()
            if user_reply != "yes":
                return await ctx.send("Ok, backing out.")
            if user_reply == "yes":
                await ctx.send("Ok, this may take a bit.")
                bans = await ctx.guild.bans()
                for ban in bans:
                    user = ban.user
                    await ctx.guild.unban(
                        user,
                        reason=f"Mass Unban | Responsible User: {ctx.author}")
                await ctx.send(
                    f"Successfully unbanned {sum(1 for ban in bans)} people")

    @commands.command(aliases=["barn", "banish"])
    @commands.guild_only()
    @commands.has_permissions(ban_members=True)
    @commands.bot_has_permissions(ban_members=True)
    async def ban(self,
                  ctx: utils.CustomContext,
                  user: MemberOrID,
                  *,
                  reason: str = "No reason provided."):
        """Bans someone for a given reason.
        Permissions needed: `Ban Members`"""

        await ctx.guild.ban(
            user, reason=f"{reason} | Responsible User: {ctx.author}")
        await ctx.thumbsup()

    @commands.command(aliases=["unbarn", "unbanish"])
    @commands.has_permissions(ban_members=True)
    @commands.bot_has_permissions(ban_members=True)
    async def unban(self, ctx: utils.CustomContext, user: BannedUser):
        """Unbans a given user.
        Permissions needed: `Ban Members`"""

        await ctx.guild.unban(
            user,
            reason=f"Responsible User: {ctx.author}",
        )
        await ctx.thumbsup()

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(kick_members=True)
    @commands.bot_has_permissions(kick_members=True)
    async def kick(self,
                   ctx: utils.CustomContext,
                   user: NotStaffMember,
                   *,
                   reason: str = "No reason provided."):
        """Kicks a user for a given reason.
        Permissions needed: `Kick Members`"""

        await user.kick(reason=f"{reason} | Responsible User: {ctx.author}")
        await ctx.thumbsup()

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    @commands.bot_has_permissions(manage_nicknames=True)
    async def setnick(self,
                      ctx: utils.CustomContext,
                      user: discord.Member,
                      *,
                      new_name: str = None):
        """Sets a new nickname for a given user.
        Permissions needed: `Manage Messages`"""

        try:
            if len(new_name) > 32:
                new_name = new_name[:len(new_name) - (len(new_name) - 32)]
            await user.edit(nick=new_name,
                            reason=f"Responsible User: {ctx.author}")
        except discord.Forbidden:
            return await ctx.send(
                "I was unable to change the nickname for that user.")

        await ctx.thumbsup()

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    @commands.bot_has_permissions(send_messages=True)
    async def members(self, ctx: utils.CustomContext, *, role: Role):
        """Check the list of members in a certain role.
        Permissions needed: `Manage Messages`"""

        in_role = []
        [
            in_role.append(f"{member.mention} ({member})")
            for member in role.members
        ]
        columns = [in_role, ["\u200b"]]
        if len(in_role) > 1:
            columns[0], columns[1] = utils.split_list(in_role)
            columns.sort(reverse=True)

        if len("\n".join(columns[0])) > 1024:
            columns[0] = columns[0][:20]

        if len("\n".join(columns[1])) > 1024:
            columns[1] = columns[1][:20]

        embed = self.bot.embed(
            ctx,
            title=f"Members in {role.name} [{sum(1 for m in role.members)}]")
        [
            embed.add_field(name="\u200b",
                            value="\n".join(column) if column else "\u200b")
            for column in columns
        ]

        await ctx.send(embed=embed)

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    @commands.bot_has_permissions(manage_messages=True)
    async def clean(self, ctx: utils.CustomContext):
        """Cleans all 100 previous bot messages.
        Permissions needed: `Manage Messages`"""

        await ctx.message.delete()

        def check(m):
            return m.author.bot

        await ctx.channel.purge(limit=100, check=check, bulk=True)

    @commands.command()
    @commands.guild_only()
    @commands.has_permissions(manage_messages=True)
    @commands.bot_has_permissions(manage_messages=True)
    async def purge(self, ctx: utils.CustomContext, amount: int):
        """Purges a given amount of messages
        Permissions needed: `Manage Messages`"""

        await ctx.message.delete()
        await ctx.channel.purge(limit=amount)

    @commands.group(invoke_without_command=True)
    @commands.guild_only()
    @commands.has_permissions(manage_roles=True)
    @commands.bot_has_permissions(manage_roles=True)
    async def role(self, ctx: utils.CustomContext, user: discord.Member,
                   *roles: Role):
        """
        Give someone a role.

        Permissions needed: `Manage Roles`
        To give multiple roles, this is the syntax:
        `{prefix}role @kal#1806 "role one" role2 role`
        """

        mr_ids = [
            622258457785008150,
            668232158862639134,
            622267750232096808,
            703780954602471445,
            735699294174183454,
        ]

        modifiers = []

        current_roles = user.roles

        for role in roles:
            if role.id in mr_ids:
                continue
            if role in user.roles:
                modifiers.append(f"-{role.mention}")
                current_roles.remove(role)
            else:
                modifiers.append(f"+{role.mention}")
                current_roles.append(role)

        await user.edit(roles=current_roles)
        await ctx.thumbsup()

        embed = self.bot.embed(
            ctx,
            title="Updated Member Roles",
            description=f"{user.mention} | {' '.join(modifiers)}",
        )
        await ctx.send(embed=embed)

    @role.command(name="add")
    @commands.guild_only()
    @commands.has_permissions(manage_roles=True)
    @commands.bot_has_permissions(manage_roles=True)
    async def role_add(self, ctx: utils.CustomContext, *, role: str):
        """Adds a new role with a given name."""

        await ctx.guild.create_role(name=role,
                                    reason=f"Responsible User: {ctx.author}")
        await ctx.thumbsup()

    @role.command(name="del")
    @commands.guild_only()
    @commands.has_permissions(manage_roles=True)
    @commands.bot_has_permissions(manage_roles=True)
    async def role_del(self, ctx: utils.CustomContext, *, role: Role):
        """Deletes a given role."""

        await role.delete(reason=f"Responsible User: {ctx.author}")
        await ctx.thumbsup()

    @role.command(name="colour", aliases=["color"])
    @commands.guild_only()
    @commands.has_permissions(manage_roles=True)
    @commands.bot_has_permissions(manage_roles=True)
    async def role_colour(self, ctx: utils.CustomContext, role: Role,
                          colour: str):
        """Sets the colour of a given role."""

        hex_regex = r"^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"

        if not re.match(hex_regex, colour):
            return await ctx.send(
                "The colour must be a properly formed **hex** colour.")

        hex_to_rgb = utils.hex_to_rgb(colour[1:])
        colour = discord.Colour.from_rgb(hex_to_rgb[0], hex_to_rgb[1],
                                         hex_to_rgb[2])
        await role.edit(colour=colour)
        await ctx.thumbsup()

    @role.command(name="info")
    @commands.guild_only()
    @commands.has_permissions(manage_roles=True)
    @commands.bot_has_permissions(send_messages=True)
    async def role_info(self, ctx: utils.CustomContext, *roles: Role):
        """Get information on a given role."""

        embed_list = []

        for role in roles:
            role_perms = []

            permissions_dict = {
                "kick_members": "Kick Members",
                "ban_members": "Ban Members",
                "administrator": "Administrator",
                "manage_channels": "Manage Channels",
                "manage_guild": "Manage Server",
                "manage_messages": "Manage Messages",
                "mention_everyone": "Mention Everyone",
                "mute_members": "Mute Members (VC)",
                "deafen_members": "Deafen Members (VC)",
                "move_members": "Move Members (VC)",
                "manage_nicknames": "Manage Nicknames",
                "manage_roles": "Manage Roles"
            }

            permissions = dict(role.permissions)

            for permission, true_false in permissions.items():
                if true_false is True:
                    if (perm :=
                            permissions_dict.get(str(permission))) is not None:
                        role_perms.append(f"✅ {perm}")

            repr_permissions = '\n'.join(role_perms)

            created_at_str = f"{role.created_at.day}/{role.created_at.month}/{role.created_at.year} {role.created_at.hour}:{role.created_at.minute}:{role.created_at.second}"
            role_colour = (role.colour.r, role.colour.g, role.colour.b)
            fields = [
                ["Name", role.name, True],
                ["Mention", f"`{role.mention}`", True],
                ["Created At", created_at_str, True],
                ["Role Position", role.position, True],
                ["Hoisted", role.hoist, True],
                ["Mentionable", role.mentionable, True],
                ["Colour", utils.rgb_to_hex(role_colour), True],
                ["Members", sum(1 for member in role.members), True],
                [
                    "Permissions",
                    f"```\n{repr_permissions or 'Nothing special.'}```", False
                ],
            ]
            embed = self.bot.embed(ctx,
                                   colour=discord.Color.from_rgb(*role_colour))
            [embed.add_field(name=n, value=v, inline=i) for n, v, i in fields]

            embed_list.append(embed)

        if len(embed_list) > 1:
            source = utils.EmbedMenu(embed_list)
            paginator = utils.KalPages(source)
            await paginator.start(ctx)
        else:
            await ctx.send(embed=embed_list[0])