Allow manual 3x-ui sync without prior save; persist form credentials.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
orohi
2026-07-26 00:25:56 +03:00
co-authored by Cursor
parent d1eb49cb83
commit 69886f130c
2 changed files with 54 additions and 12 deletions
+35 -5
View File
@@ -1422,10 +1422,14 @@ async def _xui_fetch_clients(client: httpx.AsyncClient, base_url: str, headers:
return []
async def sync_users_with_xui(data: dict):
"""Import / update panel users from an existing 3x-ui instance."""
async def sync_users_with_xui(data: dict, *, force: bool = False):
"""Import / update panel users from an existing 3x-ui instance.
force=True: used by the manual "Sync now" button (ignores xui_sync_users flag).
Background jobs keep force=False and only run when xui_sync_users is enabled.
"""
settings = data.get('settings', {}).get('sync', {})
if not settings.get('xui_sync_users'):
if not force and not settings.get('xui_sync_users'):
return 0, "3x-ui synchronization is disabled in settings"
url = (settings.get('xui_url') or '').strip()
@@ -4042,8 +4046,34 @@ async def api_xui_sync_now(request: Request):
if not _check_admin(request):
return JSONResponse({'error': 'Forbidden'}, status_code=403)
data = load_data()
count, msg = await sync_users_with_xui(data)
return {'status': 'success', 'count': count, 'message': msg}
# Allow syncing with credentials from the request body (form may not be saved yet)
try:
body = await request.json()
except Exception:
body = {}
if isinstance(body, dict) and body:
sync_cfg = data.setdefault('settings', {}).setdefault('sync', {})
for key in (
'xui_url', 'xui_username', 'xui_password', 'xui_api_token',
'xui_create_conns', 'xui_server_id', 'xui_protocol', 'xui_sync_users', 'xui_sync',
):
if key in body and body[key] is not None:
sync_cfg[key] = body[key]
# Persist so background sync / next page load keep the values
async with DATA_LOCK:
current = load_data()
current.setdefault('settings', {}).setdefault('sync', {}).update(sync_cfg)
save_data(current)
data = current
count, msg = await sync_users_with_xui(data, force=True)
ok = count > 0 or (isinstance(msg, str) and msg.startswith('Successfully'))
return {
'status': 'success' if ok else 'error',
'count': count,
'message': msg,
}
@app.post('/api/settings/xui_sync_delete', tags=["Settings"])