fix command error handling

so, i had a fundamental misunderstanding about how command errors work.
turns out the help command runs the checks for each function.
This ended up sending one "permission denied" message for each command in the Emotes cog,
*each time help was run*.

To fix this, __local_check needs to not have extra side effects.
I create one new exception, MissingManageServerEmojis, and raise it in case the user or bot is missing permissions.
I re-use NoPrivateMessages, since that's already a d.py exception.

Then I catch the errors in on_command_error, and send them to the user.
This commit is contained in:
bmintz 2018-07-31 02:38:14 -05:00
parent 52618915be
commit c5c6e7ef24
2 changed files with 20 additions and 16 deletions

View File

@ -48,26 +48,25 @@ class Emotes:
async def __local_check(self, context): async def __local_check(self, context):
if not context.guild: if not context.guild:
await context.send( raise commands.NoPrivateMessage
f'{utils.SUCCESS_EMOTES[False]} Sorry, this command may only be used in a server.')
return False return False
if ( if (
not context.author.guild_permissions.manage_emojis not context.author.guild_permissions.manage_emojis
or not context.guild.me.guild_permissions.manage_emojis or not context.guild.me.guild_permissions.manage_emojis
): ):
await context.send( raise errors.MissingManageEmojisPermission
f'{utils.SUCCESS_EMOTES[False]} '
"Sorry, you don't have enough permissions to run this command. "
'You and I both need the Manage Emojis permission.')
return False
return True return True
async def on_command_error(self, context, error): async def on_command_error(self, context, error):
if isinstance(error, errors.EmoteManagerError): if isinstance(error, (errors.EmoteManagerError, errors.MissingManageEmojisPermission)):
await context.send(str(error)) await context.send(str(error))
if isinstance(error, commands.NoPrivateMessage):
await context.send(
f'{utils.SUCCESS_EMOTES[False]} Sorry, this command may only be used in a server.')
@commands.command() @commands.command()
async def add(self, context, *args): async def add(self, context, *args):
"""Add a new emote to this server. """Add a new emote to this server.

View File

@ -1,44 +1,49 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# encoding: utf-8 # encoding: utf-8
from discord.ext.commands import CommandError from discord.ext import commands
import utils
class EmoteManagerError(CommandError): class MissingManageEmojisPermission(commands.MissingPermissions):
"""The invoker or the bot doesn't have permissions to manage server emojis."""
def __init__(self):
super(Exception, self).__init__(
f'{utils.SUCCESS_EMOTES[False]} '
"Sorry, you don't have enough permissions to run this command. "
'You and I both need the Manage Emojis permission.')
class EmoteManagerError(commands.CommandError):
"""Generic error with the bot. This can be used to catch all bot errors.""" """Generic error with the bot. This can be used to catch all bot errors."""
pass pass
class HTTPException(EmoteManagerError): class HTTPException(EmoteManagerError):
"""The server did not respond with an OK status code.""" """The server did not respond with an OK status code."""
def __init__(self, status): def __init__(self, status):
super().__init__(f'URL error: server returned error code {status}') super().__init__(f'URL error: server returned error code {status}')
class EmoteNotFoundError(EmoteManagerError): class EmoteNotFoundError(EmoteManagerError):
"""An emote with that name was not found""" """An emote with that name was not found"""
def __init__(self, name): def __init__(self, name):
super().__init__(f'An emote called `{name}` does not exist in this server.') super().__init__(f'An emote called `{name}` does not exist in this server.')
class InvalidImageError(EmoteManagerError): class InvalidImageError(EmoteManagerError):
"""The image is not a GIF, PNG, or JPG""" """The image is not a GIF, PNG, or JPG"""
def __init__(self): def __init__(self):
super().__init__('The image supplied was not a GIF, PNG, or JPG.') super().__init__('The image supplied was not a GIF, PNG, or JPG.')
class NoMoreSlotsError(EmoteManagerError): class NoMoreSlotsError(EmoteManagerError):
"""Raised in case all slots of a particular type (static/animated) are full""" """Raised in case all slots of a particular type (static/animated) are full"""
def __init__(self): def __init__(self):
super().__init__('No more backend slots available.') super().__init__('No more backend slots available.')
class PermissionDeniedError(EmoteManagerError): class PermissionDeniedError(EmoteManagerError):
"""Raised when a user tries to modify an emote without the Manage Emojis permission""" """Raised when a user tries to modify an emote without the Manage Emojis permission"""
def __init__(self, name): def __init__(self, name):
super().__init__(f"You're not authorized to modify `{name}`.") super().__init__(f"You're not authorized to modify `{name}`.")
class DiscordError(Exception): class DiscordError(Exception):
"""Usually raised when the client cache is being baka""" """Usually raised when the client cache is being baka"""
def __init__(self): def __init__(self):