From 05374d7c85a7e6b2427ab28f846da4ba2946f92d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 6 Jan 2020 22:00:39 +0100 Subject: [PATCH] Fix google sync (#30524) --- homeassistant/components/cloud/google_config.py | 15 +++++++++++++++ homeassistant/components/cloud/http_api.py | 2 +- .../components/google_assistant/helpers.py | 9 +++++++-- homeassistant/components/google_assistant/http.py | 4 ++++ .../components/google_assistant/smart_home.py | 2 +- tests/components/cloud/test_client.py | 10 +++++++--- tests/components/google_assistant/__init__.py | 4 ++++ 7 files changed, 39 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/cloud/google_config.py b/homeassistant/components/cloud/google_config.py index 1ff87bf95f5..639540fbf03 100644 --- a/homeassistant/components/cloud/google_config.py +++ b/homeassistant/components/cloud/google_config.py @@ -77,6 +77,12 @@ class CloudGoogleConfig(AbstractConfig): """Return Cloud User account.""" return self._user + async def async_initialize(self): + """Perform async initialization of config.""" + await super().async_initialize() + # Remove bad data that was there until 0.103.6 - Jan 6, 2020 + self._store.pop_agent_user_id(self._user) + def should_expose(self, state): """If a state object should be exposed.""" return self._should_expose_entity_id(state.entity_id) @@ -93,6 +99,15 @@ class CloudGoogleConfig(AbstractConfig): entity_config = entity_configs.get(entity_id, {}) return entity_config.get(PREF_SHOULD_EXPOSE, DEFAULT_SHOULD_EXPOSE) + @property + def agent_user_id(self): + """Return Agent User Id to use for query responses.""" + return self._cloud.username + + def get_agent_user_id(self, context): + """Get agent user ID making request.""" + return self.agent_user_id + def should_2fa(self, state): """If an entity should be checked for 2FA.""" entity_configs = self._prefs.google_entity_configs diff --git a/homeassistant/components/cloud/http_api.py b/homeassistant/components/cloud/http_api.py index b97feb7c6f4..9afaad422ba 100644 --- a/homeassistant/components/cloud/http_api.py +++ b/homeassistant/components/cloud/http_api.py @@ -175,7 +175,7 @@ class GoogleActionsSyncView(HomeAssistantView): hass = request.app["hass"] cloud: Cloud = hass.data[DOMAIN] gconf = await cloud.client.get_google_config() - status = await gconf.async_sync_entities(gconf.cloud_user) + status = await gconf.async_sync_entities(gconf.agent_user_id) return self.json({}, status_code=status) diff --git a/homeassistant/components/google_assistant/helpers.py b/homeassistant/components/google_assistant/helpers.py index 8a847eca705..6493d759880 100644 --- a/homeassistant/components/google_assistant/helpers.py +++ b/homeassistant/components/google_assistant/helpers.py @@ -1,4 +1,5 @@ """Helper classes for Google Assistant integration.""" +from abc import ABC, abstractmethod from asyncio import gather from collections.abc import Mapping import logging @@ -35,7 +36,7 @@ SYNC_DELAY = 15 _LOGGER = logging.getLogger(__name__) -class AbstractConfig: +class AbstractConfig(ABC): """Hold the configuration for Google Assistant.""" _unsub_report_state = None @@ -95,9 +96,13 @@ class AbstractConfig: """Return the user ID to be used for actions received via the local SDK.""" raise NotImplementedError + @abstractmethod + def get_agent_user_id(self, context): + """Get agent user ID from context.""" + + @abstractmethod def should_expose(self, state) -> bool: """Return if entity should be exposed.""" - raise NotImplementedError def should_2fa(self, state): """If an entity should have 2FA checked.""" diff --git a/homeassistant/components/google_assistant/http.py b/homeassistant/components/google_assistant/http.py index 233923e97a9..f8fa51da8d7 100644 --- a/homeassistant/components/google_assistant/http.py +++ b/homeassistant/components/google_assistant/http.py @@ -121,6 +121,10 @@ class GoogleConfig(AbstractConfig): return is_default_exposed or explicit_expose + def get_agent_user_id(self, context): + """Get agent user ID making request.""" + return context.user_id + def should_2fa(self, state): """If an entity should have 2FA checked.""" return True diff --git a/homeassistant/components/google_assistant/smart_home.py b/homeassistant/components/google_assistant/smart_home.py index b111e6dc942..8033bcec865 100644 --- a/homeassistant/components/google_assistant/smart_home.py +++ b/homeassistant/components/google_assistant/smart_home.py @@ -78,7 +78,7 @@ async def async_devices_sync(hass, data, payload): EVENT_SYNC_RECEIVED, {"request_id": data.request_id}, context=data.context ) - agent_user_id = data.context.user_id + agent_user_id = data.config.get_agent_user_id(data.context) devices = await asyncio.gather( *( diff --git a/tests/components/cloud/test_client.py b/tests/components/cloud/test_client.py index b3bfebb0ee7..2338f0eaa1e 100644 --- a/tests/components/cloud/test_client.py +++ b/tests/components/cloud/test_client.py @@ -103,13 +103,17 @@ async def test_handler_google_actions(hass): reqid = "5711642932632160983" data = {"requestId": reqid, "inputs": [{"intent": "action.devices.SYNC"}]} - config = await cloud.client.get_google_config() - resp = await cloud.client.async_google_message(data) + with patch( + "hass_nabucasa.Cloud._decode_claims", + return_value={"cognito:username": "myUserName"}, + ): + await cloud.client.get_google_config() + resp = await cloud.client.async_google_message(data) assert resp["requestId"] == reqid payload = resp["payload"] - assert payload["agentUserId"] == config.cloud_user + assert payload["agentUserId"] == "myUserName" devices = payload["devices"] assert len(devices) == 1 diff --git a/tests/components/google_assistant/__init__.py b/tests/components/google_assistant/__init__.py index b00b690cba5..d2cb27663ac 100644 --- a/tests/components/google_assistant/__init__.py +++ b/tests/components/google_assistant/__init__.py @@ -64,6 +64,10 @@ class MockConfig(helpers.AbstractConfig): """Return local SDK webhook id.""" return self._local_sdk_user_id + def get_agent_user_id(self, context): + """Get agent user ID making request.""" + return context.user_id + def should_expose(self, state): """Expose it all.""" return self._should_expose is None or self._should_expose(state)