From c97b1c60b06b40017b6bdce7b7371ede10bc571a Mon Sep 17 00:00:00 2001 From: Aaron Bach 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 6dcd20f6ad6e..fe5242327dcf 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 b05f613a73ff..b729b368c37e 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 1e04c4a8e8ef..f387e8202538 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 2af231d582e4..58c5c0d44eea 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 8825e25bfe84..fa47c2819ba0 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 f7651a570cff..60ca4c07fb5a 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