diff --git a/.coveragerc b/.coveragerc index 6dcd20f6ad6eb1f232ab1eea68c10413d6762cd4..fe5242327dcf0665add61958d1073bd38bc4fad8 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 b05f613a73ffa61782e1ef48192258d432c71b98..b729b368c37e81357e709e7261e8dac3ffcca7d3 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 1e04c4a8e8effa4b8876df9b92b452499816a1c5..f387e82025380d5868c6b3e64c7b98df8565cf17 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 2af231d582e4d8dc61e8fa9b3f09f52fb7808758..58c5c0d44eea626994b2d39fe5c1dc76a1f4de45 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 8825e25bfe841a394e3cfd55a7d0b2dc29ccc4c1..fa47c2819ba0368f71ae52902be3cd487dae10e8 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 f7651a570cffe796d7b4b2d4662142d1e07a745e..60ca4c07fb5a0193e9397704582dfc0660a7632d 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