Edit on GitHub

tickets_plus.ext.checks

Tickets+ decorators for use with discord.py app commands.

A set of decorators for use with discord.py application commands. These are generally Tickets Plus specific checks. They require the client to be a tickets_plus.bot.TicketsPlusBot instance. Though some may work with any discord.ext.commands.Bot instance.

Typical usage example:
from discord import app_commands
from tickets_plus.ext import checks

@app_commands.command()
@checks.is_owner_check()
async def command(interaction: discord.Interaction):
    ...
  1"""Tickets+ decorators for use with discord.py app commands.
  2
  3A set of decorators for use with discord.py application commands.
  4These are generally Tickets Plus specific checks.
  5They require the client to be a `tickets_plus.bot.TicketsPlusBot` instance.
  6Though some may work with any `discord.ext.commands.Bot` instance.
  7
  8Typical usage example:
  9    ```py
 10    from discord import app_commands
 11    from tickets_plus.ext import checks
 12
 13    @app_commands.command()
 14    @checks.is_owner_check()
 15    async def command(interaction: discord.Interaction):
 16        ...
 17    ```
 18"""
 19# License: EPL-2.0
 20# SPDX-License-Identifier: EPL-2.0
 21# Copyright (c) 2021-present The Tickets+ Contributors
 22# This Source Code may also be made available under the following
 23# Secondary Licenses when the conditions for such availability set forth
 24# in the Eclipse Public License, v. 2.0 are satisfied: GPL-3.0-only OR
 25# If later approved by the Initial Contributor, GPL-3.0-or-later.
 26
 27import discord
 28from discord import app_commands
 29
 30from tickets_plus.ext import exceptions
 31
 32
 33def is_owner_check():
 34    """A check for owner only commands.
 35
 36    We need to create our own check because the default one doesn't work with
 37    application commands.
 38
 39    Returns:
 40        `discord.app_commands.check`: The check.
 41            It's a decorator, so you can use it like this:
 42            ```py
 43            @app_commands.command()
 44            @is_owner_check()
 45            async def command(interaction: discord.Interaction):
 46                ...
 47            ```
 48    """
 49
 50    async def is_owner(interaction: discord.Interaction) -> bool:
 51        """Checks if interaction user is an owner.
 52
 53        The actual check. It's a coroutine, so it can be awaited.
 54
 55        Args:
 56            interaction: The interaction to check.
 57
 58        Returns:
 59            `bool`: Whether the user is an owner or not.
 60                Doesn't return if the user is not an owner.
 61
 62        Raises:
 63            `tickets_plus.exceptions.TicketsCheckFailure`: Requirements not met.
 64                Raised if the user is not an owner. This is according to the
 65                discord.py convention.
 66        """
 67        app = await interaction.client.application_info()
 68        if app.team:
 69            # Split to avoid errors ie AttributeError
 70            if interaction.user in app.team.members:
 71                return True
 72        if interaction.user == app.owner:
 73            return True
 74        raise exceptions.TicketsCheckFailure("You do not have permission to do this.")
 75
 76    return app_commands.check(is_owner)
 77
 78
 79def is_staff_check():
 80    """A staff check using the database.
 81
 82    We need to create our own check, so we can use the database.
 83
 84    Returns:
 85        `discord.app_commands.check`: The check.
 86            It's a decorator, so you can use it like this:
 87            ```py
 88            @app_commands.command()
 89            @is_staff_check()
 90            async def command(interaction: discord.Interaction):
 91                ...
 92            ```
 93    """
 94
 95    async def is_staff(interaction: discord.Interaction) -> bool:
 96        """Checks if interaction user is staff.
 97
 98        The actual check. It's a coroutine, so it can be awaited.
 99
100        Args:
101            interaction: The interaction to check.
102
103        Returns:
104            bool: Whether the user is staff or not.
105                Doesn't return if the user is not staff.
106
107        Raises:
108            `tickets_plus.exceptions.TicketsCheckFailure`: Requirements not met.
109                Raised if the user is not staff. This is according to the
110                discord.py convention.
111        """
112        if interaction.guild is None:
113            return False
114        app = await interaction.client.application_info()
115        if app.team:
116            # Bot owners are always staff, split to avoid errors
117            if interaction.user in app.team.members:
118                return True
119        if interaction.user == app.owner:
120            return True
121        async with interaction.client.get_connection() as conn:  # type: ignore
122            staff_roles = await conn.get_all_staff_roles(interaction.guild_id)
123            for role in staff_roles:
124                parsed_role = interaction.guild.get_role(role.role_id)
125                if parsed_role in interaction.user.roles:  # type: ignore
126                    # Already checked for member
127                    return True
128        raise exceptions.TicketsCheckFailure("You do not have"
129                                             " permission to do this here.")
130
131    return app_commands.check(is_staff)
def is_owner_check():
34def is_owner_check():
35    """A check for owner only commands.
36
37    We need to create our own check because the default one doesn't work with
38    application commands.
39
40    Returns:
41        `discord.app_commands.check`: The check.
42            It's a decorator, so you can use it like this:
43            ```py
44            @app_commands.command()
45            @is_owner_check()
46            async def command(interaction: discord.Interaction):
47                ...
48            ```
49    """
50
51    async def is_owner(interaction: discord.Interaction) -> bool:
52        """Checks if interaction user is an owner.
53
54        The actual check. It's a coroutine, so it can be awaited.
55
56        Args:
57            interaction: The interaction to check.
58
59        Returns:
60            `bool`: Whether the user is an owner or not.
61                Doesn't return if the user is not an owner.
62
63        Raises:
64            `tickets_plus.exceptions.TicketsCheckFailure`: Requirements not met.
65                Raised if the user is not an owner. This is according to the
66                discord.py convention.
67        """
68        app = await interaction.client.application_info()
69        if app.team:
70            # Split to avoid errors ie AttributeError
71            if interaction.user in app.team.members:
72                return True
73        if interaction.user == app.owner:
74            return True
75        raise exceptions.TicketsCheckFailure("You do not have permission to do this.")
76
77    return app_commands.check(is_owner)

A check for owner only commands.

We need to create our own check because the default one doesn't work with application commands.

Returns:

discord.app_commands.check: The check. It's a decorator, so you can use it like this:

@app_commands.command()
@is_owner_check()
async def command(interaction: discord.Interaction):
    ...

def is_staff_check():
 80def is_staff_check():
 81    """A staff check using the database.
 82
 83    We need to create our own check, so we can use the database.
 84
 85    Returns:
 86        `discord.app_commands.check`: The check.
 87            It's a decorator, so you can use it like this:
 88            ```py
 89            @app_commands.command()
 90            @is_staff_check()
 91            async def command(interaction: discord.Interaction):
 92                ...
 93            ```
 94    """
 95
 96    async def is_staff(interaction: discord.Interaction) -> bool:
 97        """Checks if interaction user is staff.
 98
 99        The actual check. It's a coroutine, so it can be awaited.
100
101        Args:
102            interaction: The interaction to check.
103
104        Returns:
105            bool: Whether the user is staff or not.
106                Doesn't return if the user is not staff.
107
108        Raises:
109            `tickets_plus.exceptions.TicketsCheckFailure`: Requirements not met.
110                Raised if the user is not staff. This is according to the
111                discord.py convention.
112        """
113        if interaction.guild is None:
114            return False
115        app = await interaction.client.application_info()
116        if app.team:
117            # Bot owners are always staff, split to avoid errors
118            if interaction.user in app.team.members:
119                return True
120        if interaction.user == app.owner:
121            return True
122        async with interaction.client.get_connection() as conn:  # type: ignore
123            staff_roles = await conn.get_all_staff_roles(interaction.guild_id)
124            for role in staff_roles:
125                parsed_role = interaction.guild.get_role(role.role_id)
126                if parsed_role in interaction.user.roles:  # type: ignore
127                    # Already checked for member
128                    return True
129        raise exceptions.TicketsCheckFailure("You do not have"
130                                             " permission to do this here.")
131
132    return app_commands.check(is_staff)

A staff check using the database.

We need to create our own check, so we can use the database.

Returns:

discord.app_commands.check: The check. It's a decorator, so you can use it like this:

@app_commands.command()
@is_staff_check()
async def command(interaction: discord.Interaction):
    ...