From f749f7366e4578a0f82586568c622ab552e3380f Mon Sep 17 00:00:00 2001 From: Aidaho Date: Sun, 8 Jun 2025 12:55:43 +0300 Subject: [PATCH] v8.2.1: Refactor JS and Python models, remove unused functions, and improve form validation Updated JavaScript to refine option selection logic and remove redundant functions (`showCompare`, `showCompareConfigs`). Enhanced Python models with validators to enforce non-empty inputs for critical fields (`port`, `maxconn`, etc.). Optimized configuration diff logic for better performance and readability. Added file lock checks before database migrations. --- app/__init__.py | 8 ++++-- app/modules/config/config.py | 14 +++------- app/modules/roxywi/class_models.py | 30 ++++++++++++++++++++ app/static/js/script.js | 45 +++--------------------------- 4 files changed, 43 insertions(+), 54 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 930a9a86..a1aafd71 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -5,6 +5,7 @@ from flask_apscheduler import APScheduler from app.modules.common.common import set_correct_owner from app.modules.roxywi import logger +from app.modules.common.lock_utils import acquire_file_lock app = Flask(__name__) app.config.from_object('app.config.Configuration') @@ -33,9 +34,10 @@ from app.modules.db.db_model import create_tables from app.create_db import default_values from app.modules.db.migration_manager import migrate -create_tables() -default_values() -migrate() +if not acquire_file_lock(): + create_tables() + default_values() + migrate() set_correct_owner('/var/lib/roxy-wi') diff --git a/app/modules/config/config.py b/app/modules/config/config.py index ec5ad49a..654fb440 100644 --- a/app/modules/config/config.py +++ b/app/modules/config/config.py @@ -359,13 +359,10 @@ def diff_config(old_cfg, cfg) -> str: :param cfg: Path to the new configuration file to compare. :return: Unified diff output showing the differences between `old_cfg` and `cfg`. """ - diff = "" cmd = f"/bin/diff -ub {old_cfg} {cfg}" output, stderr = server_mod.subprocess_execute(cmd) - - for line in output: - diff += line + "\n" - return diff + output = '\n'.join(output) + return output def _classify_line(line: str) -> str: @@ -429,12 +426,9 @@ def compare_config(service: str, left: str, right: str) -> str: :param right: The name of the right configuration file. :return: The rendered template with the diff output and the user language for Flask. """ - lang = roxywi_common.get_user_lang_for_flask() config_dir = config_common.get_config_dir(service) - cmd = f'diff -pub {config_dir}{left} {config_dir}{right}' - output, stderr = server_mod.subprocess_execute(cmd) - - return render_template('ajax/compare.html', stdout=output, lang=lang) + output = diff_config(f'{config_dir}{left}', f'{config_dir}{right}') + return output def show_config(server_ip: str, service: str, config_file_name: str, configver: str, claims: dict, edit_section: str) -> str: diff --git a/app/modules/roxywi/class_models.py b/app/modules/roxywi/class_models.py index a55b8281..06b19f97 100644 --- a/app/modules/roxywi/class_models.py +++ b/app/modules/roxywi/class_models.py @@ -388,6 +388,20 @@ class HaproxyBackendServer(BaseModel): send_proxy: Optional[bool] = 0 backup: Optional[bool] = 0 + @model_validator(mode='before') + @classmethod + def int_cannot_be_empty(cls, values): + if 'port' in values: + if values['port'] == '': + raise ValueError('Port cannot be empty') + if 'port_check' in values: + if values['port_check'] == '': + raise ValueError('Port check cannot be empty') + if 'maxconn' in values: + if values['maxconn'] == '': + raise ValueError('Maxconn cannot be empty') + return values + class HaproxyCookie(BaseModel): dynamic: str @@ -559,6 +573,21 @@ class NginxBackendServer(BaseModel): fail_timeout: int + @model_validator(mode='before') + @classmethod + def int_cannot_be_empty(cls, values): + if 'port' in values: + if values['port'] == '': + raise ValueError('Port cannot be empty') + if 'max_fails' in values: + if values['max_fails'] == '': + raise ValueError('max_fails cannot be empty') + if 'fail_timeout' in values: + if values['fail_timeout'] == '': + raise ValueError('fail_timeout cannot be empty') + return values + + class NginxUpstreamRequest(BaseModel): name: EscapedString balance: Optional[Literal['ip_hash', 'least_conn', 'random', 'round_robin']] @@ -619,6 +648,7 @@ class NginxLocationRequest(BaseModel): class NginxProxyPassRequest(BaseModel): locations: List[NginxLocationRequest] name: Union[IPvAnyAddress, DomainName] + name_aliases: List[Union[IPvAnyAddress, DomainName]] = None port: Annotated[int, Gt(1), Le(65535)] type: Literal['proxy_pass'] = 'proxy_pass' scheme: Literal['http', 'https'] = 'http' diff --git a/app/static/js/script.js b/app/static/js/script.js index b5685a16..d87c6026 100644 --- a/app/static/js/script.js +++ b/app/static/js/script.js @@ -98,15 +98,15 @@ function showStats() { }); } function openStats() { - let serv = $("#serv").val(); - let service_url = cur_url[4]; + let serv = $("#serv option:selected").val(); + let service_url = $('#service').val(); let url = "/stats/"+service_url+"/"+serv let win = window.open(url, '_blank'); win.focus(); } function openVersions() { - let serv = $("#serv").val(); - let service_url = cur_url[4]; + let serv = $("#serv option:selected").val(); + let service_url = $('#service').val(); let url = "/config/versions/"+service_url+"/"+serv let win = window.open(url,"_self"); win.focus(); @@ -230,43 +230,6 @@ function showMap() { } }); } -function showCompare() { - $.ajax({ - url: "/config/compare/" + $("#service").val() + "/" + $("#serv").val() + "/show", - data: { - left: $('#left').val(), - right: $("#right").val(), - }, - type: "POST", - success: function (data) { - if (data.indexOf('error:') != '-1') { - toastr.error(data); - } else { - toastr.clear(); - $("#ajax").html(data); - } - } - }); -} -function showCompareConfigs() { - clearAllAjaxFields(); - $('#ajax-config_file_name').empty(); - $.ajax({ - url: "/config/compare/" + $("#service").val() + "/" + $("#serv").val() + "/files", - type: "GET", - success: function (data) { - if (data.indexOf('error:') != '-1') { - toastr.error(data); - } else { - toastr.clear(); - $("#ajax-compare").html(data); - $("input[type=submit], button").button(); - $("select").selectmenu(); - window.history.pushState("Show compare config", "Show compare config", '/config/compare/' + $("#service").val() + '/' + $("#serv").val()); - } - } - }); -} function showConfig() { let edit_section = ''; let edit_section_uri = '';