From 4898a41dcf12b9201e1da35e025d68f1899ce196 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Tue, 13 Sep 2022 20:58:12 +0200 Subject: [PATCH] Don't allow partial update of timer settings (#78378) --- homeassistant/components/timer/__init__.py | 17 +++++------------ tests/components/timer/test_init.py | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/timer/__init__.py b/homeassistant/components/timer/__init__.py index 53912a4dec8..ff50e96a18c 100644 --- a/homeassistant/components/timer/__init__.py +++ b/homeassistant/components/timer/__init__.py @@ -61,18 +61,12 @@ SERVICE_FINISH = "finish" STORAGE_KEY = DOMAIN STORAGE_VERSION = 1 -CREATE_FIELDS = { +STORAGE_FIELDS = { vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_DURATION, default=DEFAULT_DURATION): cv.time_period, vol.Optional(CONF_RESTORE, default=DEFAULT_RESTORE): cv.boolean, } -UPDATE_FIELDS = { - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_ICON): cv.icon, - vol.Optional(CONF_DURATION): cv.time_period, - vol.Optional(CONF_RESTORE): cv.boolean, -} def _format_timedelta(delta: timedelta): @@ -137,7 +131,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: await storage_collection.async_load() collection.StorageCollectionWebsocket( - storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS + storage_collection, DOMAIN, DOMAIN, STORAGE_FIELDS, STORAGE_FIELDS ).async_setup(hass) async def reload_service_handler(service_call: ServiceCall) -> None: @@ -171,12 +165,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: class TimerStorageCollection(collection.StorageCollection): """Timer storage based collection.""" - CREATE_SCHEMA = vol.Schema(CREATE_FIELDS) - UPDATE_SCHEMA = vol.Schema(UPDATE_FIELDS) + CREATE_UPDATE_SCHEMA = vol.Schema(STORAGE_FIELDS) async def _process_create_data(self, data: dict) -> dict: """Validate the config is valid.""" - data = self.CREATE_SCHEMA(data) + data = self.CREATE_UPDATE_SCHEMA(data) # make duration JSON serializeable data[CONF_DURATION] = _format_timedelta(data[CONF_DURATION]) return data @@ -188,7 +181,7 @@ class TimerStorageCollection(collection.StorageCollection): async def _update_data(self, data: dict, update_data: dict) -> dict: """Return a new updated data object.""" - data = {**data, **self.UPDATE_SCHEMA(update_data)} + data = {CONF_ID: data[CONF_ID]} | self.CREATE_UPDATE_SCHEMA(update_data) # make duration JSON serializeable if CONF_DURATION in update_data: data[CONF_DURATION] = _format_timedelta(data[CONF_DURATION]) diff --git a/tests/components/timer/test_init.py b/tests/components/timer/test_init.py index b51200c6ad0..ac2dde57c8d 100644 --- a/tests/components/timer/test_init.py +++ b/tests/components/timer/test_init.py @@ -585,17 +585,27 @@ async def test_update(hass, hass_ws_client, storage_setup): client = await hass_ws_client(hass) + updated_settings = { + CONF_NAME: "timer from storage", + CONF_DURATION: 33, + CONF_RESTORE: True, + } await client.send_json( { "id": 6, "type": f"{DOMAIN}/update", f"{DOMAIN}_id": f"{timer_id}", - CONF_DURATION: 33, - CONF_RESTORE: True, + **updated_settings, } ) resp = await client.receive_json() assert resp["success"] + assert resp["result"] == { + "id": "from_storage", + CONF_DURATION: "0:00:33", + CONF_NAME: "timer from storage", + CONF_RESTORE: True, + } state = hass.states.get(timer_entity_id) assert state.attributes[ATTR_DURATION] == _format_timedelta(cv.time_period(33))