def check_quota(self): """ Get the current quota :return: """ try: response = urlopen( f"https://api.stackexchange.com/2.2/info?site=stackoverflow&key={self.api_key}" ).read() buffer = io.BytesIO(response) gzipped_file = gzip.GzipFile(fileobj=buffer) content = gzipped_file.read() data = Struct(**json.loads(content.decode("utf-8"))) return data.quota_remaining except urllib.error.HTTPError as e: main_logger.error( f"Error calling the SE API: Got repsonse code {e.code} and message {e.reason}." ) return None
def _user_id_valid(user_id, utils): """ Validate the specified ID using the Stack Exchange API """ user_id = str(user_id) if user_id.isdecimal(): # Now we call the Stack Exchange API to validate the user's id if utils is not None and utils.config is not None and utils.config.stackExchangeApiKey is not None: stack_exchange_api_key = utils.config.stackExchangeApiKey else: raise NoApiKeyError se_api = stackexchange_api.se_api(stack_exchange_api_key) data = Struct(**se_api.get_user(user_id)) if data is None or len(data.items) is 0: raise NonExistentUserIdError if len(data.items) is 1: return True else: raise InvalidUserIdError
def get_user_name(user_id, utils): """ Get the display name from the ID using the Stack Exchange API """ if user_id.isdecimal(): # Now we call the Stack Exchange API to validate the user's id if utils is not None and utils.config is not None and utils.config.stackExchangeApiKey is not None: stack_exchange_api_key = utils.config.stackExchangeApiKey else: raise NoApiKeyError try: se_api = stackexchange_api.se_api(stack_exchange_api_key) data = Struct(**se_api.get_user(user_id)) except HTTPError: raise NonExistentUserIdError if len(data.items) is 1 and data.items[0]["display_name"] is not None: return data.items[0]["display_name"] else: raise InvalidUserIdError
def check_flags_lp(self): cu = self.utils.get_current_room().get_current_users() self.users = self.utils.checkable_user_ids(cu) for u in self.users: try: #Obtain the current flag count and the next flag rank flag_count = 0 next_flag_rank = None try: flag_count = check_flags.get_flag_count_for_user( u.id, self.utils) next_flag_rank = Struct(**check_flags.get_next_flag_rank( check_flags.get_current_flag_rank(flag_count))) except NoApiKeyError: auto_logger.error( "No API Key specified, unable to check flags.") return except InvalidUserIdError: auto_logger.error( f"The user id was invalid while checking user {u.name}." ) return except NonExistentUserIdError: auto_logger.error( f"The user id for {u.name} appears to not belong to an actual user." ) return except NotEnoughFlagsError: next_flag_rank = Struct(**check_flags.get_next_flag_rank()) except (IndexError, ValueError) as e: auto_logger.error( f"Error while parsing flag count for user {u.name}") return flags_to_next_rank = next_flag_rank.count - flag_count #flags #Replace flags to next rank with custom goal if its flag count is lower than the next rank custom_goal = custom_goals.get_custom_goal_for_user(u.id) if custom_goal is not None: if custom_goal["flag_count"] is not None and custom_goal[ "flag_count"] < next_flag_rank.count: flags_to_next_rank = custom_goal[ "flag_count"] - flag_count #If the user is closer than 20 flags to his next rank, move him to the high priority queue hp_users = [] if self.thread_list is not None: hp_users = self.thread_list[1].users if flags_to_next_rank <= 20 and u.id not in ( u.id for o in hp_users): self.swap_priority(u, next_flag_rank) auto_logger.info( f"[LP->HP] User {u.name} is {flags_to_next_rank} flags away from their next rank and was therefore moved to the high priority queue." ) elif u.id not in (u.id for o in hp_users): auto_logger.info( f"[LP] {u.name} needs {flags_to_next_rank} more flags for their next rank." ) #Update scoreboard update_scoreboard(flag_count, u) except TypeError as e: auto_logger.error(e) auto_logger.info( f"[LP] Checking flags for user {u.name} failed.") except BaseException as e: auto_logger.error("[LP]] Critical Error while checking flags:") auto_logger.error(e)
def check_flags_hp(self): if len(self.users) > 0: for u in self.users: try: #Obtain the current flag count and the next flag rank flag_count = 0 next_flag_rank = None try: flag_count = check_flags.get_flag_count_for_user( u.id, self.utils) next_flag_rank = Struct( **check_flags.get_next_flag_rank( check_flags.get_current_flag_rank(flag_count))) except NoApiKeyError: auto_logger.error( "No API Key specified, unable to check flags.") return except InvalidUserIdError: auto_logger.error( f"The user id was invalid while checking user {u.name}." ) return except NonExistentUserIdError: auto_logger.error( f"The user id for {u.name} appears to not belong to an actual user." ) return except NotEnoughFlagsError: next_flag_rank = Struct( **check_flags.get_next_flag_rank()) except (IndexError, ValueError) as e: auto_logger.error( f"Error while parsing flag count for user {u.name}" ) return flags_to_next_rank = next_flag_rank.count - flag_count #Replace flags to next rank with custom goal if its flag count is lower than the next rank is_custom_goal = False custom_goal = custom_goals.get_custom_goal_for_user(u.id) if custom_goal is not None: if custom_goal[ 'flag_count'] is not None and custom_goal[ 'flag_count'] < next_flag_rank.count: flags_to_next_rank = custom_goal[ 'flag_count'] - flag_count is_custom_goal = True #If the user has reached the flags to their next or custom rank, move them to the low priority queue if flags_to_next_rank <= 0: next_rank_desc = "" if next_flag_rank.description is not None: next_rank_desc = f" ({next_flag_rank.description})" self.swap_priority( u, check_flags.get_next_flag_rank(next_flag_rank)) if is_custom_goal: custom_msg = "" if custom_goal[ 'custom_message'] is not None and not 'None': custom_msg = f" They set a custom message for this event: {custom_goal['custom_message']}" self.utils.post_message( f"Congratulations to @{u.name} for reaching their custom goal of {custom_goal['flag_count']} helpful flags!{custom_msg}" ) custom_goals.delete_custom_goal(u.id) auto_logger.info( f"[HP->LP] User {u.name} has reached their custom rank and is therefore moved to the low priority queue" ) else: self.utils.post_message( f"Congratulations to @{u.name} for reaching the rank {next_flag_rank.title}{next_rank_desc} by surpassing {next_flag_rank.count} helpful flags!" ) auto_logger.info( f"[HP->LP] User {u.name} has reached their next rank and is therefore moved to the low priority queue" ) else: auto_logger.info( f"[HP] {u.name} needs {flags_to_next_rank} more flags for their next rank." ) #Update scoreboard update_scoreboard(flag_count, u.id) except TypeError as e: auto_logger.error(e) auto_logger.info( f"[LP] Checking flags for user {u.name} failed.") except BaseException as e: auto_logger.error( "[HP]] Critical Error while checking flags:") auto_logger.error(e)
def get_flags_to_next_rank(_flag_count): flag_count = int(_flag_count.replace(",", "")) current_flag_rank = get_current_flag_rank(flag_count) next_flag_rank = Struct(**get_next_flag_rank(current_flag_rank)) return next_flag_rank.count - int(flag_count)
def main(): """ Main thread of the bot """ debug_mode = False #Get config for the mode (debug/prod) try: if sys.argv[1] == "--debug": print("Using debug config.") utils.config = Struct(**config.debug_config) debug_mode = True else: raise IndexError except IndexError: print( "Using productive config. \nIf you intended to use the debug config, use the '--debug' command line option" ) utils.config = Struct(**config.prod_config) #Set version utils.config.botVersion = "v2.5.0" #Initialize SE API class instance utils.se_api = stackexchange_api.se_api(utils.config.stackExchangeApiKey) try: #Login and connection to chat print("Logging in and joining chat room...") utils.room_number = utils.config.room client = Client(utils.config.chatHost) client.login(utils.config.email, utils.config.password) utils.client = client room = client.get_room(utils.config.room) try: room.join() except ValueError as e: if str(e).startswith( "invalid literal for int() with base 10: 'login?returnurl" ) or str(e).startswith("failed to get "): raise chatexchange.browser.LoginError( "Too many recent logins. Please wait a bit and try again.") try: room.watch_polling(on_message, 3) except (BaseException, HTTPError) as e: main_logger.error(e) main_logger.error( "Recovered from above exception, trying to reboot...") os._exit(1) print(room.get_current_user_names()) utils.room_owners = room.owners main_logger.info( f"Joined room '{room.name}' on {utils.config.chatHost}") #Initialize Firebase database if os.path.isfile("./service_account_key.json"): cred = credentials.Certificate("./service_account_key.json") firebase_admin.initialize_app(cred, { 'databaseURL': "https://rankoverflow-56959.firebaseio.com/", }) #Automated flag checking thread_list = [] try: stop_auto_checking_lp = threading.Event() auto_check_lp_thread = fac.AutoFlagThread(stop_auto_checking_lp, utils, 0, room, thread_list) auto_check_lp_thread.start() thread_list.append(auto_check_lp_thread) except BaseException as e: print(e) main_logger.error(f"CRITICAL ERROR: {e}") try: stop_auto_checking_hp = threading.Event() auto_check_hp_thread = fac.AutoFlagThread(stop_auto_checking_hp, utils, 1, None, thread_list) auto_check_hp_thread.start() thread_list.append(auto_check_hp_thread) except BaseException as e: print(e) main_logger.error(f"CRITICAL ERROR: {e}") #Redunda pinging if debug_mode: room.send_message( f"[ [CheckYerFlags](https://stackapps.com/q/7792) ] {utils.config.botVersion} started in debug mode on {utils.config.botOwner}/{utils.config.botMachine}." ) else: stop_redunda = threading.Event() redunda_thread = redunda.RedundaThread(stop_redunda, utils.config, main_logger) redunda_thread.start() room.send_message( f"[ [CheckYerFlags](https://stackapps.com/q/7792) ] {utils.config.botVersion} started on {utils.config.botOwner}/{utils.config.botMachine}." ) while True: message = input() if message in ["restart", "reboot"]: os._exit(1) else: room.send_message(message) except KeyboardInterrupt: os._exit(0) except BaseException as e: print(e) os._exit(1)
def on_message(message, client): """ Handling the event if a message was posted, edited or deleted """ if not isinstance(message, MessagePosted) and not isinstance( message, MessageEdited): #We ignore events that aren't MessagePosted or MessageEdited events. return #Check that the message object is defined if message is None or message.content is None: try: if message.user.id is 6294609: return except AttributeError: main_logger.warning( "ChatExchange message object or content property is None.") main_logger.warning(message) return #Get message as full string and as single words message_val = message.content words = message.content.split() #If the bot account posted a message, store it's id if message.user.id == 9220325: utils.last_bot_message = message #Check for non-alias-command calls if message.content.startswith("🚂"): utils.log_command("train") utils.post_message("[🚃](https://youtu.be/943gMyU5-PQ)") elif message.content.lower().startswith("@bots alive"): utils.log_command("@bots alive") utils.post_message("Yep, I'm fine.") elif "shrug" in message_val: utils.log_command("shrug") utils.post_message("¯\\ \_(ツ)\_ /¯", log_message=False) elif "/tableflip" in message_val: utils.log_command("tableflip") utils.post_message("(╯°□°)╯︵ ┻━┻", log_message=False) elif "/unflip" in message_val: utils.log_command("unflip") utils.post_message("┬─┬ ノ( ゜-゜ノ)", log_message=False) elif "/kappa" in message_val: utils.log_command("kappa") message.reply_to("https://i.imgur.com/8TRbWHM.gif") elif "After a happy meal, feeds @Zoe now" in message_val: utils.log_command("ping war") utils.post_message("@BhargavRao, it's your turn to wash the dishes.") elif "I think it is better to wait till @Filnor and @PaulStenne finishes their meals." in message_val: utils.log_command("ping war") utils.post_message( "We will be changing plates for dessert, so get @BhargavRao working! Maybe @Zoe wants to help you?" ) #Check if alias is valid if not utils.alias_valid(words[0]): return #Check if command is not set if len(words) <= 1: message.reply_to("Huh?") return #Store command in it's own variable command = words[1] full_command = ' '.join(words[1:]) utils.log_command(full_command) try: #Here are the commands defined if command in ["del", "delete", "poof"]: msg = client.get_message(message.parent_message_id) if msg is not None: if utils.is_privileged(message): msg.delete() else: message.reply_to( "This command is restricted to moderators and room owners." ) elif command in ["amiprivileged", "aip", "privs"]: if utils.is_privileged(message): message.reply_to("You are privileged.") else: message.reply_to( f"You are not privileged. Ping {utils.config.botOwner} if that doesn't makes sense to you." ) elif command in ["a", "alive"]: message.reply_to("You doubt me?") elif command in ["v", "version"]: message.reply_to(f"Current version is {utils.config.botVersion}") elif command in ["loc", "location"]: message.reply_to( f"This instance is running on {utils.config.botOwner}/{utils.config.botMachine}" ) elif command in ["say"]: main_logger.warning(f"Leave requested by {message.user.name}") #Don't process commands by the bot account itself (to prevent abuse) of the say command if message.user.id == 9220325: return #Restrict function to (site) moderators and room owners if utils.is_privileged(message): say_message = md(' '.join(map(str, words[2:]))) utils.post_message(say_message) else: message.reply_to( "This command is restricted to moderators and room owners." ) elif command in ["welcome"]: #Only run in SOBotics if utils.room_number == 111347 and utils.is_privileged(message): message_ping = "" try: user_to_ping = words[2] message_ping = f"@{user_to_ping.replace('@', '')} " except IndexError: pass utils.post_message( f"{message_ping}Welcome to SOBotics! You can learn more about SOBotics and what we and all the bots are doing here at our website, https://sobotics.org/. If you'd like to help out with flagging, reporting, or anything else, let us know! We have tons of userscripts to make things easier, and you'll always find someone around who will help you to install them and explain how they work. Also make sure to check out our GitHub organization.\nAll bots: https://sobotics.org/all-bots/ UserScripts: https://sobotics.org/userscripts/ GitHub: https://github.com/sobotics", length_check=False) else: if utils.is_privileged(message): utils.post_message( "This command is not supported in this room.") else: message.reply_to( "This command is restricted to moderators and room owners." ) elif command in ["quota"]: utils.post_message( f"The remaining API quota is {utils.se_api.check_quota()}.") elif command in ["kill", "stop"]: main_logger.warning(f"Stop requested by {message.user.name}") if utils.is_privileged(message): try: utils.post_message("I'll be back!") utils.client.get_room(utils.room_number).leave() except BaseException: pass raise os._exit(0) else: message.reply_to( "This command is restricted to moderators and room owners." ) elif command in ["standby", "sb"]: main_logger.warning(f"Leave requested by {message.user.name}") # Restrict function to (site) moderators, room owners and maintainers if utils.is_privileged(message): utils.post_message("I'll be back!") utils.client.get_room(utils.room_number).leave() else: message.reply_to( "This command is restricted to moderators and room owners." ) elif command in ["reboot", "restart"]: main_logger.warning(f"Reboot requested by {message.user.name}") if utils.is_privileged(message): try: utils.post_message("Rebooting now...") utils.client.get_room(utils.room_number).leave() except BaseException: pass raise os._exit(1) else: message.reply_to( "This command is restricted to moderators and room owners." ) elif command in ["commands", "help"]: utils.post_message(" ### CheckYerFlags commands ###\n" + \ " del[ete], poof - Deletes the message replied to, if possible. Requires privileges.\n" + \ " amiprivileged - Checks if you're allowed to run privileged commands.\n" + \ " a[live] - Replies with a message if the bot is running.\n" + \ " v[ersion] - Returns current version.\n" + \ " loc[ation] - Returns current location where the bot is running.\n" + \ " say <message> - Sends [message] as a chat message.\n" + \ " welcome <username> - Post a chat room introduction message (only in SOBotics). If the username is specified, the user will also get pinged.\n" + \ " quota - Returns the amount of remaining Stack Exchange API quota.\n" + \ " kill, stop - Stops the bot. Requires privileges.\n" + \ " standby, sb - Tells the bot to go to standby mode. That means it leaves the chat room and a bot maintainer needs to issue a restart manually. Requires privileges.\n" + \ " restart, reboot - Restarts the bot. Requires privileges.\n" + \ " commands, help - This command. Lists all available commands.\n" + \ " s[tatus] m[ine] - Gets your own flag rank and status to the next rank.\n" + \ " s[tatus] <user id> - Gets flag rank and status to the next rank for the specified <user id>.\n" + \ " goal <flag count> [message] - Set your custom goal to <flag count> flags. Displays an optional message once you reach your custom rank.\n" + \ " goal del[ete] - Deletes our custom goal\n" + \ " ranks, ranks next, r n - Gets your next flag rank and how much flags you need to get to it. Returns your custom goal if it's closer than the next rank.\n" + \ " uptime - Returns how long the bot is running\n" + \ " update - Updates the bot to the latest git commit and restarts it. Requires owner privileges.\n" + \ " system - Returns uptime, location and api quota.\n" + \ " why - Gives the answer to everything.\n" + \ " good bot, good job - Thanks you for being nice.\n" + \ " ty, thx, thanks, thank you - Replies \"You're welcome.\"", log_message=False, length_check=False) elif full_command in ["s m", "status mine"]: flag_count = 0 try: flag_count = check_flags.get_flag_count_for_user( message.user.id, utils) except NoApiKeyError: main_logger.error( "No API Key specified, unable to check flags") message.reply_to("No API Key specified, unable to check flags") return except InvalidUserIdError: message.reply_to( "The specfied argument for the user id is not correct. Only digits are allowed." ) return except NonExistentUserIdError: message.reply_to( "The specfied user id does not belong to an existing user." ) return except (IndexError, ValueError) as e: utils.post_message( f"Error while parsing flag count. (cc @{utils.config.botOwner})" ) return try: current_flag_rank = check_flags.get_current_flag_rank( flag_count) next_flag_rank = Struct( **check_flags.get_next_flag_rank(current_flag_rank)) current_flag_rank = Struct(**current_flag_rank) flag_count_difference = next_flag_rank.count - flag_count except NotEnoughFlagsError: message.reply_to( f"You have {flag_count} helpful flags. Appears that you are not flagging that much." ) return current_rank_description = "" if current_flag_rank.description is not None: current_rank_description = f" ({current_flag_rank.description})" message.reply_to( f"You have {flag_count} helpful flags. Your last achieved rank was **{current_flag_rank.title}**{current_rank_description} for {current_flag_rank.count} helpful flags. You need {flag_count_difference} more flags for your next rank, *{next_flag_rank.title}*." ) elif command in ["s", "status" ] and full_command not in ["s m", "status mine"]: flag_count = 0 user_name = "" try: flag_count = check_flags.get_flag_count_for_user( words[2], utils) user_name = check_flags.get_user_name(words[2], utils) except NoApiKeyError: main_logger.error( "No API Key specified, unable to check flags") message.reply_to("No API Key specified, unable to check flags") return except InvalidUserIdError: message.reply_to( "The specfied argument for the user id is not correct. Only digits are allowed." ) return except NonExistentUserIdError: message.reply_to( "The specfied user id does not belong to an existing user." ) return except (IndexError, ValueError) as e: utils.post_message( f"Error while parsing flag count. (cc @{utils.config.botOwner})" ) return except BaseException as e: utils.post_message(f"Critical Error: {e}") return try: current_flag_rank = check_flags.get_current_flag_rank( flag_count) next_flag_rank = Struct( **check_flags.get_next_flag_rank(current_flag_rank)) current_flag_rank = Struct(**current_flag_rank) flag_count_difference = next_flag_rank.count - flag_count except NotEnoughFlagsError: utils.post_message( f"{user_name} has {flag_count} helpful flags. Appears that they are not flagging that much." ) return current_rank_description = "" if current_flag_rank.description is not None: current_rank_description = f" ({current_flag_rank.description})" utils.post_message( f"{user_name} has {flag_count} helpful flags. Their last achieved rank was **{current_flag_rank.title}**{current_rank_description} for {current_flag_rank.count} helpful flags. They need {flag_count_difference} more flags for their next rank, *{next_flag_rank.title}*." ) elif full_command in ["r", "ranks", "r n", "ranks next"]: flag_count = 0 try: flag_count = check_flags.get_flag_count_for_user( message.user.id, utils) except NoApiKeyError: main_logger.error( "No API Key specified, unable to check flags") message.reply_to("No API Key specified, unable to check flags") return except InvalidUserIdError: message.reply_to( "The specfied argument for the user id is not correct. Only digits are allowed." ) return except NonExistentUserIdError: message.reply_to( "The specfied user id does not belong to an existing user." ) return except (IndexError, ValueError) as e: utils.post_message( f"Error while parsing flag count. (cc @{utils.config.botOwner})" ) return flag_count_difference = None try: current_flag_rank = check_flags.get_current_flag_rank( flag_count) next_flag_rank = Struct( **check_flags.get_next_flag_rank(current_flag_rank)) current_flag_rank = Struct(**current_flag_rank) flag_count_difference = next_flag_rank.count - flag_count except NotEnoughFlagsError: first_flag_rank = Struct( **check_flags.get_current_flag_rank(365)) if flag_count_difference is None: flag_count_difference = first_flag_rank.count message.reply_to( f"You need {flag_count_difference} more flags to get your first flag rank, **{first_flag_rank.title}** ({first_flag_rank.count} flags in total)." ) return #Try to check for custom goal custom_goal_closer = False custom_goal = custom_goals.get_custom_goal_for_user( message.user.id) if custom_goal is not None: if custom_goal['flag_count'] is not None and ( custom_goal['flag_count'] - flag_count) < flag_count_difference: flag_count_difference = custom_goal[ 'flag_count'] - flag_count custom_goal_closer = True next_rank_description = "" if current_flag_rank.description is not None: next_rank_description = f" ({next_flag_rank.description})" if custom_goal_closer: custom_msg = "" if custom_goal['custom_message'] is not "": custom_msg = f" You set the following custom message: {custom_goal['custom_message']}" message.reply_to( f"You need {flag_count_difference} more flags to reach your custom goal ({custom_goal['flag_count']} flags in total).{custom_msg}" ) else: message.reply_to( f"You need {flag_count_difference} more flags to get your next flag rank, **{next_flag_rank.title}**{next_rank_description} ({next_flag_rank.count} flags in total)." ) elif command in ["why"]: message.reply_to( "[42.](https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Answer_to_the_Ultimate_Question_of_Life,_the_Universe,_and_Everything_(42))" ) elif full_command in ["good bot", "good job"]: message.reply_to("Thank you!") elif full_command.lower() in ["ty", "thx", "thanks", "thank you"]: message.reply_to("You're welcome.") elif full_command.lower() in ["code", "github", "source"]: message.reply_to( "My code is on GitHub [here](https://github.com/SOBotics/CheckYerFlags)." ) elif command in ["leaderboard", "scoreboard", "sb"]: message.reply_to( "You can find the scoreboard [here](https://rankoverflow.philnet.ch/scoreboard). Note that loading the data takes about 15 seconds." ) elif command in ["goal"]: goal_flag_count = 0 user_id = message.user.id try: goal_flag_count = words[2] custom_message = None try: msg = "" for word in words[3:]: msg = f"{msg} {word}" custom_message = msg.lstrip() except IndexError: pass #Validate if given parameter als if goal_flag_count.isdigit() or goal_flag_count in [ "del", "delete" ]: goal_flag_count = int(goal_flag_count) else: message.reply_to( "Please pass an integer number as parameter") return #Check if the user has not already reached this amount of flags current_flag_count = check_flags.get_flag_count_for_user( user_id, utils) if goal_flag_count <= current_flag_count: message.reply_to( f"Your custom goal must be higher than your current flag count, which is {current_flag_count}." ) return if custom_goals.add_custom_goal(user_id, goal_flag_count, custom_message): message.reply_to( f"Set custom goal to {goal_flag_count} helpful flags.") except IndexError: utils.post_message( "Usage: `@CheckYerFlags goal <flag count> [message]`") return except ValueError: if words[2] in ["del", "delete"]: if custom_goals.delete_custom_goal(user_id): message.reply_to("Your custom goal was deleted.") else: message.reply_to( "Your custom goal couldn't be deleted. Please try again later." ) return return elif command in ["uptime"]: message.reply_to(f"Running since {utils.get_uptime()}") elif command in ["system"]: utils.post_message(f" uptime {utils.get_uptime()}\n" + \ f" location {utils.config.botOwner}/{utils.config.botMachine}\n" + \ f" api quota {utils.se_api.check_quota()}", log_message=False, length_check=False) elif command in ["update"]: if utils.is_privileged(message, owners_only=True): try: repo = git.Repo(".") repo.git.reset("--hard", "origin/master") g = git.cmd.Git(".") g.pull() main_logger.info("Update completed, restarting now.") os._exit(1) except BaseException as e: main_logger.error(f"Error while updating: {e}") pass os._exit(1) else: message.reply_to("This command is restricted to bot owners.") except BaseException as e: main_logger.error(f"CRITICAL ERROR: {e}") if message is not None: try: if message.îd is not None: main_logger.error(f"Caused by message id {message.id}") except AttributeError: pass main_logger.error(traceback.format_exc()) try: utils.post_message( f"Error on processing the last command ({e}); rebooting instance... (cc @{utils.config.botOwner})" ) os._exit(1) except AttributeError: os._exit(1) pass