Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added simple base for a has_any_role decorator check. #81

Closed
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions tanjun/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import time
import typing
from collections import abc as collections
from functools import partial

import hikari

Expand Down Expand Up @@ -787,3 +788,63 @@ def with_check(check: tanjun_abc.CheckSig, /) -> collections.Callable[[CommandT]
A command decorator callback which adds the check.
"""
return lambda command: command.add_check(check)


def with_any_role_check(
patchwork-systems marked this conversation as resolved.
Show resolved Hide resolved
roles: list[str | int] = list(),
patchwork-systems marked this conversation as resolved.
Show resolved Hide resolved
*,
error_message: str | None = "You do not have the required roles to use this command!",
halt_execution: bool = True,
) -> collections.Callable[[CommandT], CommandT]:
"""Only let a command run if the author has a specific role.

Parameters
----------
roles: list[str | int]
The author must have at least one (1) role in this list. (Role.name and Role.id are checked)
patchwork-systems marked this conversation as resolved.
Show resolved Hide resolved

Other Parameters
----------------
error_message: str | None
The error message raised if the member does not have a required role.

Defaults to 'You do not have the required roles to use this command!'
halt_execution: bool
Whether this check should raise `tanjun.errors.HaltExecution` to
end the execution search when it fails instead of returning `False`.

Defaults to `False`.

Returns
-------
collections.abc.Callable[[CommandT], CommandT]
A command decorator callback which adds the check."""

def any_role_check(
patchwork-systems marked this conversation as resolved.
Show resolved Hide resolved
ctx: tanjun_abc.Context,
*,
roles: list[str],
error_message: str | None = None,
patchwork-systems marked this conversation as resolved.
Show resolved Hide resolved
halt_execution: bool = False,
) -> bool:

if not ctx.member:
patchwork-systems marked this conversation as resolved.
Show resolved Hide resolved
return _handle_result(False, "You must be a member to use this!", True)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really a good way to handle this, these fields should also be decided based on user input and while halt_execution can just be re-used here you'd likely have to distinguish between the two error messages somehow (possibly by taking them as separate keyword-arguments).


member_roles = ctx.member.get_roles()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably make sense to fallback to fetching the roles from rest if necessary to make this check more compatible with a cacheless bot (e.g. interaction server).

Plus if we process the roles while initialising the class for this check we could add a hot path for when no role names are provided which avoids getting the role objects all together and rather just checks against ctx.member.role_ids


def check_roles(member_role: Role, required_roles: list[str | int]) -> bool:
for check in required_roles:
if isinstance(check, int):
if member_role.id == check:
return True
if member_role.name == check:
return True

result = any(check_roles(member_role, roles) for member_role in member_roles)
return _handle_result(result, error_message, halt_execution)

partial_any_role_check = partial(
any_role_check, roles=roles, error_message=error_message, halt_execution=halt_execution
patchwork-systems marked this conversation as resolved.
Show resolved Hide resolved
)
return lambda command: command.add_check(partial_any_role_check)