aboutsummaryrefslogtreecommitdiffstats
path: root/bot
diff options
context:
space:
mode:
authorGravatar Amrou Bellalouna <[email protected]>2024-03-20 18:57:34 +0100
committerGravatar GitHub <[email protected]>2024-03-20 10:57:34 -0700
commitd418e9f28efa8f725173975d0ba42ab5c1228700 (patch)
tree6b172d2fd8d72dc77e19965a958669227083e5ef /bot
parentBump sentry-sdk from 1.41.0 to 1.42.0 (#1476) (diff)
Bump Pydis core to v11 (#1478)
Diffstat (limited to 'bot')
-rw-r--r--bot/utils/checks.py127
1 files changed, 6 insertions, 121 deletions
diff --git a/bot/utils/checks.py b/bot/utils/checks.py
index bc6e7111..faba1c72 100644
--- a/bot/utils/checks.py
+++ b/bot/utils/checks.py
@@ -1,16 +1,9 @@
-import datetime
-from collections.abc import Callable, Container, Iterable
+from collections.abc import Container
from discord.ext.commands import (
- BucketType,
- CheckFailure,
- Cog,
- Command,
- CommandOnCooldown,
Context,
- Cooldown,
- CooldownMapping,
)
+from pydis_core.utils.checks import in_whitelist_check as core_in_whitelist_check
from pydis_core.utils.logging import get_logger
from bot import constants
@@ -19,22 +12,6 @@ log = get_logger(__name__)
CODEJAM_CATEGORY_NAME = "Code Jam"
-class InWhitelistCheckFailure(CheckFailure):
- """Raised when the `in_whitelist` check fails."""
-
- def __init__(self, redirect_channel: int | None):
- self.redirect_channel = redirect_channel
-
- if redirect_channel:
- redirect_message = f" here. Please use the <#{redirect_channel}> channel instead"
- else:
- redirect_message = ""
-
- error_message = f"You are not allowed to use that command{redirect_message}."
-
- super().__init__(error_message)
-
-
def in_whitelist_check(
ctx: Context,
channels: Container[int] = (),
@@ -46,57 +23,11 @@ def in_whitelist_check(
"""
Check if a command was issued in a whitelisted context.
- The whitelists that can be provided are:
-
- - `channels`: a container with channel ids for whitelisted channels
- - `categories`: a container with category ids for whitelisted categories
- - `roles`: a container with with role ids for whitelisted roles
-
- If the command was invoked in a context that was not whitelisted, the member is either
- redirected to the `redirect` channel that was passed (default: #bot-commands) or simply
- told that they're not allowed to use this particular command (if `None` was passed).
+ Check bot-core's in_whitelist_check docstring for more details.
"""
- if redirect and redirect not in channels:
- # It does not make sense for the channel whitelist to not contain the redirection
- # channel (if applicable). That's why we add the redirection channel to the `channels`
- # container if it's not already in it. As we allow any container type to be passed,
- # we first create a tuple in order to safely add the redirection channel.
- #
- # Note: It's possible for the redirect channel to be in a whitelisted category, but
- # there's no easy way to check that and as a channel can easily be moved in and out of
- # categories, it's probably not wise to rely on its category in any case.
- channels = tuple(channels) + (redirect,)
-
- ctx_channel = ctx.channel
- if hasattr(ctx_channel, "parent"):
- ctx_channel = ctx_channel.parent
-
- if channels and ctx_channel.id in channels:
- log.trace(f"{ctx.author} may use the `{ctx.command.name}` command as they are in a whitelisted channel.")
- return True
-
- # Only check the category id if we have a category whitelist and the channel has a `category_id`
- if categories and hasattr(ctx_channel, "category_id") and ctx_channel.category_id in categories:
- log.trace(f"{ctx.author} may use the `{ctx.command.name}` command as they are in a whitelisted category.")
- return True
-
- category = getattr(ctx_channel, "category", None)
- if category and category.name == CODEJAM_CATEGORY_NAME:
- log.trace(f"{ctx.author} may use the `{ctx.command.name}` command as they are in a codejam team channel.")
- return True
-
- # Only check the roles whitelist if we have one and ensure the author's roles attribute returns
- # an iterable to prevent breakage in DM channels (for if we ever decide to enable commands there).
- if roles and any(r.id in roles for r in getattr(ctx.author, "roles", ())):
- log.trace(f"{ctx.author} may use the `{ctx.command.name}` command as they have a whitelisted role.")
- return True
-
- log.trace(f"{ctx.author} may not use the `{ctx.command.name}` command within this context.")
-
- # Some commands are secret, and should produce no feedback at all.
- if not fail_silently:
- raise InWhitelistCheckFailure(redirect)
- return False
+ return core_in_whitelist_check(
+ ctx=ctx, channels=channels, categories=categories, roles=roles, redirect=redirect, fail_silently=fail_silently
+ )
def with_role_check(ctx: Context, *role_ids: int) -> bool:
@@ -136,49 +67,3 @@ def without_role_check(ctx: Context, *role_ids: int) -> bool:
f"The result of the without_role check was {check}."
)
return check
-
-
-def cooldown_with_role_bypass(rate: int, per: float, type: BucketType = BucketType.default, *,
- bypass_roles: Iterable[int]) -> Callable:
- """
- Applies a cooldown to a command, but allows members with certain roles to be ignored.
-
- NOTE: this replaces the `Command.before_invoke` callback, which *might* introduce problems in the future.
- """
- # Make it a set so lookup is hash based.
- bypass = set(bypass_roles)
-
- # This handles the actual cooldown logic.
- buckets = CooldownMapping(Cooldown(rate, per, type))
-
- # Will be called after the command has been parse but before it has been invoked, ensures that
- # the cooldown won't be updated if the user screws up their input to the command.
- async def predicate(cog: Cog, ctx: Context) -> None:
- nonlocal bypass, buckets
-
- if any(role.id in bypass for role in ctx.author.roles):
- return
-
- # Cooldown logic, taken from discord.py internals.
- current = ctx.message.created_at.replace(tzinfo=datetime.UTC).timestamp()
- bucket = buckets.get_bucket(ctx.message)
- retry_after = bucket.update_rate_limit(current)
- if retry_after:
- raise CommandOnCooldown(bucket, retry_after)
-
- def wrapper(command: Command) -> Command:
- # NOTE: this could be changed if a subclass of Command were to be used. I didn't see the need for it
- # so I just made it raise an error when the decorator is applied before the actual command object exists.
- #
- # If the `before_invoke` detail is ever a problem then I can quickly just swap over.
- if not isinstance(command, Command):
- raise TypeError(
- "Decorator `cooldown_with_role_bypass` must be applied after the command decorator. "
- "This means it has to be above the command decorator in the code."
- )
-
- command._before_invoke = predicate
-
- return command
-
- return wrapper