aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/error_handler.py6
-rw-r--r--bot/cogs/information.py10
-rw-r--r--bot/cogs/snekbox.py9
-rw-r--r--bot/cogs/utils.py8
-rw-r--r--bot/cogs/verification.py18
-rw-r--r--bot/decorators.py49
-rw-r--r--tests/bot/cogs/test_information.py4
-rw-r--r--tests/bot/test_decorators.py60
8 files changed, 72 insertions, 92 deletions
diff --git a/bot/cogs/error_handler.py b/bot/cogs/error_handler.py
index 3f56a9798..b2f4c59f6 100644
--- a/bot/cogs/error_handler.py
+++ b/bot/cogs/error_handler.py
@@ -9,7 +9,7 @@ from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.constants import Channels
from bot.converters import TagNameConverter
-from bot.decorators import InWhitelistedContextCheckFailure
+from bot.decorators import InWhitelistCheckFailure
log = logging.getLogger(__name__)
@@ -202,7 +202,7 @@ class ErrorHandler(Cog):
* BotMissingRole
* BotMissingAnyRole
* NoPrivateMessage
- * InWhitelistedContextCheckFailure
+ * InWhitelistCheckFailure
"""
bot_missing_errors = (
errors.BotMissingPermissions,
@@ -215,7 +215,7 @@ class ErrorHandler(Cog):
await ctx.send(
f"Sorry, it looks like I don't have the permissions or roles I need to do that."
)
- elif isinstance(e, (InWhitelistedContextCheckFailure, errors.NoPrivateMessage)):
+ elif isinstance(e, (InWhitelistCheckFailure, errors.NoPrivateMessage)):
ctx.bot.stats.incr("errors.wrong_channel_or_dm_error")
await ctx.send(e)
diff --git a/bot/cogs/information.py b/bot/cogs/information.py
index 6b3fc0c96..4eb36c340 100644
--- a/bot/cogs/information.py
+++ b/bot/cogs/information.py
@@ -12,7 +12,7 @@ from discord.utils import escape_markdown
from bot import constants
from bot.bot import Bot
-from bot.decorators import InWhitelistedContextCheckFailure, in_whitelisted_context, with_role
+from bot.decorators import InWhitelistCheckFailure, in_whitelist, with_role
from bot.pagination import LinePaginator
from bot.utils.checks import cooldown_with_role_bypass, with_role_check
from bot.utils.time import time_since
@@ -152,7 +152,7 @@ class Information(Cog):
# Non-staff may only do this in #bot-commands
if not with_role_check(ctx, *constants.STAFF_ROLES):
if not ctx.channel.id == constants.Channels.bot_commands:
- raise InWhitelistedContextCheckFailure(constants.Channels.bot_commands)
+ raise InWhitelistCheckFailure(constants.Channels.bot_commands)
embed = await self.create_user_embed(ctx, user)
@@ -331,11 +331,7 @@ class Information(Cog):
@cooldown_with_role_bypass(2, 60 * 3, BucketType.member, bypass_roles=constants.STAFF_ROLES)
@group(invoke_without_command=True)
- @in_whitelisted_context(
- whitelisted_channels=(constants.Channels.bot_commands,),
- whitelisted_roles=constants.STAFF_ROLES,
- redirect_channel=constants.Channels.bot_commands,
- )
+ @in_whitelist(channels=(constants.Channels.bot_commands,), roles=constants.STAFF_ROLES)
async def raw(self, ctx: Context, *, message: Message, json: bool = False) -> None:
"""Shows information about the raw API response."""
# I *guess* it could be deleted right as the command is invoked but I felt like it wasn't worth handling
diff --git a/bot/cogs/snekbox.py b/bot/cogs/snekbox.py
index 4999074b6..8d4688114 100644
--- a/bot/cogs/snekbox.py
+++ b/bot/cogs/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_whitelisted_context
+from bot.decorators import in_whitelist
from bot.utils.messages import wait_for_deletion
log = logging.getLogger(__name__)
@@ -269,12 +269,7 @@ class Snekbox(Cog):
@command(name="eval", aliases=("e",))
@guild_only()
- @in_whitelisted_context(
- whitelisted_channels=EVAL_CHANNELS,
- whitelisted_categories=EVAL_CATEGORIES,
- whitelisted_roles=EVAL_ROLES,
- redirect_channel=Channels.bot_commands,
- )
+ @in_whitelist(channels=EVAL_CHANNELS, categories=EVAL_CATEGORIES, 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/cogs/utils.py b/bot/cogs/utils.py
index 234ec514d..8023eb962 100644
--- a/bot/cogs/utils.py
+++ b/bot/cogs/utils.py
@@ -13,7 +13,7 @@ from discord.ext.commands import BadArgument, Cog, Context, command
from bot.bot import Bot
from bot.constants import Channels, MODERATION_ROLES, Mention, STAFF_ROLES
-from bot.decorators import in_whitelisted_context, with_role
+from bot.decorators import in_whitelist, with_role
from bot.utils.time import humanize_delta
log = logging.getLogger(__name__)
@@ -118,11 +118,7 @@ class Utils(Cog):
await ctx.message.channel.send(embed=pep_embed)
@command()
- @in_whitelisted_context(
- whitelisted_channels=(Channels.bot_commands,),
- whitelisted_roles=STAFF_ROLES,
- redirect_channel=Channels.bot_commands,
- )
+ @in_whitelist(channels=(Channels.bot_commands,), roles=STAFF_ROLES)
async def charinfo(self, ctx: Context, *, characters: str) -> None:
"""Shows you information on up to 25 unicode characters."""
match = re.match(r"<(a?):(\w+):(\d+)>", characters)
diff --git a/bot/cogs/verification.py b/bot/cogs/verification.py
index 040f52fbf..388b7a338 100644
--- a/bot/cogs/verification.py
+++ b/bot/cogs/verification.py
@@ -9,7 +9,7 @@ from discord.ext.commands import Cog, Context, command
from bot import constants
from bot.bot import Bot
from bot.cogs.moderation import ModLog
-from bot.decorators import InWhitelistedContextCheckFailure, in_whitelisted_context, without_role
+from bot.decorators import InWhitelistCheckFailure, in_whitelist, without_role
from bot.utils.checks import without_role_check
log = logging.getLogger(__name__)
@@ -122,7 +122,7 @@ class Verification(Cog):
@command(name='accept', aliases=('verify', 'verified', 'accepted'), hidden=True)
@without_role(constants.Roles.verified)
- @in_whitelisted_context(whitelisted_channels=(constants.Channels.verification,))
+ @in_whitelist(channels=(constants.Channels.verification,))
async def accept_command(self, ctx: Context, *_) -> None: # We don't actually care about the args
"""Accept our rules and gain access to the rest of the server."""
log.debug(f"{ctx.author} called !accept. Assigning the 'Developer' role.")
@@ -138,10 +138,7 @@ class Verification(Cog):
await ctx.message.delete()
@command(name='subscribe')
- @in_whitelisted_context(
- whitelisted_channels=(constants.Channels.bot_commands,),
- redirect_channel=constants.Channels.bot_commands,
- )
+ @in_whitelist(channels=(constants.Channels.bot_commands,))
async def subscribe_command(self, ctx: Context, *_) -> None: # We don't actually care about the args
"""Subscribe to announcement notifications by assigning yourself the role."""
has_role = False
@@ -165,10 +162,7 @@ class Verification(Cog):
)
@command(name='unsubscribe')
- @in_whitelisted_context(
- whitelisted_channels=(constants.Channels.bot_commands,),
- redirect_channel=constants.Channels.bot_commands,
- )
+ @in_whitelist(channels=(constants.Channels.bot_commands,))
async def unsubscribe_command(self, ctx: Context, *_) -> None: # We don't actually care about the args
"""Unsubscribe from announcement notifications by removing the role from yourself."""
has_role = False
@@ -193,8 +187,8 @@ class Verification(Cog):
# This cannot be static (must have a __func__ attribute).
async def cog_command_error(self, ctx: Context, error: Exception) -> None:
- """Check for & ignore any InWhitelistedContextCheckFailure."""
- if isinstance(error, InWhitelistedContextCheckFailure):
+ """Check for & ignore any InWhitelistCheckFailure."""
+ if isinstance(error, InWhitelistCheckFailure):
error.handled = True
@staticmethod
diff --git a/bot/decorators.py b/bot/decorators.py
index 149564d18..2ee5879f2 100644
--- a/bot/decorators.py
+++ b/bot/decorators.py
@@ -11,30 +11,34 @@ from discord.errors import NotFound
from discord.ext import commands
from discord.ext.commands import CheckFailure, Cog, Context
-from bot.constants import ERROR_REPLIES, RedirectOutput
+from bot.constants import Channels, ERROR_REPLIES, RedirectOutput
from bot.utils.checks import with_role_check, without_role_check
log = logging.getLogger(__name__)
-class InWhitelistedContextCheckFailure(CheckFailure):
+class InWhitelistCheckFailure(CheckFailure):
"""Raised when the `in_whitelist` check fails."""
- def __init__(self, redirect_channel: Optional[int] = None):
- error_message = "Sorry, but you are not allowed to use that command here."
+ def __init__(self, redirect_channel: Optional[int]) -> None:
+ self.redirect_channel = redirect_channel
if redirect_channel:
- error_message += f" Please use the <#{redirect_channel}> channel instead."
+ 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_whitelisted_context(
+def in_whitelist(
*,
- whitelisted_channels: Container[int] = (),
- whitelisted_categories: Container[int] = (),
- whitelisted_roles: Container[int] = (),
- redirect_channel: Optional[int] = None,
+ channels: Container[int] = (),
+ categories: Container[int] = (),
+ roles: Container[int] = (),
+ redirect: Optional[int] = Channels.bot_commands,
) -> Callable:
"""
@@ -46,45 +50,40 @@ def in_whitelisted_context(
- `categories`: a container with category ids for whitelisted categories
- `roles`: a container with with role ids for whitelisted roles
- An optional `redirect_channel` can be provided to redirect users that are not
- authorized to use the command in the current context. If no such channel is
- provided, the users are simply told that they are not authorized to use the
- command.
+ 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).
"""
- if redirect_channel and redirect_channel not in whitelisted_channels:
+ if redirect and redirect not in channels:
# It does not make sense for the channel whitelist to not contain the redirection
- # channel (if provided). That's why we add the redirection channel to the `channels`
+ # 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.
- whitelisted_channels = tuple(whitelisted_channels) + (redirect_channel,)
+ channels = tuple(channels) + (redirect,)
def predicate(ctx: Context) -> bool:
"""Check if a command was issued in a whitelisted context."""
- if whitelisted_channels and ctx.channel.id in whitelisted_channels:
+ 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 (
- whitelisted_categories
- and hasattr(ctx.channel, "category_id")
- and ctx.channel.category_id in whitelisted_categories
- ):
+ 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
# 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 whitelisted_roles and any(r.id in whitelisted_roles for r in getattr(ctx.author, "roles", ())):
+ 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.")
- raise InWhitelistedContextCheckFailure(redirect_channel)
+ raise InWhitelistCheckFailure(redirect)
return commands.check(predicate)
diff --git a/tests/bot/cogs/test_information.py b/tests/bot/cogs/test_information.py
index 4a36fe030..6dace1080 100644
--- a/tests/bot/cogs/test_information.py
+++ b/tests/bot/cogs/test_information.py
@@ -7,7 +7,7 @@ import discord
from bot import constants
from bot.cogs import information
-from bot.decorators import InWhitelistedContextCheckFailure
+from bot.decorators import InWhitelistCheckFailure
from tests import helpers
@@ -525,7 +525,7 @@ class UserCommandTests(unittest.TestCase):
ctx = helpers.MockContext(author=self.author, channel=helpers.MockTextChannel(id=100))
msg = "Sorry, but you may only use this command within <#50>."
- with self.assertRaises(InWhitelistedContextCheckFailure, msg=msg):
+ with self.assertRaises(InWhitelistCheckFailure, msg=msg):
asyncio.run(self.cog.user_info.callback(self.cog, ctx))
@unittest.mock.patch("bot.cogs.information.Information.create_user_embed", new_callable=unittest.mock.AsyncMock)
diff --git a/tests/bot/test_decorators.py b/tests/bot/test_decorators.py
index fae7c0c52..645051fec 100644
--- a/tests/bot/test_decorators.py
+++ b/tests/bot/test_decorators.py
@@ -2,15 +2,15 @@ import collections
import unittest
import unittest.mock
-from bot.decorators import InWhitelistedContextCheckFailure, in_whitelisted_context
+from bot.decorators import InWhitelistCheckFailure, in_whitelist
from tests import helpers
WhitelistedContextTestCase = collections.namedtuple("WhitelistedContextTestCase", ("kwargs", "ctx"))
-class InWhitelistedContextTests(unittest.TestCase):
- """Tests for the `in_whitelisted_context` check."""
+class InWhitelistTests(unittest.TestCase):
+ """Tests for the `in_whitelist` check."""
@classmethod
def setUpClass(cls):
@@ -23,43 +23,43 @@ class InWhitelistedContextTests(unittest.TestCase):
cls.staff_role = helpers.MockRole(id=121212)
cls.staff_member = helpers.MockMember(roles=(cls.staff_role,))
- cls.whitelisted_channels = (cls.bot_commands.id,)
- cls.whitelisted_categories = (cls.help_channel.category_id,)
- cls.whitelisted_roles = (cls.staff_role.id,)
+ cls.channels = (cls.bot_commands.id,)
+ cls.categories = (cls.help_channel.category_id,)
+ cls.roles = (cls.staff_role.id,)
def test_predicate_returns_true_for_whitelisted_context(self):
"""The predicate should return `True` if a whitelisted context was passed to it."""
test_cases = (
# Commands issued in whitelisted channels by members without whitelisted roles
WhitelistedContextTestCase(
- kwargs={"whitelisted_channels": self.whitelisted_channels},
+ kwargs={"channels": self.channels},
ctx=helpers.MockContext(channel=self.bot_commands, author=self.non_staff_member)
),
- # `redirect_channel` should be added implicitly to the `whitelisted_channels`
+ # `redirect` should be added implicitly to the `channels`
WhitelistedContextTestCase(
- kwargs={"redirect_channel": self.bot_commands.id},
+ kwargs={"redirect": self.bot_commands.id},
ctx=helpers.MockContext(channel=self.bot_commands, author=self.non_staff_member)
),
# Commands issued in a whitelisted category by members without whitelisted roles
WhitelistedContextTestCase(
- kwargs={"whitelisted_categories": self.whitelisted_categories},
+ kwargs={"categories": self.categories},
ctx=helpers.MockContext(channel=self.help_channel, author=self.non_staff_member)
),
# Command issued by a staff member in a non-whitelisted channel/category
WhitelistedContextTestCase(
- kwargs={"whitelisted_roles": self.whitelisted_roles},
+ kwargs={"roles": self.roles},
ctx=helpers.MockContext(channel=self.non_whitelisted_channel, author=self.staff_member)
),
# With all kwargs provided
WhitelistedContextTestCase(
kwargs={
- "whitelisted_channels": self.whitelisted_channels,
- "whitelisted_categories": self.whitelisted_categories,
- "whitelisted_roles": self.whitelisted_roles,
- "redirect_channel": self.bot_commands,
+ "channels": self.channels,
+ "categories": self.categories,
+ "roles": self.roles,
+ "redirect": self.bot_commands,
},
ctx=helpers.MockContext(channel=self.help_channel, author=self.staff_member)
),
@@ -69,31 +69,31 @@ class InWhitelistedContextTests(unittest.TestCase):
# patch `commands.check` with a no-op lambda that just returns the predicate passed to it
# so we can test the predicate that was generated from the specified kwargs.
with unittest.mock.patch("bot.decorators.commands.check", new=lambda predicate: predicate):
- predicate = in_whitelisted_context(**test_case.kwargs)
+ predicate = in_whitelist(**test_case.kwargs)
with self.subTest(test_case=test_case):
self.assertTrue(predicate(test_case.ctx))
def test_predicate_raises_exception_for_non_whitelisted_context(self):
- """The predicate should raise `InWhitelistedContextCheckFailure` for a non-whitelisted context."""
+ """The predicate should raise `InWhitelistCheckFailure` for a non-whitelisted context."""
test_cases = (
- # Failing check with `redirect_channel`
+ # Failing check with `redirect`
WhitelistedContextTestCase(
kwargs={
- "whitelisted_categories": self.whitelisted_categories,
- "whitelisted_channels": self.whitelisted_channels,
- "whitelisted_roles": self.whitelisted_roles,
- "redirect_channel": self.bot_commands.id,
+ "categories": self.categories,
+ "channels": self.channels,
+ "roles": self.roles,
+ "redirect": self.bot_commands.id,
},
ctx=helpers.MockContext(channel=self.non_whitelisted_channel, author=self.non_staff_member)
),
- # Failing check without `redirect_channel`
+ # Failing check without `redirect`
WhitelistedContextTestCase(
kwargs={
- "whitelisted_categories": self.whitelisted_categories,
- "whitelisted_channels": self.whitelisted_channels,
- "whitelisted_roles": self.whitelisted_roles,
+ "categories": self.categories,
+ "channels": self.channels,
+ "roles": self.roles,
},
ctx=helpers.MockContext(channel=self.non_whitelisted_channel, author=self.non_staff_member)
),
@@ -102,14 +102,14 @@ class InWhitelistedContextTests(unittest.TestCase):
for test_case in test_cases:
# Create expected exception message based on whether or not a redirect channel was provided
expected_message = "Sorry, but you are not allowed to use that command here."
- if test_case.kwargs.get("redirect_channel"):
- expected_message += f" Please use the <#{test_case.kwargs['redirect_channel']}> channel instead."
+ if test_case.kwargs.get("redirect"):
+ expected_message += f" Please use the <#{test_case.kwargs['redirect']}> channel instead."
# patch `commands.check` with a no-op lambda that just returns the predicate passed to it
# so we can test the predicate that was generated from the specified kwargs.
with unittest.mock.patch("bot.decorators.commands.check", new=lambda predicate: predicate):
- predicate = in_whitelisted_context(**test_case.kwargs)
+ predicate = in_whitelist(**test_case.kwargs)
with self.subTest(test_case=test_case):
- with self.assertRaises(InWhitelistedContextCheckFailure, msg=expected_message):
+ with self.assertRaises(InWhitelistCheckFailure, msg=expected_message):
predicate(test_case.ctx)