Record a timezone-only admin update as an explicit choice (task 45243478)
update_settings() now persists timezone_configured=True when the changes supply timezone without timezone_configured, so Home Assistant's reported zone can no longer replace an admin-chosen zone (release review RR-001). An explicit timezone_configured is kept as supplied; the automatic adoption path is unchanged and still leaves the marker false. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -184,6 +184,11 @@ async def update_settings(
|
||||
in one atomic upsert; the updated settings are returned. The whole
|
||||
read → merge → write span runs inside the per-database settings
|
||||
lock, so concurrent updates queue instead of interleaving.
|
||||
|
||||
Supplying ``timezone`` without ``timezone_configured`` records the
|
||||
zone as the admin's explicit choice (``timezone_configured`` is
|
||||
persisted ``True`` in the same write); an explicitly supplied
|
||||
``timezone_configured`` is kept exactly as given.
|
||||
"""
|
||||
if not isinstance(changes, Mapping):
|
||||
raise ValueError(
|
||||
@@ -199,6 +204,10 @@ async def update_settings(
|
||||
raise ValueError(
|
||||
f"unknown settings field(s): {listed}; known fields: {known}"
|
||||
)
|
||||
if "timezone" in changes and "timezone_configured" not in changes:
|
||||
# An admin-supplied zone is an explicit choice, so Home
|
||||
# Assistant's reported zone must no longer replace it.
|
||||
changes = {**changes, "timezone_configured": True}
|
||||
async with _settings_lock(database):
|
||||
current = await load_settings(database)
|
||||
return await _write_merged(database, current, changes)
|
||||
|
||||
@@ -445,6 +445,44 @@ async def test_admin_chosen_zone_wins_over_reported_zone(
|
||||
assert stored["timezone_configured"] is True
|
||||
|
||||
|
||||
# --- a timezone-only admin update is an explicit choice (task 45243478) ------
|
||||
|
||||
|
||||
@pytest.mark.parametrize("chosen", ["America/Los_Angeles", ""])
|
||||
async def test_timezone_only_admin_update_is_an_explicit_choice(
|
||||
household: SimpleNamespace, chosen: str
|
||||
) -> None:
|
||||
"""``PATCH {"timezone": ...}`` alone marks the zone admin-chosen."""
|
||||
await _adopt_new_york(household)
|
||||
response = await household.client.patch(
|
||||
"/api/v1/admin/settings",
|
||||
json={"timezone": chosen},
|
||||
headers=_admin_headers(),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["timezone_configured"] is True
|
||||
# A conflicting report is no longer adopted.
|
||||
await _panel_pack_bag(household, "America/Chicago")
|
||||
stored = await _stored_settings(household)
|
||||
assert stored["timezone"] == chosen
|
||||
assert stored["timezone_configured"] is True
|
||||
|
||||
|
||||
async def test_explicit_timezone_configured_false_is_respected(
|
||||
household: SimpleNamespace,
|
||||
) -> None:
|
||||
"""A supplied ``timezone_configured`` is persisted exactly as given."""
|
||||
response = await household.client.patch(
|
||||
"/api/v1/admin/settings",
|
||||
json={"timezone": "America/Chicago", "timezone_configured": False},
|
||||
headers=_admin_headers(),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["timezone_configured"] is False
|
||||
await _panel_pack_bag(household, HOUSEHOLD_ZONE)
|
||||
assert (await _stored_settings(household))["timezone"] == HOUSEHOLD_ZONE
|
||||
|
||||
|
||||
async def test_invalid_reported_zone_is_ignored(
|
||||
household: SimpleNamespace,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user