Merge remote-tracking branch 'origin/dev' into release/2026-09-28-time-zone-errors
This commit is contained in:
@@ -184,6 +184,11 @@ async def update_settings(
|
|||||||
in one atomic upsert; the updated settings are returned. The whole
|
in one atomic upsert; the updated settings are returned. The whole
|
||||||
read → merge → write span runs inside the per-database settings
|
read → merge → write span runs inside the per-database settings
|
||||||
lock, so concurrent updates queue instead of interleaving.
|
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):
|
if not isinstance(changes, Mapping):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@@ -199,6 +204,10 @@ async def update_settings(
|
|||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"unknown settings field(s): {listed}; known fields: {known}"
|
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):
|
async with _settings_lock(database):
|
||||||
current = await load_settings(database)
|
current = await load_settings(database)
|
||||||
return await _write_merged(database, current, changes)
|
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
|
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(
|
async def test_invalid_reported_zone_is_ignored(
|
||||||
household: SimpleNamespace,
|
household: SimpleNamespace,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user