""" Classes used to handle bot events and errors. *Classes* --------- EventHandler ErrorHandler """ import discord # Used to init discord.Game and discord.Status, as well # as compare errors to discord errors and as typehints import traceback # Used to get the traceback of errors import sys # Used to get traceback when the specific error is not # available from discord.ext import commands # Used to compare errors with command # errors from discord_slash.context import SlashContext from utils.utilFunctions import emojiToCommand class EventHandler(): """ Handles bot events. *Methods* --------- on_ready() on_slash_command(ctx: discord_slash.context.SlashContext) on_reaction_add(ctx: discord_slash.context.SlashContext) """ def __init__(self, bot): """Initialize the handler.""" self.bot = bot async def on_ready(self): """Log and sets status when it logs in.""" await self.bot.databaseFuncs.syncCommands() name = self.bot.user.name userid = str(self.bot.user.id) loggedInMessage = f"Logged in as {name}, {userid}" self.bot.log(loggedInMessage, level=25) game = discord.Game("Use /help for commands") onlineStatus = discord.Status.online await self.bot.change_presence(activity=game, status=onlineStatus) async def on_slash_command(self, ctx: SlashContext): """Log when a slash command is given.""" if ctx.subcommand_name is not None: subcommand = f" {ctx.subcommand_name} " else: subcommand = " " if ctx.subcommand_group is not None: subcommandGroup = f"{ctx.subcommand_group} " else: subcommandGroup = "" args = " ".join([str(i) for i in ctx.args]) fullCommand = f"/{ctx.command}{subcommand}{subcommandGroup}{args}" logMessage = f"{ctx.author.display_name} ran {fullCommand}" self.bot.log(logMessage, str(ctx.channel_id), level=25) async def on_reaction_add(self, reaction: discord.Reaction, user: discord.User): """Take action if the reaction is on a command message.""" if not user.bot: tests = self.bot.databaseFuncs message = reaction.message channel = message.channel reactedMessage = f"{user.display_name} reacted to a message" self.bot.log(reactedMessage, str(channel.id)) plexData = tests.bedreNetflixReactionTest(message) # plexData is a list containing 3 elements: whether it was # the addshow/addmovie command message the reaction was to # (bool), whether it's a movie (bool) (if false, it's a # show), and the imdb ids/names for the for the movies or # shows listed in the message (list). reactionTestParams = [message, f"#{str(user.id)}"] if tests.connectFourReactionTest(*reactionTestParams): column = emojiToCommand(reaction.emoji) params = [message, f"#{user.id}", column-1] await self.bot.games.connectFour.placePiece(*params) if plexData[0]: plexFuncs = self.bot.other.bedreNetflix if plexData[1]: moviePick = emojiToCommand(reaction.emoji) if moviePick == "none": imdbID = None else: imdbID = plexData[2][moviePick-1] if isinstance(channel, discord.DMChannel): await message.delete() await plexFuncs.addMovie(message, imdbID, False) else: await message.clear_reactions() await plexFuncs.addMovie(message, imdbID) else: showPick = emojiToCommand(reaction.emoji) if showPick == "none": imdbName = None else: imdbName = plexData[2][showPick-1] if isinstance(channel, discord.DMChannel): await message.delete() await plexFuncs.addShow(message, imdbName, False) else: await message.clear_reactions() await plexFuncs.addShow(message, imdbName) elif tests.hangmanReactionTest(*reactionTestParams): self.bot.log("They reacted to the hangman message") if ord(reaction.emoji) in range(127462, 127488): # The range is letter-emojis guess = chr(ord(reaction.emoji)-127397) # Converts emoji to letter params = [message, f"#{user.id}", guess] await self.bot.games.hangman.guess(*params) else: self.bot.log("Bot they didn't react with a valid guess") class ErrorHandler(): """ Handles errors. *Methods* --------- on_slash_command_error(ctx: discord_slash.context.SlashContext, error: Exception) on_error(method: str) """ def __init__(self, bot): """Initialize the handler.""" self.bot = bot async def on_slash_command_error(self, ctx: SlashContext, error: Exception): """Log when there's a slash command.""" if isinstance(error, commands.CommandNotFound): await ctx.send("That's not a command") elif isinstance(error, discord.errors.NotFound): self.bot.log("Deleted message before I could add all reactions") elif isinstance(error, commands.errors.MissingRequiredArgument): self.bot.log(f"{error}", str(ctx.channel_id)) await ctx.send(self.bot.longStrings["missing parameters"]) else: params = [type(error), error, error.__traceback__] exception = traceback.format_exception(*params) exceptionString = "".join(exception) logMessages = [f"exception in /{ctx.name}", f"{exceptionString}"] self.bot.log(logMessages, str(ctx.channel_id), 40) if isinstance(error, discord.errors.NotFound): self.bot.log("Context is non-existant", level=40) else: await ctx.send("Something went wrong (error code 000)") async def on_error(self, method: str): """Log when there's an error.""" errorType = sys.exc_info()[0] if errorType == discord.errors.NotFound: self.bot.log("Deleted message before I could add all reactions") else: exception = traceback.format_exc() exceptionString = "".join(exception) logMessages = [f"exception in {method}", f"{exceptionString}"] self.bot.log(logMessages, level=40)