diff --git a/homeassistant/components/cloud/client.py b/homeassistant/components/cloud/client.py index fda2014c9c3..8320eafb7a6 100644 --- a/homeassistant/components/cloud/client.py +++ b/homeassistant/components/cloud/client.py @@ -110,7 +110,7 @@ class CloudClient(Interface): async def logged_in(self) -> None: """When user logs in.""" - await self.prefs.async_set_username(self.cloud.username) + is_new_user = await self.prefs.async_set_username(self.cloud.username) async def enable_alexa(_): """Enable Alexa.""" @@ -136,6 +136,9 @@ class CloudClient(Interface): if gconf.should_report_state: gconf.async_enable_report_state() + if is_new_user: + await gconf.async_sync_entities(gconf.agent_user_id) + tasks = [] if self._prefs.alexa_enabled and self._prefs.alexa_report_state: diff --git a/homeassistant/components/cloud/google_config.py b/homeassistant/components/cloud/google_config.py index 26cb830e8c6..62ca1b15a71 100644 --- a/homeassistant/components/cloud/google_config.py +++ b/homeassistant/components/cloud/google_config.py @@ -131,6 +131,11 @@ class CloudGoogleConfig(AbstractConfig): """Return Agent User Id to use for query responses.""" return self._cloud.username + @property + def has_registered_user_agent(self): + """Return if we have a Agent User Id registered.""" + return len(self._store.agent_user_ids) > 0 + def get_agent_user_id(self, context): """Get agent user ID making request.""" return self.agent_user_id diff --git a/homeassistant/components/cloud/http_api.py b/homeassistant/components/cloud/http_api.py index 2bcc37fec05..e9771012379 100644 --- a/homeassistant/components/cloud/http_api.py +++ b/homeassistant/components/cloud/http_api.py @@ -27,7 +27,6 @@ from homeassistant.const import ( HTTP_OK, HTTP_UNAUTHORIZED, ) -from homeassistant.core import callback from .const import ( DOMAIN, @@ -225,6 +224,7 @@ class CloudLoginView(HomeAssistantView): hass = request.app["hass"] cloud = hass.data[DOMAIN] await cloud.login(data["email"], data["password"]) + return self.json({"success": True}) @@ -310,15 +310,15 @@ class CloudForgotPasswordView(HomeAssistantView): return self.json_message("ok") -@callback -def websocket_cloud_status(hass, connection, msg): +@websocket_api.async_response +async def websocket_cloud_status(hass, connection, msg): """Handle request for account info. Async friendly. """ cloud = hass.data[DOMAIN] connection.send_message( - websocket_api.result_message(msg["id"], _account_data(cloud)) + websocket_api.result_message(msg["id"], await _account_data(cloud)) ) @@ -446,7 +446,7 @@ async def websocket_hook_delete(hass, connection, msg): connection.send_message(websocket_api.result_message(msg["id"])) -def _account_data(cloud): +async def _account_data(cloud): """Generate the auth data JSON response.""" if not cloud.is_logged_in: @@ -456,6 +456,8 @@ def _account_data(cloud): client = cloud.client remote = cloud.remote + gconf = await client.get_google_config() + # Load remote certificate if remote.certificate: certificate = attr.asdict(remote.certificate) @@ -467,6 +469,7 @@ def _account_data(cloud): "email": claims["email"], "cloud": cloud.iot.state, "prefs": client.prefs.as_dict(), + "google_registered": gconf.has_registered_user_agent, "google_entities": client.google_user_config["filter"].config, "alexa_entities": client.alexa_user_config["filter"].config, "remote_domain": remote.instance_domain, @@ -485,7 +488,7 @@ async def websocket_remote_connect(hass, connection, msg): cloud = hass.data[DOMAIN] await cloud.client.prefs.async_update(remote_enabled=True) await cloud.remote.connect() - connection.send_result(msg["id"], _account_data(cloud)) + connection.send_result(msg["id"], await _account_data(cloud)) @websocket_api.require_admin @@ -498,7 +501,7 @@ async def websocket_remote_disconnect(hass, connection, msg): cloud = hass.data[DOMAIN] await cloud.client.prefs.async_update(remote_enabled=False) await cloud.remote.disconnect() - connection.send_result(msg["id"], _account_data(cloud)) + connection.send_result(msg["id"], await _account_data(cloud)) @websocket_api.require_admin diff --git a/homeassistant/components/cloud/prefs.py b/homeassistant/components/cloud/prefs.py index 2b15a620b83..c51d5278730 100644 --- a/homeassistant/components/cloud/prefs.py +++ b/homeassistant/components/cloud/prefs.py @@ -173,7 +173,7 @@ class CloudPreferences: updated_entities = {**entities, entity_id: updated_entity} await self.async_update(alexa_entity_configs=updated_entities) - async def async_set_username(self, username): + async def async_set_username(self, username) -> bool: """Set the username that is logged in.""" # Logging out. if username is None: @@ -182,18 +182,20 @@ class CloudPreferences: if user is not None: await self._hass.auth.async_remove_user(user) await self._save_prefs({**self._prefs, PREF_CLOUD_USER: None}) - return + return False cur_username = self._prefs.get(PREF_USERNAME) if cur_username == username: - return + return False if cur_username is None: await self._save_prefs({**self._prefs, PREF_USERNAME: username}) else: await self._save_prefs(self._empty_config(username)) + return True + def as_dict(self): """Return dictionary version.""" return { diff --git a/homeassistant/components/google_assistant/helpers.py b/homeassistant/components/google_assistant/helpers.py index f248202e5f0..7eb69d08724 100644 --- a/homeassistant/components/google_assistant/helpers.py +++ b/homeassistant/components/google_assistant/helpers.py @@ -269,13 +269,17 @@ class AbstractConfig(ABC): if webhook_id is None: return - webhook.async_register( - self.hass, - DOMAIN, - "Local Support", - webhook_id, - self._handle_local_webhook, - ) + try: + webhook.async_register( + self.hass, + DOMAIN, + "Local Support", + webhook_id, + self._handle_local_webhook, + ) + except ValueError: + _LOGGER.info("Webhook handler is already defined!") + return self._local_sdk_active = True diff --git a/tests/components/cloud/test_http_api.py b/tests/components/cloud/test_http_api.py index 80641c304be..35d261d5603 100644 --- a/tests/components/cloud/test_http_api.py +++ b/tests/components/cloud/test_http_api.py @@ -379,6 +379,7 @@ async def test_websocket_status( "exclude_entity_globs": [], "exclude_entities": [], }, + "google_registered": False, "remote_domain": None, "remote_connected": False, "remote_certificate": None, diff --git a/tests/components/cloud/test_prefs.py b/tests/components/cloud/test_prefs.py index d1b6f9ed867..4c0d9acb8f0 100644 --- a/tests/components/cloud/test_prefs.py +++ b/tests/components/cloud/test_prefs.py @@ -39,6 +39,18 @@ async def test_set_username_migration(hass): assert not prefs.google_enabled +async def test_set_new_username(hass, hass_storage): + """Test if setting new username returns true.""" + hass_storage[STORAGE_KEY] = {"version": 1, "data": {"username": "old-user"}} + + prefs = CloudPreferences(hass) + await prefs.async_initialize() + + assert not await prefs.async_set_username("old-user") + + assert await prefs.async_set_username("new-user") + + async def test_load_invalid_cloud_user(hass, hass_storage): """Test loading cloud user with invalid storage.""" hass_storage[STORAGE_KEY] = {"version": 1, "data": {"cloud_user": "non-existing"}}