def generic_update(self, bot, source, message, field, api_fn): if not message: bot.say(f"You must specify a {field} to update to!") return try: api_fn(self.bot.streamer_user_id, message, authorization=bot.bot_token_manager) except HTTPError as e: if e.response.status_code == 401: bot.say( f"Error (bot operator): The bot needs to be re-authenticated to be able to update the {field}." ) return elif e.response.status_code == 403: bot.say( f"Error: The bot is not a channel editor and was not able to update the {field}." ) return else: raise e log_msg = f'{source} updated the {field} to "{message}"' bot.say(log_msg) AdminLogManager.add_entry(f"{field.capitalize()} set", source, log_msg)
def playsound_create(playsound_name: str, **options) -> ResponseReturnValue: # Create playsound playsound_name = PlaysoundModule.massage_name(playsound_name) if not PlaysoundModule.validate_name(playsound_name): return ( { "error": "Invalid Playsound name. The playsound name may only contain lowercase latin letters, 0-9, -, or _. No spaces :rage:" }, 400, ) try: json_data = request.get_json() if not json_data: return {"error": "Missing json body"}, 400 data = CreatePlaysoundSchema().load(json_data) except ValidationError as err: return {"error": f"Did not match schema: {json.dumps(err.messages)}"}, 400 with DBManager.create_session_scope() as db_session: count = db_session.query(Playsound).filter(Playsound.name == playsound_name).count() if count >= 1: return "Playsound already exists", 400 # the rest of the parameters are initialized with defaults playsound = Playsound(name=playsound_name, link=data.link) db_session.add(playsound) log_msg = f"The {playsound_name} playsound has been added" AdminLogManager.add_entry("Playsound added", options["user"], log_msg) return "OK", 200
def permaban_command(bot, source, message, **rest) -> bool: if not message: return False username = message.split(" ")[0] with DBManager.create_session_scope() as db_session: user = User.find_by_user_input(db_session, username) if not user: bot.whisper(source, "No user with that name found.") return False if user.banned: bot.whisper(source, "User is already permabanned.") return False user.banned = True bot.ban( user, reason= f"User has been added to the {bot.bot_user.login} banlist. Contact a moderator level 1000 or higher for unban.", ) log_msg = f"{user} has been permabanned" bot.whisper(source, log_msg) AdminLogManager.add_entry("Permaban added", source, log_msg) return True
def unpermaban_command(self, bot, source, message, **rest): if not message: return username = message.split(" ")[0] with DBManager.create_session_scope() as db_session: user = User.find_by_user_input(db_session, username) if not user: bot.whisper(source, "No user with that name found.") return False if user.banned is False: bot.whisper(source, "User is not permabanned.") return False user.banned = False log_msg = f"{user} is no longer permabanned" bot.whisper(source, log_msg) AdminLogManager.add_entry("Permaban remove", source, log_msg) if self.settings["unban_from_chat"] is True: bot.unban(user) if self.settings["enable_send_timeout"] is True: bot.timeout( user, 1, self.settings["timeout_reason"].format(source=source), once=True)
def level(self, **options): message = options['message'] bot = options['bot'] source = options['source'] if message: msg_args = message.split(' ') if len(msg_args) > 1: username = msg_args[0].lower() new_level = int(msg_args[1]) if new_level >= source.level: bot.whisper(source.username, 'You cannot promote someone to the same or higher level as you ({0}).'.format(source.level)) return False # We create the user if the user didn't already exist in the database. with bot.users.get_user_context(username) as user: old_level = user.level user.level = new_level log_msg = '{}\'s user level changed from {} to {}'.format( user.username_raw, old_level, new_level) bot.whisper(source.username, log_msg) AdminLogManager.add_entry('Userlevel edited', source, log_msg) return True bot.whisper(source.username, 'Usage: !level USERNAME NEW_LEVEL') return False
def remove_alias(bot, source, message, event, args): """Dispatch method for removing aliases from a command. Usage: !remove alias EXISTING_ALIAS_1 EXISTING_ALIAS_2""" if message: aliases = re.split(r"\|| ", message.lower()) log.info(aliases) if len(aliases) < 1: bot.whisper(source.username, "Usage: !remove alias EXISTINGALIAS") return False num_removed = 0 commands_not_found = [] for alias in aliases: if alias not in bot.commands: commands_not_found.append(alias) continue command = bot.commands[alias] # error out on commands that are not from the DB, e.g. module commands like !8ball that cannot have # aliases registered. (command.command and command.data are None on those commands) if command.data is None or command.command is None: bot.whisper( source.username, "That command cannot have aliases removed from.") return False current_aliases = command.command.split("|") current_aliases.remove(alias) if len(current_aliases) == 0: bot.whisper( source.username, "{0} is the only remaining alias for this command and can't be removed." .format(alias), ) continue new_aliases = "|".join(current_aliases) bot.commands.edit_command(command, command=new_aliases) num_removed += 1 del bot.commands[alias] log_msg = "The alias {0} has been removed from {1}".format( alias, new_aliases.split("|")[0]) AdminLogManager.add_entry("Alias removed", source, log_msg) whisper_str = "" if num_removed > 0: whisper_str = "Successfully removed {0} aliases.".format( num_removed) if len(commands_not_found) > 0: whisper_str += " Aliases {0} not found".format( ", ".join(commands_not_found)) if len(whisper_str) > 0: bot.whisper(source.username, whisper_str) else: bot.whisper(source.username, "Usage: !remove alias EXISTINGALIAS")
def level(self, **options): message = options['message'] bot = options['bot'] source = options['source'] if message: msg_args = message.split(' ') if len(msg_args) > 1: username = msg_args[0].lower() new_level = int(msg_args[1]) if new_level >= source.level: bot.whisper( source.username, 'You cannot promote someone to the same or higher level as you ({0}).' .format(source.level)) return False # We create the user if the user didn't already exist in the database. with bot.users.get_user_context(username) as user: old_level = user.level user.level = new_level log_msg = '{}\'s user level changed from {} to {}'.format( user.username_raw, old_level, new_level) bot.whisper(source.username, log_msg) AdminLogManager.add_entry('Userlevel edited', source, log_msg) return True bot.whisper(source.username, 'Usage: !level USERNAME NEW_LEVEL') return False
def put(self, playsound_name, **options): playsound_name = PlaysoundModule.massage_name(playsound_name) if not PlaysoundModule.validate_name(playsound_name): return ( { "error": "Invalid Playsound name. The playsound name may only contain lowercase latin letters, 0-9, -, or _. No spaces :rage:" }, 400, ) post_parser = RequestParser() post_parser.add_argument("link", required=True) args = post_parser.parse_args() try: link = args["link"] except (ValueError, KeyError): return {"error": "Invalid `link` parameter."}, 400 with DBManager.create_session_scope() as db_session: count = db_session.query(Playsound).filter(Playsound.name == playsound_name).count() if count >= 1: return "Playsound already exists", 400 # the rest of the parameters are initialized with defaults playsound = Playsound(name=playsound_name, link=link) db_session.add(playsound) log_msg = f"The {playsound_name} playsound has been added" AdminLogManager.add_entry("Playsound added", options["user"], log_msg) return "OK", 200
def set_title(bot, source, message, event, args): # XXX: This should be a module if message: bot.twitchapi.set_title(bot.streamer, message) log_msg = '{0} updated the title to "{1}"'.format(source.username_raw, message) bot.say(log_msg) AdminLogManager.add_entry('Title set', source, log_msg)
def add_command(bot, source, message, event, args): """Dispatch method for creating commands. Usage: !add command ALIAS [options] RESPONSE See pajbot/managers/command.py parse_command_arguments for available options """ if not message: return False # Make sure we got both an alias and a response message_parts = message.split() if len(message_parts) < 2: bot.send_message_to_user( source, "Usage: !add command ALIAS [options] RESPONSE", event, method="whisper") return False options, response = bot.commands.parse_command_arguments( message_parts[1:]) if options is False: bot.send_message_to_user(source, "Invalid command", event, method="whisper") return False options["added_by"] = source.id alias_str = message_parts[0].replace("!", "").lower() action_type: str = options.get("action_type", "say") if response.startswith("/me") or response.startswith(".me"): action_type = "me" response = " ".join(response.split(" ")[1:]) action = {"type": action_type, "message": response} command, new_command, alias_matched = bot.commands.create_command( alias_str, action=action, **options) if new_command is True: bot.send_message_to_user(source, f"Added your command (ID: {command.id})", event, method="whisper") log_msg = f"The !{command.command.split('|')[0]} command has been created" AdminLogManager.add_entry("Command created", source, log_msg) return True # At least one alias is already in use, notify the user to use !edit command instead bot.send_message_to_user( source, f"The alias {alias_matched} is already in use. To edit that command, use !edit command instead of !add command.", event, method="whisper", ) return False
def add_command(bot, source, message, event, args): """Dispatch method for creating commands. Usage: !add command ALIAS [options] RESPONSE Multiple options available: --whisper/--no-whisper --reply/--no-reply --modonly/--no-modonly --cd CD --usercd USERCD --level LEVEL --cost COST """ if message: # Make sure we got both an alias and a response message_parts = message.split() if len(message_parts) < 2: bot.whisper(source.username, 'Usage: !add command ALIAS [options] RESPONSE') return False options, response = bot.commands.parse_command_arguments(message_parts[1:]) options['added_by'] = source.id if options is False: bot.whisper(source.username, 'Invalid command') return False alias_str = message_parts[0].replace('!', '').lower() type = 'say' if options['whisper'] is True: type = 'whisper' elif options['reply'] is True: type = 'reply' elif response.startswith('/me') or response.startswith('.me'): type = 'me' response = ' '.join(response.split(' ')[1:]) elif options['whisper'] is False or options['reply'] is False: type = 'say' action = { 'type': type, 'message': response, } command, new_command, alias_matched = bot.commands.create_command(alias_str, action=action, **options) if new_command is True: bot.whisper(source.username, 'Added your command (ID: {command.id})'.format(command=command)) log_msg = 'The !{} command has been created'.format(command.command.split('|')[0]) AdminLogManager.add_entry('Command created', source, log_msg) return True # At least one alias is already in use, notify the user to use !edit command instead bot.whisper(source.username, 'The alias {} is already in use. To edit that command, use !edit command instead of !add command.'.format(alias_matched)) return False
def add_alias(bot, source, message, event, args): """Dispatch method for adding aliases to already-existing commands. Usage: !add alias EXISTING_ALIAS NEW_ALIAS_1 NEW_ALIAS_2 ... """ if message: message = message.replace("!", "").lower() # Make sure we got both an existing alias and at least one new alias message_parts = message.split() if len(message_parts) < 2: bot.whisper(source.username, "Usage: !add alias existingalias newalias") return False existing_alias = message_parts[0] new_aliases = re.split(r"\|| ", " ".join(message_parts[1:])) added_aliases = [] already_used_aliases = [] if existing_alias not in bot.commands: bot.whisper( source.username, 'No command called "{0}" found'.format(existing_alias)) return False command = bot.commands[existing_alias] for alias in set(new_aliases): if alias in bot.commands: already_used_aliases.append(alias) else: added_aliases.append(alias) bot.commands[alias] = command if len(added_aliases) > 0: new_aliases = "{}|{}".format(command.command, "|".join(added_aliases)) bot.commands.edit_command(command, command=new_aliases) bot.whisper( source.username, "Successfully added the aliases {0} to {1}".format( ", ".join(added_aliases), existing_alias), ) log_msg = "The aliases {0} has been added to {1}".format( ", ".join(added_aliases), existing_alias) AdminLogManager.add_entry("Alias added", source, log_msg) if len(already_used_aliases) > 0: bot.whisper( source.username, "The following aliases were already in use: {0}".format( ", ".join(already_used_aliases)), ) else: bot.whisper(source.username, "Usage: !add alias existingalias newalias")
def add_alias(bot, source, message, event, args): """Dispatch method for adding aliases to already-existing commands. Usage: !add alias EXISTING_ALIAS NEW_ALIAS_1 NEW_ALIAS_2 ... """ if message: message = message.replace("!", "").lower() # Make sure we got both an existing alias and at least one new alias message_parts = message.split() if len(message_parts) < 2: bot.whisper(source, "Usage: !add alias existingalias newalias") return False existing_alias = message_parts[0] new_aliases = re.split(r"\|| ", " ".join(message_parts[1:])) added_aliases = [] already_used_aliases = [] if existing_alias not in bot.commands: bot.whisper(source, f'No command called "{existing_alias}" found') return False command = bot.commands[existing_alias] # error out on commands that are not from the DB, e.g. module commands like !8ball that cannot have # aliases registered. (command.command and command.data are None on those commands) if command.data is None or command.command is None: bot.whisper(source, "That command cannot have aliases added to.") return False for alias in set(new_aliases): if alias in bot.commands: already_used_aliases.append(alias) else: added_aliases.append(alias) bot.commands[alias] = command if len(added_aliases) > 0: new_aliases = f"{command.command}|{'|'.join(added_aliases)}" bot.commands.edit_command(command, command=new_aliases) bot.whisper( source, f"Successfully added the aliases {', '.join(added_aliases)} to {existing_alias}" ) log_msg = f"The aliases {', '.join(added_aliases)} has been added to {existing_alias}" AdminLogManager.add_entry("Alias added", source, log_msg) if len(already_used_aliases) > 0: bot.whisper( source, f"The following aliases were already in use: {', '.join(already_used_aliases)}" ) else: bot.whisper(source, "Usage: !add alias existingalias newalias")
def edit_playsound_command(self, bot, source, message, **rest): """Method for editing playsounds. Usage: !edit playsound PLAYSOUNDNAME [LINK] [options] Multiple options available: --volume VOLUME --cooldown COOLDOWN --enabled/--disabled """ options, name, link = self.parse_playsound_arguments(message) if options is False or name is False or link is False: bot.whisper( source, "Invalid usage. Correct syntax: !edit playsound <name> [link] " + "[--volume 0-100] [--cooldown 60/none] [--enabled/--disabled]", ) return with DBManager.create_session_scope() as session: playsound = session.query(Playsound).filter( Playsound.name == name).one_or_none() if playsound is None: bot.whisper( source, "No playsound with that name exists. You can create playsounds with " "!add playsound <name> <link> [options].", ) return old_link = playsound.link if not self.update_link(bot, source, playsound, link): return if not self.update_volume(bot, source, playsound, options): return if not self.update_cooldown(bot, source, playsound, options): return if not self.update_enabled(bot, source, playsound, options): return if link in message: log_msg = f"The {name} playsound has been updated from {old_link} to {link}" else: log_msg = f"The {name} playsound has been updated" session.add(playsound) bot.whisper(source, "Successfully edited your playsound.") AdminLogManager.add_entry("Playsound edited", source, log_msg)
def playsound_delete(playsound_name: str, **options) -> ResponseReturnValue: with DBManager.create_session_scope() as db_session: playsound = db_session.query(Playsound).filter(Playsound.name == playsound_name).one_or_none() if playsound is None: return "Playsound does not exist", 404 log_msg = f"The {playsound.name} playsound has been removed" AdminLogManager.add_entry("Playsound removed", options["user"], log_msg) db_session.delete(playsound) return "OK", 200
def twitter_unfollow(bot, source, message, event, args): if message: username = message.split(" ")[0].strip().lower() if bot.twitter_manager.unfollow_user(username): log_msg = f"No longer following {username}" bot.whisper(source, log_msg) AdminLogManager.add_entry("Twitter user unfollowed", source, log_msg) else: bot.whisper( source, f"An error occured while attempting to unfollow {username}, perhaps we are not following this person?", )
def remove_command(bot, source, message, event, args): if message: id = None command = None try: id = int(message) except Exception: pass if id is None: potential_cmd = ''.join( message.split(' ')[:1]).lower().replace('!', '') if potential_cmd in bot.commands: command = bot.commands[potential_cmd] log.info('got command: {0}'.format(command)) else: for key, check_command in bot.commands.items(): if check_command.id == id: command = check_command break if command is None: bot.whisper(source.username, 'No command with the given parameters found') return False if command.id == -1: bot.whisper( source.username, 'That command is an internal command, it cannot be removed.' ) return False if source.level < 2000: if command.action is not None and not command.action.type == 'message': bot.whisper( source.username, 'That command is not a normal command, it cannot be removed by you.' ) return False bot.whisper( source.username, 'Successfully removed command with id {0}'.format(command.id)) log_msg = 'The !{} command has been removed'.format( command.command.split('|')[0]) AdminLogManager.add_entry('Command removed', source, log_msg) bot.commands.remove_command(command) else: bot.whisper(source.username, 'Usage: !remove command (COMMAND_ID|COMMAND_ALIAS)')
def remove_alias(bot, source, message, event, args): """Dispatch method for removing aliases from a command. Usage: !remove alias EXISTING_ALIAS_1 EXISTING_ALIAS_2""" if message: aliases = re.split('\|| ', message.lower()) log.info(aliases) if len(aliases) < 1: bot.whisper(source.username, 'Usage: !remove alias EXISTINGALIAS') return False num_removed = 0 commands_not_found = [] for alias in aliases: if alias not in bot.commands: commands_not_found.append(alias) continue command = bot.commands[alias] current_aliases = command.command.split('|') current_aliases.remove(alias) if len(current_aliases) == 0: bot.whisper( source.username, "{0} is the only remaining alias for this command and can't be removed." .format(alias)) continue new_aliases = '|'.join(current_aliases) bot.commands.edit_command(command, command=new_aliases) num_removed += 1 del bot.commands[alias] log_msg = 'The alias {0} has been removed from {1}'.format( alias, new_aliases.split('|')[0]) AdminLogManager.add_entry('Alias removed', source, log_msg) whisper_str = '' if num_removed > 0: whisper_str = 'Successfully removed {0} aliases.'.format( num_removed) if len(commands_not_found) > 0: whisper_str += ' Aliases {0} not found'.format( ', '.join(commands_not_found)) if len(whisper_str) > 0: bot.whisper(source.username, whisper_str) else: bot.whisper(source.username, 'Usage: !remove alias EXISTINGALIAS')
def remove_command(bot, source, message, event, args): if message: id = None command = None try: id = int(message) except Exception: pass if id is None: potential_cmd = "".join( message.split(" ")[:1]).lower().replace("!", "") if potential_cmd in bot.commands: command = bot.commands[potential_cmd] else: for key, check_command in bot.commands.items(): if check_command.id == id: command = check_command break if command is None: bot.whisper(source.username, "No command with the given parameters found") return False if command.id == -1: bot.whisper( source.username, "That command is an internal command, it cannot be removed." ) return False if source.level < 2000: if command.action is not None and not command.action.type == "message": bot.whisper( source.username, "That command is not a normal command, it cannot be removed by you." ) return False bot.whisper( source.username, "Successfully removed command with id {0}".format(command.id)) log_msg = "The !{} command has been removed".format( command.command.split("|")[0]) AdminLogManager.add_entry("Command removed", source, log_msg) bot.commands.remove_command(command) else: bot.whisper(source.username, "Usage: !remove command (COMMAND_ID|COMMAND_ALIAS)")
def update_game(self, bot: Bot, source, message, **rest) -> Any: auth_error = "Error: The streamer must grant permissions to update the game. The streamer needs to be re-authenticated to fix this problem." if ("user:edit:broadcast" not in bot.streamer_access_token_manager.token.scope and "channel:manage:broadcast" not in bot.streamer_access_token_manager.token.scope): bot.say(auth_error) return game_name = message if not game_name: bot.say("You must specify a game to update to!") return # Resolve game name to game ID game = bot.twitch_helix_api.get_game_by_game_name(game_name) if not game: bot.say(f"Unable to find a game with the name '{game_name}'") return try: bot.twitch_helix_api.modify_channel_information( bot.streamer.id, {"game_id": game.id}, authorization=bot.streamer_access_token_manager, ) except HTTPError as e: if e.response.status_code == 401: log.error( f"Failed to update game to '{game_name}' - auth error") bot.say(auth_error) bot.streamer_access_token_manager.invalidate_token() elif e.response.status_code == 500: log.error( f"Failed to update game to '{game_name}' - internal server error" ) bot.say(f"{source}, Failed to update game! Please try again.") else: log.exception( f"Unhandled HTTPError when updating to {game_name}") return log_msg = f'{source} updated the game to "{game_name}"' bot.say(log_msg) AdminLogManager.add_entry("Game set", source, log_msg)
def update_title(self, bot: Bot, source, message, **rest) -> Any: auth_error = "Error: The streamer must grant permissions to update the title. The streamer needs to be re-authenticated to fix this problem." if ("user:edit:broadcast" not in bot.streamer_access_token_manager.token.scope and "channel:manage:broadcast" not in bot.streamer_access_token_manager.token.scope): bot.say(auth_error) return title = message if not title: bot.say("You must specify a title to update to!") return try: bot.twitch_helix_api.modify_channel_information( bot.streamer.id, {"title": title}, authorization=bot.streamer_access_token_manager, ) except HTTPError as e: if e.response.status_code == 401: log.error(f"Failed to update title to '{title}' - auth error") bot.say(auth_error) bot.streamer_access_token_manager.invalidate_token() elif e.response.status_code == 400: log.error(f"Title '{title}' contains banned words") bot.say( f"{source}, Title contained banned words. Please remove the banned words and try again." ) elif e.response.status_code == 500: log.error( f"Failed to update title to '{title}' - internal server error" ) bot.say( f"{source}, Failed to update the title! Please try again.") else: log.exception(f"Unhandled HTTPError when updating to {title}") return log_msg = f'{source} updated the title to "{title}"' bot.say(log_msg) AdminLogManager.add_entry("Title set", source, log_msg)
def remove_alias(bot, source, message, event, args): """Dispatch method for removing aliases from a command. Usage: !remove alias EXISTING_ALIAS_1 EXISTING_ALIAS_2""" if message: aliases = re.split('\|| ', message.lower()) log.info(aliases) if len(aliases) < 1: bot.whisper(source.username, 'Usage: !remove alias EXISTINGALIAS') return False num_removed = 0 commands_not_found = [] for alias in aliases: if alias not in bot.commands: commands_not_found.append(alias) continue command = bot.commands[alias] current_aliases = command.command.split('|') current_aliases.remove(alias) if len(current_aliases) == 0: bot.whisper(source.username, "{0} is the only remaining alias for this command and can't be removed.".format(alias)) continue new_aliases = '|'.join(current_aliases) bot.commands.edit_command(command, command=new_aliases) num_removed += 1 del bot.commands[alias] log_msg = 'The alias {0} has been removed from {1}'.format(alias, new_aliases.split('|')[0]) AdminLogManager.add_entry('Alias removed', source, log_msg) whisper_str = '' if num_removed > 0: whisper_str = 'Successfully removed {0} aliases.'.format(num_removed) if len(commands_not_found) > 0: whisper_str += ' Aliases {0} not found'.format(', '.join(commands_not_found)) if len(whisper_str) > 0: bot.whisper(source.username, whisper_str) else: bot.whisper(source.username, 'Usage: !remove alias EXISTINGALIAS')
def permaban_command(self, **options): message = options['message'] bot = options['bot'] source = options['source'] if message: username = message.split(' ')[0].strip().lower() with bot.users.get_user_context(username) as user: if user.banned: bot.whisper(source.username, 'User is already permabanned.') return False user.banned = True message = message.lower() log_msg = '{} has been permabanned'.format(user.username_raw) bot.whisper(source.username, log_msg) AdminLogManager.add_entry('Permaban added', source, log_msg)
def permaban_command(**options): message = options["message"] bot = options["bot"] source = options["source"] if message: username = message.split(" ")[0].strip().lower() with bot.users.get_user_context(username) as user: if user.banned: bot.whisper(source.username, "User is already permabanned.") return False user.banned = True message = message.lower() log_msg = "{} has been permabanned".format(user.username_raw) bot.whisper(source.username, log_msg) AdminLogManager.add_entry("Permaban added", source, log_msg)
def get(self, command_id, **options): with DBManager.create_session_scope() as db_session: command = db_session.query(Command).filter_by(id=command_id).one_or_none() if command is None: return {'error': 'Invalid command ID'}, 404 if command.level > options['user'].level: return {'error': 'Unauthorized'}, 403 log_msg = 'The !{} command has been removed'.format(command.command.split('|')[0]) AdminLogManager.add_entry('Command removed', options['user'], log_msg) db_session.delete(command.data) db_session.delete(command) if SocketClientManager.send('command.remove', {'command_id': command_id}) is True: return {'success': 'good job'}, 200 else: return {'error': 'could not push update'}, 500
def add_alias(bot, source, message, event, args): """Dispatch method for adding aliases to already-existing commands. Usage: !add alias EXISTING_ALIAS NEW_ALIAS_1 NEW_ALIAS_2 ... """ if message: message = message.replace('!', '').lower() # Make sure we got both an existing alias and at least one new alias message_parts = message.split() if len(message_parts) < 2: bot.whisper(source.username, 'Usage: !add alias existingalias newalias') return False existing_alias = message_parts[0] new_aliases = re.split('\|| ', ' '.join(message_parts[1:])) added_aliases = [] already_used_aliases = [] if existing_alias not in bot.commands: bot.whisper(source.username, 'No command called "{0}" found'.format(existing_alias)) return False command = bot.commands[existing_alias] for alias in set(new_aliases): if alias in bot.commands: already_used_aliases.append(alias) else: added_aliases.append(alias) bot.commands[alias] = command if len(added_aliases) > 0: new_aliases = '{}|{}'.format(command.command, '|'.join(added_aliases)) bot.commands.edit_command(command, command=new_aliases) bot.whisper(source.username, 'Successfully added the aliases {0} to {1}'.format(', '.join(added_aliases), existing_alias)) log_msg = 'The aliases {0} has been added to {1}'.format(', '.join(added_aliases), existing_alias) AdminLogManager.add_entry('Alias added', source, log_msg) if len(already_used_aliases) > 0: bot.whisper(source.username, 'The following aliases were already in use: {0}'.format(', '.join(already_used_aliases))) else: bot.whisper(source.username, 'Usage: !add alias existingalias newalias')
def level(bot, source, message, **rest): if not message: bot.whisper(source, "Usage: !level USERNAME NEW_LEVEL") return False msg_args = message.split(" ") if len(msg_args) < 2: return False username = msg_args[0].lower() new_level = int(msg_args[1]) if new_level >= source.level: bot.whisper( source, f"You cannot promote someone to the same or higher level as you ({source.level})." ) return False # We create the user if the user didn't already exist in the database. with DBManager.create_session_scope() as db_session: user = User.find_or_create_from_user_input(db_session, bot.twitch_helix_api, username) if user is None: bot.whisper( source, f'A user with the name "{username}" could not be found.') return False if user.level >= source.level: bot.whisper( source, f"You cannot change the level of someone who is the same or higher level than you. You are level {source.level}, and {username} is level {user.level}", ) return False old_level = user.level user.level = new_level log_msg = f"{user}'s user level changed from {old_level} to {new_level}" bot.whisper(source, log_msg) AdminLogManager.add_entry("Userlevel edited", source, log_msg)
def post(self, command_id, **options): with DBManager.create_session_scope() as db_session: command = db_session.query(Command).filter_by( id=command_id).one_or_none() if command is None: return {"error": "Invalid command ID"}, 404 if command.level > options["user"].level: return {"error": "Unauthorized"}, 403 log_msg = f"The !{command.command.split('|')[0]} command has been removed" AdminLogManager.add_entry("Command removed", options["user"], log_msg) db_session.delete(command.data) db_session.delete(command) if SocketClientManager.send("command.remove", {"command_id": command_id}) is True: return {"success": "good job"}, 200 else: return {"error": "could not push update"}, 500
def level(**options): message = options["message"] bot = options["bot"] source = options["source"] if message: msg_args = message.split(" ") if len(msg_args) > 1: username = msg_args[0].lower() new_level = int(msg_args[1]) if new_level >= source.level: bot.whisper( source.username, "You cannot promote someone to the same or higher level as you ({0})." .format(source.level), ) return False # We create the user if the user didn't already exist in the database. with bot.users.get_user_context(username) as user: if user.level >= source.level: bot.whisper( source.username, "You cannot change the level of someone who is the same or higher level than you. You are level {}, and {} is level {}" .format(source.level, username, user.level), ) return False old_level = user.level user.level = new_level log_msg = "{}'s user level changed from {} to {}".format( user.username_raw, old_level, new_level) bot.whisper(source.username, log_msg) AdminLogManager.add_entry("Userlevel edited", source, log_msg) return True bot.whisper(source.username, "Usage: !level USERNAME NEW_LEVEL") return False
def permaban_command(bot, source, message, **rest): if not message: return username = message.split(" ")[0] with DBManager.create_session_scope() as db_session: user = User.find_by_user_input(db_session, username) if not user: bot.whisper(source, "No user with that name found.") return False if user.banned: bot.whisper(source, "User is already permabanned.") return False user.banned = True log_msg = f"{user} has been permabanned" bot.whisper(source, log_msg) AdminLogManager.add_entry("Permaban added", source, log_msg)
def remove_command(bot, source, message, event, args): if message: id = None command = None try: id = int(message) except Exception: pass if id is None: potential_cmd = ''.join(message.split(' ')[:1]).lower().replace('!', '') if potential_cmd in bot.commands: command = bot.commands[potential_cmd] log.info('got command: {0}'.format(command)) else: for key, check_command in bot.commands.items(): if check_command.id == id: command = check_command break if command is None: bot.whisper(source.username, 'No command with the given parameters found') return False if command.id == -1: bot.whisper(source.username, 'That command is an internal command, it cannot be removed.') return False if source.level < 2000: if command.action is not None and not command.action.type == 'message': bot.whisper(source.username, 'That command is not a normal command, it cannot be removed by you.') return False bot.whisper(source.username, 'Successfully removed command with id {0}'.format(command.id)) log_msg = 'The !{} command has been removed'.format(command.command.split('|')[0]) AdminLogManager.add_entry('Command removed', source, log_msg) bot.commands.remove_command(command) else: bot.whisper(source.username, 'Usage: !remove command (COMMAND_ID|COMMAND_ALIAS)')
def generic_update(self, bot: Bot, source, message: str, field: str, extra_args: Dict[str, str]) -> None: if not message: bot.say(f"You must specify a {field} to update to!") return if ("user:edit:broadcast" not in bot.streamer_access_token_manager.token.scope or not self.bot.twitch_helix_api.modify_channel_information( self.bot.streamer_user_id, authorization=bot.streamer_access_token_manager, **extra_args, )): bot.say( "Error: The streamer grants permission to update the game. The streamer needs to be re-authenticated to fix this problem." ) return log_msg = f'{source} updated the {field} to "{message}"' bot.say(log_msg) AdminLogManager.add_entry(f"{field.capitalize()} set", source, log_msg)
def generic_update(self, bot, source, message, field, api_fn): if not message: bot.say(f"You must specify a {field} to update to!") return if "channel_editor" in bot.streamer_access_token_manager.token.scope: api_fn(self.bot.streamer_user_id, message, authorization=bot.streamer_access_token_manager) else: try: api_fn(self.bot.streamer_user_id, message, authorization=bot.bot_token_manager) except HTTPError as e: if e.response.status_code == 401: bot.say( f"Error: Neither the streamer nor the bot token grants permission to update the {field}. The streamer needs to be re-authenticated to fix this problem." ) return else: raise e log_msg = f'{source} updated the {field} to "{message}"' bot.say(log_msg) AdminLogManager.add_entry(f"{field.capitalize()} set", source, log_msg)
def unpermaban_command(**options): message = options["message"] bot = options["bot"] source = options["source"] if message: username = message.split(" ")[0].strip().lower() with bot.users.find_context(username) as user: if not user: bot.whisper(source.username, "No user with that name found.") return False if user.banned is False: bot.whisper(source.username, "User is not permabanned.") return False user.banned = False message = message.lower() log_msg = "{} is no longer permabanned".format(user.username_raw) bot.whisper(source.username, log_msg) AdminLogManager.add_entry("Permaban remove", source, log_msg)
def unpermaban_command(self, **options): message = options['message'] bot = options['bot'] source = options['source'] if message: username = message.split(' ')[0].strip().lower() with bot.users.find_context(username) as user: if not user: bot.whisper(source.username, 'No user with that name found.') return False if user.banned is False: bot.whisper(source.username, 'User is not permabanned.') return False user.banned = False message = message.lower() log_msg = '{} is no longer permabanned'.format(user.username_raw) bot.whisper(source.username, log_msg) AdminLogManager.add_entry('Permaban remove', source, log_msg)
def edit_command(bot, source, message, event, args): """Dispatch method for editing commands. Usage: !edit command ALIAS [options] RESPONSE Multiple options available: --whisper/--no-whisper --reply/--no-reply --modonly/--no-modonly --cd CD --usercd USERCD --level LEVEL --cost COST """ if message: # Make sure we got both an alias and a response message_parts = message.split() if len(message_parts) < 2: bot.whisper(source.username, 'Usage: !add command ALIAS [options] RESPONSE') return False options, response = bot.commands.parse_command_arguments(message_parts[1:]) options['edited_by'] = source.id if options is False: bot.whisper(source.username, 'Invalid command') return False alias = message_parts[0].replace('!', '').lower() type = 'say' if options['whisper'] is True: type = 'whisper' elif options['reply'] is True: type = 'reply' elif response.startswith('/me') or response.startswith('.me'): type = 'me' response = ' '.join(response.split(' ')[1:]) elif options['whisper'] is False or options['reply'] is False: type = 'say' action = { 'type': type, 'message': response, } command = bot.commands.get(alias, None) if command is None: bot.whisper(source.username, 'No command found with the alias {}. Did you mean to create the command? If so, use !add command instead.'.format(alias)) return False old_message = '' new_message = '' if len(action['message']) > 0: options['action'] = action old_message = command.action.response new_message = action['message'] elif not type == command.action.subtype: options['action'] = { 'type': type, 'message': command.action.response, } bot.commands.edit_command(command, **options) bot.whisper(source.username, 'Updated the command (ID: {command.id})'.format(command=command)) if len(new_message) > 0: log_msg = 'The !{} command has been updated from "{}" to "{}"'.format( command.command.split('|')[0], old_message, new_message) else: log_msg = 'The !{} command has been updated'.format(command.command.split('|')[0]) AdminLogManager.add_entry('Command edited', source, log_msg, data={ 'old_message': old_message, 'new_message': new_message, })
def commands_create(**options): session.pop('command_created_id', None) session.pop('command_edited_id', None) if request.method == 'POST': if 'aliases' not in request.form: abort(403) alias_str = request.form.get('aliases', '').replace('!', '').lower() delay_all = request.form.get('cd', Command.DEFAULT_CD_ALL) delay_user = request.form.get('usercd', Command.DEFAULT_CD_USER) level = request.form.get('level', Command.DEFAULT_LEVEL) cost = request.form.get('cost', 0) try: delay_all = int(delay_all) delay_user = int(delay_user) level = int(level) cost = int(cost) except ValueError: abort(403) if len(alias_str) == 0: abort(403) if delay_all < 0 or delay_all > 9999: abort(403) if delay_user < 0 or delay_user > 9999: abort(403) if level < 0 or level > 2000: abort(403) if cost < 0 or cost > 9999999: abort(403) user = options.get('user', None) if user is None: abort(403) options = { 'delay_all': delay_all, 'delay_user': delay_user, 'level': level, 'cost': cost, 'added_by': user.id, } valid_action_types = ['say', 'me', 'whisper', 'reply'] action_type = request.form.get('reply', 'say').lower() if action_type not in valid_action_types: abort(403) response = request.form.get('response', '') if len(response) == 0: abort(403) action = { 'type': action_type, 'message': response } options['action'] = action command_manager = ( pajbot.managers.command.CommandManager( socket_manager=None, module_manager=ModuleManager(None).load(), bot=None).load(enabled=None)) command_aliases = [] for alias, command in command_manager.items(): command_aliases.append(alias) if command.command and len(command.command) > 0: command_aliases.extend(command.command.split('|')) command_aliases = set(command_aliases) alias_str = alias_str.replace(' ', '').replace('!', '').lower() alias_list = alias_str.split('|') alias_list = [alias for alias in alias_list if len(alias) > 0] if len(alias_list) == 0: return render_template('admin/create_command_fail.html') for alias in alias_list: if alias in command_aliases: return render_template('admin/create_command_fail.html') alias_str = '|'.join(alias_list) command = Command(command=alias_str, **options) command.data = CommandData(command.id, **options) log_msg = 'The !{} command has been created'.format(command.command.split('|')[0]) AdminLogManager.add_entry('Command created', user, log_msg) with DBManager.create_session_scope(expire_on_commit=False) as db_session: db_session.add(command) db_session.add(command.data) db_session.commit() db_session.expunge(command) db_session.expunge(command.data) SocketClientManager.send('command.update', {'command_id': command.id}) session['command_created_id'] = command.id return redirect('/admin/commands/', 303) else: return render_template('admin/create_command.html')
def post(self, command_id, **extra_args): args = pajbot.utils.remove_none_values(self.post_parser.parse_args()) if len(args) == 0: return { 'error': 'Missing parameter to edit.' }, 400 valid_names = [ 'enabled', 'level', 'delay_all', 'delay_user', 'cost', 'can_execute_with_whisper', 'sub_only' ] valid_action_names = [ 'type', 'message' ] with DBManager.create_session_scope() as db_session: command = db_session.query(Command).options(joinedload(Command.data).joinedload(CommandData.user)).filter_by(id=command_id).one_or_none() if command is None: return {'error': 'Invalid command ID'}, 404 if command.level > extra_args['user'].level: return {'error': 'Unauthorized'}, 403 parsed_action = json.loads(command.action_json) options = { 'edited_by': extra_args['user'].id, } for key in args: if key.startswith('data_'): name = key[5:] value = args[key] if name.startswith('action_'): name = name[7:] if name in valid_action_names and name in parsed_action and command.action.type == 'message': value_type = type(parsed_action[name]) if value_type is bool: parsed_value = True if value == '1' else False elif value_type is int: try: parsed_value = int(value) except ValueError: continue else: parsed_value = value parsed_action[name] = parsed_value command.action_json = json.dumps(parsed_action) else: if name in valid_names: value_type = type(getattr(command, name)) if value_type is bool: parsed_value = True if value == '1' else False elif value_type is int: try: parsed_value = int(value) except ValueError: continue else: parsed_value = value options[name] = parsed_value aj = json.loads(command.action_json) old_message = '' new_message = '' try: old_message = command.action.response new_message = aj['message'] except: pass command.set(**options) command.data.set(**options) if len(old_message) > 0 and old_message != new_message: log_msg = 'The !{} command has been updated from "{}" to "{}"'.format( command.command.split('|')[0], old_message, new_message) else: log_msg = 'The !{} command has been updated'.format(command.command.split('|')[0]) AdminLogManager.add_entry('Command edited', extra_args['user'], log_msg, data={ 'old_message': old_message, 'new_message': new_message, }) if SocketClientManager.send('command.update', {'command_id': command_id}) is True: return {'success': 'good job'}, 200 else: return {'error': 'could not push update'}, 500