From 9459af30b0e6392219fac410c9fa176f434a3ca3 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Tue, 13 Sep 2022 20:56:40 +0200 Subject: [PATCH] Don't allow partial update of input_datetime settings (#78373) --- .../components/input_datetime/__init__.py | 20 ++++++------------- tests/components/input_datetime/test_init.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/input_datetime/__init__.py b/homeassistant/components/input_datetime/__init__.py index bda5572081c..daedfd251b0 100644 --- a/homeassistant/components/input_datetime/__init__.py +++ b/homeassistant/components/input_datetime/__init__.py @@ -61,20 +61,13 @@ def validate_set_datetime_attrs(config): STORAGE_KEY = DOMAIN STORAGE_VERSION = 1 -CREATE_FIELDS = { +STORAGE_FIELDS = { vol.Required(CONF_NAME): vol.All(str, vol.Length(min=1)), vol.Optional(CONF_HAS_DATE, default=False): cv.boolean, vol.Optional(CONF_HAS_TIME, default=False): cv.boolean, vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_INITIAL): cv.string, } -UPDATE_FIELDS = { - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_HAS_DATE): cv.boolean, - vol.Optional(CONF_HAS_TIME): cv.boolean, - vol.Optional(CONF_ICON): cv.icon, - vol.Optional(CONF_INITIAL): cv.string, -} def has_date_or_time(conf): @@ -167,7 +160,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: @@ -213,12 +206,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: class DateTimeStorageCollection(collection.StorageCollection): """Input storage based collection.""" - CREATE_SCHEMA = vol.Schema(vol.All(CREATE_FIELDS, has_date_or_time)) - UPDATE_SCHEMA = vol.Schema(UPDATE_FIELDS) + CREATE_UPDATE_SCHEMA = vol.Schema(vol.All(STORAGE_FIELDS, has_date_or_time)) async def _process_create_data(self, data: dict) -> dict: """Validate the config is valid.""" - return self.CREATE_SCHEMA(data) + return self.CREATE_UPDATE_SCHEMA(data) @callback def _get_suggested_id(self, info: dict) -> str: @@ -227,8 +219,8 @@ class DateTimeStorageCollection(collection.StorageCollection): async def _update_data(self, data: dict, update_data: dict) -> dict: """Return a new updated data object.""" - update_data = self.UPDATE_SCHEMA(update_data) - return has_date_or_time({**data, **update_data}) + update_data = self.CREATE_UPDATE_SCHEMA(update_data) + return {CONF_ID: data[CONF_ID]} | update_data class InputDatetime(RestoreEntity): diff --git a/tests/components/input_datetime/test_init.py b/tests/components/input_datetime/test_init.py index 28ca2ab02bd..9e694488797 100644 --- a/tests/components/input_datetime/test_init.py +++ b/tests/components/input_datetime/test_init.py @@ -583,17 +583,23 @@ async def test_update(hass, hass_ws_client, storage_setup): client = await hass_ws_client(hass) + updated_settings = { + CONF_NAME: "even newer name", + CONF_HAS_DATE: False, + CONF_HAS_TIME: True, + CONF_INITIAL: INITIAL_DATETIME, + } await client.send_json( { "id": 6, "type": f"{DOMAIN}/update", f"{DOMAIN}_id": f"{input_id}", - ATTR_NAME: "even newer name", - CONF_HAS_DATE: False, + **updated_settings, } ) resp = await client.receive_json() assert resp["success"] + assert resp["result"] == {"id": "from_storage"} | updated_settings state = hass.states.get(input_entity_id) assert state.state == INITIAL_TIME