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.
master
Aidaho 2025-06-08 12:55:43 +03:00
parent 44ddae6dd1
commit f749f7366e
4 changed files with 43 additions and 54 deletions

View File

@ -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')

View File

@ -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:

View File

@ -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'

View File

@ -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 = '';