aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/decorators.py45
-rw-r--r--bot/exts/backend/error_handler.py4
-rw-r--r--bot/exts/utils/snekbox.py10
-rw-r--r--bot/utils/checks.py8
4 files changed, 57 insertions, 10 deletions
diff --git a/bot/decorators.py b/bot/decorators.py
index 1d30317ef..e971a5bd3 100644
--- a/bot/decorators.py
+++ b/bot/decorators.py
@@ -11,7 +11,7 @@ from discord.ext.commands import Cog, Context
from bot.constants import Channels, DEBUG_MODE, RedirectOutput
from bot.utils import function
-from bot.utils.checks import in_whitelist_check
+from bot.utils.checks import ContextCheckFailure, in_whitelist_check
from bot.utils.function import command_wraps
log = logging.getLogger(__name__)
@@ -45,6 +45,49 @@ def in_whitelist(
return commands.check(predicate)
+class NotInBlacklistCheckFailure(ContextCheckFailure):
+ """Raised when the 'not_in_blacklist' check fails."""
+
+
+def not_in_blacklist(
+ *,
+ channels: t.Container[int] = (),
+ categories: t.Container[int] = (),
+ roles: t.Container[int] = (),
+ override_roles: t.Container[int] = (),
+ redirect: t.Optional[int] = Channels.bot_commands,
+ fail_silently: bool = False,
+) -> t.Callable:
+ """
+ Check if a command was not issued in a blacklisted context.
+
+ The blacklists that can be provided are:
+
+ - `channels`: a container with channel ids for blacklisted channels
+ - `categories`: a container with category ids for blacklisted categories
+ - `roles`: a container with role ids for blacklisted roles
+
+ If the command was invoked in a context that was blacklisted, 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).
+
+ The blacklist can be overridden through the roles specified in `override_roles`.
+ """
+ def predicate(ctx: Context) -> bool:
+ """Check if command was issued in a blacklisted context."""
+ not_blacklisted = not in_whitelist_check(ctx, channels, categories, roles, fail_silently=True)
+ overridden = in_whitelist_check(ctx, roles=override_roles, fail_silently=True)
+
+ success = not_blacklisted or overridden
+
+ if not success and not fail_silently:
+ raise NotInBlacklistCheckFailure(redirect)
+
+ return success
+
+ return commands.check(predicate)
+
+
def has_no_roles(*roles: t.Union[str, int]) -> t.Callable:
"""
Returns True if the user does not have any of the roles specified.
diff --git a/bot/exts/backend/error_handler.py b/bot/exts/backend/error_handler.py
index 76ab7dfc2..da0e94a7e 100644
--- a/bot/exts/backend/error_handler.py
+++ b/bot/exts/backend/error_handler.py
@@ -12,7 +12,7 @@ from bot.bot import Bot
from bot.constants import Colours, Icons, MODERATION_ROLES
from bot.converters import TagNameConverter
from bot.errors import InvalidInfractedUser, LockedResourceError
-from bot.utils.checks import InWhitelistCheckFailure
+from bot.utils.checks import ContextCheckFailure
log = logging.getLogger(__name__)
@@ -274,7 +274,7 @@ class ErrorHandler(Cog):
await ctx.send(
"Sorry, it looks like I don't have the permissions or roles I need to do that."
)
- elif isinstance(e, (InWhitelistCheckFailure, errors.NoPrivateMessage)):
+ elif isinstance(e, (ContextCheckFailure, errors.NoPrivateMessage)):
ctx.bot.stats.incr("errors.wrong_channel_or_dm_error")
await ctx.send(e)
diff --git a/bot/exts/utils/snekbox.py b/bot/exts/utils/snekbox.py
index 9f480c067..da95240bb 100644
--- a/bot/exts/utils/snekbox.py
+++ b/bot/exts/utils/snekbox.py
@@ -13,7 +13,7 @@ from discord.ext.commands import Cog, Context, command, guild_only
from bot.bot import Bot
from bot.constants import Categories, Channels, Roles, URLs
-from bot.decorators import in_whitelist
+from bot.decorators import not_in_blacklist
from bot.utils import send_to_paste_service
from bot.utils.messages import wait_for_deletion
@@ -38,9 +38,9 @@ RAW_CODE_REGEX = re.compile(
MAX_PASTE_LEN = 10000
-# `!eval` command whitelists
-EVAL_CHANNELS = (Channels.bot_commands, Channels.esoteric)
-EVAL_CATEGORIES = (Categories.help_available, Categories.help_in_use, Categories.voice)
+# `!eval` command whitelists and blacklists.
+NO_EVAL_CHANNELS = (Channels.python_general,)
+NO_EVAL_CATEGORIES = ()
EVAL_ROLES = (Roles.helpers, Roles.moderators, Roles.admins, Roles.owners, Roles.python_community, Roles.partners)
SIGKILL = 9
@@ -280,7 +280,7 @@ class Snekbox(Cog):
@command(name="eval", aliases=("e",))
@guild_only()
- @in_whitelist(channels=EVAL_CHANNELS, categories=EVAL_CATEGORIES, roles=EVAL_ROLES)
+ @not_in_blacklist(channels=NO_EVAL_CHANNELS, categories=NO_EVAL_CATEGORIES, override_roles=EVAL_ROLES)
async def eval_command(self, ctx: Context, *, code: str = None) -> None:
"""
Run Python code and get the results.
diff --git a/bot/utils/checks.py b/bot/utils/checks.py
index 460a937d8..3d0c8a50c 100644
--- a/bot/utils/checks.py
+++ b/bot/utils/checks.py
@@ -20,8 +20,8 @@ from bot import constants
log = logging.getLogger(__name__)
-class InWhitelistCheckFailure(CheckFailure):
- """Raised when the `in_whitelist` check fails."""
+class ContextCheckFailure(CheckFailure):
+ """Raised when a context-specific check fails."""
def __init__(self, redirect_channel: Optional[int]) -> None:
self.redirect_channel = redirect_channel
@@ -36,6 +36,10 @@ class InWhitelistCheckFailure(CheckFailure):
super().__init__(error_message)
+class InWhitelistCheckFailure(ContextCheckFailure):
+ """Raised when the `in_whitelist` check fails."""
+
+
def in_whitelist_check(
ctx: Context,
channels: Container[int] = (),