async def set_guild(self, ctx: MyContext, role: discord.Role, permission: str, value: bool): """ Set a permission for a role in a guild """ _ = await ctx.get_translate_function() if role.guild.id != ctx.guild.id: await ctx.send( _("❌ Can't set permissions for a role that does not exist in this guild." )) return False db_guild = await get_from_db(ctx.guild) current_permissions = db_guild.permissions.get(str(role.id), {}) current_permissions[permission] = value db_guild.permissions[str(role.id)] = current_permissions await db_guild.save(update_fields=['permissions']) await ctx.send( _("👌 Permission {permission} for role {role_name} [`{role_id}`] has been set to {value} in this guild.", permission=escape_everything(permission), role_name=escape_everything(role.name), role_id=role.id, value=value))
async def set_channel(self, ctx: MyContext, channel: discord.TextChannel, role: discord.Role, permission: str, value: bool): """ Set a permission for a role in a channel """ _ = await ctx.get_translate_function() if channel not in ctx.guild.channels: await ctx.send(_("❌ Can't set permissions in a channel that is not in this guild.")) return False if role.guild.id != ctx.guild.id: await ctx.send(_("❌ Can't set permissions for a role that does not exist in this guild.")) return False db_channel = await get_from_db(channel) current_permissions = db_channel.permissions.get(str(role.id), {}) current_permissions[permission] = value db_channel.permissions[str(role.id)] = current_permissions await db_channel.save(update_fields=['permissions']) await ctx.send( _("👌 Permission {0} for role {1} [`{2}`] has been set to {3} in this channel.", escape_everything(permission), escape_everything(role.name), role.id, value))
async def view_channel(self, ctx: MyContext, channel: discord.TextChannel = None): """ Display all permissions set for this channel """ _ = await ctx.get_translate_function() said_something = False guild = ctx.guild if not channel or channel.guild.id != guild.id: channel = ctx.channel db_channel = await get_from_db(channel) permissions_by_role = db_channel.permissions for role_id, role_permissions in permissions_by_role.items(): role = guild.get_role(int(role_id)) if role and role_permissions: message = [_("**{0} permissions**", escape_everything(role.name)), "```diff"] for permission, value in role_permissions.items(): sign = "+" if value else "-" message.append(f"{sign} {permission}") message.append("```") said_something = True await ctx.send("\n".join(message)) if not said_something: await ctx.send(_("There are no specific permissions set in this channel."))
async def view_guild(self, ctx: MyContext): """ Display all permissions set for this guild """ _ = await ctx.get_translate_function() said_something = False guild = ctx.guild db_guild = await get_from_db(guild) permissions_by_role = db_guild.permissions for role_id, role_permissions in permissions_by_role.items(): role = guild.get_role(int(role_id)) if role and len(role_permissions): message = [ _("**{role} permissions**", role=escape_everything(role.name)), "```diff" ] for permission, value in role_permissions.items(): sign = "+" if value else "-" message.append(f"{sign} {permission}") message.append("```") said_something = True await ctx.send("\n".join(message)) if not said_something: await ctx.send( _("There are no specific permissions set in this guild."))
async def set_member(self, ctx: MyContext, member: discord.Member, permission: str, value: bool): """ Set a permission for a member in a guild """ _ = await ctx.get_translate_function() db_user = await get_from_db(member, as_user=False) db_user.permissions[permission] = value await db_user.save(update_fields=['permissions']) await ctx.send(_( "👌 Permission {0} for member {1} has been set to {2} globally.", escape_everything(permission), member, value))
async def set_user(self, ctx: MyContext, user: discord.User, permission: str, value: bool): """ Set a permission for a specific user, globally. """ _ = await ctx.get_translate_function() db_user = await get_from_db(user, as_user=True) db_user.permissions[permission] = value await db_user.save(update_fields=['permissions']) await ctx.send( _("👌 Permission {0} for user {1} has been set to {2} globally.", escape_everything(permission), str(user), value))
async def on_command_error(self, ctx: MyContext, exception: Exception) -> None: _ = await ctx.get_translate_function() # This prevents any commands with local handlers being handled here in on_command_error. if hasattr(ctx.command, 'on_error'): return ignored = (commands.CommandNotFound, ) # Allows us to check for original exceptions raised and sent to CommandInvokeError. # If nothing is found. We keep the exception passed to on_command_error. # Anything in ignored will return and prevent anything happening. if isinstance(exception, ignored): return DELETE_ERROR_MESSAGE_AFTER = 60 command_invoke_help = f"{ctx.prefix}{ctx.command.qualified_name} {ctx.command.signature}" ctx.logger.debug( f"Error during processing: {exception} ({repr(exception)})") # https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.CommandError if isinstance(exception, commands.CommandError): if isinstance(exception, commands.ConversionError): original = exception.original message = _( "There was an error converting one of your arguments with {exception.converter}. The " "correct syntax would be `{command_invoke_help}`. The converter returned the following error" ": {original}", command_invoke_help=command_invoke_help, original=escape_everything(str(original))) elif isinstance(exception, commands.UserInputError): if isinstance(exception, commands.errors.MissingRequiredArgument): message = _( "This command is missing an argument. The correct syntax would be `{command_invoke_help}`.", command_invoke_help=command_invoke_help) elif isinstance(exception, commands.errors.ArgumentParsingError): if isinstance(exception, commands.UnexpectedQuoteError): message = _( "Too many quotes were provided in your message: don't forget to escape your " "quotes like this `\\{exception.quote}`. The correct syntax for the command is " "`{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.InvalidEndOfQuotedStringError): message = _( "A space was expected after a closing quote, but I found {exception.char}. " "Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.ExpectedClosingQuoteError): message = _( "A closing quote was expected, but wasn't found. Don't forget to close your " "quotes with `{exception.close_quote}` at the end of your argument. Please check " "that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.TooManyArguments): message = _( "Too many arguments were passed in this command. " "Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help) else: # Should not trigger, just in case some more errors are added. message = _( "The way you are invoking this command is confusing me. The correct syntax would " "be `{command_invoke_help}`.", command_invoke_help=command_invoke_help) elif isinstance(exception, commands.BadArgument): message = _( "An argument passed was incorrect. `{exception}`." "Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.BadUnionArgument): message = _( "{exception} Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=str(exception)) else: message = f"{str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.CheckFailure): if isinstance(exception, commands.PrivateMessageOnly): message = _( "This command can only be used in a private message.") elif isinstance(exception, commands.NoPrivateMessage): message = _( "This command cannot be used in a private message.") elif isinstance(exception, commands.CheckAnyFailure): message = _( "Multiple errors were encountered when running your command : {exception.errors}", exception=exception) elif isinstance(exception, commands.NotOwner): message = _( "You need to be the owner of the bot to run that.") # We could edit and change the message here, but the lib messages are fine and specify exactly what permissions are missing elif isinstance(exception, commands.MissingPermissions): message = f"{str(exception)}" elif isinstance(exception, commands.BotMissingPermissions): message = f"{str(exception)}" elif isinstance(exception, commands.MissingRole): message = f"{str(exception)}" elif isinstance(exception, commands.BotMissingRole): message = f"{str(exception)}" elif isinstance(exception, commands.MissingAnyRole): message = f"{str(exception)}" elif isinstance(exception, commands.BotMissingAnyRole): message = f"{str(exception)}" elif isinstance(exception, commands.NSFWChannelRequired): message = _( "You need to be in a NSFW channel to run that.") # Custom checks errors elif isinstance(exception, checks.NotInServer): correct_guild = self.bot.get_guild( exception.must_be_in_guild_id) if correct_guild: message = _( "You need to be in the {correct_guild.name} server (`{exception.must_be_in_guild_id}`).", correct_guild=correct_guild, exception=exception) else: message = _( "You need to be in a server with ID {exception.must_be_in_guild_id}.", exception=exception) elif isinstance(exception, checks.HavingPermission): message = _( "You have the `{exception.permission}` permission.", exception=exception) elif isinstance(exception, checks.MissingPermission): message = _( "You need the `{exception.permission}` permission.", exception=exception) elif isinstance(exception, checks.HavingPermissions): message = _( "You have {exception.required} or more of the following permissions : `{exception.permissions}`.", exception=exception) elif isinstance(exception, checks.MissingPermissions): message = _( "You need {exception.required} or more of the following permissions : `{exception.permissions}`.", exception=exception) elif isinstance(exception, checks.BotIgnore): return else: message = f"Check error running this command : {str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.CommandNotFound): # This should be disabled. message = _("The provided command was not found.") elif isinstance(exception, commands.errors.DisabledCommand): message = _("That command has been disabled.") elif isinstance(exception, commands.CommandInvokeError): message = _( "There was an error running the specified command. Contact the bot admins." ) ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.errors.CommandOnCooldown): if await self.bot.is_owner( ctx.author ) or checks.has_permission("bot.bypass_cooldowns"): await ctx.reinvoke() return else: delta = datetime.timedelta( seconds=min(round(exception.retry_after, 1), 1)) # NOTE : This message uses a formatted, direction date in some_time. Formatted, it'll give something like : # "This command is overused. Please try again *in 4 seconds*" message = _( "This command is overused. Please try again {some_time}.", some_time=dates.format_timedelta( delta, add_direction=True, locale=await ctx.get_language_code())) elif isinstance(exception, commands.errors.MaxConcurrencyReached): message = f"{str(exception)}" # The message from the lib is great. else: message = f"{str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) else: message = _( "This should not have happened. A command raised an error that does not comes from CommandError. Please inform the owner." ) ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) if message: await ctx.send("❌ " + message, delete_after=DELETE_ERROR_MESSAGE_AFTER)
async def on_command_error(self, ctx: MyContext, exception: Exception) -> None: _ = await ctx.get_translate_function() # This prevents any commands with local handlers being handled here in on_command_error. if hasattr(ctx.command, 'on_error'): return ignored = (commands.CommandNotFound, ) # Allows us to check for original exceptions raised and sent to CommandInvokeError. # If nothing is found. We keep the exception passed to on_command_error. # Anything in ignored will return and prevent anything happening. if isinstance(exception, ignored): return delete_error_message_after = 60 command_invoke_help = f"{ctx.prefix}{ctx.command.qualified_name} {ctx.command.signature}" ctx.logger.warning( f"Error during processing: {exception} ({repr(exception)})") # https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.CommandError if isinstance(exception, commands.CommandError): if isinstance(exception, commands.ConversionError): original = exception.original message = _( "There was an error converting one of your arguments with {0}. The " "correct syntax would be `{1}`. The converter returned the following " "error: {2}", exception.converter, command_invoke_help, escape_everything(str(original))) elif isinstance(exception, commands.UserInputError): if isinstance(exception, commands.errors.MissingRequiredArgument): message = _( "This command is missing an argument. The correct syntax would be " "`{0}`.", command_invoke_help) elif isinstance(exception, commands.errors.ArgumentParsingError): if isinstance(exception, commands.UnexpectedQuoteError): message = _( "Too many quotes were provided in your message: don't forget to escape your " "quotes like this `\\{0}`. The correct syntax for the command is " "`{1}`.", exception.quote, command_invoke_help) elif isinstance(exception, commands.InvalidEndOfQuotedStringError): message = _( "A space was expected after a closing quote, but I found {0}. " "Please check that you are using the correct syntax: `{1}`.", exception.char, command_invoke_help) elif isinstance(exception, commands.ExpectedClosingQuoteError): message = _( "A closing quote was expected, but wasn't found. Don't forget to close your " "quotes with `{0}` at the end of your argument. Please check " "that you are using the correct syntax: `{1}`.", exception.close_quote, command_invoke_help) elif isinstance(exception, commands.TooManyArguments): message = _( "Too many arguments were passed in this command. " "Please check that you are using the correct syntax: `{0}`.", command_invoke_help) else: # Should not trigger, just in case some more errors are added. message = _( "The way you are invoking this command is confusing me. The correct syntax would " "be `{0}`.", command_invoke_help) elif isinstance(exception, commands.BadArgument): message = _( "An argument passed was incorrect. `{0}`." "Please check that you are using the correct syntax: `{1}`.", str(exception), command_invoke_help) elif isinstance(exception, commands.BadUnionArgument): message = _( "{0} Please check that you are using the correct syntax: `{1}`.", str(exception), command_invoke_help) else: message = "{str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.CheckFailure): if isinstance(exception, commands.PrivateMessageOnly): message = _( "This command can only be used in a private message.") elif isinstance(exception, commands.NoPrivateMessage): message = _( "This command cannot be used in a private message.") elif isinstance(exception, commands.CheckAnyFailure): message = _( "Multiple errors were encountered when running your command: {0}", exception.errors) elif isinstance(exception, commands.NotOwner): message = _( "You need to be the owner of the bot to run that.") # We could edit and change the message here, but the lib messages are fine and specify exactly what # permissions are missing elif isinstance(exception, commands.MissingPermissions): message = _( "You are missing permissions to run this command. {0}", " ".join(exception.missing_perms)) elif isinstance(exception, commands.BotMissingPermissions): message = _( "I am missing permissions to run this command. {0}", " ".join(exception.missing_perms)) elif isinstance(exception, commands.MissingRole): message = _("You are missing the following role: {0}", exception.missing_role) elif isinstance(exception, commands.BotMissingRole): message = _("I am missing the following role: {0}", exception.missing_role) elif isinstance(exception, commands.MissingAnyRole): message = _( "You are missing one of the following roles: {0}", " ".join(exception.missing_roles)) elif isinstance(exception, commands.BotMissingAnyRole): message = _("I am missing one of the following roles: {0}", " ".join(exception.missing_roles)) elif isinstance(exception, commands.NSFWChannelRequired): message = _( "You need to be in a NSFW channel to run that.") # Custom checks errors elif isinstance(exception, checks.NotInServer): correct_guild = self.bot.get_guild( exception.must_be_in_guild_id) if correct_guild: message = _( "You need to be in the {0} server " "(`{1}`).", correct_guild.name, exception.must_be_in_guild_id) else: message = _("You need to be in a server with ID {0}.", exception.must_be_in_guild_id) elif isinstance(exception, checks.HavingPermission): message = _("You have the `{0}` permission.", exception.permission) elif isinstance(exception, checks.MissingPermission): message = _("You need the `{0}` permission.", exception.permission) elif isinstance(exception, checks.HavingPermissions): message = _( "You have {0} or more of the following permissions: " "`{1}`.", exception.required, exception.permissions) elif isinstance(exception, checks.MissingPermissions): message = _( "You need {0} or more of the following permissions: " "`{1}`.", exception.required, exception.permissions) elif isinstance(exception, checks.BotIgnore): return else: message = "Check error running this command : {str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.CommandNotFound): # This should be disabled. message = _("The provided command was not found.") elif isinstance(exception, commands.errors.DisabledCommand): message = _("That command has been disabled.") elif isinstance(exception, commands.CommandInvokeError): if isinstance(exception.original, discord.errors.Forbidden): await ctx.author.send( _("I don't have permissions to send messages there! Try again somewhere I do " "have permissions to send messages!")) return elif isinstance(exception.original, RuntimeError) and exception.original.args[0] == \ "The bot hasn't been set up yet! Ensure bot.async_setup is called ASAP!": message = _( "The bot's still setting up, please wait a few minutes and try again!" ) elif isinstance(exception.original, discord.errors.NotFound): message = _( "I can't find your original message, Discord may be having issues! Try again." ) elif isinstance(exception.original, api.NoDataAvailable): message = _( "No data is available at the moment. Wait a few moments. **Spamming this command will " "result in a temporary ban!**") elif isinstance(exception.original, InvalidKeyError): message = _( "A invalid key was found. If you want to use `{` and `}`, make sure you escape them by " "using two brackets instead of one. If you don't, make sure the values are correct." "{0}", exception.original.__str__()) else: message = _( "There was an error running the specified command‽ This error has been logged." ) # we want the original instead of the CommandError one await submit_error_message(exception.original, "unknown thing", self.bot, ctx) # ctx.logger.error("".join(traceback.format_exception(type(exception), # exception, exception.__traceback__))) elif isinstance(exception, commands.errors.CommandOnCooldown): if await self.bot.is_owner(ctx.author): try: await ctx.reinvoke() except Exception as e: await self.on_command_error(ctx, e) return else: delta = datetime.timedelta(seconds=exception.retry_after) # NOTE : This message uses a formatted, direction date in some_time. Formatted, it'll give something # like: "This command is overused. Please try again *in 4 seconds*" message = _( "You are being ratelimited. Please try again {0}.", dates.format_timedelta(delta, add_direction=True, locale=await ctx.get_language_code())) elif isinstance(exception, commands.errors.MaxConcurrencyReached): bucket_types = { commands.BucketType.default: _("globally"), commands.BucketType.user: _("per user"), commands.BucketType.guild: _("per guild"), commands.BucketType.channel: _("per channel"), commands.BucketType.member: _("per member"), commands.BucketType.category: _("per category"), commands.BucketType.role: _("per role") } message = _( "Too many users are using this command. Only {0} users can use it at the same time {1}.", exception.number, bucket_types[exception.per]) else: message = "{str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) await submit_error_message(exception, "unknown thing", ctx.bot, ctx) else: message = _( "This should not have happened. A command raised an error that does not comes from " "CommandError. Please inform the owner.") ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) if message: await ctx.send("❌ " + message + _( "\nFor help, join the bot's support server at {0}\n" "Check <https://discordstatus.com/> for more details on Discord issues.", self.bot.support_server_invite), delete_after=delete_error_message_after) else: await ctx.send( "❌ " + _("No message was defined. This error has been logged."))
async def view_me(self, ctx: MyContext, permission: str, negate: bool = False, administrator: bool = True, show_none: bool = False): """ Check a permission for yourself """ _ = await ctx.get_translate_function() value = await permissions.has_permission(ctx, permission, negate=negate, administrator=administrator) if value: await ctx.send(_("😃 You have that permission.")) else: await ctx.send(_("☹️ You don't have that permission.")) if ctx.guild: message = [_("Details of permissions hierarchy"), "```diff"] parsed_permission = permission.split(".") default_permissions = ctx.bot.config['permissions']['default'] value, by = _recursive_permission_check(parsed_permission, default_permissions) message.append(_("{0} Default (from {0}{1})", get_sign(value), by)) db_member: DiscordMember = await get_from_db(ctx.author) db_channel: DiscordChannel = await get_from_db(ctx.channel) db_user: DiscordUser = db_member.user db_guild: DiscordGuild = db_member.guild guild_permissions = db_guild.permissions for role in ctx.author.roles: role_permissions = guild_permissions.get(str(role.id), {}) if role_permissions: value, by = _recursive_permission_check(parsed_permission, role_permissions) if value in [True, False] or show_none: message.append(_("{0} Guild role {1} (from {0}{2})", get_sign(value), escape_everything(role.name), by)) channel_permissions = db_channel.permissions for role in ctx.author.roles: role_permissions = channel_permissions.get(str(role.id), {}) if role_permissions: value, by = _recursive_permission_check(parsed_permission, role_permissions) if value in [True, False] or show_none: message.append(_("{0} Channel role {1} (from {0}{2})", get_sign(value), escape_everything(role.name), by)) member_permissions = db_member.permissions value, by = _recursive_permission_check(parsed_permission, member_permissions) if value in [True, False] or show_none: message.append(_("{0} Member (from {0}{1})", get_sign(value), by)) fixed_permissions = ctx.bot.config['permissions']['fixed'] value, by = _recursive_permission_check(parsed_permission, fixed_permissions) if value in [True, False] or show_none: message.append(_("{0} Fixed (from {0}{1})", get_sign(value), by)) user_permissions = db_user.permissions value, by = _recursive_permission_check(parsed_permission, user_permissions) if value in [True, False] or show_none: message.append(_("{0} User (from {0}{1})", get_sign(value), by)) message.append("```") await ctx.send("\n".join(message))
async def on_command_error(self, ctx: MyContext, exception: Exception) -> None: _ = await ctx.get_translate_function() # This prevents any commands with local handlers being handled here in on_command_error. if hasattr(ctx.command, 'on_error'): return ignored = (commands.CommandNotFound, ) # Allows us to check for original exceptions raised and sent to CommandInvokeError. # If nothing is found. We keep the exception passed to on_command_error. # Anything in ignored will return and prevent anything happening. if isinstance(exception, ignored): return command_invoke_help = f"{ctx.prefix}{ctx.command.qualified_name} {ctx.command.signature}" ctx.logger.debug( f"Error during processing: {exception} ({repr(exception)})") if hasattr(exception, "original"): exception = exception.original # https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.CommandError if isinstance(exception, commands.CommandError): if isinstance(exception, commands.ConversionError): original = exception.original message = _( "There was an error converting one of your arguments with {exception.converter}. The " "correct syntax would be `{command_invoke_help}`. The converter returned the following " "error: {original}", command_invoke_help=command_invoke_help, original=escape_everything(str(original))) elif isinstance(exception, commands.UserInputError): if isinstance(exception, commands.errors.MissingRequiredArgument): message = _( "This command is missing an argument. The correct syntax would be `{command_invoke_help}`.", command_invoke_help=command_invoke_help) elif isinstance(exception, commands.errors.ArgumentParsingError): if isinstance(exception, commands.UnexpectedQuoteError): message = _( "Too many quotes were provided in your message: don't forget to escape your " "quotes like this `\\{exception.quote}`. The correct syntax for the command is " "`{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.InvalidEndOfQuotedStringError): message = _( "A space was expected after a closing quote, but I found {exception.char}. " "Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.ExpectedClosingQuoteError): message = _( "A closing quote was expected, but wasn't found. Don't forget to close your " "quotes with `{exception.close_quote}` at the end of your argument. Please check " "that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.TooManyArguments): message = _( "Too many arguments were passed in this command. " "Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help) else: # Should not trigger, just in case some more errors are added. message = _( "The way you are invoking this command is confusing me. The correct syntax would " "be `{command_invoke_help}`.", command_invoke_help=command_invoke_help) elif isinstance(exception, commands.BadArgument): message = _( "An argument passed was incorrect. `{exception}`. " "Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=exception) elif isinstance(exception, commands.BadUnionArgument): message = _( "{exception} Please check that you are using the correct syntax: `{command_invoke_help}`.", command_invoke_help=command_invoke_help, exception=str(exception)) else: message = f"{str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.CheckFailure): if isinstance(exception, commands.PrivateMessageOnly): message = _( "This command can only be used in a private message.") elif isinstance(exception, commands.NoPrivateMessage): message = _( "This command cannot be used in a private message.") elif isinstance(exception, commands.CheckAnyFailure): message = _( "Multiple errors were encountered when running your command: {exception.errors}", exception=exception) elif isinstance(exception, commands.NotOwner): message = _( "You need to be the owner of the bot to run that.") # We could edit and change the message here, but the lib messages are fine and specify exactly what # permissions are missing elif isinstance(exception, commands.MissingPermissions): message = f"{str(exception)}" elif isinstance(exception, commands.BotMissingPermissions): message = f"{str(exception)}" elif isinstance(exception, commands.MissingRole): message = f"{str(exception)}" elif isinstance(exception, commands.BotMissingRole): message = f"{str(exception)}" elif isinstance(exception, commands.MissingAnyRole): message = f"{str(exception)}" elif isinstance(exception, commands.BotMissingAnyRole): message = f"{str(exception)}" elif isinstance(exception, commands.NSFWChannelRequired): message = _( "You need to be in a NSFW channel to run that.") # Custom checks errors elif isinstance(exception, checks.NotInServer): correct_guild = self.bot.get_guild( exception.must_be_in_guild_id) if correct_guild: message = _( "You need to be in the {correct_guild.name} server (`{exception.must_be_in_guild_id}`).", correct_guild=correct_guild, exception=exception) else: message = _( "You need to be in a server with ID {exception.must_be_in_guild_id}.", exception=exception) elif isinstance(exception, checks.NotInChannel): correct_channel = self.bot.get_channel( exception.must_be_in_channel_id) if correct_channel: message = _( "You need to be in the {correct_channel.name} channel (`{exception.must_be_in_channel_id}`).", correct_channel=correct_channel, exception=exception) else: message = _( "You need to be in a channel with ID {exception.must_be_in_channel_id}.", exception=exception) elif type(exception).__name__ == NotEnoughExperience.__name__: message = _( "You don't have enough experience to enjoy this item. You'd need at least {exception.needed} exp, but you only have {exception.having}.", exception=exception) elif isinstance(exception, checks.AccessTooLow): message = _( "Your access level is too low : you have an access level of {exception.current_access.name}, and you need at least {exception.required_access.name}.", exception=exception) elif isinstance(exception, checks.ChannelDisabled): db_guild = await get_from_db(ctx.guild) if db_guild.channel_disabled_message: message = _( "The game isn't running on this channel. " "Admins can disable this message by running `dh!settings channel_disabled_message False`, " "or can enable the channel with `dh!settings enabled True`.", exception=exception) else: return elif isinstance(exception, checks.BotIgnore): return else: message = _( "Check error running this command: {err_data}", err_data= f"{str(exception)} ({type(exception).__name__})") ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.CommandNotFound): # This should be disabled. message = _("The provided command was not found.") elif isinstance(exception, commands.errors.DisabledCommand): message = _("That command has been disabled.") elif isinstance(exception, commands.CommandInvokeError): message = _( "There was an error running the specified command. Contact the bot admins." ) ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) elif isinstance(exception, commands.errors.CommandOnCooldown): if await self.bot.is_owner(ctx.author): await ctx.reinvoke() return else: delta = datetime.timedelta( seconds=min(round(exception.retry_after, 1), 1)) # NOTE: This message uses a formatted, direction date in some_time. Formatted, it'll give # something like: # "This command is overused. Please try again *in 4 seconds*" message = _( "This command is overused. Please try again {some_time}.", some_time=dates.format_timedelta( delta, add_direction=True, locale=(await ctx.get_language_code()))) elif isinstance(exception, commands.errors.MaxConcurrencyReached): message = f"{str(exception)}" # The message from the lib is great. else: message = f"{str(exception)} ({type(exception).__name__})" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) else: message = _( "This should not have happened. A command raised an error that does not comes from CommandError. " "Please inform the owner.") ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) if isinstance(exception, tortoise.exceptions.OperationalError): message = _( "You are above the limits of DuckHunt database. Try to reduce your expectations. Database message: `{exception}`", exception=exception) elif isinstance(exception, babel.core.UnknownLocaleError): message = f"Unknown server language. Fix with `{ctx.prefix}set lang en`" elif isinstance(exception, discord.Forbidden): message = _( "Missing permissions, please check I can embed links here. `{exception}`", exception=exception) elif isinstance(exception, menus.CannotAddReactions): message = _( "Missing permissions, please check I can add reactions here." ) else: message = _( "This should not have happened. A command raised an error that does not come from CommandError, and isn't handled by our error handler. " "Please inform the owner.") + "\n```py\n" + "".join( traceback.format_exception( type(exception), exception, exception.__traceback__)) + "\n```" ctx.logger.error("".join( traceback.format_exception(type(exception), exception, exception.__traceback__))) if message: await ctx.send("❌ " + message, delete_after=DELETE_ERROR_MESSAGE_AFTER)