aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/information.py35
-rw-r--r--bot/cogs/tags.py2
-rw-r--r--bot/decorators.py36
-rw-r--r--bot/utils/checks.py56
4 files changed, 102 insertions, 27 deletions
diff --git a/bot/cogs/information.py b/bot/cogs/information.py
index 7a244cdbe..129166d2f 100644
--- a/bot/cogs/information.py
+++ b/bot/cogs/information.py
@@ -1,11 +1,13 @@
import logging
+import random
import textwrap
from discord import CategoryChannel, Colour, Embed, Member, TextChannel, VoiceChannel
-from discord.ext.commands import Bot, Context, command
+from discord.ext.commands import BadArgument, Bot, CommandError, Context, MissingPermissions, command
-from bot.constants import Emojis, Keys, Roles, URLs
+from bot.constants import Channels, Emojis, Keys, NEGATIVE_REPLIES, Roles, URLs
from bot.decorators import with_role
+from bot.utils.checks import with_role_check
from bot.utils.time import time_since
log = logging.getLogger(__name__)
@@ -121,13 +123,23 @@ class Information:
await ctx.send(embed=embed)
- @with_role(*MODERATION_ROLES)
@command(name="user", aliases=["user_info", "member", "member_info"])
async def user_info(self, ctx: Context, user: Member = None, hidden: bool = False):
"""
Returns info about a user.
"""
+ # Do a role check if this is being executed on
+ # someone other than the caller
+ if user and user != ctx.author:
+ if not with_role_check(ctx, *MODERATION_ROLES):
+ raise BadArgument("You do not have permission to use this command on users other than yourself.")
+
+ # Non-moderators may only do this in #bot-commands
+ if not with_role_check(ctx, *MODERATION_ROLES):
+ if not ctx.channel.id == Channels.bot:
+ raise MissingPermissions("You can't do that here!")
+
# Validates hidden input
hidden = str(hidden)
@@ -192,6 +204,23 @@ class Information:
await ctx.send(embed=embed)
+ @user_info.error
+ async def user_info_command_error(self, ctx: Context, error: CommandError):
+ embed = Embed(colour=Colour.red())
+
+ if isinstance(error, BadArgument):
+ embed.title = random.choice(NEGATIVE_REPLIES)
+ embed.description = str(error)
+ await ctx.send(embed=embed)
+
+ elif isinstance(error, MissingPermissions):
+ embed.title = random.choice(NEGATIVE_REPLIES)
+ embed.description = f"Sorry, but you may only use this command within <#{Channels.bot}>."
+ await ctx.send(embed=embed)
+
+ else:
+ log.exception(f"Unhandled error: {error}")
+
def setup(bot):
bot.add_cog(Information(bot))
diff --git a/bot/cogs/tags.py b/bot/cogs/tags.py
index b128b6de1..8ecd80127 100644
--- a/bot/cogs/tags.py
+++ b/bot/cogs/tags.py
@@ -149,7 +149,7 @@ class Tags:
tags = []
- embed = Embed()
+ embed: Embed = Embed()
embed.colour = Colour.red()
tag_data = await self.get_tag_data(tag_name)
diff --git a/bot/decorators.py b/bot/decorators.py
index 87877ecbf..710045c10 100644
--- a/bot/decorators.py
+++ b/bot/decorators.py
@@ -10,6 +10,7 @@ from discord.ext import commands
from discord.ext.commands import CheckFailure, Context
from bot.constants import ERROR_REPLIES
+from bot.utils.checks import with_role_check, without_role_check
log = logging.getLogger(__name__)
@@ -47,35 +48,24 @@ def in_channel(*channels: int, bypass_roles: typing.Container[int] = None):
def with_role(*role_ids: int):
- async def predicate(ctx: Context):
- if not ctx.guild: # Return False in a DM
- log.debug(f"{ctx.author} tried to use the '{ctx.command.name}'command from a DM. "
- "This command is restricted by the with_role decorator. Rejecting request.")
- return False
-
- for role in ctx.author.roles:
- if role.id in role_ids:
- log.debug(f"{ctx.author} has the '{role.name}' role, and passes the check.")
- return True
+ """
+ Returns True if the user has any one
+ of the roles in role_ids.
+ """
- log.debug(f"{ctx.author} does not have the required role to use "
- f"the '{ctx.command.name}' command, so the request is rejected.")
- return False
+ async def predicate(ctx: Context):
+ return with_role_check(ctx, *role_ids)
return commands.check(predicate)
def without_role(*role_ids: int):
- async def predicate(ctx: Context):
- if not ctx.guild: # Return False in a DM
- log.debug(f"{ctx.author} tried to use the '{ctx.command.name}' command from a DM. "
- "This command is restricted by the without_role decorator. Rejecting request.")
- return False
+ """
+ Returns True if the user does not have any
+ of the roles in role_ids.
+ """
- author_roles = [role.id for role in ctx.author.roles]
- check = all(role not in author_roles for role in role_ids)
- log.debug(f"{ctx.author} tried to call the '{ctx.command.name}' command. "
- f"The result of the without_role check was {check}.")
- return check
+ async def predicate(ctx: Context):
+ return without_role_check(ctx, *role_ids)
return commands.check(predicate)
diff --git a/bot/utils/checks.py b/bot/utils/checks.py
new file mode 100644
index 000000000..37dc657f7
--- /dev/null
+++ b/bot/utils/checks.py
@@ -0,0 +1,56 @@
+import logging
+
+from discord.ext.commands import Context
+
+log = logging.getLogger(__name__)
+
+
+def with_role_check(ctx: Context, *role_ids: int) -> bool:
+ """
+ Returns True if the user has any one
+ of the roles in role_ids.
+ """
+
+ if not ctx.guild: # Return False in a DM
+ log.trace(f"{ctx.author} tried to use the '{ctx.command.name}'command from a DM. "
+ "This command is restricted by the with_role decorator. Rejecting request.")
+ return False
+
+ for role in ctx.author.roles:
+ if role.id in role_ids:
+ log.trace(f"{ctx.author} has the '{role.name}' role, and passes the check.")
+ return True
+
+ log.trace(f"{ctx.author} does not have the required role to use "
+ f"the '{ctx.command.name}' command, so the request is rejected.")
+ return False
+
+
+def without_role_check(ctx: Context, *role_ids: int) -> bool:
+ """
+ Returns True if the user does not have any
+ of the roles in role_ids.
+ """
+
+ if not ctx.guild: # Return False in a DM
+ log.trace(f"{ctx.author} tried to use the '{ctx.command.name}' command from a DM. "
+ "This command is restricted by the without_role decorator. Rejecting request.")
+ return False
+
+ author_roles = (role.id for role in ctx.author.roles)
+ check = all(role not in author_roles for role in role_ids)
+ log.trace(f"{ctx.author} tried to call the '{ctx.command.name}' command. "
+ f"The result of the without_role check was {check}.")
+ return check
+
+
+def in_channel_check(ctx: Context, channel_id: int) -> bool:
+ """
+ Checks if the command was executed
+ inside of the specified channel.
+ """
+
+ check = ctx.channel.id == channel_id
+ log.trace(f"{ctx.author} tried to call the '{ctx.command.name}' command. "
+ f"The result of the in_channel check was {check}.")
+ return check