From c97b1c60b06b40017b6bdce7b7371ede10bc571a Mon Sep 17 00:00:00 2001
From: Aaron Bach <bachya1208@gmail.com>
Date: Mon, 24 Feb 2020 22:36:58 -0700
Subject: [PATCH] Modernize Notion config flow (#32167)

* Modernize Notion config flow

* Linting
---
 .coveragerc                                   |  1 +
 .../components/notion/.translations/en.json   |  4 ++-
 homeassistant/components/notion/__init__.py   |  9 +++---
 .../components/notion/config_flow.py          | 29 +++++++------------
 homeassistant/components/notion/strings.json  |  4 ++-
 tests/components/notion/test_config_flow.py   | 19 ++++++++----
 6 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/.coveragerc b/.coveragerc
index 6dcd20f6ad6..fe5242327dc 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -480,6 +480,7 @@ omit =
     homeassistant/components/nissan_leaf/*
     homeassistant/components/nmap_tracker/device_tracker.py
     homeassistant/components/nmbs/sensor.py
+    homeassistant/components/notion/__init__.py
     homeassistant/components/notion/binary_sensor.py
     homeassistant/components/notion/sensor.py
     homeassistant/components/noaa_tides/sensor.py
diff --git a/homeassistant/components/notion/.translations/en.json b/homeassistant/components/notion/.translations/en.json
index b05f613a73f..b729b368c37 100644
--- a/homeassistant/components/notion/.translations/en.json
+++ b/homeassistant/components/notion/.translations/en.json
@@ -1,7 +1,9 @@
 {
     "config": {
+        "abort": {
+            "already_configured": "This username is already in use."
+        },
         "error": {
-            "identifier_exists": "Username already registered",
             "invalid_credentials": "Invalid username or password",
             "no_devices": "No devices found in account"
         },
diff --git a/homeassistant/components/notion/__init__.py b/homeassistant/components/notion/__init__.py
index 1e04c4a8e8e..f387e820253 100644
--- a/homeassistant/components/notion/__init__.py
+++ b/homeassistant/components/notion/__init__.py
@@ -22,7 +22,6 @@ from homeassistant.helpers.dispatcher import (
 from homeassistant.helpers.entity import Entity
 from homeassistant.helpers.event import async_track_time_interval
 
-from .config_flow import configured_instances
 from .const import DATA_CLIENT, DEFAULT_SCAN_INTERVAL, DOMAIN, TOPIC_DATA_UPDATE
 
 _LOGGER = logging.getLogger(__name__)
@@ -84,9 +83,6 @@ async def async_setup(hass, config):
 
     conf = config[DOMAIN]
 
-    if conf[CONF_USERNAME] in configured_instances(hass):
-        return True
-
     hass.async_create_task(
         hass.config_entries.flow.async_init(
             DOMAIN,
@@ -103,6 +99,11 @@ async def async_setup(hass, config):
 
 async def async_setup_entry(hass, config_entry):
     """Set up Notion as a config entry."""
+    if not config_entry.unique_id:
+        hass.config_entries.async_update_entry(
+            config_entry, unique_id=config_entry.data[CONF_USERNAME]
+        )
+
     session = aiohttp_client.async_get_clientsession(hass)
 
     try:
diff --git a/homeassistant/components/notion/config_flow.py b/homeassistant/components/notion/config_flow.py
index 2af231d582e..58c5c0d44ee 100644
--- a/homeassistant/components/notion/config_flow.py
+++ b/homeassistant/components/notion/config_flow.py
@@ -5,35 +5,27 @@ import voluptuous as vol
 
 from homeassistant import config_entries
 from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
-from homeassistant.core import callback
 from homeassistant.helpers import aiohttp_client
 
-from .const import DOMAIN
+from .const import DOMAIN  # pylint: disable=unused-import
 
 
-@callback
-def configured_instances(hass):
-    """Return a set of configured Notion instances."""
-    return set(
-        entry.data[CONF_USERNAME] for entry in hass.config_entries.async_entries(DOMAIN)
-    )
-
-
-@config_entries.HANDLERS.register(DOMAIN)
-class NotionFlowHandler(config_entries.ConfigFlow):
+class NotionFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
     """Handle a Notion config flow."""
 
     VERSION = 1
     CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
 
-    async def _show_form(self, errors=None):
-        """Show the form to the user."""
-        data_schema = vol.Schema(
+    def __init__(self):
+        """Initialize the config flow."""
+        self.data_schema = vol.Schema(
             {vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
         )
 
+    async def _show_form(self, errors=None):
+        """Show the form to the user."""
         return self.async_show_form(
-            step_id="user", data_schema=data_schema, errors=errors or {}
+            step_id="user", data_schema=self.data_schema, errors=errors or {}
         )
 
     async def async_step_import(self, import_config):
@@ -42,12 +34,11 @@ class NotionFlowHandler(config_entries.ConfigFlow):
 
     async def async_step_user(self, user_input=None):
         """Handle the start of the config flow."""
-
         if not user_input:
             return await self._show_form()
 
-        if user_input[CONF_USERNAME] in configured_instances(self.hass):
-            return await self._show_form({CONF_USERNAME: "identifier_exists"})
+        await self.async_set_unique_id(user_input[CONF_USERNAME])
+        self._abort_if_unique_id_configured()
 
         session = aiohttp_client.async_get_clientsession(self.hass)
 
diff --git a/homeassistant/components/notion/strings.json b/homeassistant/components/notion/strings.json
index 8825e25bfe8..fa47c2819ba 100644
--- a/homeassistant/components/notion/strings.json
+++ b/homeassistant/components/notion/strings.json
@@ -11,9 +11,11 @@
       }
     },
     "error": {
-      "identifier_exists": "Username already registered",
       "invalid_credentials": "Invalid username or password",
       "no_devices": "No devices found in account"
+    },
+    "abort": {
+      "already_configured": "This username is already in use."
     }
   }
 }
diff --git a/tests/components/notion/test_config_flow.py b/tests/components/notion/test_config_flow.py
index f7651a570cf..60ca4c07fb5 100644
--- a/tests/components/notion/test_config_flow.py
+++ b/tests/components/notion/test_config_flow.py
@@ -6,6 +6,7 @@ import pytest
 
 from homeassistant import data_entry_flow
 from homeassistant.components.notion import DOMAIN, config_flow
+from homeassistant.config_entries import SOURCE_USER
 from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
 
 from tests.common import MockConfigEntry, mock_coro
@@ -29,12 +30,16 @@ async def test_duplicate_error(hass):
     """Test that errors are shown when duplicates are added."""
     conf = {CONF_USERNAME: "user@host.com", CONF_PASSWORD: "password123"}
 
-    MockConfigEntry(domain=DOMAIN, data=conf).add_to_hass(hass)
-    flow = config_flow.NotionFlowHandler()
-    flow.hass = hass
+    MockConfigEntry(domain=DOMAIN, unique_id="user@host.com", data=conf).add_to_hass(
+        hass
+    )
 
-    result = await flow.async_step_user(user_input=conf)
-    assert result["errors"] == {CONF_USERNAME: "identifier_exists"}
+    result = await hass.config_entries.flow.async_init(
+        DOMAIN, context={"source": SOURCE_USER}, data=conf
+    )
+
+    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
+    assert result["reason"] == "already_configured"
 
 
 @pytest.mark.parametrize(
@@ -46,6 +51,7 @@ async def test_invalid_credentials(hass, mock_aionotion):
 
     flow = config_flow.NotionFlowHandler()
     flow.hass = hass
+    flow.context = {"source": SOURCE_USER}
 
     result = await flow.async_step_user(user_input=conf)
     assert result["errors"] == {"base": "invalid_credentials"}
@@ -55,6 +61,7 @@ async def test_show_form(hass):
     """Test that the form is served with no input."""
     flow = config_flow.NotionFlowHandler()
     flow.hass = hass
+    flow.context = {"source": SOURCE_USER}
 
     result = await flow.async_step_user(user_input=None)
 
@@ -68,6 +75,7 @@ async def test_step_import(hass, mock_aionotion):
 
     flow = config_flow.NotionFlowHandler()
     flow.hass = hass
+    flow.context = {"source": SOURCE_USER}
 
     result = await flow.async_step_import(import_config=conf)
     assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
@@ -84,6 +92,7 @@ async def test_step_user(hass, mock_aionotion):
 
     flow = config_flow.NotionFlowHandler()
     flow.hass = hass
+    flow.context = {"source": SOURCE_USER}
 
     result = await flow.async_step_user(user_input=conf)
     assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
-- 
GitLab