async def spotlight_on_error(self, exc, ctx): cmd_string = message_log_str(ctx.message) if isinstance(exc, commands.CommandInvokeError): root_exc = exc.__cause__ if exc.__cause__ is not None else exc # noinspection PyUnresolvedReferences if isinstance(root_exc, gsheets.Error): # any Google API errors logger.error("Google API error while processing command: {}\n\n{}" .format(cmd_string, tb_log_str(root_exc))) await self.bot.send_message(ctx.message.channel, "An error occurred while communicating with the Google API. " "See bot output for details.") await self.bot.send_message(self.dest_output, ("[ERROR] An error occurred while communicating with the Google API.\n" "Original command: {}\n{}\n\nSee logs for details") .format(cmd_string, exc_log_str(root_exc))) elif isinstance(root_exc, (gsheets.UnknownClientSecretsFlowError, gsheets.InvalidClientSecretsError) ): # Auth credentials file errors logger.error("Problem with Google API credentials file: {}\n\n{}" .format(cmd_string, tb_log_str(root_exc))) await self.bot.send_message(ctx.message.channel, "Problem with the stored Google API credentials. " "See bot output for details.") await self.bot.send_message(self.dest_output, ("[ERROR] Problem with Google API credentials file.\n" "Original command: {}\n{}\n\nSee logs for details") .format(cmd_string, exc_log_str(root_exc))) elif isinstance(root_exc, discord.HTTPException): cmd_string = str(ctx.message.content)[11:] logger.error("Error sending spotlight info ({}): {!s}" .format(cmd_string, root_exc)) await self.bot.send_message(ctx.message.channel, ("Error sending spotlight info, " "maybe the message is too long but Discord is stupid and might not " "give a useful error message here: {!s}").format(root_exc)) await self.bot.send_message(self.dest_output, ("[ERROR] Error sending spotlight info.\n" "Original command: {}\nDiscord API error: {!s}\n\n" "See logs for details").format(cmd_string, root_exc)) else: core_cog = self.bot.get_cog("CoreCog") await core_cog.on_command_error(exc, ctx, force=True) # Other errors can bubble up else: core_cog = self.bot.get_cog("CoreCog") await core_cog.on_command_error(exc, ctx, force=True) # Other errors can bubble up
async def _command_error(self, e: Exception, ctx: commands.Context): if isinstance(e, commands.BadArgument) and e.args[0] == 'channel': logger.error("No sticky for channel #{}".format(e.args[1].name)) await self.send_message( ctx.message.channel, ctx.message.author.mention + " Error: No sticky configured for channel #{}".format( e.args[1].name)) if isinstance(e, discord.Forbidden): data = self.cog_state.get(ctx.args[0].id) logger.error( "Error updating sticky {!r}: Permission error.\n\n{}".format( data, tb_log_str(e))) await self.send_message( ctx.message.channel, ctx.message.author.mention + "Error updating sticky {!r}. Discord permission error.".format( data)) elif isinstance(e, discord.HTTPException): data = self.cog_state.get(ctx.args[0].id) await self.send_message( ctx.message.channel, ctx.message.author.mention + "Error updating sticky {!r}. HTTP error: {}".format( data, exc_log_str(e))) else: await self.core.on_command_error(e, ctx, force=True ) # Other errors can bubble up
async def testfile_error(self, exc: Exception, ctx: commands.Context): exc = exc.__cause__ if exc.__cause__ is not None else exc if isinstance(exc, IOError): await self.send_message( ctx.message.channel, "Error opening test file test/wikichannel.txt: {}".format( exc_log_str(exc))) logger.error( "Error opening test file test/wikichannel.txt: {}".format( tb_log_str(exc))) else: core_cog = self.bot.get_cog("CoreCog") await core_cog.on_command_error(exc, ctx, force=True ) # Other errors can bubble up
async def on_task_update_sticky_error(self, e: Exception, t: TaskInstance): data = t.args[0] # type: StickyData if isinstance(e, discord.Forbidden): await self.send_output( "Error updating sticky {!r}. Permission error: {}".format( data, exc_log_str(e))) elif isinstance(e, discord.HTTPException): await self.send_output( "Error updating sticky {!r}. Will retry. HTTP error: {}". format(data, exc_log_str(e))) self.scheduler.schedule_task_in(self.task_update_sticky, 60, args=(data, )) else: logger.error("Error updating sticky {!r}: {}".format( data, tb_log_str(e))) await self.send_output("Error updating sticky {!r}: {}".format( data, exc_log_str(e)))
def import_file(filename, dry_run, verbose, check_matches): """ Import a CSV file. Params correspond to command-line arguments. """ success = True fieldnames = [ 'discord_id', 'title', 'genre', 'subgenre', 'type', 'pitch', 'description', 'url' ] with open(filename, 'r', newline='', encoding='utf-8') as f: csvr = csv.DictReader(f, fieldnames=fieldnames) print("Importing {}...".format(filename)) for row_dict in csvr: try: with query.transaction(): import_project(row_dict, dry_run, verbose, check_matches) except Exception as ee: print("[ERROR]", tb_log_str(ee)) success = False continue finally: print("") return success
async def remove(self, ctx: commands.Context, channel: discord.Channel): """!kazhelp brief: Disable a configured sticky message in a channel. description: | Disables the sticky message in the specified channel. This will delete any existing sticky message in that channel. parameters: - name: channel type: channel description: Channel to change examples: - command: ".sticky rem #resources" description: "Disables the sticky message in the #resources channel and removes any existing messages." """ try: data = self.cog_state.messages[channel.id] except KeyError: raise commands.BadArgument("channel", channel) if data.posted_message_id: try: message = await data.get_posted_message(self.bot) logger.info("Deleting old sticky message in #{.name:s}".format( channel)) await self.bot.delete_message(message) except discord.HTTPException as e: logger.warning( "Failed to delete existing sticky message in #{}; skipping: {}" .format(channel.name, tb_log_str(e))) await self.send_output( "[WARNING] Failed to delete existing sticky message in #{}; skipping.\n\n{}" .format(channel.name, exc_log_str(e))) self.cancel_channel_task(channel) sticky_config = self.cog_state.messages del sticky_config[channel.id] self.cog_state.set('messages', sticky_config) await self.send_message(ctx.message.channel, "Removed sticky in #{}".format(data.channel))
async def on_command_error(self, exc, ctx, force=False): """ Handles all command errors (see the ``discord.ext.commands.errors`` module). This method will do nothing if a command is detected to have an error handler ("on_error"); if you want on_command_error's default behaviour to take over, within a command error handler, you can call this method and pass ``force=True``. If you define custom command error handlers, note that CommandInvokeError is the one you want to handle for arbitrary errors (i.e. any exception raised that isn't derived from CommandError will cause discord.py to raise a CommandInvokeError from it). """ cmd_string = message_log_str(ctx.message) if not force and hasattr(ctx.command, "on_error"): return if ctx is not None and ctx.command is not None: usage_str = get_usage_str(ctx) else: usage_str = '(Unable to retrieve usage information)' if isinstance(exc, commands.CommandOnCooldown): await self.bot.send_message( ctx.message.channel, "`{}` is on cooldown! Try again in {:.0f} seconds.".format( get_command_str(ctx), max(exc.retry_after, 1.0))) elif isinstance(exc, commands.CommandInvokeError): root_exc = exc.__cause__ if exc.__cause__ is not None else exc if isinstance(root_exc, KeyboardInterrupt): logger.warning("Interrupted by user (SIGINT)") raise root_exc elif isinstance(root_exc, discord.HTTPException): # API errors err_msg = 'While executing {c}\n\nDiscord API error {e!s}' \ .format(c=cmd_string, e=root_exc) logger.error(err_msg + "\n\n{}".format(tb_log_str(root_exc))) await self.bot.send_message( self.dest_output, "[ERROR] " + err_msg + "\n\nSee log for details") else: logger.error( "An error occurred while processing the command: {}\n\n{}". format(cmd_string, tb_log_str(root_exc))) await self.bot.send_message( self.dest_output, "[ERROR] While executing {}\n\n{}\n\nSee logs for details". format(cmd_string, exc_log_str(root_exc))) # In all cases (except if return early/re-raise) await self.bot.send_message( ctx.message.channel, "An error occurred! Details have been logged. Let a mod know so we can " "investigate.") elif isinstance(exc, commands.DisabledCommand): msg = "Attempt to use disabled command: {}".format(cmd_string) logger.warning(msg) # No need to log this on Discord - not something mods need to be aware of # No need to inform user of this - prevents spam, "disabled" commands could just not # exist elif isinstance(exc, ModOnlyError): err_msg = "Unauthorised user for this command (not a moderator): {!r}".format( cmd_string) logger.warning(err_msg) await self.bot.send_message(self.dest_output, '[WARNING] ' + err_msg) await self.bot.send_message(ctx.message.channel, "Only mods can use that command.") elif isinstance(exc, AdminOnlyError): err_msg = "Unauthorised user for this command (not an admin): {!r}".format( cmd_string) logger.warning(err_msg) await self.bot.send_message(self.dest_output, '[WARNING] ' + err_msg) await self.bot.send_message(ctx.message.channel, "Only admins can use that command.") elif isinstance(exc, (UnauthorizedUserError, commands.CheckFailure)): logger.warning("Check failed on command: {!r}\n\n{}".format( cmd_string, tb_log_str(exc))) await self.bot.send_message( ctx.message.channel, "You're not allowed to use that command. " " *(Dev note: Implement error handler with more precise reason)*" ) elif isinstance(exc, UnauthorizedChannelError): err_msg = "Unauthorised channel for this command: {!r}".format( cmd_string) logger.warning(err_msg) await self.bot.send_message(self.dest_output, '[WARNING] ' + err_msg) await self.bot.send_message(ctx.message.channel, "You can't use that command here.") elif isinstance(exc, commands.NoPrivateMessage): msg = "Attempt to use non-PM command in PM: {}".format(cmd_string) logger.warning(msg) await self.bot.send_message( ctx.message.channel, "Sorry, you can't use that command in PM.") # No need to log this on Discord, spammy and isn't something mods need to be aware of elif isinstance(exc, commands.BadArgument): exc_msg = exc.args[0] if len( exc.args) > 0 else '(No error message).' msg = "Bad argument passed in command: {}\n{}".format( cmd_string, exc_msg) logger.warning(msg) await self.bot.send_message(ctx.message.channel, ( "Invalid argument(s) for the command `{}`. {}\n\n**Usage:** `{}`\n\n" "Use `{}` for help. " "*(Dev note: Add error handler with more precise reason when possible)*" ).format(get_command_str(ctx), exc_msg, usage_str, get_help_str(ctx))) # No need to log user errors to mods elif isinstance(exc, commands.TooManyArguments): msg = "Too many arguments passed in command: {}".format(cmd_string) logger.warning(msg) await self.bot.send_message( ctx.message.channel, "Too many arguments.\n\n**Usage:** `{}`\n\nUse `{}` for help.". format(usage_str, get_help_str(ctx))) # No need to log user errors to mods elif isinstance(exc, commands.MissingRequiredArgument): msg = "Missing required arguments in command: {}".format( cmd_string) logger.warning(msg) await self.bot.send_message( ctx.message.channel, "Missing argument(s) for the command `{}`.\n\n**Usage:** `{}`\n\nUse `{}` for help." .format(get_command_str(ctx), usage_str, get_help_str(ctx))) # No need to log user errors to mods elif isinstance(exc, commands.CommandNotFound): msg = "Unknown command: {}".format(cmd_string) # avoid some natural language things that start with period (ellipsis, etc.) if ctx.invoked_with not in [ '.', '..' ] and not ctx.invoked_with.startswith('.'): logger.warning(msg) await self.bot.send_message( ctx.message.channel, "Sorry, I don't know the command `{}{.invoked_with}`". format(get_command_prefix(ctx), ctx)) else: logger.exception("Unknown exception occurred") await self.bot.send_message( ctx.message.channel, "An unexpected error occurred! Details have been logged. Let a mod know so we can " "investigate.") await self.bot.send_message( self.dest_output, ("[ERROR] Unknown error while trying to process command {}\n" "Error: {!s}\n\nSee logs for details").format( cmd_string, exc))
async def on_command_error(self, exc, ctx, force=False): """ Handles all command errors (see the ``discord.ext.commands.errors`` module). This method will do nothing if a command is detected to have an error handler ("on_error"); if you want on_command_error's default behaviour to take over, within a command error handler, you can call this method and pass ``force=True``. If you define custom command error handlers, note that CommandInvokeError is the one you want to handle for arbitrary errors (i.e. any exception raised that isn't derived from CommandError will cause discord.py to raise a CommandInvokeError from it). """ cmd_string = message_log_str(ctx.message) author_mention = ctx.message.author.mention + ' ' if not force and hasattr(ctx.command, "on_error"): return if ctx is not None and ctx.command is not None: usage_str = get_usage_str(ctx) else: usage_str = '(Unable to retrieve usage information)' if isinstance(exc, DeleteMessage): try: await self.bot.delete_message(exc.message) logger.info("on_command_error: Deleted invoking message") except discord.errors.DiscordException: logger.exception("Can't delete invoking message!") exc = exc.cause # and continue on to handle the cause of the DeleteMessage... if isinstance(exc, commands.CommandOnCooldown): await self.bot.send_message(ctx.message.channel, author_mention + "`{}` is on cooldown! Try again in {:.0f} seconds." .format(get_command_str(ctx), max(exc.retry_after, 1.0))) elif isinstance(exc, commands.CommandInvokeError): root_exc = exc.__cause__ if exc.__cause__ is not None else exc if isinstance(root_exc, KeyboardInterrupt): logger.warning("Interrupted by user (SIGINT)") raise root_exc elif isinstance(root_exc, discord.HTTPException): # API errors err_msg = 'While executing {c}\n\nDiscord API error {e!s}' \ .format(c=cmd_string, e=root_exc) logger.error(err_msg + "\n\n{}".format(tb_log_str(root_exc))) await self.send_output( "[ERROR] " + err_msg + "\n\nSee log for details") else: logger.error("An error occurred while processing the command: {}\n\n{}" .format(cmd_string, tb_log_str(root_exc))) await self.send_output( "[ERROR] While executing {}\n\n{}\n\nSee logs for details" .format(cmd_string, exc_log_str(root_exc))) # In all cases (except if return early/re-raise) await self.bot.send_message(ctx.message.channel, author_mention + "An error occurred! Details have been logged. Let a mod know so we can " "investigate.") elif isinstance(exc, commands.DisabledCommand): msg = "Attempt to use disabled command: {}".format(cmd_string) logger.warning(msg) # No need to log this on Discord - not something mods need to be aware of # No need to inform user of this - prevents spam, "disabled" commands could just not # exist elif isinstance(exc, ModOnlyError): err_msg = "Unauthorised user for this command (not a moderator): {!r}".format( cmd_string) logger.warning(err_msg) await self.send_output('[WARNING] ' + err_msg) await self.bot.send_message(ctx.message.channel, author_mention + "Only mods can use that command.") elif isinstance(exc, AdminOnlyError): err_msg = "Unauthorised user for this command (not an admin): {!r}".format( cmd_string) logger.warning(err_msg) await self.send_output('[WARNING] ' + err_msg) await self.bot.send_message(ctx.message.channel, author_mention + "Only admins can use that command.") elif isinstance(exc, (UnauthorizedUserError, commands.CheckFailure)): logger.warning( "Check failed on command: {!r}\n\n{}".format(cmd_string, tb_log_str(exc))) await self.bot.send_message(ctx.message.channel, author_mention + "You're not allowed to use that command. " " *(Dev note: Implement error handler with more precise reason)*") elif isinstance(exc, UnauthorizedChannelError): err_msg = "Unauthorised channel for this command: {!r}".format( cmd_string) logger.warning(err_msg) await self.send_output('[WARNING] ' + err_msg) await self.bot.send_message(ctx.message.channel, author_mention + "You can't use that command here.") elif isinstance(exc, commands.NoPrivateMessage): msg = "Attempt to use non-PM command in PM: {}".format(cmd_string) logger.warning(msg) await self.bot.send_message(ctx.message.channel, "Sorry, you can't use that command in PM.") # No need to log this on Discord, spammy and isn't something mods need to be aware of elif isinstance(exc, commands.BadArgument): exc_msg = exc.args[0] if len(exc.args) > 0 else '(No error message).' msg = "Bad argument passed in command: {}\n{}".format(cmd_string, exc_msg) logger.warning(msg) await self.bot.send_message(ctx.message.channel, author_mention + ("Invalid argument(s): {}\n\n**Usage:** `{}`\n\n" "Use `{}` for help.") .format(exc_msg, usage_str, get_help_str(ctx))) # No need to log user errors to mods elif isinstance(exc, commands.TooManyArguments): msg = "Too many arguments passed in command: {}".format(cmd_string) logger.warning(msg) await self.bot.send_message(ctx.message.channel, author_mention + "Too many arguments.\n\n**Usage:** `{}`\n\nUse `{}` for help." .format(usage_str, get_help_str(ctx))) # No need to log user errors to mods elif isinstance(exc, commands.MissingRequiredArgument): msg = "Missing required arguments in command: {}".format(cmd_string) logger.warning(msg) await self.bot.send_message(ctx.message.channel, author_mention + "Missing argument(s).\n\n**Usage:** `{}`\n\nUse `{}` for help." .format(usage_str, get_help_str(ctx))) # No need to log user errors to mods elif isinstance(exc, BotNotReady): try: cog_name = exc.args[0] except IndexError: cog_name = 'unknown' logger.warning("Attempted to use command while cog is not ready: {}".format(cmd_string)) await self.bot.send_message( ctx.message.channel, author_mention + "Sorry, I'm still loading the {} module! Try again in a few seconds." .format(cog_name) ) elif isinstance(exc, commands.CommandNotFound): msg = "Unknown command: {}".format(cmd_string) # safe to assume commands usually words - symbolic commands are rare # and we want to avoid emoticons ('._.', etc.), punctuation ('...') and decimal numbers # without leading 0 (.12) being detected if ctx.invoked_with and all(c.isalnum() for c in ctx.invoked_with) \ and not ctx.invoked_with[0].isdigit(): logger.warning(msg) await self.bot.send_message(ctx.message.channel, author_mention + "Sorry, I don't know the command `{}{.invoked_with}`" .format(get_command_prefix(ctx), ctx)) else: logger.exception("Unknown exception occurred") await self.bot.send_message(ctx.message.channel, author_mention + "An unexpected error occurred! Details have been logged. Let a mod know so we can " "investigate.") await self.send_output( ("[ERROR] Unknown error while trying to process command {}\n" "Error: {!s}\n\nSee logs for details").format(cmd_string, exc))
'-v', action='store_true', help='Show each project added to the database.') parser.add_argument( '--allow-duplicates', '-d', action='store_true', help= 'Do not check if an existing project exists before adding. If not specified, this ' 'script will skip any user+title matches already in the database.') args = parser.parse_args() args.file = str(Path(args.file).resolve()) add_application_path() from kaztron.cog.projects import query, wizard from kaztron.utils.discord import extract_user_id from kaztron.utils.logging import tb_log_str, exc_log_str query.init_db() try: r = import_file(args.file, args.dry_run, args.verbose, not args.allow_duplicates) except OSError as e: print("[ERROR]", exc_log_str(e)) sys.exit(1) except Exception as e: print("[ERROR]", tb_log_str(e)) sys.exit(1) sys.exit(0 if r else 1)