diff --git a/api/api.py b/api/api.py deleted file mode 100644 index a39ab2ee..00000000 --- a/api/api.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -import json -import os -from bottle import route, run, hook, response, request, error - -import api_funct -import app.modules.db.user as user_sql -import app.modules.roxywi.common as roxywi_common - -_error_auth = '403 Auth before' -_allow_origin = '*' -_allow_methods = 'PUT, GET, POST, DELETE, OPTIONS' -_allow_headers = 'Authorization, Origin, Accept, Content-Type, X-Requested-With' - - -@hook('before_request') -def check_login(required_service=0): - return api_funct.check_login(required_service=required_service) - - -@hook('after_request') -def enable_cors(): - response.headers['Access-Control-Allow-Origin'] = _allow_origin - response.headers['Access-Control-Allow-Methods'] = _allow_methods - response.headers['Access-Control-Allow-Headers'] = _allow_headers - - -@error(500) -def error_handler_500(error): - return json.dumps({"status": "error", "message": str(error.exception)}) - - -@route('/', method=['GET', 'POST']) -@route('/help', method=['GET', 'POST']) -def index(): - if not check_login(required_service=1): - return dict(error=_error_auth) - - data = { - 'help': 'show all available endpoints', - 'login': 'get temporarily token. Must be JSON body: login, password and group for which getting token. METHOD: POST', - 'user': 'show info about all users inside a group. METHOD: GET', - 'user': 'create a new user inside a group. Must be JSON body: username, email, password, role. METHOD: POST', - 'server': 'show info about all servers. METHOD: GET', - 'server': 'create a new server inside a group. Must be JSON body: hostname, ip, port, virt: enter 0 if is not Virtual IP, group_id, master_id: enter 0 if is not slave, cred_id, description. METHOD: POST', - 'server/ssh': 'show info about all SSH credentials inside a group. METHOD: GET', - 'server/ssh': 'create a new SSH credentials inside a group. Must be JSON body: name, key_enabled, username, password. METHOD: POST', - 'server/ssh/key': 'upload a new SSH key inside a group. Must be JSON body: name, key, passphrase (could be empty). Name it is credentials name, in key new lines must be replaced with "\n" METHOD: POST', - 'servers/status': 'show status all HAProxyes. METHOD: GET', - 'haproxy/': 'show info about the HAProxy by id or hostname or ip. METHOD: GET', - 'haproxy//status': 'show HAProxy status by id or hostname or ip. METHOD: GET', - 'haproxy//runtime': 'exec HAProxy runtime commands by id or hostname or ip. Must be JSON body: "command". METHOD: POST', - 'haproxy//backends': 'show backends by id or hostname or ip. METHOD: GET', - 'haproxy//action/start': 'start HAProxy service by id or hostname or ip. METHOD: GET', - 'haproxy//action/stop': 'stop HAProxy service by id or hostname or ip. METHOD: GET', - 'haproxy//action/restart': 'restart HAProxy service by id or hostname or ip. METHOD: GET', - 'haproxy//config': 'get HAProxy config from a server by id or hostname or ip. METHOD: GET', - 'haproxy//config': 'upload HAProxy config to a server by id or hostname or ip. Headers: action: save/reload/restart. Body must consist a whole HAProxy config. METHOD: POST', - 'haproxy//log': 'show HAProxy logs by id or hostname or ip. May to have config next Headers: rows(format INT) default: 10 grep, waf(if needs WAF log) default: 0, start_hour(format: 24) default: 00, start_minute, end_hour(format: 24) default: 24, end_minute. METHOD: GET', - 'haproxy//section': 'show a certain section, headers: section-name. METHOD: GET', - 'haproxy//section/add': 'add a section to the HAProxy config by id or hostname or ip. Has to have config header with section and action header for action after upload. Section header must consist type: listen, frontend, etc. Action header accepts next value: save, test, reload and restart. Can be empty for just save. METHOD: POST', - 'haproxy//section/edit': 'edit a section in the HAProxy config by id or hostname or ip. Has to have config header section-name, action header for action after upload and body of a new section configuration. Section header must consist type: listen, frontend, etc. Action header accepts next value: save, test, reload and restart. Can be empty for just save. METHOD: POST', - 'haproxy//section/delete': 'delete a section in the HAProxy config by id or hostname or ip. Has to have config header section-name, action header for action after upload and body of a new section configuration. Section header must consist type: listen, frontend, etc. Action header accepts next value: save, test, reload and restart. Can be empty for just save. METHOD: POST', - 'haproxy//acl': 'add an acl to certain section. Must be JSON body: "section-name", "if", "then", "if_value", "then_value" and "action" for action after upload. Action accepts next value: "save", "test", "reload" and "restart". METHOD: POST', - 'haproxy//acl': 'delete an acl to certain section. Must be JSON body: "section-name", "if", "then", "if_value", "then_value" and "action" for action after upload. Action accepts next value: "save", "test", "reload" and "restart". METHOD: DELETE', - 'nginx/': 'show info about the NGINX by id or hostname or ip. METHOD: GET', - 'nginx//status': 'show NGINX status by id or hostname or ip. METHOD: GET', - 'nginx//action/start': 'start NGINX service by id or hostname or ip. METHOD: GET', - 'nginx//action/stop': 'stop NGINX service by id or hostname or ip. METHOD: GET', - 'nginx//action/restart': 'restart NGINX service by id or hostname or ip. METHOD: GET', - 'nginx//config': 'get NGINX config from a server by id or hostname or ip. Headers: The full path to a config file, like: /etc/nginx/conf.d/default.conf. METHOD: GET', - 'nginx//config': 'upload NGINX config to a server by id or hostname or ip. Headers: action: save/reload/restart, config-file: the full path to the config, like /etc/nginx/conf.d/example.com.conf. Body must consist a whole NGINX config. METHOD: POST', - 'apache/': 'show info about the Apache by id or hostname or ip. METHOD: GET', - 'apache//status': 'show Apache status by id or hostname or ip. METHOD: GET', - 'apache//action/start': 'start Apache service by id or hostname or ip. METHOD: GET', - 'apache//action/stop': 'stop Apache service by id or hostname or ip. METHOD: GET', - 'apache//action/restart': 'restart Apache service by id or hostname or ip. METHOD: GET', - 'apache//config': 'get Apache config from a server by id or hostname or ip. Headers: The full path to a config file, like: /etc/httpd/conf.d/default.conf. METHOD: GET', - 'apache//config': 'upload Apache config to a server by id or hostname or ip. Headers: action: save/reload/restart, config-file: the full path to the config, like /etc/httpd/conf.d/example.com.conf. Body must consist a whole Apache config. METHOD: POST', - 'keepalived/': 'show info about the Keepalived by id or hostname or ip. METHOD: GET', - 'keepalived//status': 'show Keepalived status by id or hostname or ip. METHOD: GET', - 'keepalived//action/start': 'start Keepalived service by id or hostname or ip. METHOD: GET', - 'keepalived//action/stop': 'stop Keepalived service by id or hostname or ip. METHOD: GET', - 'keepalived//action/restart': 'restart Keepalived service by id or hostname or ip. METHOD: GET', - 'keepalived//config': 'get Keepalived config from a server by id or hostname or ip. METHOD: GET', - 'keepalived//config': 'upload Keepalived config to a server by id or hostname or ip. Headers: action: save/reload/restart. Body must consist a whole Keepalived config. METHOD: POST', - 'ha': 'HA clusters list. METHOD: GET', - 'ha': 'Create HA cluster. Body must be JSON: name: str, desc: str, cluster_id: 0, router_id: "", vip: str, servers: {server_id: dict:{eth: str, ip: str, name: str, master: int}}, service: dict: {{haproxy: int, docker: int}, {nginx: int, docker: int}}, virt_server: int, syn_flood: int, return_to_master: int, use_src: int. METHOD: POST', - 'ha': 'Edit HA cluster. Body must be JSON: name: str, desc: str, cluster_id: int, router_id: "", vip: str, servers: {server_id: dict:{eth: str, ip: str, name: str, master: int}}, service: dict: {{haproxy: int, docker: int}, {nginx: int, docker: int}}, virt_server: int, syn_flood: int, return_to_master: int, use_src: int. METHOD: PUT', - 'ha': 'Delete HA cluster. Body must be JSON: cluster_id: int. METHOD: DELETE', - } - return dict(help=data) - - -@route('/login', method=['POST']) -def get_token(): - token = api_funct.get_token() - return dict(token=token) - - -@route('/server', method=['GET']) -def get_servers(): - if not check_login(): - return dict(error=_error_auth) - data = {} - try: - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - servers = roxywi_common.get_dick_permit(username=login, group_id=group_id, token=token) - - for s in servers: - data[s[0]] = { - 'server_id': s[0], - 'hostname': s[1], - 'ip': s[2], - 'group': s[3], - 'virt': s[4], - 'enable': s[5], - 'is_master': s[6], - 'creds': s[7], - 'alert': s[8], - 'metrics': s[9] - } - except Exception as e: - data = {'error': e} - - return dict(servers=data) - - -@route('/server', method=['POST']) -def show_servers(): - if not check_login(): - return dict(error=_error_auth) - return api_funct.create_server() - - -@route('/user', method=['GET']) -def show_users(): - if not check_login(): - return dict(error=_error_auth) - return api_funct.user_list() - - -@route('/user', method=['POST']) -def create_user(): - if not check_login(): - return dict(error=_error_auth) - return api_funct.create_user() - - -@route('/server/ssh', method=['GET']) -def show_ssh(): - if not check_login(): - return dict(error=_error_auth) - return api_funct.ssh_list() - - -@route('/server/ssh', method=['POST']) -def create_ssh(): - if not check_login(): - return dict(error=_error_auth) - return api_funct.create_ssh() - - -@route('/server/ssh/key', method=['POST']) -def upload_ssh_key(): - if not check_login(): - return dict(error=_error_auth) - return api_funct.upload_ssh_key() - - -@route('/servers/status', method=['GET']) -def servers_status(): - if not check_login(): - return dict(error=_error_auth) - return api_funct.get_all_statuses() - - -@route('/haproxy//runtime', method=['POST']) -@route('/haproxy//runtime', method=['POST']) -def haproxy_runtime(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.runtime(haproxy_id) - - -@route('/haproxy//backends', method=['GET']) -@route('/haproxy//backends', method=['GET']) -def haproxy_backends(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.show_backends(haproxy_id) - - -@route('/haproxy//log', method=['GET']) -@route('/haproxy//log', method=['GET']) -def haproxy_log(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.show_log(haproxy_id) - - -@route('/haproxy//section', method=['GET']) -def get_section(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.get_section(haproxy_id) - - -@route('/haproxy//section/add', method=['POST']) -@route('/haproxy//section/add', method=['POST']) -def haproxy_section_add(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.add_to_config(haproxy_id) - - -@route('/haproxy//section/delete', method=['POST']) -@route('/haproxy//section/delete', method=['POST']) -def haproxy_section_delete(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.edit_section(haproxy_id, delete=1) - - -@route('/haproxy//section/edit', method=['POST']) -@route('/haproxy//section/edit', method=['POST']) -def haproxy_sectiond_edit(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.edit_section(haproxy_id) - - -@route('/haproxy//acl', method=['POST']) -def add_acl(haproxy_id): - if not check_login(required_service=1): - return dict(error=_error_auth) - return api_funct.add_acl(haproxy_id) - - -@route('/ha', method=['GET', 'POST', 'PUT', 'DELETE']) -def create_ha(): - if not check_login(required_service=5): - return dict(error=_error_auth) - if request.method == 'POST': - return api_funct.create_ha_cluster() - elif request.method == 'PUT': - return api_funct.update_cluster() - elif request.method == 'DELETE': - return api_funct.delete_ha_cluster() - elif request.method == 'GET': - return api_funct.cluster_list() - - -@route('//', method=['GET']) -@route('//', method=['GET']) -def callback(server_id, service): - required_service = api_funct.return_requred_serivce(service) - if not check_login(required_service=required_service): - return dict(error=_error_auth) - return api_funct.get_server(server_id, service) - - -@route('///status', method=['GET']) -@route('///status', method=['GET']) -def service_status(server_id, service): - required_service = api_funct.return_requred_serivce(service) - if not check_login(required_service=required_service): - return dict(error=_error_auth) - return api_funct.get_status(server_id, service) - - -@route('///action/', method=['GET']) -@route('///action/', method=['GET']) -def service_action(server_id, action, service): - required_service = api_funct.return_requred_serivce(service) - if not check_login(required_service=required_service): - return dict(error=_error_auth) - return api_funct.actions(server_id, action, service) - - -@route('///config', method=['GET']) -@route('///config', method=['GET']) -def service_config_show(server_id, service): - required_service = api_funct.return_requred_serivce(service) - if not check_login(required_service=required_service): - return dict(error=_error_auth) - config_path = request.headers.get('config-file') - return api_funct.get_config(server_id, service=service, config_path=config_path) - - -@route('///config', method=['POST']) -@route('///config', method=['POST']) -def service_config_edit(server_id, service): - required_service = api_funct.return_requred_serivce(service) - if not check_login(required_service=required_service): - return dict(error=_error_auth) - config_path = request.headers.get('config-file') - return api_funct.upload_config(server_id, service=service, config_path=config_path) - - -if __name__ == '__main__': - port = int(os.environ.get('PORT', 8080)) - run(host='0.0.0.0', port=port, debug=True) diff --git a/api/api_funct.py b/api/api_funct.py deleted file mode 100644 index 3ab8f6bb..00000000 --- a/api/api_funct.py +++ /dev/null @@ -1,933 +0,0 @@ -import os -import sys -import json - -from bottle import request -sys.path.append(os.path.join(sys.path[0], '/var/www/haproxy-wi/')) - -import app.modules.db.sql as sql -import app.modules.db.cred as cred_sql -import app.modules.db.user as user_sql -import app.modules.db.group as group_sql -import app.modules.db.server as server_sql -import app.modules.db.ha_cluster as ha_sql -import app.modules.server.ssh as ssh_mod -import app.modules.server.server as server_mod -import app.modules.config.section as section_mod -import app.modules.config.config as config_mod -import app.modules.config.runtime as runtime_mod -import app.modules.roxy_wi_tools as roxy_wi_tools -import app.modules.roxywi.logs as roxywi_logs -import app.modules.roxywi.user as roxywi_user -import app.modules.roxywi.common as roxywi_common -import app.modules.service.common as service_common -import app.modules.service.installation as service_mod -import app.modules.service.ha_cluster as ha_cluster - -get_config_var = roxy_wi_tools.GetConfigVar() - - -def get_token(): - try: - user_subscription = roxywi_common.return_user_status() - except Exception as e: - user_subscription = roxywi_common.return_unsubscribed_user_status() - roxywi_common.logging('Roxy-WI server', f'Cannot get a user plan: {e}', roxywi=1) - - if user_subscription['user_status'] == 0: - roxywi_common.logging('API', 'You are not subscribed. Please subscribe to have access to this feature.', roxywi=1) - return False - elif user_subscription['user_plan'] == 'user': - roxywi_common.logging('API', 'This feature is not available for your plan.', roxywi=1) - return False - - try: - body = request.body.getvalue().decode('utf-8') - login_pass = json.loads(body) - login = login_pass['login'] - password_from_user = login_pass['password'] - except Exception as e: - return f'error getting credentials: {e}' - try: - group_name = login_pass['group'] - group_id = group_sql.get_group_id_by_name(group_name) - except Exception as e: - return f'error getting group: {e}' - try: - user = user_sql.get_user_id_by_username(login) - password = roxy_wi_tools.Tools.get_hash(password_from_user) - except Exception as e: - return f'error one more: {e}' - - if user.activeuser == 0: - return False - if login in user.username and password == user.password: - import uuid - user_token = str(uuid.uuid4()) - role_id = user_sql.get_role_id(user.user_id, group_id) - user_sql.write_api_token(user_token, group_id, role_id, user.username) - return user_token - else: - return False - - -def check_login(required_service=0) -> bool: - try: - user_subscription = roxywi_common.return_user_status() - except Exception as e: - user_subscription = roxywi_common.return_unsubscribed_user_status() - roxywi_common.logging('Roxy-WI server', f'Cannot get a user plan: {e}', roxywi=1) - - if user_subscription['user_status'] == 0: - roxywi_common.logging('API', 'You are not subscribed. Please subscribe to have access to this feature.', roxywi=1) - return False - elif user_subscription['user_plan'] == 'user': - roxywi_common.logging('API', 'This feature is not available for your plan.', roxywi=1) - return False - - token = request.headers.get('token') - if user_sql.get_api_token(token): - if required_service != 0: - user_id = user_sql.get_user_id_by_api_token(token) - try: - user_services = user_sql.select_user_services(user_id) - except Exception: - return False - - if str(required_service) in user_services: - return True - else: - return False - - else: - return True - else: - return False - - -def return_dict_from_out(server_id, out): - data = {server_id: {}} - for k in out: - if "Ncat:" not in k: - k = k.split(':') - data[server_id][k[0]] = k[1].strip() - else: - data[server_id] = {"error": "Cannot connect to HAProxy"} - - return data - - -def check_permit_to_server(server_id, service='haproxy'): - servers = server_sql.select_servers(id_hostname=server_id) - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - - try: - for s in servers: - server = roxywi_common.get_dick_permit(username=login, group_id=group_id, ip=s[2], token=token, service=service) - except Exception as e: - raise Exception(f'error: {e}') - - return server - - -def return_requred_serivce(service): - if service == 'haproxy': - required_service = 1 - elif service == 'nginx': - required_service = 2 - elif service == 'apache': - required_service = 4 - elif service == 'keepalived': - required_service = 3 - else: - required_service = 0 - - return required_service - - -def get_server(server_id, service): - if service != 'apache' and service != 'nginx' and service != 'haproxy' and service != 'keepalived': - return dict(status='wrong service') - data = {} - try: - servers = check_permit_to_server(server_id, service=service) - - for s in servers: - data = { - 'server_id': s[0], - 'hostname': s[1], - 'ip': s[2], - 'group': s[3], - 'virt': s[4], - 'enable': s[5], - 'master': s[6], - 'creds': s[7] - } - except Exception as e: - data = {server_id: {"error": f"{e}"}} - return dict(error=data) - - return dict(server=data) - - -def get_status(server_id, service): - if service not in ('apache', 'nginx', 'haproxy', 'keepalived'): - return dict(status='wrong service') - try: - servers = check_permit_to_server(server_id, service=service) - - for s in servers: - if service == 'haproxy': - cmd = 'echo "show info" |nc %s %s -w 1|grep -e "Ver\|CurrConns\|Maxco\|MB\|Uptime:"' % (s[2], sql.get_setting('haproxy_sock_port')) - out = server_mod.subprocess_execute(cmd) - data = return_dict_from_out(server_id, out[0]) - elif service == 'nginx': - cmd = "/usr/sbin/nginx -v 2>&1|awk '{print $3}' && systemctl status nginx |grep -e 'Active'|awk '{print $2, $9$10$11$12$13}' && ps ax |grep nginx:|grep -v grep |wc -l" - try: - out = server_mod.ssh_command(s[2], cmd) - out1 = out.split() - json_for_sending = {server_id: {"Version": out1[0].split('/')[1], "Uptime": out1[2], "Process": out1[3]}} - data = json_for_sending - except Exception as e: - data = {server_id: {"error": "Cannot get status: " + str(e)}} - elif service == 'apache': - apache_stats_user = sql.get_setting('apache_stats_user') - apache_stats_password = sql.get_setting('apache_stats_password') - apache_stats_port = sql.get_setting('apache_stats_port') - apache_stats_page = sql.get_setting('apache_stats_page') - cmd = "curl -s -u %s:%s http://%s:%s/%s?auto |grep 'ServerVersion\|Processes\|ServerUptime:'" % \ - (apache_stats_user, apache_stats_password, s[2], apache_stats_port, apache_stats_page) - servers_with_status = list() - try: - out = server_mod.subprocess_execute(cmd) - if out != '': - for k in out: - servers_with_status.append(k) - json_for_sending = { - server_id: { - "Version": servers_with_status[0][0].split('/')[1], - "Uptime": servers_with_status[0][1].split(':')[1].strip(), - "Process": servers_with_status[0][2].split(' ')[1] - } - } - data = json_for_sending - except Exception as e: - data = {server_id: {"error": "Cannot get status: " + str(e)}} - - except Exception: - data = {server_id: {"error": "Cannot find the server"}} - return dict(error=data) - - return dict(status=data) - - -def get_all_statuses(): - data = {} - try: - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - sock_port = sql.get_setting('haproxy_sock_port') - except Exception as e: - data = {"error": f"Cannot parameters: {e}"} - return dict(error=data) - try: - servers = roxywi_common.get_dick_permit(username=login, group_id=group_id, token=token) - except Exception as e: - data = {"error": f"Cannot get the server: {e}"} - return dict(error=data) - try: - for s in servers: - cmd = 'echo "show info" |nc %s %s -w 1|grep -e "Ver\|CurrConns\|Maxco\|MB\|Uptime:"' % (s[2], sock_port) - data[s[2]] = {} - out = server_mod.subprocess_execute(cmd) - data[s[2]] = return_dict_from_out(s[1], out[0]) - except Exception as e: - data = {"error": f"Cannot find the server: {e}"} - return dict(error=data) - - return dict(status=data) - - -def actions(server_id, action, service): - if action not in ('start', 'stop', 'restart', 'reload'): - return dict(status='wrong action') - if service not in ('apache', 'nginx', 'haproxy', 'keepalived'): - return dict(status='wrong service') - - try: - servers = check_permit_to_server(server_id, service=service) - - for s in servers: - if service == 'apache': - service = service_common.get_correct_apache_service_name(server_ip=s[2]) - cmd = "sudo systemctl %s %s" % (action, service) - error = server_mod.ssh_command(s[2], cmd) - done = error if error else 'done' - data = {'server_id': s[0], 'ip': s[2], 'action': action, 'hostname': s[1], 'status': done} - - return dict(status=data) - except Exception as e: - return dict(status=str(e)) - - -def runtime(server_id): - try: - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - action = json_loads['command'] - haproxy_sock = sql.get_setting('haproxy_sock') - servers = check_permit_to_server(server_id) - cmd = 'echo "%s" |sudo socat stdio %s' % (action, haproxy_sock) - - for s in servers: - out = server_mod.ssh_command(s[2], cmd) - - sep_data = out.split('\r\n') - data = {server_id: sep_data} - - return dict(status=data) - except Exception: - return dict(status='error') - - -def show_backends(server_id): - try: - servers = check_permit_to_server(server_id) - - for s in servers: - out = runtime_mod.show_backends(s[2], ret=1) - - data = {server_id: out} - - except Exception: - data = {server_id: {"error": "Cannot find the server"}} - return dict(error=data) - - return dict(backends=data) - - -def get_config(server_id, **kwargs): - service = kwargs.get('service') - if service not in ('apache', 'nginx', 'haproxy', 'keepalived'): - return dict(status='wrong service') - - try: - servers = check_permit_to_server(server_id, service=service) - except Exception as e: - data = {server_id: {"error": f"Cannot find the server {e}"}} - return dict(error=data) - - for s in servers: - server_ip = s[2] - - try: - cfg = f'/tmp/{server_ip}.cfg' - except Exception as e: - data = {server_id: {"error": f"Cannot find the server with the service {service}: {e}"}} - return dict(error=data) - try: - config_mod.get_config(server_ip, cfg, service=service, config_file_name=kwargs.get('config_path')) - except Exception as e: - data = {server_id: {"error": f"Cannot get config {e}"}} - return dict(error=data) - try: - os.system("sed -i 's/\\n/\n/g' " + cfg) - except Exception as e: - data = {server_id: {"error": f"Cannot edit config {e}"}} - return dict(error=data) - try: - conf = open(cfg, "r") - config_read = conf.read() - conf.close() - except IOError as e: - data = {server_id: {"error": f"Cannot read config {e}"}} - return dict(error=data) - - data = {server_id: config_read} - - return dict(config=data) - - -def get_section(server_id): - section_name = request.headers.get('section-name') - servers = check_permit_to_server(server_id) - for s in servers: - cfg = '/tmp/' + s[2] + '.cfg' - - config_mod.get_config(s[2], cfg) - start_line, end_line, config_read = section_mod.get_section_from_config(cfg, section_name) - - data = {server_id: {section_name: {'start_line': start_line, 'end_line': end_line, 'config_read': config_read}}} - return dict(section=data) - - -def edit_section(server_id, delete=0): - body = request.body.getvalue().decode('utf-8') - section_name = request.headers.get('section-name') - save = request.headers.get('action') - token = request.headers.get('token') - servers = check_permit_to_server(server_id) - hap_configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - - if save == '': - save = 'save' - elif save == 'restart': - save = '' - elif save == 'reload': - save = 'reload' - - if delete == 1: - body = '' - action = 'deleted' - else: - action = 'edited' - - for s in servers: - ip = s[2] - cfg = f'/tmp/{ip}.cfg' - - out = config_mod.get_config(ip, cfg) - start_line, end_line, config_read = section_mod.get_section_from_config(cfg, section_name) - returned_config = section_mod.rewrite_section(start_line, end_line, cfg, body) - time_zone = sql.get_setting('time_zone') - get_date = roxy_wi_tools.GetDate(time_zone) - cur_date = get_date.return_date('config') - - try: - cfg_for_save = f'{hap_configs_dir}{ip}-{cur_date}.cfg' - - try: - with open(cfg, "w") as conf: - conf.write(returned_config) - return_mess = 'section has been updated' - os.system(f"/bin/cp {cfg} {cfg_for_save}") - out = config_mod.master_slave_upload_and_restart(ip, cfg, save, login=login) - roxywi_common.logging('localhost', f" section {section_name} has been {action} via API", login=login) - roxywi_common.logging( - ip, f'Section {section_name} has been {action} via API', roxywi=1, - login=login, keep_history=1, service='haproxy' - ) - - if out: - return_mess = out - except IOError: - return_mess = "cannot upload config" - - data = {server_id: return_mess} - except Exception as e: - data = {server_id: {"error": str(e)}} - return dict(error=data) - - return dict(config=data) - - -def upload_config(server_id, **kwargs): - service = kwargs.get('service') - if service not in ('apache', 'nginx', 'haproxy', 'keepalived'): - return dict(status='wrong service') - - body = request.body.getvalue().decode('utf-8') - save = request.headers.get('action') - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - nginx = '' - apache = '' - - if service == 'nginx': - configs_dir = get_config_var.get_config_var('configs', 'nginx_save_configs_dir') - service_name = 'Apache' - nginx = 1 - elif service == 'apache': - configs_dir = get_config_var.get_config_var('configs', 'apache_save_configs_dir') - service_name = 'NGINX' - apache = 1 - else: - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - service_name = 'HAProxy' - - if save == '': - save = 'save' - elif save == 'restart': - save = '' - elif save == 'reload': - save = 'reload' - - try: - servers = check_permit_to_server(server_id) - - for s in servers: - ip = s[2] - cfg = f'/tmp/{ip}.cfg' - time_zone = sql.get_setting('time_zone') - get_date = roxy_wi_tools.GetDate(time_zone) - cur_date = get_date.return_date('config') - cfg_for_save = f'{configs_dir}{ip}-{cur_date}.cfg' - - try: - with open(cfg, "w") as conf: - conf.write(body) - return_mess = 'config has been uploaded' - os.system("/bin/cp %s %s" % (cfg, cfg_for_save)) - - if kwargs.get('service') == 'nginx': - out = config_mod.master_slave_upload_and_restart(ip, cfg, save, login=login, nginx=nginx, config_file_name=kwargs.get('config_path')) - elif kwargs.get('service') == 'apache': - out = config_mod.master_slave_upload_and_restart(ip, cfg, save, login=login, apache=apache, config_file_name=kwargs.get('config_path')) - else: - out = config_mod.master_slave_upload_and_restart(ip, cfg, save, login=login) - - roxywi_common.logging('localhost', " config has been uploaded via API", login=login) - roxywi_common.logging( - ip, 'Config has been uploaded via API', roxywi=1, login=login, keep_history=1, service=service_name - ) - - if out: - return_mess = out - except IOError as e: - return_mess = f"cannot upload config {e}" - - data = {server_id: return_mess} - except Exception as e: - data = {server_id: {"error": str(e)}} - return dict(error=data) - - return dict(config=data) - - -def add_to_config(server_id): - data = {} - body = request.body.getvalue().decode('utf-8') - save = request.headers.get('action') - hap_configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - time_zone = sql.get_setting('time_zone') - get_date = roxy_wi_tools.GetDate(time_zone) - - if save == '': - save = 'save' - elif save == 'restart': - save = '' - - try: - servers = check_permit_to_server(server_id) - - for s in servers: - ip = s[2] - cfg = f'/tmp/{ip}.cfg' - cur_date = get_date.return_date('config') - cfg_for_save = f'{hap_configs_dir}{ip}-{cur_date}.cfg' - out = config_mod.get_config(ip, cfg) - try: - with open(cfg, "a") as conf: - conf.write('\n' + body + '\n') - - return_mess = 'section has been added to the config' - os.system(f"/bin/cp {cfg} {cfg_for_save}") - roxywi_common.logging('localhost', " section has been added via REST API", login=login) - out = config_mod.upload_and_restart(ip, cfg, just_save=save) - - if out: - return_mess = out - except IOError: - return_mess = "cannot upload config" - - data = {server_id: return_mess} - except Exception: - data[server_id] = {"error": "cannot find the server"} - return dict(error=data) - - return dict(config=data) - - -def show_log(server_id): - data = {} - rows = request.headers.get('rows') - waf = request.headers.get('waf') - grep = request.headers.get('grep') - hour = request.headers.get('start_hour') - minute = request.headers.get('start_minute') - hour1 = request.headers.get('end_hour') - minute1 = request.headers.get('end_minute') - - if rows is None: - rows = '10' - if waf is None: - waf = '0' - if hour is None: - hour = '00' - if minute is None: - minute = '00' - if hour1 is None: - hour1 = '24' - if minute1 is None: - minute1 = '00' - - try: - servers = check_permit_to_server(server_id) - - for s in servers: - ip = s[2] - except Exception: - - data[server_id] = {"error": "Cannot find the server"} - return dict(error=data) - - out = roxywi_logs.show_roxy_log(ip, rows=rows, waf=str(waf), grep=grep, hour=str(hour), minut=str(minute), hour1=str(hour1), minut1=str(minute1), html=0) - data = {server_id: out} - - return dict(log=data) - - -def add_acl(server_id): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - save = json_loads['action'] - section_name = json_loads['section-name'] - - acl = generate_acl(with_newline=1) - servers = check_permit_to_server(server_id) - status = '' - - for s in servers: - cfg = '/tmp/' + s[2] + '.cfg' - server_ip = s[2] - - try: - out = config_mod.get_config(server_ip, cfg) - start_line, end_line, config_read = section_mod.get_section_from_config(cfg, section_name) - except Exception as e: - data = {server_id: {"error": f"Cannot read section: {e}"}} - return dict(error=data) - - try: - config_read += acl - config = section_mod.rewrite_section(start_line, end_line, cfg, config_read) - try: - with open(cfg, "w") as conf: - conf.write(config) - except IOError as e: - data = {server_id: {"error": f"Cannot read import config file: {e}"}} - return dict(error=data) - except Exception as e: - data = {server_id: {"error": f"{e}"}} - return dict(error=data) - - try: - out = config_mod.master_slave_upload_and_restart(server_ip, cfg, just_save=save) - if out != '': - status = out - else: - status = 'ACL has been added' - except Exception as e: - data = {server_id: {"error": f"{e}"}} - return dict(error=data) - - data = {'acl': status} - return dict(data) - - -def del_acl(server_id): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - save = json_loads['action'] - section_name = json_loads['section-name'] - acl = generate_acl() - servers = check_permit_to_server(server_id) - - for s in servers: - server_ip = s[2] - cfg = f'/tmp/{server_ip}.cfg' - try: - out = config_mod.get_config(server_ip, cfg) - start_line, end_line, config_read = section_mod.get_section_from_config(cfg, section_name) - except Exception as e: - data = {server_id: {"error": f"{e}"}} - return dict(error=data) - - try: - config_new_read = '' - for line in config_read.split('\n'): - if not line.startswith(acl): - if line != '': - config_new_read += line + '\n' - except Exception as e: - data = {server_id: {"error": f"Cannot delete ACL: {e}"}} - return dict(error=data) - - try: - config = config_mod.master_slave_upload_and_restart(start_line, end_line, cfg, config_new_read) - try: - with open(cfg, "w") as conf: - conf.write(config) - except IOError as e: - data = {server_id: {"error": f"Cannot read import config file: {e}"}} - return dict(error=data) - except Exception as e: - data = {server_id: {"error": f"Cannot delete ACL: {e}"}} - return dict(error=data) - - try: - out = config_mod.master_slave_upload_and_restart(server_ip, cfg, just_save=save) - if out != '': - status = out - else: - status = 'ACL has been deleted' - except Exception as e: - data = {server_id: {"error": f"{e}"}} - return dict(error=data) - - return dict(acl=status) - - -def generate_acl(**kwargs): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - if_value = json_loads['if_value'] - then_value = json_loads['then_value'] - if_acl = json_loads['if'] - then_acl = json_loads['then'] - acl = '' - - if if_acl == 'host_starts': - acl_if_word = 'hdr_beg(host) -i ' - elif if_acl == 'host_ends': - acl_if_word = 'hdr_end(host) -i ' - elif if_acl == 'path_starts': - acl_if_word = 'path_beg -i ' - elif if_acl == 'path_ends': - acl_if_word = 'path_end -i ' - elif if_acl == 'src_ip': - acl_if_word = 'src ip ' - else: - acl_if_word = '' - - if then_acl == 'use_backend': - acl += ' use_backend ' - elif then_acl == 'redirect': - acl += ' http-request redirect location ' - elif then_acl == 'allow': - acl += ' http-request allow' - elif then_acl == 'deny': - acl += ' http-request deny' - elif then_acl == 'return': - acl += ' return ' - elif then_acl == 'set-header': - acl += ' set-header ' - - newline = '\n' if kwargs.get('with_newline') else '' - acl += then_value + ' if { ' + acl_if_word + if_value + ' } ' + newline - - return acl - - -def user_list(): - data = {} - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - users = user_sql.select_users(by_group_id=group_id) - for user in users: - data[user.user_id] = { - 'login': user.username, - 'email': user.email, - 'role': user.role, - 'ldap': user.ldap_user, - 'enabled': user.activeuser, - 'last_login_ip': user.last_login_ip, - } - data = {'users': data} - return dict(data) - - -def create_user(): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - name = json_loads['name'] - email = json_loads['email'] - password = json_loads['password'] - role = json_loads['role'] - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - - if roxywi_user.create_user(name, email, password, role, 1, group_id, role_id=role_id, token=token): - data = {'status': 'done'} - return dict(data) - else: - data = {'status': 'something went wrong'} - return dict(data) - - -def ssh_list(): - data = {} - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - sshs = cred_sql.select_ssh(group=group_id) - for ssh in sshs: - data[ssh.id] = { - 'name': ssh.name, - 'username': ssh.username, - 'key_enabled': ssh.enable, - } - data = {'creds': data} - return dict(data) - - -def create_ssh(): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - name = json_loads['name'] - enable = json_loads['key_enabled'] - username = json_loads['username'] - password = json_loads['password'] - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - try: - ssh_mod.create_ssh_cred_api(name, enable, group_id, username, password) - data = {'status': 'done'} - except Exception as e: - data = {'status': f'error: {e}'} - return dict(data) - - -def upload_ssh_key(): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - name = json_loads['name'] - key = json_loads['key'] - passphrase = json_loads['passphrase'] - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - groups = group_sql.select_groups(id=group_id) - for group in groups: - user_group = group.name - try: - ssh_mod.upload_ssh_key(f'{name}_{user_group}', user_group, key, passphrase) - data = {'status': 'done'} - return dict(data) - except Exception as e: - data = {'status': f'{e}'} - return dict(data) - - -def create_server(): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - hostname = json_loads['hostname'] - ip = json_loads['ip'] - port = json_loads['port'] - virt = json_loads['virt'] - master_id = json_loads['master_id'] - cred_id = json_loads['cred_id'] - desc = json_loads['description'] - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - - try: - if server_mod.create_server(hostname, ip, group_id, virt, 1, master_id, cred_id, port, desc, 0, 0, 0, 0, role_id=role_id, token=token): - data = {'status': 'done'} - roxywi_common.logging(ip, f'A new server {hostname} has been created', roxywi=1, keep_history=1, service='server') - return dict(data) - except Exception as e: - data = {'status': f'error: {e}'} - return dict(data) - - -def cluster_list(): - token = request.headers.get('token') - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - clusters = ha_sql.select_clusters(group_id) - data = {} - for cluster in clusters: - data.setdefault(cluster.id, cluster.name) - - return dict(data) - - -def create_ha_cluster(): - token = request.headers.get('token') - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - data = {'status': dict()} - - try: - cluster_id = ha_cluster.create_cluster(json_loads, group_id) - except Exception as e: - data['status'] = f'error: Cannot create HA cluster: {e}' - return data['status'] - else: - data['status'].setdefault('cluster', 'done') - try: - json_loads['cluster_id'] = cluster_id - json_dump = json.dumps(json_loads) - service_mod.install_service('keepalived', json.loads(json_dump)) - except Exception as e: - data['status'].setdefault('keepalived', f'{e}') - else: - data['status'].setdefault('keepalived', 'done') - - if json_loads['services']['haproxy']['enabled']: - try: - service_mod.install_service('haproxy', json.loads(body)) - except Exception as e: - data['status'].setdefault('haproxy', f'{e}') - else: - data['status'].setdefault('haproxy', 'done') - - if json_loads['services']['nginx']['enabled']: - try: - service_mod.install_service('nginx', json.loads(body)) - except Exception as e: - data['status'].setdefault('nginx', f'{e}') - else: - data['status'].setdefault('nginx', 'done') - - return dict(data) - - -def update_cluster(): - token = request.headers.get('token') - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - login, group_id, role_id = user_sql.get_username_group_id_from_api_token(token) - data = {'status': dict()} - - try: - ha_cluster.update_cluster(json_loads, group_id) - except Exception as e: - data['status'] = f'error: Cannot create HA cluster: {e}' - return data['status'] - - if json_loads['services']['haproxy']['enabled']: - try: - service_mod.install_service('haproxy', body) - except Exception as e: - data['status'].setdefault('haproxy', f'error: {e}') - else: - data['status'].setdefault('haproxy', 'done') - - if json_loads['services']['nginx']['enabled']: - try: - service_mod.install_service('nginx', body) - except Exception as e: - data['status'].setdefault('nginx', f'error: {e}') - else: - data['status'].setdefault('nginx', 'done') - - return dict(data) - - -def delete_ha_cluster(): - body = request.body.getvalue().decode('utf-8') - json_loads = json.loads(body) - cluster_id = json_loads['cluster_id'] - data = {'status': dict()} - try: - ha_cluster.delete_cluster(cluster_id) - except Exception as e: - data['status'] = f'error: {e}' - else: - data['status'] = 'done' - return dict(data) diff --git a/api/app.wsgi b/api/app.wsgi deleted file mode 100644 index a644fc90..00000000 --- a/api/app.wsgi +++ /dev/null @@ -1,8 +0,0 @@ -import sys -import os -import bottle -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -os.chdir(os.path.dirname(os.path.abspath(__file__))) -import api - -application = bottle.default_app() \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index ac06e144..6862f7c9 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,6 +1,6 @@ from flask import Flask from flask_caching import Cache -from flask_login import LoginManager +from flask_jwt_extended import JWTManager from flask_apscheduler import APScheduler app = Flask(__name__) @@ -15,8 +15,11 @@ scheduler = APScheduler() scheduler.init_app(app) scheduler.start() -login_manager = LoginManager(app) -login_manager.login_view = 'login_page' +jwt = JWTManager(app) + +from app.api.routes import bp as api_bp + +app.register_blueprint(api_bp, url_prefix='/api') from app.routes.main import bp as main_bp from app.routes.overview import bp as overview_bp diff --git a/app/api/routes/__init__.py b/app/api/routes/__init__.py new file mode 100644 index 00000000..b108d15e --- /dev/null +++ b/app/api/routes/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('api', __name__) + +from app.api.routes import routes diff --git a/app/api/routes/routes.py b/app/api/routes/routes.py new file mode 100644 index 00000000..379760a0 --- /dev/null +++ b/app/api/routes/routes.py @@ -0,0 +1,178 @@ +from flask_swagger import swagger +from flask import jsonify, render_template, abort +from flask_pydantic import validate + +from app import app, jwt +from app.api.routes import bp +from app.views.install.views import InstallView +from app.views.server.views import ( + ServerView, CredView, CredsView, ServerGroupView, ServerGroupsView, ServersView, ServerIPView +) +from app.views.server.backup_vews import BackupView, S3BackupView +from app.views.service.views import ServiceView, ServiceActionView, ServiceBackendView, ServiceConfigView, ServiceConfigVersionsView +from app.views.ha.views import HAView, HAVIPView, HAVIPsView +from app.views.user.views import UserView, UserGroupView, UserRoles +from app.views.udp.views import UDPListener, UDPListeners, UDPListenerActionView +from app.views.channel.views import ChannelView, ChannelsView +from app.views.tools.views import CheckerView +from app.views.admin.views import SettingsView +from app.modules.roxywi.class_models import LoginRequest +import app.modules.roxywi.auth as roxywi_auth +import app.modules.roxywi.common as roxywi_common + + +@bp.before_request +def before_request(): + """ Protect all the API endpoints. """ + user_subscription = roxywi_common.return_user_subscription() + if user_subscription['user_status'] == 0 or user_subscription['user_plan'] == 'user': + abort(403, 'Your subscription is not active or you are on a Home plan.') + pass + + +@jwt.expired_token_loader +def my_expired_token_callback(jwt_header, jwt_payload): + return jsonify(error="Token is expired"), 401 + + +@jwt.unauthorized_loader +def custom_unauthorized_response(_err): + return jsonify(error="Authorize first"), 401 + + +def register_api(view, endpoint, url, pk='listener_id', pk_type='int'): + view_func = view.as_view(endpoint) + bp.add_url_rule(url, view_func=view_func, methods=['POST']) + bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'DELETE']) + + +def register_api_id_ip(view, endpoint, url: str = '', methods: list = ['GET', 'POST']): + for point in ('_id', '_ip'): + view_func = view.as_view(f'{endpoint}_{point}') + pk = 'int:' if point == '_id' else '' + bp.add_url_rule(f'/service//<{pk}server_id>{url}', view_func=view_func, methods=methods) + + +register_api(HAView, 'ha_cluster', '/ha/', 'cluster_id') +register_api(UDPListener, 'udp_listener', '//listener', 'listener_id') +bp.add_url_rule('//listener//', view_func=UDPListenerActionView.as_view('listener_action'), methods=['GET']) +bp.add_url_rule('//listeners', view_func=UDPListeners.as_view('listeners'), methods=['GET']) +bp.add_url_rule('/ha///vip/', view_func=HAVIPView.as_view('ha_vip_g'), methods=['GET']) +bp.add_url_rule('/ha///vip', view_func=HAVIPView.as_view('ha_vip'), methods=['POST', 'PUT']) +bp.add_url_rule('/ha///vip', view_func=HAVIPView.as_view('ha_vip_d'), methods=['DELETE']) +bp.add_url_rule('/ha///vips', view_func=HAVIPsView.as_view('ha_vips'), methods=['GET']) + +register_api_id_ip(ServiceView, 'service', '/status', ['GET']) +register_api_id_ip(ServiceBackendView, 'service_backend', '/backend', ['GET']) +register_api_id_ip(ServiceConfigView, 'config_view') +register_api_id_ip(ServiceConfigVersionsView, 'config_version', '/versions', methods=['GET']) +register_api_id_ip(CheckerView, 'checker', '/tools') +register_api_id_ip(InstallView, 'install', '/install', methods=['POST']) +register_api_id_ip(ServiceActionView, 'service_action', '/', methods=['GET']) + +register_api(ServerView, 'server', '/server', 'server_id') +register_api(BackupView, 'backup_fs', '/server/backup/fs', 'backup_id') +register_api(S3BackupView, 'backup_s3', '/server/backup/s3', 'backup_id') +bp.add_url_rule('/server//ip', view_func=ServerIPView.as_view('server_ip_ip'), methods=['GET']) +bp.add_url_rule('/server//ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET']) +register_api(CredView, 'cred', '/server/cred', 'creds_id') +bp.add_url_rule('/server/creds', view_func=CredsView.as_view('creds'), methods=['GET']) +bp.add_url_rule('/servers', view_func=ServersView.as_view('servers'), methods=['GET']) + +register_api(ServerGroupView, 'group', '/group', 'group_id') +bp.add_url_rule('/groups', view_func=ServerGroupsView.as_view('groups'), methods=['GET']) + + +def register_api_with_group(view, endpoint, url_beg, url_end, pk='user_id', pk_type='int', pk_end='group_id', pk_type_end='int'): + view_func = view.as_view(endpoint) + bp.add_url_rule(f'/{url_beg}/<{pk_type}:{pk}>/{url_end}', view_func=view_func, methods=['GET']) + bp.add_url_rule(f'/{url_beg}/<{pk_type}:{pk}>/{url_end}/<{pk_type_end}:{pk_end}>', view_func=view_func, methods=['PUT', 'DELETE', 'POST', 'PATCH']) + + +register_api(UserView, 'user', '/user', 'user_id') +register_api_with_group(UserGroupView, 'user_group', '/user', 'groups') +bp.add_url_rule('/user/roles', view_func=UserRoles.as_view('roles')) + +def register_api_channel(view, endpoint, url_beg, pk='receiver', pk_type='int', pk_end='channel_id', pk_type_end='int'): + view_func = view.as_view(endpoint, True) + bp.add_url_rule(f'/{url_beg}/', view_func=view_func, methods=['POST']) + bp.add_url_rule(f'/{url_beg}//<{pk_type_end}:{pk_end}>', view_func=view_func, methods=['PUT', 'DELETE', 'GET', 'PATCH']) + + +register_api_channel(ChannelView, 'channel', '/channel') +bp.add_url_rule('/channels/', view_func=ChannelsView.as_view('channels'), methods=['GET']) + + +bp.add_url_rule( + '/settings', + view_func=SettingsView.as_view('settings'), + methods=['GET'], + defaults={'section': None} +) + +bp.add_url_rule( + '/settings/', + view_func=SettingsView.as_view('settings_section'), + methods=['GET', 'POST'] +) + + +@bp.route("/spec") +def spec(): + swag = swagger(app) + swag['info']['version'] = "1.0" + swag['info']['title'] = "Roxy-WI API" + return jsonify(swag) + + +@bp.route("/swagger") +def swagger_ui(): + return render_template('swagger.html') + + +@bp.post('/login') +@validate(body=LoginRequest) +def do_login(body: LoginRequest): + """ + Do log in + --- + tags: + - Authentication + description: This route is used to log into the system + parameters: + - name: body + in: body + schema: + type: object + properties: + login: + type: string + required: true + description: The user's login name + password: + type: string + required: true + description: The user's password + responses: + 200: + description: Login successfully, return a JWT token + schema: + type: object + properties: + access_token: + type: string + description: JWT token for user authentication + 401: + description: Authentication Error + """ + try: + login = body.login + password = body.password + except Exception as e: + return roxywi_common.handler_exceptions_for_json_data(e, 'There is no login or password') + try: + user_params = roxywi_auth.check_user_password(login, password) + except Exception as e: + return roxywi_common.handle_json_exceptions(e, ''), 401 + access_token = roxywi_auth.create_jwt_token(user_params) + return jsonify(access_token=access_token) diff --git a/app/config.py b/app/config.py index 364245a0..45f196a5 100644 --- a/app/config.py +++ b/app/config.py @@ -1,7 +1,16 @@ +from datetime import timedelta + + class Configuration(object): SECRET_KEY = 'very secret salt to protect your Roxy-WI sessions' - SESSION_COOKIE_SECURE = True - SESSION_COOKIE_SAMESITE = 'strict' CACHE_TYPE = 'SimpleCache' CACHE_DEFAULT_TIMEOUT = 3000 SCHEDULER_API_ENABLED = True + JWT_ACCESS_TOKEN_EXPIRES = timedelta(days=1) + JWT_ALGORITHM = 'RS256' + JWT_PRIVATE_KEY = open('/var/lib/roxy-wi/keys/roxy-wi-key').read() + JWT_PUBLIC_KEY = open('/var/lib/roxy-wi/keys/roxy-wi-key.pub').read() + JWT_TOKEN_LOCATION = ["headers", "cookies"] + JWT_IDENTITY_CLAIM = 'user_id' + JWT_ERROR_MESSAGE_KEY = 'error' + FLASK_PYDANTIC_VALIDATION_ERROR_RAISE = True diff --git a/app/create_db.py b/app/create_db.py index 3e67b736..0578abdf 100644 --- a/app/create_db.py +++ b/app/create_db.py @@ -1,7 +1,10 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3.11 +import os +import sys import distro -from modules.db.db_model import * +sys.path.append(os.path.join(sys.path[0], '/var/www/haproxy-wi/')) +from app.modules.db.db_model import * conn = connect() @@ -101,9 +104,9 @@ def default_values(): print(str(e)) data_source = [ - {'username': 'admin', 'email': 'admin@localhost', 'password': '21232f297a57a5a743894a0e4a801fc3', 'role': '1', 'groups': '1'}, - {'username': 'editor', 'email': 'editor@localhost', 'password': '5aee9dbd2a188839105073571bee1b1f', 'role': '2', 'groups': '1'}, - {'username': 'guest', 'email': 'guest@localhost', 'password': '084e0343a0486ff05530df6c705c8bb4', 'role': '4', 'groups': '1'} + {'username': 'admin', 'email': 'admin@localhost', 'password': '21232f297a57a5a743894a0e4a801fc3', 'role': '1', 'group_id': '1'}, + {'username': 'editor', 'email': 'editor@localhost', 'password': '5aee9dbd2a188839105073571bee1b1f', 'role': '2', 'group_id': '1'}, + {'username': 'guest', 'email': 'guest@localhost', 'password': '084e0343a0486ff05530df6c705c8bb4', 'role': '4', 'group_id': '1'} ] try: @@ -458,7 +461,7 @@ def update_db_v_3_4_5_22(): def update_db_v_4_3_0(): try: UserGroups.insert_from( - User.select(User.user_id, User.groups), fields=[UserGroups.user_id, UserGroups.user_group_id] + User.select(User.user_id, User.group_id), fields=[UserGroups.user_id, UserGroups.user_group_id] ).on_conflict_ignore().execute() except Exception as e: if e.args[0] == 'duplicate column name: haproxy' or str(e) == '(1060, "Duplicate column name \'haproxy\'")': @@ -659,6 +662,37 @@ def update_db_v_7_3_1(): else: print("An error occurred:", e) +def update_db_v_7_4(): + try: + migrate( + migrator.rename_column('backups', 'cred', 'cred_id'), + migrator.rename_column('backups', 'backup_type', 'type'), + migrator.rename_column('servers', 'active', 'haproxy_active'), + migrator.rename_column('servers', 'metrics', 'haproxy_metrics'), + migrator.rename_column('servers', 'alert', 'haproxy_alert'), + migrator.rename_column('udp_balancers', 'desc', 'description'), + migrator.rename_column('ha_clusters', 'desc', 'description'), + migrator.rename_column('servers', 'desc', 'description'), + migrator.rename_column('telegram', 'groups', 'group_id'), + migrator.rename_column('slack', 'groups', 'group_id'), + migrator.rename_column('mattermost', 'groups', 'group_id'), + migrator.rename_column('pd', 'groups', 'group_id'), + migrator.rename_column('servers', 'groups', 'group_id'), + migrator.rename_column('servers', 'cred', 'cred_id'), + migrator.rename_column('servers', 'enable', 'enabled'), + migrator.rename_column('user', 'activeuser', 'enabled'), + migrator.rename_column('user', 'groups', 'group_id'), + migrator.rename_column('cred', 'enable', 'key_enabled'), + migrator.rename_column('cred', 'groups', 'group_id'), + ) + except Exception as e: + if e.args[0] == 'no such column: "cred"' or str(e) == '(1060, no such column: "cred")': + print("Updating... DB has been updated to version 7.4") + elif e.args[0] == "'bool' object has no attribute 'sql'": + print("Updating... DB has been updated to version 7.4") + else: + print("An error occurred:", e) + def update_ver(): try: @@ -693,6 +727,7 @@ def update_all(): update_db_v_7_2_0_1() update_db_v_7_2_3() update_db_v_7_3_1() + update_db_v_7_4() update_ver() diff --git a/app/jobs.py b/app/jobs.py index 4b99ffef..371fa3c6 100644 --- a/app/jobs.py +++ b/app/jobs.py @@ -39,13 +39,6 @@ def update_cur_tool_versions(): tools_common.update_cur_tool_versions() -@scheduler.task('interval', id='delete_old_uuid', minutes=60, misfire_grace_time=None) -def delete_old_uuid(): - app = scheduler.app - with app.app_context(): - user_sql.delete_old_uuid() - - @scheduler.task('interval', id='delete_action_history_for_period', minutes=70, misfire_grace_time=None) def delete_action_history_for_period(): app = scheduler.app diff --git a/app/login.py b/app/login.py index 41e54079..8576b06e 100644 --- a/app/login.py +++ b/app/login.py @@ -1,103 +1,67 @@ -from flask import render_template, request, redirect, url_for, make_response -from flask_login import login_required, logout_user, current_user, login_url +from flask import render_template, request, redirect, make_response, abort +from flask_jwt_extended import unset_jwt_cookies, jwt_required -from app import app, login_manager, cache +from app import app import app.modules.db.user as user_sql -import app.modules.roxywi.common as roxywi_common -import app.modules.roxywi.auth as roxywi_auth import app.modules.roxywi.roxy as roxy -import app.modules.roxy_wi_tools as roxy_wi_tools +import app.modules.roxywi.auth as roxywi_auth +import app.modules.roxywi.common as roxywi_common @app.before_request def check_login(): - if request.endpoint not in ( - 'login_page', 'static', 'main.show_roxywi_version', 'service.check_service', 'smon.show_smon_status_page', - 'smon.smon_history_statuses', 'smon.agent_get_checks', 'smon.get_check_status' - ): + allowed_endpoints = ( + 'login_page', 'static', 'main.show_roxywi_version', 'service.check_service', 'smon.show_smon_status_page', + 'smon.smon_history_statuses', 'smon.agent_get_checks', 'smon.get_check_status' 'api', 'favicon' + ) + if 'api' not in request.url and request.endpoint not in allowed_endpoints: try: user_params = roxywi_common.get_users_params() - except Exception: - return redirect(login_url('login_page', next_url=request.url)) + except Exception as e: + print(f'{e}') + abort(401) if not user_sql.is_user_active(user_params['user_id']): - return redirect(login_url('login_page', next_url=request.url)) + abort(401) try: - roxywi_auth.check_login(user_params['user_uuid']) + roxywi_auth.check_login(user_params['user_id']) except Exception: - return redirect(login_url('login_page', next_url=request.url)) - - -@login_manager.user_loader -def load_user(user_id): - user = f'user_{user_id}' - user_obj = cache.get(user) - - if user_obj is None: - query = user_sql.get_user_id(user_id) - cache.set(user, query, timeout=360) - return query - - return user_obj + abort(401) @app.after_request def redirect_to_login(response): - if response.status_code == 401: - return redirect(login_url('login_page', next_url=request.url)) - return response @app.route('/login', methods=['GET', 'POST']) def login_page(): - try: - roxy.update_plan() - except Exception: - pass - next_url = request.args.get('next') or request.form.get('next') - login = request.form.get('login') - password = request.form.get('pass') - - if login and password: - users = user_sql.select_users(user=login) - - for user in users: - if user.activeuser == 0: - return 'Your login is disabled', 200 - if user.ldap_user == 1: - if login in user.username: - if roxywi_auth.check_in_ldap(login, password): - user_uuid = roxywi_auth.create_uuid_and_token(login) - return roxywi_auth.do_login(user_uuid, str(user.groups), user, next_url) - - else: - hashed_password = roxy_wi_tools.Tools.get_hash(password) - if login in user.username and hashed_password == user.password: - user_uuid = roxywi_auth.create_uuid_and_token(login) - return roxywi_auth.do_login(user_uuid, str(user.groups), user, next_url) - else: - return 'ban', 200 - else: - return 'ban', 200 - - try: + if request.method == 'GET': lang = roxywi_common.get_user_lang_for_flask() - except Exception: - lang = 'en' - return render_template('login.html', lang=lang) + return render_template('login.html', lang=lang) + elif request.method == 'POST': + next_url = request.args.get('next') or request.form.get('next') + login = request.json.get('login') + password = request.json.get('pass') + try: + roxy.update_plan() + except Exception: + pass + try: + user_params = roxywi_auth.check_user_password(login, password) + except Exception as e: + return roxywi_common.handle_json_exceptions(e, 'Cannot check login password'), 401 + try: + return roxywi_auth.do_login(user_params, next_url) + except Exception as e: + return roxywi_common.handle_json_exceptions(e, 'Cannot do login'), 401 @app.route('/logout', methods=['GET', 'POST']) -@login_required +@jwt_required() def logout(): - user = f'user_{current_user.id}' - cache.delete(user) - logout_user() - resp = make_response(redirect(url_for('login_page'))) - resp.delete_cookie('uuid') - resp.delete_cookie('group') - + resp = make_response(redirect('/', 302)) + unset_jwt_cookies(resp) return resp diff --git a/app/middleware.py b/app/middleware.py index 5f8ea12b..5d9f9ca5 100644 --- a/app/middleware.py +++ b/app/middleware.py @@ -2,8 +2,8 @@ from functools import wraps from flask import redirect, url_for, abort, g -import modules.roxywi.auth as roxywi_auth -import modules.roxywi.common as roxywi_common +import app.modules.roxywi.auth as roxywi_auth +import app.modules.roxywi.common as roxywi_common def check_services(fn): @@ -26,7 +26,30 @@ def get_user_params(virt=0, disable=0): user_params = roxywi_common.get_users_params(virt=virt, disable=disable, service=kwargs.get('service')) g.user_params = user_params except Exception: - return redirect(url_for('login_page')) + return abort(401) + return fn(*args, **kwargs) + return decorated_views + return inner_decorator + + +def page_for_admin(level=1): + def inner_decorator(fn): + @wraps(fn) + def decorated_views(*args, **kwargs): + if not roxywi_auth.is_admin(level=level): + return abort(403, 'bad permission') + else: + return fn(*args, **kwargs) + return decorated_views + return inner_decorator + + +def check_group(): + def inner_decorator(fn): + @wraps(fn) + def decorated_views(*args, **kwargs): + if not roxywi_common.check_user_group_for_flask(): + return roxywi_common.handle_json_exceptions('Wrong group', 'Cannot create user') return fn(*args, **kwargs) return decorated_views return inner_decorator diff --git a/app/modules/common/common_classes.py b/app/modules/common/common_classes.py new file mode 100644 index 00000000..8020702c --- /dev/null +++ b/app/modules/common/common_classes.py @@ -0,0 +1,50 @@ +from typing import Union + +from flask import g + +import app.modules.db.server as server_sql +import app.modules.roxywi.common as roxywi_common +from app.modules.roxywi.exception import RoxywiResourceNotFound +from app.modules.roxywi.class_models import ServerRequest, GroupQuery, CredRequest, ChannelRequest +from app.middleware import get_user_params + +class SupportClass: + def __init__(self, is_id=True): + self.is_id = is_id + + @get_user_params() + def return_server_ip_or_id(self, server_id: Union[int, str]) -> Union[int, str]: + if isinstance(server_id, str): + try: + server = server_sql.get_server_by_ip(server_id) + except Exception as e: + raise e + else: + try: + server = server_sql.get_server_by_id(server_id) + except Exception as e: + raise e + try: + roxywi_common.is_user_has_access_to_group(g.user_params['user_id'], server.group_id) + except Exception as e: + roxywi_common.handler_exceptions_for_json_data(e, '') + + if self.is_id: + return server.server_id + else: + return server.ip + + @staticmethod + @get_user_params() + def return_group_id(body: Union[ServerRequest, CredRequest, GroupQuery, ChannelRequest]): + if body.group_id: + if g.user_params['role'] == 1: + return body.group_id + else: + try: + roxywi_common.is_user_has_access_to_group(g.user_params['user_id'], body.group_id) + return body.group_id + except Exception: + return int(g.user_params['group_id']) + else: + return int(g.user_params['group_id']) diff --git a/app/modules/config/common.py b/app/modules/config/common.py index 7854b081..a5b5a1f8 100644 --- a/app/modules/config/common.py +++ b/app/modules/config/common.py @@ -1,5 +1,5 @@ import app.modules.db.sql as sql -import modules.roxy_wi_tools as roxy_wi_tools +import app.modules.roxy_wi_tools as roxy_wi_tools get_config_var = roxy_wi_tools.GetConfigVar() time_zone = sql.get_setting('time_zone') diff --git a/app/modules/config/config.py b/app/modules/config/config.py index addc74ef..a2707e20 100644 --- a/app/modules/config/config.py +++ b/app/modules/config/config.py @@ -2,7 +2,9 @@ import os from pathlib import Path from typing import Any -from flask import render_template, request, g +from flask import render_template, g +from flask_jwt_extended import get_jwt +from flask_jwt_extended import verify_jwt_in_request import app.modules.db.sql as sql import app.modules.db.user as user_sql @@ -243,7 +245,7 @@ def upload_and_restart(server_ip: str, cfg: str, just_save: str, service: str, * try: commands = _generate_command(service, server_id, just_save, config_path, tmp_file, cfg, server_ip) except Exception as e: - return f'error: {e}' + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot generate command for service {service}') try: error = server_mod.ssh_command(server_ip, commands) @@ -383,19 +385,20 @@ def diff_config(old_cfg, cfg, **kwargs): return diff try: - user_uuid = request.cookies.get('uuid') - login = user_sql.get_user_name_by_uuid(user_uuid) + verify_jwt_in_request() + claims = get_jwt() + login = user_sql.get_user_id(claims['user_id']) except Exception: login = '' for line in output: - diff += f"{date} user: {login}, group: {user_group} {line}\n" + diff += f"{date} user: {login.username}, group: {user_group} {line}\n" try: with open(log_file, 'a') as log: log.write(diff) except IOError as e: - roxywi_common.logging('Roxy-WI server', f'error: Cannot write a diff config to the log file: {e}, {stderr}', login=login, roxywi=1) + roxywi_common.logging('Roxy-WI server', f'error: Cannot write a diff config to the log file: {e}, {stderr}', login=login.username, roxywi=1) def _classify_line(line: str) -> str: @@ -409,7 +412,7 @@ def show_finding_in_config(stdout: str, **kwargs) -> str: """ :param stdout: The stdout of a command execution. :param kwargs: Additional keyword arguments. - :keyword grep: The word to find and highlight in the output. (Optional) + :keyword grep: The word to find and highlight in the output. (Optional) :return: The output with highlighted lines and formatted dividers. This method takes the stdout of a command execution and additional keyword arguments. It searches for a word specified by the `grep` keyword argument in each line of the stdout and highlights @@ -467,10 +470,11 @@ def compare_config(service: str, left: str, right: str) -> str: return render_template('ajax/compare.html', stdout=output, lang=lang) -def show_config(server_ip: str, service: str, config_file_name: str, configver: str) -> str: +def show_config(server_ip: str, service: str, config_file_name: str, configver: str, claims: dict) -> str: """ Get and display the configuration file for a given server. + :param claims: :param server_ip: The IP address of the server. :param service: The name of the service. :param config_file_name: The name of the configuration file. @@ -478,8 +482,8 @@ def show_config(server_ip: str, service: str, config_file_name: str, configver: :return: The rendered template for displaying the configuration. """ - user_uuid = request.cookies.get('uuid') - group_id = int(request.cookies.get('group')) + user_id = claims['user_id'] + group_id = claims['group'] configs_dir = config_common.get_config_dir(service) server_id = server_sql.select_server_id_by_ip(server_ip) @@ -513,7 +517,7 @@ def show_config(server_ip: str, service: str, config_file_name: str, configver: 'conf': conf, 'serv': server_ip, 'configver': configver, - 'role': user_sql.get_user_role_by_uuid(user_uuid, group_id), + 'role': user_sql.get_user_role_in_group(user_id, group_id), 'service': service, 'config_file_name': config_file_name, 'is_serv_protected': server_sql.is_serv_protected(server_ip), diff --git a/app/modules/db/backup.py b/app/modules/db/backup.py index dbf31adc..f8bb22d3 100644 --- a/app/modules/db/backup.py +++ b/app/modules/db/backup.py @@ -1,62 +1,46 @@ from app.modules.db.db_model import Backup, S3Backup, GitSetting from app.modules.db.common import out_error +from app.modules.roxywi.exception import RoxywiResourceNotFound def insert_backup_job(server, rserver, rpath, backup_type, time, cred, description): try: - Backup.insert( - server=server, rhost=rserver, rpath=rpath, backup_type=backup_type, time=time, - cred=cred, description=description + return Backup.insert( + server=server, rhost=rserver, rpath=rpath, type=backup_type, time=time, + cred_id=cred, description=description ).execute() except Exception as e: out_error(e) - return False - else: - return True -def insert_s3_backup_job(server, s3_server, bucket, secret_key, access_key, time, description): +def insert_s3_backup_job(**kwargs): try: - S3Backup.insert( - server=server, s3_server=s3_server, bucket=bucket, secret_key=secret_key, access_key=access_key, time=time, - description=description - ).execute() + return S3Backup.insert(**kwargs).execute() except Exception as e: out_error(e) - return False - else: - return True def update_backup(server, rserver, rpath, backup_type, time, cred, description, backup_id): backup_update = Backup.update( - server=server, rhost=rserver, rpath=rpath, backup_type=backup_type, time=time, - cred=cred, description=description + server=server, rhost=rserver, rpath=rpath, type=backup_type, time=time, + cred_id=cred, description=description ).where(Backup.id == backup_id) try: backup_update.execute() except Exception as e: out_error(e) - return False - else: - return True -def delete_backups(backup_id: int) -> bool: - query = Backup.delete().where(Backup.id == backup_id) +def delete_backups(backup_id: int) -> None: try: - query.execute() + Backup.delete().where(Backup.id == backup_id).execute() except Exception as e: out_error(e) - return False - else: - return True def delete_s3_backups(backup_id: int) -> bool: - query = S3Backup.delete().where(S3Backup.id == backup_id) try: - query.execute() + S3Backup.delete().where(S3Backup.id == backup_id).execute() except Exception as e: out_error(e) return False @@ -106,11 +90,9 @@ def select_backups(**kwargs): query = Backup.select().order_by(Backup.id) try: - query_res = query.execute() + return query.execute() except Exception as e: out_error(e) - else: - return query_res def select_s3_backups(**kwargs): @@ -153,3 +135,18 @@ def check_exists_s3_backup(server: str) -> bool: return True else: return False + + +def get_backup(backup_id: int, model: str) -> Backup: + models = { + 'fs': Backup, + 's3': S3Backup, + 'git': GitSetting, + } + model = models[model] + try: + return model.get(model.id == backup_id) + except model.DoesNotExist: + raise RoxywiResourceNotFound + except Exception as e: + out_error(e) diff --git a/app/modules/db/channel.py b/app/modules/db/channel.py index f9db813e..10c5be42 100644 --- a/app/modules/db/channel.py +++ b/app/modules/db/channel.py @@ -1,272 +1,82 @@ from app.modules.db.db_model import Telegram, Slack, PD, Server, MM from app.modules.db.common import out_error +from app.modules.roxywi.exception import RoxywiResourceNotFound + +models = { + 'telegram': Telegram, + 'slack': Slack, + 'pd': PD, + 'mm': MM + } -def get_user_telegram_by_group(group): +def get_user_receiver_by_group(receiver: str, group: int): + model = models[receiver] try: - return Telegram.select().where(Telegram.groups == group).execute() + return model.select().where(model.group_id == group).execute() except Exception as e: out_error(e) -def get_telegram_by_ip(ip): +def get_receiver_by_ip(receiver:str, ip: str): + model = models[receiver] try: - return Telegram.select().join(Server, on=(Server.groups == Telegram.groups)).where(Server.ip == ip).execute() + return model.select().join(Server, on=(Server.group_id == model.group_id)).where(Server.ip == ip).execute() except Exception as e: out_error(e) -def get_telegram_by_id(telegram_id): +def get_receiver_by_id(receiver: str, channel_id: str): + model = models[receiver] try: - return Telegram.select().where(Telegram.id == telegram_id).execute() + return model.select().where(model.id == channel_id).execute() except Exception as e: out_error(e) -def get_user_slack_by_group(group): +def select_receiver(receiver: str, channel_id: str): + model = models[receiver] try: - return Slack.select().where(Slack.groups == group).execute() + return model.get(model.id == channel_id) + except model.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) -def get_slack_by_ip(ip): +def insert_new_receiver(receiver: str, token: str, channel: str, group: str): + model = models[receiver] try: - return Slack.select().join(Server, on=(Server.groups == Slack.groups)).where(Server.ip == ip).execute() + return model.insert(token=token, chanel_name=channel, group_id=group).execute() except Exception as e: out_error(e) -def get_slack_by_id(slack_id): +def update_receiver(receiver: str, token: str, channel: str, group: str, channel_id: int) -> None: + model = models[receiver] try: - return Slack.select().where(Slack.id == slack_id).execute() + model.update(token=token, chanel_name=channel, group_id=group).where(model.id == channel_id).execute() + except model.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) -def get_user_pd_by_group(group): +def delete_receiver(receiver: str, channel_id: int) -> None: + model = models[receiver] try: - return PD.select().where(PD.groups == group).execute() + model.delete().where(model.id == channel_id).execute() + except model.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) -def get_user_mm_by_group(group): +def get_receiver_with_group(receiver: str, channel_id: int, group_id: int): try: - return MM.select().where(MM.groups == group).execute() - except Exception as e: - out_error(e) - - -def get_pd_by_ip(ip): - query = PD.select().join(Server, on=(Server.groups == PD.groups)).where(Server.ip == ip) - try: - query_res = query.execute() - except Exception as e: - out_error(e) - else: - return query_res - - -def get_pd_by_id(pd_id): - try: - return PD.select().where(PD.id == pd_id).execute() - except Exception as e: - out_error(e) - - -def delete_telegram(telegram_id): - query = Telegram.delete().where(Telegram.id == telegram_id) - try: - query.execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def select_telegram(**kwargs): - if kwargs.get('token'): - query = Telegram.select().where(Telegram.token == kwargs.get('token')) - elif kwargs.get('id'): - query = Telegram.select().where(Telegram.id == kwargs.get('id')) - else: - query = Telegram.select() - try: - query_res = query.execute() - except Exception as e: - out_error(e) - else: - return query_res - - -def insert_new_telegram(token, channel, group): - try: - Telegram.insert(token=token, chanel_name=channel, groups=group).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def update_telegram(token, channel, group, telegram_id): - telegram_update = Telegram.update(token=token, chanel_name=channel, groups=group).where(Telegram.id == telegram_id) - try: - telegram_update.execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def delete_slack(slack_id): - query = Slack.delete().where(Slack.id == slack_id) - try: - query.execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def select_slack(**kwargs): - if kwargs.get('token'): - query = Slack.select().where(Slack.token == kwargs.get('token')) - elif kwargs.get('id'): - query = Slack.select().where(Slack.id == kwargs.get('id')) - else: - query = Slack.select() - try: - query_res = query.execute() - except Exception as e: - out_error(e) - else: - return query_res - - -def insert_new_slack(token, chanel, group): - try: - Slack.insert(token=token, chanel_name=chanel, groups=group).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def update_slack(token, chanel, group, slack_id): - try: - return Slack.update(token=token, chanel_name=chanel, groups=group).where(Slack.id == slack_id).execute() - except Exception as e: - out_error(e) - - -def delete_pd(pd_id): - try: - PD.delete().where(PD.id == pd_id).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def select_pd(**kwargs): - if kwargs.get('token'): - query = PD.select().where(PD.token == kwargs.get('token')) - elif kwargs.get('id'): - query = PD.select().where(PD.id == kwargs.get('id')) - else: - query = PD.select() - try: - query_res = query.execute() - except Exception as e: - out_error(e) - else: - return query_res - - -def insert_new_pd(token, chanel, group): - try: - PD.insert(token=token, chanel_name=chanel, groups=group).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def update_pd(token, chanel, group, pd_id): - try: - PD.update(token=token, chanel_name=chanel, groups=group).where(PD.id == pd_id).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def insert_new_mm(token, chanel, group): - try: - MM.insert(token=token, chanel_name=chanel, groups=group).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def update_mm(token, chanel, group, mm_id): - try: - MM.update(token=token, chanel_name=chanel, groups=group).where(MM.id == mm_id).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def delete_mm(pd_id): - try: - MM.delete().where(MM.id == pd_id).execute() - except Exception as e: - out_error(e) - return False - else: - return True - - -def select_mm(**kwargs): - if kwargs.get('token'): - query = MM.select().where(MM.token == kwargs.get('token')) - elif kwargs.get('id'): - query = MM.select().where(MM.id == kwargs.get('id')) - else: - query = MM.select() - try: - query_res = query.execute() - except Exception as e: - out_error(e) - else: - return query_res - - -def get_mm_by_ip(ip): - query = MM.select().join(Server, on=(Server.groups == MM.groups)).where(Server.ip == ip) - try: - query_res = query.execute() - except Exception as e: - out_error(e) - else: - return query_res - - -def get_mm_by_id(pd_id): - try: - return MM.select().where(MM.id == pd_id).execute() + model = models[receiver] + return model.get((model.id == channel_id) & (model.group_id == group_id)) + except model.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) diff --git a/app/modules/db/checker.py b/app/modules/db/checker.py index 0c1893ad..2c92ff9f 100644 --- a/app/modules/db/checker.py +++ b/app/modules/db/checker.py @@ -19,12 +19,9 @@ def select_checker_settings_for_server(service_id: int, server_id: int): & (CheckerSetting.server_id == server_id) ) try: - query_res = query.execute() + return query.execute() except Exception as e: out_error(e) - return - else: - return query_res def insert_new_checker_setting_for_server(server_ip: str) -> None: @@ -121,10 +118,10 @@ def inset_or_update_service_status(server_id: int, service_id: int, service_chec def select_alert(**kwargs): if kwargs.get("group") is not None: query = Server.select(Server.ip).where( - (Server.alert == 1) & (Server.enable == 1) & (Server.groups == kwargs.get('group')) + (Server.haproxy_alert == 1) & (Server.enabled == 1) & (Server.group_id == kwargs.get('group')) ) else: - query = Server.select(Server.ip).where((Server.alert == 1) & (Server.enable == 1)) + query = Server.select(Server.ip).where((Server.haproxy_alert == 1) & (Server.enabled == 1)) try: query_res = query.execute() except Exception as e: @@ -136,10 +133,10 @@ def select_alert(**kwargs): def select_all_alerts(**kwargs): if kwargs.get("group") is not None: query = Server.select(Server.ip).where( - ((Server.alert == 1) | (Server.nginx_alert == 1)) & (Server.enable == 1) & (Server.groups == kwargs.get('group')) + ((Server.haproxy_alert == 1) | (Server.nginx_alert == 1)) & (Server.enabled == 1) & (Server.group_id == kwargs.get('group')) ) else: - query = Server.select(Server.ip).where(((Server.alert == 1) | (Server.nginx_alert == 1)) & (Server.enable == 1)) + query = Server.select(Server.ip).where(((Server.haproxy_alert == 1) | (Server.nginx_alert == 1)) & (Server.enabled == 1)) try: query_res = query.execute() except Exception as e: @@ -152,14 +149,14 @@ def select_nginx_alert(**kwargs): if kwargs.get("group") is not None: query = Server.select(Server.ip).where( (Server.nginx_alert == 1) - & (Server.enable == 1) - & (Server.groups == kwargs.get('group')) + & (Server.enabled == 1) + & (Server.group_id == kwargs.get('group')) & (Server.nginx == 1) ) else: query = Server.select(Server.ip).where( (Server.nginx_alert == 1) - & (Server.enable == 1) + & (Server.enabled == 1) & (Server.nginx == 1) ) try: @@ -174,12 +171,12 @@ def select_apache_alert(**kwargs): if kwargs.get("group") is not None: query = Server.select(Server.ip).where( (Server.apache_alert == 1) - & (Server.enable == 1) - & (Server.groups == kwargs.get('group')) + & (Server.enabled == 1) + & (Server.group_id == kwargs.get('group')) & (Server.apache == 1) ) else: - query = Server.select(Server.ip).where((Server.apache_alert == 1) & (Server.enable == 1) & (Server.apache == 1)) + query = Server.select(Server.ip).where((Server.apache_alert == 1) & (Server.enabled == 1) & (Server.apache == 1)) try: query_res = query.execute() except Exception as e: @@ -192,14 +189,14 @@ def select_keepalived_alert(**kwargs): if kwargs.get("group") is not None: query = Server.select(Server.ip).where( (Server.keepalived_alert == 1) - & (Server.enable == 1) - & (Server.groups == kwargs.get('group')) + & (Server.enabled == 1) + & (Server.group_id == kwargs.get('group')) & (Server.keepalived == 1) ) else: query = Server.select(Server.ip).where( (Server.keepalived_alert == 1) - & (Server.enable == 1) + & (Server.enabled == 1) & (Server.keepalived == 1) ) try: diff --git a/app/modules/db/cred.py b/app/modules/db/cred.py index 15f23b97..9faac5e1 100644 --- a/app/modules/db/cred.py +++ b/app/modules/db/cred.py @@ -1,5 +1,6 @@ from app.modules.db.db_model import Cred, Server from app.modules.db.common import out_error +from app.modules.roxywi.exception import RoxywiResourceNotFound def select_ssh(**kwargs): @@ -8,9 +9,9 @@ def select_ssh(**kwargs): elif kwargs.get("id") is not None: query = Cred.select().where(Cred.id == kwargs.get('id')) elif kwargs.get("serv") is not None: - query = Cred.select().join(Server, on=(Cred.id == Server.cred)).where(Server.ip == kwargs.get('serv')) + query = Cred.select().join(Server, on=(Cred.id == Server.cred_id)).where(Server.ip == kwargs.get('serv')) elif kwargs.get("group") is not None: - query = Cred.select().where(Cred.groups == kwargs.get("group")) + query = Cred.select().where(Cred.group_id == kwargs.get("group")) else: query = Cred.select() try: @@ -25,7 +26,7 @@ def insert_new_ssh(name, enable, group, username, password): if password is None: password = 'None' try: - return Cred.insert(name=name, enable=enable, groups=group, username=username, password=password).execute() + return Cred.insert(name=name, key_enabled=enable, group_id=group, username=username, password=password).execute() except Exception as e: out_error(e) @@ -44,7 +45,7 @@ def update_ssh(cred_id, name, enable, group, username, password): if password is None: password = 'None' - cred_update = Cred.update(name=name, enable=enable, groups=group, username=username, password=password).where( + cred_update = Cred.update(name=name, key_enabled=enable, group_id=group, username=username, password=password).where( Cred.id == cred_id) try: cred_update.execute() @@ -57,3 +58,21 @@ def update_ssh_passphrase(name: str, passphrase: str): Cred.update(passphrase=passphrase).where(Cred.name == name).execute() except Exception as e: out_error(e) + + +def get_ssh_by_id_and_group(creds_id: int, group_id: int) -> Cred: + try: + return Cred.select().where((Cred.group_id == group_id) & (Cred.id == creds_id)).execute() + except Cred.DoesNotExist: + raise RoxywiResourceNotFound + except Exception as e: + out_error(e) + + +def get_ssh(ssh_id: int) -> Cred: + try: + return Cred.get(Cred.id == ssh_id) + except Cred.DoesNotExist: + raise RoxywiResourceNotFound + except Exception as e: + out_error(e) diff --git a/app/modules/db/db_model.py b/app/modules/db/db_model.py index 7ee38d3e..e17a97f0 100644 --- a/app/modules/db/db_model.py +++ b/app/modules/db/db_model.py @@ -1,11 +1,10 @@ from datetime import datetime from playhouse.migrate import * -from flask_login import UserMixin from playhouse.shortcuts import ReconnectMixin from playhouse.sqlite_ext import SqliteExtDatabase -import modules.roxy_wi_tools as roxy_wi_tools +import app.modules.roxy_wi_tools as roxy_wi_tools get_config = roxy_wi_tools.GetConfigVar() mysql_enable = get_config.get_config_var('mysql', 'enable') @@ -43,15 +42,15 @@ class BaseModel(Model): database = connect() -class User(BaseModel, UserMixin): +class User(BaseModel): user_id = AutoField(column_name='id') username = CharField(constraints=[SQL('UNIQUE')]) email = CharField(constraints=[SQL('UNIQUE')]) password = CharField(null=True) role = CharField() - groups = CharField() + group_id = CharField() ldap_user = IntegerField(constraints=[SQL('DEFAULT "0"')]) - activeuser = IntegerField(constraints=[SQL('DEFAULT "1"')]) + enabled = IntegerField(constraints=[SQL('DEFAULT "1"')]) user_services = CharField(constraints=[SQL('DEFAULT "1 2 3 4 5 6"')]) last_login_date = DateTimeField(constraints=[SQL('DEFAULT "0000-00-00 00:00:00"')]) last_login_ip = CharField(null=True) @@ -64,16 +63,16 @@ class Server(BaseModel): server_id = AutoField(column_name='id') hostname = CharField() ip = CharField(constraints=[SQL('UNIQUE')]) - groups = CharField() + group_id = CharField() type_ip = IntegerField(constraints=[SQL('DEFAULT 0')]) - enable = IntegerField(constraints=[SQL('DEFAULT 1')]) + enabled = IntegerField(constraints=[SQL('DEFAULT 1')]) master = IntegerField(constraints=[SQL('DEFAULT 0')]) - cred = IntegerField(constraints=[SQL('DEFAULT 1')]) - alert = IntegerField(constraints=[SQL('DEFAULT 0')]) - metrics = IntegerField(constraints=[SQL('DEFAULT 0')]) + cred_id = IntegerField(constraints=[SQL('DEFAULT 1')]) + haproxy_alert = IntegerField(constraints=[SQL('DEFAULT 0')]) + haproxy_metrics = IntegerField(constraints=[SQL('DEFAULT 0')]) port = IntegerField(constraints=[SQL('DEFAULT 22')]) - desc = CharField(null=True) - active = IntegerField(constraints=[SQL('DEFAULT 0')]) + description = CharField(null=True) + haproxy_active = IntegerField(constraints=[SQL('DEFAULT 0')]) keepalived = IntegerField(constraints=[SQL('DEFAULT 0')]) nginx = IntegerField(constraints=[SQL('DEFAULT 0')]) haproxy = IntegerField(constraints=[SQL('DEFAULT 0')]) @@ -107,7 +106,7 @@ class Telegram(BaseModel): id = AutoField() token = CharField() chanel_name = CharField() - groups = IntegerField() + group_id = IntegerField() class Meta: table_name = 'telegram' @@ -117,7 +116,7 @@ class Slack(BaseModel): id = AutoField() token = CharField() chanel_name = CharField() - groups = IntegerField() + group_id = IntegerField() class Meta: table_name = 'slack' @@ -127,7 +126,7 @@ class MM(BaseModel): id = AutoField() token = CharField() chanel_name = CharField() - groups = IntegerField() + group_id = IntegerField() class Meta: table_name = 'mattermost' @@ -137,22 +136,12 @@ class PD(BaseModel): id = AutoField() token = CharField() chanel_name = CharField() - groups = IntegerField() + group_id = IntegerField() class Meta: table_name = 'pd' -class UUID(BaseModel): - user_id = IntegerField() - uuid = CharField() - exp = DateTimeField(default=datetime.now) - - class Meta: - table_name = 'uuid' - primary_key = False - - class ApiToken(BaseModel): token = CharField() user_name = CharField() @@ -202,10 +191,10 @@ class UserGroups(BaseModel): class Cred(BaseModel): id = AutoField() name = CharField() - enable = IntegerField(constraints=[SQL('DEFAULT 1')]) + key_enabled = IntegerField(constraints=[SQL('DEFAULT 1')]) username = CharField() password = CharField(null=True) - groups = IntegerField(constraints=[SQL('DEFAULT 1')]) + group_id = IntegerField(constraints=[SQL('DEFAULT 1')]) passphrase = CharField(null=True) class Meta: @@ -218,9 +207,9 @@ class Backup(BaseModel): server = CharField() rhost = CharField() rpath = CharField() - backup_type = CharField(column_name='type') + type = CharField(column_name='type') time = CharField() - cred = IntegerField() + cred_id = IntegerField() description = CharField(null=True) class Meta: @@ -693,7 +682,7 @@ class HaCluster(BaseModel): name = CharField() syn_flood = IntegerField(constraints=[SQL('DEFAULT "0"')]) group_id = IntegerField() - desc = CharField() + description = CharField() pos = IntegerField(constraints=[SQL('DEFAULT "0"')]) class Meta: @@ -765,7 +754,7 @@ class UDPBalancer(BaseModel): port = IntegerField() group_id = ForeignKeyField(Groups) config = CharField() - desc = CharField() + description = CharField() lb_algo = CharField(constraints=[SQL('DEFAULT "rr"')]) check_enabled = IntegerField(constraints=[SQL('DEFAULT "1"')]) delay_loop = IntegerField(constraints=[SQL('DEFAULT "10"')]) @@ -781,7 +770,7 @@ def create_tables(): conn = connect() with conn: conn.create_tables( - [User, Server, Role, Telegram, Slack, UUID, ApiToken, Groups, UserGroups, ConfigVersion, Setting, + [User, Server, Role, Telegram, Slack, ApiToken, Groups, UserGroups, ConfigVersion, Setting, Cred, Backup, Metrics, WafMetrics, Version, Option, SavedServer, Waf, ActionHistory, PortScannerSettings, PortScannerPorts, PortScannerHistory, ServiceSetting, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics, SystemInfo, Services, UserName, GitSetting, CheckerSetting, ApacheMetrics, WafNginx, ServiceStatus, diff --git a/app/modules/db/group.py b/app/modules/db/group.py index f22b7e02..57acda0c 100644 --- a/app/modules/db/group.py +++ b/app/modules/db/group.py @@ -1,5 +1,6 @@ from app.modules.db.db_model import Groups, Setting, UserGroups from app.modules.db.common import out_error +from app.modules.roxywi.exception import RoxywiResourceNotFound def select_groups(**kwargs): @@ -123,11 +124,11 @@ def update_group(name, descript, group_id): def get_group_name_by_id(group_id): try: - group_name = Groups.get(Groups.group_id == group_id) + return Groups.get(Groups.group_id == group_id).name + except Groups.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) - else: - return group_name.name def get_group_id_by_name(group_name): diff --git a/app/modules/db/ha_cluster.py b/app/modules/db/ha_cluster.py index 295f18ba..396129d4 100644 --- a/app/modules/db/ha_cluster.py +++ b/app/modules/db/ha_cluster.py @@ -12,7 +12,7 @@ def select_clusters(group_id: int): def create_cluster(name: str, syn_flood: int, group_id: int, desc: str) -> int: try: last_id = HaCluster.insert( - name=name, syn_flood=syn_flood, group_id=group_id, desc=desc + name=name, syn_flood=syn_flood, group_id=group_id, description=desc ).execute() return last_id except Exception as e: @@ -79,7 +79,7 @@ def select_cluster_master_slaves(cluster_id: int, group_id: int, router_id: int) conn = connect() cursor = conn.cursor() sql = f"select * from servers left join ha_cluster_slaves on (servers.id = ha_cluster_slaves.server_id) " \ - f"where servers.groups = {group_id} and ha_cluster_slaves.cluster_id = {cluster_id} and ha_cluster_slaves.router_id = {router_id};" + f"where servers.group_id = {group_id} and ha_cluster_slaves.cluster_id = {cluster_id} and ha_cluster_slaves.router_id = {router_id};" try: cursor.execute(sql) except Exception as e: @@ -133,7 +133,7 @@ def select_ha_cluster_not_masters_not_slaves(group_id: int): query = Server.select().where( (Server.type_ip == 0) & (Server.server_id.not_in(HaClusterSlave.select(HaClusterSlave.server_id))) & - (Server.groups == group_id) + (Server.group_id == group_id) ) return query.execute() except Exception as e: @@ -206,7 +206,7 @@ def update_slave(cluster_id: int, server_id: int, eth: str, master: int, router_ def update_cluster(cluster_id: int, name: str, desc: str, syn_flood: int) -> None: try: - HaCluster.update(name=name, desc=desc, syn_flood=syn_flood).where(HaCluster.id == cluster_id).execute() + HaCluster.update(name=name, description=desc, syn_flood=syn_flood).where(HaCluster.id == cluster_id).execute() except Exception as e: out_error(e) @@ -276,4 +276,4 @@ def get_cred_id_by_server_ip(server_ip): except Exception as e: return out_error(e) else: - return cred.cred + return cred.cred_id diff --git a/app/modules/db/keep_alive.py b/app/modules/db/keep_alive.py index 4edbe3a7..2f517df1 100644 --- a/app/modules/db/keep_alive.py +++ b/app/modules/db/keep_alive.py @@ -3,7 +3,7 @@ from app.modules.db.common import out_error def select_keep_alive(): - query = Server.select(Server.ip, Server.groups, Server.server_id).where(Server.active == 1) + query = Server.select(Server.ip, Server.group_id, Server.server_id).where(Server.haproxy_active == 1) try: query_res = query.execute() except Exception as e: @@ -13,7 +13,7 @@ def select_keep_alive(): def select_nginx_keep_alive(): - query = Server.select(Server.ip, Server.groups, Server.server_id).where(Server.nginx_active == 1) + query = Server.select(Server.ip, Server.group_id, Server.server_id).where(Server.nginx_active == 1) try: query_res = query.execute() except Exception as e: @@ -23,7 +23,7 @@ def select_nginx_keep_alive(): def select_apache_keep_alive(): - query = Server.select(Server.ip, Server.groups, Server.server_id).where(Server.apache_active == 1) + query = Server.select(Server.ip, Server.group_id, Server.server_id).where(Server.apache_active == 1) try: query_res = query.execute() except Exception as e: @@ -33,7 +33,7 @@ def select_apache_keep_alive(): def select_keepalived_keep_alive(): - query = Server.select(Server.ip, Server.port, Server.groups, Server.server_id).where(Server.keepalived_active == 1) + query = Server.select(Server.ip, Server.port, Server.group_id, Server.server_id).where(Server.keepalived_active == 1) try: query_res = query.execute() except Exception as e: diff --git a/app/modules/db/metric.py b/app/modules/db/metric.py index ed34e390..9337741e 100644 --- a/app/modules/db/metric.py +++ b/app/modules/db/metric.py @@ -209,12 +209,12 @@ def select_metrics(serv, service, **kwargs): def select_servers_metrics_for_master(**kwargs): if kwargs.get('group') != 1: query = Server.select(Server.ip).where( - ((Server.metrics == 1) | (Server.nginx_metrics == 1) | (Server.apache_metrics == 1)) - & (Server.groups == kwargs.get('group')) + ((Server.haproxy_metrics == 1) | (Server.nginx_metrics == 1) | (Server.apache_metrics == 1)) + & (Server.group_id == kwargs.get('group')) ) else: query = Server.select(Server.ip).where( - (Server.metrics == 1) + (Server.haproxy_metrics == 1) | (Server.nginx_metrics == 1) | (Server.apache_metrics == 1) ) @@ -228,7 +228,7 @@ def select_servers_metrics_for_master(**kwargs): def select_haproxy_servers_metrics_for_master(): - query = Server.select(Server.ip).where(Server.metrics == 1) + query = Server.select(Server.ip).where(Server.haproxy_metrics == 1) try: query_res = query.execute() except Exception as e: @@ -262,10 +262,10 @@ def select_apache_servers_metrics_for_master(): def select_servers_metrics(group_id): if group_id == 1: - query = Server.select(Server.ip).where((Server.enable == 1) & (Server.metrics == 1)) + query = Server.select(Server.ip).where((Server.enabled == 1) & (Server.haproxy_metrics == 1)) else: query = Server.select(Server.ip).where( - (Server.enable == 1) & (Server.groups == group_id) & (Server.metrics == 1)) + (Server.enabled == 1) & (Server.group_id == group_id) & (Server.haproxy_metrics == 1)) try: query_res = query.execute() except Exception as e: @@ -281,84 +281,84 @@ def select_table_metrics(group_id): if group_id == 1: groups = "" else: - groups = "and servers.groups = '{group}' ".format(group=group_id) + groups = "and servers.group_id = '{group}' ".format(group=group_id) if mysql_enable == '1': sql = """ select ip.ip, hostname, avg_sess_1h, avg_sess_24h, avg_sess_3d, max_sess_1h, max_sess_24h, max_sess_3d, avg_cur_1h, avg_cur_24h, avg_cur_3d, max_con_1h, max_con_24h, max_con_3d from - (select servers.ip from servers where metrics = 1 ) as ip, + (select servers.ip from servers where haproxy_metrics = 1 ) as ip, (select servers.ip, servers.hostname as hostname from servers left join metrics as metr on servers.ip = metr.serv where servers.metrics = 1 %s) as hostname, (select servers.ip,round(avg(metr.sess_rate), 1) as avg_sess_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(), INTERVAL -1 HOUR) group by servers.ip) as avg_sess_1h, (select servers.ip,round(avg(metr.sess_rate), 1) as avg_sess_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -24 HOUR) group by servers.ip) as avg_sess_24h, (select servers.ip,round(avg(metr.sess_rate), 1) as avg_sess_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(), INTERVAL -3 DAY) group by servers.ip ) as avg_sess_3d, (select servers.ip,max(metr.sess_rate) as max_sess_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -1 HOUR) group by servers.ip) as max_sess_1h, (select servers.ip,max(metr.sess_rate) as max_sess_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -24 HOUR) group by servers.ip) as max_sess_24h, (select servers.ip,max(metr.sess_rate) as max_sess_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -3 DAY) group by servers.ip ) as max_sess_3d, (select servers.ip,round(avg(metr.curr_con+metr.cur_ssl_con), 1) as avg_cur_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -1 HOUR) group by servers.ip) as avg_cur_1h, (select servers.ip,round(avg(metr.curr_con+metr.cur_ssl_con), 1) as avg_cur_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -24 HOUR) group by servers.ip) as avg_cur_24h, (select servers.ip,round(avg(metr.curr_con+metr.cur_ssl_con), 1) as avg_cur_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -3 DAY) group by servers.ip ) as avg_cur_3d, (select servers.ip,max(metr.curr_con) as max_con_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -1 HOUR) group by servers.ip) as max_con_1h, (select servers.ip,max(metr.curr_con) as max_con_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -24 HOUR) group by servers.ip) as max_con_24h, (select servers.ip,max(metr.curr_con) as max_con_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -3 DAY) group by servers.ip ) as max_con_3d @@ -381,79 +381,79 @@ def select_table_metrics(group_id): sql = """ select ip.ip, hostname, avg_sess_1h, avg_sess_24h, avg_sess_3d, max_sess_1h, max_sess_24h, max_sess_3d, avg_cur_1h, avg_cur_24h, avg_cur_3d, max_con_1h, max_con_24h, max_con_3d from - (select servers.ip from servers where metrics = 1 ) as ip, + (select servers.ip from servers where haproxy_metrics = 1 ) as ip, (select servers.ip, servers.hostname as hostname from servers left join metrics as metr on servers.ip = metr.serv where servers.metrics = 1 %s) as hostname, (select servers.ip,round(avg(metr.sess_rate), 1) as avg_sess_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-1 hours', 'localtime') group by servers.ip) as avg_sess_1h, (select servers.ip,round(avg(metr.sess_rate), 1) as avg_sess_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-24 hours', 'localtime') group by servers.ip) as avg_sess_24h, (select servers.ip,round(avg(metr.sess_rate), 1) as avg_sess_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-3 days', 'localtime') group by servers.ip ) as avg_sess_3d, (select servers.ip,max(metr.sess_rate) as max_sess_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-1 hours', 'localtime') group by servers.ip) as max_sess_1h, (select servers.ip,max(metr.sess_rate) as max_sess_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-24 hours', 'localtime') group by servers.ip) as max_sess_24h, (select servers.ip,max(metr.sess_rate) as max_sess_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-3 days', 'localtime') group by servers.ip ) as max_sess_3d, (select servers.ip,round(avg(metr.curr_con+metr.cur_ssl_con), 1) as avg_cur_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-1 hours', 'localtime') group by servers.ip) as avg_cur_1h, (select servers.ip,round(avg(metr.curr_con+metr.cur_ssl_con), 1) as avg_cur_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-24 hours', 'localtime') group by servers.ip) as avg_cur_24h, (select servers.ip,round(avg(metr.curr_con+metr.cur_ssl_con), 1) as avg_cur_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-3 days', 'localtime') group by servers.ip ) as avg_cur_3d, (select servers.ip,max(metr.curr_con) as max_con_1h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-1 hours', 'localtime') group by servers.ip) as max_con_1h, (select servers.ip,max(metr.curr_con) as max_con_24h from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-24 hours', 'localtime') group by servers.ip) as max_con_24h, (select servers.ip,max(metr.curr_con) as max_con_3d from servers left join metrics as metr on metr.serv = servers.ip - where servers.metrics = 1 and + where servers.haproxy_metrics = 1 and metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-3 days', 'localtime') group by servers.ip ) as max_con_3d @@ -491,7 +491,7 @@ def select_service_table_metrics(service: str, group_id: int): if group_id == 1: groups = "" else: - groups = f"and servers.groups = '{group_id}' " + groups = f"and servers.group_id = '{group_id}' " if mysql_enable == '1': sql = """ diff --git a/app/modules/db/server.py b/app/modules/db/server.py index 7b782c2d..08297150 100644 --- a/app/modules/db/server.py +++ b/app/modules/db/server.py @@ -1,12 +1,13 @@ from app.modules.db.db_model import mysql_enable, connect, Server, SystemInfo from app.modules.db.common import out_error +from app.modules.roxywi.exception import RoxywiResourceNotFound -def add_server(hostname, ip, group, typeip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall): +def add_server(hostname, ip, group, type_ip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall): try: server_id = Server.insert( - hostname=hostname, ip=ip, groups=group, type_ip=typeip, enable=enable, master=master, cred=cred, - port=port, desc=desc, haproxy=haproxy, nginx=nginx, apache=apache, firewall_enable=firewall + hostname=hostname, ip=ip, group_id=group, type_ip=type_ip, enabled=enable, master=master, cred_id=cred, + port=port, description=desc, haproxy=haproxy, nginx=nginx, apache=apache, firewall_enable=firewall ).execute() return server_id except Exception as e: @@ -24,11 +25,11 @@ def delete_server(server_id): return True -def update_server(hostname, group, typeip, enable, master, server_id, cred, port, desc, firewall, protected): +def update_server(hostname, group, type_ip, enable, master, server_id, cred, port, desc, firewall, protected): try: server_update = Server.update( - hostname=hostname, groups=group, type_ip=typeip, enable=enable, master=master, cred=cred, - port=port, desc=desc, firewall_enable=firewall, protected=protected + hostname=hostname, group_id=group, type_ip=type_ip, enabled=enable, master=master, cred_id=cred, + port=port, description=desc, firewall_enable=firewall, protected=protected ).where(Server.server_id == server_id) server_update.execute() except Exception as e: @@ -44,9 +45,20 @@ def get_hostname_by_server_ip(server_ip): return hostname.hostname -def get_server_by_id(server_id): +def get_server_by_id(server_id: int) -> Server: try: return Server.get(Server.server_id == server_id) + except Server.DoesNotExist: + raise RoxywiResourceNotFound + except Exception as e: + return out_error(e) + + +def get_server_by_ip(server_ip: str) -> Server: + try: + return Server.get(Server.ip == server_ip) + except Server.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: return out_error(e) @@ -167,20 +179,19 @@ def select_servers(**kwargs): cursor = conn.cursor() if mysql_enable == '1': - sql = """select * from `servers` where `enable` = 1 ORDER BY servers.groups """ + sql = """select * from `servers` where `enabled` = 1 ORDER BY servers.group_id """ if kwargs.get("server") is not None: sql = """select * from `servers` where `ip` = '{}' """.format(kwargs.get("server")) if kwargs.get("full") is not None: sql = """select * from `servers` ORDER BY hostname """ if kwargs.get("get_master_servers") is not None: - sql = """select id,hostname from `servers` where `master` = 0 and type_ip = 0 and enable = 1 ORDER BY servers.groups """ - if kwargs.get("get_master_servers") is not None and kwargs.get('uuid') is not None: + sql = """select id,hostname from `servers` where `master` = 0 and type_ip = 0 and enabled = 1 ORDER BY servers.group_id """ + if kwargs.get("get_master_servers") is not None and kwargs.get('user_id') is not None: sql = """ select servers.id, servers.hostname from `servers` - left join user as user on servers.groups = user.groups - left join uuid as uuid on user.id = uuid.user_id - where uuid.uuid = '{}' and servers.master = 0 and servers.type_ip = 0 and servers.enable = 1 ORDER BY servers.groups - """.format(kwargs.get('uuid')) + left join user as user on servers.group_id = user.group_id + where user.user_id = '{}' and servers.master = 0 and servers.type_ip = 0 and servers.enabled = 1 ORDER BY servers.group_id + """.format(kwargs.get('user_id')) if kwargs.get("id"): sql = """select * from `servers` where `id` = '{}' """.format(kwargs.get("id")) if kwargs.get("hostname"): @@ -189,22 +200,21 @@ def select_servers(**kwargs): sql = """select * from `servers` where `hostname` ='{}' or id = '{}' or ip = '{}'""".format( kwargs.get("id_hostname"), kwargs.get("id_hostname"), kwargs.get("id_hostname")) if kwargs.get("server") and kwargs.get("keep_alive"): - sql = """select active from `servers` where `ip` = '{}' """.format(kwargs.get("server")) + sql = """select haproxy_active from `servers` where `ip` = '{}' """.format(kwargs.get("server")) else: - sql = """select * from servers where enable = '1' ORDER BY servers.groups """ + sql = """select * from servers where enabled = '1' ORDER BY servers.group_id """ if kwargs.get("server") is not None: sql = """select * from servers where ip = '{}' """.format(kwargs.get("server")) if kwargs.get("full") is not None: sql = """select * from servers ORDER BY hostname """ if kwargs.get("get_master_servers") is not None: - sql = """select id,hostname from servers where master = 0 and type_ip = 0 and enable = 1 ORDER BY servers.groups """ - if kwargs.get("get_master_servers") is not None and kwargs.get('uuid') is not None: + sql = """select id,hostname from servers where master = 0 and type_ip = 0 and enabled = 1 ORDER BY servers.group_id """ + if kwargs.get("get_master_servers") is not None and kwargs.get('user_id') is not None: sql = """ select servers.id, servers.hostname from servers - left join user as user on servers.groups = user.groups - left join uuid as uuid on user.id = uuid.user_id - where uuid.uuid = '{}' and servers.master = 0 and servers.type_ip = 0 and servers.enable = 1 ORDER BY servers.groups - """.format(kwargs.get('uuid')) + left join user as user on servers.group_id = user.group_id + where user.user_id = '{}' and servers.master = 0 and servers.type_ip = 0 and servers.enabled = 1 ORDER BY servers.group_id + """.format(kwargs.get('user_id')) if kwargs.get("id"): sql = """select * from servers where id = '{}' """.format(kwargs.get("id")) if kwargs.get("hostname"): @@ -213,7 +223,7 @@ def select_servers(**kwargs): sql = """select * from servers where hostname = '{}' or id = '{}' or ip = '{}'""".format( kwargs.get("id_hostname"), kwargs.get("id_hostname"), kwargs.get("id_hostname")) if kwargs.get("server") and kwargs.get("keep_alive"): - sql = """select active from servers where ip = '{}' """.format(kwargs.get("server")) + sql = """select haproxy_active from servers where ip = '{}' """.format(kwargs.get("server")) try: cursor.execute(sql) @@ -225,7 +235,7 @@ def select_servers(**kwargs): def get_dick_permit(group_id, **kwargs): only_group = kwargs.get('only_group') - disable = 'enable = 1' + disable = 'enabled = 1' haproxy = '' nginx = '' keepalived = '' @@ -237,7 +247,7 @@ def get_dick_permit(group_id, **kwargs): else: type_ip = "and type_ip = 0" if kwargs.get('disable') == 0: - disable = '(enable = 1 or enable = 0)' + disable = '(enabled = 1 or enabled = 0)' if kwargs.get('ip'): ip = "and ip = '%s'" % kwargs.get('ip') if kwargs.get('haproxy') or kwargs.get('service') == 'haproxy': @@ -255,12 +265,12 @@ def get_dick_permit(group_id, **kwargs): if group_id == '1' and not only_group: sql = f" select * from `servers` where {disable} {type_ip} {nginx} {haproxy} {keepalived} {apache} {ip} order by `pos` asc" else: - sql = f" select * from `servers` where `groups` = {group_id} and ({disable}) {type_ip} {ip} {haproxy} {nginx} {keepalived} {apache} order by `pos` asc" + sql = f" select * from `servers` where `group_id` = {group_id} and ({disable}) {type_ip} {ip} {haproxy} {nginx} {keepalived} {apache} order by `pos` asc" else: if group_id == '1' and not only_group: sql = f" select * from servers where {disable} {type_ip} {nginx} {haproxy} {keepalived} {apache} {ip} order by pos" else: - sql = f" select * from servers where groups = '{group_id}' and ({disable}) {type_ip} {ip} {haproxy} {nginx} {keepalived} {apache} order by pos" + sql = f" select * from servers where group_id = '{group_id}' and ({disable}) {type_ip} {ip} {haproxy} {nginx} {keepalived} {apache} order by pos" except Exception as e: raise Exception(f'error: {e}') @@ -293,8 +303,19 @@ def is_master(ip, **kwargs): return cursor.fetchall() -def get_server(server_id: int) -> Server: +def get_server_with_group(server_id: int, group_id: int) -> Server: try: - return Server.get(Server.server_id == server_id) + return Server.get((Server.server_id == server_id) & (Server.group_id == group_id)) + except Server.DoesNotExist: + raise RoxywiResourceNotFound + except Exception as e: + out_error(e) + + +def select_servers_with_group(group_id: int) -> Server: + try: + return Server.select().where(Server.group_id == group_id) + except Server.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) diff --git a/app/modules/db/service.py b/app/modules/db/service.py index 1c0efe30..4ba5af4d 100644 --- a/app/modules/db/service.py +++ b/app/modules/db/service.py @@ -15,7 +15,7 @@ def update_hapwi_server(server_id, alert, metrics, active, service_name): update_hapwi = Server.update(apache_alert=alert, apache_active=active, apache_metrics=metrics).where( Server.server_id == server_id) else: - update_hapwi = Server.update(alert=alert, metrics=metrics, active=active).where( + update_hapwi = Server.update(haproxy_alert=alert, haproxy_metrics=metrics, haproxy_active=active).where( Server.server_id == server_id) update_hapwi.execute() except Exception as e: diff --git a/app/modules/db/smon.py b/app/modules/db/smon.py index 46a2367b..955bf756 100644 --- a/app/modules/db/smon.py +++ b/app/modules/db/smon.py @@ -9,7 +9,7 @@ import app.modules.roxy_wi_tools as roxy_wi_tools def get_agents(group_id: int): try: - return SmonAgent.select(SmonAgent, Server).join(Server).where(Server.groups == group_id).objects().execute() + return SmonAgent.select(SmonAgent, Server).join(Server).where(Server.group_id == group_id).objects().execute() except Exception as e: out_error(e) @@ -19,7 +19,7 @@ def get_free_servers_for_agent(group_id: int): query = Server.select().where( (Server.type_ip == 0) & (Server.server_id.not_in(SmonAgent.select(SmonAgent.server_id))) & - (Server.groups == group_id) + (Server.group_id == group_id) ) return query.execute() except Exception as e: diff --git a/app/modules/db/sql.py b/app/modules/db/sql.py index 0290fe04..ea3a40c6 100755 --- a/app/modules/db/sql.py +++ b/app/modules/db/sql.py @@ -1,20 +1,17 @@ -from flask import request - from app.modules.db.db_model import GeoipCodes, Setting, Role from app.modules.db.common import out_error def get_setting(param, **kwargs): - user_group_id = '' - try: - user_group_id = request.cookies.get('group') - except Exception: - pass - if user_group_id == '' or user_group_id is None or param == 'proxy': + if kwargs.get('group_id'): + user_group_id = kwargs.get('group_id') + else: user_group_id = 1 - if kwargs.get('all'): + if kwargs.get('all') and not kwargs.get('section'): query = Setting.select().where(Setting.group == user_group_id).order_by(Setting.section.desc()) + elif kwargs.get('section'): + query = Setting.select().where((Setting.group == user_group_id) & (Setting.section == kwargs.get('section'))) else: query = Setting.select().where((Setting.param == param) & (Setting.group == user_group_id)) @@ -23,7 +20,7 @@ def get_setting(param, **kwargs): except Exception as e: out_error(e) else: - if kwargs.get('all'): + if kwargs.get('all') or kwargs.get('section'): return query_res else: for setting in query_res: @@ -38,14 +35,12 @@ def get_setting(param, **kwargs): return setting.value -def update_setting(param: str, val: str, user_group: int) -> bool: +def update_setting(param: str, val: str, user_group: int) -> None: query = Setting.update(value=val).where((Setting.param == param) & (Setting.group == user_group)) try: query.execute() - return True except Exception as e: out_error(e) - return False def select_roles(): diff --git a/app/modules/db/udp.py b/app/modules/db/udp.py index 779349fd..9ce8e51a 100644 --- a/app/modules/db/udp.py +++ b/app/modules/db/udp.py @@ -1,10 +1,13 @@ from app.modules.db.db_model import UDPBalancer from app.modules.db.common import out_error +from app.modules.roxywi.exception import RoxywiResourceNotFound, RoxywiGroupNotFound def select_listeners(group_id: int) -> UDPBalancer: try: return UDPBalancer.select().where(UDPBalancer.group_id == group_id).execute() + except UDPBalancer.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) @@ -12,13 +15,19 @@ def select_listeners(group_id: int) -> UDPBalancer: def insert_listener(**kwargs) -> int: try: return UDPBalancer.insert(**kwargs).execute() + except UDPBalancer.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: + if e.args[0] == 1215 or str(e) == 'FOREIGN KEY constraint failed': + raise RoxywiGroupNotFound out_error(e) def update_listener(listener_id: int, **kwargs) -> int: try: return UDPBalancer.update(**kwargs).where(UDPBalancer.id == listener_id).execute() + except UDPBalancer.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) @@ -26,6 +35,8 @@ def update_listener(listener_id: int, **kwargs) -> int: def get_listener(listener_id: int) -> UDPBalancer: try: return UDPBalancer.get(UDPBalancer.id == listener_id) + except UDPBalancer.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) @@ -33,5 +44,7 @@ def get_listener(listener_id: int) -> UDPBalancer: def delete_listener(listener_id: int) -> None: try: UDPBalancer.delete().where(UDPBalancer.id == listener_id).execute() + except UDPBalancer.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) diff --git a/app/modules/db/user.py b/app/modules/db/user.py index 0d68b7e6..8dbb47b2 100644 --- a/app/modules/db/user.py +++ b/app/modules/db/user.py @@ -1,9 +1,10 @@ from peewee import Case, JOIN -from app.modules.db.db_model import User, UserGroups, Groups, UUID, ApiToken +from app.modules.db.db_model import User, UserGroups, Groups, ApiToken from app.modules.db.sql import get_setting from app.modules.db.common import out_error import app.modules.roxy_wi_tools as roxy_wi_tools +from app.modules.roxywi.exception import RoxywiResourceNotFound def add_user(user, email, password, role, enabled, group): @@ -11,7 +12,7 @@ def add_user(user, email, password, role, enabled, group): try: hashed_pass = roxy_wi_tools.Tools.get_hash(password) last_id = User.insert( - username=user, email=email, password=hashed_pass, role=role, activeuser=enabled, groups=group + username=user, email=email, password=hashed_pass, role=role, enabled=enabled, group_id=group ).execute() except Exception as e: out_error(e) @@ -20,7 +21,7 @@ def add_user(user, email, password, role, enabled, group): else: try: last_id = User.insert( - username=user, email=email, role=role, ldap_user=1, activeuser=enabled, groups=group + username=user, email=email, role=role, ldap_user=1, enabled=enabled, group_id=group ).execute() except Exception as e: out_error(e) @@ -28,16 +29,16 @@ def add_user(user, email, password, role, enabled, group): return last_id -def update_user(user, email, role, user_id, active_user): +def update_user(user, email, role, user_id, enabled): try: - User.update(username=user, email=email, role=role, activeuser=active_user).where(User.user_id == user_id).execute() + User.update(username=user, email=email, role=role, enabled=enabled).where(User.user_id == user_id).execute() except Exception as e: out_error(e) -def update_user_from_admin_area(user, email, user_id, active_user): +def update_user_from_admin_area(user_id, **kwargs): try: - User.update(username=user, email=email, activeuser=active_user).where(User.user_id == user_id).execute() + User.update(**kwargs).where(User.user_id == user_id).execute() except Exception as e: out_error(e) @@ -53,17 +54,16 @@ def delete_user_groups(user_id): return True -def update_user_current_groups(groups, user_uuid): - user_id = get_user_id_by_uuid(user_uuid) +def update_user_current_groups(group_id: int, user_id: int) -> None: try: - User.update(groups=groups).where(User.user_id == user_id).execute() + User.update(group_id=group_id).where(User.user_id == user_id).execute() except Exception as e: out_error(e) def update_user_current_groups_by_id(groups, user_id): try: - user_update = User.update(groups=groups).where(User.user_id == user_id) + user_update = User.update(group_id=groups).where(User.user_id == user_id) user_update.execute() except Exception as e: out_error(e) @@ -111,7 +111,7 @@ def select_users(**kwargs): UserGroups.user_group_id == kwargs.get("group") )) elif kwargs.get('by_group_id'): - query = User.select().where(User.groups == kwargs.get("by_group_id")) + query = User.select().where(User.group_id == kwargs.get("by_group_id")) else: get_date = roxy_wi_tools.GetDate(get_setting('time_zone')) cur_date = get_date.return_date('regular', timedelta_minutes_minus=15) @@ -127,7 +127,7 @@ def select_users(**kwargs): def is_user_active(user_id: int) -> int: try: - query = User.get(User.user_id == user_id).activeuser + query = User.get(User.user_id == user_id).enabled except Exception as e: out_error(e) else: @@ -137,6 +137,8 @@ def is_user_active(user_id: int) -> int: def check_user_group(user_id, group_id): try: query_res = UserGroups.get((UserGroups.user_id == user_id) & (UserGroups.user_group_id == group_id)) + except UserGroups.DoesNotExist: + return False except Exception: return False else: @@ -188,55 +190,26 @@ def select_users_roles(): return query_res -def update_last_act_user(uuid: str,ip: str) -> None: +def update_last_act_user(user_id: int, ip: str) -> None: get_date = roxy_wi_tools.GetDate(get_setting('time_zone')) - session_ttl = get_setting('session_ttl') - cur_date_session = get_date.return_date('regular', timedelta=session_ttl) cur_date = get_date.return_date('regular') - user_id = get_user_id_by_uuid(uuid) try: - UUID.update(exp=cur_date_session).where(UUID.uuid == uuid).execute() User.update(last_login_date=cur_date, last_login_ip=ip).where(User.user_id == user_id).execute() except Exception as e: out_error(e) -def get_user_name_by_uuid(uuid): - try: - query = User.select(User.username).join(UUID, on=(User.user_id == UUID.user_id)).where(UUID.uuid == uuid) - query_res = query.execute() - except Exception as e: - out_error(e) - else: - for user in query_res: - return user.username - - -def get_user_id_by_uuid(uuid): - try: - query = User.select(User.user_id).join(UUID, on=(User.user_id == UUID.user_id)).where(UUID.uuid == uuid) - query_res = query.execute() - except Exception as e: - out_error(e) - else: - for user in query_res: - return user.user_id - - -def get_user_id_by_username(username: str) -> User: +def get_user_by_username(username: str) -> User: try: return User.get(User.username == username) except Exception as e: out_error(e) -def get_user_role_by_uuid(uuid, group_id): +def get_user_role_in_group(user_id, group_id): try: - query_res = UserGroups.select(UserGroups.user_role_id).join( - UUID, on=(UserGroups.user_id == UUID.user_id) - ).where( - (UUID.uuid == uuid) & - (UserGroups.user_group_id == group_id) + query_res = UserGroups.select().where( + (UserGroups.user_id == user_id) & (UserGroups.user_group_id == group_id) ).execute() except Exception as e: out_error(e) @@ -245,28 +218,9 @@ def get_user_role_by_uuid(uuid, group_id): return int(user_id.user_role_id) -def get_user_current_group_by_uuid(uuid): +def get_user_id_by_username(username: str) -> User: try: - query_res = User.select(User.groups).join( - UUID, on=(User.user_id == UUID.user_id) - ).where( - (UUID.uuid == uuid) - ).execute() - except Exception as e: - out_error(e) - else: - for user_id in query_res: - return int(user_id.groups) - - -def write_user_uuid(login, user_uuid): - session_ttl = get_setting('session_ttl') - user_id = get_user_id_by_username(login) - get_date = roxy_wi_tools.GetDate() - cur_date = get_date.return_date('regular', timedelta=session_ttl) - - try: - UUID.insert(user_id=user_id.user_id, uuid=user_uuid, exp=cur_date).execute() + return User.get(User.username == username) except Exception as e: out_error(e) @@ -304,7 +258,7 @@ def get_super_admin_count() -> int: def select_users_emails_by_group_id(group_id: int): - query = User.select(User.email).where((User.groups == group_id) & (User.role != 'guest')) + query = User.select(User.email).where((User.group_id == group_id) & (User.role != 'guest')) try: query_res = query.execute() except Exception as e: @@ -314,17 +268,6 @@ def select_users_emails_by_group_id(group_id: int): return query_res -def select_user_email_by_uuid(uuid: str) -> str: - user_id = get_user_id_by_uuid(uuid) - try: - query_res = User.get(User.user_id == user_id).email - except Exception as e: - out_error(e) - return "" - else: - return query_res - - def is_user_super_admin(user_id: int) -> bool: query = UserGroups.select().where(UserGroups.user_id == user_id) try: @@ -383,15 +326,6 @@ def get_username_group_id_from_api_token(token): return user_name.user_name, user_name.user_group_id, user_name.user_role -def delete_old_uuid(): - get_date = roxy_wi_tools.GetDate() - cur_date = get_date.return_date('regular') - try: - UUID.delete().where((UUID.exp < cur_date) | (UUID.exp.is_null(True))).execute() - except Exception as e: - out_error(e) - - def get_role_id(user_id: int, group_id: int) -> int: try: role_id = UserGroups.get((UserGroups.user_id == user_id) & (UserGroups.user_group_id == group_id)) @@ -404,5 +338,16 @@ def get_role_id(user_id: int, group_id: int) -> int: def get_user_id(user_id: int) -> User: try: return User.get(User.user_id == user_id) + except User.DoesNotExist: + raise RoxywiResourceNotFound + except Exception as e: + out_error(e) + + +def delete_user_from_group(group_id: int, user_id): + try: + UserGroups.delete().where((UserGroups.user_id == user_id) & (UserGroups.user_group_id == group_id)).execute() + except UserGroups.DoesNotExist: + raise RoxywiResourceNotFound except Exception as e: out_error(e) diff --git a/app/modules/db/waf.py b/app/modules/db/waf.py index 00ec124c..c0590884 100644 --- a/app/modules/db/waf.py +++ b/app/modules/db/waf.py @@ -46,7 +46,7 @@ def insert_waf_nginx_server(server_ip): def select_waf_servers_metrics_for_master(): query = Server.select(Server.ip).join( Waf, on=(Waf.server_id == Server.server_id) - ).where((Server.enable == 1) & Waf.metrics == 1) + ).where((Server.enabled == 1) & Waf.metrics == 1) try: query_res = query.execute() except Exception as e: @@ -58,11 +58,11 @@ def select_waf_servers_metrics_for_master(): def select_waf_servers_metrics(group_id): if group_id == '1': query = Waf.select(Server.ip).join(Server, on=(Waf.server_id == Server.server_id)).where( - (Server.enable == 1) & (Waf.metrics == 1) + (Server.enabled == 1) & (Waf.metrics == 1) ) else: query = Waf.select(Server.ip).join(Server, on=(Waf.server_id == Server.server_id)).where( - (Server.enable == 1) & (Waf.metrics == 1) & (Server.groups == group_id) + (Server.enabled == 1) & (Waf.metrics == 1) & (Server.group_id == group_id) ) try: query_res = query.execute() diff --git a/app/modules/roxywi/auth.py b/app/modules/roxywi/auth.py index f6527d2b..d512fb42 100644 --- a/app/modules/roxywi/auth.py +++ b/app/modules/roxywi/auth.py @@ -1,40 +1,38 @@ -import uuid - -from flask import request, abort, make_response, url_for -from flask_login import login_user -from datetime import datetime, timedelta +from flask import request, abort, url_for, jsonify +from flask_jwt_extended import create_access_token, set_access_cookies +from flask_jwt_extended import get_jwt +from flask_jwt_extended import verify_jwt_in_request import app.modules.db.sql as sql import app.modules.db.user as user_sql import app.modules.db.group as group_sql import app.modules.db.service as service_sql import app.modules.roxywi.common as roxywi_common +import app.modules.roxy_wi_tools as roxy_wi_tools -def check_login(user_uuid) -> str: - if user_uuid is None: +def check_login(user_id: int) -> str: + if user_id is None: return 'login_page' - if user_uuid is not None: - if user_sql.get_user_name_by_uuid(user_uuid) is None: - return 'login_page' - else: - try: - ip = request.remote_addr - except Exception: - ip = '' + if user_sql.get_user_id(user_id) is None: + return 'login_page' + else: + try: + ip = request.remote_addr + except Exception: + ip = '' - user_sql.update_last_act_user(user_uuid, ip) + user_sql.update_last_act_user(user_id, ip) - return 'ok' - return 'login_page' + return 'ok' def is_access_permit_to_service(service: str) -> bool: service_id = service_sql.select_service_id_by_slug(service) - user_uuid = request.cookies.get('uuid') - user_id = user_sql.get_user_id_by_uuid(user_uuid) - user_services = user_sql.select_user_services(user_id) + verify_jwt_in_request() + claims = get_jwt() + user_services = user_sql.select_user_services(claims['user_id']) if str(service_id) in user_services: return True else: @@ -45,11 +43,13 @@ def is_admin(level=1, **kwargs): if kwargs.get('role_id'): role = kwargs.get('role_id') else: - user_id = request.cookies.get('uuid') - group_id = request.cookies.get('group') + verify_jwt_in_request() + claims = get_jwt() + user_id = claims['user_id'] + group_id = claims['group'] try: - role = user_sql.get_user_role_by_uuid(user_id, group_id) + role = user_sql.get_user_role_in_group(user_id, group_id) except Exception: role = 4 try: @@ -60,7 +60,7 @@ def is_admin(level=1, **kwargs): def page_for_admin(level=1) -> None: if not is_admin(level=level): - return abort(404, 'Not found') + return abort(400, 'bad permission') def check_in_ldap(user, password): @@ -103,42 +103,51 @@ def check_in_ldap(user, password): return True -def create_uuid_and_token(login: str): - user_uuid = str(uuid.uuid4()) - user_sql.write_user_uuid(login, user_uuid) - - return user_uuid - - -def do_login(user_uuid: str, user_group: str, user: str, next_url: str): - try: - session_ttl = sql.get_setting('session_ttl') - except Exception: - session_ttl = 5 - if session_ttl is None: - session_ttl = 5 - +def do_login(user_params: dict, next_url: str): if next_url: redirect_to = f'https://{request.host}{next_url}' else: redirect_to = f"https://{request.host}{url_for('overview.index')}" - expires = datetime.utcnow() + timedelta(days=session_ttl) - - login_user(user) - resp = make_response(redirect_to) - resp.set_cookie('uuid', user_uuid, secure=True, expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"), samesite='Strict') - resp.set_cookie('group', str(user_group), expires=expires.strftime("%a, %d %b %Y %H:%M:%S GMT"), samesite='Strict') + response = jsonify({"status": "done", "next_url": redirect_to}) + access_token = create_jwt_token(user_params) + set_access_cookies(response, access_token) try: - user_group_name = group_sql.get_group_name_by_id(user_group) + user_group_name = group_sql.get_group_name_by_id(user_params['group']) except Exception: user_group_name = '' try: - user_name = user_sql.get_user_name_by_uuid(user_uuid) - roxywi_common.logging('Roxy-WI server', f' user: {user_name}, group: {user_group_name} login', roxywi=1) + roxywi_common.logging('RMON server', f' user: {user_params["name"]}, group: {user_group_name} login', roxywi=1) except Exception as e: print(f'error: {e}') - return resp + return response + + +def create_jwt_token(user_params: dict) -> str: + additional_claims = {'group': str(user_params['group'])} + return create_access_token(str(user_params['user']), additional_claims=additional_claims) + + +def check_user_password(login: str, password: str) -> dict: + if not login and not password: + raise Exception('There is no login or password') + try: + user = user_sql.get_user_by_username(login) + except Exception: + raise Exception('ban') + if user.enabled == 0: + raise Exception('Your login is disabled') + if user.ldap_user == 1: + if login in user.username and check_in_ldap(login, password): + return {'group': str(user.group_id), 'user': user.user_id, 'name': user.username} + else: + raise Exception('ban') + else: + hashed_password = roxy_wi_tools.Tools.get_hash(password) + if login in user.username and hashed_password == user.password: + return {'group': str(user.group_id), 'user': user.user_id, 'name': user.username} + else: + raise Exception('ban') diff --git a/app/modules/roxywi/common.py b/app/modules/roxywi/common.py index 0f86633c..1853fa45 100644 --- a/app/modules/roxywi/common.py +++ b/app/modules/roxywi/common.py @@ -2,7 +2,9 @@ import os import glob from typing import Any, Union -from flask import request +from flask import request, g +from flask_jwt_extended import get_jwt +from flask_jwt_extended import verify_jwt_in_request from app.modules.db.sql import get_setting import app.modules.db.udp as udp_sql @@ -13,6 +15,8 @@ import app.modules.db.server as server_sql import app.modules.db.history as history_sql import app.modules.db.ha_cluster as ha_sql import app.modules.roxy_wi_tools as roxy_wi_tools +from app.modules.roxywi.class_models import ErrorResponse +from app.modules.roxywi.exception import RoxywiResourceNotFound, RoxywiGroupMismatch, RoxywiGroupNotFound get_config_var = roxy_wi_tools.GetConfigVar() @@ -25,37 +29,45 @@ def get_user_group(**kwargs) -> int: user_group = '' try: - user_group_id = request.cookies.get('group') + verify_jwt_in_request() + claims = get_jwt() + user_group_id = claims['group'] groups = group_sql.select_groups(id=user_group_id) - for g in groups: - if g.group_id == int(user_group_id): + for group in groups: + if group.group_id == int(user_group_id): if kwargs.get('id'): - user_group = g.group_id + user_group = group.group_id else: - user_group = g.name + user_group = group.name except Exception as e: raise Exception(f'error: {e}') return user_group -def check_user_group_for_flask(**kwargs) -> bool: - if kwargs.get('api_token') is not None: +def check_user_group_for_flask(api_token: bool = False): + if api_token: return True - if kwargs.get('user_uuid'): - group_id = kwargs.get('user_group_id') - user_uuid = kwargs.get('user_uuid') - else: - user_uuid = request.cookies.get('uuid') - group_id = request.cookies.get('group') + verify_jwt_in_request() + claims = get_jwt() + user_id = claims['user_id'] + group_id = claims['group'] - user_id = user_sql.get_user_id_by_uuid(user_uuid) if user_sql.check_user_group(user_id, group_id): return True else: - logging('Roxy-WI server', ' has tried to actions in not his group ', roxywi=1, login=1) + logging('RMON server', 'has tried to actions in not his group', login=1) return False +def check_user_group_for_socket(user_id: int, group_id: int) -> bool: + if user_sql.check_user_group(user_id, group_id): + return True + else: + logging('RMON server', 'has tried to actions in not his group', login=1) + return False + + + def check_is_server_in_group(server_ip: str) -> bool: group_id = get_user_group(id=1) servers = server_sql.select_servers(server=server_ip) @@ -63,7 +75,7 @@ def check_is_server_in_group(server_ip: str) -> bool: if (s[2] == server_ip and int(s[3]) == int(group_id)) or group_id == 1: return True else: - logging('Roxy-WI server', ' has tried to actions in not his group server ', roxywi=1, login=1) + logging('Roxy-WI server', 'has tried to actions in not his group server', roxywi=1, login=1) return False @@ -98,6 +110,10 @@ def logging(server_ip: Union[str, int], action: str, **kwargs) -> None: get_date = roxy_wi_tools.GetDate(get_setting('time_zone')) cur_date_in_log = get_date.return_date('date_in_log') log_path = get_config_var.get_config_var('main', 'log_path') + verify_jwt_in_request() + claims = get_jwt() + user_id = claims['user_id'] + login = user_sql.get_user_id(user_id=user_id) if not os.path.exists(log_path): os.makedirs(log_path) @@ -112,25 +128,19 @@ def logging(server_ip: Union[str, int], action: str, **kwargs) -> None: except Exception: ip = '' - try: - user_uuid = request.cookies.get('uuid') - login = user_sql.get_user_name_by_uuid(user_uuid) - except Exception: - login = '' - if kwargs.get('roxywi') == 1: if kwargs.get('login'): - mess = f"{cur_date_in_log} from {ip} user: {login}, group: {user_group}, {action} on: {server_ip}\n" + mess = f"{cur_date_in_log} from {ip} user: {login.username}, group: {user_group}, {action} on: {server_ip}\n" else: mess = f"{cur_date_in_log} {action} from {ip}\n" log_file = f"{log_path}/roxy-wi.log" else: - mess = f"{cur_date_in_log} from {ip} user: {login}, group: {user_group}, {action} on: {server_ip} {kwargs.get('service')}\n" + mess = f"{cur_date_in_log} from {ip} user: {login.username}, group: {user_group}, {action} on: {server_ip} {kwargs.get('service')}\n" log_file = f"{log_path}/config_edit.log" if kwargs.get('keep_history'): try: - keep_action_history(kwargs.get('service'), action, server_ip, login, ip) + keep_action_history(kwargs.get('service'), action, server_ip, login.username, ip) except Exception as e: print(f'error: Cannot save history: {e}') @@ -198,34 +208,22 @@ def get_dick_permit(**kwargs): def get_users_params(**kwargs): + verify_jwt_in_request() + user_data = get_jwt() + try: - user_uuid = request.cookies.get('uuid') - user = user_sql.get_user_name_by_uuid(user_uuid) + user_id = user_data['user_id'] + user = user_sql.get_user_id(user_id) except Exception: - raise Exception('error: Cannot get user UUID') + raise Exception('error: Cannot get user id') + + if int(user_data['group']) != int(user.group_id): + raise Exception('error: Wrong active group') try: - group_id = user_sql.get_user_current_group_by_uuid(user_uuid) + role = user_sql.get_role_id(user_id, user.group_id) except Exception as e: - raise Exception(f'error: Cannot get user group: {e}') - - try: - group_id_from_cookies = int(request.cookies.get('group')) - except Exception as e: - raise Exception(f'error: Cannot get group id from cookies: {e}') - - if group_id_from_cookies != group_id: - raise Exception('error: Wrong current group') - - try: - role = user_sql.get_user_role_by_uuid(user_uuid, group_id) - except Exception: - raise Exception('error: Cannot get user role') - - try: - user_id = user_sql.get_user_id_by_uuid(user_uuid) - except Exception as e: - raise Exception(f'error: Cannot get user id {e}') + raise Exception(f'error: Cannot get user role {e}') try: user_services = user_sql.select_user_services(user_id) @@ -246,14 +244,13 @@ def get_users_params(**kwargs): user_lang = get_user_lang_for_flask() user_params = { - 'user': user, - 'user_uuid': user_uuid, + 'user': user.username, 'role': role, 'servers': servers, 'user_services': user_services, 'lang': user_lang, 'user_id': user_id, - 'group_id': group_id + 'group_id': user.group_id } return user_params @@ -305,9 +302,33 @@ def handle_exceptions(ex: Exception, server_ip: str, message: str, **kwargs: Any """ logging(server_ip, f'error: {message}: {ex}', **kwargs) - raise Exception(f'error: {message}: {ex}') + raise Exception(f'{message}: {ex}') +def is_user_has_access_to_its_group(user_id: int) -> None: + if not user_sql.check_user_group(user_id, g.user_params['group_id']) and g.user_params['role'] != 1: + raise RoxywiGroupMismatch + + +def is_user_has_access_to_group(user_id: int, group_id: int) -> None: + if not user_sql.check_user_group(user_id, group_id) and g.user_params['role'] != 1: + raise RoxywiGroupMismatch + def handle_json_exceptions(ex: Exception, message: str, server_ip='Roxy-WI server') -> dict: - logging(server_ip, f'error: {message}: {ex}', roxywi=1, login=1) - return {'status': 'failed', 'error': f'{message}: {ex}'} + logging(server_ip, f'{message}: {ex}', login=1, roxywi=1) + return ErrorResponse(error=f'{message}: {ex}').model_dump(mode='json') + + +def handler_exceptions_for_json_data(ex: Exception, main_ex_mes: str) -> tuple[dict, int]: + if isinstance(ex, KeyError): + return handle_json_exceptions(ex, 'Missing key in JSON data'), 500 + elif isinstance(ex, ValueError): + return handle_json_exceptions(ex, 'Wrong type or missing value in JSON data'), 500 + elif isinstance(ex, RoxywiResourceNotFound): + return handle_json_exceptions(ex, 'Resource not found'), 404 + elif isinstance(ex, RoxywiGroupNotFound): + return handle_json_exceptions(ex, 'Group not found'), 404 + elif isinstance(ex, RoxywiGroupMismatch): + return handle_json_exceptions(ex, 'Resource not found in group'), 404 + else: + return handle_json_exceptions(ex, main_ex_mes), 500 diff --git a/app/modules/roxywi/overview.py b/app/modules/roxywi/overview.py index d1ea6f35..c3ee7e6b 100644 --- a/app/modules/roxywi/overview.py +++ b/app/modules/roxywi/overview.py @@ -1,6 +1,8 @@ import psutil import requests from flask import render_template, request +from flask_jwt_extended import get_jwt +from flask_jwt_extended import verify_jwt_in_request import app.modules.db.sql as sql import app.modules.db.waf as waf_sql @@ -40,13 +42,12 @@ def show_sub_ovw() -> str: def show_overview(serv) -> str: servers = [] - user_uuid = request.cookies.get('uuid') - group_id = request.cookies.get('group') + verify_jwt_in_request() + claims = get_jwt() lang = roxywi_common.get_user_lang_for_flask() - role = user_sql.get_user_role_by_uuid(user_uuid, group_id) + role = user_sql.get_user_role_in_group(claims['user_id'], claims['group']) server = [server for server in server_sql.select_servers(server=serv)] - user_id = user_sql.get_user_id_by_uuid(user_uuid) - user_services = user_sql.select_user_services(user_id) + user_services = user_sql.select_user_services(claims['user_id']) haproxy = service_sql.select_haproxy(serv) if '1' in user_services else 0 nginx = service_sql.select_nginx(serv) if '2' in user_services else 0 diff --git a/app/modules/roxywi/user.py b/app/modules/roxywi/user.py index 77735034..55cd2dce 100644 --- a/app/modules/roxywi/user.py +++ b/app/modules/roxywi/user.py @@ -45,18 +45,7 @@ def delete_user(user_id: int): roxywi_common.logging(user.username, 'has been deleted user', roxywi=1, login=1) -def update_user(email, new_user, user_id, enabled, group_id, role_id): - try: - user_sql.update_user(new_user, email, role_id, user_id, enabled) - except Exception as e: - roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot update user {new_user}', roxywi=1, login=1) - user_sql.update_user_role(user_id, group_id, role_id) - roxywi_common.logging(new_user, ' has been updated user ', roxywi=1, login=1) - - -def update_user_password(password: str, uuid: str, user_id: int): - if uuid: - user_id = user_sql.get_user_id_by_uuid(uuid) +def update_user_password(password, user_id): user = user_sql.get_user_id(user_id) user_sql.update_user_password(password, user_id) roxywi_common.logging(f'user {user.username}', 'has changed password', roxywi=1, login=1) @@ -85,36 +74,36 @@ def change_user_services(user: str, user_id: int, user_services: dict): roxywi_common.logging('Roxy-WI server', f'Access to the services has been updated for user: {user}', roxywi=1, login=1) -def change_user_active_group(group_id: int, user_uuid: str) -> str: +def change_user_active_group(group_id: int, user_id: int) -> str: try: - user_sql.update_user_current_groups(group_id, user_uuid) + user_sql.update_user_current_groups(group_id, user_id) return 'Ok' except Exception as e: roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot change the group', roxywi=1, login=1) -def get_user_active_group(uuid: str, group: str) -> str: - group_id = user_sql.get_user_id_by_uuid(uuid) - groups = user_sql.select_user_groups_with_names(group_id) +def get_user_active_group(group_id: int, user_id: int) -> str: + # group_id = user_sql.get_user_id_by_uuid(uuid) + groups = user_sql.select_user_groups_with_names(user_id) lang = roxywi_common.get_user_lang_for_flask() - return render_template('ajax/user_current_group.html', groups=groups, group=group, id=group_id, lang=lang) + return render_template('ajax/user_current_group.html', groups=groups, group=group_id, lang=lang) -def show_user_groups_and_roles(user_id: int, lang: str) -> str: - groups = user_sql.select_user_groups_with_names(user_id, user_not_in_group=1) - roles = sql.select_roles() - user_groups = user_sql.select_user_groups_with_names(user_id) - return render_template('ajax/user_groups_and_roles.html', groups=groups, user_groups=user_groups, roles=roles, lang=lang) +# def show_user_groups_and_roles(user_id: int, lang: str) -> str: +# groups = user_sql.select_user_groups_with_names(user_id, user_not_in_group=1) +# roles = sql.select_roles() +# user_groups = user_sql.select_user_groups_with_names(user_id) +# return render_template('ajax/user_groups_and_roles.html', groups=groups, user_groups=user_groups, roles=roles, lang=lang) -def is_current_user(user_id: int, user_uuid: str) -> bool: - current_user_id = user_sql.get_user_id_by_uuid(user_uuid) - if current_user_id == user_id: - return True - return False +# def is_current_user(user_id: int, user_uuid: str) -> bool: +# current_user_id = user_sql.get_user_id_by_uuid(user_uuid) +# if current_user_id == user_id: +# return True +# return False -def save_user_group_and_role(user: str, groups_and_roles: dict, user_uuid: str): +def save_user_group_and_role(user: str, groups_and_roles: dict): resp = make_response('ok') for k, v in groups_and_roles.items(): user_id = int(k) @@ -125,8 +114,7 @@ def save_user_group_and_role(user: str, groups_and_roles: dict, user_uuid: str): role_id = int(v2['role_id']) if len(v) == 1: user_sql.update_user_current_groups_by_id(group_id, user_id) - if is_current_user(user_id, user_uuid): - resp.set_cookie('group', str(group_id), secure=True) + resp.set_cookie('group', str(group_id), secure=True) try: user_sql.update_user_role(user_id, group_id, role_id) except Exception as e: diff --git a/app/modules/roxywi/waf.py b/app/modules/roxywi/waf.py index 14430208..86f6afde 100644 --- a/app/modules/roxywi/waf.py +++ b/app/modules/roxywi/waf.py @@ -1,4 +1,4 @@ -from flask import render_template, request +from flask import render_template import app.modules.db.sql as sql import app.modules.db.waf as waf_sql @@ -10,11 +10,9 @@ import app.modules.server.server as server_mod import app.modules.roxywi.common as roxywi_common -def waf_overview(serv, waf_service) -> str: +def waf_overview(serv: str, waf_service: str, claims: dict) -> str: servers = server_sql.select_servers(server=serv) - user_id = request.cookies.get('uuid') - group_id = int(request.cookies.get('group')) - role = user_sql.get_user_role_by_uuid(user_id, group_id) + role = user_sql.get_user_role_in_group(claims['user_id'], claims['group']) returned_servers = [] waf = '' metrics_en = 0 diff --git a/app/modules/server/server.py b/app/modules/server/server.py index 73277dd4..61f06885 100644 --- a/app/modules/server/server.py +++ b/app/modules/server/server.py @@ -414,11 +414,11 @@ def show_firewalld_rules(server_ip) -> str: return render_template('ajax/firewall_rules.html', input_chain=input_chain2, IN_public_allow=in_public_allow, output_chain=output_chain, lang=lang) -def create_server(hostname, ip, group, typeip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall, **kwargs) -> int: +def create_server(hostname, ip, group, type_ip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall, **kwargs) -> int: if not roxywi_auth.is_admin(level=2, role_id=kwargs.get('role_id')): raise Exception('error: not enough permission') - last_id = server_sql.add_server(hostname, ip, group, typeip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall) + last_id = server_sql.add_server(hostname, ip, group, type_ip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall) return last_id diff --git a/app/modules/server/ssh.py b/app/modules/server/ssh.py index 3972752a..997db5d1 100644 --- a/app/modules/server/ssh.py +++ b/app/modules/server/ssh.py @@ -2,7 +2,7 @@ import os from cryptography.fernet import Fernet import paramiko -from flask import render_template, request +from flask import render_template import app.modules.db.cred as cred_sql import app.modules.db.group as group_sql @@ -11,6 +11,7 @@ import app.modules.common.common as common from app.modules.server import ssh_connection import app.modules.roxywi.common as roxywi_common import app.modules.roxy_wi_tools as roxy_wi_tools +from app.modules.roxywi.class_models import IdResponse, IdDataResponse error_mess = common.error_mess get_config = roxy_wi_tools.GetConfigVar() @@ -40,10 +41,10 @@ def return_ssh_keys_path(server_ip: str, **kwargs) -> dict: else: passphrase = ssh.passphrase - ssh_settings.setdefault('enabled', ssh.enable) + ssh_settings.setdefault('enabled', ssh.key_enabled) ssh_settings.setdefault('user', ssh.username) ssh_settings.setdefault('password', password) - ssh_key = f'{lib_path}/keys/{ssh.name}.pem' if ssh.enable == 1 else '' + ssh_key = f'{lib_path}/keys/{ssh.name}.pem' if ssh.key_enabled == 1 else '' ssh_settings.setdefault('key', ssh_key) ssh_settings.setdefault('passphrase', passphrase) @@ -63,32 +64,29 @@ def ssh_connect(server_ip): return ssh -def create_ssh_cred(json_data: dict) -> dict: - name = common.checkAjaxInput(json_data['ssh']) - enable = int(json_data['enabled']) - group = common.checkAjaxInput(json_data['group']) +def create_ssh_cred(name: str, password: str, group: int, username: str, enable: int, is_api: int) -> dict: group_name = group_sql.get_group_name_by_id(group) - username = common.checkAjaxInput(json_data['user']) - password = common.checkAjaxInput(json_data['pass']) lang = roxywi_common.get_user_lang_for_flask() name = f'{name}_{group_name}' - - if password != '': + if password and password != "''": try: password = crypt_password(password) except Exception as e: raise Exception(e) - - if username is None or name is None: - return error_mess + else: + password = '' try: last_id = cred_sql.insert_new_ssh(name, enable, group, username, password) except Exception as e: - roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot create new SSH credentials', roxywi=1, login=1) - roxywi_common.logging('Roxy-WI server', f'New SSH credentials {name} has been created', roxywi=1, login=1) - rendered_template = render_template('ajax/new_ssh.html', groups=group_sql.select_groups(), sshs=cred_sql.select_ssh(name=name), lang=lang) - return {'id': last_id, 'template': rendered_template} + return roxywi_common.handle_json_exceptions(e, 'Cannot create new SSH credentials') + roxywi_common.logging('RMON server', f'New SSH credentials {name} has been created', roxywi=1, login=1) + + if is_api: + return IdResponse(id=last_id).model_dump(mode='json') + else: + data = render_template('ajax/new_ssh.html', groups=group_sql.select_groups(), sshs=cred_sql.select_ssh(name=name), lang=lang) + return IdDataResponse(id=last_id, data=data).model_dump(mode='json') def create_ssh_cred_api(name: str, enable: str, group: str, username: str, password: str) -> bool: @@ -116,30 +114,28 @@ def create_ssh_cred_api(name: str, enable: str, group: str, username: str, passw roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot create SSH credentials {name}', roxywi=1) -def upload_ssh_key(name: str, user_group: int, key: str, passphrase: str) -> str: - if '..' in name: - raise Exception('error: nice try') - - if name == '': - raise Exception('error: please select credentials first') +def upload_ssh_key(ssh_id: int, key: str, passphrase: str) -> None: + key = key.replace("'", "") + ssh = cred_sql.get_ssh(ssh_id) + group_name = group_sql.get_group_name_by_id(ssh.group_id) + lib_path = get_config.get_config_var('main', 'lib_path') + full_dir = f'{lib_path}/keys/' + name = ssh.name + ssh_keys = f'{name}.pem' try: key = paramiko.pkey.load_private_key(key, password=passphrase) except Exception as e: - raise Exception(f'error: Cannot save SSH key file: {e}') - - lib_path = get_config.get_config_var('main', 'lib_path') - full_dir = f'{lib_path}/keys/' - ssh_keys = f'{name}.pem' + raise Exception(e) try: - _check_split = name.split('_')[1] + _ = name.split('_')[1] split_name = True except Exception: split_name = False if not os.path.isfile(ssh_keys) and not split_name: - name = f'{name}_{user_group}' + name = f'{ssh.name}_{group_name}' if not os.path.exists(full_dir): os.makedirs(full_dir) @@ -149,38 +145,35 @@ def upload_ssh_key(name: str, user_group: int, key: str, passphrase: str) -> str try: key.write_private_key_file(ssh_keys) except Exception as e: - raise Exception(f'error: Cannot save SSH key file: {e}') + raise Exception(e) + try: os.chmod(ssh_keys, 0o600) except IOError as e: - roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1) - raise Exception(f'error: something went wrong: {e}') + roxywi_common.logging('RMON server', e.args[0], roxywi=1) + raise Exception(e) - if passphrase != '': + if passphrase != "''": try: passphrase = crypt_password(passphrase) except Exception as e: raise Exception(e) + else: + passphrase = '' try: - cred_sql.update_ssh_passphrase(name, passphrase) + cred_sql.update_ssh_passphrase(ssh_id, passphrase) except Exception as e: raise Exception(e) - roxywi_common.logging("Roxy-WI server", f"A new SSH cert has been uploaded {ssh_keys}", roxywi=1, login=1) - return f'success: SSH key has been saved into: {ssh_keys}' + roxywi_common.logging("RMON server", f"A new SSH cert has been uploaded {ssh_keys}", roxywi=1, login=1) -def update_ssh_key(json_data: dict): - ssh_id = int(json_data['id']) - name = common.checkAjaxInput(json_data['name']) - enable = common.checkAjaxInput(json_data['ssh_enable']) - group = int(json_data['group']) - username = common.checkAjaxInput(json_data['ssh_user']) - password = common.checkAjaxInput(json_data['ssh_pass']) - new_ssh_key_name = '' - ssh_key_name = '' - ssh_enable = 0 +def update_ssh_key(ssh_id: int, name: str, password: str, enable: int, username: str, group: int) -> None: + lib_path = get_config.get_config_var('main', 'lib_path') + ssh = cred_sql.get_ssh(ssh_id) + ssh_key_name = f'{lib_path}/keys/{ssh.name}.pem' + new_ssh_key_name = f'{lib_path}/keys/{name}.pem' if password != '': try: @@ -188,22 +181,15 @@ def update_ssh_key(json_data: dict): except Exception as e: raise Exception(e) - if username is None: - return error_mess - - lib_path = get_config.get_config_var('main', 'lib_path') - - for sshs in cred_sql.select_ssh(id=ssh_id): - ssh_enable = sshs.enable - ssh_key_name = f'{lib_path}/keys/{sshs.name}.pem' - new_ssh_key_name = f'{lib_path}/keys/{name}.pem' - - if ssh_enable == 1: + if ssh.key_enabled == 1 and os.path.isfile(ssh_key_name): os.rename(ssh_key_name, new_ssh_key_name) os.chmod(new_ssh_key_name, 0o600) - cred_sql.update_ssh(ssh_id, name, enable, group, username, password) - roxywi_common.logging('Roxy-WI server', f'The SSH credentials {name} has been updated ', roxywi=1, login=1) + try: + cred_sql.update_ssh(ssh_id, name, enable, group, username, password) + roxywi_common.logging('RMON server', f'The SSH credentials {name} has been updated ', roxywi=1, login=1) + except Exception as e: + raise Exception(e) def delete_ssh_key(ssh_id) -> str: @@ -213,7 +199,7 @@ def delete_ssh_key(ssh_id) -> str: ssh_key_name = '' for sshs in cred_sql.select_ssh(id=ssh_id): - ssh_enable = sshs.enable + ssh_enable = sshs.key_enabled name = sshs.name ssh_key_name = f'{lib_path}/keys/{sshs.name}.pem' diff --git a/app/modules/service/action.py b/app/modules/service/action.py index 11255466..c5440678 100644 --- a/app/modules/service/action.py +++ b/app/modules/service/action.py @@ -1,8 +1,4 @@ -import socket -from contextlib import closing - import app.modules.db.sql as sql -import app.modules.db.user as user_sql import app.modules.db.server as server_sql import app.modules.db.service as service_sql import app.modules.common.common as common @@ -11,7 +7,7 @@ import app.modules.roxywi.common as roxywi_common import app.modules.service.common as service_common -def common_action(server_ip: str, action: str, service: str) -> str: +def common_action(server_ip: str, action: str, service: str) -> None: action_functions = { 'haproxy': service_action, 'nginx': service_action, @@ -21,11 +17,13 @@ def common_action(server_ip: str, action: str, service: str) -> str: 'waf_nginx': action_nginx_waf } - return action_functions[service](server_ip, action, service) + try: + action_functions[service](server_ip, action, service) + except Exception as e: + raise e - -def service_action(server_ip: str, action: str, service: str) -> str: +def service_action(server_ip: str, action: str, service: str) -> None: """ :param server_ip: The IP address of the server on which the action will be performed. :param action: The action to be performed on the service (e.g., "start", "stop"). @@ -35,25 +33,21 @@ def service_action(server_ip: str, action: str, service: str) -> str: try: service_common.is_protected(server_ip, action) except Exception as e: - return str(e) + raise e server_id = server_sql.select_server_id_by_ip(server_ip=server_ip) if service_common.is_not_allowed_to_restart(server_id, service, action): - return 'error: This server is not allowed to be restarted' + raise Exception('This server is not allowed to be restarted') try: if service != 'keepalived': service_common.check_service_config(server_ip, server_id, service) except Exception as e: - return f'error: Cannot check config: {e}' + raise Exception(f'Cannot check config: {e}') command = get_action_command(service, action, server_id) - try: - server_mod.ssh_command(server_ip, command) - roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service=service) - return f"success: {service.title()} has been {action}" - except Exception as e: - return f"error: Cannot {action} {service.title()}: {e}" + server_mod.ssh_command(server_ip, command) + roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service=service) def get_action_command(service: str, action: str, server_id: int) -> str: @@ -77,29 +71,26 @@ def get_action_command(service: str, action: str, server_id: int) -> str: return commands -def action_haproxy_waf(server_ip: str, action: str, service: str) -> str: +def action_haproxy_waf(server_ip: str, action: str, service: str) -> None: try: service_common.is_protected(server_ip, action) except Exception as e: - return str(e) + raise e roxywi_common.logging( server_ip, f'HAProxy WAF service has been {action}ed', roxywi=1, login=1, keep_history=1, service='haproxy' ) command = f"sudo systemctl {action} waf" - try: - server_mod.ssh_command(server_ip, command) - return f"success: WAF has been {action}" - except Exception as e: - return f"error: Cannot {action} WAF service: {e}" + server_mod.ssh_command(server_ip, command) -def action_nginx_waf(server_ip: str, action: str, service: str) -> str: + +def action_nginx_waf(server_ip: str, action: str, service: str) -> None: config_dir = common.return_nice_path(sql.get_setting('nginx_dir')) try: service_common.is_protected(server_ip, action) except Exception as e: - return str(e) + raise e waf_new_state = 'on' if action == 'start' else 'off' waf_old_state = 'off' if action == 'start' else 'on' @@ -108,37 +99,32 @@ def action_nginx_waf(server_ip: str, action: str, service: str) -> str: command = (f"sudo sed -i 's/modsecurity {waf_old_state}/modsecurity {waf_new_state}/g' {config_dir}nginx.conf " f"&& sudo systemctl reload nginx") - try: - server_mod.ssh_command(server_ip, command) - return f"success: WAF has been {action}" - except Exception as e: - return f"error: Cannot {action} WAF service: {e}" + server_mod.ssh_command(server_ip, command) -def check_service(server_ip: str, user_uuid: str, service: str) -> str: - user_id = user_sql.get_user_id_by_uuid(user_uuid) - user_services = user_sql.select_user_services(user_id) - - if '1' in user_services: - if service == 'haproxy': - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - cmd = 'echo "show info" |nc %s %s -w 1 -v|grep Name' % (server_ip, haproxy_sock_port) - out = server_mod.subprocess_execute(cmd) - for k in out[0]: - if "Name" in k: - return 'up' - else: - return 'down' - if ('2' in user_services and service == 'nginx') or ('4' in user_services and service == 'apache'): - stats_port = sql.get_setting(f'{service}_stats_port') - - with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: - sock.settimeout(5) - - try: - if sock.connect_ex((server_ip, stats_port)) == 0: - return 'up' - else: - return 'down' - except Exception as e: - return f'down {e}' +# def check_service(server_ip: str, user_id: int, service: str) -> str: +# user_services = user_sql.select_user_services(user_id) +# +# if '1' in user_services: +# if service == 'haproxy': +# haproxy_sock_port = sql.get_setting('haproxy_sock_port') +# cmd = 'echo "show info" |nc %s %s -w 1 -v|grep Name' % (server_ip, haproxy_sock_port) +# out = server_mod.subprocess_execute(cmd) +# for k in out[0]: +# if "Name" in k: +# return 'up' +# else: +# return 'down' +# if ('2' in user_services and service == 'nginx') or ('4' in user_services and service == 'apache'): +# stats_port = sql.get_setting(f'{service}_stats_port') +# +# with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: +# sock.settimeout(5) +# +# try: +# if sock.connect_ex((server_ip, stats_port)) == 0: +# return 'up' +# else: +# return 'down' +# except Exception as e: +# return f'down {e}' diff --git a/app/modules/service/backup.py b/app/modules/service/backup.py index 97d6e123..5d749863 100644 --- a/app/modules/service/backup.py +++ b/app/modules/service/backup.py @@ -1,5 +1,3 @@ -import os - from flask import render_template import app.modules.db.sql as sql @@ -8,102 +6,42 @@ import app.modules.db.backup as backup_sql import app.modules.db.server as server_sql import app.modules.db.service as service_sql import app.modules.server.ssh as ssh_mod -import app.modules.server.server as server_mod -import app.modules.common.common as common import app.modules.roxywi.common as roxywi_common import app.modules.service.installation as installation_mod +from app.modules.roxywi.class_models import BackupRequest, IdResponse, IdDataResponse, BaseResponse, S3BackupRequest -def delete_backup(serv: str, backup_id: int) -> None: - if backup_sql.check_exists_backup(serv): - raise Exception(f'Backup job for {serv} already exists') - - backup_sql.delete_backups(backup_id) - roxywi_common.logging('backup ', f' a backup job for server {serv} has been deleted', roxywi=1, login=1) - - -def backup(json_data) -> str: - cred = int(json_data['cred']) - server = common.is_ip_or_dns(json_data['server']) - rserver = common.is_ip_or_dns(json_data['rserver']) - ssh_settings = ssh_mod.return_ssh_keys_path(rserver, id=cred) - update_id = '' - description = '' - if 'del_id' in json_data: - time = '' - rpath = '' - backup_type = '' - del_id = int(json_data['del_id']) - else: - del_id = '' - rpath = common.checkAjaxInput(json_data['rpath']) - backup_type = common.checkAjaxInput(json_data['type']) - time = common.checkAjaxInput(json_data['time']) - description = common.checkAjaxInput(json_data['description']) - if backup_sql.check_exists_backup(server): - return f'warning: Backup job for {server} already exists' - - if 'update_id' in json_data: - update_id = int(json_data['update_id']) - +def create_backup_inv(json_data: BackupRequest, del_id: int = 0) -> None: + ssh_settings = ssh_mod.return_ssh_keys_path(str(json_data.server), id=json_data.cred_id) inv = {"server": {"hosts": {}}} server_ips = [] - inv['server']['hosts'][server] = { - 'HOST': rserver, - "SERVER": server, - "TYPE": backup_type, - "TIME": time, - "RPATH": rpath, + inv['server']['hosts'][str(json_data.server)] = { + 'HOST': str(json_data.rserver), + "SERVER": str(json_data.server), + "TYPE": json_data.type, + "TIME": json_data.time, + "RPATH": json_data.rpath, "DELJOB": del_id, "USER": ssh_settings['user'], "KEY": ssh_settings['key'] } - server_ips.append(server) + server_ips.append(str(json_data.server)) try: installation_mod.run_ansible(inv, server_ips, 'backup') except Exception as e: raise Exception(f'error: {e}') - if not del_id and not update_id: - if backup_sql.insert_backup_job(server, rserver, rpath, backup_type, time, cred, description): - roxywi_common.logging('backup ', f' a new backup job for server {server} has been created', roxywi=1, - login=1) - return render_template( - 'ajax/new_backup.html', backups=backup_sql.select_backups(server=server, rserver=rserver), sshs=cred_sql.select_ssh() - ) - - else: - raise Exception('Cannot add the job into DB') - elif del_id: - backup_sql.delete_backups(del_id) - roxywi_common.logging('backup ', f' a backup job for server {server} has been deleted', roxywi=1, login=1) - return 'ok' - elif update_id: - backup_sql.update_backup(server, rserver, rpath, backup_type, time, cred, description, update_id) - roxywi_common.logging('backup ', f' a backup job for server {server} has been updated', roxywi=1, login=1) - return 'ok' - - -def s3_backup(server, s3_server, bucket, secret_key, access_key, time, deljob, description) -> str: - if deljob: - time = '' - secret_key = '' - access_key = '' - tag = 'delete' - else: - tag = 'add' - if backup_sql.check_exists_s3_backup(server): - raise Exception(f'error: Backup job for {server} already exists') +def create_s3_backup_inv(data: S3BackupRequest, tag: str) -> None: inv = {"server": {"hosts": {}}} inv["server"]["hosts"]["localhost"] = { - "SERVER": server, - "S3_SERVER": s3_server, - "BUCKET": bucket, - "SECRET_KEY": secret_key, - "ACCESS_KEY": access_key, - "TIME": time, + "SERVER": str(data.server), + "S3_SERVER": str(data.s3_server), + "BUCKET": data.bucket, + "SECRET_KEY": data.secret_key, + "ACCESS_KEY": data.access_key, + "TIME": data.time, "action": tag } @@ -112,17 +50,85 @@ def s3_backup(server, s3_server, bucket, secret_key, access_key, time, deljob, d except Exception as e: raise Exception(f'error: {e}') - if not deljob: - try: - backup_sql.insert_s3_backup_job(server, s3_server, bucket, secret_key, access_key, time, description) - except Exception as e: - raise Exception(e) - roxywi_common.logging('backup ', f' a new S3 backup job for server {server} has been created', roxywi=1, login=1) - return render_template('ajax/new_s3_backup.html', backups=backup_sql.select_s3_backups(server=server, s3_server=s3_server, bucket=bucket)) - elif deljob: - backup_sql.delete_s3_backups(deljob) - roxywi_common.logging('backup ', f' a S3 backup job for server {server} has been deleted', roxywi=1, login=1) - return 'ok' + +def create_backup(json_data: BackupRequest, is_api: bool) -> tuple: + if backup_sql.check_exists_backup(json_data.server): + raise Exception(f'warning: Backup job for {json_data.server} already exists') + + create_backup_inv(json_data) + + last_id = backup_sql.insert_backup_job(json_data.server, json_data.rserver, json_data.rpath, json_data.type, + json_data.time, json_data.cred_id, json_data.description) + roxywi_common.logging('backup ', f' a new backup job for server {json_data.server} has been created', roxywi=1, login=1) + if is_api: + return IdResponse(id=last_id).model_dump(mode='json'), 201 + else: + data = render_template( + 'ajax/new_backup.html', + backups=backup_sql.select_backups(server=json_data.server, rserver=json_data.rserver), + sshs=cred_sql.select_ssh() + ) + return IdDataResponse(data=data, id=last_id).model_dump(mode='json'), 201 + + + +def delete_backup(json_data: BackupRequest, backup_id: int) -> tuple: + create_backup_inv(json_data, backup_id) + backup_sql.delete_backups(backup_id) + roxywi_common.logging('backup ', f' a backup job for server {json_data.server} has been deleted', roxywi=1, login=1) + return BaseResponse().model_dump(mode='json'), 204 + + +def update_backup(json_data: BackupRequest, backup_id: int) -> tuple: + create_backup_inv(json_data) + backup_sql.update_backup(json_data.server, json_data.rserver, json_data.rpath, json_data.type, + json_data.time, json_data.cred_id, json_data.description, backup_id) + roxywi_common.logging('backup ', f' a backup job for server {json_data.server} has been updated', roxywi=1, login=1) + return BaseResponse().model_dump(mode='json'), 201 + + +def create_s3_backup(data: S3BackupRequest, is_api: bool) -> tuple: + # if deljob: + # time = '' + # secret_key = '' + # access_key = '' + # tag = 'delete' + # else: + # tag = 'add' + if backup_sql.check_exists_s3_backup(data.server): + raise Exception(f'Backup job for {data.server} already exists') + + try: + create_s3_backup_inv(data, 'add') + except Exception as e: + raise e + + # if not deljob: + try: + last_id = backup_sql.insert_s3_backup_job(**data.model_dump(mode='json')) + roxywi_common.logging('backup ', f'a new S3 backup job for server {data.server} has been created', roxywi=1, login=1) + except Exception as e: + raise Exception(e) + + if is_api: + return IdResponse(id=last_id).model_dump(mode='json'), 201 + else: + temp = render_template('ajax/new_s3_backup.html', backups=backup_sql.select_s3_backups(**data.model_dump(mode='json'))) + return IdDataResponse(id=last_id, data=temp).model_dump(mode='json'), 201 + # elif deljob: + # backup_sql.delete_s3_backups(deljob) + # roxywi_common.logging('backup ', f' a S3 backup job for server {server} has been deleted', roxywi=1, login=1) + # return 'ok' + + + +def delete_s3_backup(data: S3BackupRequest, backup_id: int) -> None: + try: + create_s3_backup_inv(data, 'delete') + backup_sql.delete_s3_backups(backup_id) + roxywi_common.logging('backup ', f'a S3 backup job for server {data.server} has been deleted', roxywi=1, login=1) + except Exception as e: + raise e def git_backup(server_id, service_id, git_init, repo, branch, period, cred, del_job, description, backup_id) -> str: diff --git a/app/modules/service/common.py b/app/modules/service/common.py index add774ba..cc1965c4 100644 --- a/app/modules/service/common.py +++ b/app/modules/service/common.py @@ -1,5 +1,7 @@ import requests from flask import render_template, request +from flask_jwt_extended import get_jwt +from flask_jwt_extended import verify_jwt_in_request import app.modules.db.sql as sql import app.modules.db.user as user_sql @@ -32,15 +34,15 @@ def get_correct_service_name(service: str, server_id: int) -> str: return service -def check_haproxy_version(server_ip): - hap_sock_p = sql.get_setting('haproxy_sock_port') - ver = "" - cmd = f"echo 'show info' |nc {server_ip} {hap_sock_p} |grep Version |awk '{{print $2}}'" - output, stderr = server_mod.subprocess_execute(cmd) - for line in output: - ver = line - - return ver +# def check_haproxy_version(server_ip): +# hap_sock_p = sql.get_setting('haproxy_sock_port') +# ver = "" +# cmd = f"echo 'show info' |nc {server_ip} {hap_sock_p} |grep Version |awk '{{print $2}}'" +# output, stderr = server_mod.subprocess_execute(cmd) +# for line in output: +# ver = line +# +# return ver def is_protected(server_ip: str, action: str) -> None: @@ -52,9 +54,9 @@ def is_protected(server_ip: str, action: str) -> None: :return: None :raises: Exception if the server is protected and the user role is not high enough. """ - user_uuid = request.cookies.get('uuid') - group_id = int(request.cookies.get('group')) - user_role = user_sql.get_user_role_by_uuid(user_uuid, group_id) + verify_jwt_in_request() + claims = get_jwt() + user_role = user_sql.get_user_role_in_group(claims['user_id'], claims['group']) if server_sql.is_serv_protected(server_ip) and int(user_role) > 2: raise Exception(f'error: This server is protected. You cannot {action} it') @@ -187,11 +189,9 @@ def check_service_config(server_ip: str, server_id: int, service: str) -> None: def overview_backends(server_ip: str, service: str) -> str: - import modules.config.config as config_mod + import app.modules.config.config as config_mod - lang = roxywi_common.get_user_lang_for_flask() - - if service != 'nginx' and service != 'apache': + if service not in ('nginx', 'apache'): format_file = config_common.get_file_format(service) config_dir = config_common.get_config_dir(service) cfg = config_common.generate_config_path(service, server_ip) @@ -204,16 +204,24 @@ def overview_backends(server_ip: str, service: str) -> str: try: config_mod.get_config(server_ip, cfg, service=service) except Exception as e: - roxywi_common.logging('Roxy-WI server', f' Cannot download a config {e}', roxywi=1) + raise e try: sections = section_mod.get_sections(cfg, service=service) except Exception as e: - roxywi_common.logging('Roxy-WI server', f' Cannot get sections from config file {e}', roxywi=1) - sections = f'error: Cannot get backends {e}' + raise e else: - sections = section_mod.get_remote_sections(server_ip, service) + sections = {} + sections_not_formated = section_mod.get_remote_sections(server_ip, service) + for section in sections_not_formated.split('\r'): + if section == '\n': + continue + back_path = section.split(":")[0] + back_name = section.split(":")[1] + back_name = back_name.strip().replace('\n', '').replace('\r', '').replace(';', '') + back_path = back_path.strip().replace('/', '92').replace(':', '') + sections[back_path] = back_name - return render_template('ajax/haproxyservers_backends.html', backends=sections, serv=server_ip, service=service, lang=lang) + return sections def get_overview_last_edit(server_ip: str, service: str) -> str: @@ -261,24 +269,24 @@ def get_stat_page(server_ip: str, service: str) -> str: return data.decode('utf-8') -def show_service_version(server_ip: str, service: str) -> str: - if service == 'haproxy': - return check_haproxy_version(server_ip) - - server_id = server_sql.select_server_id_by_ip(server_ip) - service_name = get_correct_service_name(service, server_id) - is_dockerized = service_sql.select_service_setting(server_id, service, 'dockerized') - - if is_dockerized == '1': - container_name = sql.get_setting(f'{service}_container_name') - if service == 'apache': - cmd = f'docker exec -it {container_name} /usr/local/apache2/bin/httpd -v 2>&1|head -1|awk -F":" \'{{print $2}}\'' - else: - cmd = f'docker exec -it {container_name} /usr/sbin/{service_name} -v 2>&1|head -1|awk -F":" \'{{print $2}}\'' - else: - cmd = [f'sudo /usr/sbin/{service_name} -v|head -1|awk -F":" \'{{print $2}}\''] - - try: - return server_mod.ssh_command(server_ip, cmd, timeout=5) - except Exception as e: - return f'{e}' +# def show_service_version(server_ip: str, service: str) -> str: +# if service == 'haproxy': +# return check_haproxy_version(server_ip) +# +# server_id = server_sql.select_server_id_by_ip(server_ip) +# service_name = get_correct_service_name(service, server_id) +# is_dockerized = service_sql.select_service_setting(server_id, service, 'dockerized') +# +# if is_dockerized == '1': +# container_name = sql.get_setting(f'{service}_container_name') +# if service == 'apache': +# cmd = f'docker exec -it {container_name} /usr/local/apache2/bin/httpd -v 2>&1|head -1|awk -F":" \'{{print $2}}\'' +# else: +# cmd = f'docker exec -it {container_name} /usr/sbin/{service_name} -v 2>&1|head -1|awk -F":" \'{{print $2}}\'' +# else: +# cmd = [f'sudo /usr/sbin/{service_name} -v|head -1|awk -F":" \'{{print $2}}\''] +# +# try: +# return server_mod.ssh_command(server_ip, cmd, timeout=5) +# except Exception as e: +# return f'{e}' diff --git a/app/modules/service/ha_cluster.py b/app/modules/service/ha_cluster.py index 8cd17c5c..e873037d 100644 --- a/app/modules/service/ha_cluster.py +++ b/app/modules/service/ha_cluster.py @@ -1,45 +1,57 @@ -import json +from typing import Union import app.modules.db.server as server_sql import app.modules.db.ha_cluster as ha_sql import app.modules.db.service as service_sql from app.modules.db.db_model import HaCluster, HaClusterRouter, HaClusterVip, HaClusterVirt -import app.modules.common.common as common import app.modules.server.server as server_mod import app.modules.roxywi.common as roxywi_common from app.modules.server.ssh import return_ssh_keys_path +from app.modules.roxywi.class_models import HAClusterRequest, HAClusterVIP -def create_cluster(cluster: json, group_id: int) -> str: +def _get_servers_dict(cluster: Union[HAClusterRequest, HAClusterVIP]) -> dict: + for i, k in cluster.model_dump(mode='json').items(): + if i == 'servers': + servers = k + return servers + + +def _get_services_dict(cluster: HAClusterRequest) -> dict: + for i, k in cluster.model_dump(mode='json').items(): + if i == 'services': + services = k + return services + + +def create_cluster(cluster: HAClusterRequest, group_id: int) -> int: master_ip = None - vip = common.is_ip_or_dns(cluster['vip']) - syn_flood = int(cluster['syn_flood']) - return_master = int(cluster['return_to_master']) - cluster_name = common.checkAjaxInput(cluster['name']) - desc = common.checkAjaxInput(cluster['desc']) + servers = _get_servers_dict(cluster) + services = _get_services_dict(cluster) try: - cluster_id = ha_sql.create_cluster(cluster_name, syn_flood, group_id, desc) + cluster_id = ha_sql.create_cluster(cluster.name, cluster.syn_flood, group_id, cluster.description) roxywi_common.logging(cluster_id, 'New cluster has been created', keep_history=1, roxywi=1, service='HA cluster') except Exception as e: - return f'error: Cannot create new HA cluster: {e}' + raise Exception(f'error: Cannot create new HA cluster: {e}') try: router_id = HaClusterRouter.insert(cluster_id=cluster_id, default=1).on_conflict_ignore().execute() except Exception as e: - return f'error: Cannon create router: {e}' + raise Exception(f'error: Cannon create router: {e}') try: - vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=vip, return_master=return_master).execute() - roxywi_common.logging(cluster_id, f'New vip {vip} has been created and added to the cluster', keep_history=1, roxywi=1, service='HA cluster') + vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=cluster.vip, return_master=cluster.return_master).execute() + roxywi_common.logging(cluster_id, f'New vip {cluster.vip} has been created and added to the cluster', keep_history=1, roxywi=1, service='HA cluster') except Exception as e: - return f'error: Cannon add VIP: {e}' + raise Exception(f'error: Cannon add VIP: {e}') - for _slave_id, value in cluster['servers'].items(): + + for value in cluster.servers: if value['master']: master_ip = value['ip'] - for _slave_id, value in cluster['servers'].items(): + for value in cluster.servers: if value['master']: continue try: @@ -47,7 +59,8 @@ def create_cluster(cluster: json, group_id: int) -> str: except Exception as e: raise Exception(f'error: Cannot update master on slave {value["ip"]: {e}}') - for slave_id, value in cluster['servers'].items(): + for value in servers: + slave_id = servers['ip'] if value['master']: slave_id = server_sql.select_server_id_by_ip(master_ip) try: @@ -56,7 +69,7 @@ def create_cluster(cluster: json, group_id: int) -> str: except Exception as e: raise Exception(f'error: Cannot update slave server {value["ip"]}: {e}') - for service, value in cluster['services'].items(): + for service, value in services.items(): if not value['enabled']: continue try: @@ -66,17 +79,15 @@ def create_cluster(cluster: json, group_id: int) -> str: except Exception as e: raise Exception(f'error: Cannot add service {service}: {e}') - if cluster['virt_server']: - add_or_update_virt(cluster, cluster_id, vip_id, group_id) + if cluster.virt_server: + add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id) - return str(cluster_id) + return int(cluster_id) -def update_cluster(cluster: json, group_id: int) -> None: - cluster_id = int(cluster['cluster_id']) - syn_flood = int(cluster['syn_flood']) - cluster_name = common.checkAjaxInput(cluster['name']) - desc = common.checkAjaxInput(cluster['desc']) +def update_cluster(cluster: HAClusterRequest, cluster_id: int, group_id: int) -> None: + servers = _get_servers_dict(cluster) + services = _get_services_dict(cluster) try: router_id = ha_sql.get_router_id(cluster_id, default_router=1) @@ -84,12 +95,12 @@ def update_cluster(cluster: json, group_id: int) -> None: raise Exception(f'error: Cannot get router: {e}') try: - ha_sql.update_cluster(cluster_id, cluster_name, desc, syn_flood) + ha_sql.update_cluster(cluster_id, cluster.name, cluster.description, cluster.syn_flood) except Exception as e: raise Exception(f'error: Cannot update HA cluster: {e}') try: - update_slaves(cluster, router_id) + update_slaves(servers, cluster_id, router_id) except Exception as e: raise Exception(e) @@ -103,7 +114,7 @@ def update_cluster(cluster: json, group_id: int) -> None: except Exception as e: raise Exception(f'error: Cannot delete old services: {e}') - for service, value in cluster['services'].items(): + for service, value in services.items(): if not value['enabled']: continue try: @@ -112,7 +123,7 @@ def update_cluster(cluster: json, group_id: int) -> None: except Exception as e: raise Exception(f'error: Cannot add service {service}: {e}') - roxywi_common.logging(cluster_id, f'Cluster {cluster_name} has been updated', keep_history=1, roxywi=1, service='HA cluster') + roxywi_common.logging(cluster_id, f'Cluster {cluster.name} has been updated', keep_history=1, roxywi=1, service='HA cluster') def delete_cluster(cluster_id: int) -> str: @@ -132,39 +143,37 @@ def delete_cluster(cluster_id: int) -> str: return 'ok' -def update_vip(cluster_id: int, router_id: int, json_data: json, group_id: int) -> None: - return_master = int(json_data['return_to_master']) - use_src = int(json_data['use_src']) - vip = common.is_ip_or_dns(json_data['vip']) +def update_vip(cluster_id: int, router_id: int, cluster: Union[HAClusterRequest, HAClusterVIP], group_id: int) -> None: vip_id = ha_sql.select_clusters_vip_id(cluster_id, router_id) + servers = _get_servers_dict(cluster) try: - ha_sql.update_ha_cluster_vip(cluster_id, router_id, vip, return_master, use_src) + ha_sql.update_ha_cluster_vip(cluster_id, router_id, cluster.vip, cluster.return_master, cluster.use_src) except Exception as e: raise Exception(f'error: Cannot update VIP: {e}') - for slave_id, value in json_data['servers'].items(): + for value in servers: try: - ha_sql.update_slave(cluster_id, slave_id, value['eth'], value['master'], router_id) + ha_sql.update_slave(cluster_id, value['id'], value['eth'], value['master'], router_id) except Exception as e: raise Exception(f'error: Cannot add server {value["ip"]}: {e}') - if json_data['virt_server']: - add_or_update_virt(json_data, cluster_id, vip_id, group_id) + if cluster.virt_server: + add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id) else: try: if ha_sql.check_ha_virt(vip_id): ha_sql.delete_ha_virt(vip_id) - roxywi_common.logging(cluster_id, f'Cluster virtual server for VIP: {vip} has been deleted', keep_history=1, roxywi=1, service='HA cluster') + roxywi_common.logging(cluster_id, f'Cluster virtual server for VIP: {cluster.vip} has been deleted', keep_history=1, roxywi=1, service='HA cluster') except Exception as e: - roxywi_common.logging(cluster_id, f'Cannot delete cluster virtual server for VIP {vip}: {e}', keep_history=1, roxywi=1, service='HA cluster') + roxywi_common.logging(cluster_id, f'Cannot delete cluster virtual server for VIP {cluster.vip}: {e}', keep_history=1, roxywi=1, service='HA cluster') - roxywi_common.logging(cluster_id, f'Cluster VIP {vip} has been updated', keep_history=1, roxywi=1, service='HA cluster') + roxywi_common.logging(cluster_id, f'Cluster VIP {cluster.vip} has been updated', keep_history=1, roxywi=1, service='HA cluster') -def insert_vip(cluster_id: int, json_data: json, group_id: int) -> None: - vip = common.is_ip_or_dns(json_data['vip']) - return_master = int(json_data['return_to_master']) +def insert_vip(cluster_id: int, cluster: HAClusterVIP, group_id: int) -> None: + vip = cluster.vip + servers = _get_servers_dict(cluster) try: router_id = ha_sql.create_ha_router(cluster_id) @@ -172,39 +181,38 @@ def insert_vip(cluster_id: int, json_data: json, group_id: int) -> None: raise Exception(f'error: Cannot create new router: {e}') try: - vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=vip, return_master=return_master).execute() + vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=vip, return_master=cluster.return_master).execute() except Exception as e: raise Exception(f'error: Cannot save VIP {vip}: {e}') - for slave_id, value in json_data['servers'].items(): + for value in servers: try: - ha_sql.insert_or_update_slave(cluster_id, slave_id, value['eth'], value['master'], router_id) + ha_sql.insert_or_update_slave(cluster_id, value['id'], value['eth'], value['master'], router_id) except Exception as e: raise Exception(f'error: Cannot add server {value["ip"]}: {e}') - if json_data['virt_server']: - add_or_update_virt(json_data, cluster_id, vip_id, group_id) + if cluster.virt_server: + add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id) roxywi_common.logging(cluster_id, f'New cluster VIP: {vip} has been created', keep_history=1, roxywi=1, service='HA cluster') -def update_slaves(json_data: json, router_id: int) -> None: +def update_slaves(servers: dict, cluster_id: int, router_id: int) -> None: master_ip = None - cluster = json_data - cluster_id = int(json_data['cluster_id']) all_routers_in_cluster = HaClusterRouter.select(HaClusterRouter.id).where(HaClusterRouter.cluster_id == cluster_id).execute() server_ids_from_db = ha_sql.select_cluster_slaves(cluster_id, router_id) server_ids = [] server_ids_from_json = [] - for _slave_id, value in cluster['servers'].items(): + for value in servers: if value['master']: - master_ip = common.is_ip_or_dns(value['ip']) + master_ip = value['ip'] for server in server_ids_from_db: server_ids.append(server[0]) - for slave_id, value in cluster['servers'].items(): + for value in servers: + slave_id = value['id'] if value['master']: slave_id = server_sql.select_server_id_by_ip(master_ip) server_ids_from_json.append(int(slave_id)) @@ -213,7 +221,8 @@ def update_slaves(json_data: json, router_id: int) -> None: server_ids_for_adding = set(server_ids_from_json) - set(server_ids) for router in all_routers_in_cluster: - for slave_id, value in cluster['servers'].items(): + for value in servers: + slave_id = value['id'] for server_id_add in server_ids_for_adding: if int(slave_id) == int(server_id_add): try: @@ -229,15 +238,16 @@ def update_slaves(json_data: json, router_id: int) -> None: except Exception as e: raise Exception(f'error: Cannot recreate slaves server: {e}') - for _slave_id, value in cluster['servers'].items(): + for value in servers: if value['master']: continue try: - ha_sql.update_server_master(master_ip, common.is_ip_or_dns((value['ip']))) + ha_sql.update_server_master(master_ip, value['ip']) except Exception as e: raise Exception(f'error: Cannot update master on slave {value["ip"]}: {e}') - for slave_id, value in cluster['servers'].items(): + for value in servers: + slave_id = value['id'] if value['master']: slave_id = server_sql.select_server_id_by_ip(master_ip) try: @@ -246,17 +256,16 @@ def update_slaves(json_data: json, router_id: int) -> None: raise Exception(f'error: Cannot update server {value["ip"]}: {e}') -def add_or_update_virt(cluster: json, cluster_id: int, vip_id: int, group_id: int) -> None: +def add_or_update_virt(cluster: Union[HAClusterRequest, HAClusterVIP], servers: dict, cluster_id: int, vip_id: int, group_id: int) -> None: haproxy = 0 nginx = 0 apache = 0 master_ip = None - vip = common.is_ip_or_dns(cluster['vip']) - cluster_name = common.checkAjaxInput(cluster['name']) + vip = cluster.vip - for _slave_id, value in cluster['servers'].items(): + for value in servers: if value['master']: - master_ip = common.is_ip_or_dns(value['ip']) + master_ip = value['ip'] if ha_sql.check_ha_virt(vip_id): try: @@ -276,7 +285,7 @@ def add_or_update_virt(cluster: json, cluster_id: int, vip_id: int, group_id: in ssh_settings = return_ssh_keys_path(master_ip) virt_id = server_sql.add_server( f'{vip}-VIP', vip, group_id, '1', '1', '0', cred_id, ssh_settings['port'], - f'VRRP IP for {cluster_name} cluster', haproxy, nginx, apache, firewall + f'VRRP IP for {cluster.name} cluster', haproxy, nginx, apache, firewall ) HaClusterVirt.insert(cluster_id=cluster_id, virt_id=virt_id, vip_id=vip_id).execute() roxywi_common.logging(cluster_id, f'New cluster virtual server for VIP: {vip} has been created', keep_history=1, roxywi=1, diff --git a/app/modules/service/haproxy.py b/app/modules/service/haproxy.py index 0b203af1..27670344 100644 --- a/app/modules/service/haproxy.py +++ b/app/modules/service/haproxy.py @@ -234,12 +234,12 @@ def show_map(serv: str) -> str: nx.draw_networkx_edge_labels(G, pos, alpha=0.4, label_pos=0.5, font_color="#5d9ceb", edge_labels=edge_labels, font_size=8) - plt.savefig("/var/www/haproxy-wi/map.png") + plt.savefig("/var/www/haproxy-wi/app/static/map.png") plt.show() except Exception as e: return f'error: Cannot create a map: {e}' - output += 'map' + output += 'map' return output diff --git a/app/modules/service/installation.py b/app/modules/service/installation.py index 91a2ca54..9695cc60 100644 --- a/app/modules/service/installation.py +++ b/app/modules/service/installation.py @@ -1,5 +1,7 @@ import os import json +from typing import Union + from packaging import version import ansible @@ -15,6 +17,7 @@ import app.modules.common.common as common import app.modules.server.server as server_mod import app.modules.roxywi.common as roxywi_common from app.modules.server.ssh import return_ssh_keys_path +from app.modules.roxywi.class_models import ServiceInstall def generate_udp_inv(listener_id: int, action: str) -> object: @@ -26,7 +29,6 @@ def generate_udp_inv(listener_id: int, action: str) -> object: elif listener['server_id']: server = server_sql.get_server_by_id(listener['server_id']) server_ips.append(server.ip) - for server_ip in server_ips: inv['server']['hosts'][server_ip] = { 'action': action, @@ -66,6 +68,7 @@ def generate_grafana_inv() -> object: def generate_kp_inv(json_data: json, installed_service) -> object: inv = {"server": {"hosts": {}}} server_ips = [] + print(json_data) cluster_id = int(json_data['cluster_id']) haproxy = json_data['services']['haproxy']['enabled'] nginx = json_data['services']['nginx']['enabled'] @@ -88,7 +91,7 @@ def generate_kp_inv(json_data: json, installed_service) -> object: routers[router_id][slave_ip].setdefault('master', slave.master) routers[router_id][slave_ip].setdefault('eth', slave.eth) - for k, v in json_data['servers'].items(): + for v in json_data['servers']: server_ip = v['ip'] inv['server']['hosts'][server_ip] = { "HAPROXY": haproxy, @@ -116,7 +119,7 @@ def generate_waf_inv(server_ip: str, installed_service: str) -> object: return inv, server_ips -def generate_haproxy_inv(json_data: json, installed_service: str) -> object: +def generate_haproxy_inv(json_data: ServiceInstall, installed_service: str) -> object: inv = {"server": {"hosts": {}}} slaves = [] server_ips = [] @@ -130,13 +133,13 @@ def generate_haproxy_inv(json_data: json, installed_service: str) -> object: container_name = sql.get_setting('haproxy_container_name') haproxy_ver = '2.9.6-1' is_docker = json_data['services']['haproxy']['docker'] - for k, v in json_data['servers'].items(): + for v in json_data['servers']: if not v['master']: slaves.append(v['ip']) else: master_ip = v['ip'] - for k, v in json_data['servers'].items(): + for v in json_data['servers']: server_ip = v['ip'] is_master = v['master'] @@ -163,7 +166,7 @@ def generate_haproxy_inv(json_data: json, installed_service: str) -> object: return inv, server_ips -def generate_service_inv(json_data: json, installed_service: str) -> object: +def generate_service_inv(json_data: ServiceInstall, installed_service: str) -> object: inv = {"server": {"hosts": {}}} server_ips = [] stats_user = sql.get_setting(f'{installed_service}_stats_user') @@ -204,7 +207,7 @@ def generate_service_inv(json_data: json, installed_service: str) -> object: return inv, server_ips -def run_ansible(inv: dict, server_ips: list, ansible_role: str) -> object: +def run_ansible(inv: dict, server_ips: list, ansible_role: str) -> dict: inventory_path = '/var/www/haproxy-wi/app/scripts/ansible/inventory' inventory = f'{inventory_path}/{ansible_role}.json' proxy = sql.get_setting('proxy') @@ -325,7 +328,7 @@ def service_actions_after_install(server_ips: str, service: str, json_data) -> N service_sql.insert_or_update_service_setting(server_id, service, 'restart', '1') -def install_service(service: str, json_data: str) -> object: +def install_service(service: str, json_data: Union[str, ServiceInstall]) -> dict: generate_functions = { 'haproxy': generate_haproxy_inv, 'nginx': generate_service_inv, @@ -333,13 +336,14 @@ def install_service(service: str, json_data: str) -> object: 'keepalived': generate_kp_inv, } + json_data = json_data.model_dump(mode='json') try: inv, server_ips = generate_functions[service](json_data, service) except Exception as e: roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot generate inv {service}', roxywi=1) try: service_actions_after_install(server_ips, service, json_data) - return run_ansible(inv, server_ips, service), 201 + return run_ansible(inv, server_ips, service) except Exception as e: roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot install {service}', roxywi=1) diff --git a/app/modules/service/udp.py b/app/modules/service/udp.py index 4f4ea13f..c2ba7555 100644 --- a/app/modules/service/udp.py +++ b/app/modules/service/udp.py @@ -1,94 +1,15 @@ -import json - from playhouse.shortcuts import model_to_dict import app.modules.db.udp as udp_sql import app.modules.db.server as server_sql import app.modules.db.ha_cluster as ha_sql -import app.modules.common.common as common import app.modules.server.server as server_mod import app.modules.roxywi.common as roxywi_common -def create_listener(json_data: json) -> int: - listener = _validate_form(json_data) - listener_id = udp_sql.insert_listener(**listener) - roxywi_common.logging(listener_id, f'UDP listener {listener["name"]} has been created', keep_history=1, roxywi=1, service='UDP Listener') - return listener_id - - -def update_listener(json_data: json) -> str: - listener = _validate_form(json_data) - listener_id = json_data['listener_id'] - udp_sql.update_listener(listener_id, **listener) - roxywi_common.logging(listener_id, f'UDP listener {listener["name"]} has been updated', keep_history=1, roxywi=1, service='UDP Listener') - return 'ok' - - -def _validate_form(json_data: json) -> dict: - returned_data = {} - if not isinstance(json_data, dict): - raise ValueError("error: Invalid form data") - returned_data['name'] = common.checkAjaxInput(json_data['new-listener-name']) - returned_data['desc'] = common.checkAjaxInput(json_data['new-listener-desc']) - returned_data['lb_algo'] = common.checkAjaxInput(json_data['new-udp-balancer-type']) - try: - returned_data['port'] = int(json_data['new-listener-port']) - except Exception: - raise ValueError("error: Invalid port number") - returned_data['group_id'] = int(json_data['group_id']) - returned_data['config'] = {} - for k, v in json_data.items(): - if k == 'servers': - _validate_backend_servers(v) - for server, value in v.items(): - server_ip = common.is_ip_or_dns(server) - returned_data['config'][server_ip] = {} - returned_data['config'][server_ip]['port'] = int(value['port']) - returned_data['config'][server_ip]['weight'] = int(value['weight']) - if json_data['new-listener-type'] == 'server': - returned_data['server_id'] = int(json_data['serv']) - try: - returned_data['vip'] = common.is_ip_or_dns(json_data['new-udp-ip']) - except ValueError: - raise ValueError("error: Cannot parse Server and IP") - else: - try: - cluster_id = int(json_data['ha-cluster']) - returned_data['cluster_id'] = cluster_id - except ValueError: - raise ValueError("error: Cannot parse Cluster ID") - returned_data['vip'] = common.is_ip_or_dns(json_data['new-udp-vip']) - - return returned_data - - -def _validate_backend_servers(serves: dict): - if not isinstance(serves, dict): - raise ValueError("error: Invalid backend servers data") - if len(serves) == 0: - raise ValueError("error: Empty backend servers") - for server, value in serves.items(): - server = common.is_ip_or_dns(server) - if server == '': - raise ValueError("error: Cannot parse backend server IP") - try: - port = int(value['port']) - except ValueError: - raise ValueError(f"error: Invalid port for backend server {server}") - if port > 65535 or port < 1: - raise Exception(f'error: Port must be 1-65535 for backend server {server}') - try: - weight = int(value['weight']) - except ValueError: - raise ValueError(f"error: Invalid weight for backend server {server}") - if weight > 65535 or weight < 1: - raise Exception(f'error: Weight must be 1-65535 for backend server {server}') - - def get_listener_config(listener_id: int) -> dict: listener = udp_sql.get_listener(listener_id) - listener_json = model_to_dict(listener) + listener_json = model_to_dict(listener, recurse=False) listener_json['config'] = eval(listener_json['config']) return listener_json @@ -111,7 +32,7 @@ def get_slaves_for_udp_listener(cluster_id: int, vip: str) -> list: def _return_listener_servers(listener_id: int, group_id=None): servers = [] listener = udp_sql.get_listener(listener_id) - if group_id is not None and int(listener.group_id.group_id) != group_id: + if group_id is not None and int(listener.group_id.group_id) != int(group_id): raise ValueError("error: Invalid group") if listener.cluster_id: servers = get_slaves_for_udp_listener(listener.cluster_id, listener.vip) @@ -125,10 +46,7 @@ def _return_listener_servers(listener_id: int, group_id=None): -def listener_actions(listener_id: int, action: str, group_id: int) -> str: - if action not in ('start', 'stop', 'restart'): - raise ValueError("error: Invalid action") - +def listener_actions(listener_id: int, action: str, group_id: int) -> None: cmd = f'sudo systemctl {action} keepalived-udp-{listener_id}.service' try: servers, listener = _return_listener_servers(listener_id, group_id) @@ -141,7 +59,6 @@ def listener_actions(listener_id: int, action: str, group_id: int) -> str: roxywi_common.logging(listener.id, f'UDP listener {listener.name} has been {action} on {server_ip}', keep_history=1, roxywi=1, service='UDP Listener') except Exception as e: roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot {action} for UDP balancer {listener.name}', roxywi=1) - return 'ok' def check_is_listener_active(listener_id: int) -> str: diff --git a/app/modules/tools/alerting.py b/app/modules/tools/alerting.py index ca544ccf..9528d7af 100644 --- a/app/modules/tools/alerting.py +++ b/app/modules/tools/alerting.py @@ -5,7 +5,7 @@ import pdpyras import requests import telebot from telebot import apihelper -from flask import render_template, request, abort +from flask import render_template, request, abort, g import app.modules.db.sql as sql import app.modules.db.user as user_sql @@ -176,9 +176,9 @@ def telegram_send_mess(mess, level, **kwargs): return if kwargs.get('channel_id'): - telegrams = channel_sql.get_telegram_by_id(kwargs.get('channel_id')) + telegrams = channel_sql.get_receiver_by_id('telegram', kwargs.get('channel_id')) else: - telegrams = channel_sql.get_telegram_by_ip(kwargs.get('ip')) + telegrams = channel_sql.get_receiver_by_ip('telegram', kwargs.get('ip')) proxy = sql.get_setting('proxy') @@ -210,9 +210,9 @@ def slack_send_mess(mess, level, **kwargs): return if kwargs.get('channel_id'): - slacks = channel_sql.get_slack_by_id(kwargs.get('channel_id')) + slacks = channel_sql.get_receiver_by_id('slack', kwargs.get('channel_id')) else: - slacks = channel_sql.get_slack_by_ip(kwargs.get('ip')) + slacks = channel_sql.get_receiver_by_ip('slack', kwargs.get('ip')) proxy = sql.get_setting('proxy') @@ -241,12 +241,12 @@ def pd_send_mess(mess, level, server_ip=None, service_id=None, alert_type=None, if kwargs.get('channel_id'): try: - pds = channel_sql.get_pd_by_id(kwargs.get('channel_id')) + pds = channel_sql.get_receiver_by_id('pd', kwargs.get('channel_id')) except Exception as e: print(e) else: try: - pds = channel_sql.get_pd_by_ip(kwargs.get('ip')) + pds = channel_sql.get_receiver_by_ip('pd', kwargs.get('ip')) except Exception as e: print(e) @@ -283,12 +283,12 @@ def mm_send_mess(mess, level, server_ip=None, service_id=None, alert_type=None, if kwargs.get('channel_id'): try: - mms = channel_sql.get_mm_by_id(kwargs.get('channel_id')) + mms = channel_sql.get_receiver_by_id('mm', kwargs.get('channel_id')) except Exception as e: print(e) else: try: - mms = channel_sql.get_mm_by_ip(kwargs.get('ip')) + mms = channel_sql.get_receiver_by_ip('mm', kwargs.get('ip')) except Exception as e: print(e) @@ -343,164 +343,48 @@ def check_rabbit_alert() -> None: raise Exception(f'Cannot send message {e}') -def check_email_alert() -> None: +def check_email_alert() -> str: subject = 'test message' message = 'Test message from Roxy-WI' try: - user_uuid = request.cookies.get('uuid') + user = user_sql.get_user_id(g.user_params['user_id']) except Exception as e: - raise Exception(f'Cannot send a message {e}') + return f'error: Cannot get a user email: {e}' try: - user_email = user_sql.select_user_email_by_uuid(user_uuid) + send_email(user.email, subject, message) except Exception as e: - raise Exception(f'Cannot get a user email: {e}') + return f'error: Cannot send a message {e}' - try: - send_email(user_email, subject, message) - except Exception as e: - raise Exception('Cannot send a message {e}') + return 'ok' -def add_telegram_channel(token: str, channel: str, group: str) -> str: - if token is None or channel is None or group is None: - return error_mess +def add_receiver(receiver: str, token: str, channel: str, group: str, is_api=False) -> str: + last_id = channel_sql.insert_new_receiver(receiver, token, channel, group) + + if is_api: + return last_id else: - if channel_sql.insert_new_telegram(token, channel, group): - lang = roxywi_common.get_user_lang_for_flask() - channels = channel_sql.select_telegram(token=token) - groups = group_sql.select_groups() - roxywi_common.logging('Roxy-WI server', f'A new Telegram channel {channel} has been created ', roxywi=1, login=1) - - return render_template('ajax/new_receiver.html', groups=groups, lang=lang, channels=channels, receiver='telegram') - - -def add_slack_channel(token: str, channel: str, group: str) -> str: - if token is None or channel is None or group is None: - return error_mess - else: - if channel_sql.insert_new_slack(token, channel, group): - lang = roxywi_common.get_user_lang_for_flask() - channels = channel_sql.select_slack(token=token) - groups = group_sql.select_groups() - roxywi_common.logging('Roxy-WI server', f'A new Slack channel {channel} has been created ', roxywi=1, login=1) - return render_template('ajax/new_receiver.html', groups=groups, lang=lang, channels=channels, receiver='slack') - - -def add_pd_channel(token: str, channel: str, group: str) -> str: - if token is None or channel is None or group is None: - return error_mess - else: - if channel_sql.insert_new_pd(token, channel, group): - lang = roxywi_common.get_user_lang_for_flask() - channels = channel_sql.select_pd(token=token) - groups = group_sql.select_groups() - roxywi_common.logging('Roxy-WI server', f'A new PagerDuty channel {channel} has been created ', roxywi=1, login=1) - return render_template('ajax/new_receiver.html', groups=groups, lang=lang, channels=channels, receiver='pd') - - -def add_mm_channel(token: str, channel: str, group: str) -> str: - if token is None or channel is None or group is None: - return error_mess - else: - if channel_sql.insert_new_mm(token, channel, group): - lang = roxywi_common.get_user_lang_for_flask() - channels = channel_sql.select_mm(token=token) - groups = group_sql.select_groups() - roxywi_common.logging('Roxy-WI server', f'A new Mattermost channel {channel} has been created ', roxywi=1, login=1) - return render_template('ajax/new_receiver.html', groups=groups, lang=lang, channels=channels, receiver='mm') - - -def delete_telegram_channel(channel_id) -> str: - telegram = channel_sql.select_telegram(id=channel_id) - channel_name = '' - for t in telegram: - channel_name = t.token - if channel_sql.delete_telegram(channel_id): - roxywi_common.logging('Roxy-WI server', f'The Telegram channel {channel_name} has been deleted ', roxywi=1, login=1) - return 'ok' - - -def delete_slack_channel(channel_id) -> None: - slack = channel_sql.select_slack(id=channel_id) - channel_name = '' - for t in slack: - channel_name = t.chanel_name - if channel_sql.delete_slack(channel_id): - roxywi_common.logging('Roxy-WI server', f'The Slack channel {channel_name} has been deleted ', roxywi=1, login=1) - - -def delete_pd_channel(channel_id) -> None: - pd = channel_sql.select_pd(id=channel_id) - channel_name = '' - for t in pd: - channel_name = t.chanel_name - if channel_sql.delete_pd(channel_id): - roxywi_common.logging('Roxy-WI server', f'The PageDuty channel {channel_name} has been deleted ', roxywi=1, login=1) - - -def delete_mm_channel(channel_id) -> None: - pd = channel_sql.select_mm(id=channel_id) - channel_name = '' - for t in pd: - channel_name = t.chanel_name - if channel_sql.delete_mm(channel_id): - roxywi_common.logging('Roxy-WI server', f'The Mattermost channel {channel_name} has been deleted ', roxywi=1, login=1) - - -def update_telegram(token: str, channel: str, group: int, user_id: int) -> None: - channel_sql.update_telegram(token, channel, group, user_id) - roxywi_common.logging(f'group {group}', f'The Telegram token has been updated for channel: {channel}', roxywi=1, login=1) - - -def update_slack(token: str, channel: str, group: int, user_id: int) -> None: - channel_sql.update_slack(token, channel, group, user_id) - roxywi_common.logging(f'group {group}', f'The Slack token has been updated for channel: {channel}', roxywi=1, login=1) - - -def update_pd(token: str, channel: str, group: int, user_id: int) -> None: - channel_sql.update_pd(token, channel, group, user_id) - roxywi_common.logging(f'group {group}', f'The PagerDuty token has been updated for channel: {channel}', roxywi=1, login=1) - - -def update_mm(token: str, channel: str, group: int, user_id: int) -> None: - channel_sql.update_mm(token, channel, group, user_id) - roxywi_common.logging(f'group {group}', f'The Mattermost token has been updated for channel: {channel}', roxywi=1, login=1) + lang = roxywi_common.get_user_lang_for_flask() + new_channel = channel_sql.select_receiver(receiver, last_id) + groups = group_sql.select_groups() + roxywi_common.logging('Roxy-WI server', f'A new {receiver.title()} channel {channel} has been created ', roxywi=1, login=1) + return render_template('ajax/new_receiver.html', groups=groups, lang=lang, channel=new_channel, receiver=receiver) def delete_receiver_channel(channel_id: int, receiver_name: str) -> None: - delete_functions = { - "telegram": delete_telegram_channel, - "slack": delete_slack_channel, - "pd": delete_pd_channel, - "mm": delete_mm_channel, - } - return delete_functions[receiver_name](channel_id) - - -def add_receiver_channel(receiver_name: str, token: str, channel: str, group: id) -> str: - add_functions = { - "telegram": add_telegram_channel, - "slack": add_slack_channel, - "pd": add_pd_channel, - "mm": add_mm_channel, - } - try: - return add_functions[receiver_name](token, channel, group) + channel_sql.delete_receiver(receiver_name, channel_id) except Exception as e: - raise Exception(e) + raise e -def update_receiver_channel(receiver_name: str, token: str, channel: str, group: id, user_id: int) -> None: - update_functions = { - "telegram": update_telegram, - "slack": update_slack, - "pd": update_pd, - "mm": update_mm, - } - return update_functions[receiver_name](token, channel, group, user_id) +def update_receiver_channel(receiver_name: str, token: str, channel: str, group: id, channel_id: int) -> None: + try: + channel_sql.update_receiver(receiver_name, token, channel, group, channel_id) + except Exception as e: + raise e def check_receiver(channel_id: int, receiver_name: str) -> None: @@ -543,11 +427,11 @@ def load_channels(): if user_subscription['user_status']: user_group = roxywi_common.get_user_group(id=1) - kwargs.setdefault('telegrams', channel_sql.get_user_telegram_by_group(user_group)) - kwargs.setdefault('pds', channel_sql.get_user_pd_by_group(user_group)) - kwargs.setdefault('mms', channel_sql.get_user_mm_by_group(user_group)) + kwargs.setdefault('telegrams', channel_sql.get_user_receiver_by_group('telegram', user_group)) + kwargs.setdefault('pds', channel_sql.get_user_receiver_by_group('pd', user_group)) + kwargs.setdefault('mms', channel_sql.get_user_receiver_by_group('mm', user_group)) kwargs.setdefault('groups', group_sql.select_groups()) - kwargs.setdefault('slacks', channel_sql.get_user_slack_by_group(user_group)) + kwargs.setdefault('slacks', channel_sql.get_user_receiver_by_group('slack', user_group)) kwargs.setdefault('user_subscription', user_subscription) kwargs.setdefault('user_params', user_params) kwargs.setdefault('lang', user_params['lang']) diff --git a/app/modules/tools/checker.py b/app/modules/tools/checker.py index e9c6dd84..32c754d2 100644 --- a/app/modules/tools/checker.py +++ b/app/modules/tools/checker.py @@ -28,11 +28,11 @@ def load_checker() -> str: if user_subscription['user_status']: user_group = roxywi_common.get_user_group(id=1) kwargs.setdefault('services', tools_common.get_services_status()) - kwargs.setdefault('telegrams', channel_sql.get_user_telegram_by_group(user_group)) - kwargs.setdefault('pds', channel_sql.get_user_pd_by_group(user_group)) - kwargs.setdefault('mms', channel_sql.get_user_mm_by_group(user_group)) + kwargs.setdefault('telegrams', channel_sql.get_user_receiver_by_group('telegram', user_group)) + kwargs.setdefault('pds', channel_sql.get_user_receiver_by_group('pd', user_group)) + kwargs.setdefault('mms', channel_sql.get_user_receiver_by_group('mm', user_group)) kwargs.setdefault('groups', group_sql.select_groups()) - kwargs.setdefault('slacks', channel_sql.get_user_slack_by_group(user_group)) + kwargs.setdefault('slacks', channel_sql.get_user_receiver_by_group('slack', user_group)) kwargs.setdefault('haproxy_servers', roxywi_common.get_dick_permit(haproxy=1, only_group=1)) kwargs.setdefault('nginx_servers', roxywi_common.get_dick_permit(nginx=1, only_group=1)) kwargs.setdefault('apache_servers', roxywi_common.get_dick_permit(apache=1, only_group=1)) diff --git a/app/routes/add/routes.py b/app/routes/add/routes.py index 7b4bc3c9..81511e5a 100644 --- a/app/routes/add/routes.py +++ b/app/routes/add/routes.py @@ -1,7 +1,7 @@ import os from flask import render_template, request, jsonify, redirect, url_for, g -from flask_login import login_required +from flask_jwt_extended import jwt_required, get_jwt from app.routes.add import bp import app.modules.db.sql as sql @@ -17,7 +17,7 @@ get_config = roxy_wi_tools.GetConfigVar() @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -41,7 +41,8 @@ def add(service): } if service == 'haproxy': - user_group = request.cookies.get('group') + claims = get_jwt() + user_group = claims['group'] lib_path = get_config.get_config_var('main', 'lib_path') list_dir = lib_path + "/lists" white_dir = lib_path + "/lists/" + user_group + "/white" diff --git a/app/routes/admin/routes.py b/app/routes/admin/routes.py index 25f60b1d..72b9b21e 100644 --- a/app/routes/admin/routes.py +++ b/app/routes/admin/routes.py @@ -1,6 +1,6 @@ import pytz from flask import render_template, request, g -from flask_login import login_required +from flask_jwt_extended import jwt_required from app import scheduler from app.routes.admin import bp @@ -16,10 +16,17 @@ import app.modules.roxywi.auth as roxywi_auth import app.modules.roxywi.common as roxywi_common import app.modules.tools.smon as smon_mod import app.modules.tools.common as tools_common +from app.views.admin.views import SettingsView + +bp.add_url_rule( + '/settings/', + view_func=SettingsView.as_view('settings'), + methods=['GET', 'POST'] +) @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -38,7 +45,7 @@ def admin(): else: users = user_sql.select_users(group=user_group) servers = roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1) - masters = server_sql.select_servers(get_master_servers=1, uuid=g.user_params['user_uuid']) + masters = server_sql.select_servers(get_master_servers=1, uuid=g.user_params['user_id']) sshs = cred_sql.select_ssh(group=user_group) kwargs = { @@ -115,7 +122,7 @@ def check_update(): @get_user_params() def get_settings(): kwargs = { - 'settings': sql.get_setting('', all=1), + 'settings': sql.get_setting('', all=1, group_id=g.user_params['group_id']), 'timezones': pytz.all_timezones, } return render_template('include/admin_settings.html', **kwargs) @@ -126,13 +133,16 @@ def update_settings(param): roxywi_auth.page_for_admin(level=2) val = request.form.get('val').replace('92', '/') user_group = roxywi_common.get_user_group(id=1) - if sql.update_setting(param, val, user_group): - roxywi_common.logging('Roxy-WI server', f'The {param} setting has been changed to: {val}', roxywi=1, login=1) + try: + sql.update_setting(param, val, user_group) + except Exception as e: + roxywi_common.handle_json_exceptions(e, 'Cannot update settings') + roxywi_common.logging('Roxy-WI server', f'The {param} setting has been changed to: {val}', roxywi=1, login=1) - if param == 'master_port': - try: - smon_mod.change_smon_port(val) - except Exception as e: - return f'{e}' + if param == 'master_port': + try: + smon_mod.change_smon_port(int(val)) + except Exception as e: + return f'{e}' return 'Ok' diff --git a/app/routes/channel/routes.py b/app/routes/channel/routes.py index db0bcf0d..9f13e369 100644 --- a/app/routes/channel/routes.py +++ b/app/routes/channel/routes.py @@ -1,15 +1,24 @@ from flask import request, render_template, g, jsonify -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.channel import bp from app.middleware import get_user_params import app.modules.common.common as common import app.modules.tools.alerting as alerting import app.modules.roxywi.common as roxywi_common +from app.views.channel.views import ChannelView + +def register_api_channel(view, endpoint, url_beg, pk='receiver', pk_type='int', pk_end='channel_id', pk_type_end='int'): + view_func = view.as_view(endpoint, False) + bp.add_url_rule(f'/{url_beg}/', view_func=view_func, methods=['POST']) + bp.add_url_rule(f'/{url_beg}//<{pk_type_end}:{pk_end}>', view_func=view_func, methods=['PUT', 'DELETE', 'GET', 'PATCH']) + + +register_api_channel(ChannelView, 'channel', '') @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -33,15 +42,15 @@ def load_channels(): return f'{e}' -@bp.route('/check//') -def check_receiver(channel_id, receiver_name): - receiver_name = common.checkAjaxInput(receiver_name) - - try: - alerting.check_receiver(channel_id, receiver_name) - return jsonify({'status': 'success'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot send message via {receiver_name}') +# @bp.route('/check//') +# def check_receiver(channel_id, receiver_name): +# receiver_name = common.checkAjaxInput(receiver_name) +# +# try: +# alerting.check_receiver(channel_id, receiver_name) +# return jsonify({'status': 'success'}) +# except Exception as e: +# return roxywi_common.handle_json_exceptions(e, f'Cannot send message via {receiver_name}') @bp.post('/check') @@ -57,37 +66,3 @@ def check_sender(): return jsonify({'status': 'success'}) except Exception as e: return roxywi_common.handle_json_exceptions(e, f'Cannot send message via {sender.title()}') - - -@bp.route('/receiver/', methods=['PUT', 'POST', 'DELETE']) -@get_user_params() -def receiver(receiver_name): - json_data = request.get_json() - if request.method == 'POST': - token = common.checkAjaxInput(json_data['receiver']) - channel = common.checkAjaxInput(json_data['channel']) - group = int(json_data['group']) - - try: - data = alerting.add_receiver_channel(receiver_name, token, channel, group) - return jsonify({'status': 'updated', 'data': data}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot create {receiver_name} channel') - elif request.method == 'PUT': - token = common.checkAjaxInput(json_data['receiver_token']) - channel = common.checkAjaxInput(json_data['channel']) - group = int(json_data['group']) - user_id = int(json_data['id']) - - try: - alerting.update_receiver_channel(receiver_name, token, channel, group, user_id) - return jsonify({'status': 'updated'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot update {receiver_name} channel') - elif request.method == 'DELETE': - channel_id = int(json_data['channel_id']) - try: - alerting.delete_receiver_channel(channel_id, receiver_name) - return jsonify({'status': 'deleted'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot delete {receiver_name} channel') diff --git a/app/routes/checker/routes.py b/app/routes/checker/routes.py index f06f5fa2..5e29542f 100644 --- a/app/routes/checker/routes.py +++ b/app/routes/checker/routes.py @@ -1,5 +1,5 @@ from flask import render_template, request, g -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.checker import bp from app.middleware import get_user_params @@ -9,7 +9,7 @@ import app.modules.tools.checker as checker_mod @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass diff --git a/app/routes/config/routes.py b/app/routes/config/routes.py index 880149d2..60483713 100644 --- a/app/routes/config/routes.py +++ b/app/routes/config/routes.py @@ -1,11 +1,10 @@ import os from flask import render_template, request, g -from flask_login import login_required +from flask_jwt_extended import jwt_required, get_jwt from app.routes.config import bp import app.modules.db.sql as sql -import app.modules.db.user as user_sql import app.modules.db.config as config_sql import app.modules.db.server as server_sql import app.modules.db.service as service_sql @@ -18,10 +17,14 @@ import app.modules.config.common as config_common import app.modules.config.section as section_mod import app.modules.service.haproxy as service_haproxy import app.modules.server.server as server_mod +from app.views.service.views import ServiceConfigView + + +bp.add_url_rule('//', view_func=ServiceConfigView.as_view('config_view_ip'), methods=['POST']) @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -33,8 +36,9 @@ def show_config(service): config_file_name = request.form.get('config_file_name') configver = request.form.get('configver') server_ip = request.form.get('serv') + claims = get_jwt() - return config_mod.show_config(server_ip, service, config_file_name, configver) + return config_mod.show_config(server_ip, service, config_file_name, configver, claims) @bp.route('//show-files', methods=['POST']) @@ -132,43 +136,43 @@ def config(service, serv, edit, config_file_name, new): return render_template('config.html', **kwargs) -@bp.route('///save', methods=['POST']) -@check_services -@get_user_params() -def save_config(service, server_ip): - roxywi_common.check_is_server_in_group(server_ip) - config_file = request.form.get('config') - oldcfg = request.form.get('oldconfig') - save = request.form.get('save') - config_file_name = request.form.get('config_file_name') - - try: - cfg = config_mod.return_cfg(service, server_ip, config_file_name) - except Exception as e: - return f'error: Cannot get config {e}' - - try: - with open(cfg, "a") as conf: - conf.write(config_file) - except IOError as e: - return f"error: Cannot read imported config file: {e}", 200 - - try: - if service == 'keepalived': - stderr = config_mod.upload_and_restart(server_ip, cfg, save, service, oldcfg=oldcfg) - else: - stderr = config_mod.master_slave_upload_and_restart(server_ip, cfg, save, service, oldcfg=oldcfg, - config_file_name=config_file_name) - except Exception as e: - return f'error: {e}', 200 - - if save != 'test': - config_mod.diff_config(oldcfg, cfg) - - if stderr: - return stderr, 200 - - return +# @bp.route('///save', methods=['POST']) +# @check_services +# @get_user_params() +# def save_config(service, server_ip): +# roxywi_common.check_is_server_in_group(server_ip) +# config_file = request.form.get('config') +# oldcfg = request.form.get('oldconfig') +# save = request.form.get('save') +# config_file_name = request.form.get('config_file_name') +# +# try: +# cfg = config_mod.return_cfg(service, server_ip, config_file_name) +# except Exception as e: +# return f'error: Cannot get config {e}' +# +# try: +# with open(cfg, "a") as conf: +# conf.write(config_file) +# except IOError as e: +# return f"error: Cannot read imported config file: {e}", 200 +# +# try: +# if service == 'keepalived': +# stderr = config_mod.upload_and_restart(server_ip, cfg, save, service, oldcfg=oldcfg) +# else: +# stderr = config_mod.master_slave_upload_and_restart(server_ip, cfg, save, service, oldcfg=oldcfg, +# config_file_name=config_file_name) +# except Exception as e: +# return f'error: {e}', 200 +# +# if save != 'test': +# config_mod.diff_config(oldcfg, cfg) +# +# if stderr: +# return stderr, 200 +# +# return @bp.route('/versions/', defaults={'server_ip': None}, methods=['GET', 'POST']) @@ -177,15 +181,15 @@ def save_config(service, server_ip): @get_user_params(disable=1) def versions(service, server_ip): roxywi_auth.page_for_admin(level=3) - aftersave = '' + after_save = '' file = set() stderr = '' - file_fortmat = config_common.get_file_format(service) + file_format = config_common.get_file_format(service) if request.form.get('del'): - aftersave = 1 + after_save = 1 for get in request.form.getlist('do_delete'): - if file_fortmat in get and server_ip in get: + if file_format in get and server_ip in get: try: if config_sql.delete_config_version(service, get): try: @@ -209,7 +213,7 @@ def versions(service, server_ip): kwargs = { 'serv': server_ip, - 'aftersave': aftersave, + 'aftersave': after_save, 'file': file, 'service': service, 'stderr': stderr, @@ -222,10 +226,10 @@ def versions(service, server_ip): @check_services def list_of_version(service): server_ip = common.is_ip_or_dns(request.form.get('serv')) - configver = common.checkAjaxInput(request.form.get('configver')) + config_ver = common.checkAjaxInput(request.form.get('configver')) for_delver = common.checkAjaxInput(request.form.get('for_delver')) - return config_mod.list_of_versions(server_ip, service, configver, for_delver) + return config_mod.list_of_versions(server_ip, service, config_ver, for_delver) @bp.route('/versions///', defaults={'save': None}, methods=['GET', 'POST']) diff --git a/app/routes/ha/routes.py b/app/routes/ha/routes.py index 254e4ddb..8382f792 100644 --- a/app/routes/ha/routes.py +++ b/app/routes/ha/routes.py @@ -1,64 +1,37 @@ -from flask import render_template, g, request, jsonify -from flask_login import login_required -from playhouse.shortcuts import model_to_dict +from flask import render_template, g, request +from flask_jwt_extended import jwt_required from app.routes.ha import bp from app.middleware import get_user_params, check_services import app.modules.db.ha_cluster as ha_sql import app.modules.db.server as server_sql import app.modules.db.service as service_sql -import app.modules.common.common as common import app.modules.server.server as server_mod import app.modules.roxywi.common as roxywi_common import app.modules.service.keepalived as keepalived -import app.modules.service.ha_cluster as ha_cluster +from app.views.ha.views import HAView, HAVIPView, HAVIPsView + + +# def register_api(view, endpoint, url, pk='listener_id', pk_type='int'): +# view_func = view.as_view(endpoint) +# bp.add_url_rule(url, view_func=view_func, methods=['GET'], defaults={pk: None}) +# bp.add_url_rule(url, view_func=view_func, methods=['POST']) +# bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'DELETE']) + +# register_api(HAView, 'ha_cluster', '/', 'cluster_id') +# bp.add_url_rule('///vip/', view_func=HAVIPView.as_view('ha_vip_g'), methods=['GET']) +bp.add_url_rule('/', view_func=HAView.as_view('ha_cluster'), methods=['GET'], defaults={'cluster_id': None}) +# bp.add_url_rule('///vip', view_func=HAVIPView.as_view('ha_vip_d'), methods=['DELETE']) +# bp.add_url_rule('///vips', view_func=HAVIPsView.as_view('ha_vips'), methods=['GET']) @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass -@bp.route('/', methods=['GET', 'POST', 'PUT', 'DELETE']) -@check_services -@get_user_params() -def cluster_function(service): - group_id = g.user_params['group_id'] - if request.method == 'GET': - kwargs = { - 'clusters': ha_sql.select_clusters(group_id), - 'is_needed_tool': common.is_tool('ansible'), - 'user_subscription': roxywi_common.return_user_subscription(), - 'lang': g.user_params['lang'], - } - - return render_template('ha_cluster.html', **kwargs) - elif request.method == 'PUT': - cluster = request.get_json() - - try: - ha_cluster.update_cluster(cluster, group_id) - return jsonify({'status': 'updated'}) - except Exception as e: - return jsonify({'status': 'failed', 'error': f'Cannot update the cluster: {e}'}) - elif request.method == 'POST': - cluster = request.get_json() - - try: - cluster_id = ha_cluster.create_cluster(cluster, group_id) - return jsonify({'status': 'created', 'cluster_id': cluster_id}) - except Exception as e: - return jsonify({'status': 'failed', 'error': f'Cannot create a cluster: {e}'}) - elif request.method == 'DELETE': - cluster_id = int(request.form.get('cluster_id')) - try: - return ha_cluster.delete_cluster(cluster_id) - except Exception as e: - return jsonify({'status': 'failed', 'error': f'Cannot delete the cluster: {e}'}) - - @bp.route('//get/') @check_services @get_user_params() @@ -80,41 +53,6 @@ def get_ha_cluster(service, cluster_id): return render_template('ajax/ha/clusters.html', **kwargs) -@bp.route('//settings/') -@check_services -@get_user_params() -def get_cluster_settings(service, cluster_id): - settings = {} - clusters = ha_sql.select_cluster(cluster_id) - router_id = ha_sql.get_router_id(cluster_id, default_router=1) - slaves = ha_sql.select_cluster_slaves(cluster_id, router_id) - cluster_services = ha_sql.select_cluster_services(cluster_id) - vip = ha_sql.select_cluster_vip(cluster_id, router_id) - is_virt = ha_sql.check_ha_virt(vip.id) - for cluster in clusters: - settings.setdefault('name', cluster.name) - settings.setdefault('desc', cluster.desc) - settings.setdefault('return_to_master', vip.return_master) - settings.setdefault('syn_flood', cluster.syn_flood) - settings.setdefault('vip', vip.vip) - settings.setdefault('virt_server', is_virt) - settings.setdefault('use_src', vip.use_src) - - for slave in slaves: - if slave[31]: - settings.setdefault('eth', slave[32]) - - for c_s in cluster_services: - if int(c_s.service_id) == 1: - settings.setdefault('haproxy', 1) - elif int(c_s.service_id) == 2: - settings.setdefault('nginx', 1) - elif int(c_s.service_id) == 4: - settings.setdefault('apache', 1) - - return jsonify(settings) - - @bp.route('//') @check_services @get_user_params() @@ -214,58 +152,3 @@ def get_masters(service): free_servers = ha_sql.select_ha_cluster_not_masters_not_slaves(group_id) return render_template('ajax/ha/masters.html', free_servers=free_servers) - - -@bp.route('//settings//vip/') -@check_services -def get_vip_settings(service, cluster_id, router_id): - settings = {} - vip = ha_sql.select_cluster_vip(cluster_id, router_id) - is_virt = ha_sql.check_ha_virt(vip.id) - settings.setdefault('return_to_master', vip.return_master) - settings.setdefault('use_src', vip.use_src) - settings.setdefault('virt_server', is_virt) - return jsonify(settings) - - -@bp.route('///vip', methods=['POST', 'PUT', 'DELETE']) -@check_services -@get_user_params() -def ha_vip(service, cluster_id): - user_params = g.user_params - group_id = user_params['group_id'] - json_data = request.get_json() - if request.method == 'PUT': - router_id = int(json_data['router_id']) - try: - ha_cluster.update_vip(cluster_id, router_id, json_data, group_id) - except Exception as e: - return jsonify({'status': 'failed', 'error': f'Cannot update VIP: {e}'}) - return jsonify({'status': 'updated'}) - elif request.method == 'POST': - try: - ha_cluster.insert_vip(cluster_id, json_data, group_id) - except Exception as e: - return jsonify({'status': 'failed', 'error': f'Cannot create VIP: {e}'}) - - return jsonify({'status': 'created'}) - elif request.method == 'DELETE': - router_id = int(json_data['router_id']) - router = ha_sql.get_router(router_id) - if router.default: - return jsonify({'status': 'failed', 'error': 'You cannot delete default VIP'}) - try: - ha_sql.delete_ha_router(router_id) - return jsonify({'status': 'deleted'}) - except Exception as e: - return jsonify({'status': 'failed', 'error': f'Cannot delete VIP: {e}'}) - - -@bp.route('///vips', methods=['GET']) -@check_services -@get_user_params() -def get_vips(service, cluster_id): - if request.method == 'GET': - vips = ha_sql.select_cluster_vips(cluster_id) - vips = [model_to_dict(vip) for vip in vips] - return jsonify(vips) diff --git a/app/routes/install/routes.py b/app/routes/install/routes.py index 797407d3..feb9fb93 100644 --- a/app/routes/install/routes.py +++ b/app/routes/install/routes.py @@ -1,8 +1,8 @@ from flask import render_template, request, g, jsonify -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.install import bp -from app.middleware import get_user_params, check_services +from app.middleware import get_user_params import app.modules.db.sql as sql import app.modules.db.waf as waf_sql import app.modules.common.common as common @@ -11,10 +11,23 @@ import app.modules.server.server as server_mod import app.modules.service.common as service_common import app.modules.service.installation as service_mod import app.modules.service.exporter_installation as exp_installation +from app.views.install.views import InstallView +bp.add_url_rule( + '/', + view_func=InstallView.as_view('install'), + methods=['POST'], + defaults={'server_id': None} +) +bp.add_url_rule( + '//', + view_func=InstallView.as_view('install_ip'), + methods=['POST'], +) + @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -32,25 +45,14 @@ def install_monitoring(): return render_template('install.html', **kwargs) -@bp.post('/') -@check_services -def install_service(service): - json_data = request.get_json() - try: - return service_mod.install_service(service, json_data) - except Exception as e: - return jsonify({'status': 'failed', 'error': f'{e}'}) - - -@bp.route('//version/') -def get_service_version(service, server_ip): - if service in ('haproxy', 'nginx', 'apache'): - return service_common.show_service_version(server_ip, service) - elif service == 'keepalived': - cmd = "sudo /usr/sbin/keepalived -v 2>&1|head -1|awk '{print $2}'" - return server_mod.ssh_command(server_ip, cmd) - else: - return 'error: Wrong service' +# @bp.post('/') +# @check_services +# def install_service(service): +# json_data = request.get_json() +# try: +# return service_mod.install_service(service, json_data) +# except Exception as e: +# return jsonify({'status': 'failed', 'error': f'{e}'}) @bp.post('/exporter/') @@ -140,13 +142,13 @@ def check_geoip(service, server_ip): cmd = f"ls {service_dir}geoip/" return server_mod.ssh_command(server_ip, cmd) - -@bp.post('/udp') -def install_udp(): - json_data = request.get_json() - listener_id = int(json_data['listener_id']) - try: - inv, server_ips = service_mod.generate_udp_inv(listener_id, 'install') - return service_mod.run_ansible(inv, server_ips, 'udp'), 201 - except Exception as e: - return jsonify({'status': 'failed', 'error': f'Cannot create listener: {e}'}) +# +# @bp.post('/udp') +# def install_udp(): +# json_data = request.get_json() +# listener_id = int(json_data['listener_id']) +# try: +# inv, server_ips = service_mod.generate_udp_inv(listener_id, 'install') +# return service_mod.run_ansible(inv, server_ips, 'udp'), 201 +# except Exception as e: +# return jsonify({'status': 'failed', 'error': f'Cannot create listener: {e}'}) diff --git a/app/routes/logs/routes.py b/app/routes/logs/routes.py index a16889c4..ceb415f0 100644 --- a/app/routes/logs/routes.py +++ b/app/routes/logs/routes.py @@ -1,5 +1,5 @@ from flask import render_template, request, redirect, url_for, g -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.logs import bp from app.middleware import check_services, get_user_params @@ -16,7 +16,7 @@ get_config = roxy_wi_tools.GetConfigVar() @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass diff --git a/app/routes/main/routes.py b/app/routes/main/routes.py index 8fd8f5f0..67d3e452 100644 --- a/app/routes/main/routes.py +++ b/app/routes/main/routes.py @@ -1,10 +1,8 @@ import os -import sys -from flask import render_template, request, session, g, abort, jsonify -from flask_login import login_required - -sys.path.append(os.path.join(sys.path[0], '/var/www/haproxy-wi/app')) +from flask import render_template, request, g, abort, jsonify, redirect, url_for, send_from_directory +from flask_jwt_extended import jwt_required +from flask_pydantic.exceptions import ValidationError from app import app, cache from app.routes.main import bp @@ -20,6 +18,7 @@ import app.modules.roxywi.nettools as nettools_mod import app.modules.roxywi.common as roxywi_common import app.modules.service.common as service_common import app.modules.service.haproxy as service_haproxy +from app.modules.roxywi.class_models import ErrorResponse @app.template_filter('strftime') @@ -27,9 +26,37 @@ def _jinja2_filter_datetime(date, fmt=None): return common.get_time_zoned_date(date, fmt) +@app.errorhandler(ValidationError) +def handle_pydantic_validation_errors1(e): + errors = [] + if e.body_params: + req_type = e.body_params + elif e.form_params: + req_type = e.form_params + elif e.path_params: + req_type = e.path_params + else: + req_type = e.query_params + for er in req_type: + if len(er["loc"]) > 0: + errors.append(f'{er["loc"][0]}: {er["msg"]}') + else: + errors.append(er["msg"]) + return ErrorResponse(error=errors).model_dump(mode='json'), 400 + + +@app.errorhandler(401) +def no_auth(e): + if 'api' in request.url: + return jsonify({'error': str(e)}), 401 + return redirect(url_for('login_page')) + + @app.errorhandler(403) @get_user_params() def page_is_forbidden(e): + if 'api' in request.url: + return jsonify({'error': str(e)}), 403 kwargs = { 'user_params': g.user_params, 'title': e, @@ -41,6 +68,8 @@ def page_is_forbidden(e): @app.errorhandler(404) @get_user_params() def page_not_found(e): + if 'api' in request.url: + return jsonify({'error': str(e)}), 404 kwargs = { 'user_params': g.user_params, 'title': e, @@ -52,6 +81,8 @@ def page_not_found(e): @app.errorhandler(405) @get_user_params() def method_not_allowed(e): + if 'api' in request.url: + return jsonify({'error': str(e)}), 405 kwargs = { 'user_params': g.user_params, 'title': e, @@ -63,6 +94,8 @@ def method_not_allowed(e): @app.errorhandler(500) @get_user_params() def internal_error(e): + if 'api' in request.url: + return jsonify({'error': str(e)}), 500 kwargs = { 'user_params': g.user_params, 'title': e, @@ -71,19 +104,19 @@ def internal_error(e): return render_template('error.html', **kwargs), 500 -@app.before_request -def make_session_permanent(): - session.permanent = True +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'images/favicon/favicon.ico', mimetype='image/vnd.microsoft.icon') @bp.route('/stats//', defaults={'serv': None}) @bp.route('/stats//') -@login_required +@jwt_required() @check_services @get_user_params() def stats(service, serv): kwargs = { - 'autorefresh': 1, 'serv': serv, 'service': service, 'service_desc': service_sql.select_service(service), @@ -93,7 +126,7 @@ def stats(service, serv): @bp.route('/stats/view//') -@login_required +@jwt_required() @check_services def show_stats(service, server_ip): server_ip = common.is_ip_or_dns(server_ip) @@ -111,14 +144,14 @@ def show_stats(service, server_ip): @bp.route('/nettools') -@login_required +@jwt_required() @get_user_params(1) def nettools(): return render_template('nettools.html', lang=g.user_params['lang']) @bp.post('/nettools/') -@login_required +@jwt_required() def nettools_check(check): server_from = common.checkAjaxInput(request.form.get('server_from')) server_to = common.is_ip_or_dns(request.form.get('server_to')) @@ -154,7 +187,7 @@ def nettools_check(check): @bp.route('/history//') -@login_required +@jwt_required() @get_user_params() def service_history(service, server_ip): history = '' diff --git a/app/routes/metric/routes.py b/app/routes/metric/routes.py index f690585b..9e40d872 100644 --- a/app/routes/metric/routes.py +++ b/app/routes/metric/routes.py @@ -3,7 +3,7 @@ import time import distro from flask import render_template, request, jsonify, g, Response, stream_with_context -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.metric import bp import app.modules.db.server as server_sql @@ -17,7 +17,7 @@ import app.modules.roxywi.common as roxywi_common @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass diff --git a/app/routes/overview/routes.py b/app/routes/overview/routes.py index 378ad692..3b79487f 100644 --- a/app/routes/overview/routes.py +++ b/app/routes/overview/routes.py @@ -1,5 +1,5 @@ from flask import render_template, g -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.overview import bp from app.middleware import get_user_params @@ -10,7 +10,7 @@ import app.modules.roxywi.overview as roxy_overview @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass diff --git a/app/routes/portscanner/routes.py b/app/routes/portscanner/routes.py index 7af65246..5282953a 100644 --- a/app/routes/portscanner/routes.py +++ b/app/routes/portscanner/routes.py @@ -1,5 +1,5 @@ from flask import render_template, request, g, jsonify -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.portscanner import bp from app.middleware import get_user_params @@ -12,7 +12,7 @@ import app.modules.tools.common as tools_common @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass diff --git a/app/routes/runtime/routes.py b/app/routes/runtime/routes.py index ba938bb8..7e9b05a9 100644 --- a/app/routes/runtime/routes.py +++ b/app/routes/runtime/routes.py @@ -1,5 +1,5 @@ from flask import render_template, request, g -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.runtime import bp from app.middleware import get_user_params @@ -9,7 +9,7 @@ import app.modules.service.haproxy as service_haproxy @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass diff --git a/app/routes/server/routes.py b/app/routes/server/routes.py index 148320bc..7411dbaa 100644 --- a/app/routes/server/routes.py +++ b/app/routes/server/routes.py @@ -1,29 +1,45 @@ import json import time -from flask import render_template, request, g, jsonify, Response, stream_with_context -from flask_login import login_required +from flask import render_template, request, g, jsonify, Response +from flask_jwt_extended import jwt_required from app.routes.server import bp import app.modules.db.cred as cred_sql -import app.modules.db.group as group_sql import app.modules.db.server as server_sql import app.modules.db.backup as backup_sql import app.modules.common.common as common -import app.modules.roxywi.group as group_mod import app.modules.roxywi.auth as roxywi_auth import app.modules.roxywi.common as roxywi_common -import app.modules.server.ssh as ssh_mod import app.modules.server.server as server_mod -import app.modules.tools.smon as smon_mod import app.modules.service.backup as backup_mod from app.middleware import get_user_params +from app.views.server.views import ServerView, CredView, CredsView, ServerGroupView, ServerGroupsView, ServerIPView +from app.views.server.backup_vews import BackupView, S3BackupView + + +def register_api(view, endpoint, url, pk='listener_id', pk_type='int'): + view_func = view.as_view(endpoint) + bp.add_url_rule(url, view_func=view_func, methods=['POST']) + bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'DELETE']) + + +register_api(ServerView, 'server', '', 'server_id') +register_api(ServerGroupView, 'group', '/group', 'group_id') +register_api(CredView, 'cred', '/cred', 'creds_id') +bp.add_url_rule('/groups', view_func=ServerGroupsView.as_view('groups'), methods=['GET']) +bp.add_url_rule('/creds', view_func=CredsView.as_view('creds'), methods=['GET']) + +bp.add_url_rule('//ip', view_func=ServerIPView.as_view('server_ip_ip'), methods=['GET']) +bp.add_url_rule('//ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET']) +bp.add_url_rule('/backup', view_func=BackupView.as_view('backup', False), methods=['POST']) +bp.add_url_rule('/backup/s3', view_func=S3BackupView.as_view('backup_s3', False), methods=['POST']) error_mess = roxywi_common.return_error_message() @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -45,7 +61,7 @@ def check_server(server_id): def get_check(): while True: try: - server = server_sql.get_server(server_id) + server = server_sql.get_server_by_id(server_id) except Exception as e: raise e result = server_mod.server_is_up(server.ip) @@ -54,19 +70,19 @@ def check_server(server_id): 'name': server.hostname, 'ip': server.ip, 'port': server.port, - 'enabled': server.enable, - 'creds_id': server.cred, - 'group_id': server.groups, + 'enabled': server.enabled, + 'creds_id': server.cred_id, + 'group_id': server.group_id, 'firewall': server.firewall_enable, 'slave': server.master, 'type_ip': server.type_ip, - 'desc': server.desc, + 'description': server.description, 'protected': server.protected, } yield f'data:{json.dumps(status)}\n\n' - time.sleep(60) + time.sleep(10) - response = Response(stream_with_context(get_check()), mimetype="text/event-stream") + response = Response(get_check(), mimetype="text/event-stream") response.headers["Cache-Control"] = "no-cache" response.headers["X-Accel-Buffering"] = "no" return response @@ -81,205 +97,6 @@ def show_if(server_ip): return server_mod.ssh_command(server_ip, command) -@bp.route('/show/ip/') -def show_ip_by_id(server_ip): - server_ip = common.is_ip_or_dns(server_ip) - if server_ip == '': - raise Exception('error: Cannot find server ip') - commands = 'sudo hostname -I | tr " " "\\n"|sed "/^$/d"' - - return server_mod.ssh_command(server_ip, commands, ip="1") - - -@bp.route('/show/ip/') -def show_ip(server_id): - server_ip = server_sql.get_server_by_id(server_id) - commands = 'sudo hostname -I | tr " " "\\n"|sed "/^$/d"' - - return server_mod.ssh_command(server_ip.ip, commands, ip="1") - - -@bp.route('', methods=['POST', 'PUT', 'DELETE', 'PATCH']) -@get_user_params() -def create_server(): - roxywi_auth.page_for_admin(level=2) - json_data = request.get_json() - lang = roxywi_common.get_user_lang_for_flask() - if request.method in ('POST', 'PUT'): - hostname = common.checkAjaxInput(json_data['name']) - group = int(json_data['group']) - type_ip = int(json_data['type_ip']) - firewall = int(json_data['firewall']) - enable = int(json_data['enable']) - cred = int(json_data['cred']) - port = int(json_data['port']) - desc = common.checkAjaxInput(json_data['desc']) - master = int(json_data['slave']) - protected = int(json_data['protected']) - - if request.method == 'POST': - ip = common.is_ip_or_dns(json_data['ip']) - haproxy = int(json_data['haproxy']) - nginx = int(json_data['nginx']) - apache = int(json_data['apache']) - add_to_smon = int(json_data['add_to_smon']) - if ip == '': - return jsonify({'status': 'failed','error': 'IP or DNS name is not valid'}) - try: - last_id = server_mod.create_server(hostname, ip, group, type_ip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot create server') - - try: - user_subscription = roxywi_common.return_user_status() - except Exception as e: - user_subscription = roxywi_common.return_unsubscribed_user_status() - roxywi_common.logging('Roxy-WI server', f'Cannot get a user plan: {e}', roxywi=1) - - if add_to_smon: - try: - user_group = roxywi_common.get_user_group(id=1) - json_data = { - "name": hostname, - "ip": ip, - "port": "0", - "enabled": "1", - "url": "", - "body": "", - "group": hostname, - "desc": f"Ping {hostname}", - "tg": "0", - "slack": "0", - "pd": "0", - "resolver": "", - "record_type": "", - "packet_size": "56", - "http_method": "", - "check_type": "ping", - "agent_id": "1", - "interval": "120", - } - smon_mod.create_smon(json_data, user_group) - except Exception as e: - roxywi_common.logging(ip, f'error: Cannot add server {hostname} to SMON: {e}', roxywi=1) - - roxywi_common.logging(ip, f'A new server {hostname} has been created', roxywi=1, login=1, keep_history=1, service='server') - - kwargs = { - 'groups': group_sql.select_groups(), - 'servers': server_sql.select_servers(server=ip), - 'lang': lang, - 'masters': server_sql.select_servers(get_master_servers=1), - 'sshs': cred_sql.select_ssh(group=group), - 'user_subscription': user_subscription, - 'adding': 1 - } - return jsonify({'status': 'created', 'id': last_id, 'data': render_template('ajax/new_server.html', **kwargs)}) - elif request.method == 'PUT': - serv_id = int(json_data['id']) - if hostname is None or port is None: - return jsonify({'status': 'failed', 'error': 'Cannot find server ip or port'}) - else: - try: - server_sql.update_server(hostname, group, type_ip, enable, master, serv_id, cred, port, desc, firewall, protected) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot update server') - server_ip = server_sql.select_server_ip_by_id(serv_id) - roxywi_common.logging(server_ip, f'The server {hostname} has been update', roxywi=1, login=1, - keep_history=1, service='server') - return jsonify({'status': 'updated'}) - elif request.method == 'DELETE': - server_id = int(json_data['id']) - try: - server_mod.delete_server(server_id) - return jsonify({'status': 'deleted'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot delete the server') - elif request.method == 'PATCH': - hostname = common.checkAjaxInput(json_data['name']) - ip = common.is_ip_or_dns(json_data['ip']) - scan_server = int(json_data['scan_server']) - try: - server_mod.update_server_after_creating(hostname, ip, scan_server) - return jsonify({'status': 'updated'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot scan the server') - - -@bp.route('/group', methods=['POST', 'PUT', 'DELETE']) -def create_group(): - roxywi_auth.page_for_admin() - json_data = request.get_json() - if request.method == 'POST': - name = json_data.get('name') - desc = json_data.get('desc') - if name == '': - return error_mess - try: - last_id = group_sql.add_group(name, desc) - roxywi_common.logging('Roxy-WI server', f'A new group {name} has been created', roxywi=1, login=1) - return jsonify({ - 'status': 'created', - 'id': last_id, - 'data': render_template('ajax/new_group.html', groups=group_sql.select_groups(group=name))} - ) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot create a new group') - elif request.method == 'PUT': - name = json_data.get('name') - desc = json_data.get('desc') - group_id = json_data.get('group_id') - try: - group_mod.update_group(group_id, name, desc) - return jsonify({'status': 'updated'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot update group {name}') - elif request.method == 'DELETE': - group_id = json_data.get('group_id') - try: - group_mod.delete_group(group_id) - return jsonify({'status': 'deleted'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot delete {group_id}') - - -@bp.route('/ssh', methods=['POST', 'PUT', 'DELETE', 'PATCH']) -@get_user_params() -def create_ssh(): - roxywi_auth.page_for_admin(level=2) - json_data = request.get_json() - if request.method == 'POST': - try: - data = ssh_mod.create_ssh_cred(json_data) - return jsonify({'status': 'created', 'id': data['id'], 'data': data['template']}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot create SSH') - elif request.method == 'PUT': - try: - ssh_mod.update_ssh_key(json_data) - return jsonify({'status': 'updated'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot update SSH') - elif request.method == 'DELETE': - ssh_id = int(json_data.get('id')) - try: - ssh_mod.delete_ssh_key(ssh_id) - return jsonify({'status': 'deleted'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot delete SSH') - elif request.method == 'PATCH': - user_group = roxywi_common.get_user_group() - name = common.checkAjaxInput(json_data['name']) - passphrase = common.checkAjaxInput(json_data['pass']) - key = json_data['ssh_cert'] - - try: - saved_path = ssh_mod.upload_ssh_key(name, user_group, key, passphrase) - return jsonify({'status': 'uploaded', 'message': saved_path}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot upload ssh') - - @bp.app_template_filter('string_to_dict') def string_to_dict(dict_string) -> dict: from ast import literal_eval @@ -322,47 +139,39 @@ def show_firewall(server_ip): return server_mod.show_firewalld_rules(server_ip) -@bp.route('/backup', methods=['GET', 'POST', 'PUT', 'DELETE']) +@bp.route('/backup', methods=['GET']) @get_user_params() def load_backup(): - if request.method == 'GET': - user_group = g.user_params['group_id'] - kwargs = { - 'sshs': cred_sql.select_ssh(group=user_group), - 'servers': roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1), - 'backups': backup_sql.select_backups(), - 's3_backups': backup_sql.select_s3_backups(), - 'gits': backup_sql.select_gits(), - 'lang': g.user_params['lang'], - 'is_needed_tool': common.is_tool('ansible'), - 'user_subscription': roxywi_common.return_user_subscription(), - } - return render_template('include/admin_backup.html', **kwargs) - elif request.method in ('POST', 'PUT', 'DELETE'): - json_data = request.get_json() - try: - data = backup_mod.backup(json_data) - return jsonify({'status': 'ok', 'data': data}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot {request.method} backup') + user_group = g.user_params['group_id'] + kwargs = { + 'sshs': cred_sql.select_ssh(group=user_group), + 'servers': roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1), + 'backups': backup_sql.select_backups(), + 's3_backups': backup_sql.select_s3_backups(), + 'gits': backup_sql.select_gits(), + 'lang': g.user_params['lang'], + 'is_needed_tool': common.is_tool('ansible'), + 'user_subscription': roxywi_common.return_user_subscription(), + } + return render_template('include/admin_backup.html', **kwargs) -@bp.post('/s3backup/create') -@bp.post('/s3backup/delete') -def create_s3_backup(): - server = common.is_ip_or_dns(request.form.get('s3_backup_server')) - s3_server = common.checkAjaxInput(request.form.get('s3_server')) - bucket = common.checkAjaxInput(request.form.get('s3_bucket')) - secret_key = common.checkAjaxInput(request.form.get('s3_secret_key')) - access_key = common.checkAjaxInput(request.form.get('s3_access_key')) - time = common.checkAjaxInput(request.form.get('time')) - deljob = common.checkAjaxInput(request.form.get('dels3job')) - description = common.checkAjaxInput(request.form.get('description')) - - try: - return backup_mod.s3_backup(server, s3_server, bucket, secret_key, access_key, time, deljob, description) - except Exception as e: - return str(e) +# @bp.post('/s3backup/create') +# @bp.post('/s3backup/delete') +# def create_s3_backup(): +# server = common.is_ip_or_dns(request.form.get('s3_backup_server')) +# s3_server = common.checkAjaxInput(request.form.get('s3_server')) +# bucket = common.checkAjaxInput(request.form.get('s3_bucket')) +# secret_key = common.checkAjaxInput(request.form.get('s3_secret_key')) +# access_key = common.checkAjaxInput(request.form.get('s3_access_key')) +# time = common.checkAjaxInput(request.form.get('time')) +# deljob = common.checkAjaxInput(request.form.get('dels3job')) +# description = common.checkAjaxInput(request.form.get('description')) +# +# try: +# return backup_mod.s3_backup(server, s3_server, bucket, secret_key, access_key, time, deljob, description) +# except Exception as e: +# return str(e) @bp.route('/git', methods=['DELETE', 'POST']) diff --git a/app/routes/service/routes.py b/app/routes/service/routes.py index ee28ccd9..bf649b1b 100644 --- a/app/routes/service/routes.py +++ b/app/routes/service/routes.py @@ -1,6 +1,6 @@ import distro from flask import render_template, request, g -from flask_login import login_required +from flask_jwt_extended import jwt_required, get_jwt from app import cache from app.routes.service import bp @@ -13,15 +13,22 @@ import app.modules.db.service as service_sql from app.middleware import check_services, get_user_params import app.modules.common.common as common import app.modules.server.server as server_mod -import app.modules.service.action as service_action import app.modules.service.common as service_common import app.modules.service.keepalived as keepalived import app.modules.roxywi.common as roxywi_common import app.modules.roxywi.overview as roxy_overview +from app.views.service.views import ServiceActionView, ServiceBackendView, ServiceView +bp.add_url_rule('///', view_func=ServiceActionView.as_view('service_action_ip'), methods=['GET']) +bp.add_url_rule('///', view_func=ServiceActionView.as_view('service_action'), methods=['GET']) +bp.add_url_rule('///backend', view_func=ServiceBackendView.as_view('service_backend_ip'), methods=['GET']) +bp.add_url_rule('///backend', view_func=ServiceBackendView.as_view('service_backend'), methods=['GET']) +bp.add_url_rule('///status', view_func=ServiceView.as_view('service_ip'), methods=['GET']) +bp.add_url_rule('///status', view_func=ServiceView.as_view('service'), methods=['GET']) + @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -178,22 +185,22 @@ def services(service, serv): return render_template('service.html', **kwargs) -@bp.post('/action//check-service') -def check_service(service): - user_uuid = request.cookies.get('uuid') - server_ip = common.checkAjaxInput(request.form.get('server_ip')) - - try: - return service_action.check_service(server_ip, user_uuid, service) - except Exception: - return 'logout' - - -@bp.route('/action///', methods=['GET']) -def action_service(service, server_ip, action): - server_ip = common.is_ip_or_dns(server_ip) - - return service_action.common_action(server_ip, action, service) +# @bp.post('/action//check-service') +# def check_service(service): +# claims = get_jwt() +# server_ip = common.checkAjaxInput(request.form.get('server_ip')) +# +# try: +# return service_action.check_service(server_ip, claims['user_id'], service) +# except Exception: +# return 'logout' +# +# +# @bp.route('/action///', methods=['GET']) +# def action_service(service, server_ip, action): +# server_ip = common.is_ip_or_dns(server_ip) +# +# return service_action.common_action(server_ip, action, service) @bp.route('///last-edit') @@ -222,11 +229,10 @@ def cpu_ram_metrics(server_ip, server_id, name, service): return_out = '' servers = [[name, server_ip, return_out]] - user_id = request.cookies.get('uuid') - group_id = int(request.cookies.get('group')) + claims = get_jwt() kwargs = { 'service_status': sorted(servers, key=common.get_key), - 'role': user_sql.get_user_role_by_uuid(user_id, group_id), + 'role': user_sql.get_user_role_in_group(claims['user_id'], claims['group']), 'id': server_id, 'service_page': service, 'lang': g.user_params['lang'] @@ -271,26 +277,26 @@ def show_keepalived_become_master(): server_ip = common.is_ip_or_dns(request.form.get('keepalivedBecameMaster')) return roxy_overview.keepalived_became_master(server_ip) - - -@bp.route('//backends/') -@cache.cached() -def show_service_backends(service, server_ip): - server_ip = common.is_ip_or_dns(server_ip) - - return service_common.overview_backends(server_ip, service) +# +# +# @bp.route('//backends/') +# @cache.cached() +# def show_service_backends(service, server_ip): +# server_ip = common.is_ip_or_dns(server_ip) +# +# return service_common.overview_backends(server_ip, service) @bp.route('/position//') def change_pos(server_id, pos): return server_sql.update_server_pos(pos, server_id) - -@bp.route('/haproxy/version/') -def get_haproxy_v(server_ip): - server_ip = common.is_ip_or_dns(server_ip) - - return service_common.check_haproxy_version(server_ip) +# +# @bp.route('/haproxy/version/') +# def get_haproxy_v(server_ip): +# server_ip = common.is_ip_or_dns(server_ip) +# +# return service_common.check_haproxy_version(server_ip) @bp.route('/settings//') diff --git a/app/routes/smon/agent_routes.py b/app/routes/smon/agent_routes.py index 9219814e..047f826e 100644 --- a/app/routes/smon/agent_routes.py +++ b/app/routes/smon/agent_routes.py @@ -1,8 +1,8 @@ from flask import render_template, request, jsonify, g -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.smon import bp -from middleware import get_user_params +from app.middleware import get_user_params import app.modules.db.smon as smon_sql import app.modules.common.common as common import app.modules.tools.smon_agent as smon_agent @@ -12,7 +12,7 @@ import app.modules.server.server as server_mod @bp.route('/agent', methods=['GET', 'POST', 'PUT', 'DELETE']) -@login_required +@jwt_required() @get_user_params() def agent(): if request.method == 'GET': @@ -61,7 +61,7 @@ def agent_get_checks(): @bp.get('/agent/free') -@login_required +@jwt_required() @get_user_params() def get_free_agents(): group_id = g.user_params['group_id'] @@ -74,7 +74,7 @@ def get_free_agents(): @bp.get('/agent/count') -@login_required +@jwt_required() def get_agent_count(): try: smon_agent.check_agent_limit() @@ -85,7 +85,7 @@ def get_agent_count(): @bp.get('/agent/') -@login_required +@jwt_required() @get_user_params() def get_agent(agent_id): try: @@ -97,7 +97,7 @@ def get_agent(agent_id): @bp.get('/agent/settings/') -@login_required +@jwt_required() def get_agent_settings(agent_id): settings = {} try: @@ -116,7 +116,7 @@ def get_agent_settings(agent_id): @bp.get('/agent/version/') -@login_required +@jwt_required() def get_agent_version(server_ip): agent_id = int(request.args.get('agent_id')) @@ -128,7 +128,7 @@ def get_agent_version(server_ip): @bp.get('/agent/uptime/') -@login_required +@jwt_required() def get_agent_uptime(server_ip): agent_id = int(request.args.get('agent_id')) @@ -140,7 +140,7 @@ def get_agent_uptime(server_ip): @bp.get('/agent/status/') -@login_required +@jwt_required() def get_agent_status(server_ip): agent_id = int(request.args.get('agent_id')) @@ -152,7 +152,7 @@ def get_agent_status(server_ip): @bp.get('/agent/checks/') -@login_required +@jwt_required() def get_agent_checks(server_ip): agent_id = int(request.args.get('agent_id')) @@ -164,7 +164,7 @@ def get_agent_checks(server_ip): @bp.post('/agent/action/') -@login_required +@jwt_required() def agent_action(action): server_ip = common.is_ip_or_dns(request.form.get('server_ip')) diff --git a/app/routes/smon/routes.py b/app/routes/smon/routes.py index 949b7f71..6126861b 100644 --- a/app/routes/smon/routes.py +++ b/app/routes/smon/routes.py @@ -1,7 +1,7 @@ import json from flask import render_template, request, jsonify, g -from flask_login import login_required +from flask_jwt_extended import jwt_required from datetime import datetime from app.routes.smon import bp @@ -16,7 +16,7 @@ import app.modules.tools.common as tools_common @bp.route('/dashboard') -@login_required +@jwt_required() @get_user_params() def smon_main_dashboard(): """ @@ -36,10 +36,10 @@ def smon_main_dashboard(): 'group': group_id, 'smon_status': tools_common.is_tool_active('roxy-wi-smon'), 'user_subscription': roxywi_common.return_user_subscription(), - 'telegrams': channel_sql.get_user_telegram_by_group(group_id), - 'slacks': channel_sql.get_user_slack_by_group(group_id), - 'pds': channel_sql.get_user_pd_by_group(group_id), - 'mms': channel_sql.get_user_mm_by_group(group_id), + 'telegrams': channel_sql.get_user_receiver_by_group('telegram', group_id), + 'slacks': channel_sql.get_user_receiver_by_group('slack', group_id), + 'pds': channel_sql.get_user_receiver_by_group('pd', group_id), + 'mms': channel_sql.get_user_receiver_by_group('mm', group_id), 'sort': request.args.get('sort', None) } @@ -47,7 +47,7 @@ def smon_main_dashboard(): @bp.route('/dashboard//') -@login_required +@jwt_required() @get_user_params() def smon_dashboard(smon_id, check_id): """ @@ -115,7 +115,7 @@ def smon_dashboard(smon_id, check_id): @bp.route('/check', methods=['POST', 'PUT', 'DELETE']) -@login_required +@jwt_required() def smon_add(): json_data = request.get_json() if request.method == "POST": @@ -150,7 +150,7 @@ def smon_add(): @bp.route('/check/settings//') -@login_required +@jwt_required() def check(smon_id, check_type_id): smon = smon_sql.select_one_smon(smon_id, check_type_id) settings = {} @@ -190,7 +190,7 @@ def check(smon_id, check_type_id): @bp.route('/check//') -@login_required +@jwt_required() @get_user_params() def get_check(smon_id, check_type_id): """ @@ -210,7 +210,7 @@ def get_check(smon_id, check_type_id): @bp.route('/status-page', methods=['GET', 'POST', 'DELETE', 'PUT']) -@login_required +@jwt_required() @get_user_params() def status_page(): """ @@ -295,7 +295,7 @@ def status_page(): @bp.route('/status/checks/') -@login_required +@jwt_required() def get_checks(page_id): """ :param page_id: The ID of the page for which to fetch the checks. @@ -327,7 +327,7 @@ def smon_history_statuses_avg(page_id): @bp.route('/history') -@login_required +@jwt_required() @get_user_params() def smon_history(): roxywi_common.check_user_group_for_flask() @@ -344,7 +344,7 @@ def smon_history(): @bp.route('/history/host/') -@login_required +@jwt_required() @get_user_params() def smon_host_history(server_ip): roxywi_common.check_user_group_for_flask() @@ -367,7 +367,7 @@ def smon_host_history(server_ip): @bp.route('/history/metric/') -@login_required +@jwt_required() def smon_history_metric(dashboard_id): return jsonify(smon_mod.history_metrics(dashboard_id)) @@ -378,13 +378,13 @@ def smon_history_statuses(dashboard_id): @bp.route('/history/cur_status//') -@login_required +@jwt_required() def smon_history_cur_status(dashboard_id, check_id): return smon_mod.history_cur_status(dashboard_id, check_id) @bp.post('/refresh') -@login_required +@jwt_required() def smon_show(): sort = common.checkAjaxInput(request.form.get('sort')) return smon_mod.show_smon(sort) diff --git a/app/routes/udp/routes.py b/app/routes/udp/routes.py index 6e14aedd..01e38710 100644 --- a/app/routes/udp/routes.py +++ b/app/routes/udp/routes.py @@ -1,122 +1,14 @@ -from flask import render_template, request, g, jsonify -from flask_login import login_required +from flask_jwt_extended import jwt_required from app.routes.udp import bp -import app.modules.db.udp as udp_sql -import app.modules.db.server as server_sql -import app.modules.db.ha_cluster as ha_sql -import app.modules.common.common as common -import app.modules.roxywi.auth as roxywi_auth -import app.modules.roxywi.common as roxywi_common -import app.modules.service.udp as udp_mod -import app.modules.service.installation as service_mod -from app.middleware import get_user_params, check_services +from app.views.udp.views import UDPListener @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass - -@bp.route('//listener', methods=['GET', 'POST', 'PUT', 'DELETE']) -@check_services -@get_user_params() -def listener_funct(service): - if request.method != 'GET': - roxywi_auth.page_for_admin(level=2) - if request.method == 'GET': - kwargs = { - 'listeners': udp_sql.select_listeners(g.user_params['group_id']), - 'lang': g.user_params['lang'], - 'clusters': ha_sql.select_clusters(g.user_params['group_id']), - 'is_needed_tool': common.is_tool('ansible'), - 'user_subscription': roxywi_common.return_user_subscription() - } - return render_template('udp/listeners.html', **kwargs) - elif request.method == 'POST': - json_data = request.get_json() - json_data['group_id'] = g.user_params['group_id'] - listener_name = json_data['new-listener-name'] - try: - listener_id = udp_mod.create_listener(json_data) - roxywi_common.logging(listener_id, f'UDP listener {listener_name} has been created', roxywi=1, keep_history=1, login=1, service='UDP listener') - return jsonify({'status': 'created', 'listener_id': listener_id}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e,'Cannot create UDP listener') - elif request.method == 'PUT': - json_data = request.get_json() - json_data['group_id'] = g.user_params['group_id'] - listener_name = json_data['new-listener-name'] - listener_id = json_data['listener_id'] - try: - udp_mod.update_listener(json_data) - roxywi_common.logging(listener_id, f'UDP listener {listener_name} has been updated', roxywi=1, keep_history=1, login=1, service='UDP listener') - return jsonify({'status': 'updated'}), 201 - except Exception as e: - return jsonify({'status': 'failed', 'error': str(e)}) - elif request.method == 'DELETE': - kwargs = request.get_json() - listener_id = int(kwargs['listener_id']) - try: - inv, server_ips = service_mod.generate_udp_inv(listener_id, 'uninstall') - service_mod.run_ansible(inv, server_ips, 'udp'), 201 - roxywi_common.logging(listener_id, f'UDP listener has been deleted {listener_id}', roxywi=1, keep_history=1, login=1, service='UDP listener') - except Exception as e: - return roxywi_common.handle_json_exceptions(e,f'Cannot create inventory for UDP listener deleting {listener_id}') - try: - udp_sql.delete_listener(listener_id) - return jsonify({'status': 'deleted'}), 201 - except Exception as e: - return roxywi_common.handle_json_exceptions(e,f'Cannot delete UDP listener {listener_id}') - - -@bp.get('//listener/') -@check_services -@get_user_params() -def get_listener(service, listener_id): - listener = udp_sql.get_listener(listener_id) - cluster = dict() - server = dict() - if listener.cluster_id: - cluster = ha_sql.select_cluster(listener.cluster_id) - elif listener.server_id: - server = server_sql.get_server_by_id(listener.server_id) - kwargs = { - 'clusters': cluster, - 'listener': listener, - 'server': server, - 'lang': g.user_params['lang'], - } - return render_template('udp/listener.html', **kwargs) - - -@bp.get('//listener//settings') -@check_services -@get_user_params() -def get_listener_settings(service, listener_id): - listener_config = udp_mod.get_listener_config(listener_id) - return jsonify(listener_config) - - -@bp.get('//listener//') -@check_services -@get_user_params() -def action_with_listener(service, listener_id, action): - try: - udp_mod.listener_actions(listener_id, action, g.user_params['group_id']) - roxywi_common.logging(listener_id, f'UDP listener {listener_id} has been {action}ed', roxywi=1, keep_history=1, login=1, service='UDP listener') - return jsonify({'status': 'done'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e,f'Cannot {action} listener') - - -@bp.get('//listener//check') -@check_services -def check_listener(service, listener_id): - try: - status = udp_mod.check_is_listener_active(listener_id) - return jsonify({'status': status}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e,f'Cannot get status') +bp.add_url_rule('//listener', view_func=UDPListener.as_view('udp_listener', False), methods=['GET'], defaults={'listener_id': None}) +bp.add_url_rule('//listener/', view_func=UDPListener.as_view('udp_listener_id', False), methods=['GET']) diff --git a/app/routes/user/routes.py b/app/routes/user/routes.py index d2f18744..add6762e 100644 --- a/app/routes/user/routes.py +++ b/app/routes/user/routes.py @@ -1,74 +1,87 @@ import json -from flask import render_template, request, jsonify, g, abort -from flask_login import login_required +from flask import request, jsonify, g +from flask_jwt_extended import jwt_required, get_jwt from app.routes.user import bp -import app.modules.db.sql as sql -import app.modules.db.user as user_sql -import app.modules.db.group as group_sql import app.modules.common.common as common import app.modules.roxywi.user as roxywi_user import app.modules.roxywi.auth as roxywi_auth import app.modules.roxywi.common as roxywi_common from app.middleware import get_user_params +from app.modules.roxywi.class_models import BaseResponse, ErrorResponse +from app.views.user.views import UserView, UserGroupView +def register_api_with_group(view, endpoint, url_beg, url_end, pk='user_id', pk_type='int', pk_end='group_id', pk_type_end='int'): + view_func = view.as_view(endpoint) + bp.add_url_rule(f'/<{pk_type}:{pk}>/{url_end}', view_func=view_func, methods=['GET']) + bp.add_url_rule(f'/<{pk_type}:{pk}>/{url_end}/<{pk_type_end}:{pk_end}>', view_func=view_func, methods=['PUT', 'DELETE', 'POST', 'PATCH']) + + +def register_api(view, endpoint, url, pk='listener_id', pk_type='int'): + view_func = view.as_view(endpoint) + bp.add_url_rule(url, view_func=view_func, methods=['POST']) + bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'DELETE']) + + +register_api(UserView, 'user', '', 'user_id') +register_api_with_group(UserGroupView, 'user_group', '', 'groups') @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass -@bp.route('', methods=['POST', 'PUT', 'DELETE']) -@get_user_params() -def create_user(): - roxywi_auth.page_for_admin(level=2) - json_data = request.get_json() - - if request.method == 'POST': - email = common.checkAjaxInput(json_data['email']) - password = common.checkAjaxInput(json_data['password']) - role = int(json_data['role']) - new_user = common.checkAjaxInput(json_data['username']) - enabled = int(json_data['enabled']) - group_id = int(json_data['user_group']) - lang = roxywi_common.get_user_lang_for_flask() - current_user_role_id = g.user_params['role'] - if not roxywi_common.check_user_group_for_flask(): - return roxywi_common.handle_json_exceptions('Wrong group', 'Roxy-WI server', '') - if current_user_role_id > role: - return roxywi_common.handle_json_exceptions('Wrong role', 'Roxy-WI server', '') - try: - user_id = roxywi_user.create_user(new_user, email, password, role, enabled, group_id) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot create a new user') - else: - return jsonify({'status': 'created', 'id': user_id, 'data': render_template( - 'ajax/new_user.html', users=user_sql.select_users(user=new_user), groups=group_sql.select_groups(), - roles=sql.select_roles(), adding=1, lang=lang - )}) - elif request.method == 'PUT': - user_id = int(json_data['user_id']) - user_name = common.checkAjaxInput(json_data['username']) - email = common.checkAjaxInput(json_data['email']) - enabled = int(json_data['enabled']) - if roxywi_common.check_user_group_for_flask(): - try: - user_sql.update_user_from_admin_area(user_name, email, user_id, enabled) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot update user') - roxywi_common.logging(user_name, ' has been updated user ', roxywi=1, login=1) - return jsonify({'status': 'updated'}) - elif request.method == 'DELETE': - roxywi_auth.page_for_admin(level=2) - user_id = int(json_data['user_id']) - try: - roxywi_user.delete_user(user_id) - return jsonify({'status': 'deleted'}) - except Exception as e: - return roxywi_common.handle_json_exceptions(e, f'Cannot delete the user {user_id}') +# @bp.route('', methods=['POST', 'PUT', 'DELETE']) +# @get_user_params() +# def create_user(): +# roxywi_auth.page_for_admin(level=2) +# json_data = request.get_json() +# +# if request.method == 'POST': +# email = common.checkAjaxInput(json_data['email']) +# password = common.checkAjaxInput(json_data['password']) +# role = int(json_data['role']) +# new_user = common.checkAjaxInput(json_data['username']) +# enabled = int(json_data['enabled']) +# group_id = int(json_data['user_group']) +# lang = roxywi_common.get_user_lang_for_flask() +# current_user_role_id = g.user_params['role'] +# if not roxywi_common.check_user_group_for_flask(): +# return roxywi_common.handle_json_exceptions('Wrong group', 'Roxy-WI server', '') +# if current_user_role_id > role: +# return roxywi_common.handle_json_exceptions('Wrong role', 'Roxy-WI server', '') +# try: +# user_id = roxywi_user.create_user(new_user, email, password, role, enabled, group_id) +# except Exception as e: +# return roxywi_common.handle_json_exceptions(e, 'Cannot create a new user') +# else: +# return jsonify({'status': 'created', 'id': user_id, 'data': render_template( +# 'ajax/new_user.html', users=user_sql.select_users(user=new_user), groups=group_sql.select_groups(), +# roles=sql.select_roles(), adding=1, lang=lang +# )}) +# elif request.method == 'PUT': +# user_id = int(json_data['user_id']) +# user_name = common.checkAjaxInput(json_data['username']) +# email = common.checkAjaxInput(json_data['email']) +# enabled = int(json_data['enabled']) +# if roxywi_common.check_user_group_for_flask(): +# try: +# user_sql.update_user_from_admin_area(user_name, email, user_id, enabled) +# except Exception as e: +# return roxywi_common.handle_json_exceptions(e, 'Cannot update user') +# roxywi_common.logging(user_name, ' has been updated user ', roxywi=1, login=1) +# return jsonify({'status': 'updated'}) +# elif request.method == 'DELETE': +# roxywi_auth.page_for_admin(level=2) +# user_id = int(json_data['user_id']) +# try: +# roxywi_user.delete_user(user_id) +# return jsonify({'status': 'deleted'}) +# except Exception as e: +# return roxywi_common.handle_json_exceptions(e, f'Cannot delete the user {user_id}') @bp.route('/ldap/') @@ -83,21 +96,27 @@ def get_ldap_email(username): @bp.post('/password') -def update_password(): - json_data = request.get_json() - password = json_data['password'] - uuid = '' - user_id = '' - if 'uuid' in json_data: - uuid = common.checkAjaxInput(json_data['uuid']) - else: - user_id = int(json_data['id']) +@get_user_params() +def update_user_its_password(): + password = request.json.get('pass') try: - roxywi_user.update_user_password(password, uuid, user_id) - return jsonify({'status': 'updated'}) + roxywi_user.update_user_password(password, g.user_params['user_id']) + return BaseResponse().model_dump(mode='json') except Exception as e: - return roxywi_common.handle_json_exceptions(e, 'Cannot update password') + return ErrorResponse(error=str(e)).model_dump(mode='json'), 501 + + +@bp.post('/password/') +def update_user_password(user_id): + password = request.json.get('pass') + + try: + roxywi_user.update_user_password(password, user_id) + return BaseResponse().model_dump(mode='json') + except Exception as e: + return ErrorResponse(error=str(e)).model_dump(mode='json'), 501 + @bp.route('/services/', methods=['GET', 'POST']) @@ -117,33 +136,35 @@ def show_user_services(user_id): @bp.route('/group', methods=['GET', 'PUT']) def get_current_group(): + claims = get_jwt() + group_id = claims['group'] + user_id = claims['user_id'] if request.method == 'GET': - uuid = common.checkAjaxInput(request.cookies.get('uuid')) - group = common.checkAjaxInput(request.cookies.get('group')) - return roxywi_user.get_user_active_group(uuid, group) + # uuid = common.checkAjaxInput(request.cookies.get('uuid')) + # group = common.checkAjaxInput(request.cookies.get('group')) + return roxywi_user.get_user_active_group(group_id, user_id) elif request.method == 'PUT': - group_id = common.checkAjaxInput(request.form.get('group')) - user_uuid = common.checkAjaxInput(request.form.get('uuid')) + # group_id = common.checkAjaxInput(request.form.get('group')) + # user_uuid = common.checkAjaxInput(request.form.get('uuid')) - return roxywi_user.change_user_active_group(group_id, user_uuid) + return roxywi_user.change_user_active_group(group_id, user_id) -@bp.route('/groups/') -def show_user_groups_and_roles(user_id): - lang = roxywi_common.get_user_lang_for_flask() - - return roxywi_user.show_user_groups_and_roles(user_id, lang) +# @bp.route('/groups/') +# def show_user_groups_and_roles(user_id): +# lang = roxywi_common.get_user_lang_for_flask() +# +# return roxywi_user.show_user_groups_and_roles(user_id, lang) @bp.post('/groups/save') def change_user_groups_and_roles(): user = common.checkAjaxInput(request.form.get('changeUserGroupsUser')) groups_and_roles = json.loads(request.form.get('jsonDatas')) - user_uuid = request.cookies.get('uuid') - return roxywi_user.save_user_group_and_role(user, groups_and_roles, user_uuid) + return roxywi_user.save_user_group_and_role(user, groups_and_roles) -@bp.route('/group/name/') -def get_group_name_by_id(group_id): - return group_sql.get_group_name_by_id(group_id) +# @bp.route('/group/name/') +# def get_group_name_by_id(group_id): +# return group_sql.get_group_name_by_id(group_id) diff --git a/app/routes/waf/routes.py b/app/routes/waf/routes.py index 50883185..3ab043e9 100644 --- a/app/routes/waf/routes.py +++ b/app/routes/waf/routes.py @@ -1,7 +1,7 @@ import os from flask import render_template, request, g, abort, jsonify -from flask_login import login_required +from flask_jwt_extended import jwt_required, get_jwt from app.routes.waf import bp import app.modules.db.sql as sql @@ -18,7 +18,7 @@ get_config = roxy_wi_tools.GetConfigVar() @bp.before_request -@login_required +@jwt_required() def before_request(): """ Protect all the admin endpoints. """ pass @@ -218,7 +218,9 @@ def overview_waf(service, server_ip): if service not in ('haproxy', 'nginx'): return 'error: Wrong service' - return roxy_waf.waf_overview(server_ip, service) + claims = get_jwt() + + return roxy_waf.waf_overview(server_ip, service, claims) @bp.route('/metric/enable//') diff --git a/app/scripts/ansible/roles/udp/templates/keepalived-udp.conf.j2 b/app/scripts/ansible/roles/udp/templates/keepalived-udp.conf.j2 index d8fe4d46..317c6b56 100644 --- a/app/scripts/ansible/roles/udp/templates/keepalived-udp.conf.j2 +++ b/app/scripts/ansible/roles/udp/templates/keepalived-udp.conf.j2 @@ -7,11 +7,11 @@ virtual_server {{ vip }} {{ port }} { retry 3 -{% for server, value in config.items() %} - real_server {{ server }} {{ value.port }} { - weight {{ value.weight }} +{% for server in config %} + real_server {{ server.backend_ip }} {{ server.port }} { + weight {{ server.weight }} MISC_CHECK { - misc_path "{{ service_dir }}/checks/udp_check.sh {{ server }} {{ value.port }}" + misc_path "{{ service_dir }}/checks/udp_check.sh {{ server.backend_ip }} {{ server.port }}" misc_timeout 5 } } diff --git a/app/static/css/awesome-6.3.9.css b/app/static/css/awesome-6.3.9.css index f875beb4..31004b65 100644 --- a/app/static/css/awesome-6.3.9.css +++ b/app/static/css/awesome-6.3.9.css @@ -35,11 +35,11 @@ font-family: "Font Awesome 5 Regular"; content: "\f080"; } -.logs::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f02d"; -} +/*.logs::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f02d";*/ +/*}*/ .map::before { display: none; font-family: "Font Awesome 5 Solid"; @@ -50,16 +50,16 @@ font-family: "Font Awesome 5 Solid"; content: "\f233"; } -.metrics::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f1fe"; -} -.config-show::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f6ff"; -} +/*.metrics::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f1fe";*/ +/*}*/ +/*.config-show::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f6ff";*/ +/*}*/ .compare::before { display: none; font-family: "Font Awesome 5 Regular"; @@ -76,16 +76,16 @@ .plus-after > .fa-plus, .minus-after > .fa-minus, .minus > .fa-minus, .plus > .fa-plus { color: var(--blue-color); } -.add-proxy::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f067"; -} -.cert::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f0a3"; -} +/*.add-proxy::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f067";*/ +/*}*/ +/*.cert::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f0a3";*/ +/*}*/ .option::before { display: none; font-family: "Font Awesome 5 Regular"; @@ -101,11 +101,11 @@ font-family: "Font Awesome 5 Solid"; content: "\f0cb"; } -.waf-menu::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f06d"; -} +/*.waf-menu::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f06d";*/ +/*}*/ .hap-menu::before { display: none; font-family: "Font Awesome 5 Solid"; @@ -116,11 +116,11 @@ font-family: "Font Awesome 5 Regular"; content: "\f074"; } -.backup::before { - display: none; - font-family: "Font Awesome 5 Regular"; - content: "\f24d"; -} +/*.backup::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Regular";*/ +/* content: "\f24d";*/ +/*}*/ .ha::before { display: none; font-family: "Font Awesome 5 Solid"; @@ -131,11 +131,11 @@ font-family: "Font Awesome 5 Solid"; content: "\f126"; } -.nginx-menu::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f0e8"; -} +/*.nginx-menu::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f0e8";*/ +/*}*/ .apache-menu::before { display: none; font-family: "Font Awesome 5 Solid"; @@ -146,7 +146,7 @@ font-family: "Font Awesome 5 Solid"; content: "\f1da"; } -.tools::before, +/*.tools::before,*/ .services::before { display: none; font-family: "Font Awesome 5 Regular"; @@ -185,11 +185,11 @@ font-family: "Font Awesome 5 Solid"; content: "\f21b"; } -.users::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f234"; -} +/*.users::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f234";*/ +/*}*/ .group::before { display: none; font-family: "Font Awesome 5 Solid"; @@ -200,11 +200,11 @@ font-family: "Font Awesome 5 Regular"; content: "\f2b9"; } -.settings::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f0ad"; -} +/*.settings::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f0ad";*/ +/*}*/ .add-admin::before { display: none; font-family: "Font Awesome 5 Solid"; @@ -362,16 +362,16 @@ .note-symbol .question-circle { padding-left: 5px; } -.port-scanner::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f796"; -} -.net-tools::before { - display: none; - font-family: "Font Awesome 5 Solid"; - content: "\f7d9"; -} +/*.port-scanner::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f796";*/ +/*}*/ +/*.net-tools::before {*/ +/* display: none;*/ +/* font-family: "Font Awesome 5 Solid";*/ +/* content: "\f7d9";*/ +/*}*/ .shield::before { display: none; font-family: "Font Awesome 5 Solid"; diff --git a/app/static/css/nprogress.css b/app/static/css/nprogress.css index c8552c86..403b010b 100644 --- a/app/static/css/nprogress.css +++ b/app/static/css/nprogress.css @@ -37,8 +37,10 @@ height: 40px; box-sizing: border-box; border: solid 5px transparent; - border-top-color: #5d9ceb; - border-left-color: #5d9ceb; + /*border-top-color: #5d9ceb;*/ + /*border-left-color: #5d9ceb;*/ + border-top-color: var(--color-wanring); + border-left-color: var(--color-wanring); border-radius: 50%; -webkit-animation: nprogress-spinner 400ms linear infinite; animation: nprogress-spinner 400ms linear infinite; diff --git a/app/static/css/select2.css b/app/static/css/select2.css index 28647e2b..61d5f78c 100644 --- a/app/static/css/select2.css +++ b/app/static/css/select2.css @@ -1 +1 @@ -.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:24.4px;border-radius: var(--border-radius);user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;#EBF1F1-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline;list-style:none;padding:0}.select2-container .select2-selection--multiple .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;margin-left:5px;padding:0;max-width:100%;resize:none;height:18px;vertical-align:bottom;font-family:Arial,Helvetica,sans-serif;overflow:hidden;word-break:keep-all}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:#EBF1F1;border:1px solid #aaa;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option--selectable{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;#EBF1F1-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#f6f6f6;border:1px solid #c5c5c5;border-radius: 3px;}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:24px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:normal;height:26px;margin-right:20px;padding-right:0px}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:25px;position:absolute;top:0px;right:13px;width:15px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#777 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:#EBF1F1;border:1px solid #aaa;cursor:text;padding-bottom:5px;padding-right:5px;position:relative}.select2-container--default .select2-selection--multiple.select2-selection--clearable{padding-right:25px}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;font-weight:normal;height:20px;margin-right:10px;margin-top:5px;position:absolute;right:0;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;box-sizing:border-box;display:inline-block;margin-left:5px;margin-top:5px;padding:0;padding-left:20px;position:relative;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;#EBF1F1-space:nowrap}.select2-container--default .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-right:1px solid #aaa;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#999;cursor:pointer;font-size:1em;font-weight:normal;padding:0 4px;position:absolute;left:0;top:0}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover,.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:focus{background-color:#f1f1f1;color:#333;outline:none}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-left:1px solid #aaa;border-right:none;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__clear{float:left;margin-left:10px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{background: #EBF1F1;border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;background: #EBF1F1;}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--group{padding:0}.select2-container--default .select2-results__option--disabled{color:#999}.select2-container--default .select2-results__option--selected{background-color:#EBF1F1}.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable{background-color:#4A89D8;color:#EBF1F1}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:normal;height:26px;margin-right:20px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:#EBF1F1;border:1px solid #aaa;cursor:text;outline:0;padding-bottom:5px;padding-right:5px}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;display:inline-block;margin-left:5px;margin-top:5px;padding:0}.select2-container--classic .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#888;cursor:pointer;font-size:1em;font-weight:normal;padding:0 4px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;outline:none}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0,backgtound: #EBF1F1;}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option--group{padding:0}.select2-container--classic .select2-results__option--disabled{color:grey}.select2-container--classic .select2-results__option--highlighted.select2-results__option--selectable{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} \ No newline at end of file +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:24.4px;border-radius: var(--border-radius);user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;#EBF1F1-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline;list-style:none;padding:0}.select2-container .select2-selection--multiple .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;margin-left:5px;padding:0;max-width:100%;resize:none;height:18px;vertical-align:bottom;font-family:Arial,Helvetica,sans-serif;overflow:hidden;word-break:keep-all}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:#EBF1F1;border:1px solid #aaa;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option--selectable{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;#EBF1F1-space:nowrap !important}.select2-container--default .select2-selection--single{background-color: var(--color-gray-alpha);border: none;border-radius: 10px;}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:24px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:normal;height:26px;margin-right:20px;padding-right:0px}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:25px;position:absolute;top:0px;right:13px;width:15px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#777 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:#EBF1F1;border:1px solid #aaa;cursor:text;padding-bottom:5px;padding-right:5px;position:relative}.select2-container--default .select2-selection--multiple.select2-selection--clearable{padding-right:25px}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;font-weight:normal;height:20px;margin-right:10px;margin-top:5px;position:absolute;right:0;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;box-sizing:border-box;display:inline-block;margin-left:5px;margin-top:5px;padding:0;padding-left:20px;position:relative;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;#EBF1F1-space:nowrap}.select2-container--default .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-right:1px solid #aaa;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#999;cursor:pointer;font-size:1em;font-weight:normal;padding:0 4px;position:absolute;left:0;top:0}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover,.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:focus{background-color:#f1f1f1;color:#333;outline:none}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-left:1px solid #aaa;border-right:none;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__clear{float:left;margin-left:10px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{background: #EBF1F1;border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto;background: #EBF1F1;}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--group{padding:0}.select2-container--default .select2-results__option--disabled{color:#999}.select2-container--default .select2-results__option--selected{background-color:#EBF1F1}.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable{background-color:#4A89D8;color:#EBF1F1}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:normal;height:26px;margin-right:20px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:#EBF1F1;border:1px solid #aaa;cursor:text;outline:0;padding-bottom:5px;padding-right:5px}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;display:inline-block;margin-left:5px;margin-top:5px;padding:0}.select2-container--classic .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#888;cursor:pointer;font-size:1em;font-weight:normal;padding:0 4px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;outline:none}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0,backgtound: #EBF1F1;}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option--group{padding:0}.select2-container--classic .select2-results__option--disabled{color:grey}.select2-container--classic .select2-results__option--highlighted.select2-results__option--selectable{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} \ No newline at end of file diff --git a/app/static/css/style-6.3.9.css b/app/static/css/styles.css similarity index 74% rename from app/static/css/style-6.3.9.css rename to app/static/css/styles.css index 0018344d..3426ec52 100644 --- a/app/static/css/style-6.3.9.css +++ b/app/static/css/styles.css @@ -8,32 +8,43 @@ --right-menu-blue-rolor: #5D9CEB; --yellow-color: #ffcc00; --unknown-color: #fff3cd; - --border-radius: 3px; --indent: 15px; + --container--width: 1434px; + --background: #f0f0f0; + --background-dark: #e9e9e9; + --color-black: #000000; + --color-white: #ffffff; + --color-wanring: #ff9501; + --color-secondary: #8d8d8d; + --color-blue: #027f9f; + --color-gray: #D9D9D9; + --color-gray-light: #e7e7e7; + --color-gray-alpha: rgba(217, 217, 217, 0.5); + --color-gray-light-alpha: rgba(217, 217, 217, 0.3); + --color-gray-dark-alpha: rgba(192, 192, 192, 0.3); + --border-radius: 10px; } html { font-size: 10px; } body { - font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; - font-size: 1.2em; - line-height: 1.42857143; - color: #000; - background-color: #fff; - margin: 0; - padding: 0; - overflow: auto; - height:100% + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol; + font-size: 1.2em; + line-height: 1.42857143; + color: #000; + margin: 0; + padding: 0; + overflow: auto; + height: 100%; + background-color: var(--background); } h2 { - font-size: 1.5em; - background: var(--blue-color); - border: 1px solid var(--blue-color); - padding: 2px 3px 3px 15px; - color: #fff; - margin-top: 0; - margin-bottom: 0; - height: 27px; + font-size: 3em; + background-color: transparent; + border: none; + color: var(--color-black); + margin-bottom: 20px; + margin-left: var(--indent); } h3 { margin-top: -0; @@ -49,7 +60,7 @@ ul#browse_history { margin-top: 3px; margin-bottom: -1px; list-style: none; - border-bottom: 1px solid #D9D9D9; + border: none; padding-bottom: 5px; clear: both; } @@ -94,7 +105,7 @@ pre { .icon-hapservs { margin-bottom: 0; } -.top-menu { +.top-menu { position: absolute; min-height: calc(99vh - 50px); height: 120%; @@ -105,14 +116,15 @@ pre { right: 0; left: 0; display: block; - background-color: var(--menu-color); + background-color: var(--color-gray-light) !important; font-size: 12px; z-index: 99; } .menu-active { - padding-left: 30px; - background-color: var(--right-menu-blue-rolor) !important; - border-left: 4px solid var(--right-menu-blue-rolor); + padding-left: 30px; + background-color: var(--color-gray-dark-alpha) !important; + border-left: none; + border-left: 4px solid var(--color-wanring) !important; } .logoText { color: #EBF1F1; @@ -120,25 +132,34 @@ pre { font-style: italic; font-weight: bold; height: 32px; - border-bottom: 1px solid aliceblue; + border-bottom: none; padding-left: 20px; padding-top: 2px; + padding-bottom: 5px; } #logo_text { display: block; - margin-top: -4px; } -.top-menu img { +.menu-logo { max-width: 200px; margin-left: 23px; margin-top: 3px; } +.menu-vendor-logo { + width: 20px; + margin: -20px 5px -6px 0; + padding: 0; +} +.menu-vendor-a { + padding-bottom: 5px; + padding-top: 5px; +} .container { min-height: calc(99vh - 50px); height: auto; max-width: 100%; min-width: 40%; - background-color: #fff; + background-color: var(--background); margin-left: 207px; padding-bottom: 10px; } @@ -148,10 +169,10 @@ pre { left: 0; max-width: 91%; min-width: 40%; - background-color: #fff; + background-color: var(--background); margin-left: 207px; margin-right: 20px; - border-top: 1px solid #ddd; + border-top: none; clear: both; } #version { @@ -160,25 +181,17 @@ pre { font-size: 14.5px; font-weight: bold; } -#logo_footer { - float: left; - margin-left: 43%; -} -#logo_footer_img { - width: 35px; - margin-top: 8px; -} .footer-div { - display: block; + display: block; padding-top: 11px; text-align: right; margin-right: 20px; - width: 380px; + width: 450px; float: left; - margin-left: 16%; + margin-left: 71%; + margin-top: -50px; } .footer-link, .footer-copyright { - color: var(--blue-color); font-size: 0.9em; padding: 12px 5px 20px 15px; } @@ -187,79 +200,60 @@ pre { float: left; margin-left: 10px; } +#main_div { + margin-top: 10%; + margin-left: 35%; + @media (max-width: 1900px) { + margin-top: 7%; + margin-left: 26%; + } + @media (max-width: 1500px) { + margin-left: 25%; + } + @media (max-width: 1024px) { + margin-left: 16%; + } + @media (max-width: 430px) { + margin-left: 12%; + margin-top: 20%; + } +} +#logo_span { + height: 270px; + float: left; + @media (max-width: 1900px) { + margin-left: 12%; + } +} +#logo_span img { + margin: auto 40px auto 100px; + width: 330px; +} .login { float: right; margin-top: 3px; margin-left: 14px; margin-right: 50px; - color: #fff !important; + color: var(--color-wanring) !important; font-size: 15px; cursor: pointer; + @media (width <= 1500px) { + margin-left: -260px; + } } -.auto-refresh { - margin-left: auto; - float: right; - margin-top: 3.7px; - margin-right: 5px; +.logs_link, .accordion-link, .link, .alert a { + color: var(--color-wanring) !important; } -.auto-refresh-span, .auto-refresh a { - color: #fff !important; - cursor: pointer; - font-size: 15px; -} -.auto-refresh-div { - display: none; - position: relative; - padding: 10px; - background-color: #F5F5F5; - border-top: solid 1px #D9D9D9; - margin-bottom: 10px; - line-height: 20px; -} -.auto-refresh-div span, .auto-refresh-div a { - color: #000; - cursor: pointer; -} -.auto-refresh-head { - font-size: 16px; - color: #2d2d2d; - font-weight: bold; - margin-left: 83%; -} -.auto-refresh-interval { - float: right; - padding: 0 15px; - margin-top: 5px; - margin-bottom: 10px; - margin-left: 60%; -} -.auto-refresh-ul{ +#auth { + margin-top: 260px; + margin-left: -310px; float: left; - padding-left: 0; - list-style: none; - margin-top: 10px; -} -.auto-refresh-ul ul li { - margin: 0; - padding: 0 0 0 15px; - border: 0; - font-family: inherit; - vertical-align: baseline; - list-style: none; -} -.auto-refresh-pause, .auto-refresh-resume { - margin-top: 10px; - margin-left: -100px; - position: fixed; - color: #000; - font-size: 12px; - height: 15px; -} -.auto-refresh-reload-icon { - margin-top: 3px; - display: block; - float: left; - margin-right: 5px; + @media (max-width: 1900px) { + margin-left: -260px; + } + @media (width <= 1900px) { + margin-left: -310px; + } } .configShow, .diff { overflow: auto; @@ -302,29 +296,26 @@ pre { font-weight: bold; } .line { - background-color: #f3f8fb; + background-color: var(--background-dark); border: 1px solid #ddd; } .line, .line3 { padding: 5px 10px; } -.line:hover { - background-color: #f6f8fa; -} -.line3:hover { - background-color: #f6f8ff; +.line:hover, .line3:hover { + background-color: var(--color-gray-light); } .accordion-link { float: right; margin-right: 1em; } .time-range { - border: 0; - background-color: #f5faf4; - font-weight: bold; - width: 18px; - padding-left: 0; - padding-right: 0; + border: 0; + background-color: var(--color-gray-light); + font-weight: bold; + width: 18px; + padding-left: 0; + padding-right: 0; } .comment { color: #aaa; @@ -374,27 +365,27 @@ pre { display: block; } .overview-wi { - width: 47%; - min-width: 566px; + width: 47%; + min-width: 566px; max-width: 50%; - min-height: 160px; - float: left; - margin: 0 20px 20px 7px; - border-bottom: 1px solid #D9D9D9; - border-top: 1px solid #D9D9D9; + min-height: 160px; + float: left; + margin: 0 20px 20px 7px; + border: none; } .overviewHead { - border-radius: 5px; - background-color: #fbfbfb; - font-weight: bold; + border-radius: var(--border-radius); + background-color: var(--color-gray-light); + font-weight: bold; } .overview-wi .overviewHead { - border-bottom: 1px solid #A4C7F5; - height: 25px; + height: 25px; + border-radius: var(--border-radius); + background-color: var(--color-gray-alpha); + border: none; } -.overview tr{ - border-bottom: 1px solid #ddd; - border-radius: 5px; +.overview tr { + border: none; } .checkbox { min-width: 30px; @@ -435,7 +426,7 @@ pre { background-color: #ddd; } .add-button { - background-color: var(--blue-color); + background-color: var(--right-menu-blue-rolor); border-radius: 5px; color: #fff; padding: 5px 10px; @@ -515,19 +506,18 @@ ul{ font-size: 1.1em; } .menu a { - background: var(--menu-color); - color: #fff; + background-color: var(--color-gray-light); + color: var(--color-black) !important; padding: 10px; display: block; - border-bottom: 1px solid #666; + border-bottom: none; transition: 0.5s all; cursor: pointer; } .menu a:hover { - background: #48505A; - padding: 10px 0 10px 20px; - color: #fff; - border-left: 4px solid var(--blue-color); + background: var(--color-gray-light) !important; + color: var(--color-wanring) !important; + border-left: none; } .menu li:first-child a, .menu li .v_menu li:first-child a{ border-radius: 3px 3px 0 0; @@ -549,7 +539,7 @@ ul{ transition: 0.5s opacity; } .v_menu a { - background-color: #48505A; + background-color: var(--color-gray-light) !important; } .p_menu:hover .v_menu{ opacity: 1; @@ -559,7 +549,7 @@ ul{ content: ""; position: absolute; border:5px solid; - border-color: transparent transparent transparent #eee; + border-color: transparent var(--color-gray) transparent transparent; top:1em; right: 0.7em; transition: 0.5s; @@ -570,35 +560,23 @@ ul{ .head-submenu { margin-left: 20px; } -@keyframes shadow { - from {box-shadow: 0 0 0 red inset;} - 50% {text-shadow: 0 0 30px black;} - to {box-shadow: 0 -5px 5px -5px rgb(38, 137, 60) inset} -} -@keyframes shadow-red { - from {box-shadow: 0 0 0 red inset;} - 50% {text-shadow: 0 0 30px black;} - to {box-shadow: 0 -5px 5px -5px var(--blue-color) inset} -} -.form-control:hover { - animation: shadow-red 0.3s forwards; -} -.form-control:invalid, .form-control:valid { - background-image: linear-gradient(0deg,#d50000 2px,rgba(213,0,0,0) 0),linear-gradient(0deg,rgba(0,0,0,.26) 1px,transparent 0); -} .form-control { - background: no-repeat bottom,50% calc(100% - 1px); - background-size: 0 100%,100% 100%; - border: 0; + background: no-repeat bottom, 50% calc(100% - 1px); + background-size: 0 100%, 100% 100%; transition: background 1s ease-out; - font-size: 0.9em; + font-size: 0.9em; + border-top: none; + border-left: none; + border-right: none; + border-bottom: 1px solid var(--color-secondary); } .form-login { - background-color: #fff; + background-color: var(--color-gray) !important; padding: 10px 10px 10px 30px; - width: 220px; - background-size: 0 !important; - border: 0 !important; + width: 220px; + background-size: 0 !important; + border: none; + border-radius: var(--border-radius); } .ui-selectmenu-open, .ui-selectmenu-menu { z-index: 1010 !important; @@ -650,7 +628,7 @@ ul{ } .ui-state-active { background-color: #376fb6 !important; - border: none var(--link-dark-blue) !important; + border: none; } .ui-tabs-nav { border-radius: 0 !important; @@ -658,9 +636,10 @@ ul{ padding-top: 0.28em !important; } .ui-tabs .ui-tabs-panel { + background-color: var(--background) !important; padding: 0 !important; padding-bottom: 10px !important; - } +} .ui-tabs { padding-left: 0 !important; margin-left: -2px; @@ -678,6 +657,50 @@ ul{ .ui-state-focus { border: none !important; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited, a.ui-button, a:link.ui-button, a:visited.ui-button, .ui-button { + background-color: var(--color-gray-dark-alpha) !important; + border-radius: 7px !important; + border: none !important; +} +.ui-state-active, .ui-widget-content .ui-state-active { + background-color: var(--color-blue) !important; + color: #fff !important; +} +.ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active { + color: #D6D6D6 !important; + background-color: var(--color-gray-dark-alpha) !important; + border: none !important; +} +.ui-button.ui-state-active:hover { + background-color: var(--color-blue) !important; +} +.ui-icon-blank.ui-icon-blank.ui-icon-blank { + background-color: var(--background) !important; +} +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { + color: var(--color-black) !important; +} +.ui-widget.ui-widget-content, .ui-widget-content { + border: none !important; +} +.ui-widget-header { + background-color: var(--color-gray-light) !important; +} +.ui-dialog { + padding: 0 !important; +} +.ui-dialog .ui-dialog-content { + background-color: var(--background) !important; +} +.ui-widget-content { + background-color: var(--background) !important; +} +.ui-dialog .ui-dialog-title { + color: var(--color-black) !important; +} +.ui-tabs-active, .ui-state-active, .ui-state-focus, .ui-tabs-focus { + border: none !important; +} .need-field { color: var(--red-color); } @@ -688,7 +711,7 @@ a, a:visited { text-decoration: underline; } a { - color: var(--link-dark-blue); + color: var(--color-wanring); text-decoration: none; background-color: transparent; } @@ -700,18 +723,14 @@ a:focus { outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } -.logs_link, .accordion-link, .link { - color: var(--blue-color) !important; +.accordion-link, .link { + color: var(--color-wanring) !important; cursor: pointer; } -.logs_link { - color: var(--link-dark-blue) !important; -} table { border-spacing: 0; border-collapse: collapse; background-color: transparent; - border-top: 1px solid #ddd; border-radius: var(--border-radius); width: 100%; font-size: 1.1em; @@ -728,8 +747,17 @@ td,th { text-align: left; min-width: 25px; } +textarea { + background-color: var(--background); +} +.odd { + background-color: var(--background) !important; +} +.even { + background-color: var(--color-gray-light-alpha) !important; +} .odd:hover, .even:hover { - background-color: var(--light-blue-color); + background-color: var(--color-gray-alpha); } .row { margin-right: -15px; @@ -751,6 +779,7 @@ td,th { } .alert-danger, .alert-info, .alert-success, .alert-warning, .added { margin-top: var(--indent); + border-radius: var(--border-radius); } .alert-danger { color: #a94442; @@ -759,24 +788,23 @@ td,th { margin-bottom: -50px; } .alert-success, .added{ - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; + color: var(--color-blue); + background-color: rgba(2, 159, 201, 0.15); } .alert-info { - color: #0c5460; - background-color: #d1ecf1; - border-color: #bee5eb; - margin-left: var(--indent); + color: #0c5460; + background-color: var(--color-gray-light); + border: none; + margin-left: var(--indent); + border-radius: var(--border-radius); } .alert-warning { - color: #856404; - background-color: var(--unknown-color); - border-color: #ffeeba; + color: #000; + background-color: rgba(255, 149, 1, 0.15); } .wrong-login { display: none; - margin-top: 220px; + margin-top: 450px; margin-right: 50px; width: 300px; text-align: center; @@ -804,19 +832,13 @@ label { font-weight: bold; padding-right: 10px; } -.odd { - background-color: white; -} -.even { - background-color: #f3f8fb; -} #up-pannel { margin-top: var(--indent); } .div-server, .div-server-hapwi, .bin_bout { - background-color: #fbfbfb; - border: 1px solid #A4C7F5; - border-radius: var(--border-radius); + background-color: var(--color-gray-light-alpha); + border: none; + border-radius: var(--border-radius); height: 165px; width: 400px; padding: 10px 15px 20px; @@ -828,19 +850,19 @@ label { height: 95px; } .div-server-head-up { - border-top: 3px solid var(--green-color) !important; + border-top: 7px solid var(--green-color) !important; } .div-server-head-down { - border-top: 3px solid var(--red-color) !important; + border-top: 7px solid var(--red-color) !important; } .div-server-head-dis { - border-top: 3px solid #aaa !important; + border-top: 7px solid #aaa !important; } .div-server-head-pause { - border-top: 3px solid orange !important; + border-top: 7px solid orange !important; } .div-server-head-unknown { - border-top: 3px solid #efdb9d !important; + border-top: 7px solid #efdb9d !important; } .div-server-head-up, .div-server-head-down, .div-server-head-dis, .div-server-head-pause { padding-top: 7px; @@ -858,12 +880,17 @@ label { width: 91.2%; } .server-name { - padding-bottom: 3px; + padding-bottom: 3px; font-size: 1.4em; - color: var(--blue-color); - border-bottom: 1px solid #A4C7F5; - width: 99%; - height: 25px; + color: var(--color-wanring); + width: 99%; + height: 25px; + border: none; +} +.name-span { + width: 260px; + display: inline-block; + margin-top: 3px; } .server-status { border-radius: 50% 50%; @@ -906,12 +933,13 @@ label { float: left; } .ajax-server { - border-radius: var(--border-radius); - margin: 25px 25px 0 787px; - width: 797px; - display: none; - height: 185px; - padding: 10px 0 0 15px; + display: block; + background-color: var(--color-gray-light); + border-radius: var(--border-radius); + margin: 25px 25px 0 787px; + width: 797px; + height: 185px; + padding: 10px 0 0 15px; } .haproxy-info { display: inline-block; @@ -955,16 +983,6 @@ label { .span-link { cursor: pointer; } -#logo_span { - float: left; - margin-left: 8%; - border-right: 3px solid #ddd; - height: 270px; -} -#logo_span img { - margin: auto 40px auto 100px; - width: 330px; -} .chart-container, .chart-container_overview { position: relative; height: 300px; @@ -996,11 +1014,11 @@ label { width: 300px; height: 185px; float: left; - background-color: #fbfbfb;; + background-color: var(--color-gray-light-alpha); margin: 10px 10px 10px 0; padding-left: var(--indent); padding-top: 0; - border: 1px solid #A4C7F5; + border-radius: var(--border-radius); } #good_services { clear: both; @@ -1015,7 +1033,6 @@ label { padding-top: 5px; padding-bottom: 3px; color: var(--blue-color); - border-bottom: 1px solid #A4C7F5; width: 93%; margin-bottom: 5px; } @@ -1046,9 +1063,8 @@ label { border-color: #ebccd1; } .unknown { - color: #856404; - background-color: var(--unknown-color); - border-color: #ffeeba; + color: #e3a556; + background-color: rgba(255, 149, 1, 0.15); } .disable { background-color: grey; @@ -1058,23 +1074,11 @@ label { cursor: pointer; } @media (max-width: 1920px) { - #logo_span { - margin-left: 17%; - } -} -@media (max-width: 1900px) { - #logo_span { - margin-left: 15%; - } .wrong-login { - margin-left: 44%; + margin-left: -360px; } } @media (max-width: 1600px) { - #logo_span img { - width: 300px; - margin: 25px 50px auto 85px; - } .ajax-server { clear: both !important; margin-left: 20px !important; @@ -1083,10 +1087,6 @@ label { } } @media (max-width: 1450px) { - #logo_span img { - width: 250px; - margin: 35px 30px auto 120px; - } .ajax-server, .div-backends { clear: both !important; margin-left: 20px !important; @@ -1112,10 +1112,6 @@ label { } } @media (max-width: 1280px) { - #logo_span img { - width: 250px; - margin: 30px 60px auto 70px; - } .div-pannel { height: 430px !important; } @@ -1134,13 +1130,6 @@ label { } } @media (max-width: 1024px) { - #logo_span { - margin-left: -5%; - } - #logo_span img { - width: 250px; - margin: 35px 0 auto 120px; - } .wrong-login { margin-right: -150px; } @@ -1159,13 +1148,6 @@ label { } } @media (max-width: 1080px) { - #logo_span { - margin-left: -5%; - } - #logo_span img { - width: 250px; - margin: 35px 60px auto 120px; - } .chart-container { position: relative; height: 410px; @@ -1190,14 +1172,6 @@ label { } } @media (max-width: 768px) { - #logo_span { - margin-left: -12%; - border: none; - } - #logo_span img { - width: 250px; - margin: 35px 0 auto 120px; - } .wrong-login { margin-right: -260px; } @@ -1225,14 +1199,6 @@ label { } } @media (max-width: 667px) { - #logo_span { - margin-left: -12%; - border: none; - } - #logo_span img { - width: 250px; - margin: 35px 0 auto 120px; - } .wrong-login { margin-right: -210px; } diff --git a/app/static/images/HAProxy_icon.png b/app/static/images/HAProxy_icon.png new file mode 100644 index 00000000..fa6ead64 Binary files /dev/null and b/app/static/images/HAProxy_icon.png differ diff --git a/app/static/images/NGINX_icon.png b/app/static/images/NGINX_icon.png new file mode 100644 index 00000000..3d12e76d Binary files /dev/null and b/app/static/images/NGINX_icon.png differ diff --git a/app/static/images/logo_login.png b/app/static/images/logo_login.png index 3c4de79d..df9f527e 100644 Binary files a/app/static/images/logo_login.png and b/app/static/images/logo_login.png differ diff --git a/app/static/images/logo_menu.png b/app/static/images/logo_menu.png index 06e406c6..ddb694bd 100644 Binary files a/app/static/images/logo_menu.png and b/app/static/images/logo_menu.png differ diff --git a/app/static/js/add.js b/app/static/js/add.js index 21076bd1..b59f0799 100644 --- a/app/static/js/add.js +++ b/app/static/js/add.js @@ -262,10 +262,10 @@ $( function() { request.term = 1 } $.ajax({ - url: "/app/server/show/ip/" + $("#serv").val(), + url: `/server/${$("#serv").val()}/ip`, + contentType: "application/json; charset=utf-8", success: function (data) { - data = data.replace(/\s+/g, ' '); - response(data.split(" ")); + response(data); } }); }, @@ -282,10 +282,10 @@ $( function() { request.term = 1 } $.ajax({ - url: "/app/server/show/ip/" + $("#serv2").val(), + url: `/server/${$("#serv2").val()}/ip`, + contentType: "application/json; charset=utf-8", success: function (data) { - data = data.replace(/\s+/g, ' '); - response(data.split(" ")); + response(data); } }); }, @@ -302,7 +302,7 @@ $( function() { request.term = 1 } $.ajax({ - url: "/app/runtimeapi/backends/" + $("#serv2").val(), + url: "/runtimeapi/backends/" + $("#serv2").val(), success: function (data) { response(data.split('
')); } @@ -317,7 +317,7 @@ $( function() { request.term = 1 } $.ajax({ - url: "/app/add/haproxy/bwlists/black/" + $("#group_id").val(), + url: "/add/haproxy/bwlists/black/" + $("#group_id").val(), success: function (data) { data = data.replace(/\s+/g, ' '); response(data.split(" ")); @@ -333,7 +333,7 @@ $( function() { request.term = 1 } $.ajax({ - url: "/app/add/haproxy/bwlists/black/" + $("#group_id").val(), + url: "/add/haproxy/bwlists/black/" + $("#group_id").val(), success: function (data) { data = data.replace(/\s+/g, ' '); response(data.split(" ")); @@ -349,7 +349,7 @@ $( function() { request.term = 1 } $.ajax({ - url: "/app/add/haproxy/bwlists/white/" + $("#group_id").val(), + url: "/add/haproxy/bwlists/white/" + $("#group_id").val(), success: function (data) { data = data.replace(/\s+/g, ' '); response(data.split(" ")); @@ -365,7 +365,7 @@ $( function() { request.term = 1 } $.ajax({ - url: "/app/add/haproxy/bwlists/white/" + $("#group_id").val(), + url: "/add/haproxy/bwlists/white/" + $("#group_id").val(), success: function (data) { data = data.replace(/\s+/g, ' '); response(data.split(" ")); @@ -399,7 +399,7 @@ $( function() { }); $("#saved-options").autocomplete({ dataType: "json", - source: "/app/add/option/get/" + $('#group_id').val(), + source: "/add/option/get/" + $('#group_id').val(), autoFocus: true, minLength: 1, select: function (event, ui) { @@ -420,7 +420,7 @@ $( function() { }); $("#saved-options1").autocomplete({ dataType: "json", - source: "/app/add/option/get/" + $('#group_id').val(), + source: "/add/option/get/" + $('#group_id').val(), autoFocus: true, minLength: 1, select: function (event, ui) { @@ -441,7 +441,7 @@ $( function() { }); $("#saved-options2").autocomplete({ dataType: "json", - source: "/app/add/option/get/" + $('#group_id').val(), + source: "/add/option/get/" + $('#group_id').val(), autoFocus: true, minLength: 1, select: function (event, ui) { @@ -457,7 +457,7 @@ $( function() { }); $('#add-option-new').click(function () { $.ajax({ - url: "/app/add/option/save", + url: "/add/option/save", data: { option: $('#new-option').val() }, @@ -481,7 +481,7 @@ $( function() { }); $('[name=servers]').autocomplete({ - source: "/app/add/server/get/" + $('#group_id').val(), + source: "/add/server/get/" + $('#group_id').val(), autoFocus: true, minLength: 1, select: function (event, ui) { @@ -501,7 +501,7 @@ $( function() { }); $('#add-saved-server-new').click(function () { $.ajax({ - url: "/app/add/server/save", + url: "/add/server/save", data: { server: $('#new-saved-servers').val(), desc: $('#new-saved-servers-description').val() @@ -722,7 +722,7 @@ $( function() { $("[name=port_check_text]").show("fast"); } }); - let cur_url = window.location.href.split('/app/').pop(); + let cur_url = window.location.href.split('/').pop(); cur_url = cur_url.split('/'); if (cur_url[0] == "add") { $("#cache").checkboxradio("disable"); @@ -838,7 +838,7 @@ $( function() { source: function (request, response) { if (!checkIsServerFiled('#serv')) return false; $.ajax({ - url: "/app/add/certs/" + $('#serv').val(), + url: "/add/certs/" + $('#serv').val(), success: function (data) { data = data.replace(/\s+/g, ' '); response(data.split(" ")); @@ -852,7 +852,7 @@ $( function() { source: function (request, response) { if (!checkIsServerFiled('#serv2')) return false; $.ajax({ - url: "/app/add/certs/" + $('#serv2').val(), + url: "/add/certs/" + $('#serv2').val(), success: function (data) { data = data.replace(/\s+/g, ' '); response(data.split(" ")); @@ -867,7 +867,7 @@ $( function() { if (!checkIsServerFiled('#ssl_name', 'Enter the Certificate name')) return false; if (!checkIsServerFiled('#ssl_cert', 'Paste the contents of the certificate file')) return false; $.ajax({ - url: "/app/add/cert/add", + url: "/add/cert/add", data: { serv: $('#serv4').val(), ssl_cert: $('#ssl_cert').val(), @@ -893,7 +893,7 @@ $( function() { $('#ssl_key_view').click(function () { if (!checkIsServerFiled('#serv5')) return false; $.ajax({ - url: "/app/add/certs/" + $('#serv5').val(), + url: "/add/certs/" + $('#serv5').val(), success: function (data) { if (data.indexOf('error:') != '-1') { toastr.error(data); @@ -931,7 +931,7 @@ $( function() { } else if (validateEmail(lets_email)) { $("#ajax-ssl").html(wait_mess); $.ajax({ - url: "/app/add/lets", + url: "/add/lets", data: { serv: $('#serv_for_lets').val(), lets_domain: lets_domain, @@ -1324,7 +1324,7 @@ function confirmDeleteOption(id) { function removeOption(id) { $("#option-"+id).css("background-color", "#f2dede"); $.ajax( { - url: "/app/add/option/delete/" + id, + url: "/add/option/delete/" + id, success: function( data ) { data = data.replace(/\s+/g,' '); if (data.indexOf('error:') != '-1') { @@ -1338,7 +1338,7 @@ function removeOption(id) { function updateOptions(id) { toastr.clear(); $.ajax({ - url: "/app/add/option/update", + url: "/add/option/update", data: { option: $('#option-body-' + id).val(), id: id, @@ -1381,7 +1381,7 @@ function confirmDeleteSavedServer(id) { function removeSavedServer(id) { $("#servers-saved-"+id).css("background-color", "#f2dede"); $.ajax( { - url: "/app/add/server/delete/"+id, + url: "/add/server/delete/"+id, success: function( data ) { data = data.replace(/\s+/g,' '); if(data.indexOf('ok') != '-1') { @@ -1393,7 +1393,7 @@ function removeSavedServer(id) { function updateSavedServer(id) { toastr.clear(); $.ajax( { - url: "/app/add/server/update", + url: "/add/server/update", data: { server: $('#servers-ip-'+id).val(), desc: $('#servers-desc-'+id).val(), @@ -1417,7 +1417,7 @@ function view_ssl(id) { let raw_word = translate_div.attr('data-raw'); if(!checkIsServerFiled('#serv5')) return false; $.ajax( { - url: "/app/add/cert/" + $('#serv5').val() + '/' + id, + url: "/add/cert/" + $('#serv5').val() + '/' + id, success: function( data ) { if (data.indexOf('error: ') != '-1') { toastr.error(data); @@ -1453,7 +1453,7 @@ function view_ssl(id) { } function showRawSSL(id) { $.ajax({ - url: "/app/add/cert/get/raw/" + $('#serv5').val() + "/" + id, + url: "/add/cert/get/raw/" + $('#serv5').val() + "/" + id, success: function (data) { if (data.indexOf('error: ') != '-1') { toastr.error(data); @@ -1490,7 +1490,7 @@ function showRawSSL(id) { function deleteSsl(id) { if (!checkIsServerFiled('#serv5')) return false; $.ajax({ - url: "/app/add/cert/" + $("#serv5").val() + "/" + id, + url: "/add/cert/" + $("#serv5").val() + "/" + id, type: "DELETE", success: function (data) { if (data.indexOf('error: ') != '-1') { @@ -1505,10 +1505,10 @@ function deleteSsl(id) { } function change_select_acceleration(id) { $.ajax({ - url: "/app/service/haproxy/version/" + $('#serv' + id + ' option:selected').val(), + url: "/service/haproxy/" + $('#serv' + id + ' option:selected').val() + "/status", + contentType: "application/json; charset=utf-8", success: function (data) { - data = data.replace(/\s+/g, ' '); - if (parseFloat(data) < parseFloat('1.8') || data == ' ') { + if (parseFloat(data.Version.split('-')[0]) < parseFloat('1.8') || data.Version == ' ') { $("#cache" + id).checkboxradio("disable"); } else { $("#cache" + id).checkboxradio("enable"); @@ -1518,9 +1518,10 @@ function change_select_acceleration(id) { } function change_select_waf(id) { $.ajax({ - url: "/app/service/haproxy/version/" + $('#serv' + id + ' option:selected').val(), + url: "/service/haproxy/" + $('#serv' + id + ' option:selected').val() + "/status", + contentType: "application/json; charset=utf-8", success: function (data) { - if (parseFloat(data) < parseFloat('1.8')) { + if (parseFloat(data.Version.split('-')[0]) < parseFloat('1.8') || data.Version == ' ') { $("#waf" + id).checkboxradio("disable"); } else { $("#waf" + id).checkboxradio("enable"); @@ -1536,7 +1537,7 @@ function createList(color) { } list = escapeHtml(list); $.ajax( { - url: "/app/add/haproxy/bwlist/create", + url: "/add/haproxy/bwlist/create", data: { bwlists_create: list, color: color @@ -1560,7 +1561,7 @@ function createList(color) { } function editList(list, color) { $.ajax( { - url: "/app/add/haproxy/bwlist/" + list + "/" + color + "/" + $('#group_id').val(), + url: "/add/haproxy/bwlist/" + list + "/" + color + "/" + $('#group_id').val(), success: function( data ) { if (data.indexOf('error:') != '-1') { toastr.error(data); @@ -1611,7 +1612,7 @@ function saveList(action, list, color) { let serv = $("#serv-" + color + "-list option:selected").val(); if (!checkIsServerFiled($("#serv-" + color + "-list"))) return false; $.ajax({ - url: "/app/add/haproxy/bwlist/save", + url: "/add/haproxy/bwlist/save", data: { bwlists_save: list, serv: serv, @@ -1640,7 +1641,7 @@ function deleteList(list, color) { let serv = $( "#serv-"+color+"-list option:selected" ).val(); if(!checkIsServerFiled($("#serv-"+color+"-list"))) return false; $.ajax({ - url: "/app/add/haproxy/bwlist/delete/" + serv + "/" + color + "/" + list + "/" + $('#group_id').val(), + url: "/add/haproxy/bwlist/delete/" + serv + "/" + color + "/" + list + "/" + $('#group_id').val(), success: function (data) { if (data.indexOf('error:') != '-1' || data.indexOf('Failed') != '-1' || data.indexOf('Errno') != '-1') { toastr.error(data); @@ -1659,7 +1660,7 @@ function createMap() { map_name = $('#new_map_name').val() map_name = escapeHtml(map_name); $.ajax( { - url: "/app/add/map", + url: "/add/map", data: { map_name: map_name }, @@ -1682,7 +1683,7 @@ function createMap() { } function editMap(map) { $.ajax({ - url: "/app/add/map", + url: "/add/map", data: { map_name: map, }, @@ -1737,7 +1738,7 @@ function saveMap(action, map) { let serv = $( "#serv-map option:selected" ).val(); if(!checkIsServerFiled($("#serv-map"))) return false; $.ajax({ - url: "/app/add/map", + url: "/add/map", data: { map_name: map, serv: serv, @@ -1765,7 +1766,7 @@ function deleteMap(map) { let serv = $( "#serv-map option:selected" ).val(); if(!checkIsServerFiled($("#serv-map"))) return false; $.ajax({ - url: "/app/add/map", + url: "/add/map", data: { map_name: map, serv: serv, @@ -2071,10 +2072,10 @@ function make_actions_for_adding_bind(section_id) { request.term = 1 } $.ajax({ - url: "/app/server/show/ip/" + $("#" + serv).val(), + url: "/server/" + $("#" + serv).val() + "/ip", + contentType: "application/json; charset=utf-8", success: function (data) { - data = data.replace(/\s+/g, ' '); - response(data.split(" ")); + response(data); } }); }, @@ -2099,7 +2100,7 @@ function showUserlists() { let select_id = $("#existing_userlist_serv"); if (!checkIsServerFiled(select_id)) return false; $.ajax({ - url: "/app/add/haproxy/userlist/" + serv, + url: "/add/haproxy/userlist/" + serv, success: function (data) { if (data.indexOf('error:') != '-1' || data.indexOf('Failed') != '-1') { toastr.error(data); @@ -2111,7 +2112,7 @@ function showUserlists() { let existing_userlist_ajax = $.find("#existing_userlist_ajax"); existing_userlist_ajax = existing_userlist_ajax[0].id; data[i] = escapeHtml(data[i]); - $('#' + existing_userlist_ajax).append('' + data[i] + ' '); + $('#' + existing_userlist_ajax).append('' + data[i] + ' '); } } } diff --git a/app/static/js/admin/admin_settings.js b/app/static/js/admin/admin_settings.js index f0e865c3..4b60b8d9 100644 --- a/app/static/js/admin/admin_settings.js +++ b/app/static/js/admin/admin_settings.js @@ -36,19 +36,21 @@ $( function() { var id = $(this).attr('id'); var val = $(this).val(); updateSettings(id, val); - updateSettings(id[1]) + let section = $(this).parent().parent().attr('class').split(' ')[1].split('-')[0]; + updateSettings(id, section, val); }); $( "#settings input" ).change(function() { var id = $(this).attr('id'); var val = $(this).val(); if($('#'+id).is(':checkbox')) { if ($('#'+id).is(':checked')){ - val = 1; + val = '1'; } else { - val = 0; + val = '0'; } } - updateSettings(id, val); + let section = $(this).parent().parent().attr('class').split(' ')[1].split('-')[0]; + updateSettings(id, section, val); }); }); function hideAndShowSettings(section) { @@ -65,23 +67,27 @@ function hideAndShowSettings(section) { $.getScript(awesome); } } -function updateSettings(param, val) { +function updateSettings(param, section, val) { try { val = val.replace(/\//g, "92"); } catch (e) { val = val; } toastr.clear(); + let json_data = { + 'param': param, + 'value': val + } + if (section === 'smon') { + section = 'rmon'; + } $.ajax({ - url: "/app/admin/setting/" + param, - data: { - val: val, - token: $('#token').val() - }, + url: "/admin/settings/" + section, + data: JSON.stringify(json_data), type: "POST", + contentType: "application/json; charset=utf-8", success: function (data) { - data = data.replace(/\s+/g, ' '); - if (data.indexOf('error:') != '-1') { + if (data.status === 'failed') { toastr.error(data); } else { toastr.clear(); diff --git a/app/static/js/admin/common.js b/app/static/js/admin/common.js index d36edbb3..c5428b11 100644 --- a/app/static/js/admin/common.js +++ b/app/static/js/admin/common.js @@ -3,12 +3,7 @@ $( function() { let activeTab = $(this).find("a").attr("href"); let activeTabClass = activeTab.replace('#', ''); $('.menu li ul li').each(function () { - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('padding-left', '20px') - $(this).find('a').css('background-color', '#48505A'); - $(this).children("." + activeTabClass).css('padding-left', '30px'); - $(this).children("." + activeTabClass).css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children("." + activeTabClass).css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), activeTabClass) }); if (activeTab == '#tools') { loadServices(); @@ -24,7 +19,7 @@ $( function() { window.onload = function() { $('#tabs').tabs(); let activeTabIdx = $('#tabs').tabs('option','active') - if (cur_url[0].split('#')[0] == 'admin') { + if (cur_url.split('#')[0] == 'admin') { if (activeTabIdx == 6) { loadServices(); } else if (activeTabIdx == 3) { @@ -40,7 +35,7 @@ function updateService(service, action='update') { $("#ajax-update").html('') $("#ajax-update").html(wait_mess); $.ajax({ - url: "/app/admin/tools/update/" + service, + url: "/admin/tools/update/" + service, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('Complete!') != '-1' || data.indexOf('Unpacking') != '-1') { @@ -90,7 +85,7 @@ function updateService(service, action='update') { } function loadSettings() { $.ajax({ - url: "/app/admin/settings", + url: "/admin/settings", success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1') { @@ -106,7 +101,7 @@ function loadSettings() { } function loadServices() { $.ajax({ - url: "/app/admin/tools", + url: "/admin/tools", success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('danger') != '-1' || data.indexOf('unique') != '-1' || data.indexOf('error:') != '-1') { @@ -120,7 +115,7 @@ function loadServices() { } function loadupdatehapwi() { $.ajax({ - url: "/app/admin/update", + url: "/admin/update", success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('danger') != '-1' || data.indexOf('unique') != '-1' || data.indexOf('error:') != '-1') { @@ -133,7 +128,7 @@ function loadupdatehapwi() { } function checkUpdateRoxy() { $.ajax({ - url: "/app/admin/update/check", + url: "/admin/update/check", success: function (data) { loadupdatehapwi(); } @@ -163,7 +158,7 @@ function confirmAjaxServiceAction(action, service) { } function ajaxActionServices(action, service) { $.ajax( { - url: "/app/admin/tools/action/" + service + "/" + action, + url: "/admin/tools/action/" + service + "/" + action, success: function( data ) { if (data.indexOf('error:') != '-1' || data.indexOf('Failed') != '-1') { toastr.error(data); @@ -185,7 +180,7 @@ function showApacheLog(serv) { let minute = $('#time_range_out_minut').val(); let hour1 = $('#time_range_out_hour1').val(); let minute1 = $('#time_range_out_minut1').val(); - let url = "/app/logs/apache_internal/" + serv + "/" + rows; + let url = "/logs/apache_internal/" + serv + "/" + rows; $.ajax( { url: url, data: { diff --git a/app/static/js/admin/group.js b/app/static/js/admin/group.js index 22bbff8c..37338e00 100644 --- a/app/static/js/admin/group.js +++ b/app/static/js/admin/group.js @@ -39,13 +39,15 @@ function addGroup(dialog_id) { let allFields = $([]).add($('#new-group-add')); allFields.removeClass("ui-state-error"); valid = valid && checkLength($('#new-group-add'), "new group name", 1); + let name = $('#new-group-add').val(); + let desc = $('#new-desc').val(); if (valid) { let jsonData = { - 'name': $('#new-group-add').val(), - 'desc': $('#new-desc').val() + 'name': name, + 'desc': desc } $.ajax({ - url: "/app/server/group", + url: "/server/group", type: 'POST', data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", @@ -55,7 +57,19 @@ function addGroup(dialog_id) { } else { let id = data.id; $('select:regex(id, group)').append('').selectmenu("refresh"); - common_ajax_action_after_success(dialog_id, 'newgroup', 'ajax-group', data.data); + let new_group = elem("tr", {"id":"group-"+id,"class":"newgroup"}, [ + elem("td", {"class":"padding10","style":"width: 0"}, id), + elem("td", {"class":"padding10 first-collumn"}, [ + elem("input", {"type":"text","name":"name-"+id,"value": name,"id":"name-"+id,"class":"form-control","autocomplete":"off"}) + ]), + elem("td", null, [ + elem("input", {"type":"text","name":"descript-"+id,"value":desc,"id":"descript-"+id,"size":"60","class":"form-control","autocomplete":"off"}) + ]), + elem("td", null, [ + elem("a", {"class":"delete","onclick":"confirmDeleteGroup("+id+")","title":"Delete group "+name,"style":"cursor: pointer;"}) + ]) + ]) + common_ajax_action_after_success(dialog_id, 'newgroup', 'ajax-group', new_group); } } }); @@ -66,10 +80,9 @@ function updateGroup(id) { let jsonData = { "name": $('#name-' + id).val(), "desc": $('#descript-' + id).val(), - "group_id": id } $.ajax({ - url: "/app/server/group", + url: "/server/group/" + id, type: "PUT", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", @@ -112,31 +125,41 @@ function confirmDeleteGroup(id) { function removeGroup(id) { $("#group-" + id).css("background-color", "#f2dede"); $.ajax({ - url: "/app/server/group", + url: "/server/group/" + id, type: 'DELETE', - data: JSON.stringify({'group_id': id}), contentType: "application/json; charset=utf-8", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { - $("#group-" + id).remove(); + statusCode: { + 204: function (xhr) { + $("#group-" + id).remove(); $('select:regex(id, group) option[value=' + id + ']').remove(); $('select:regex(id, group)').selectmenu("refresh"); - } - } + }, + 404: function (xhr) { + $("#group-" + id).remove(); + $('select:regex(id, group) option[value=' + id + ']').remove(); + $('select:regex(id, group)').selectmenu("refresh"); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } + } + } }); } function getGroupNameById(group_id) { let group_name = '' $.ajax({ - url: "/app/user/group/name/" + group_id, + url: "/server/group/" + group_id, async: false, + contentType: "application/json; charset=utf-8", success: function (data) { - if (data.indexOf('error:') != '-1') { + if (data.status === 'failed') { toastr.error(data); } else { - group_name = data; + group_name = data.name; } } }); diff --git a/app/static/js/admin/server.js b/app/static/js/admin/server.js index 5bd28775..b2ec3dbd 100644 --- a/app/static/js/admin/server.js +++ b/app/static/js/admin/server.js @@ -65,7 +65,7 @@ function addServer(dialog_id) { if ($('#scan_server').is(':checked')) { scan_server = '1'; } - if ($('#typeip').is(':checked')) { + if ($('#type_ip').is(':checked')) { type_ip = '1'; } if ($('#enable').is(':checked')) { @@ -104,24 +104,24 @@ function addServer(dialog_id) { } if (valid) { let json_data = { - "name": servername, + "hostname": servername, "ip": ip, "port": $('#new-port').val(), - "group": server_group, + "group_id": server_group, "type_ip": type_ip, "haproxy": haproxy, 'nginx': nginx, "apache": apache, - "firewall": firewall, + "firewall_enable": firewall, "add_to_smon": add_to_smon, - "enable": enable, - "slave": $('#slavefor').val(), - "cred": cred, - "desc": $('#desc').val(), + "enabled": enable, + "master": $('#slavefor').val(), + "cred_id": cred, + "description": $('#desc').val(), "protected": 0 } $.ajax({ - url: "/app/server", + url: "/server", type: "POST", data: JSON.stringify(json_data), contentType: "application/json; charset=utf-8", @@ -145,40 +145,18 @@ function addServer(dialog_id) { $('select:regex(id, haproxyaddserv)').append('').selectmenu("refresh"); $('select:regex(id, nginxaddserv)').append('').selectmenu("refresh"); $('select:regex(id, apacheaddserv)').append('').selectmenu("refresh"); - after_server_creating(servername, ip, scan_server); } } }); } } -function after_server_creating(servername, ip, scan_server) { - let json_data = { - "name": servername, - "ip": ip, - "scan_server": scan_server - } - $.ajax({ - url: "/app/server", - data: JSON.stringify(json_data), - contentType: "application/json; charset=utf-8", - type: "PATCH", - success: function (data) { - data = data.replace(/\s+/g, ' '); - if (data.indexOf('You should install lshw on the server') != '-1') { - toastr.error(data); - } else if (data.indexOf('error:') != '-1') { - toastr.error(data); - } - } - }); -} function updateServer(id) { toastr.clear(); let type_ip = 0; let enable = 0; let firewall = 0; let protected_serv = 0; - if ($('#typeip-' + id).is(':checked')) { + if ($('#type_ip-' + id).is(':checked')) { type_ip = '1'; } if ($('#enable-' + id).is(':checked')) { @@ -195,20 +173,20 @@ function updateServer(id) { group = $('#new-sshgroup').val(); } let json_data = { - "name": $('#hostname-' + id).val(), + "hostname": $('#hostname-' + id).val(), "port": $('#port-' + id).val(), - "group": group, + "ip": $('#ip-' + id).text(), + "group_id": group, "type_ip": type_ip, - "firewall": firewall, - "enable": enable, - "slave": $('#slavefor-' + id + ' option:selected').val(), - "cred": $('#credentials-' + id + ' option:selected').val(), - "id": id, - "desc": $('#desc-' + id).val(), + "firewall_enable": firewall, + "enabled": enable, + "master": $('#slavefor-' + id + ' option:selected').val(), + "cred_id": $('#credentials-' + id + ' option:selected').val(), + "description": $('#desc-' + id).val(), "protected": protected_serv } $.ajax({ - url: "/app/server", + url: "/server/" + id, type: 'PUT', contentType: "application/json; charset=utf-8", data: JSON.stringify(json_data), @@ -253,10 +231,10 @@ function cloneServer(id) { } else { $('#enable').prop('checked', false) } - if ($('#typeip-'+id).is(':checked')) { - $('#typeip').prop('checked', true) + if ($('#type_ip-'+id).is(':checked')) { + $('#type_ip').prop('checked', true) } else { - $('#typeip').prop('checked', false) + $('#type_ip').prop('checked', false) } if ($('#haproxy-'+id).is(':checked')) { $('#haproxy').prop('checked', true) @@ -269,7 +247,7 @@ function cloneServer(id) { $('#nginx').prop('checked', false) } $('#enable').checkboxradio("refresh"); - $('#typeip').checkboxradio("refresh"); + $('#type_ip').checkboxradio("refresh"); $('#haproxy').checkboxradio("refresh"); $('#nginx').checkboxradio("refresh"); $('#new-server-add').val($('#hostname-'+id).val()) @@ -288,22 +266,29 @@ function cloneServer(id) { function removeServer(id) { $("#server-" + id).css("background-color", "#f2dede"); $.ajax({ - url: "/app/server", + url: "/server/" + id, type: "DELETE", - data: JSON.stringify({'id': id}), contentType: "application/json; charset=utf-8", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { + statusCode: { + 204: function (xhr) { $("#server-" + id).remove(); + }, + 404: function (xhr) { + $("#server-" + id).remove(); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } } } }); } function viewFirewallRules(ip) { $.ajax({ - url: "/app/server/firewall/" + ip, + url: "/server/firewall/" + ip, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('danger') != '-1' || data.indexOf('unique') != '-1' || data.indexOf('error: ') != '-1') { @@ -330,7 +315,7 @@ function viewFirewallRules(ip) { } function updateServerInfo(ip, id) { $.ajax({ - url: "/app/server/system_info/update/" + ip + "/" + id, + url: "/server/system_info/update/" + ip + "/" + id, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1' || data.indexOf('error_code') != '-1') { @@ -346,7 +331,7 @@ function updateServerInfo(ip, id) { function showServerInfo(id, ip) { let server_info = translate_div.attr('data-server_info'); $.ajax({ - url: "/app/server/system_info/get/" + ip + "/" +id, + url: "/server/system_info/get/" + ip + "/" +id, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1' || data.indexOf('error_code') != '-1') { @@ -374,7 +359,7 @@ function showServerInfo(id, ip) { async function serverIsUp(server_id) { let random_sleep = getRandomArbitrary(1000, 10000); await sleep(random_sleep); - const source = new EventSource(`/app/server/check/server/${server_id}`); + const source = new EventSource(`/server/check/server/${server_id}`); let server_div = $('#server_status-' + server_id); source.onmessage = function (event) { let data = JSON.parse(event.data); @@ -397,7 +382,7 @@ async function serverIsUp(server_id) { $('#hostname-' + server_id).val(data.name); $('#ip-' + server_id).val(data.ip); $('#port-' + server_id).val(data.port); - $('#desc-' + server_id).val(data.desc); + $('#desc-' + server_id).val(data.description); if (data.enabled === 1) { $('#enable-' + server_id).prop('checked', true); } else { @@ -409,11 +394,11 @@ async function serverIsUp(server_id) { $('#protected-' + server_id).prop('checked', false); } if (data.type_ip === 1) { - $('#typeip-' + server_id).prop('checked', true); + $('#type_ip-' + server_id).prop('checked', true); } else { - $('#typeip-' + server_id).prop('checked', false); + $('#type_ip-' + server_id).prop('checked', false); } - $('#typeip-' + server_id).checkboxradio("refresh"); + $('#type_ip-' + server_id).checkboxradio("refresh"); $('#protected-' + server_id).checkboxradio("refresh"); $('#enable-' + server_id).checkboxradio("refresh"); $('#servergroup-' + server_id).val(data.group_id).change(); @@ -431,7 +416,7 @@ function openChangeServerServiceDialog(server_id) { let user_groups_word = translate_div.attr('data-user_groups'); let hostname = $('#hostname-' + server_id).val(); $.ajax({ - url: "/app/server/services/" + server_id, + url: "/server/services/" + server_id, success: function (data) { $("#groups-roles").html(data); $("#groups-roles").dialog({ @@ -493,7 +478,7 @@ function changeServerServices(server_id) { jsonData[this_id] = 0 }); $.ajax({ - url: "/app/server/services/" + server_id, + url: "/server/services/" + server_id, data: { jsonDatas: JSON.stringify(jsonData), changeServerServicesServer: $('#hostname-' + server_id).val(), diff --git a/app/static/js/admin/ssh.js b/app/static/js/admin/ssh.js index 8636b786..f0f118fe 100644 --- a/app/static/js/admin/ssh.js +++ b/app/static/js/admin/ssh.js @@ -68,14 +68,14 @@ function addCreds(dialog_id) { valid = valid && checkLength($('#ssh_user'), "Credentials", 1); if (valid) { let jsonData = { - "ssh": ssh_add_div.val(), - "group": $('#new-sshgroup').val(), - "user": $('#ssh_user').val(), + "name": ssh_add_div.val(), + "group_id": $('#new-sshgroup').val(), + "username": $('#ssh_user').val(), "pass": $('#ssh_pass').val(), - "enabled": ssh_enable, + "key_enabled": ssh_enable, } $.ajax({ - url: "/app/server/ssh", + url: "/server/cred", type: "POST", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", @@ -123,14 +123,13 @@ function updateSSH(id) { } let jsonData = { "name": ssh_name_val, - "group": group, - "ssh_enable": ssh_enable, - "ssh_user": $('#ssh_user-' + id).val(), - "ssh_pass": $('#ssh_pass-' + id).val(), - "id": id + "group_id": group, + "key_enabled": ssh_enable, + "username": $('#ssh_user-' + id).val(), + "password": $('#ssh_pass-' + id).val(), } $.ajax({ - url: "/app/server/ssh", + url: "/server/cred/" + id, data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: "PUT", @@ -175,52 +174,58 @@ function confirmDeleteSsh(id) { function removeSsh(id) { $("#ssh-table-" + id).css("background-color", "#f2dede"); $.ajax({ - url: "/app/server/ssh", + url: "/server/cred/" + id, type: "DELETE", - data: JSON.stringify({"id": id}), contentType: "application/json; charset=utf-8", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { + statusCode: { + 204: function (xhr) { $("#ssh-table-" + id).remove(); $('select:regex(id, credentials) option[value=' + id + ']').remove(); $('select:regex(id, credentials)').selectmenu("refresh"); + }, + 404: function (xhr) { + $("#ssh-table-" + id).remove(); + $('select:regex(id, credentials) option[value=' + id + ']').remove(); + $('select:regex(id, credentials)').selectmenu("refresh"); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } } } }); } function uploadSsh() { - toastr.clear(); - if ($("#ssh-key-name option:selected").val() == "------" || $('#ssh_cert').val() == '') { - toastr.error('All fields must be completed'); - } else { - let jsonData = { - "ssh_cert": $('#ssh_cert').val(), - "name": $('#ssh-key-name').val(), - "pass": $('#ssh-key-pass').val() - } - $.ajax({ - url: "/app/server/ssh", - type: "PATCH", - data: JSON.stringify(jsonData), - contentType: "application/json; charset=utf-8", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else if (data.status === 'uploaded') { - toastr.clear(); - toastr.success(data.message) - } else { - toastr.error('Something wrong, check and try again'); - } - } - }); + toastr.clear(); + if ($("#ssh-key-name option:selected").val() == "------" || $('#ssh_cert').val() == '') { + toastr.error('All fields must be completed'); + return false; + } + let jsonData = { + "private_key": $('#ssh_cert').val(), + "passphrase": $('#ssh-key-pass').val(), } + $.ajax({ + url: "/server/cred/" + $('#ssh-key-name').val().split("_")[0], + data: JSON.stringify(jsonData), + contentType: "application/json; charset=utf-8", + type: "PATCH", + success: function (data) { + if (data.status === 'failed') { + toastr.error(data.error); + } else { + toastr.clear(); + toastr.success('The SSH key has been loaded') + } + } + }); } function checkSshConnect(ip) { $.ajax({ - url: "/app/server/check/ssh/" + ip, + url: "/server/check/ssh/" + ip, success: function (data) { if (data.indexOf('error:') != '-1') { toastr.error(data) diff --git a/app/static/js/admin/user.js b/app/static/js/admin/user.js index 6003458b..fd0bd8ce 100644 --- a/app/static/js/admin/user.js +++ b/app/static/js/admin/user.js @@ -1,5 +1,6 @@ -var cur_url = window.location.href.split('/app/').pop(); -cur_url = cur_url.split('/'); +var cur_url = window.location.href.split('/').pop(); +// cur_url = cur_url.split('/'); +let superAdmin_pass = translate_div.attr('data-superAdmin_pass'); $( function() { $('#add-user-button').click(function () { addUserDialog.dialog('open'); @@ -35,11 +36,21 @@ $( function() { }); $("#ajax-users input").change(function () { let id = $(this).attr('id').split('-'); - updateUser(id[1]) + if ($('#role-'+id + ' option:selected' ).val() === 'Select a role') { + toastr.warning(superAdmin_pass); + return false; + } else { + updateUser(id[1]) + } }); $("#ajax-users select").on('selectmenuchange', function () { let id = $(this).attr('id').split('-'); - updateUser(id[1]) + if ($('#role-'+id + ' option:selected' ).val() === 'Select a role') { + toastr.warning(superAdmin_pass); + return false; + } else { + updateUser(id[1]) + } }); $('#search_ldap_user').click(function () { toastr.clear(); @@ -51,7 +62,7 @@ $( function() { let user = username_div.val() if (valid) { $.ajax({ - url: "/app/user/ldap/" + user, + url: "/user/ldap/" + user, contentType: "application/json; charset=utf-8", success: function (data) { if (data.status === 'failed') { @@ -103,7 +114,7 @@ function addUser(dialog_id) { "user_group": user_group, } $.ajax({ - url: "/app/user", + url: "/user", type: "POST", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", @@ -142,15 +153,22 @@ function confirmDeleteUser(id) { function removeUser(id) { $("#user-" + id).css("background-color", "#f2dede"); $.ajax({ - url: "/app/user", - data: JSON.stringify({'user_id': id}), + url: "/user/" + id, contentType: "application/json; charset=utf-8", type: "DELETE", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { + statusCode: { + 204: function (xhr) { $("#user-" + id).remove(); + }, + 404: function (xhr) { + $("#user-" + id).remove(); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } } } }); @@ -165,10 +183,9 @@ function updateUser(id) { "username": $('#login-' + id).val(), "email": $('#email-' + id).val(), "enabled": enabled, - "user_id": id } $.ajax({ - url: "/app/user", + url: "/user/" + id, type: "PUT", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", @@ -192,10 +209,9 @@ function openChangeUserServiceDialog(id) { changeUserServiceDialog(id); } function changeUserPasswordDialog(id) { - let superAdmin_pass = translate_div.attr('data-superAdmin_pass'); let change_word = translate_div.attr('data-change2'); let password_word = translate_div.attr('data-password'); - if ($('#role-'+id + ' option:selected' ).val() == 'Select a role') { + if ($('#role-'+id + ' option:selected' ).val() === 'Select a role') { toastr.warning(superAdmin_pass); return false; } @@ -229,25 +245,21 @@ function changeUserPasswordDialog(id) { }); } function changeUserPassword(id, d) { - let pass = $('#change-password').val(); - let pass2 = $('#change2-password').val(); + var pass = $('#change-password').val(); + var pass2 = $('#change2-password').val(); if (pass != pass2) { $('#missmatchpass').show(); } else { $('#missmatchpass').hide(); toastr.clear(); - let jsonData = { - "password": pass, - "id": id - } $.ajax({ - url: "/app/user/password", - data: JSON.stringify(jsonData), - contentType: "application/json; charset=utf-8", + url: "/user/password/" + id, + data: JSON.stringify({'pass': pass,}), type: "POST", + contentType: "application/json; charset=utf-8", success: function (data) { if (data.status === 'failed') { - toastr.error(data.error); + toastr.error(data); } else { toastr.clear(); $("#user-" + id).addClass("update", 1000); @@ -270,7 +282,7 @@ function changeUserServiceDialog(id) { return false; } $.ajax({ - url: "/app/user/services/" + id, + url: "/user/services/" + id, success: function (data) { if (data.indexOf('danger') != '-1') { toastr.error(data); @@ -310,7 +322,7 @@ function changeUserServices(user_id) { jsonData['services'][user_id][this_id] = {} }); $.ajax( { - url: "/app/user/services/" + user_id, + url: "/user/services/" + user_id, data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: "POST", @@ -355,10 +367,19 @@ function removeServiceFromUser(service_id) { function confirmChangeGroupsAndRoles(user_id) { let user_groups_word = translate_div.attr('data-user_groups'); let username = $('#login-' + user_id).val(); + let groups = getAllGroups(); $.ajax({ - url: "/app/user/groups/" + user_id, + url: "/user/" + user_id + "/groups", + contentType: "application/json; charset=utf-8", success: function (data) { - $("#groups-roles").html(data); + $("#checked_groups tbody").html(''); + $("#all_groups tbody").html(''); + for (let group of groups) { + removeGroupFromUser(group.group_id, group.name, group.description) + } + for (let group of data) { + addGroupToUser(group.user_group_id, group.user_role_id); + } $("#groups-roles").dialog({ resizable: false, height: "auto", @@ -381,29 +402,40 @@ function confirmChangeGroupsAndRoles(user_id) { } }); } -function addGroupToUser(group_id) { - let group_name = $('#add_group-'+group_id).attr('data-group_name'); +function addGroupToUser(group_id, user_role_id=0) { + let group_name = $('#add_group-' + group_id).attr('data-group_name'); let group2_word = translate_div.attr('data-group2'); let length_tr = $('#all_groups tbody tr').length; const roles = {1: 'superAdmin', 2: 'admin', 3: 'user', 4: 'guest'}; let options_roles = ''; for (const [role_id, role_name] of Object.entries(roles)) { - options_roles += ''; + console.log(user_role_id) + if (user_role_id === Number(role_id)) { + options_roles += ''; + } else { + options_roles += ''; + } } let tr_class = 'odd'; if (length_tr % 2 != 0) { tr_class = 'even'; } - let html_tag = '\n' + - ' '+group_name+'\n' + + let html_tag = '\n' + + ' ' + group_name + '\n' + ' \n' + - ' \n' + - ' -' - $('#add_group-'+group_id).remove(); + ' \n' + + ' -' + $('#add_group-' + group_id).remove(); $("#checked_groups tbody").append(html_tag); } -function removeGroupFromUser(group_id) { +function removeGroupFromUser(group_id, name=false, desc=false) { let group_name = $('#remove_group-'+group_id).attr('data-group_name'); + let description = ''; + if (name) { + group_name = name; + description = desc; + } + let group2_word = translate_div.attr('data-group2'); let length_tr = $('#all_groups tbody tr').length; let tr_class = 'odd'; @@ -412,7 +444,7 @@ function removeGroupFromUser(group_id) { } let html_tag = '\n' + ' '+group_name+'\n' + - ' +' + ' +' $('#remove_group-'+group_id).remove(); $("#all_groups tbody").append(html_tag); } @@ -432,7 +464,7 @@ function saveGroupsAndRoles(user_id) { } } $.ajax({ - url: "/app/user/groups/save", + url: "/user/groups/save", data: { changeUserGroupsUser: $('#login-' + user_id).val(), jsonDatas: JSON.stringify(jsonData) diff --git a/app/static/js/backup.js b/app/static/js/backup.js index 041d74ec..9ce7f11e 100644 --- a/app/static/js/backup.js +++ b/app/static/js/backup.js @@ -113,14 +113,14 @@ $( function() { }); function loadBackup() { $.ajax({ - url: "/app/server/backup", + url: "/server/backup", success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('danger') != '-1' || data.indexOf('unique') != '-1' || data.indexOf('error:') != '-1') { toastr.error(data); } else { $('#backup').html(data); - $.getScript('/app/static/js/backup.js'); + $.getScript('/static/js/backup.js'); $("select").selectmenu(); $.getScript(awesome); } @@ -144,13 +144,13 @@ function addBackup(dialog_id) { "rpath": $('#rpath').val(), "type": $('#backup-type').val(), "time": $('#backup-time').val(), - "cred": $('#backup-credentials').val(), + "cred_id": $('#backup-credentials').val(), "description": $('#backup-description').val() } $.ajax({ - url: "/app/server/backup", + url: "/server/backup", data: JSON.stringify(jsonData), - type: "PUT", + type: "POST", contentType: "application/json; charset=utf-8", success: function (data) { if (data.status === 'failed') { @@ -166,7 +166,7 @@ function addBackup(dialog_id) { function addS3Backup(dialog_id) { let valid = true; toastr.clear(); - allFields = $([]).add($('#s3-backup-server')).add($('#s3_server')).add($('#s3_bucket')).add($('#s3_secret_key')).add($('#s3_access_key')) + let allFields = $([]).add($('#s3-backup-server')).add($('#s3_server')).add($('#s3_bucket')).add($('#s3_secret_key')).add($('#s3_access_key')) allFields.removeClass("ui-state-error"); valid = valid && checkLength($('#s3-backup-server'), "backup server ", 1); valid = valid && checkLength($('#s3_server'), "S3 server", 1); @@ -174,31 +174,25 @@ function addS3Backup(dialog_id) { valid = valid && checkLength($('#s3_secret_key'), "S3 secret key", 1); valid = valid && checkLength($('#s3_access_key'), "S3 access key", 1); if (valid) { + let json_data = { + "s3_server": $('#s3-backup-server').val(), + "server": $('#s3_server').val(), + "bucket": $('#s3_bucket').val(), + "secret_key": $('#s3_secret_key').val(), + "access_key": $('#s3_access_key').val(), + "time": $('#s3-backup-time').val(), + "description": $('#s3-backup-description').val(), + } $.ajax({ - url: "/app/server/s3backup/create", - data: { - s3_backup_server: $('#s3-backup-server').val(), - s3_server: $('#s3_server').val(), - s3_bucket: $('#s3_bucket').val(), - s3_secret_key: $('#s3_secret_key').val(), - s3_access_key: $('#s3_access_key').val(), - time: $('#s3-backup-time').val(), - description: $('#s3-backup-description').val(), - token: $('#token').val() - }, + url: "/server/backup/s3", + data: JSON.stringify(json_data), type: "POST", + contentType: "application/json; charset=utf-8", success: function (data) { - data = data.replace(/\s+/g, ' '); - if (data.indexOf('error: ') != '-1') { + if (data.status === 'failed') { toastr.error(data); - } else if (data.indexOf('info: ') != '-1') { - toastr.clear(); - toastr.info(data); - } else if (data.indexOf('warning: ') != '-1') { - toastr.clear(); - toastr.warning(data); } else { - common_ajax_action_after_success(dialog_id, 'newbackup', 'ajax-backup-s3-table', data); + common_ajax_action_after_success(dialog_id, 'newbackup', 'ajax-backup-s3-table', data.data); $("select").selectmenu(); } } @@ -236,7 +230,7 @@ function addGit(dialog_id) { "desc": $('#git-description').text(), } $.ajax({ - url: "/app/server/git", + url: "/server/git", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: "POST", @@ -338,42 +332,55 @@ function cloneS3Backup(id) { function removeBackup(id) { $("#backup-table-" + id).css("background-color", "#f2dede"); let jsonData = { - "del_id": id, - "cred": $('#backup-credentials-' + id).val(), + "cred_id": $('#backup-credentials-' + id).val(), "server": $('#backup-server-' + id).text(), - "rserver": $('#backup-rserver-' + id).val() } $.ajax({ - url: "/app/server/backup", + url: api_prefix + "/server/backup/fs/" + id, data: JSON.stringify(jsonData), type: "DELETE", contentType: "application/json; charset=utf-8", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { + statusCode: { + 204: function (xhr) { $("#backup-table-" + id).remove(); + }, + 404: function (xhr) { + $("#backup-table-" + id).remove(); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } } } }); } function removeS3Backup(id) { $("#backup-table-s3-" + id).css("background-color", "#f2dede"); + let jsonData = { + "bucket": $('#bucket-' + id).text(), + "server": $('#backup-s3-server-' + id).text(), + } $.ajax({ - url: "/app/server/s3backup/delete", - data: { - dels3job: id, - s3_bucket: $('#bucket-' + id).text(), - s3_backup_server: $('#backup-s3-server-' + id).text(), - token: $('#token').val() - }, - type: "POST", - success: function (data) { - data = data.replace(/\s+/g, ' '); - if (data.indexOf('ok') != '-1') { + url: api_prefix + "/server/backup/s3/" + id, + data: JSON.stringify(jsonData), + type: "DELETE", + contentType: "application/json; charset=utf-8", + statusCode: { + 204: function (xhr) { $("#s3-backup-table-" + id).remove(); - } else if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { - toastr.error(data); + }, + 404: function (xhr) { + $("#s3-backup-table-" + id).remove(); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } } } }); @@ -393,7 +400,7 @@ function removeGit(id) { "desc": '', } $.ajax({ - url: "/app/server/git", + url: "/server/git", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: "DELETE", @@ -412,17 +419,16 @@ function updateBackup(id) { toastr.error('All fields must be completed'); } else { let jsonData = { - "update_id": id, "server": $('#backup-server-' + id).text(), "rserver": $('#backup-rserver-' + id).val(), "rpath": $('#backup-rpath-' + id).val(), "type": $('#backup-type-' + id).val(), "time": $('#backup-time-' + id).val(), - "cred": $('#backup-credentials-' + id).val(), + "cred_id": $('#backup-credentials-' + id).val(), "description": $('#backup-description-' + id).val() } $.ajax({ - url: "/app/server/backup", + url: api_prefix + "/server/backup/fs/" + id, data: JSON.stringify(jsonData), type: "PUT", contentType: "application/json; charset=utf-8", diff --git a/app/static/js/channel.js b/app/static/js/channel.js index 0ff70db6..a008be83 100644 --- a/app/static/js/channel.js +++ b/app/static/js/channel.js @@ -154,7 +154,7 @@ $( function() { }); function loadChannel() { $.ajax({ - url: "/app/channel/load", + url: "/channel/load", type: "GET", success: function (data) { data = data.replace(/\s+/g, ' '); @@ -165,7 +165,7 @@ function loadChannel() { $("select").selectmenu(); $("button").button(); $("input[type=checkbox]").checkboxradio(); - $.getScript('/app/static/js/channel.js'); + $.getScript('/static/js/channel.js'); $.getScript(awesome); } } @@ -178,13 +178,12 @@ function updateReceiver(id, receiver_name) { } toastr.clear(); let json_data = { - "receiver_token": $('#' + receiver_name + '-token-' + id).val(), + "token": $('#' + receiver_name + '-token-' + id).val(), "channel": $('#' + receiver_name + '-chanel-' + id).val(), - "group": group, - "id": id + "group_id": group, } $.ajax({ - url: "/app/channel/receiver/" + receiver_name, + url: "/channel/" + receiver_name + "/" + id, data: JSON.stringify(json_data), contentType: "application/json; charset=utf-8", type: "PUT", @@ -203,8 +202,9 @@ function updateReceiver(id, receiver_name) { } function checkReceiver(channel_id, receiver_name) { $.ajax({ - url: "/app/channel/check/" + channel_id + "/" + receiver_name, + url: "/channel/" + receiver_name + "/" + channel_id, contentType: "application/json; charset=utf-8", + type: "PATCH", success: function (data) { if (data.status === 'failed') { toastr.error(data.error); @@ -229,13 +229,13 @@ function addRecevier(dialog_id, receiver_name) { } if (valid) { let jsonData = { - "receiver": receiver_name_div.val(), + "token": receiver_name_div.val(), "channel": channel_div.val(), - "group": group, + "group_id": group } toastr.clear(); $.ajax({ - url: "/app/channel/receiver/" + receiver_name, + url: "/channel/" + receiver_name, data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: "POST", @@ -279,22 +279,29 @@ function cloneReceiver(id, receiver_name) { function removeReceiver(receiver_name, receiver_id) { $("#" + receiver_name + "-table-" + receiver_id).css("background-color", "#f2dede"); $.ajax({ - url: "/app/channel/receiver/" + receiver_name, - data: JSON.stringify({"channel_id": receiver_id}), + url: "/channel/" + receiver_name + "/" + receiver_id, contentType: "application/json; charset=utf-8", type: "DELETE", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { + statusCode: { + 204: function (xhr) { $("#" + receiver_name + "-table-" + receiver_id).remove(); + }, + 404: function (xhr) { + $("#" + receiver_name + "-table-" + receiver_id).remove(); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } } } }); } function sendCheckMessage(sender) { $.ajax({ - url: "/app/channel/check", + url: "/channel/check", data: JSON.stringify({'sender': sender}), type: "POST", contentType: "application/json; charset=utf-8", diff --git a/app/static/js/checker.js b/app/static/js/checker.js index 91b5d635..4ba3b98d 100644 --- a/app/static/js/checker.js +++ b/app/static/js/checker.js @@ -51,7 +51,7 @@ function updateHaproxyCheckerSettings(id) { maxconn = '1'; } $.ajax({ - url: "/app/checker/settings/update", + url: "/checker/settings/update", data: { service: 'haproxy', setting_id: id, @@ -95,7 +95,7 @@ function updateKeepalivedCheckerSettings(id) { backend = '1'; } $.ajax({ - url: "/app/checker/settings/update", + url: "/checker/settings/update", data: { service: 'keepavlied', setting_id: id, @@ -134,7 +134,7 @@ function updateServiceCheckerSettings(id, service_name) { server = '1'; } $.ajax({ - url: "/app/checker/settings/update", + url: "/checker/settings/update", data: { service: service_name, setting_id: id, @@ -163,7 +163,7 @@ function updateServiceCheckerSettings(id, service_name) { } function loadchecker() { $.ajax({ - url: "/app/checker/settings/load", + url: "/checker/settings/load", type: "GET", success: function (data) { data = data.replace(/\s+/g, ' '); @@ -174,7 +174,7 @@ function loadchecker() { $( "select" ).selectmenu(); $("button").button(); $( "input[type=checkbox]" ).checkboxradio(); - $.getScript('/app/static/js/checker.js'); + $.getScript('/static/js/checker.js'); $.getScript(awesome); } } diff --git a/app/static/js/configshow.js b/app/static/js/configshow.js index b489c4a8..8645a1dd 100644 --- a/app/static/js/configshow.js +++ b/app/static/js/configshow.js @@ -1,22 +1,22 @@ $( function() { - $( "input[type=submit], button" ).button(); - $( ".configShow" ).accordion({ + $("input[type=submit], button").button(); + $(".configShow").accordion({ collapsible: true, heightStyle: "content", - icons: { "header": "ui-icon-plus", "activeHeader": "ui-icon-minus" } + icons: {"header": "ui-icon-plus", "activeHeader": "ui-icon-minus"} }); - $('#raw').click(function() { + $('#raw').click(function () { $(".configShow").accordion("destroy"); $('#raw').css('display', 'none'); $('.numRow').css('display', 'none'); $('#according').css('display', 'inline-block'); $('.accordion-expand-all').css('display', 'none'); }); - $('#according').click(function() { - $( ".configShow" ).accordion({ + $('#according').click(function () { + $(".configShow").accordion({ collapsible: true, heightStyle: "content", - icons: { "header": "ui-icon-plus", "activeHeader": "ui-icon-minus" } + icons: {"header": "ui-icon-plus", "activeHeader": "ui-icon-minus"} }); $('#raw').css('display', 'inline-block'); $('.numRow').css('display', 'inline-block'); @@ -25,9 +25,9 @@ $( function() { }); let headers = $('.configShow .accordion-header'); let contentAreas = $('.configShow .ui-accordion-content ').hide() - .first().show().end(); + .first().show().end(); let expandLink = $('.accordion-expand-all'); - headers.click(function() { + headers.click(function () { // close all panels contentAreas.slideUp(); // open the appropriate panel @@ -37,39 +37,49 @@ $( function() { .data('isAllOpen', false); // stop page scroll return false; - }); + }); // hook up the expand/collapse all - expandLink.click(function(){ + expandLink.click(function () { let isAllOpen = !$(this).data('isAllOpen'); console.log({isAllOpen: isAllOpen, contentAreas: contentAreas}) - contentAreas[isAllOpen? 'slideDown': 'slideUp'](); - - expandLink.text(isAllOpen? 'Collapse All': 'Expand all') - .data('isAllOpen', isAllOpen); - }); - $(".accordion-link a").on("click", function(event) { - window.location.href = $(this).attr("href"); - event.preventDefault(); - }); + contentAreas[isAllOpen ? 'slideDown' : 'slideUp'](); - $( "#saveconfig" ).on("click", ":submit", function(e){ + expandLink.text(isAllOpen ? 'Collapse All' : 'Expand all') + .data('isAllOpen', isAllOpen); + }); + $(".accordion-link a").on("click", function (event) { + window.location.href = $(this).attr("href"); + event.preventDefault(); + }); + + $("#saveconfig").on("click", ":submit", function (e) { let frm = $('#saveconfig'); - let service = $('#service').val(); myCodeMirror.save(); + + let unindexed_array = frm.serializeArray(); + let indexed_array = {}; + $.map(unindexed_array, function (n, i) { + if (n['value'] != 'undefined') { + indexed_array[n['name']] = n['value']; + } + }); + indexed_array['action'] = $(this).val(); $.ajax({ url: frm.attr('action'), - data: frm.serialize() + "&save=" + $(this).val(), + dataType: 'json', + data: JSON.stringify(indexed_array), type: frm.attr('method'), - success: function( data ) { - data = data.replace(/\n/g, "
"); + contentType: "application/json; charset=UTF-8", + success: function (data) { toastr.clear(); - returnNiceCheckingConfig(data); + data.data = data.data.replace(/\n/g, "
"); + returnNiceCheckingConfig(data.data); $(window).unbind('beforeunload'); - if (data.indexOf('warning: ') != '-1') { - toastr.warning(data) + if (data.status === 'failed') { + toastr.warning(data.error) } } }); - event.preventDefault(); + e.preventDefault(); }); }) diff --git a/app/static/js/element.js b/app/static/js/element.js new file mode 100644 index 00000000..01db3423 --- /dev/null +++ b/app/static/js/element.js @@ -0,0 +1,119 @@ +"use strict"; // silly safari + +if (typeof elem == "undefined") { + + function elem(tagName, attributes, children, isHTML) { + + let parent; + + if (typeof tagName == "string") { + parent = document.createElement(tagName); + } else if (tagName instanceof HTMLElement) { + parent = tagName; + } + + // I'm tired of using null as the attributes, e.g.: elem("div", null, ["some", "elements"]) + // Wouldn't it be nice if I could just do: elem("div", ["some", "elements"]) + // attributes expects a plain object; we can use that to differentiate + if (typeof attributes != "undefined" && ["undefined", "boolean"].includes(typeof children) && typeof isHTML == "undefined") { + let attrType = typeof attributes; + if (["string", "number"].includes(attrType) + || (attrType == "object" && attributes instanceof Array) + || (attrType == "object" && attributes instanceof HTMLElement) ) { + isHTML = children; + children = attributes; + attributes = null; + } + } + + if (attributes) { + + for (let attribute in attributes) { + + if (attribute.startsWith("on")) { + + let callback = attributes[attribute]; + + if (typeof callback == "string") { + parent.setAttribute(attribute, callback); + } + else if (typeof callback == "function") { + + let eventMatch = attribute.match(/^on([a-zA-Z]+)/); + if (eventMatch) { + let event = eventMatch[1]; + // TODO: make sure it's a valid event? + parent.addEventListener(event, callback); + parent.eventListeners = parent.eventListeners || {}; + parent.eventListeners[event] = parent.eventListeners[event] || []; + parent.eventListeners[event].push(callback); + } + + } + + } else { + parent.setAttribute(attribute, attributes[attribute]); + } + + } + + } + + if (typeof children != "undefined" || children === 0) { + elem.append(parent, children, isHTML); + } + + return parent; + }; + + elem.append = function (parent, children, isHTML) { + + if (parent instanceof HTMLTextAreaElement || parent instanceof HTMLInputElement) { + + if (children instanceof Text || typeof children == "string" || typeof children == "number") { + parent.value = children; + } + else if (children instanceof Array) { + children.forEach(function (child) { + elem.append(parent, child); + }); + } + else if (typeof children == "function") { + elem.append(parent, children()); + } + + } else { + + if (children instanceof HTMLElement || children instanceof Text) { + parent.appendChild(children); + } + else if (typeof children == "string" || typeof children == "number") { + if (isHTML) { + parent.innerHTML += children; + } else { + parent.appendChild(document.createTextNode(children)); + } + } + else if (children instanceof Array) { + children.forEach(function (child) { + elem.append(parent, child); + }); + } + else if (typeof children == "function") { + elem.append(parent, children()); + } + + } + }; + + window.elem = elem; + +} else { + + if (typeof elem == "function" && elem.hasOwnProperty("append")) { + console.warn("elem() is already initialized."); + } else { + console.warn("The name \"elem\" is already in use by some other script."); + } + +} diff --git a/app/static/js/ha.js b/app/static/js/ha.js index 928ee79a..db248501 100644 --- a/app/static/js/ha.js +++ b/app/static/js/ha.js @@ -72,16 +72,21 @@ function confirmDeleteCluster(cluster_id) { } function deleteCluster(cluster_id) { $.ajax({ - url: "/app/ha/cluster", + url: api_prefix + "/ha/cluster/" + cluster_id, type: "DELETE", - data: { - cluster_id: cluster_id, + statusCode: { + 204: function (xhr) { + $("#cluster-" + cluster_id).remove(); + }, + 404: function (xhr) { + $("#cluster-" + cluster_id).remove(); + } }, success: function (data) { - if (data.indexOf('error:') != '-1') { - toastr.error(data); - } else { - $("#cluster-" + cluster_id).remove(); + if (data) { + if (data.status === "failed") { + toastr.error(data); + } } } }); @@ -92,7 +97,7 @@ function createHaClusterStep1(edited=false, cluster_id=0, clean=true) { if (clean) { clearClusterDialog(edited); $.ajax({ - url: "/app/ha/cluster/masters", + url: "/ha/cluster/masters", async: false, type: "GET", success: function (data) { @@ -118,13 +123,13 @@ function createHaClusterStep1(edited=false, cluster_id=0, clean=true) { $('#ha-cluster-master').selectmenu("refresh"); get_keepalived_ver($('#cur_master_ver'), master_ip); $.ajax({ - url: "/app/ha/cluster/settings/" + cluster_id, + url: api_prefix + "/ha/cluster/" + cluster_id, type: "GET", async: false, success: function (data) { let clusterSettings = JSON.parse(JSON.stringify(data)); - $('#ha-cluster-name').val(clusterSettings.name); - $('#ha-cluster-desc').val(clusterSettings.desc); + $('#ha-cluster-name').val(clusterSettings.name.replaceAll("'", "")); + $('#ha-cluster-desc').val(clusterSettings.description.replaceAll("'", "")); $('#ha-cluster-master-interface').val(clusterSettings.eth); $('#vrrp-ip').val(clusterSettings.vip); if (clusterSettings.haproxy) { @@ -137,10 +142,10 @@ function createHaClusterStep1(edited=false, cluster_id=0, clean=true) { } else { $('#nginx').prop('checked', false); } - if (clusterSettings.return_to_master) { - $('#return_to_master').prop('checked', true); + if (clusterSettings.return_master) { + $('#return_master').prop('checked', true); } else { - $('#return_to_master').prop('checked', false); + $('#return_master').prop('checked', false); } if (clusterSettings.syn_flood) { $('#syn_flood').prop('checked', true); @@ -162,7 +167,7 @@ function createHaClusterStep1(edited=false, cluster_id=0, clean=true) { }); } $.ajax({ - url: "/app/ha/cluster/slaves/servers/" + cluster_id, + url: "/ha/cluster/slaves/servers/" + cluster_id, async: false, type: "GET", success: function (data) { @@ -282,7 +287,7 @@ function createHaClusterStep2(edited=false, cluster_id=0, jsonData='') { } function saveCluster(jsonData, cluster_id=0, edited=0, reconfigure=0) { let virt_server = 0; - let return_to_master = 0; + let return_master = 0; let syn_flood = 0; let use_src = 0; let hap = 0; @@ -291,14 +296,12 @@ function saveCluster(jsonData, cluster_id=0, edited=0, reconfigure=0) { let nginx_docker = 0; let apache = 0; let req_method = 'POST'; - if (edited) { - req_method = 'PUT'; - } + let url = api_prefix + '/ha/cluster'; if ($('#virt_server').is(':checked')) { virt_server = '1'; } - if ($('#return_to_master').is(':checked')) { - return_to_master = '1'; + if ($('#return_master').is(':checked')) { + return_master = '1'; } if ($('#syn_flood').is(':checked')) { syn_flood = '1'; @@ -321,12 +324,15 @@ function saveCluster(jsonData, cluster_id=0, edited=0, reconfigure=0) { if ($('#apache').is(':checked')) { apache = '1'; } - jsonData['cluster_id'] = cluster_id; + if (edited) { + req_method = 'PUT'; + url = api_prefix + '/ha/cluster/' + cluster_id; + } jsonData['name'] = $('#ha-cluster-name').val(); - jsonData['desc'] = $('#ha-cluster-desc').val(); + jsonData['description'] = $('#ha-cluster-desc').val(); jsonData['vip'] = $('#vrrp-ip').val(); jsonData['virt_server'] = virt_server; - jsonData['return_to_master'] = return_to_master; + jsonData['return_master'] = return_master; jsonData['syn_flood'] = syn_flood; jsonData['use_src'] = use_src; jsonData['services'] = {'haproxy': {'enabled': hap, 'docker': hap_docker}}; @@ -334,7 +340,7 @@ function saveCluster(jsonData, cluster_id=0, edited=0, reconfigure=0) { jsonData['services']['apache'] = {'enabled': apache, 'docker': 0}; jsonData['router_id'] = $('#router_id-' + cluster_id).val(); $.ajax({ - url: "/app/ha/cluster", + url: url, type: req_method, async: false, data: JSON.stringify(jsonData), @@ -344,7 +350,7 @@ function saveCluster(jsonData, cluster_id=0, edited=0, reconfigure=0) { toastr.error(data.error); } else { if (!edited) { - cluster_id = data.cluster_id; + cluster_id = data.id; getHaCluster(cluster_id, true); } else { getHaCluster(cluster_id); @@ -432,7 +438,7 @@ function installServiceCluster(jsonData, service, progress_step, cluster_id) { let nice_service_name = {'keepalived': 'HA Custer', 'haproxy': 'HAProxy', 'nginx': 'NGINX', 'apache': 'Apache'}; $('#server_creating_list').append('
  • ' + install_mess + ' ' + nice_service_name[service] + '
  • '); return $.ajax({ - url: "/app/install/" + service, + url: "/install/" + service, type: "POST", data: JSON.stringify(servers), contentType: "application/json; charset=utf-8", @@ -446,8 +452,7 @@ function installServiceCluster(jsonData, service, progress_step, cluster_id) { }, success: function (data) { if (data.status === 'failed') { - toastr.error(data.error); - toastr.error(data); + showErrorStatus(nice_service_name[service], servers["name"], li_id, servers['cluster_id'], progress_step, something_wrong); } else { checkInstallResp(data, servers['cluster_id'], progress_step, servers["name"], li_id, nice_service_name[service]); } @@ -467,7 +472,6 @@ function checkInstallResp(output, server_id, progress_step, name, li_id, service output = JSON.parse(JSON.stringify(output)); let was_installed = translate_div.attr('data-was_installed'); let something_wrong = translate_div.attr('data-something_wrong'); - // let check_apache_log = translate_div.attr('data-check_apache_log'); for (let k in output['ok']) { $('#' + li_id + server_id).removeClass('proccessing'); $('#' + li_id + server_id).addClass('proccessing_done'); @@ -504,15 +508,15 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit let req_method = 'GET'; if (edited) { $.ajax({ - url: "/app/ha/cluster/settings/" + cluster_id + "/vip/" + router_id, + url: api_prefix + "/ha/cluster/" + cluster_id + "/vip/" + router_id, type: "GET", async: false, success: function (data) { let clusterSettings = JSON.parse(JSON.stringify(data)); - if (clusterSettings.return_to_master) { - $('#vrrp-ip-add-return_to_master').prop('checked', true); + if (clusterSettings.return_master) { + $('#vrrp-ip-add-return_master').prop('checked', true); } else { - $('#vrrp-ip-add-return_to_master').prop('checked', false); + $('#vrrp-ip-add-return_master').prop('checked', false); } if (clusterSettings.virt_server) { $('#vrrp-ip-add-virt_server').prop('checked', true); @@ -588,7 +592,7 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit }] } $.ajax({ - url: "/app/ha/cluster/slaves/" + cluster_id, + url: "/ha/cluster/slaves/" + cluster_id, data: { router_id: router_id, }, @@ -626,11 +630,11 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit } function saveVip(jsonData, cluster_id, dialog_id, cluster_name, edited, router_id='', vip='', deleted=false) { let req_type = 'POST' - let return_to_master = 0 + let return_master = 0 let virt_server = 0 let use_src = 0 - if ($('#vrrp-ip-add-return_to_master').is(':checked')) { - return_to_master = '1'; + if ($('#vrrp-ip-add-return_master').is(':checked')) { + return_master = '1'; } if ($('#vrrp-ip-add-virt_server').is(':checked')) { virt_server = '1'; @@ -639,30 +643,45 @@ function saveVip(jsonData, cluster_id, dialog_id, cluster_name, edited, router_i use_src = '1'; } jsonData['vip'] = $('#vrrp-ip-add').val(); - jsonData['return_to_master'] = return_to_master; + jsonData['return_master'] = return_master; jsonData['virt_server'] = virt_server; jsonData['use_src'] = use_src; jsonData['name'] = cluster_name; + let url = api_prefix + "/ha/cluster/" + cluster_id + "/vip"; if (edited) { req_type = 'PUT'; jsonData['router_id'] = router_id; } if (deleted) { req_type = 'DELETE'; - jsonData['router_id'] = router_id; + url = api_prefix + "/ha/cluster/" + router_id + "/vip" } $.ajax({ - url: "/app/ha/cluster/" + cluster_id + "/vip", + url: url, data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: req_type, - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { + statusCode: { + 204: function (xhr) { getHaCluster(cluster_id); dialog_id.dialog('destroy'); clearClusterDialog(); + }, + 404: function (xhr) { + getHaCluster(cluster_id); + dialog_id.dialog('destroy'); + clearClusterDialog(); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data); + } else { + getHaCluster(cluster_id); + dialog_id.dialog('destroy'); + clearClusterDialog(); + } } } }); @@ -671,7 +690,7 @@ function get_interface(input_id, server_ip) { input_id.autocomplete({ source: function (request, response) { $.ajax({ - url: "/app/server/show/if/" + server_ip, + url: "/server/show/if/" + server_ip, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1' || data.indexOf('Failed') != '-1') { @@ -688,16 +707,16 @@ function get_interface(input_id, server_ip) { } function get_keepalived_ver(div_id, server_ip) { $.ajax({ - url: "/app/install/keepalived/version/" + server_ip, + url: api_prefix + "/service/keepalived/" + server_ip + "/status", + contentType: "application/json; charset=utf-8", success: function (data) { - data = data.replace(/^\s+|\s+$/g, ''); - if (data.indexOf('error:') != '-1') { - let p_err = show_pretty_ansible_error(data); + if (data.status === 'failed') { + let p_err = show_pretty_ansible_error(data.error); toastr.error(p_err); - } else if (data.indexOf('keepalived:') != '-1') { + } else if (!data.Version) { div_id.text('Keepalived has not installed'); } else { - div_id.text(data); + div_id.text(data.Version); div_id.css('font-weight', 'bold'); } } @@ -740,19 +759,20 @@ function removeCheckFromStatus(server_id, server_ip) { } function createJsonCluster(div_id) { let jsonData = {}; - jsonData = {'servers': {}}; - jsonData['servers'][1] = { + jsonData = {'servers': []}; + jsonData['servers'].push({ + 'id': 1, 'eth': $('#ha-cluster-master-interface').val(), 'ip': $('#ha-cluster-master option:selected').val(), 'name': $('#ha-cluster-master option:selected').text(), 'master': 1 - }; + }); $(div_id).each(function () { let this_id = $(this).attr('id').split('-')[1]; let eth = $('#slave_int-' + this_id).val(); let ip = $('#slave_int_div-' + this_id).attr('data-ip'); let name = $('#slave_int_div-' + this_id).parent().text().replace('\n','').replace('\t','').trim(); - jsonData['servers'][this_id] = {'eth': eth, 'ip': ip, 'name': name, 'master': 0}; + jsonData['servers'].push({'id': this_id, 'eth': eth, 'ip': ip, 'name': name, 'master': 0}); }); return jsonData; } @@ -801,7 +821,7 @@ function clearClusterDialog(edited=0) { $('#vrrp-ip-edit').val(''); $('#cur_master_ver').text(''); $('#virt_server').prop('checked', true); - $('#return_to_master').prop('checked', true); + $('#return_master').prop('checked', true); $('#use_src').prop('checked', false); $('#hap').prop('checked', false); $('#hap_docker').prop('checked', false); @@ -818,7 +838,7 @@ function clearClusterDialog(edited=0) { } function getHaCluster(cluster_id, new_cluster=false) { $.ajax({ - url: "/app/ha/cluster/get/" + cluster_id, + url: "/ha/cluster/get/" + cluster_id, success: function (data) { data = data.replace(/^\s+|\s+$/g, ''); if (data.indexOf('error:') != '-1') { diff --git a/app/static/js/install.js b/app/static/js/install.js index 21b81e98..0ad9cfb4 100644 --- a/app/static/js/install.js +++ b/app/static/js/install.js @@ -19,7 +19,7 @@ $( function() { $("#ajaxmon").html(''); $("#ajaxmon").html(wait_mess); $.ajax({ - url: "/app/install/grafana", + url: "/install/grafana", success: function (data) { data = data.replace(/\s+/g, ' '); $("#ajaxmon").html(''); @@ -102,7 +102,7 @@ $( function() { "update": updating_geoip } $.ajax({ - url: "/app/install/geoip", + url: "/install/geoip", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: "POST", @@ -120,7 +120,7 @@ $( function() { }); function checkGeoipInstallation() { $.ajax({ - url: "/app/install/geoip/" + $('#geoip_service option:selected').val() + "/" + $('#geoipserv option:selected').val(), + url: "/install/geoip/" + $('#geoip_service option:selected').val() + "/" + $('#geoipserv option:selected').val(), success: function (data) { data = data.replace(/^\s+|\s+$/g, ''); if (data.indexOf('No such file or directory') != '-1' || data.indexOf('cannot access') != '-1') { @@ -144,27 +144,31 @@ function installService(service) { if ($('#' + service + '_docker').is(':checked')) { docker = '1'; } - if ($(select_id).val() == '------' || $(select_id).val() === null) { + if ($(select_id).val() === '------' || $(select_id).val() === null) { let select_server = translate_div.attr('data-select_server'); toastr.warning(select_server); return false } let jsonData = {}; - jsonData['servers'] = {'0': {}} + let server = { + "ip": $(select_id).val(), + "master": '0', + "name": $(select_id + ' option:selected').text(), + } + if (service === 'haproxy') { + server['version'] = $('#hapver option:selected').val(); + } + jsonData['servers'] = {} jsonData['services'] = {}; jsonData['services'][service] = {}; jsonData['syn_flood'] = syn_flood; - jsonData['servers']['0']['ip'] = $(select_id).val(); - jsonData['servers']['0']['master'] = '0'; - jsonData['servers']['0']['name'] = $(select_id + ' option:selected').text(); - if (service == 'haproxy') { - jsonData['servers']['0']['version'] = $('#hapver option:selected').val(); - } + jsonData['servers'] = []; + jsonData['servers'].push(server); jsonData['services'][service]['enabled'] = 1; jsonData['services'][service]['docker'] = docker; $("#ajax").html(wait_mess); $.ajax({ - url: "/app/install/" + service, + url: "/install/" + service + "/" + $(select_id).val(), 500: function () { showErrorStatus(nice_names[service], $(select_id + ' option:selected').text()); }, @@ -178,8 +182,8 @@ function installService(service) { if (data.status === 'failed') { toastr.error(data.error); } else { - parseAnsibleJsonOutput(data, nice_names[service], select_id); $(select_id).trigger("selectmenuchange"); + $("#ajax").empty(); } } }); @@ -200,7 +204,7 @@ function installExporter(exporter) { } $("#ajax").html(wait_mess); $.ajax({ - url: "/app/install/exporter/" + exporter, + url: "/install/exporter/" + exporter, 500: function () { showErrorStatus(nice_exporter_name, $(exporter_id + ' option:selected').text()); }, @@ -214,15 +218,16 @@ function installExporter(exporter) { if (data.status === 'failed') { toastr.error(data.error); } else { - parseAnsibleJsonOutput(data, nice_exporter_name, exporter_id); + parseAnsibleJsonOutput(data, nice_names[service], select_id); $(exporter_id).trigger("selectmenuchange"); + $("#ajax").empty(); } } }); } function showExporterVersion(exporter) { $.ajax({ - url: "/app/install/exporter/" + exporter + "/version/" + $('#' + exporter + '_exp_addserv option:selected').val(), + url: "/install/exporter/" + exporter + "/version/" + $('#' + exporter + '_exp_addserv option:selected').val(), success: function (data) { data = data.replace(/^\s+|\s+$/g, ''); if (data.indexOf('error:') != '-1') { @@ -237,28 +242,28 @@ function showExporterVersion(exporter) { }); } function showServiceVersion(service) { + let install_div = $('#' + service + '_install'); + let ver_div = $('#cur_' + service + '_ver'); $.ajax({ - url: "/app/install/" + service + "/version/" + $('#' + service + 'addserv option:selected').val(), + url: "/service/" + service + "/" + $('#' + service + 'addserv option:selected').val() + "/status", + statusCode: { + 404: function (xhr) { + ver_div.text(service + ' has not installed'); + install_div.text('Install'); + install_div.attr('title', 'Install'); + } + }, success: function (data) { - data = data.replace(/^\s+|\s+$/g, ''); - if (data.indexOf('error: ') != '-1') { - toastr.warning(data); - $('#cur_' + service + '_ver').text(''); - } else if(data.indexOf('bash') != '-1' || data.indexOf('such') != '-1' || data.indexOf('command not found') != '-1' || data.indexOf('from') != '-1') { - $('#cur_' + service + '_ver').text(service + ' has not installed'); - $('#' + service + '_install').text('Install'); - $('#' + service + '_install').attr('title', 'Install'); - } else if (data.indexOf('warning: ') != '-1') { - toastr.warning(data); - } else if (data == '') { - $('#cur_' + service + '_ver').text(service + ' has not installed'); - $('#' + service + '_install').text('Install'); - $('#' + service + '_install').attr('title', 'Install'); + if (data.status === 'failed') { + ver_div.text(service + ' has not installed'); + install_div.text('Install'); + install_div.attr('title', 'Install'); + toastr.warning('Cannot get version'); } else { - $('#cur_' + service + '_ver').text(data); - $('#cur_' + service + '_ver').css('font-weight', 'bold'); - $('#' + service + '_install').text('Update'); - $('#' + service + '_install').attr('title', 'Update'); + ver_div.text(data.Version); + ver_div.css('font-weight', 'bold'); + install_div.text('Update'); + install_div.attr('title', 'Update'); } } }); diff --git a/app/static/js/metrics.js b/app/static/js/metrics.js index a4b73629..4e451dc9 100644 --- a/app/static/js/metrics.js +++ b/app/static/js/metrics.js @@ -64,7 +64,7 @@ function return_service_chart_config() { function stream_chart(chart_id, service, service_ip, is_http=0) { let random_sleep = getRandomArbitrary(500, 2000); sleep(random_sleep); - const source = new EventSource(`/app/metrics/${service}/${service_ip}/${is_http}/chart-stream`); + const source = new EventSource(`/metrics/${service}/${service_ip}/${is_http}/chart-stream`); source.onmessage = function (event) { const data = JSON.parse(event.data); if (chart_id.data.labels.length >= 30) { @@ -89,7 +89,7 @@ function getHttpChartData(server) { return false; } $.ajax({ - url: `/app/metrics/haproxy/${server}/http`, + url: `/metrics/haproxy/${server}/http`, data: { time_range: $( "#time-range option:selected" ).val(), }, @@ -211,7 +211,7 @@ function renderHttpChart(data, labels, server) { } function getChartData(server) { $.ajax({ - url: "/app/metrics/haproxy/" + server, + url: "/metrics/haproxy/" + server, data: { time_range: $( "#time-range option:selected" ).val(), }, @@ -315,7 +315,7 @@ function renderChart(data, labels, server) { } function getWafChartData(server) { $.ajax({ - url: "/app/metrics/waf/" + server, + url: "/metrics/waf/" + server, data: { time_range: $( "#time-range option:selected" ).val(), }, @@ -355,7 +355,7 @@ function renderServiceChart(data, labels, server, service) { } function getNginxChartData(server) { $.ajax({ - url: "/app/metrics/nginx/" + server, + url: "/metrics/nginx/" + server, data: { time_range: $( "#time-range option:selected" ).val(), }, @@ -371,7 +371,7 @@ function getNginxChartData(server) { } function getApacheChartData(server) { $.ajax({ - url: "/app/metrics/apache/" + server, + url: "/metrics/apache/" + server, data: { time_range: $( "#time-range option:selected" ).val(), }, @@ -388,9 +388,9 @@ function getApacheChartData(server) { function loadMetrics() { let service = $('#service').val(); $.ajax({ - url: "/app/metrics/" + service + "/table-metrics", + url: "/metrics/" + service + "/table-metrics", beforeSend: function () { - $('#table_metrics').html('loading...') + $('#table_metrics').html('loading...') }, type: "GET", success: function (data) { @@ -404,14 +404,14 @@ function loadMetrics() { } function getChartDataHapWiRam(ip) { $.ajax({ - url: "/app/metrics/ram", + url: "/metrics/ram", data: { metrics_hapwi_ram: '1', ip: ip, token: $('#token').val() }, beforeSend: function() { - $('#ram').html('loading...') + $('#ram').html('loading...') }, type: "POST", success: function (result) { @@ -482,7 +482,7 @@ function renderChartHapWiRam(data) { } function getChartDataHapWiCpu(ip) { $.ajax({ - url: "/app/metrics/cpu", + url: "/metrics/cpu", data: { metrics_hapwi_cpu: '1', ip: ip, diff --git a/app/static/js/nettools.js b/app/static/js/nettools.js index 7a8e5f78..64c58ec6 100644 --- a/app/static/js/nettools.js +++ b/app/static/js/nettools.js @@ -116,7 +116,7 @@ $( function() { return false; } $.ajax({ - url: "/app/portscanner/scan", + url: "/portscanner/scan", data: JSON.stringify({'ip': port_server}), type: "POST", contentType: "application/json; charset=utf-8", diff --git a/app/static/js/overview.js b/app/static/js/overview.js index e4abbe52..a2232447 100644 --- a/app/static/js/overview.js +++ b/app/static/js/overview.js @@ -1,4 +1,4 @@ -var cur_url = window.location.href.split('/app/').pop(); +var cur_url = window.location.href.split('/').pop(); cur_url = cur_url.split('/'); function showHapservers(serv, hostnamea, service) { let i; @@ -8,9 +8,9 @@ function showHapservers(serv, hostnamea, service) { } function showHapserversCallBack(serv, hostnamea, service) { $.ajax( { - url: "/app/service/" + service + "/" + serv + "/last-edit", + url: "/service/" + service + "/" + serv + "/last-edit", beforeSend: function() { - $("#edit_date_"+hostnamea).html(''); + $("#edit_date_"+hostnamea).html(''); }, type: "GET", success: function( data ) { @@ -28,18 +28,30 @@ function showHapserversCallBack(serv, hostnamea, service) { } } ); } -function overviewHapserverBackends(serv, hostnamea, service) { +function overviewHapserverBackends(serv, hostname, service) { + let div = ''; $.ajax( { - url: "/app/service/" + service + "/backends/" + serv[0], + url: `/service/${service}/${serv[0]}/backend`, beforeSend: function() { - $("#top-"+hostnamea).html(''); + $("#top-"+hostname).html(''); }, + contentType: "application/json; charset=utf-8", success: function( data ) { - if (data.indexOf('error:') != '-1') { + if (data.status === 'failed') { toastr.error(data); } else { - $("#top-" + hostnamea).empty(); - $("#top-" + hostnamea).html(data); + $('.div-backends').css('height', 'auto'); + $("#top-" + hostname).empty(); + for (let i in data.data) { + if (service === 'haproxy') { + div = `${data.data[i]} ` + } else if (service === 'nginx' || service === 'apache') { + div = `${data.data[i]}`; + } else { + div = data.data[i]; + } + $("#top-" + hostname).append(div); + } } } } ); @@ -57,9 +69,9 @@ function showOverview(serv, hostnamea) { } function showOverviewCallBack(serv, hostnamea) { $.ajax( { - url: "/app/overview/server/"+serv, + url: "/overview/server/"+serv, beforeSend: function() { - $("#"+hostnamea).html(''); + $("#"+hostnamea).html(''); }, type: "GET", success: function( data ) { @@ -75,9 +87,9 @@ function showOverviewCallBack(serv, hostnamea) { } function showServicesOverview() { $.ajax( { - url: "/app/overview/services", + url: "/overview/services", beforeSend: function() { - $("#services_ovw").html(''); + $("#services_ovw").html(''); }, type: "GET", @@ -93,15 +105,12 @@ function showServicesOverview() { } function showOverviewServer(name, ip, id, service) { $.ajax( { - url: "/app/service/cpu-ram-metrics/" + ip + "/" + id + "/" + name + "/" + service, + url: "/service/cpu-ram-metrics/" + ip + "/" + id + "/" + name + "/" + service, success: function( data ) { if (data.indexOf('error:') != '-1') { toastr.error(data); } else { $("#ajax-server-" + id).empty(); - $("#ajax-server-" + id).css('display', 'block'); - $("#ajax-server-" + id).css('background-color', '#fbfbfb'); - $("#ajax-server-" + id).css('border', '1px solid #A4C7F5'); $(".ajax-server").css('display', 'block'); $(".div-server").css('clear', 'both'); $(".div-pannel").css('clear', 'both'); @@ -118,28 +127,17 @@ function showOverviewServer(name, ip, id, service) { } ); } function ajaxActionServers(action, id, service) { - $.ajax( { - url: "/app/service/action/" + service + "/" + id + "/" + action, - success: function( data ) { - data = data.replace(/\s+/g,' '); - if( data == 'Bad config, check please ' ) { - toastr.error(data); + $.ajax({ + url: "/service/" + service + "/" + id + "/" + action, + contentType: "application/json; charset=utf-8", + success: function (data) { + if (data.status === 'failed') { + toastr.error(data.error); } else { - if (data.indexOf('error:') != '-1') { - toastr.error(data); - } else { - if (data.indexOf('warning: ') != '-1') { - toastr.warning(data); - } else { - location.reload(); - } - } + location.reload(); } - }, - error: function(){ - alert(w.data_error); } - } ); + }); } $( function() { try { @@ -222,14 +220,14 @@ $( function() { } }); }); -function confirmAjaxAction(action, service, id) { +function confirmAjaxAction(action, service, id, name) { let action_word = translate_div.attr('data-'+action); $( "#dialog-confirm" ).dialog({ resizable: false, height: "auto", width: 400, modal: true, - title: action_word + " " + id + "?", + title: action_word + " " + name + "?", buttons: [{ text: action_word, click: function () { @@ -244,13 +242,7 @@ function confirmAjaxAction(action, service, id) { } } else if (service == "waf") { ajaxActionServers(action, id, 'waf_haproxy'); - } else if (service == "nginx") { - ajaxActionServers(action, id, service); - } else if (service == "keepalived") { - ajaxActionServers(action, id, service); - } else if (service == "apache") { - ajaxActionServers(action, id, service); - } else if (service == "waf_nginx") { + } else { ajaxActionServers(action, id, service); } } @@ -276,7 +268,7 @@ function updateHapWIServer(id, service_name) { active = '1'; } $.ajax({ - url: "/app/service/" + service_name + "/tools/update", + url: "/service/" + service_name + "/tools/update", data: { server_id: id, name: $('#server-name-' + id).val(), @@ -301,7 +293,7 @@ function updateHapWIServer(id, service_name) { } function change_pos(pos, id) { $.ajax({ - url: "/app/service/position/" + id + "/" + pos, + url: "/service/position/" + id + "/" + pos, // data: { // token: $('#token').val() // }, @@ -313,14 +305,14 @@ function change_pos(pos, id) { } function showBytes(serv) { $.ajax( { - url: "/app/service/haproxy/bytes", + url: "/service/haproxy/bytes", data: { showBytes: serv }, type: "POST", beforeSend: function() { - $("#show_bin_bout").html(''); - $("#sessions").html(''); + $("#show_bin_bout").html(''); + $("#sessions").html(''); }, success: function( data ) { data = data.replace(/\s+/g,' '); @@ -335,13 +327,13 @@ function showBytes(serv) { } function showNginxConnections(serv) { $.ajax( { - url: "/app/service/nginx/connections", + url: "/service/nginx/connections", data: { nginxConnections: serv }, type: "POST", beforeSend: function() { - $("#sessions").html(''); + $("#sessions").html(''); }, success: function( data ) { data = data.replace(/\s+/g,' '); @@ -356,13 +348,13 @@ function showNginxConnections(serv) { } function showApachekBytes(serv) { $.ajax( { - url: "/app/service/apache/bytes", + url: "/service/apache/bytes", data: { apachekBytes: serv }, type: "POST", beforeSend: function() { - $("#sessions").html(''); + $("#sessions").html(''); }, success: function( data ) { data = data.replace(/\s+/g,' '); @@ -377,13 +369,13 @@ function showApachekBytes(serv) { } function keepalivedBecameMaster(serv) { $.ajax( { - url: "/app/service/keepalived/become-master", + url: "/service/keepalived/become-master", data: { keepalivedBecameMaster: serv }, type: "POST", beforeSend: function() { - $("#bin_bout").html(''); + $("#bin_bout").html(''); }, success: function( data ) { data = data.replace(/\s+/g,' '); @@ -405,7 +397,7 @@ function showUsersOverview() { // }, type: "GET", beforeSend: function() { - $("#users-table").html(''); + $("#users-table").html(''); }, success: function( data ) { data = data.replace(/\s+/g,' '); @@ -419,14 +411,14 @@ function showUsersOverview() { } function showSubOverview() { $.ajax( { - url: "/app/overview/sub", + url: "/overview/sub", // data: { // show_sub_ovw: 1, // token: $('#token').val() // }, type: "GET", beforeSend: function() { - $("#sub-table").html(''); + $("#sub-table").html(''); }, success: function( data ) { data = data.replace(/\s+/g,' '); @@ -443,7 +435,7 @@ function serverSettings(id, name) { let for_word = translate_div.attr('data-for'); let service = $('#service').val(); $.ajax({ - url: "/app/service/settings/" + service + "/" + id, + url: "/service/settings/" + service + "/" + id, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1') { @@ -500,7 +492,7 @@ function serverSettingsSave(id, name, service, dialog_id) { service_restart = '1'; } $.ajax({ - url: "/app/service/settings/" + service, + url: "/service/settings/" + service, data: { serverSettingsSave: id, serverSettingsEnterprise: haproxy_enterprise, @@ -525,38 +517,41 @@ function check_service_status(id, ip, service) { return false; } NProgress.configure({showSpinner: false}); - if (service == 'keepalived') return false; + if (service === 'keepalived') return false; + let server_div = $('#div-server-' + id); $.ajax({ - url: "/app/service/action/" + service + "/check-service", - data: { - server_ip: ip - }, - type: "POST", - success: function (data) { - if (data.indexOf('logout') != '-1') { + url: "/service/" + service + "/" + id + "/status", + contentType: "application/json; charset=utf-8", + statusCode: { + 401: function (xhr) { + sessionStorage.setItem('check-service', 0) + }, + 404: function (xhr) { sessionStorage.setItem('check-service', 0) } - data = data.replace(/\s+/g, ' '); - if (cur_url[0] == 'service') { - if (data.indexOf('up') != '-1') { - $('#div-server-' + id).addClass('div-server-head-up'); - $('#div-server-' + id).removeClass('div-server-head-down'); - } else if (data.indexOf('down') != '-1') { - $('#div-server-' + id).removeClass('div-server-head-up'); - $('#div-server-' + id).addClass('div-server-head-down'); - } - } else if (cur_url[0] == '') { + }, + success: function (data) { + if (cur_url[0] === 'overview') { let span_id = $('#' + service + "_" + id); - if (data.indexOf('up') != '-1') { + if (data.status === 'failed') { + span_id.addClass('serverDown'); + span_id.removeClass('serverUp'); + span_id.attr('title', 'Service is down') + } else { span_id.addClass('serverUp'); span_id.removeClass('serverDown'); if (span_id.attr('title').indexOf('Service is down') != '-1') { span_id.attr('title', 'Service running') } - } else if (data.indexOf('down') != '-1') { - span_id.addClass('serverDown'); - span_id.removeClass('serverUp'); - span_id.attr('title', 'Service is down') + } + } else { + console.log(data.length) + if (data.status === 'failed') { + server_div.removeClass('div-server-head-up'); + server_div.addClass('div-server-head-down'); + } else { + server_div.addClass('div-server-head-up'); + server_div.removeClass('div-server-head-down'); } } } @@ -565,10 +560,10 @@ function check_service_status(id, ip, service) { } function ShowOverviewLogs() { $.ajax( { - url: "/app/overview/logs", + url: "/overview/logs", type: "GET", beforeSend: function() { - $("#overview-logs").html(''); + $("#overview-logs").html(''); }, success: function( data ) { data = data.replace(/\s+/g,' '); diff --git a/app/static/js/runtimeapi.js b/app/static/js/runtimeapi.js index 94638fb0..01015c21 100644 --- a/app/static/js/runtimeapi.js +++ b/app/static/js/runtimeapi.js @@ -5,7 +5,7 @@ function showRuntime() { saveCheck = ""; } $.ajax({ - url: "/app/runtimeapi/action/" + $("#serv").val(), + url: "/runtimeapi/action/" + $("#serv").val(), data: { servaction: $('#servaction').val(), servbackend: $("#servbackend").val(), @@ -25,7 +25,7 @@ $( function() { $("#maxconn_select").on('selectmenuchange', function () { let server_ip = $('#maxconn_select').val(); $.ajax({ - url: "/app/runtimeapi/maxconn/" + $('#maxconn_select').val(), + url: "/runtimeapi/maxconn/" + $('#maxconn_select').val(), success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error: ') != '-1') { @@ -47,7 +47,7 @@ $( function() { }); $('#maxconnglobalform').submit(function () { $.ajax({ - url: "/app/runtimeapi/maxconn/global/" + $('#maxconn_global_select').val(), + url: "/runtimeapi/maxconn/global/" + $('#maxconn_global_select').val(), data: { maxconn: $('#maxconnintglobal').val(), }, @@ -65,7 +65,7 @@ $( function() { }); $('#maxconnform').submit(function () { $.ajax({ - url: "/app/runtimeapi/maxconn/frontend/" + $('#maxconn_select').val(), + url: "/runtimeapi/maxconn/frontend/" + $('#maxconn_select').val(), data: { maxconn_frontend: $('#maxconnfront').val(), maxconn: $('#maxconnint').val(), @@ -84,7 +84,7 @@ $( function() { }); $('#maxconnbackform').submit(function () { $.ajax({ - url: "/app/runtimeapi/maxconn/backend/" + $('#maxconn_backend_select').val(), + url: "/runtimeapi/maxconn/backend/" + $('#maxconn_backend_select').val(), data: { maxconn_backend: $('#maxconnbackend').val(), maxconn_backend_server: $('#maxconn_backend_server').val(), @@ -132,7 +132,7 @@ $( function() { $('#backend_ip').val(); $('#backend_port').val(); $.ajax({ - url: "/app/runtimeapi/backend/server/" + $('#ip_select').val() + "/" + $('#ipbackend').val() + "/" + $('#backend_server').val(), + url: "/runtimeapi/backend/server/" + $('#ip_select').val() + "/" + $('#ipbackend').val() + "/" + $('#backend_server').val(), success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error: ') != '-1') { @@ -150,7 +150,7 @@ $( function() { }); $('#runtimeapiip').submit(function () { $.ajax({ - url: "/app/runtimeapi/server", + url: "/runtimeapi/server", data: { serv: $('#ip_select').val(), backend_backend: $('#ipbackend').val(), @@ -176,7 +176,7 @@ $( function() { check = 1; } $.ajax({ - url: "/app/runtimeapi/server", + url: "/runtimeapi/server", data: { serv: $('#ip_select_server').val(), backend_backend: $('#ipBackendServer').val(), @@ -200,7 +200,7 @@ $( function() { }); $('#runtimeapiip_delete').submit(function () { $.ajax({ - url: "/app/runtimeapi/server", + url: "/runtimeapi/server", data: { serv: $('#ip_select_delete').val(), backend_backend: $('#ipbackend_delete').val(), @@ -229,7 +229,7 @@ $( function() { }); $("#table_serv_select").on('selectmenuchange', function () { $.ajax({ - url: "/app/runtimeapi/tables/" + $('#table_serv_select').val(), + url: "/runtimeapi/tables/" + $('#table_serv_select').val(), success: function (data) { data = data.replace(/\s+/g, ''); if (data.indexOf('error: ') != '-1') { @@ -254,7 +254,7 @@ $( function() { }); $("#list_serv_select").on('selectmenuchange', function () { $.ajax({ - url: "/app/runtimeapi/list/" + $('#list_serv_select').val(), + url: "/runtimeapi/list/" + $('#list_serv_select').val(), success: function (data) { data = data.replace(/, /g, ','); if (data.indexOf('error: ') != '-1') { @@ -292,7 +292,7 @@ $( function() { function deleteTableEntry(id, table, ip) { $(id).parent().parent().css("background-color", "#f2dede"); $.ajax( { - url: "/app/runtimeapi/table/" + $('#table_serv_select').val() + "/" + table + "/" + ip , + url: "/runtimeapi/table/" + $('#table_serv_select').val() + "/" + table + "/" + ip , success: function( data ) { if (data.indexOf('error: ') != '-1') { toastr.error(data); @@ -304,7 +304,7 @@ function deleteTableEntry(id, table, ip) { } function clearTable(table) { $.ajax( { - url: "/app/runtimeapi/table/clear/" + $('#table_serv_select').val() + "/" + table, + url: "/runtimeapi/table/clear/" + $('#table_serv_select').val() + "/" + table, success: function( data ) { if (data.indexOf('error: ') != '-1') { toastr.error(data); @@ -316,7 +316,7 @@ function clearTable(table) { } function getTable() { $.ajax({ - url: "/app/runtimeapi/table/" + $('#table_serv_select').val() + "/" + $('#table_select').val(), + url: "/runtimeapi/table/" + $('#table_serv_select').val() + "/" + $('#table_select').val(), success: function (data) { if (data.indexOf('error:') != '-1') { toastr.error(data); @@ -335,7 +335,7 @@ function getList() { let list_name = $('#list_select option:selected').text().split('/')[1]; console.log(list_name) $.ajax({ - url: "/app/runtimeapi/list/" + $('#list_serv_select').val() + "/" + $('#list_select').val() + "/" + color + "/" + list_name, + url: "/runtimeapi/list/" + $('#list_serv_select').val() + "/" + $('#list_select').val() + "/" + color + "/" + list_name, success: function (data) { if (data.indexOf('error: ') != '-1') { toastr.error(data); @@ -353,7 +353,7 @@ function deleteListIp(id, list_id, ip_id, ip) { toastr.clear(); $(id).parent().parent().css("background-color", "#f2dede !important"); $.ajax({ - url: "/app/runtimeapi/list/delete", + url: "/runtimeapi/list/delete", data: { serv: $('#list_serv_select').val(), list_id_for_delete: list_id, @@ -382,7 +382,7 @@ function addNewIp() { let ip = $('#list_add_ip_new_ip').val(); if (valid) { $.ajax({ - url: "/app/runtimeapi/list/add", + url: "/runtimeapi/list/add", data: { serv: $('#list_serv_select').val(), list_ip_for_add: ip, @@ -405,7 +405,7 @@ function addNewIp() { } function getSessions() { $.ajax({ - url: "/app/runtimeapi/session/" + $('#sessions_serv_select').val(), + url: "/runtimeapi/session/" + $('#sessions_serv_select').val(), success: function (data) { if (data.indexOf('error: ') != '-1') { toastr.error(data); @@ -421,7 +421,7 @@ function getSessions() { } function getSessionInfo(sess_id) { $.ajax({ - url: "/app/runtimeapi/session/" + $('#sessions_serv_select').val() + "/" + sess_id, + url: "/runtimeapi/session/" + $('#sessions_serv_select').val() + "/" + sess_id, success: function (data) { if (data.indexOf('danger') != '-1') { toastr.error(data); @@ -449,7 +449,7 @@ function deleteSession(id, sess_id) { toastr.clear(); $(id).parent().parent().css("background-color", "#f2dede !important"); $.ajax({ - url: "/app/runtimeapi/session/delete/" +$('#sessions_serv_select').val() + "/" + sess_id, + url: "/runtimeapi/session/delete/" +$('#sessions_serv_select').val() + "/" + sess_id, success: function (data) { if (data.indexOf('error: ') != '-1') { toastr.error(data); @@ -463,7 +463,7 @@ function deleteSession(id, sess_id) { } function get_backends(server_ip, backends_select_tag, ip_and_port=0) { $.ajax({ - url: "/app/runtimeapi/backends/" + server_ip, + url: "/runtimeapi/backends/" + server_ip, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error: ') != '-1') { @@ -482,7 +482,7 @@ function get_backends(server_ip, backends_select_tag, ip_and_port=0) { } function get_backend_servers(server_ip, backend, servers_select_tag, ip_and_port=0) { $.ajax({ - url: "/app/runtimeapi/backend/servers/" + server_ip + "/" + backend, + url: "/runtimeapi/backend/servers/" + server_ip + "/" + backend, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error: ') != '-1') { diff --git a/app/static/js/script.js b/app/static/js/script.js index 84d95a31..a5b0e833 100644 --- a/app/static/js/script.js +++ b/app/static/js/script.js @@ -1,4 +1,4 @@ -var cur_url = window.location.href.split('/app/').pop(); +var cur_url = window.location.href.split('/').pop(); cur_url = cur_url.split('/'); var intervalId; function validateEmail(email) { @@ -7,9 +7,9 @@ function validateEmail(email) { } function ValidateIPaddress(ipaddress) { if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) { - return (true) + return true } - return (false) + return false } var select_server = translate_div.attr('data-select_server'); function checkIsServerFiled(select_id, message = select_server) { @@ -36,109 +36,53 @@ function show_current_page(id) { id.parent().css('left', '0'); id.parent().children().css('margin-left', '-20px'); id.parent().find('a').css('padding-left', '20px'); - id.find('a').css('background-color', 'var(--right-menu-blue-rolor)'); + id.find('a').css('border-left', '4px solid var(--color-wanring) !important'); + id.find('a').css('background-color', 'var(--color-gray-dark-alpha) !important'); } $( function() { $('.menu li ul li').each(function () { - var link = $(this).find('a').attr('href'); - var link2 = link.split('/')[2]; - var link3 = link.split('/')[3]; - var link4 = link.split('/')[4]; - if (cur_url[1] == null) { - cur_url[1] = 'haproxy'; - } - var full_uri = cur_url[0] + '/' + cur_url[1] - var full_uri1 = link2 + '/' + link3 - var full_uri2 = cur_url[0] + '/' + cur_url[1] + '/' + cur_url[2] - var full_uri3 = link2 + '/' + link3 + '/' + link4 - if (cur_url[0] == link2 && link3 == null) { + let link = $(this).find('a').attr('href'); + let link2 = link.split('#')[1]; + let link3 = link.split('/')[2]; + let link4 = link.split('/')[3]; + // if (cur_url[1] == null) { + // cur_url[1] = 'haproxy'; + // } + let full_uri = window.location.pathname + let full_uri1 = window.location.hash + let full_uri2 = cur_url[0] + '/' + cur_url[1] + '/' + cur_url[2] + let full_uri3 = link2 + '/' + link3 + '/' + link4 + // console.log(link) + // console.log(window.location.hash) + let params = new URL(document.location.toString()).searchParams; + // console.log(params.get("service")) + // console.log(link) + // console.log(full_uri) + // console.log(full_uri1) + // console.log(full_uri + "/" + full_uri1) + // if (full_uri1 === '/service/haproxy') { + // console.log(full_uri) + // console.log(full_uri1) + // } + if (full_uri === link) { show_current_page($(this)) - } else if (full_uri == 'config/haproxy' && full_uri1 == 'config/haproxy') { + // } else if (window.location.pathname.indexOf('add/haproxy#') != '-1' && link.indexOf('add/haproxy#proxy') != '-1') { + // show_current_page($(this)) + } else if (link === full_uri + full_uri1) { show_current_page($(this)) - } else if (full_uri == 'config/nginx' && full_uri1 == 'config/nginx') { + // } else if (link === '/admin#servers' && full_uri1 === '#servers') { + // show_current_page($(this)) + // } else if (link === '/admin#ssh' && full_uri1 === '#ssh') { + // show_current_page($(this)) + // } else if (link === '/add/haproxy#proxy' && full_uri1 === '#proxy') { + // show_current_page($(this)) + } else if (link === '/add/haproxy#ssl' && full_uri1 === '#ssl' && params.get("service") != 'nginx') { show_current_page($(this)) - } else if (full_uri == 'config/apache' && full_uri1 == 'config/apache') { + } else if (link === '/add/haproxy#ssl' && full_uri1 === '#ssl' && params.get("service") === 'nginx') { show_current_page($(this)) - } else if (full_uri == 'config/keepalived' && full_uri1 == 'config/keepalived') { + } else if (full_uri === 'add/haproxy?service=nginx#ssl' && cur_url[1].split('?')[1] === 'service=nginx#ssl' && full_uri1 === 'add/haproxy?service=nginx#ssl') { show_current_page($(this)) - } else if (full_uri2 == 'config/versions/haproxy' && full_uri3 == 'config/versions/haproxy') { - show_current_page($(this)) - } else if (full_uri2 == 'config/versions/nginx' && full_uri3 == 'config/versions/nginx') { - show_current_page($(this)) - } else if (full_uri2 == 'config/versions/keepalived' && full_uri3 == 'config/versions/keepalived') { - show_current_page($(this)) - } else if (full_uri2 == 'config/versions/apache' && full_uri3 == 'config/versions/apache') { - show_current_page($(this)) - } else if (full_uri2 == 'config/map/haproxy' && full_uri1 == 'config/haproxy') { - show_current_page($(this)) - } else if (full_uri2 == 'config/compare/haproxy' && full_uri1 == 'config/haproxy') { - show_current_page($(this)) - } else if (full_uri2 == 'config/compare/nginx' && full_uri1 == 'config/nginx') { - show_current_page($(this)) - } else if (full_uri2 == 'config/compare/keepalived' && full_uri3 == 'config/keepalived') { - show_current_page($(this)) - } else if (full_uri2 == 'config/compare/apache' && full_uri3 == 'config/apache') { - show_current_page($(this)) - } else if (full_uri == 'logs/haproxy' && full_uri1 == 'logs/haproxy') { - show_current_page($(this)) - } else if (full_uri == 'logs/nginx' && full_uri1 == 'logs/nginx') { - show_current_page($(this)) - } else if (full_uri == 'logs/keepalived' && full_uri1 == 'logs/keepalived') { - show_current_page($(this)) - } else if (full_uri == 'logs/apache' && full_uri1 == 'logs/apache') { - show_current_page($(this)) - } else if (full_uri == 'logs/internal' && full_uri1 == 'logs/internal') { - show_current_page($(this)) - } else if (full_uri == 'service/haproxy' && full_uri1 == 'service/haproxy') { - show_current_page($(this)) - } else if (full_uri == 'service/nginx' && full_uri1 == 'service/nginx') { - show_current_page($(this)) - } else if (full_uri == 'service/keepalived' && full_uri1 == 'service/keepalived') { - show_current_page($(this)) - } else if (full_uri == 'service/apache' && full_uri1 == 'service/apache') { - show_current_page($(this)) - } else if (full_uri == 'stats/haproxy' && full_uri1 == 'stats/haproxy') { - show_current_page($(this)) - } else if (full_uri == 'stats/nginx' && full_uri1 == 'stats/nginx') { - show_current_page($(this)) - } else if (full_uri == 'stats/apache' && full_uri1 == 'stats/apache') { - show_current_page($(this)) - } else if (full_uri.indexOf('add/haproxy#') != '-1' && full_uri1.indexOf('add/haproxy#proxy') != '-1') { - show_current_page($(this)) - } else if (full_uri == 'add/haproxy#ssl' && full_uri1 == 'add/haproxy#ssl') { - show_current_page($(this)) - } else if (full_uri == 'add/nginx#proxy' && full_uri1 == 'add/nginx#proxy') { - show_current_page($(this)) - } else if (full_uri == 'smon/dashboard' && full_uri1 == 'smon/dashboard') { - show_current_page($(this)) - } else if (full_uri == 'smon/agent' && full_uri1 == 'smon/agent') { - show_current_page($(this)) - } else if (full_uri == 'smon/history' && full_uri1 == 'smon/history') { - show_current_page($(this)) - } else if (full_uri == 'smon/status-page' && full_uri1 == 'smon/status-page') { - show_current_page($(this)) - } else if (full_uri === 'checker/settings' && full_uri1 === 'checker/settings') { - show_current_page($(this)) - } else if (full_uri == 'checker/history' && full_uri1 == 'checker/history') { - show_current_page($(this)) - } else if (full_uri == 'add/haproxy?service=nginx#ssl' && cur_url[1].split('?')[1] == 'service=nginx#ssl' && full_uri1 == 'add/haproxy?service=nginx#ssl') { - show_current_page($(this)) - } else if (cur_url[0] == 'app/logs' && cur_url[1].split('&')[0] == 'type=2' && link2 == 'viewlogs.py?type=2') { - show_current_page($(this)); - return false; - } else if (full_uri == 'metrics/haproxy' && full_uri1 == 'metrics/haproxy') { - show_current_page($(this)) - } else if (full_uri == 'metrics/nginx' && full_uri1 == 'metrics/nginx') { - show_current_page($(this)) - } else if (full_uri == 'metrics/apache' && full_uri1 == 'metrics/apache') { - show_current_page($(this)) - } else if (full_uri == 'add/haproxy?service=apache#ssl' && cur_url[1].split('?')[1] == 'service=apache#ssl' && full_uri1 == 'add/haproxy?service=apache#ssl') { - show_current_page($(this)) - } else if (full_uri == 'waf/haproxy' && full_uri1 == 'waf/haproxy') { - show_current_page($(this)) - } else if (full_uri == 'waf/nginx' && full_uri1 == 'waf/nginx') { - show_current_page($(this)) - } else if (full_uri == 'install/ha' && full_uri1 == 'install/ha') { + } else if (full_uri === 'add/haproxy?service=apache#ssl' && cur_url[1].split('?')[1] === 'service=apache#ssl' && full_uri1 === 'add/haproxy?service=apache#ssl') { show_current_page($(this)) } }); @@ -156,29 +100,10 @@ jQuery.expr[':'].regex = function(elem, index, match) { regex = new RegExp(matchParams.join('').replace(/^\s+|\s+$/g,''), regexFlags); return regex.test(jQuery(elem)[attr.method](attr.property)); } -window.onblur= function() { - window.onfocus= function () { - if(sessionStorage.getItem('auto-refresh-pause') == "0" && sessionStorage.getItem('auto-refresh') > 5000) { - if (cur_url[0] == "logs") { - showLog(); - } else if (cur_url[0] == "stats") { - showStats() - } else if (cur_url[0] == "/") { - showOverview(); - } else if (cur_url[0] == "internal") { - viewLogs(); - } else if (cur_url[0] == "metrics") { - showMetrics(); - } else if (cur_url[0] == "smon" && cur_url[1] == "dashboard") { - showSmon('refresh') - } - } - } -}; if(localStorage.getItem('restart')) { - var ip_for_restart = localStorage.getItem('restart'); + let ip_for_restart = localStorage.getItem('restart'); $.ajax({ - url: "/app/service/check-restart/" + ip_for_restart, + url: "/service/check-restart/" + ip_for_restart, success: function (data) { if (data.indexOf('ok') != '-1') { var apply_div = $.find("#apply_div"); @@ -186,7 +111,7 @@ if(localStorage.getItem('restart')) { $("#apply").css('display', 'block'); $('#' + apply_div).css('width', '850px'); ip_for_restart = escapeHtml(ip_for_restart); - if (cur_url[0] == "service") { + if (cur_url[0] === "service") { $('#' + apply_div).css('width', '650px'); $('#' + apply_div).addClass("alert-one-row"); $('#' + apply_div).html("You have made changes to the server: " + ip_for_restart + ". Changes will take effect only afterrestartX"); @@ -198,134 +123,15 @@ if(localStorage.getItem('restart')) { } }); } -function autoRefreshStyle(autoRefresh) { - var margin; - if (cur_url[0] == "/" || cur_url[0] == "waf" || cur_url[0] == "metrics") { - if (autoRefresh < 60000) { - autoRefresh = 60000; - } - } - autoRefresh = autoRefresh / 1000; - if (autoRefresh == 60) { - timeRange = " minute" - autoRefresh = autoRefresh / 60; - } else if (autoRefresh > 60 && autoRefresh < 3600) { - timeRange = " minutes" - autoRefresh = autoRefresh / 60; - } else if (autoRefresh >= 3600 && autoRefresh < 86401) { - timeRange = " hours" - autoRefresh = autoRefresh / 3600; - } else { - timeRange = " seconds"; - } - $('#1').text(autoRefresh + timeRange); - $('#0').text(autoRefresh + timeRange); - $('.auto-refresh-pause').css('display', 'inline'); - $('.auto-refresh-resume').css('display', 'none'); - $('.auto-refresh-pause').css('margin-left', "-25px"); - $('.auto-refresh-resume').css('margin-left', "-25px"); - $('#browse_history').css("border-bottom", "none"); - $('.auto-refresh img').remove(); -} -function setRefreshInterval(interval) { - if (interval == "0") { - var autoRefresh = sessionStorage.getItem('auto-refresh'); - if (autoRefresh !== undefined) { - var autorefresh_word = translate_div.attr('data-autorefresh'); - sessionStorage.removeItem('auto-refresh'); - pauseAutoRefresh(); - $('#0').html(' '+autorefresh_word); - $('.auto-refresh').css('display', 'inline'); - $('.auto-refresh').css('font-size', '15px'); - $('#1').text(autorefresh_word); - $('.auto-refresh-resume').css('display', 'none'); - $('.auto-refresh-pause').css('display', 'none'); - $.getScript(overview); - } - hideAutoRefreshDiv(); - } else { - clearInterval(intervalId); - sessionStorage.setItem('auto-refresh', interval) - sessionStorage.setItem('auto-refresh-pause', 0) - startSetInterval(interval); - hideAutoRefreshDiv(); - autoRefreshStyle(interval); - } -} -function startSetInterval(interval) { - if(sessionStorage.getItem('auto-refresh-pause') == "0") { - if (cur_url[0] == "logs") { - intervalId = setInterval('showLog()', interval); - showLog(); - } else if (cur_url[0] == "stats") { - intervalId = setInterval('showStats()', interval); - showStats() - } else if (cur_url[0] == "/") { - if(interval < 60000) { - interval = 60000; - } - intervalId = setInterval('showOverview(ip, hostnamea)', interval); - showOverview(ip, hostnamea); - } else if (cur_url[1] == "internal") { - intervalId = setInterval('viewLogs()', interval); - viewLogs(); - } else if (cur_url[0] == "metrics") { - if(interval < 60000) { - interval = 60000; - } - intervalId = setInterval('showMetrics()', interval); - showMetrics(); - } else if (cur_url[0] == "waf") { - if(interval < 60000) { - interval = 60000; - } - intervalId = setInterval('showOverviewWaf(ip, hostnamea)', interval); - showOverviewWaf(ip, hostnamea); - showWafMetrics(); - } else if (cur_url[0] == "service") { - if(interval < 60000) { - interval = 60000; - } - intervalId = setInterval('showMetrics()', interval); - showMetrics(); - } else if (cur_url[0] == "smon" && cur_url[1] == "dashboard") { - intervalId = setInterval("showSmon('refresh')", interval); - showSmon('refresh'); - } else if (cur_url[0] == "smon" && cur_url[1] == "history") { - if(interval < 60000) { - interval = 60000; - } - intervalId = setInterval('showSmonHistory()', interval); - showSmonHistory(); - } - } else { - pauseAutoRefresh(); - } -} -function pauseAutoRefresh() { - clearInterval(intervalId); - $('.auto-refresh-pause').css('display', 'none'); - $('.auto-refresh-resume').css('display', 'inline'); - sessionStorage.setItem('auto-refresh-pause', '1'); -} -function pauseAutoResume(){ - var autoRefresh = sessionStorage.getItem('auto-refresh'); - setRefreshInterval(autoRefresh); - sessionStorage.setItem('auto-refresh-pause', '0'); -} -function hideAutoRefreshDiv() { - $(function() { - $('.auto-refresh-div').hide("blind", "fast"); - $('#1').css("display", "none"); - $('#0').css("display", "inline"); - }); -} $( document ).ajaxSend(function( event, request, settings ) { NProgress.start(); }); $( document ).ajaxComplete(function( event, request, settings ) { NProgress.done(); }); +$.ajaxSetup({ + headers: {"X-CSRF-TOKEN": csrf_token}, +}); $(document).ajaxError(function myErrorHandler(event, xhr, ajaxOptions, thrownError) { if (xhr.status != 401) { toastr.error(xhr.responseJSON.error); @@ -333,38 +139,38 @@ $(document).ajaxError(function myErrorHandler(event, xhr, ajaxOptions, thrownErr }); function showStats() { $.ajax({ - url: "/app/stats/view/" + $("#service").val() + "/" + $("#serv").val(), + url: "/stats/view/" + $("#service").val() + "/" + $("#serv").val(), success: function (data) { if (data.indexOf('error:') != '-1' && data.indexOf('Internal error:') == '-1') { toastr.error(data); } else { toastr.clear(); $("#ajax").html(data); - window.history.pushState("Stats", "Stats", "/app/stats/" + $("#service").val() + "/" + $("#serv").val()); + window.history.pushState("Stats", "Stats", "/stats/" + $("#service").val() + "/" + $("#serv").val()); wait(); } } }); } function openStats() { - var serv = $("#serv").val(); - var service_url = cur_url[1]; - var url = "/app/stats/"+service_url+"/"+serv - var win = window.open(url, '_blank'); + let serv = $("#serv").val(); + let service_url = cur_url[4]; + let url = "/stats/"+service_url+"/"+serv + let win = window.open(url, '_blank'); win.focus(); } function openVersions() { - var serv = $("#serv").val(); - var service_url = cur_url[1]; - var url = "/app/config/versions/"+service_url+"/"+serv - var win = window.open(url,"_self"); + let serv = $("#serv").val(); + let service_url = cur_url[4]; + let url = "/config/versions/"+service_url+"/"+serv + let win = window.open(url,"_self"); win.focus(); } function openSection() { - var serv = $("#serv").val(); - var section = $("#section").val(); - var url = "/app/config/section/haproxy/"+serv+"/"+section; - var win = window.open(url,"_self"); + let serv = $("#serv").val(); + let section = $("#section").val(); + let url = "/config/section/haproxy/"+serv+"/"+section; + let win = window.open(url,"_self"); win.focus(); } function showLog() { @@ -392,10 +198,10 @@ function showLog() { service = 'haproxy'; } if (waf) { - var url = "/app/logs/" + service + "/waf/" + serv + "/" + rows; + var url = "/logs/" + service + "/waf/" + serv + "/" + rows; waf = 1; } else { - var url = "/app/logs/" + service + "/" + serv + "/" + rows; + var url = "/logs/" + service + "/" + serv + "/" + rows; } $.ajax( { url: url, @@ -435,7 +241,7 @@ function showRemoteLogFiles() { service = 'haproxy'; } $.ajax( { - url: "/app/logs/" + service + "/" + serv , + url: "/logs/" + service + "/" + serv , data: { serv: $("#serv").val(), }, @@ -469,21 +275,21 @@ function showMap() { clearAllAjaxFields(); $('#ajax-config_file_name').empty(); $.ajax( { - url: "/app/config/map/haproxy/" + $("#serv").val() + '/show', + url: "/config/map/haproxy/" + $("#serv").val() + '/show', success: function( data ) { if (data.indexOf('error:') != '-1') { toastr.error(data); } else { toastr.clear(); $("#ajax").html(data); - window.history.pushState("Show Map", "Show Map", '/app/config/map/' + $("#service").val() + '/' + $("#serv").val()); + window.history.pushState("Show Map", "Show Map", '/config/map/' + $("#service").val() + '/' + $("#serv").val()); } } } ); } function showCompare() { $.ajax( { - url: "/app/config/compare/" + $("#service").val() + "/" + $("#serv").val() + "/show", + url: "/config/compare/" + $("#service").val() + "/" + $("#serv").val() + "/show", data: { left: $('#left').val(), right: $("#right").val(), @@ -503,7 +309,7 @@ function showCompareConfigs() { clearAllAjaxFields(); $('#ajax-config_file_name').empty(); $.ajax( { - url: "/app/config/compare/" + $("#service").val() + "/" + $("#serv").val() + "/files", + url: "/config/compare/" + $("#service").val() + "/" + $("#serv").val() + "/files", type: "GET", success: function( data ) { if (data.indexOf('error:') != '-1') { @@ -513,19 +319,20 @@ function showCompareConfigs() { $("#ajax-compare").html(data); $("input[type=submit], button").button(); $("select").selectmenu(); - window.history.pushState("Show compare config", "Show compare config", '/app/config/compare/' + $("#service").val() + '/' + $("#serv").val()); + window.history.pushState("Show compare config", "Show compare config", '/config/compare/' + $("#service").val() + '/' + $("#serv").val()); } } } ); } function showConfig() { - var service = $('#service').val(); - var config_file_name = encodeURI($('#config_file_name').val()); - if (service == 'nginx' || service == 'apache') { - if ($('#config_file_name').val() === undefined || $('#config_file_name').val() === null) { + let service = $('#service').val(); + let config_file = $('#config_file_name').val() + let config_file_name = encodeURI(config_file); + if (service === 'nginx' || service === 'apache') { + if (config_file === undefined || config_file === null) { config_file_name = cur_url[4] - if (config_file_name == '') { - toastr.warning('Select a config file firts'); + if (config_file_name === '') { + toastr.warning('Select a config file first'); return false; } else { showConfigFiles(true); @@ -534,7 +341,7 @@ function showConfig() { } clearAllAjaxFields(); $.ajax( { - url: "/app/config/" + service + "/show", + url: "/config/" + service + "/show", data: { serv: $("#serv").val(), service: service, @@ -548,7 +355,7 @@ function showConfig() { toastr.clear(); $("#ajax").html(data); $.getScript(configShow); - window.history.pushState("Show config", "Show config", "/app/config/" + service + "/" + $("#serv").val() + "/show/" + config_file_name); + window.history.pushState("Show config", "Show config", "/config/" + service + "/" + $("#serv").val() + "/show/" + config_file_name); } } } ); @@ -558,7 +365,7 @@ function showConfigFiles(not_redirect=false) { var server_ip = $("#serv").val(); clearAllAjaxFields(); $.ajax( { - url: "/app/config/" + service + "/show-files", + url: "/config/" + service + "/show-files", data: { serv: server_ip, service: service @@ -572,7 +379,7 @@ function showConfigFiles(not_redirect=false) { $("#ajax-config_file_name").html(data); if (findGetParameter('findInConfig') === null) { if (not_redirect) { - window.history.pushState("Show config", "Show config", "/app/config/" + service + "/" + server_ip + "/show-files"); + window.history.pushState("Show config", "Show config", "/config/" + service + "/" + server_ip + "/show-files"); } } } @@ -580,12 +387,12 @@ function showConfigFiles(not_redirect=false) { } ); } function showConfigFilesForEditing() { - var service = $('#service').val(); - var server_ip = $("#serv").val(); - var config_file_name = findGetParameter('config_file_name') - if (service == 'nginx' || service == 'apache') { + let service = $('#service').val(); + let server_ip = $("#serv").val(); + let config_file_name = findGetParameter('config_file_name') + if (service === 'nginx' || service === 'apache') { $.ajax({ - url: "/app/config/" + service + "/" + server_ip + "/edit/" + config_file_name, + url: "/config/" + service + "/" + server_ip + "/edit/" + config_file_name, type: "POST", success: function (data) { if (data.indexOf('error:') != '-1') { @@ -599,11 +406,11 @@ function showConfigFilesForEditing() { } } function showUploadConfig() { - var service = $('#service').val(); - var configver = $('#configver').val(); - var serv = $("#serv").val() + let service = $('#service').val(); + let configver = $('#configver').val(); + let serv = $("#serv").val() $.ajax( { - url: "/app/config/" + service + "/show", + url: "/config/" + service + "/show", data: { serv: serv, configver: configver @@ -615,21 +422,21 @@ function showUploadConfig() { } else { toastr.clear(); $("#ajax").html(data); - window.history.pushState("Show config", "Show config", "/app/config/versions/" + service + "/" + serv + "/" + configver); + window.history.pushState("Show config", "Show config", "/config/versions/" + service + "/" + serv + "/" + configver); $.getScript(configShow); } } } ); } function showListOfVersion(for_delver) { - var cur_url = window.location.href.split('/app/').pop(); + let cur_url = window.location.href.split('/').pop(); cur_url = cur_url.split('/'); - var service = $('#service').val(); - var serv = $("#serv").val(); - var configver = cur_url[4]; + let service = $('#service').val(); + let serv = $("#serv").val(); + let configver = cur_url[4]; clearAllAjaxFields(); $.ajax( { - url: "/app/config/version/" + service + "/list", + url: "/config/version/" + service + "/list", data: { serv: serv, configver: configver, @@ -643,39 +450,39 @@ function showListOfVersion(for_delver) { toastr.clear(); $("#config_version_div").html(data); $( "input[type=checkbox]" ).checkboxradio(); - window.history.pushState("Show config", "Show config", "/app/config/versions/" + service + "/" + serv); + window.history.pushState("Show config", "Show config", "/config/versions/" + service + "/" + serv); } } } ); } function findGetParameter(parameterName) { - var result = null, + let result = null, tmp = []; - var items = location.search.substr(1).split("&"); - for (var index = 0; index < items.length; index++) { + let items = location.search.substr(1).split("&"); + for (let index = 0; index < items.length; index++) { tmp = items[index].split("="); if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]); } return result; } function viewLogs() { - var viewlogs = $('#viewlogs').val(); - if (viewlogs == '------' || viewlogs === null) { return false; } - if(viewlogs == 'roxy-wi.error.log' || viewlogs == 'roxy-wi.access.log' || viewlogs == 'fail2ban.log') { + let viewlogs = $('#viewlogs').val(); + if (viewlogs === '------' || viewlogs === null) { return false; } + if(viewlogs === 'roxy-wi.error.log' || viewlogs === 'roxy-wi.access.log' || viewlogs === 'fail2ban.log') { showApacheLog(viewlogs); } else { - var rows = $('#rows').val(); - var grep = $('#grep').val(); - var exgrep = $('#exgrep').val(); - var hour = $('#time_range_out_hour').val(); - var minute = $('#time_range_out_minut').val(); - var hour1 = $('#time_range_out_hour1').val(); - var minute1 = $('#time_range_out_minut1').val(); - var type = findGetParameter('type') + let rows = $('#rows').val(); + let grep = $('#grep').val(); + let exgrep = $('#exgrep').val(); + let hour = $('#time_range_out_hour').val(); + let minute = $('#time_range_out_minut').val(); + let hour1 = $('#time_range_out_hour1').val(); + let minute1 = $('#time_range_out_minut1').val(); + let type = findGetParameter('type') if (viewlogs == null){ viewlogs = findGetParameter('viewlogs') } - var url = "/app/logs/internal/" + viewlogs + "/" + rows; + let url = "/logs/internal/" + viewlogs + "/" + rows; $.ajax({ url: url, data: { @@ -701,7 +508,7 @@ $( function() { try { var cur_path = window.location.pathname; var attr = $(this).attr('href'); - if (cur_path == '/app/add/haproxy' || cur_path == '/app/add/nginx' || cur_path == '/app/admin' || cur_path == '/app/install' || cur_path == '/app/runtimeapi') { + if (cur_path == '/add/haproxy' || cur_path == '/add/nginx' || cur_path == '/admin' || cur_path == '/install' || cur_path == '/runtimeapi') { if (typeof attr !== typeof undefined && attr !== false) { $('title').text($(this).attr('title')); history.pushState({}, '', $(this).attr('href')); @@ -730,16 +537,6 @@ $( function() { $("#show").css("pointer-events", "none"); $("#show").css("cursor", "not-allowed"); } - - var pause = '' - var autoRefresh = sessionStorage.getItem('auto-refresh'); - - if ($('.auto-refresh')) { - if(autoRefresh) { - startSetInterval(autoRefresh); - autoRefreshStyle(autoRefresh); - } - } $( "#tabs" ).tabs(); $( "select" ).selectmenu(); @@ -862,42 +659,45 @@ $( function() { } else { $('#time_range_out_minut1').val(date2_minute); } - - $('#0').click(function() { - $('.auto-refresh-div').show("blind", "fast"); - $('#0').css("display", "none"); - $('#1').css("display", "inline"); - }); - - $('#1').click(function() { - $('.auto-refresh-div').hide("blind", "fast"); - $('#1').css("display", "none"); - $('#0').css("display", "inline"); - }); - $('#auth').submit(function() { - var next_url = findGetParameter('next'); - $.ajax( { - url: "/app/login", - data: { - login: $('#login').val(), - pass: $('#pass').val(), - next: next_url - }, + $('#auth').submit(function () { + let next_url = findGetParameter('next'); + let json_data = { + "login": $('#login').val(), + "pass": $('#pass').val(), + "next": next_url + } + $.ajax({ + url: "/login", + data: JSON.stringify(json_data), + contentType: "application/json; charset=utf-8", type: "POST", - success: function( data ) { - if (data.indexOf('disabled') != '-1') { + statusCode: { + 401: function (xhr) { $('.alert').show(); - $('.alert').html(data); - } else if (data.indexOf('ban') != '-1') { - ban(); - } else if (data.indexOf('error') != '-1') { - toastr.error(data); + if (xhr.responseText.indexOf('disabled') != '-1') { + $('.alert').html('Your login is disabled') + } else { + $('.alert').html('Login or password is incorrect'); + ban(); + } + } + }, + success: function (data) { + if (data.status === 'failed') { + if (data.error.indexOf('disabled') != '-1') { + $('.alert').show(); + $('.alert').html(data.error); + } else { + $('.alert').show(); + $('.alert').html(data.error); + ban(); + } } else { sessionStorage.removeItem('check-service'); - window.location.replace(data); + window.location.replace(data.next_url); } } - } ); + }); return false; }); $('#show_log_form').submit(function() { @@ -908,88 +708,24 @@ $( function() { viewLogs(); return false; }); - - var user_settings_tabel_title = $( "#show-user-settings-table" ).attr('title'); - var change_word = translate_div.attr('data-change'); - var password_word = translate_div.attr('data-password'); - var change_pass_word = change_word + ' ' + password_word - var showUserSettings = $( "#show-user-settings" ).dialog({ - autoOpen: false, - width: 600, - modal: true, - title: user_settings_tabel_title, - buttons: [{ - text: save_word, - click: function () { - saveUserSettings(); - $(this).dialog("close"); - } - }, { - text: change_pass_word, - click: function () { - changePassword(); - $(this).dialog("close"); - } - }, { - text: cancel_word, - click: function () { - $(this).dialog("close"); - } - }] - }); - - $('#show-user-settings-button').click(function() { - if (localStorage.getItem('disabled_alert') == '1') { - $('#disable_alerting').prop('checked', false).checkboxradio('refresh'); - } else { - $('#disable_alerting').prop('checked', true).checkboxradio('refresh'); - } - $.ajax({ - url: "/app/user/group", - success: function (data) { - if (data.indexOf('danger') != '-1') { - $("#ajax").html(data); - } else { - $('#show-user-settings-group').html(data); - $("select").selectmenu(); - } - } - }); - showUserSettings.dialog('open'); - }); - var cur_url = window.location.href.split('/app/').pop(); - cur_url = cur_url.split('/'); + let cur_url = window.location.href.split('/').pop(); + cur_url = cur_url.split('#'); if (cur_url[0].indexOf('install') != '-1') { $(".installproxy").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('padding-left', '20px') - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".installproxy").css('padding-left', '30px'); - $(this).children(".installproxy").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".installproxy").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'installproxy'); }); $("#tabs").tabs("option", "active", 0); }); $(".installmon").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('padding-left', '20px') - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".installmon").css('padding-left', '30px'); - $(this).children(".installmon").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".installmon").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'instalmon'); }); $("#tabs").tabs("option", "active", 1); }); $(".installgeo").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('padding-left', '20px') - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".installgeo").css('padding-left', '30px'); - $(this).children(".installgeo").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".installgeo").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'installgeo'); }); $("#tabs").tabs("option", "active", 2); }); @@ -997,92 +733,52 @@ $( function() { if (cur_url[0].indexOf('admin') != '-1') { $(".users").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('padding-left', '20px') - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".users").css('padding-left', '30px'); - $(this).children(".users").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".users").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'users'); }); $("#tabs").tabs("option", "active", 0); }); - $(".runtime").on("click", function () { + $(".servers").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('padding-left', '20px'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".runtime").css('padding-left', '30px'); - $(this).children(".runtime").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".runtime").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'servers'); }); $("#tabs").tabs("option", "active", 1); }); - $(".admin").on("click", function () { + $(".ssh").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('padding-left', '20px'); - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".admin").css('padding-left', '30px'); - $(this).children(".admin").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".admin").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'ssh'); }); $("#tabs").tabs("option", "active", 2); }); $(".settings").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('padding-left', '20px'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".settings").css('padding-left', '30px'); - $(this).children(".settings").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".settings").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'settings'); }); $("#tabs").tabs("option", "active", 3); loadSettings(); }); $(".backup").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('padding-left', '20px'); - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".backup").css('padding-left', '30px'); - $(this).children(".backup").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".backup").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'backup'); }); $("#tabs").tabs("option", "active", 4); loadBackup(); }); - $(".group").on("click", function () { + $(".groups").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('padding-left', '20px'); - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".group").css('padding-left', '30px'); - $(this).children(".group").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".group").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'groups'); }); $("#tabs").tabs("option", "active", 5); }); $(".tools").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('padding-left', '20px'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".tools").css('padding-left', '30px'); - $(this).children(".tools").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".tools").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'tools'); }); $("#tabs").tabs("option", "active", 6); loadServices(); }); $(".updatehapwi").on("click", function () { $('.menu li ul li').each(function () { - $(this).find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); - $(this).find('a').css('padding-left', '20px'); - $(this).find('a').css('background-color', '#48505A'); - $(this).children(".updatehapwi").css('padding-left', '30px'); - $(this).children(".updatehapwi").css('border-left', '4px solid var(--right-menu-blue-rolor)'); - $(this).children(".updatehapwi").css('background-color', 'var(--right-menu-blue-rolor)'); + activeSubMenu($(this), 'updatehapwi'); }); $("#tabs").tabs("option", "active", 7); loadupdatehapwi(); @@ -1104,14 +800,21 @@ $( function() { document.body.removeChild(el); }) }); -function saveUserSettings(){ +function activeSubMenu(sub_menu, sub_menu_class) { + sub_menu.find('a').css('padding-left', '20px'); + sub_menu.find('a').css('border-left', '0px solid var(--right-menu-blue-rolor)'); + sub_menu.find('a').css('background-color', '#48505A'); + sub_menu.children("." + sub_menu_class).css('padding-left', '30px'); + sub_menu.children("." + sub_menu_class).css('border-left', '4px solid var(--color-wanring) !important'); + sub_menu.children("." + sub_menu_class).css('background-color', 'var(--color-gray-dark-alpha) !important'); +} +function saveUserSettings(user_id){ if ($('#disable_alerting').is(':checked')) { localStorage.removeItem('disabled_alert'); } else { localStorage.setItem('disabled_alert', '1'); } - changeCurrentGroupF(); - Cookies.set('lang', $('#lang_select').val(), { expires: 365, path: '/', samesite: 'strict', secure: 'true' }); + changeCurrentGroupF(user_id); } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); @@ -1120,23 +823,23 @@ function getRandomArbitrary(min, max) { return Math.random() * (max - min) + min; } async function ban() { - $( '#login').attr('disabled', 'disabled'); - $( '#pass').attr('disabled', 'disabled'); - $( "input[type=submit], button" ).button('disable'); + $('#login').attr('disabled', 'disabled'); + $('#pass').attr('disabled', 'disabled'); + $("input[type=submit], button").button('disable'); $('#wrong-login').show(); $('#ban_10').show(); - $( '#ban_timer').text(10); + $('#ban_timer').text(10); let i = 10; while (i > 0) { i--; await sleep(1000); - $( '#ban_timer').text(i); - } + $('#ban_timer').text(i); + } - $( '#login').removeAttr('disabled'); - $( '#pass').removeAttr('disabled'); - $( "input[type=submit], button" ).button('enable'); + $('#login').removeAttr('disabled'); + $('#pass').removeAttr('disabled'); + $("input[type=submit], button").button('enable'); $('#ban_10').hide(); } function replace_text(id_textarea, text_var) { @@ -1187,21 +890,16 @@ function listHistroy() { createHistroy(); listHistroy(); -function changeCurrentGroupF() { +function changeCurrentGroupF(user_id) { $.ajax({ - url: "/app/user/group", - data: { - group: $('#newCurrentGroup').val(), - uuid: Cookies.get('uuid') - }, - type: "PUT", + url: "/user/" + user_id + "/groups/" + $('#newCurrentGroup').val(), + contentType: "application/json; charset=utf-8", + type: "PATCH", success: function (data) { - if (data.indexOf('error: ') != '-1') { - toastr.error(data); + if (data.error === 'failed') { + toastr.error(data.error); } else { toastr.clear(); - Cookies.remove('group'); - Cookies.set('group', $('#newCurrentGroup').val(), {expires: 365, path: '/', samesite: 'strict', secure: 'true'}); location.reload(); } } @@ -1244,7 +942,7 @@ $(function () { } ], volume: 0.5, - path: "/app/static/js/sounds/", + path: "/static/js/sounds/", preload: true }); }); @@ -1256,11 +954,11 @@ socket.onopen = function(e) { }; function getAlerts() { - socket.send("alert_group " + Cookies.get('group') + ' ' + Cookies.get('uuid')); + socket.send("alert_group " + $('#user_group_socket').val() + " " + $('#user_id_socket').val()); } socket.onmessage = function(event) { - var cur_url = window.location.href.split('/app/').pop(); + var cur_url = window.location.href.split('/').pop(); cur_url = cur_url.split('/'); if (cur_url != 'login' && localStorage.getItem('disabled_alert') === null) { data = event.data.split(";"); @@ -1333,15 +1031,11 @@ function changeUserPasswordItOwn(d) { } else { $('#missmatchpass').hide(); toastr.clear(); - let jsonData = { - "password": pass, - "uuid": Cookies.get('uuid') - } $.ajax({ - url: "/app/user/password", - data: JSON.stringify(jsonData), - contentType: "application/json; charset=utf-8", + url: "/user/password", + data: JSON.stringify({'pass': pass}), type: "POST", + contentType: "application/json; charset=utf-8", success: function (data) { if (data.status === 'failed') { toastr.error(data.error); @@ -1356,7 +1050,7 @@ function changeUserPasswordItOwn(d) { function findInConfig(words) { clearAllAjaxFields(); $.ajax({ - url: "/app/config/" + $("#service").val() + "/find-in-config", + url: "/config/" + $("#service").val() + "/find-in-config", data: { serv: $("#serv").val(), words: words @@ -1470,7 +1164,7 @@ function returnNiceCheckingConfig(data) { function show_version() { NProgress.configure({showSpinner: false}); $.ajax( { - url: "/app/internal/show_version", + url: "/internal/show_version", success: function( data ) { $('#version').html(data); var showUpdates = $( "#show-updates" ).dialog({ @@ -1493,7 +1187,7 @@ function show_version() { NProgress.configure({showSpinner: true}); } function statAgriment() { - var cur_url = window.location.href.split('/app/').pop(); + var cur_url = window.location.href.split('/').pop(); cur_url = cur_url.split('/'); if (localStorage.getItem('statistic') == null && cur_url != 'login') { var titles = new Map() @@ -1659,3 +1353,63 @@ function common_ajax_action_after_success(dialog_id, new_group, ajax_append_id, $( "."+new_group ).removeClass( "update" ); }, 2500 ); } +function getAllGroups() { + let groups = ''; + $.ajax({ + url: "/server/groups", + contentType: "application/json; charset=utf-8", + async: false, + success: function (data) { + groups = data; + } + }); + return groups; +} +function openUserSettings(user_id) { + if (localStorage.getItem('disabled_alert') == '1') { + $('#disable_alerting').prop('checked', false).checkboxradio('refresh'); + } else { + $('#disable_alerting').prop('checked', true).checkboxradio('refresh'); + } + $.ajax({ + url: "/user/group", + success: function (data) { + if (data.indexOf('danger') != '-1') { + $("#ajax").html(data); + } else { + $('#show-user-settings-group').html(data); + $("select").selectmenu(); + } + } + }); + let user_settings_tabel_title = $("#show-user-settings-table").attr('title'); + let change_pass_word = $('#translate').attr('data-change') + ' ' + $('#translate').attr('data-password') + let showUserSettings = $("#show-user-settings").dialog({ + autoOpen: false, + width: 600, + modal: true, + title: user_settings_tabel_title, + buttons: [{ + text: save_word, + click: function () { + saveUserSettings(user_id); + $(this).dialog("close"); + } + }, { + text: change_pass_word, + click: function () { + changePassword(); + $(this).dialog("close"); + } + }, { + text: cancel_word, + click: function () { + $(this).dialog("close"); + } + }] + }); + showUserSettings.dialog('open'); +} +function generateSelect(select_id, option_value, option_name, is_selected='') { + $(select_id).append(''); +} diff --git a/app/static/js/smon.js b/app/static/js/smon.js index e0636ad4..03724442 100644 --- a/app/static/js/smon.js +++ b/app/static/js/smon.js @@ -18,7 +18,7 @@ function sort_by_status() { function showSmon(action) { let sort = ''; let location = window.location.href; - let cur_url = '/app/' + location.split('/').pop(); + let cur_url = '/' + location.split('/').pop(); if (action === 'refresh') { try { sort = cur_url[1].split('&')[1]; @@ -28,10 +28,10 @@ function showSmon(action) { } } if (action === 'not_sort') { - window.history.pushState("SMON Dashboard", "SMON Dashboard", "/app/smon/dashboard"); + window.history.pushState("SMON Dashboard", "SMON Dashboard", "/smon/dashboard"); } $.ajax({ - url: "/app/smon/refresh", + url: "/smon/refresh", data: { sort: sort, token: $('#token').val() @@ -108,7 +108,7 @@ function addNewSmonServer(dialog_id, smon_id=0, edit=false) { } if (valid) { $.ajax( { - url: '/app/smon/check', + url: '/smon/check', data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: method, @@ -155,7 +155,7 @@ function removeSmon(smon_id) { $("#smon-"+smon_id).css("background-color", "#f2dede"); let jsonData = {'check_id': smon_id} $.ajax( { - url: "/app/smon/check", + url: "/smon/check", type: "DELETE", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", @@ -218,7 +218,7 @@ function openSmonDialog(check_type, smon_id=0, edit=false) { } function getCheckSettings(smon_id, check_type) { $.ajax( { - url: "/app/smon/check/settings/" + smon_id + "/" + check_types[check_type], + url: "/smon/check/settings/" + smon_id + "/" + check_types[check_type], type: "get", async: false, dataType: "json", @@ -270,7 +270,7 @@ function cloneSmom(id, check_type) { } function getSmonCheck(smon_id, check_id, dialog_id, new_check=false) { $.ajax({ - url: "/app/smon/check/" + smon_id + "/" + check_id, + url: "/smon/check/" + smon_id + "/" + check_id, type: "get", success: function (data) { if (new_check) { @@ -336,7 +336,7 @@ function clear_check_vals() { function show_statuses(dashboard_id, check_id, id_for_history_replace) { show_smon_history_statuses(dashboard_id, id_for_history_replace); $.ajax({ - url: "/app/smon/history/cur_status/" + dashboard_id + "/" + check_id, + url: "/smon/history/cur_status/" + dashboard_id + "/" + check_id, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { @@ -350,7 +350,7 @@ function show_statuses(dashboard_id, check_id, id_for_history_replace) { } function show_smon_history_statuses(dashboard_id, id_for_history_replace) { $.ajax({ - url: "/app/smon/history/statuses/" + dashboard_id, + url: "/smon/history/statuses/" + dashboard_id, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { @@ -370,7 +370,7 @@ function show_smon_history_statuses(dashboard_id, id_for_history_replace) { } function smon_status_page_avg_status(page_id) { $.ajax({ - url: "/app/smon/status/avg/" + page_id, + url: "/smon/status/avg/" + page_id, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { @@ -388,7 +388,7 @@ function smon_status_page_avg_status(page_id) { } function smon_manage_status_page_avg_status(page_id) { $.ajax({ - url: "/app/smon/status/avg/" + page_id, + url: "/smon/status/avg/" + page_id, success: function (data) { data = data.replace(/\s+/g, ' '); if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { @@ -468,7 +468,7 @@ function createStatusPageStep2(edited, page_id) { add_word = translate_div.attr('data-edit'); if ($("#enabled-check > div").length == 0) { $.ajax({ - url: "/app/smon/status/checks/" + page_id, + url: "/smon/status/checks/" + page_id, async: false, type: "GET", success: function (data) { @@ -544,7 +544,7 @@ function createStatusPage(dialog_id) { checks.push(check_id); }); $.ajax({ - url: '/app/smon/status-page', + url: '/smon/status-page', type: 'POST', data: { name: name_id.val(), @@ -575,7 +575,7 @@ function editStatusPage(dialog_id, page_id) { checks.push(check_id); }); $.ajax({ - url: '/app/smon/status-page', + url: '/smon/status-page', type: 'PUT', data: { page_id: page_id, @@ -649,7 +649,7 @@ function confirmDeleteStatusPage(id) { } function deleteStatusPage(page_id) { $.ajax({ - url: '/app/smon/status-page', + url: '/smon/status-page', type: 'DELETE', data: { page_id: page_id, @@ -667,7 +667,7 @@ function deleteStatusPage(page_id) { function checkAgentLimit() { let return_value = false; $.ajax({ - url: '/app/smon/agent/count', + url: '/smon/agent/count', async: false, success: function (data) { data = data.replace(/\s+/g, ' '); @@ -772,7 +772,7 @@ function addAgent(dialog_id, agent_id=0, edit=false, reconfigure=false) { } if (valid) { $.ajax({ - url: "/app/smon/agent", + url: "/smon/agent", type: method, data: JSON.stringify(agent_data), contentType: "application/json; charset=utf-8", @@ -795,7 +795,7 @@ function addAgent(dialog_id, agent_id=0, edit=false, reconfigure=false) { } function getAgentSettings(agent_id) { $.ajax({ - url: "/app/smon/agent/settings/" + agent_id, + url: "/smon/agent/settings/" + agent_id, async: false, success: function (data) { $('#new-agent-name').val(data['name']); @@ -815,7 +815,7 @@ function getAgentSettings(agent_id) { } function getFreeServers() { $.ajax({ - url: "/app/smon/agent/free", + url: "/smon/agent/free", async: false, contentType: "application/json; charset=utf-8", success: function (data) { @@ -838,7 +838,7 @@ function cleanAgentAddForm() { } function getAgent(agent_id, new_agent=false) { $.ajax({ - url: "/app/smon/agent/" + agent_id, + url: "/smon/agent/" + agent_id, success: function (data) { data = data.replace(/^\s+|\s+$/g, ''); if (data.indexOf('error:') != '-1') { @@ -857,7 +857,7 @@ function getAgent(agent_id, new_agent=false) { } function getAgentVersion(server_ip, agent_id){ $.ajax({ - url: '/app/smon/agent/version/' + server_ip, + url: '/smon/agent/version/' + server_ip, type: 'get', data: {agent_id: agent_id}, success: function (data){ @@ -872,7 +872,7 @@ function getAgentVersion(server_ip, agent_id){ } function getAgentUptime(server_ip, agent_id){ $.ajax({ - url: '/app/smon/agent/uptime/' + server_ip, + url: '/smon/agent/uptime/' + server_ip, type: 'get', data: {agent_id: agent_id}, success: function (data){ @@ -889,7 +889,7 @@ function getAgentUptime(server_ip, agent_id){ } function getAgentStatus(server_ip, agent_id){ $.ajax({ - url: '/app/smon/agent/status/' + server_ip, + url: '/smon/agent/status/' + server_ip, type: 'get', data: {agent_id: agent_id}, success: function (data){ @@ -919,7 +919,7 @@ function getAgentStatus(server_ip, agent_id){ } function getAgentTotalChecks(server_ip, agent_id){ $.ajax({ - url: '/app/smon/agent/checks/' + server_ip, + url: '/smon/agent/checks/' + server_ip, type: 'get', data: {agent_id: agent_id}, success: function (data){ @@ -956,7 +956,7 @@ function confirmDeleteAgent(id) { } function removeAgent(id, dialog_id) { $.ajax({ - url: "/app/smon/agent", + url: "/smon/agent", type: "delete", data: {agent_id: id}, success: function (data){ @@ -994,7 +994,7 @@ function confirmAjaxAction(action, id, server_ip) { } function agentAction(action, id, server_ip, dialog_id) { $.ajax({ - url: "/app/smon/agent/action/"+ action, + url: "/smon/agent/action/"+ action, type: "post", data: {agent_id: id, server_ip: server_ip}, success: function (data) { @@ -1012,7 +1012,7 @@ function agentAction(action, id, server_ip, dialog_id) { var charts = [] function getSmonHistoryCheckData(server) { $.ajax({ - url: "/app/smon/history/metric/" + server, + url: "/smon/history/metric/" + server, success: function (result) { let data = []; data.push(result.chartData.curr_con); diff --git a/app/static/js/udp.js b/app/static/js/udp.js index 3610a273..a1f3d1c1 100644 --- a/app/static/js/udp.js +++ b/app/static/js/udp.js @@ -1,23 +1,23 @@ $( function() { - $( "#ha-cluster" ).on('selectmenuchange',function() { - let cluster_id = $( "#ha-cluster option:selected" ).val(); - if (cluster_id != '------') { + $("#cluster_id").on('selectmenuchange', function () { + let cluster_id = $("#cluster_id option:selected").val(); + if (cluster_id != '------' && cluster_id != '' && cluster_id != undefined) { getHAClusterVIPS(cluster_id); } else { clearUdpVip(); } }); - $("#new-udp-ip").autocomplete({ + $("#ip").autocomplete({ source: function (request, response) { if (!checkIsServerFiled('#serv')) return false; if (request.term == "") { request.term = 1 } $.ajax({ - url: "/app/server/show/ip/" + $("#serv").val(), + url: `/server/${$("#serv").val()}/ip`, + contentType: "application/json; charset=UTF-8", success: function (data) { - data = data.replace(/\s+/g, ' '); - response(data.split(" ")); + response(data); } }); }, @@ -30,8 +30,9 @@ $( function() { }); }); function getHAClusterVIPS(cluster_id) { + let vip_id = $('#vip'); $.ajax({ - url: `/app/ha/cluster/${cluster_id}/vips`, + url: api_prefix + `/ha/cluster/${cluster_id}/vips`, async: false, contentType: "application/json; charset=utf-8", success: function (data) { @@ -40,11 +41,11 @@ function getHAClusterVIPS(cluster_id) { return false; } else { clearUdpVip(); - $('#new-udp-vip').append('') + vip_id.append('') data.forEach(function (obj) { - $('#new-udp-vip').append('') + vip_id.append('') }); - $('#new-udp-vip').selectmenu("refresh"); + vip_id.selectmenu("refresh"); } } }); @@ -67,35 +68,39 @@ function createUDPListener(edited=false, listener_id=0, clean=true) { $('.new-udp-servers-tr').show(); } $.ajax({ - url: `/app/udp/listener/${listener_id}/settings`, + url: `${api_prefix}/udp/listener/${listener_id}`, type: "GET", async: false, contentType: "application/json; charset=utf-8", success: function (data) { - $('#new-listener-name').val(data.name.replaceAll("'", "")); + $('#name').val(data.name.replaceAll("'", "")); $('#new-listener-type').val(place); - $('#new-listener-port').val(data.port); - $('#new-listener-desc').val(data.desc.replaceAll("'", "")); + $('#port').val(data.port); + $('#lb_algo').val(data.lb_algo).change(); + $('#lb_algo').selectmenu('refresh'); + $('#desc').val(data.description.replaceAll("'", "")); if (place === 'cluster') { $.when(getHAClusterVIPS(data.cluster_id)).done(function () { - $("#new-udp-vip option").filter(function () { + $("#vip option").filter(function () { return $(this).text() == data.vip; }).attr('selected', true); - $("#new-udp-vip").selectmenu('refresh'); + $("#vip").selectmenu('refresh'); }); - $("#ha-cluster").val(data.cluster_id).change(); - $("#ha-cluster").attr('disabled', 'disabled'); - $("#ha-cluster").selectmenu('refresh'); + $("#cluster_id").val(data.cluster_id).change(); + $("#cluster_id").attr('disabled', 'disabled'); + $("#cluster_id").selectmenu('refresh'); } else { $("#serv").val(data.server_id).change(); $("#serv").attr('disabled', 'disabled'); $("#serv").selectmenu('refresh'); - $('#new-udp-ip').val(data.vip); + $('#ip').val(data.vip); } $('#new-udp-servers-td').empty(); $('#new-udp-servers-td').append(''); - for(let server in data.config) { - createBackendServer(server, data.config[server]['port'], data.config[server]['weight']); + data.config = JSON.stringify(data.config); + let config = JSON.parse(data.config) + for(let server of config) { + createBackendServer(server.backend_ip, server.port, server.weight); } } }); @@ -206,20 +211,20 @@ function createUDPListenerStep2(edited, listener_id, place) { dialog_div.dialog('open'); } function validateUDPListenerForm(place) { - if ($('#new-listener-name').val() == '') { + if ($('#name').val() == '') { toastr.error('error: Fill in the Name field'); return false; } - if ($('#new-listener-port').val() == '') { + if ($('#port').val() == '') { toastr.error('error: Fill in the Port field'); return false; } if (place == 'server') { - if ($('#new-udp-ip').val() == '') { + if ($('#ip').val() == '') { toastr.error('error: Fill in the IP field'); return false; } - if (!ValidateIPaddress($('#new-udp-ip').val())) { + if (!ValidateIPaddress($('#ip').val())) { toastr.error('error: Wrong IP'); return false; } @@ -228,7 +233,7 @@ function validateUDPListenerForm(place) { return false; } } else { - if ($('#ha-cluster option:selected').val().indexOf('--') != '-1') { + if ($('#cluster_id option:selected').val().indexOf('--') != '-1') { toastr.error('error: Select a HA cluster'); return false; } @@ -240,11 +245,11 @@ function validateUDPListenerForm(place) { toastr.error('error: Fill in the Weight field'); return false; } - if ($('#new-udp-vip option:selected').val().indexOf('--') != '-1') { + if ($('#vip option:selected').val().indexOf('--') != '-1') { toastr.error('error: Select the VIP address'); return false; } - if (!ValidateIPaddress($('#new-udp-vip option:selected').text())) { + if (!ValidateIPaddress($('#vip option:selected').text())) { toastr.error('error: Wrong VIP'); return false; } @@ -256,35 +261,52 @@ function getFormData($form) { $("#serv").selectmenu('refresh'); let unindexed_array = $form.serializeArray(); let indexed_array = {}; - indexed_array['servers'] = {}; + indexed_array['config'] = []; $.map(unindexed_array, function (n, i) { - indexed_array[n['name']] = n['value']; + if (n['name'] === 'serv') { + indexed_array['server_id'] = n['value']; + } else { + indexed_array[n['name']] = n['value']; + } }); + $('.servers').each(function () { - let ip = $(this).children("input[name='new-udp-server']").val(); - if (ip === undefined || ip === '') { + let backend_ip = $(this).children("input[name='new-udp-server']").val(); + if (backend_ip === undefined || backend_ip === '') { return; } let port = $(this).children("input[name='new-udp-port']").val(); let weight = $(this).children("input[name='new-udp-weight']").val(); - indexed_array['servers'][ip] = {port, weight}; + indexed_array['config'].push({backend_ip, port, weight}); }); - indexed_array['ha-cluster'] = $('#ha-cluster').val(); - indexed_array['new-udp-router_id'] = $('#new-udp-vip').val(); - indexed_array['new-udp-vip'] = $('#new-udp-vip option:selected').text(); + if ($('#cluster_id').val()) { + indexed_array['cluster_id'] = $('#cluster_id').val(); + } else { + indexed_array['cluster_id'] = null; + } + if ($('#new-listener-type').val() === 'cluster') { + indexed_array['router_id'] = $('#vip').val(); + indexed_array['vip'] = $('#vip option:selected').text(); + } else { + indexed_array['vip'] = $('#ip').val(); + } $("#serv").attr('disabled', 'disabled'); $("#serv").selectmenu('refresh'); return indexed_array; } function saveUdpListener(jsonData, dialog_id, listener_id=0, edited=0, reconfigure=0) { let req_method = 'POST'; + let url = api_prefix + "/udp/listener"; + if (reconfigure) { + jsonData['reconfigure'] = 1; + } if (edited) { req_method = 'PUT'; - jsonData['listener_id'] = listener_id; + url = api_prefix + "/udp/listener/" + listener_id; } $.ajax({ - url: "/app/udp/listener", + url: url, type: req_method, data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", @@ -299,18 +321,18 @@ function saveUdpListener(jsonData, dialog_id, listener_id=0, edited=0, reconfigu $("#listener-" + listener_id).removeClass("update"); }, 2500); } else { - listener_id = data.listener_id; - getUDPListener(data.listener_id, true); + listener_id = data.id; + getUDPListener(listener_id, true); } - if (reconfigure) { - NProgress.start(); - $.when(Reconfigure(listener_id)).done(function () { - dialog_id.dialog("close"); - NProgress.done(); - }); - } else { + // if (reconfigure) { + // NProgress.start(); + // $.when(Reconfigure(listener_id)).done(function () { + // dialog_id.dialog("close"); + // NProgress.done(); + // }); + // } else { dialog_id.dialog("close"); - } + // } toastr.success('Listener ' + data.status); } } @@ -318,7 +340,7 @@ function saveUdpListener(jsonData, dialog_id, listener_id=0, edited=0, reconfigu } function Reconfigure(listener_id) { return $.ajax({ - url: "/app/install/udp", + url: "/install/udp", data: JSON.stringify({listener_id: listener_id}), contentType: "application/json; charset=utf-8", async: false, @@ -334,7 +356,7 @@ function Reconfigure(listener_id) { } function getUDPListener(listener_id, new_listener=false) { $.ajax({ - url: "/app/udp/listener/" + listener_id, + url: "/udp/listener/" + listener_id, success: function (data) { data = data.replace(/^\s+|\s+$/g, ''); if (data.indexOf('error:') != '-1') { @@ -373,17 +395,23 @@ function confirmDeleteListener(listener_id) { }); } function deleteListener(listener_id) { - let jsonData = {'listener_id': listener_id} $.ajax({ - url: "/app/udp/listener", + url: api_prefix + "/udp/listener/" + listener_id, type: "DELETE", - data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", - success: function (data) { - if (data.status === 'failed') { - toastr.error(data.error); - } else { + statusCode: { + 204: function (xhr) { $('#listener-' + listener_id).remove(); + }, + 404: function (xhr) { + $('#listener-' + listener_id).remove(); + } + }, + success: function (data) { + if (data) { + if (data.status === "failed") { + toastr.error(data.error); + } } } }); @@ -391,17 +419,16 @@ function deleteListener(listener_id) { function clearListenerDialog(edited=0) { $('#new-listener-name').val(''); $('#new-listener-desc').val(''); - $('#ha-cluster-master-interface').val(''); $('#new-udp-ip').val(''); $('#vrrp-ip').prop("readonly", false); $('#new-listener-port').val(''); - $("#ha-cluster").attr('disabled', false); + $("#cluster_id").attr('disabled', false); $("#serv").attr('disabled', false); clearUdpVip() $('#new-udp-servers-td').empty(); $('#new-udp-servers-td').append(''); createBackendServer(); - let selects = ['new-udp-type', 'ha-cluster', 'new-udp-vip', 'serv'] + let selects = ['new-udp-type', 'cluster_id', 'vip', 'serv'] for (let select of selects) { unselectSelectMenu(select); } @@ -412,9 +439,9 @@ function unselectSelectMenu(select_id) { $('#' + select_id).selectmenu("refresh"); } function clearUdpVip() { - $('#new-udp-vip').selectmenu( "destroy" ); - $('#new-udp-vip').empty(); - $('#new-udp-vip').selectmenu(); + $('#vip').selectmenu( "destroy" ); + $('#vip').empty(); + $('#vip').selectmenu(); } function confirmUdpBalancerAction(action, listener_id) { let action_word = translate_div.attr('data-'+action); @@ -441,7 +468,7 @@ function confirmUdpBalancerAction(action, listener_id) { } function ajaxActionListener(action, listener_id) { $.ajax({ - url: `/app/udp/listener/${listener_id}/${action}`, + url: `${api_prefix}/udp/listener/${listener_id}/${action}`, type: "GET", contentType: "application/json; charset=utf-8", success: function (data) { @@ -470,18 +497,29 @@ function createBackendServer(server='', port='', weight='1') { $.getScript(awesome); } function checkStatus(listener_id) { - if (sessionStorage.getItem('check-service-udp') == 0) { + if (sessionStorage.getItem('check-service-udp-'+listener_id) == 0) { return false; } NProgress.configure({showSpinner: false}); let listener_div = $('#listener-' + listener_id); $.ajax({ - url: "/app/udp/listener/" + listener_id + "/check", + url: api_prefix + "/udp/listener/" + listener_id, contentType: "application/json; charset=utf-8", + statusCode: { + 404: function (xhr) { + $('#listener-' + listener_id).remove(); + }, + 403: function (xhr) { + sessionStorage.setItem('check-service-udp-'+listener_id, 0); + }, + 500: function (xhr) { + sessionStorage.setItem('check-service-udp-'+listener_id, 0); + } + }, success: function (data) { try { if (data.indexOf('logout') != '-1') { - sessionStorage.setItem('check-service-udp', 0); + sessionStorage.setItem('check-service-udp-'+listener_id, 0); } } catch (e) {} @@ -501,6 +539,14 @@ function checkStatus(listener_id) { listener_div.removeClass('div-server-head-down'); listener_div.attr('title', 'Not all services are UP'); } + $(`#listener-name-${listener_id}`).text(data.name.replaceAll("'", "")); + if (data.description === '') { + $(`#listener-desc-${listener_id}`).text(''); + } else { + $(`#listener-desc-${listener_id}`).text(`(${data.description.replaceAll("'", "")})`); + } + $(`#port-${listener_id}`).text(data.port); + $(`#vip-${listener_id}`).text(data.vip); } }); NProgress.configure({showSpinner: true}); diff --git a/app/static/js/variables.js b/app/static/js/variables.js index 3ff5b9a7..ce3903c8 100644 --- a/app/static/js/variables.js +++ b/app/static/js/variables.js @@ -13,9 +13,16 @@ const delete_word = translate_div.attr('data-delete'); const back_word = translate_div.attr('data-back'); // JS scripts URL -const scriptPath = "/app/static/js" +const scriptPath = "/static/js" const script = `${scriptPath}/script.js`; const overview = `${scriptPath}/overview.js`; const configShow = `${scriptPath}/configshow.js`; const awesome = `${scriptPath}/fontawesome.min.js`; const ha = `${scriptPath}/ha.js`; +const waf = `${scriptPath}/waf.js` + +// csrf_token +const csrf_token = Cookies.get('csrf_access_token'); + +// API prefix +const api_prefix = '/api' diff --git a/app/static/js/waf.js b/app/static/js/waf.js index 046d3e68..d20649bd 100644 --- a/app/static/js/waf.js +++ b/app/static/js/waf.js @@ -1,27 +1,26 @@ -var waf = "/app/static/js/waf.js" -function showOverviewWaf(serv, hostnamea) { - let service = cur_url[1]; +function showOverviewWaf(serv, hostname) { + let service = cur_url[0]; if (service == 'haproxy') { - $.getScript('/app/static/js/chart.min-4.3.0.js'); + $.getScript('/static/js/chart.min-4.3.0.js'); showWafMetrics(); } let i; for (i = 0; i < serv.length; i++) { - showOverviewWafCallBack(serv[i], hostnamea[i]) + showOverviewWafCallBack(serv[i], hostname[i]) } $.getScript(overview); $.getScript(waf); } -function showOverviewWafCallBack(serv, hostnamea) { - let service = cur_url[1]; +function showOverviewWafCallBack(serv, hostname) { + let service = cur_url[0]; $.ajax({ - url: "/app/waf/overview/" + service + "/" + serv, + url: "/waf/overview/" + service + "/" + serv, beforeSend: function () { - $("#" + hostnamea).html(''); + $("#" + hostname).html(''); }, success: function (data) { - $("#" + hostnamea).empty(); - $("#" + hostnamea).html(data) + $("#" + hostname).empty(); + $("#" + hostname).html(data) $("input[type=submit], button").button(); $("input[type=checkbox]").checkboxradio(); $.getScript(overview); @@ -36,7 +35,7 @@ function metrics_waf(name) { } name = name.split('metrics')[1] $.ajax({ - url: "/app/waf/metric/enable/" + enable + "/" + name, + url: "/waf/metric/enable/" + enable + "/" + name, contentType: "application/json; charset=utf-8", success: function (data) { if (data.status === 'failed') { @@ -53,9 +52,9 @@ function metrics_waf(name) { function installWaf(ip1) { $("#ajax").html(''); $("#ajax").html(wait_mess); - let service = cur_url[1]; + let service = cur_url[0]; $.ajax({ - url: "/app/install/waf/" + service + "/" + ip1, + url: "/install/waf/" + service + "/" + ip1, type: "POST", contentType: "application/json; charset=utf-8", success: function (data) { @@ -73,9 +72,9 @@ function installWaf(ip1) { function changeWafMode(id) { let waf_mode = $('#' + id + ' option:selected').val(); let server_hostname = id.split('_')[0]; - let service = cur_url[1]; + let service = cur_url[0]; $.ajax({ - url: "/app/waf/" + service + "/mode/" + server_hostname + "/" + waf_mode, + url: "/waf/" + service + "/mode/" + server_hostname + "/" + waf_mode, contentType: "application/json; charset=utf-8", success: function (data) { if (data.status === 'failed') { @@ -103,7 +102,7 @@ function waf_rules_en(id) { } let serv = cur_url[2]; $.ajax({ - url: "/app/waf/" + serv + "/rule/" + id + "/" + enable, + url: "/waf/" + serv + "/rule/" + id + "/" + enable, contentType: "application/json; charset=utf-8", success: function (data) { if (data.status === 'failed') { @@ -147,7 +146,7 @@ function addNewConfig() { let new_rule_name = new_rule_name_id.val(); let new_rule_description = new_rule_description_id.val(); let new_rule_file = new_rule_name.replaceAll(' ', '_'); - let service = cur_url[1]; + let service = cur_url[0]; let serv = cur_url[2]; service = escapeHtml(service); new_rule_name = escapeHtml(new_rule_name); @@ -160,7 +159,7 @@ function addNewConfig() { "new_rule_file": new_rule_file } $.ajax({ - url: "/app/waf/" + service + "/" + serv + "/rule/create", + url: "/waf/" + service + "/" + serv + "/rule/create", data: JSON.stringify(jsonData), contentType: "application/json; charset=utf-8", type: "POST", @@ -168,7 +167,7 @@ function addNewConfig() { if (data.status === 'failed') { toastr.error(data.error); } else { - window.location.replace("/app/waf/" + service + "/" + serv + "/rule/" + data.id); + window.location.replace("/waf/" + service + "/" + serv + "/rule/" + data.id); } } }); diff --git a/app/templates/add.html b/app/templates/add.html index d12c7a4b..1c45732a 100644 --- a/app/templates/add.html +++ b/app/templates/add.html @@ -20,7 +20,7 @@ {% set header_params = {'add-header': 'add-header', 'set-header': 'set-header', 'del-header': 'del-header'} %} {% set if_values = {'1':'Host name starts with','2':'Host name ends with','3':'Path starts with','4':'Path ends with', '6': 'Src ip'} %} - +
    • {{lang.words.create|title()}} {{lang.words.proxy}}
    • @@ -38,7 +38,7 @@
        {% include 'include/add_proxy.html' %}
        -
        + @@ -301,7 +301,7 @@
        - +

        {{lang.words.add|title()}} {{lang.words.listener}}

        @@ -492,7 +492,7 @@
        - +

        {{lang.words.add|title()}} {{lang.words.frontend}}

        @@ -873,7 +873,7 @@
        - +

        {{lang.words.add|title()}} {{lang.words.backend}}

        @@ -956,7 +956,7 @@
        - +

        {{lang.words.add|title()}} {{lang.words.userlists}}

        diff --git a/app/templates/add_nginx.html b/app/templates/add_nginx.html index b7bf0f2d..dae944a1 100644 --- a/app/templates/add_nginx.html +++ b/app/templates/add_nginx.html @@ -5,7 +5,7 @@ {% from 'include/input_macros.html' import input, checkbox, select %} {% set balance_params = dict() %} {% set balance_params = {'ip_hash':'ip_hash','least_conn':'least_conn','random':'random', 'round_robin': 'round-robin'} %} - +

        {{lang.words.add|title()}} Peer

        diff --git a/app/templates/ajax/alerts_history.html b/app/templates/ajax/alerts_history.html index 7d72df2b..88d0e5e0 100644 --- a/app/templates/ajax/alerts_history.html +++ b/app/templates/ajax/alerts_history.html @@ -1,5 +1,5 @@ - + {% if action == "checker" %} {% set column_for_sort = 3 %} {% else %} @@ -55,9 +55,9 @@ {% if action != "checker" %} diff --git a/app/templates/ajax/channels.html b/app/templates/ajax/channels.html index 66b0e06b..9588ea21 100644 --- a/app/templates/ajax/channels.html +++ b/app/templates/ajax/channels.html @@ -32,7 +32,7 @@ {% for group in groups %} - {% if slack.groups|string() == group.group_id|string() %} + {% if slack.group_id|string() == group.group_id|string() %} {% else %} @@ -136,7 +136,7 @@ {% for group in groups %} - {% if mm.groups|string() == group.group_id|string() %} + {% if mm.group_id|string() == group.group_id|string() %} {% else %} diff --git a/app/templates/ajax/check_version.html b/app/templates/ajax/check_version.html index b93deea2..70edffa9 100644 --- a/app/templates/ajax/check_version.html +++ b/app/templates/ajax/check_version.html @@ -8,11 +8,11 @@ {%- if new_ver_without_dots > current_ver_without_dots and new_ver != "Sorry cannot get current version" %} v{{current_ver}} - + {%- else %} - v{{current_ver}} + v{{current_ver}} {%- endif %} {%- else %} - v{{current_ver}} + v{{current_ver}} {% endif -%} diff --git a/app/templates/ajax/config_show.html b/app/templates/ajax/config_show.html index 807db6c3..b152585f 100644 --- a/app/templates/ajax/config_show.html +++ b/app/templates/ajax/config_show.html @@ -5,12 +5,12 @@ {% if role <= 3 %} {% if not is_serv_protected or role <= 2 %} {% if not configver %} - {{lang.words.edit|title()}} + {{lang.words.edit|title()}} {% endif %} {% if service == 'haproxy' %} - {{lang.words.add|title()}} + {{lang.words.add|title()}} {% elif service == 'keepalived' %} - {{lang.words.add|title()}} + {{lang.words.add|title()}} {% endif %} {% endif %} {% endif %} @@ -211,7 +211,7 @@ {% if role %} {% if service != 'keepalived' %} - {{lang.words.edit|title()}} + {{lang.words.edit|title()}} {% endif %} {% endif %} @@ -222,7 +222,7 @@ {{ line }} {% if role %} - {{lang.words.edit|title()}} + {{lang.words.edit|title()}} {% endif %}
        @@ -232,12 +232,12 @@
        {{- line -}} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %} {%- set backend = line.split(' ') -%} - {{lang.words.stats|title()}} + {{lang.words.stats|title()}} {%- set backend = backend|join('_') -%} {%- do section_name.update({i: backend}) -%} @@ -249,12 +249,12 @@ {{ line }} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %} {% set backend = line.split(' ') %} - {{lang.words.stats|title()}} + {{lang.words.stats|title()}} {% set backend = backend|join('_') %} {% do section_name.update({i: backend}) %} @@ -266,12 +266,12 @@ {{ line }} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %} {% set backend = line.split(' ') %} - {{lang.words.stats|title()}} + {{lang.words.stats|title()}}
        {% continue %} @@ -280,7 +280,7 @@
        {{ line }} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %}
        @@ -290,7 +290,7 @@
        {{ line }} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %}
        @@ -300,7 +300,7 @@
        {{ line }} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %}
        @@ -310,7 +310,7 @@
        {{ line }} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %}
        @@ -320,7 +320,7 @@
        {{ line }} {% if role %} - {{lang.words.edit|title()}}/{{lang.words.delete|title()}} + {{lang.words.edit|title()}}/{{lang.words.delete|title()}} {% endif %}
        @@ -368,7 +368,7 @@
        {% if role <= 3 %} {% if not is_serv_protected or role <= 2 %} - + diff --git a/app/templates/ajax/ha/clusters.html b/app/templates/ajax/ha/clusters.html index c0daff2c..ae58c4fc 100644 --- a/app/templates/ajax/ha/clusters.html +++ b/app/templates/ajax/ha/clusters.html @@ -3,9 +3,9 @@ {% for cluster in clusters %}
        - + {{cluster.name}} - {% if cluster.desc != '' %} ({{cluster.desc|replace("'", "")}}) {% endif %} + {% if cluster.desc != '' %} ({{cluster.description|replace("'", "")}}) {% endif %} {% if g.user_params['role'] <= 3 %} @@ -59,7 +59,7 @@ {% if c_s.cluster_id|string() == cluster.id|string() %} {% for service in services %} {% if c_s.service_id|string() == service.service_id|string() %} - {{service.service}} + {{service.service}} {% endif %} {% endfor %} {% endif %} diff --git a/app/templates/ajax/haproxyservers_backends.html b/app/templates/ajax/haproxyservers_backends.html deleted file mode 100644 index 31c4fdbc..00000000 --- a/app/templates/ajax/haproxyservers_backends.html +++ /dev/null @@ -1,29 +0,0 @@ -{% import 'languages/'+lang|default('en')+'.html' as lang %} -{% from 'languages/languages.html' import languages %} - -{% if backends == 'Cannot get backends' %} - {{backends}} -{% else %} - {% if service == 'nginx' or service == 'apache' %} - {% set backends = backends.split('\n') %} - {% endif %} - {% for b in backends %} - {% if service == 'haproxy' %} - - {{b}} - - {% elif service == 'nginx' or service == 'apache' %} - {% set full_file = b.split(' ')[0] | replace ('/', '92') %} - {% set full_file = full_file.replace(':', '') %} - - {{b.split(' ')[1] | replace(';', '')}} - - {% else %} - {{b}} - {% endif %} - {% endfor %} -{% endif %} diff --git a/app/templates/ajax/list.html b/app/templates/ajax/list.html index 73959e1c..e0ddd88f 100644 --- a/app/templates/ajax/list.html +++ b/app/templates/ajax/list.html @@ -1,7 +1,7 @@ {% from 'include/input_macros.html' import input, checkbox, copy_to_clipboard %} {% include 'include/main_menu.html' %}

        {% block h2 %}{% endblock %} {% include 'include/login.html' %} - {% if autorefresh %} - - - - - - {{lang.words.auto|title()}}-{{lang.words.refresh}} - - - - {% endif %}

        - {% if autorefresh %} - {% include 'include/autorefresh_submenu.html' %} - {% endif %}
          {% if g.user_params['role'] %} {% if g.user_params['role'] <= 2 %} @@ -81,11 +66,11 @@
          - +{# #}
          -
          +

          {{lang.words.add|title()}} upstream

          {% if action == 'smon' %} - {{t.2|replace("'","")}} + {{t.2|replace("'","")}} {% else %} - {{t.2|replace("'","")}} + {{t.2|replace("'","")}} {% endif %}
          diff --git a/app/templates/channel.html b/app/templates/channel.html index 6fbf1c26..d55e1ecd 100644 --- a/app/templates/channel.html +++ b/app/templates/channel.html @@ -4,7 +4,7 @@ {% block content %} {% from 'include/input_macros.html' import input, select, copy_to_clipboard, checkbox %} - +
          - + +
          - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + {% if is_serv_protected and g.user_params['role'] > 2 %} - + {% else %} {% if g.user_params['servers']|length == 0 %} {% include 'include/getstarted.html' %} @@ -51,7 +51,7 @@ {{lang.menu_links.versions.link}} {% endif %} {% if g.user_params['role'] <= 2 %} - Git + Git {% endif %}

          @@ -65,17 +65,16 @@ {% if config %} {% if g.user_params['role'] <= 3 %}

          {{lang.words.config|title()}} {% if config_file_name and config_file_name != 'undefined' %}{{config_file_name.replace('92', '/')}}{%endif%} {{lang.words.from}} {{ serv }}

          - - - - + +{# #} + - +

          - {{lang.words.back|title()}} + {{lang.words.back|title()}} {% if is_restart|int == 0 %} @@ -90,32 +89,31 @@ {% endif %} {% endif %} +

          {{ select('serv', values=g.user_params['servers'], is_servers='true', selected=serv) }} {{lang.words.open|title()}} - {{lang.words.configs|title()}} + {{lang.words.configs|title()}} {% if service != 'keepalived' %} {{lang.words.stats|title()}} {% endif %} diff --git a/app/templates/ha_cluster.html b/app/templates/ha_cluster.html index de83ca29..43fe680c 100644 --- a/app/templates/ha_cluster.html +++ b/app/templates/ha_cluster.html @@ -3,8 +3,8 @@ {% block h2 %}{{ lang.ha_page.has }} {% endblock %} {% block content %} {% from 'include/input_macros.html' import input, checkbox, copy_to_clipboard %} - - + + @@ -98,7 +98,7 @@ {{lang.words.stay|title()}} {{lang.words.as}} {{lang.words.master|title()}}

          @@ -168,7 +168,7 @@ {{lang.words.stay|title()}} {{lang.words.as}} {{lang.words.master|title()}} diff --git a/app/templates/history.html b/app/templates/history.html index 142ae50b..f4c9c0dc 100644 --- a/app/templates/history.html +++ b/app/templates/history.html @@ -7,13 +7,13 @@ {% include 'include/no_sub.html' %} {% else %} - - - - - - - + + + + + + + {% endif %} - +{##} diff --git a/app/templates/include/admin_settings.html b/app/templates/include/admin_settings.html index 8ab3af96..c996c760 100644 --- a/app/templates/include/admin_settings.html +++ b/app/templates/include/admin_settings.html @@ -14,7 +14,7 @@ 'smon': 'SMON', } %} - +
          {{lang.words.alerts|title()}}
          - {{ checkbox('return_to_master', title=lang.ha_page.return_master) }} + {{ checkbox('return_master', title=lang.ha_page.return_master) }}
          - {{ checkbox('vrrp-ip-add-return_to_master', title=lang.ha_page.return_master) }} + {{ checkbox('vrrp-ip-add-return_master', title=lang.ha_page.return_master) }}
          {% set section = namespace(section='') %} diff --git a/app/templates/include/admin_ssh.html b/app/templates/include/admin_ssh.html index 4095b55b..2e7d3cd7 100644 --- a/app/templates/include/admin_ssh.html +++ b/app/templates/include/admin_ssh.html @@ -23,7 +23,7 @@ {{ input(id, value=ssh.name, size='15') }} diff --git a/app/templates/include/admin_users.html b/app/templates/include/admin_users.html index d9ca4932..3255efd1 100644 --- a/app/templates/include/admin_users.html +++ b/app/templates/include/admin_users.html @@ -23,7 +23,7 @@ {% set disable_superAdmin = {'disabled': ''} %} {% if g.user_params['role'] == 2 %} {% for user_role in users_roles %} - {% if user_role.user_role_id == 1 and user.user_id == user_role.user_id %} + {% if user_role.user_role_id|string() == '1' and user.user_id|string() == user_role.user_id|string() %} {% if disable_superAdmin.update({'disabled': 'disabled'}) %} {% endif %} {% endif %} {% endfor %} @@ -45,7 +45,7 @@
          - {% if ssh.enable == 1 %} + {% if ssh.key_enabled == 1 %} {% else %} @@ -33,7 +33,7 @@ {% else %} @@ -76,7 +76,7 @@ {% set activeuser_id = 'activeuser-' + user.user_id|string() %} - {% if user.activeuser == 1 %} + {% if user.enabled == 1 %} {{ checkbox(activeuser_id, checked='checked', disabled=disable_superAdmin['disabled']) }} {% else %} {{ checkbox(activeuser_id, disabled=disable_superAdmin['disabled']) }} @@ -83,7 +83,7 @@ - + diff --git a/app/templates/include/admins_dialogs.html b/app/templates/include/admins_dialogs.html index e41b0c7e..fc4f6225 100644 --- a/app/templates/include/admins_dialogs.html +++ b/app/templates/include/admins_dialogs.html @@ -310,7 +310,7 @@ {% for ssh in sshs %} - {% if ssh.enable == 1 %} + {% if ssh.key_enabled == 1 %} {% endif %} {% endfor %} @@ -440,4 +440,13 @@
          -
          + diff --git a/app/templates/include/autorefresh_submenu.html b/app/templates/include/autorefresh_submenu.html deleted file mode 100644 index 4546fe5d..00000000 --- a/app/templates/include/autorefresh_submenu.html +++ /dev/null @@ -1,38 +0,0 @@ - diff --git a/app/templates/include/getstarted.html b/app/templates/include/getstarted.html index 87f83543..3d8d9fb5 100644 --- a/app/templates/include/getstarted.html +++ b/app/templates/include/getstarted.html @@ -7,11 +7,7 @@ You don't have servers yet. Read how to add an existing server or create a new one - {% if role == 2 %} - and go to the "Servers" - {% elif role == 1 %} - and go to the "Admin area" - {% endif %} + and go to the "Servers" to add your first server diff --git a/app/templates/include/login.html b/app/templates/include/login.html index 1ff90532..6dfa63b5 100644 --- a/app/templates/include/login.html +++ b/app/templates/include/login.html @@ -1,25 +1,11 @@ {% if g.user_params['user'] %} - + {% else %} - + {% endif %} -{% if guide_me %} - - -{% endif %} - + top: 8px; + font-size: 17px; +"> diff --git a/app/templates/include/main_head.html b/app/templates/include/main_head.html index 1d3dac81..2369696c 100644 --- a/app/templates/include/main_head.html +++ b/app/templates/include/main_head.html @@ -22,28 +22,29 @@ - - + + - - - - + + + + - + - - - - - + + + + + - - - - + + + + + - + diff --git a/app/templates/include/main_menu.html b/app/templates/include/main_menu.html index 463e4117..d8a01cf4 100644 --- a/app/templates/include/main_menu.html +++ b/app/templates/include/main_menu.html @@ -2,7 +2,7 @@ @@ -13,42 +13,48 @@ {% if '5' in g.user_params['user_services'] %} {% if g.user_params['role'] <= 3 %} {% endif %} -
        • HA {{lang.words.cluster}}
        • +
        • HA {{lang.words.cluster}}
        • {% endif %} {% if '1' in g.user_params['user_services'] %}
        • - HAProxy + + + HAProxy +
        • {% endif %} {% if '2' in g.user_params['user_services'] %}
        • - NGINX + + + NGINX +
        • @@ -57,21 +63,21 @@
        • Apache
        • {% endif %} {% if '6' in g.user_params['user_services'] %} {% if g.user_params['role'] <= 2 %} -
        • {{lang.menu_links.udp.title}}
        • +
        • {{lang.menu_links.udp.title}}
        • {% endif %} {% endif %} {% if '3' in g.user_params['user_services'] %} @@ -79,10 +85,10 @@
        • Keepalived
        • {% endif %} @@ -90,26 +96,26 @@
        • {{lang.menu_links.monitoring.link}}
        • {% if g.user_params['role'] <= 2 %}
        • {{lang.words.installation|title()}}
        • {% endif %} @@ -118,15 +124,15 @@ {{lang.menu_links.admin_area.link}} diff --git a/app/templates/include/no_sub.html b/app/templates/include/no_sub.html index fd94cd37..25a75d51 100644 --- a/app/templates/include/no_sub.html +++ b/app/templates/include/no_sub.html @@ -18,5 +18,5 @@
          - Oops + Oops
          diff --git a/app/templates/include/port_scan_history.html b/app/templates/include/port_scan_history.html index 687ed7be..f1edded8 100644 --- a/app/templates/include/port_scan_history.html +++ b/app/templates/include/port_scan_history.html @@ -3,7 +3,7 @@ {% block h2 %}{{ lang.p_s_page.p_s_title_history }}{% endblock %} {% block content %} - + +
          -
          +
          - +
          {{ input('login', class='form-login', placeholder=lang.words.login|title(), required='required', autofocus='autofocus') }} @@ -81,13 +64,14 @@ body, .container {
          +
          {% if error_log or error %} -