def twitter_follow(**options): json_data = request.get_json() if not json_data: return {"error": "No input data provided"}, 400 try: data: UserRequest = UserRequestSchema().load(json_data) except ValidationError as err: return { "error": f"Did not match schema: {json.dumps(err.messages)}" }, 400 username = data.username.strip() if not username: return { "message": "username must contain at least 1 character" }, 400 with DBManager.create_session_scope() as db_session: twitter_user = db_session.query(TwitterUser).filter_by( username=username).one_or_none() if twitter_user is not None: return {"message": f"We are already following {username}"}, 409 twitter_user = TwitterUser(username) db_session.add(twitter_user) db_session.flush() db_session.commit() SocketClientManager.send("twitter.follow", {"username": username}) return {"message": f"Successfully followed {username}"}, 200
def post(self, row_id, **options): args = self.post_parser.parse_args() try: new_state = int(args["new_state"]) except (ValueError, KeyError): return {"error": "Invalid `new_state` parameter."}, 400 with DBManager.create_session_scope() as db_session: row = db_session.query(Module).filter_by(id=row_id).one_or_none() if not row: return {"error": "Module with this ID not found"}, 404 if validate_module(row_id) is False: return {"error": "cannot modify module"}, 400 row.enabled = True if new_state == 1 else False db_session.commit() payload = {"id": row.id, "new_state": row.enabled} AdminLogManager.post("Module toggled", options["user"], "Enabled" if row.enabled else "Disabled", row.id) SocketClientManager.send("module.update", payload) return {"success": "successful toggle", "new_state": new_state}
def modules_edit(module_id, **options): module_manager = ModuleManager(None).load(do_reload=False) current_module = find(lambda m: m.ID == module_id, module_manager.all_modules) if current_module is None: return render_template('admin/module_404.html'), 404 sub_modules = [] for module in module_manager.all_modules: module.db_module = None with DBManager.create_session_scope() as db_session: for db_module in db_session.query(Module): module = find(lambda m: m.ID == db_module.id, module_manager.all_modules) if module: module.db_module = db_module if module.PARENT_MODULE == current_module.__class__: sub_modules.append(module) if current_module.db_module is None: return render_template('admin/module_404.html'), 404 if request.method == 'POST': form_values = {key: value for key, value in request.form.items()} res = current_module.parse_settings(**form_values) if res is False: return render_template('admin/module_404.html'), 404 current_module.db_module.settings = json.dumps(res) db_session.commit() settings = None try: settings = json.loads(current_module.db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) payload = { 'id': current_module.db_module.id, } SocketClientManager.send('module.update', payload) AdminLogManager.post('Module edited', options['user'], current_module.NAME) return render_template('admin/configure_module.html', module=current_module, sub_modules=sub_modules) else: settings = None try: settings = json.loads(current_module.db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) return render_template('admin/configure_module.html', module=current_module, sub_modules=sub_modules)
def timer_toggle(timer_id: int, **options) -> ResponseReturnValue: try: json_data = request.get_json() if not json_data: return {"error": "Missing json body"}, 400 data: ToggleState = ToggleStateSchema().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: row = db_session.query(Timer).filter_by(id=timer_id).one_or_none() if not row: return {"error": "Timer with this ID not found"}, 404 row.enabled = data.new_state db_session.commit() payload = {"id": row.id, "new_state": data.new_state} AdminLogManager.post("Timer toggled", options["user"], "Enabled" if data.new_state else "Disabled", row.name) SocketClientManager.send("timer.update", payload) return { "success": "successful toggle", "new_state": data.new_state }
def module_toggle(row_id: str, **options) -> ResponseReturnValue: try: json_data = request.get_json() if not json_data: return {"error": "Missing json body"}, 400 data: ToggleState = ToggleStateSchema().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: row = db_session.query(Module).filter_by(id=row_id).one_or_none() if not row: return {"error": "Module with this ID not found"}, 404 if validate_module(row_id) is False: return {"error": "cannot modify module"}, 400 row.enabled = data.new_state db_session.commit() payload = {"id": row.id, "new_state": data.new_state} AdminLogManager.post("Module toggled", options["user"], "Enabled" if row.enabled else "Disabled", row.id) SocketClientManager.send("module.update", payload) log.info(f"new state: {data} - {data.new_state}") return { "success": "successful toggle", "new_state": data.new_state }
def generic_toggle(route_key, row_id, **options): valid_routes = { 'timer': Timer, 'banphrase': Banphrase, 'module': Module, } if route_key not in valid_routes: return make_response(jsonify({'error': 'Invalid route.'}), 400) if 'new_state' not in request.form: return make_response(jsonify({'error': 'Missing `new_state` parameter.'}), 400) try: new_state = int(request.form['new_state']) except (ValueError, KeyError): return make_response(jsonify({'error': 'Invalid `new_state` parameter.'}), 400) route_value = valid_routes[route_key] with DBManager.create_session_scope() as db_session: row = db_session.query(route_value).filter_by(id=row_id).one_or_none() if row: row.enabled = True if new_state == 1 else False db_session.commit() SocketClientManager.send('{}.update'.format(route_key), {'{}_id'.format(route_key): row.id}) return make_response(jsonify({'success': 'successful toggle', 'new_state': new_state})) else: return make_response(jsonify({'error': 'invalid {} id'.format(route_key)}))
def post(self, row_id, **options): args = self.post_parser.parse_args() try: new_state = int(args['new_state']) except (ValueError, KeyError): return {'error': 'Invalid `new_state` parameter.'}, 400 with DBManager.create_session_scope() as db_session: row = db_session.query(Module).filter_by(id=row_id).one_or_none() if not row: return { 'error': 'Module with this ID not found' }, 404 if validate_module(row_id) is False: return {'error': 'cannot modify module'}, 400 row.enabled = True if new_state == 1 else False db_session.commit() payload = { 'id': row.id, 'new_state': row.enabled, } AdminLogManager.post('Module toggled', options['user'], 'Enabled' if row.enabled else 'Disabled', row.id) SocketClientManager.send('module.update', payload) return {'success': 'successful toggle', 'new_state': new_state}
def post(self, row_id, **options): args = self.post_parser.parse_args() try: new_state = int(args['new_state']) except (ValueError, KeyError): return {'error': 'Invalid `new_state` parameter.'}, 400 with DBManager.create_session_scope() as db_session: row = db_session.query(Banphrase).filter_by(id=row_id).one_or_none() if not row: return { 'error': 'Banphrase with this ID not found' }, 404 row.enabled = True if new_state == 1 else False db_session.commit() payload = { 'id': row.id, 'new_state': row.enabled, } AdminLogManager.post('Banphrase toggled', options['user'], 'Enabled' if row.enabled else 'Disabled', row.phrase) SocketClientManager.send('banphrase.update', payload) return {'success': 'successful toggle', 'new_state': new_state}
def generic_toggle(route_key, row_id, **options): valid_routes = { 'timer': Timer, 'banphrase': Banphrase, 'module': Module, } route_name = { 'timer': lambda x: x.name, 'banphrase': lambda x: x.phrase, 'module': lambda x: x.id, } route_title = { 'timer': 'Timer', 'banphrase': 'Banphrase', 'module': 'Module', } route_validator = { 'module': lambda x: validate_module(x.id) } if route_key not in valid_routes: return make_response(jsonify({'error': 'Invalid route.'}), 400) if 'new_state' not in request.form: return make_response(jsonify({'error': 'Missing `new_state` parameter.'}), 400) try: new_state = int(request.form['new_state']) except (ValueError, KeyError): return make_response(jsonify({'error': 'Invalid `new_state` parameter.'}), 400) route_value = valid_routes[route_key] with DBManager.create_session_scope() as db_session: row = db_session.query(route_value).filter_by(id=row_id).one_or_none() if row: validator = route_validator.get(route_key, None) if validator is not None: res = validator(row) if not res: return make_response(jsonify({'error': 'cannot modify {}'.format(route_key)}), 400) row.enabled = True if new_state == 1 else False db_session.commit() payload = { '{}_id'.format(route_key): row.id, # remove this 'id': row.id, 'new_state': row.enabled, } AdminLogManager.post('{title} toggled'.format(title=route_title[route_key]), options['user'], 'Enabled' if row.enabled else 'Disabled', route_name[route_key](row)) SocketClientManager.send('{}.update'.format(route_key), payload) return make_response(jsonify({'success': 'successful toggle', 'new_state': new_state})) else: return make_response(jsonify({'error': 'invalid {} id'.format(route_key)}))
def timer_remove(timer_id, **options): with DBManager.create_session_scope() as db_session: timer = db_session.query(Timer).filter_by(id=timer_id).one_or_none() if timer is None: return make_response(jsonify({"error": "Invalid timer ID"})) db_session.delete(timer) SocketClientManager.send("timer.remove", {"timer_id": timer.id}) return make_response(jsonify({"success": "good job"}))
def timer_remove(timer_id, **options): with DBManager.create_session_scope() as db_session: timer = db_session.query(Timer).filter_by(id=timer_id).one_or_none() if timer is None: return make_response(jsonify({'error': 'Invalid timer ID'})) db_session.delete(timer) SocketClientManager.send('timer.remove', {'timer_id': timer.id}) return make_response(jsonify({'success': 'good job'}))
def modules_edit(module_id, **options): module_manager = ModuleManager(None).load(do_reload=False) current_module = find(lambda m: m.ID == module_id, module_manager.all_modules) if current_module is None: return render_template('admin/module_404.html'), 404 sub_modules = [] for module in module_manager.all_modules: module.db_module = None with DBManager.create_session_scope() as db_session: for db_module in db_session.query(Module): module = find(lambda m: m.ID == db_module.id, module_manager.all_modules) if module: module.db_module = db_module if module.PARENT_MODULE == current_module.__class__: sub_modules.append(module) if current_module.db_module is None: return render_template('admin/module_404.html'), 404 if request.method == 'POST': form_values = {key: value for key, value in request.form.items()} res = current_module.parse_settings(**form_values) if res is False: return render_template('admin/module_404.html'), 404 current_module.db_module.settings = json.dumps(res) db_session.commit() settings = None try: settings = json.loads(current_module.db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) SocketClientManager.send( 'module.update', {'module_id': current_module.db_module.id}) return render_template('admin/configure_module.html', module=current_module, sub_modules=sub_modules) else: settings = None try: settings = json.loads(current_module.db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) return render_template('admin/configure_module.html', module=current_module, sub_modules=sub_modules)
def timers_create(**options): session.pop('timer_created_id', None) session.pop('timer_edited_id', None) if request.method == 'POST': id = None try: if 'id' in request.form: id = int(request.form['id']) name = request.form['name'].strip() interval_online = int(request.form['interval_online']) interval_offline = int(request.form['interval_offline']) message_type = request.form['message_type'] message = request.form['message'].strip() except (KeyError, ValueError): abort(403) if interval_online < 0 or interval_offline < 0: abort(403) if message_type not in ['say', 'me']: abort(403) if len(message) == 0: abort(403) options = { 'name': name, 'interval_online': interval_online, 'interval_offline': interval_offline, } action = { 'type': message_type, 'message': message } options['action'] = action if id is None: timer = Timer(**options) with DBManager.create_session_scope(expire_on_commit=False) as db_session: if id is not None: timer = db_session.query(Timer).filter_by(id=id).one_or_none() if timer is None: return redirect('/admin/timers/', 303) timer.set(**options) else: db_session.add(timer) SocketClientManager.send('timer.update', {'timer_id': timer.id}) if id is None: session['timer_created_id'] = timer.id else: session['timer_edited_id'] = timer.id return redirect('/admin/timers/', 303) else: return render_template('admin/create_timer.html')
def get(self, timer_id, **options): with DBManager.create_session_scope() as db_session: timer = db_session.query(Timer).filter_by(id=timer_id).one_or_none() if timer is None: return {'error': 'Invalid timer ID'}, 404 AdminLogManager.post('Timer removed', options['user'], timer.name) db_session.delete(timer) SocketClientManager.send('timer.remove', {'id': timer.id}) return {'success': 'good job'}
def banphrase_remove(banphrase_id, **options): with DBManager.create_session_scope() as db_session: banphrase = db_session.query(Banphrase).filter_by(id=banphrase_id).one_or_none() if banphrase is None: return make_response(jsonify({"error": "Invalid banphrase ID"})) db_session.delete(banphrase) db_session.delete(banphrase.data) SocketClientManager.send("banphrase.remove", {"banphrase_id": banphrase.id}) return make_response(jsonify({"success": "good job"}))
def get(self, timer_id, **options): with DBManager.create_session_scope() as db_session: timer = db_session.query(Timer).filter_by(id=timer_id).one_or_none() if timer is None: return {"error": "Invalid timer ID"}, 404 AdminLogManager.post("Timer removed", options["user"], timer.name) db_session.delete(timer) SocketClientManager.send("timer.remove", {"id": timer.id}) return {"success": "good job"}
def banphrase_remove(banphrase_id, **options): with DBManager.create_session_scope() as db_session: banphrase = db_session.query(Banphrase).filter_by(id=banphrase_id).one_or_none() if banphrase is None: return make_response(jsonify({'error': 'Invalid banphrase ID'})) db_session.delete(banphrase) db_session.delete(banphrase.data) SocketClientManager.send('banphrase.remove', {'banphrase_id': banphrase.id}) return make_response(jsonify({'success': 'good job'}))
def modules_edit(module_id, **options): module_manager = ModuleManager(None).load(do_reload=False) current_module = find(lambda m: m.ID == module_id, module_manager.all_modules) if current_module is None: return render_template('admin/module_404.html'), 404 if request.method == 'POST': form_values = {key: value for key, value in request.form.items()} res = current_module.parse_settings(**form_values) if res is False: return render_template('admin/module_404.html'), 404 with DBManager.create_session_scope() as db_session: db_module = db_session.query(Module).filter_by( id=module_id).one_or_none() if db_module is None: return render_template('admin/module_404.html'), 404 db_module.settings = json.dumps(res) db_session.commit() current_module.db_module = db_module settings = None try: settings = json.loads(db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) SocketClientManager.send('module.update', {'module_id': db_module.id}) return render_template('admin/configure_module.html', module=current_module) pass else: with DBManager.create_session_scope() as db_session: db_module = db_session.query(Module).filter_by( id=module_id).one_or_none() if db_module is None: return render_template('admin/module_404.html'), 404 current_module.db_module = db_module settings = None try: settings = json.loads(db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) return render_template('admin/configure_module.html', module=current_module)
def get(self, banphrase_id, **options): with DBManager.create_session_scope() as db_session: banphrase = db_session.query(Banphrase).filter_by(id=banphrase_id).one_or_none() if banphrase is None: return {'error': 'Invalid banphrase ID'}, 404 AdminLogManager.post('Banphrase removed', options['user'], banphrase.phrase) db_session.delete(banphrase) db_session.delete(banphrase.data) SocketClientManager.send('banphrase.remove', {'id': banphrase.id}) return {'success': 'good job'}, 200
def banphrases_remove(banphrase_id, **options): with DBManager.create_session_scope() as db_session: banphrase = db_session.query(Banphrase).filter_by(id=banphrase_id).one_or_none() if banphrase is None: return {"error": "Invalid banphrase ID"}, 404 AdminLogManager.post("Banphrase removed", options["user"], banphrase.id, banphrase.phrase) db_session.delete(banphrase) db_session.delete(banphrase.data) SocketClientManager.send("banphrase.remove", {"id": banphrase.id}) return {"success": "good job"}, 200
def post(self, playsound_name, **options): with DBManager.create_session_scope() as db_session: count = db_session.query(Playsound).filter(Playsound.name == playsound_name).count() if count <= 0: return "Playsound does not exist", 404 # explicitly don't check for disabled SocketClientManager.send("playsound.play", {"name": playsound_name}) return "OK", 200
def modules_edit(module_id, **options): module_manager = ModuleManager(None).load(do_reload=False) current_module = find(lambda m: m.ID == module_id, module_manager.all_modules) if current_module is None: return render_template('admin/module_404.html'), 404 if request.method == 'POST': form_values = {key: value for key, value in request.form.items()} res = current_module.parse_settings(**form_values) if res is False: return render_template('admin/module_404.html'), 404 with DBManager.create_session_scope() as db_session: db_module = db_session.query(Module).filter_by(id=module_id).one_or_none() if db_module is None: return render_template('admin/module_404.html'), 404 db_module.settings = json.dumps(res) db_session.commit() current_module.db_module = db_module settings = None try: settings = json.loads(db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) SocketClientManager.send('module.update', {'module_id': db_module.id}) return render_template('admin/configure_module.html', module=current_module) pass else: with DBManager.create_session_scope() as db_session: db_module = db_session.query(Module).filter_by(id=module_id).one_or_none() if db_module is None: return render_template('admin/module_404.html'), 404 current_module.db_module = db_module settings = None try: settings = json.loads(db_module.settings) except (TypeError, ValueError): pass current_module.load(settings=settings) return render_template('admin/configure_module.html', module=current_module)
def post(self, **options): args = self.post_parser.parse_args() with DBManager.create_session_scope() as db_session: twitter_user = db_session.query(TwitterUser).filter_by(username=args["username"]).one_or_none() if twitter_user is None: return {"message": "We are not following a twitter user by that name."}, 404 db_session.delete(twitter_user) db_session.flush() db_session.commit() SocketClientManager.send("twitter.unfollow", {"username": args["username"]}) return {"message": "Successfully unfollowed {}".format(args["username"])}, 200
def post(self, playsound_name, **options): with DBManager.create_session_scope() as db_session: count = db_session.query(Playsound).filter( Playsound.name == playsound_name).count() if count <= 0: return "Playsound does not exist", 404 # explicitly don't check for disabled if options["user"].username_raw == "dank__doge": return "Feels Very Weird Man", 403 SocketClientManager.send("playsound.play", {"name": playsound_name}) return "OK", 200
def post(self, **options): args = self.post_parser.parse_args() with DBManager.create_session_scope() as db_session: twitter_user = db_session.query(TwitterUser).filter_by(username=args["username"]).one_or_none() if twitter_user is not None: return {"message": "We are already following {}".format(args["username"])}, 409 twitter_user = TwitterUser(args["username"].lower()) db_session.add(twitter_user) db_session.flush() db_session.commit() SocketClientManager.send("twitter.follow", {"username": args["username"]}) return {"message": "Successfully followed {}".format(args["username"])}, 200
def post(self, **options): args = self.post_parser.parse_args() with DBManager.create_session_scope() as db_session: twitter_user = db_session.query(TwitterUser).filter_by(username=args['username']).one_or_none() if twitter_user is None: return { 'message': 'We are not following a twitter user by that name.', }, 404 db_session.delete(twitter_user) db_session.flush() db_session.commit() SocketClientManager.send('twitter.unfollow', {'username': args['username']}) return { 'message': 'Successfully unfollowed {}'.format(args['username']), }, 200
def post(self, **options): args = self.post_parser.parse_args() with DBManager.create_session_scope() as db_session: twitter_user = db_session.query(TwitterUser).filter_by(username=args['username']).one_or_none() if twitter_user is not None: return { 'message': 'We are already following {}'.format(args['username']), }, 409 twitter_user = TwitterUser(args['username'].lower()) db_session.add(twitter_user) db_session.flush() db_session.commit() SocketClientManager.send('twitter.follow', {'username': args['username']}) return { 'message': 'Successfully followed {}'.format(args['username']), }, 200
def generic_toggle(route_key, row_id, **options): valid_routes = {"timer": Timer, "banphrase": Banphrase, "module": Module} if route_key not in valid_routes: return make_response(jsonify({"error": "Invalid route."}), 400) if "new_state" not in request.form: return make_response(jsonify({"error": "Missing `new_state` parameter."}), 400) try: new_state = int(request.form["new_state"]) except (ValueError, KeyError): return make_response(jsonify({"error": "Invalid `new_state` parameter."}), 400) route_value = valid_routes[route_key] with DBManager.create_session_scope() as db_session: row = db_session.query(route_value).filter_by(id=row_id).one_or_none() if row: row.enabled = True if new_state == 1 else False db_session.commit() SocketClientManager.send("{}.update".format(route_key), {"{}_id".format(route_key): row.id}) return make_response(jsonify({"success": "successful toggle", "new_state": new_state})) else: return make_response(jsonify({"error": "invalid {} id".format(route_key)}))
def banphrases_toggle(row_id, **options): json_data = request.get_json() if not json_data: return {"error": "No input data provided"}, 400 try: data: ToggleState = ToggleStateSchema().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: row = db_session.query(Banphrase).filter_by(id=row_id).one_or_none() if not row: return {"error": "Banphrase with this ID not found"}, 404 row.enabled = data.new_state db_session.commit() payload = {"id": row.id, "new_state": data.new_state} AdminLogManager.post( "Banphrase toggled", options["user"], "Enabled" if data.new_state else "Disabled", row.id, row.phrase ) SocketClientManager.send("banphrase.update", payload) return {"success": "successful toggle", "new_state": data.new_state}
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 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 toggle_banphrases(self): with DBManager.create_session_scope() as db_session: row = db_session.query(Banphrase).filter_by(id=108).one_or_none() row2 = db_session.query(Banphrase).filter_by(id=113).one_or_none() row.enabled = True if not row.enabled else False row2.enabled = True if not row2.enabled else False db_session.commit() payload1 = {"id": row.id, "new_state": row.enabled} payload2 = {"id": row2.id, "new_state": row2.enabled} SocketClientManager.init("/tmp/.bullbot.sock") SocketClientManager.send("banphrase.update", payload1) SocketClientManager.send("banphrase.update", payload2)
def banphrases_create(**options): session.pop('banphrase_created_id', None) session.pop('banphrase_edited_id', None) if request.method == 'POST': id = None try: if 'id' in request.form: id = int(request.form['id']) name = request.form['name'].strip() permanent = request.form.get('permanent', 'off') warning = request.form.get('warning', 'off') notify = request.form.get('notify', 'off') case_sensitive = request.form.get('case_sensitive', 'off') length = int(request.form['length']) phrase = request.form['phrase'].strip() operator = request.form['operator'].strip().lower() except (KeyError, ValueError): abort(403) permanent = True if permanent == 'on' else False warning = True if warning == 'on' else False notify = True if notify == 'on' else False case_sensitive = True if case_sensitive == 'on' else False if len(name) == 0: abort(403) if len(phrase) == 0: abort(403) if length < 0 or length > 1209600: abort(403) valid_operators = ['contains', 'startswith', 'endswith'] if operator not in valid_operators: abort(403) user = options.get('user', None) if user is None: abort(403) options = { 'name': name, 'phrase': phrase, 'permanent': permanent, 'warning': warning, 'notify': notify, 'case_sensitive': case_sensitive, 'length': length, 'added_by': user.id, 'operator': operator, } if id is None: banphrase = Banphrase(**options) banphrase.data = BanphraseData(banphrase.id, added_by=options['added_by']) with DBManager.create_session_scope(expire_on_commit=False) as db_session: if id is not None: banphrase = db_session.query(Banphrase).filter_by(id=id).one_or_none() if banphrase is None: return redirect('/admin/banphrases/', 303) banphrase.set(**options) else: log.info('adding...') db_session.add(banphrase) log.info('adding data..') db_session.add(banphrase.data) log.info('should commit now...') log.info('commited') SocketClientManager.send('banphrase.update', {'banphrase_id': banphrase.id}) if id is None: session['banphrase_created_id'] = banphrase.id else: session['banphrase_edited_id'] = banphrase.id return redirect('/admin/banphrases/', 303) else: return render_template('admin/create_banphrase.html')
def timers_create(**options): session.pop("timer_created_id", None) session.pop("timer_edited_id", None) if request.method != "POST": return render_template("admin/create_timer.html") id = None try: if "id" in request.form: id = int(request.form["id"]) name = request.form["name"].strip() interval_online = int(request.form["interval_online"]) interval_offline = int(request.form["interval_offline"]) message_type = request.form["message_type"] message = request.form["message"].strip() except (KeyError, ValueError): abort(403) if interval_online < 0 or interval_offline < 0: abort(403) if message_type not in ["say", "me"]: abort(403) if not message: abort(403) user = options.get("user", None) if user is None: abort(403) options = {"name": name, "interval_online": interval_online, "interval_offline": interval_offline} action = {"type": message_type, "message": message} options["action"] = action if id is None: timer = Timer(**options) with DBManager.create_session_scope(expire_on_commit=False) as db_session: if id is not None: timer = db_session.query(Timer).filter_by(id=id).one_or_none() if timer is None: return redirect("/admin/timers/", 303) old_message = "" new_message = "" try: old_message = timer.action.response new_message = action["message"] except: pass timer.set(**options) if old_message and old_message != new_message: log_msg = f'Timer "{timer.name}" has been updated from "{old_message}" to "{new_message}"' else: log_msg = f'Timer "{timer.name}" has been updated' AdminLogManager.add_entry( "Timer edited", user, log_msg, data={"old_message": old_message, "new_message": new_message} ) else: db_session.add(timer) AdminLogManager.post("Timer added", user, timer.name) SocketClientManager.send("timer.update", {"id": timer.id}) if id is None: session["timer_created_id"] = timer.id else: session["timer_edited_id"] = timer.id return redirect("/admin/timers/", 303)
def command_update(command_id, **options): if not request.method == "POST": return make_response(jsonify({"error": "Invalid request method. (Expected POST)"}), 400) if len(request.form) == 0: return make_response(jsonify({"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 make_response(jsonify({"error": "Invalid command ID"}), 404) if command.level > options["user"].level: abort(403) parsed_action = json.loads(command.action_json) options = {"edited_by": options["user"].id} for key in request.form: if key.startswith("data_"): name = key[5:] value = request.form[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 command.set(**options) command.data.set(**options) if SocketClientManager.send("command.update", {"command_id": command_id}) is True: return make_response(jsonify({"success": "good job"})) else: return make_response(jsonify({"error": "Could not push update"}))
def init(args): import configparser import datetime import logging import subprocess import sys from flask import request from flask import session from flask_scrypt import generate_random_salt import pajbot.web.common import pajbot.web.routes from pajbot.bot import Bot from pajbot.managers.db import DBManager from pajbot.managers.redis import RedisManager from pajbot.managers.time import TimeManager from pajbot.models.module import ModuleManager from pajbot.models.sock import SocketClientManager from pajbot.streamhelper import StreamHelper from pajbot.utils import load_config from pajbot.web.models import errors from pajbot.web.utils import download_logo log = logging.getLogger(__name__) config = configparser.ConfigParser() config = load_config(args.config) config.read('webconfig.ini') if 'web' not in config: log.error('Missing [web] section in config.ini') sys.exit(1) if 'pleblist_password_salt' not in config['web']: salt = generate_random_salt() config.set('web', 'pleblist_password_salt', salt.decode('utf-8')) if 'pleblist_password' not in config['web']: salt = generate_random_salt() config.set('web', 'pleblist_password', salt.decode('utf-8')) if 'secret_key' not in config['web']: salt = generate_random_salt() config.set('web', 'secret_key', salt.decode('utf-8')) if 'logo' not in config['web']: res = download_logo(config['webtwitchapi']['client_id'], config['main']['streamer']) if res: config.set('web', 'logo', 'set') StreamHelper.init_web(config['main']['streamer']) redis_options = {} if 'redis' in config: redis_options = config._sections['redis'] RedisManager.init(**redis_options) with open(args.config, 'w') as configfile: config.write(configfile) app.bot_modules = config['web'].get('modules', '').split() app.bot_commands_list = [] app.bot_config = config app.secret_key = config['web']['secret_key'] if 'sock' in config and 'sock_file' in config['sock']: SocketClientManager.init(config['sock']['sock_file']) DBManager.init(config['main']['db']) TimeManager.init_timezone(config['main'].get('timezone', 'UTC')) app.module_manager = ModuleManager(None).load() pajbot.web.routes.admin.init(app) pajbot.web.routes.api.init(app) pajbot.web.routes.base.init(app) pajbot.web.common.filters.init(app) pajbot.web.common.assets.init(app) pajbot.web.common.tasks.init(app) pajbot.web.common.menu.init(app) app.register_blueprint(pajbot.web.routes.clr.page) errors.init(app, config) pajbot.web.routes.clr.config = config version = Bot.version last_commit = '' commit_number = 0 try: current_branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).decode('utf8').strip() latest_commit = subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode('utf8').strip()[:8] commit_number = subprocess.check_output(['git', 'rev-list', 'HEAD', '--count']).decode('utf8').strip() last_commit = subprocess.check_output(['git', 'log', '-1', '--format=%cd']).decode('utf8').strip() version = '{0} DEV ({1}, {2}, commit {3})'.format(version, current_branch, latest_commit, commit_number) except: pass default_variables = { 'version': version, 'last_commit': last_commit, 'commit_number': commit_number, 'bot': { 'name': config['main']['nickname'], }, 'site': { 'domain': config['web']['domain'], 'deck_tab_images': config.getboolean('web', 'deck_tab_images'), 'websocket': { 'host': config['websocket'].get('host', config['web']['domain']), 'port': config['websocket']['port'], 'ssl': config.getboolean('websocket', 'ssl') } }, 'streamer': { 'name': config['web']['streamer_name'], 'full_name': config['main']['streamer'] }, 'modules': app.bot_modules, 'request': request, 'session': session, 'google_analytics': config['web'].get('google_analytics', None), } @app.context_processor def current_time(): current_time = {} current_time['current_time'] = datetime.datetime.now() return current_time @app.context_processor def inject_default_variables(): return default_variables
def command_update(command_id, **options): if not request.method == 'POST': return make_response(jsonify({'error': 'Invalid request method. (Expected POST)'}), 400) if len(request.form) == 0: return make_response(jsonify({'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).filter_by(id=command_id).one_or_none() if command is None: return make_response(jsonify({'error': 'Invalid command ID'}), 404) if command.level > options['user'].level: abort(403) parsed_action = json.loads(command.action_json) options = {} for key in request.form: if key.startswith('data_'): name = key[5:] value = request.form[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 command.set(**options) if SocketClientManager.send('command.update', {'command_id': command_id}) is True: return make_response(jsonify({'success': 'good job'})) else: return make_response(jsonify({'error': 'Could not push update'}))
def timers_create(**options): session.pop('timer_created_id', None) session.pop('timer_edited_id', None) if request.method == 'POST': id = None try: if 'id' in request.form: id = int(request.form['id']) name = request.form['name'].strip() interval_online = int(request.form['interval_online']) interval_offline = int(request.form['interval_offline']) message_type = request.form['message_type'] message = request.form['message'].strip() except (KeyError, ValueError): abort(403) if interval_online < 0 or interval_offline < 0: abort(403) if message_type not in ['say', 'me']: abort(403) if len(message) == 0: abort(403) user = options.get('user', None) if user is None: abort(403) options = { 'name': name, 'interval_online': interval_online, 'interval_offline': interval_offline, } action = { 'type': message_type, 'message': message } options['action'] = action if id is None: timer = Timer(**options) with DBManager.create_session_scope(expire_on_commit=False) as db_session: if id is not None: timer = db_session.query(Timer).filter_by(id=id).one_or_none() if timer is None: return redirect('/admin/timers/', 303) old_message = '' new_message = '' try: old_message = timer.action.response new_message = action['message'] except: pass timer.set(**options) if len(old_message) > 0 and old_message != new_message: log_msg = 'Timer "{0}" has been updated from "{1}" to "{2}"'.format( timer.name, old_message, new_message) else: log_msg = 'Timer "{0}" has been updated'.format(timer.name) AdminLogManager.add_entry('Timer edited', user, log_msg, data={ 'old_message': old_message, 'new_message': new_message, }) else: db_session.add(timer) AdminLogManager.post('Timer added', user, timer.name) SocketClientManager.send('timer.update', {'timer_id': timer.id}) if id is None: session['timer_created_id'] = timer.id else: session['timer_edited_id'] = timer.id return redirect('/admin/timers/', 303) else: return render_template('admin/create_timer.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
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 = ( 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 banphrases_create(**options): session.pop('banphrase_created_id', None) session.pop('banphrase_edited_id', None) if request.method == 'POST': id = None try: if 'id' in request.form: id = int(request.form['id']) name = request.form['name'].strip() permanent = request.form.get('permanent', 'off') warning = request.form.get('warning', 'off') notify = request.form.get('notify', 'off') case_sensitive = request.form.get('case_sensitive', 'off') sub_immunity = request.form.get('sub_immunity', 'off') remove_accents = request.form.get('remove_accents', 'off') length = int(request.form['length']) phrase = request.form['phrase'] operator = request.form['operator'].strip().lower() except (KeyError, ValueError): abort(403) permanent = True if permanent == 'on' else False warning = True if warning == 'on' else False notify = True if notify == 'on' else False case_sensitive = True if case_sensitive == 'on' else False sub_immunity = True if sub_immunity == 'on' else False remove_accents = True if remove_accents == 'on' else False if len(name) == 0: abort(403) if len(phrase) == 0: abort(403) if length < 0 or length > 1209600: abort(403) valid_operators = ['contains', 'startswith', 'endswith', 'exact', 'regex'] if operator not in valid_operators: abort(403) user = options.get('user', None) if user is None: abort(403) options = { 'name': name, 'phrase': phrase, 'permanent': permanent, 'warning': warning, 'notify': notify, 'case_sensitive': case_sensitive, 'sub_immunity': sub_immunity, 'remove_accents': remove_accents, 'length': length, 'added_by': user.id, 'edited_by': user.id, 'operator': operator, } if id is None: banphrase = Banphrase(**options) banphrase.data = BanphraseData(banphrase.id, added_by=options['added_by']) with DBManager.create_session_scope(expire_on_commit=False) as db_session: if id is not None: banphrase = db_session.query(Banphrase).options(joinedload(Banphrase.data)).filter_by(id=id).one_or_none() if banphrase is None: return redirect('/admin/banphrases/', 303) banphrase.set(**options) banphrase.data.set(edited_by=options['edited_by']) log.info('Updated banphrase ID {} by user ID {}'.format(banphrase.id, options['edited_by'])) AdminLogManager.post('Banphrase edited', user, banphrase.phrase) else: db_session.add(banphrase) db_session.add(banphrase.data) log.info('Added a new banphrase by user ID {}'.format(options['added_by'])) AdminLogManager.post('Banphrase added', user, banphrase.phrase) SocketClientManager.send('banphrase.update', {'id': banphrase.id}) if id is None: session['banphrase_created_id'] = banphrase.id else: session['banphrase_edited_id'] = banphrase.id return redirect('/admin/banphrases/', 303) else: return render_template('admin/create_banphrase.html')
except: pass config.set('web', 'logo', 'set') log.info('set logo') except: pass with open(args.config, 'w') as configfile: config.write(configfile) app.secret_key = config['web']['secret_key'] oauth = OAuth(app) if 'sock' in config and 'sock_file' in config['sock']: SocketClientManager.init(config['sock']['sock_file']) twitch = oauth.remote_app( 'twitch', consumer_key=config['webtwitchapi']['client_id'], consumer_secret=config['webtwitchapi']['client_secret'], request_token_params={'scope': 'user_read'}, base_url='https://api.twitch.tv/kraken/', request_token_url=None, access_token_method='POST', access_token_url='https://api.twitch.tv/kraken/oauth2/token', authorize_url='https://api.twitch.tv/kraken/oauth2/authorize', ) DBManager.init(config['main']['db']) TimeManager.init_timezone(config['main'].get('timezone', 'UTC'))
def commands_create(**options) -> ResponseReturnValue: session.pop("command_created_id", None) session.pop("command_edited_id", None) if request.method != "POST": return render_template("admin/create_command.html") 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) can_execute_with_whisper = request.form.get("whisperable", "off") == "on" sub_only = request.form.get("subonly", "off") == "on" mod_only = request.form.get("modonly", "off") == "on" run_through_banphrases = request.form.get("checkmsg", "off") == "on" try: delay_all = int(delay_all) delay_user = int(delay_user) level = int(level) cost = int(cost) except ValueError: abort(403) if not alias_str: 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, "can_execute_with_whisper": can_execute_with_whisper, "sub_only": sub_only, "mod_only": mod_only, "run_through_banphrases": run_through_banphrases, } valid_action_types = ["say", "me", "announce", "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 not response: 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_list = [] for alias, command in command_manager.items(): command_aliases_list.append(alias) if command.command and len(command.command) > 0: command_aliases_list.extend(command.command.split("|")) command_aliases = set(command_aliases_list) 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 not alias_list: 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 = f"The !{command.command.split('|')[0]} command has been created" 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)
def init(args): import subprocess import sys from flask import request from flask import session import pajbot.utils import pajbot.web.common import pajbot.web.routes from pajbot.managers.db import DBManager from pajbot.managers.redis import RedisManager from pajbot.models.module import ModuleManager from pajbot.models.sock import SocketClientManager from pajbot.streamhelper import StreamHelper from pajbot.utils import load_config from pajbot.web.models import errors from pajbot.web.utils import download_logo from pajbot.web.utils import download_sub_badge config = load_config(args.config) api_client_credentials = ClientCredentials( config["twitchapi"]["client_id"], config["twitchapi"]["client_secret"], config["twitchapi"].get( "redirect_uri", f"https://{config['web']['domain']}/login/authorized"), ) redis_options = {} if "redis" in config: redis_options = dict(config["redis"]) RedisManager.init(redis_options) twitch_id_api = TwitchIDAPI(api_client_credentials) app_token_manager = AppAccessTokenManager(twitch_id_api, RedisManager.get()) twitch_helix_api = TwitchHelixAPI(RedisManager.get(), app_token_manager) twitch_badges_api = TwitchBadgesAPI(RedisManager.get()) app.api_client_credentials = api_client_credentials app.twitch_id_api = twitch_id_api app.twitch_helix_api = twitch_helix_api if "web" not in config: log.error("Missing [web] section in config.ini") sys.exit(1) app.streamer = cfg.load_streamer(config, twitch_helix_api) app.streamer_display = app.streamer.name if "streamer_name" in config["web"]: app.streamer_display = config["web"]["streamer_name"] app.bot_user = cfg.load_bot(config, twitch_helix_api) StreamHelper.init_streamer(app.streamer.login, app.streamer.id, app.streamer.name) try: download_logo(twitch_helix_api, app.streamer) except: log.exception("Error downloading the streamers profile picture") subscriber_badge_version = config["web"].get("subscriber_badge_version", "0") # Specifying a value of -1 in the config will disable sub badge downloading. Useful if you want to keep a custom version of a sub badge for a streamer if subscriber_badge_version != "-1": try: download_sub_badge(twitch_badges_api, app.streamer, subscriber_badge_version) except: log.exception("Error downloading the streamers subscriber badge") SocketClientManager.init(app.streamer.login) app.bot_modules = config["web"].get("modules", "").split() app.bot_commands_list = [] app.bot_config = config # https://flask.palletsprojects.com/en/1.1.x/quickstart/#sessions # https://flask.palletsprojects.com/en/1.1.x/api/#sessions # https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.secret_key app.secret_key = _load_secret_key(app.bot_user.id, app.streamer.id) app.bot_dev = "flags" in config and "dev" in config["flags"] and config[ "flags"]["dev"] == "1" DBManager.init(config["main"]["db"]) app.module_manager = ModuleManager(None).load() pajbot.web.routes.admin.init(app) pajbot.web.routes.api.init(app) pajbot.web.routes.base.init(app) # Make a CSRF exemption for the /api/v1/banphrases/test endpoint csrf.exempt("pajbot.web.routes.api.banphrases.apibanphrasetest") pajbot.web.common.filters.init(app) pajbot.web.common.assets.init(app) pajbot.web.common.menu.init(app) app.register_blueprint(pajbot.web.routes.clr.page) errors.init(app, config) pajbot.web.routes.clr.config = config version = VERSION last_commit = None if app.bot_dev: version = extend_version_if_possible(VERSION) try: last_commit = subprocess.check_output( ["git", "log", "-1", "--format=%cd"]).decode("utf8").strip() except: log.exception( "Failed to get last_commit, will not show last commit") default_variables = { "version": version, "last_commit": last_commit, "bot": { "name": app.bot_user.login }, "site": { "domain": config["web"]["domain"], "deck_tab_images": cfg.get_boolean(config["web"], "deck_tab_images", False), "websocket": { "host": config["websocket"].get( "host", f"wss://{config['web']['domain']}/clrsocket") }, }, "streamer": { "name": app.streamer_display, "full_name": app.streamer.login, "id": app.streamer.id }, "modules": app.bot_modules, "request": request, "session": session, "google_analytics": config["web"].get("google_analytics", None), } @app.context_processor def current_time(): current_time = {} current_time["current_time"] = pajbot.utils.now() return current_time @app.context_processor def inject_default_variables(): return default_variables
def command_update(command_id, **options): if not request.method == 'POST': return make_response(jsonify({'error': 'Invalid request method. (Expected POST)'}), 400) if len(request.form) == 0: return make_response(jsonify({'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 make_response(jsonify({'error': 'Invalid command ID'}), 404) if command.level > options['user'].level: abort(403) parsed_action = json.loads(command.action_json) options = { 'edited_by': options['user'].id, } for key in request.form: if key.startswith('data_'): name = key[5:] value = request.form[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 command.set(**options) command.data.set(**options) if SocketClientManager.send('command.update', {'command_id': command_id}) is True: return make_response(jsonify({'success': 'good job'})) else: return make_response(jsonify({'error': 'Could not push update'}))
def banphrases_create(**options): session.pop("banphrase_created_id", None) session.pop("banphrase_edited_id", None) if request.method == "POST": id = None try: if "id" in request.form: id = int(request.form["id"]) name = request.form["name"].strip() permanent = request.form.get("permanent", "off") warning = request.form.get("warning", "off") notify = request.form.get("notify", "off") case_sensitive = request.form.get("case_sensitive", "off") sub_immunity = request.form.get("sub_immunity", "off") remove_accents = request.form.get("remove_accents", "off") length = int(request.form["length"]) phrase = request.form["phrase"] operator = request.form["operator"].strip().lower() except (KeyError, ValueError): abort(403) permanent = permanent == "on" warning = warning == "on" notify = notify == "on" case_sensitive = case_sensitive == "on" sub_immunity = sub_immunity == "on" remove_accents = remove_accents == "on" if not name: abort(403) if not phrase: abort(403) if length < 0 or length > 1209600: abort(403) valid_operators = [ "contains", "startswith", "endswith", "exact", "regex" ] if operator not in valid_operators: abort(403) user = options.get("user", None) if user is None: abort(403) options = { "name": name, "phrase": phrase, "permanent": permanent, "warning": warning, "notify": notify, "case_sensitive": case_sensitive, "sub_immunity": sub_immunity, "remove_accents": remove_accents, "length": length, "added_by": user.id, "edited_by": user.id, "operator": operator, } if id is None: banphrase = Banphrase(**options) banphrase.data = BanphraseData(banphrase.id, added_by=options["added_by"]) with DBManager.create_session_scope( expire_on_commit=False) as db_session: if id is not None: banphrase = (db_session.query(Banphrase).options( joinedload( Banphrase.data)).filter_by(id=id).one_or_none()) if banphrase is None: return redirect("/admin/banphrases/", 303) banphrase.set(**options) banphrase.data.set(edited_by=options["edited_by"]) log.info( f"Updated banphrase ID {banphrase.id} by user ID {options['edited_by']}" ) AdminLogManager.post("Banphrase edited", user, banphrase.id, banphrase.phrase) else: db_session.add(banphrase) db_session.add(banphrase.data) db_session.flush() log.info( f"Added a new banphrase by user ID {options['added_by']}" ) AdminLogManager.post("Banphrase added", user, banphrase.id, banphrase.phrase) SocketClientManager.send("banphrase.update", {"id": banphrase.id}) if id is None: session["banphrase_created_id"] = banphrase.id else: session["banphrase_edited_id"] = banphrase.id return redirect("/admin/banphrases/", 303) else: return render_template("admin/create_banphrase.html")
def generic_toggle(route_key, row_id, **options): valid_routes = { 'timer': Timer, 'banphrase': Banphrase, 'module': Module, } route_name = { 'timer': lambda x: x.name, 'banphrase': lambda x: x.phrase, 'module': lambda x: x.id, } route_title = { 'timer': 'Timer', 'banphrase': 'Banphrase', 'module': 'Module', } route_validator = {'module': lambda x: validate_module(x.id)} if route_key not in valid_routes: return make_response(jsonify({'error': 'Invalid route.'}), 400) if 'new_state' not in request.form: return make_response( jsonify({'error': 'Missing `new_state` parameter.'}), 400) try: new_state = int(request.form['new_state']) except (ValueError, KeyError): return make_response( jsonify({'error': 'Invalid `new_state` parameter.'}), 400) route_value = valid_routes[route_key] with DBManager.create_session_scope() as db_session: row = db_session.query(route_value).filter_by(id=row_id).one_or_none() if row: validator = route_validator.get(route_key, None) if validator is not None: res = validator(row) if not res: return make_response( jsonify( {'error': 'cannot modify {}'.format(route_key)}), 400) row.enabled = True if new_state == 1 else False db_session.commit() payload = { '{}_id'.format(route_key): row.id, # remove this 'id': row.id, 'new_state': row.enabled, } AdminLogManager.post( '{title} toggled'.format(title=route_title[route_key]), options['user'], 'Enabled' if row.enabled else 'Disabled', route_name[route_key](row)) SocketClientManager.send('{}.update'.format(route_key), payload) return make_response( jsonify({ 'success': 'successful toggle', 'new_state': new_state })) else: return make_response( jsonify({'error': 'invalid {} id'.format(route_key)}))