"complete" as in it supports app and text commands and has some comments explaining the code. As you may have noticed, there are multiple files in this gist:
Text Cmmands Only Here
See here the complete check with support for app and text commands:
from typing import Any, Callable, Union, Literal, TYPE_CHECKING
from discord import Permissions, Interaction
from discord.app_commands import CheckFailure as AppCheckFailure, check as app_check, Command as AppCommand
from discord.ext.commands import Context, CheckFailure as ExtCheckFailure, check as ext_check, Command as ExtCommand
if TYPE_CHECKING:
from discord.ext.commands._types import CoroFunc
ExtCheckFunc = Union[ExtCommand[Any, ..., Any], CoroFunc]
from discord.app_commands.commands import CheckInputParameter as AppCheckFunc
else:
ExtCheckFunc = Callable
AppCheckFunc = Callable
# error to raise
class MissingAllPermissions(ExtCheckFailure, AppCheckFailure):
pass
def has_any_permissions(
command_type: Literal["app", "text", "hybrid", "auto"] = "auto", **perms: bool
) -> Union[ExtCheckFunc, AppCheckFunc]:
# check if all permissions are valid
invalid = perms.keys() - Permissions.VALID_FLAGS.keys()
if invalid:
raise TypeError(f"Invalid permission(s): {', '.join(invalid)}")
# the actual check
# since this supports a text and slash command, we need to accept either Context or Interaction
def predicate(ctx_interaction: Union[Context, Interaction]):
# attribute exists on both so its safe to use.
permissions = ctx_interaction.permissions
# check the perms
if any(value == getattr(permissions, perm) for perm, value in perms.items()):
return True
raise MissingAllPermissions(f"You need at least one of the following permissions: {', '.join(perms.keys())}")
command_type = command_type if command_type != "hybrid" else "text"
from_command_type = {"text": ext_check, "app": app_check}
# this is where we handle the input when command_type is set to "auto" (default)
def fake_check(check_input: Union[ExtCheckFunc, AppCheckFunc]):
# return the right check based on the command type
if isinstance(check_input, ExtCommand):
return from_command_type["text"](predicate)(check_input)
elif isinstance(check_input, AppCommand):
return from_command_type["app"](predicate)(check_input)
else:
# else guess from the missing first param
try:
check_input() # type: ignore # call the input to see if it raises an error
except TypeError as e:
if "'ctx'" in str(e):
return from_command_type["text"](predicate)(check_input)
elif "'interaction'" in str(e):
return from_command_type["app"](predicate)(check_input)
else:
raise TypeError("Could not guess command type, please specify it manually.")
# check the command_type and return accordingly
if command_type != "auto":
return from_command_type[command_type](predicate)
else:
return fake_check # type: ignore # this is a callable