diff --git a/modules/app_device_config.py b/modules/app_device_config.py index 5b9cad5..fbf5ba2 100644 --- a/modules/app_device_config.py +++ b/modules/app_device_config.py @@ -36,10 +36,14 @@ def update_device_config(body, errors): # Allow toggling sync_enabled off if "sync_enabled" in body and not body["sync_enabled"]: _set_sync_enabled(False) - # Toggling off is always allowed — don't return error even if - # other locked fields are in the body (the JS always sends them). + # Toggling off is always allowed — don't error on locked fields + # (the JS always sends them alongside the toggle). return errors - # User cannot edit locked fields while syncing from server. + # Sync is staying enabled — locked fields are ignored silently. + # The JS always sends them; rejecting would break the save flow. + if "sync_enabled" in body and body["sync_enabled"]: + return errors + # User tried to edit locked fields without the sync toggle — reject. if any(k in body for k in ["owner_name", "car_model", "avatar_path"]): errors["error"] = "Cannot edit device config while server sync is enabled. Server is source of truth." return errors diff --git a/static/js/settings.js b/static/js/settings.js index ad0cc76..a756fa4 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -459,20 +459,18 @@ form.addEventListener('submit', async event => { } populateRemoteConfig(remoteConfigResult); - // Save device config (skip if sync is enabled — server is source of truth) - if (!fields.deviceSyncEnabled.checked) { - const deviceConfigResponse = await fetch('/api/device-config', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(deviceConfigPayload()), - }); - const deviceConfigResult = await deviceConfigResponse.json(); - if (!deviceConfigResponse.ok) { - applyErrors(deviceConfigResult.fields || {}); - throw new Error(deviceConfigResult.error || `HTTP ${deviceConfigResponse.status}`); - } - populateDeviceConfig(deviceConfigResult); + // Save device config (always send — backend validates locked fields when sync is on) + const deviceConfigResponse = await fetch('/api/device-config', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify(deviceConfigPayload()), + }); + const deviceConfigResult = await deviceConfigResponse.json(); + if (!deviceConfigResponse.ok) { + applyErrors(deviceConfigResult.fields || {}); + throw new Error(deviceConfigResult.error || `HTTP ${deviceConfigResponse.status}`); } + populateDeviceConfig(deviceConfigResult); showMessage('Settings saved.', 'success'); } catch (error) {