Reauth flow for Risco cloud (#81264)
* Risco reauth flow * Address code review comments * Remove redundant logpull/81365/head
parent
4a9859bf54
commit
f8de4c3931
|
@ -26,7 +26,7 @@ from homeassistant.const import (
|
|||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.storage import Store
|
||||
|
@ -127,10 +127,9 @@ async def _async_setup_cloud_entry(hass: HomeAssistant, entry: ConfigEntry) -> b
|
|||
try:
|
||||
await risco.login(async_get_clientsession(hass))
|
||||
except CannotConnectError as error:
|
||||
raise ConfigEntryNotReady() from error
|
||||
except UnauthorizedError:
|
||||
_LOGGER.exception("Failed to login to Risco cloud")
|
||||
return False
|
||||
raise ConfigEntryNotReady from error
|
||||
except UnauthorizedError as error:
|
||||
raise ConfigEntryAuthFailed from error
|
||||
|
||||
scan_interval = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
|
||||
coordinator = RiscoDataUpdateCoordinator(hass, risco, scan_interval)
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pyrisco import CannotConnectError, RiscoCloud, RiscoLocal, UnauthorizedError
|
||||
import voluptuous as vol
|
||||
|
@ -21,6 +22,7 @@ from homeassistant.const import (
|
|||
STATE_ALARM_ARMED_HOME,
|
||||
STATE_ALARM_ARMED_NIGHT,
|
||||
)
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import (
|
||||
|
@ -93,6 +95,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Init the config flow."""
|
||||
self._reauth_entry: config_entries.ConfigEntry | None = None
|
||||
|
||||
@staticmethod
|
||||
@core.callback
|
||||
def async_get_options_flow(
|
||||
|
@ -112,8 +118,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
"""Configure a cloud based alarm."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
await self.async_set_unique_id(user_input[CONF_USERNAME])
|
||||
self._abort_if_unique_id_configured()
|
||||
if not self._reauth_entry:
|
||||
await self.async_set_unique_id(user_input[CONF_USERNAME])
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
try:
|
||||
info = await validate_cloud_input(self.hass, user_input)
|
||||
|
@ -125,12 +132,25 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
_LOGGER.exception("Unexpected exception")
|
||||
errors["base"] = "unknown"
|
||||
else:
|
||||
return self.async_create_entry(title=info["title"], data=user_input)
|
||||
if not self._reauth_entry:
|
||||
return self.async_create_entry(title=info["title"], data=user_input)
|
||||
self.hass.config_entries.async_update_entry(
|
||||
self._reauth_entry,
|
||||
data=user_input,
|
||||
unique_id=user_input[CONF_USERNAME],
|
||||
)
|
||||
await self.hass.config_entries.async_reload(self._reauth_entry.entry_id)
|
||||
return self.async_abort(reason="reauth_successful")
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="cloud", data_schema=CLOUD_SCHEMA, errors=errors
|
||||
)
|
||||
|
||||
async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult:
|
||||
"""Handle configuration by re-auth."""
|
||||
self._reauth_entry = await self.async_set_unique_id(entry_data[CONF_USERNAME])
|
||||
return await self.async_step_cloud()
|
||||
|
||||
async def async_step_local(self, user_input=None):
|
||||
"""Configure a local based alarm."""
|
||||
errors = {}
|
||||
|
|
|
@ -70,7 +70,10 @@ def events():
|
|||
def cloud_config_entry(hass, options):
|
||||
"""Fixture for a cloud config entry."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=TEST_CLOUD_CONFIG, options=options
|
||||
domain=DOMAIN,
|
||||
data=TEST_CLOUD_CONFIG,
|
||||
options=options,
|
||||
unique_id=TEST_CLOUD_CONFIG[CONF_USERNAME],
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
return config_entry
|
||||
|
|
|
@ -10,6 +10,7 @@ from homeassistant.components.risco.config_flow import (
|
|||
UnauthorizedError,
|
||||
)
|
||||
from homeassistant.components.risco.const import DOMAIN
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
@ -142,6 +143,75 @@ async def test_form_cloud_already_exists(hass):
|
|||
assert result3["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_form_reauth(hass, cloud_config_entry):
|
||||
"""Test reauthenticate."""
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_REAUTH},
|
||||
data=cloud_config_entry.data,
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.risco.config_flow.RiscoCloud.login",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"homeassistant.components.risco.config_flow.RiscoCloud.site_name",
|
||||
new_callable=PropertyMock(return_value=TEST_SITE_NAME),
|
||||
), patch(
|
||||
"homeassistant.components.risco.config_flow.RiscoCloud.close"
|
||||
), patch(
|
||||
"homeassistant.components.risco.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {**TEST_CLOUD_DATA, CONF_PASSWORD: "new_password"}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "reauth_successful"
|
||||
assert cloud_config_entry.data[CONF_PASSWORD] == "new_password"
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_form_reauth_with_new_username(hass, cloud_config_entry):
|
||||
"""Test reauthenticate with new username."""
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_REAUTH},
|
||||
data=cloud_config_entry.data,
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.risco.config_flow.RiscoCloud.login",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"homeassistant.components.risco.config_flow.RiscoCloud.site_name",
|
||||
new_callable=PropertyMock(return_value=TEST_SITE_NAME),
|
||||
), patch(
|
||||
"homeassistant.components.risco.config_flow.RiscoCloud.close"
|
||||
), patch(
|
||||
"homeassistant.components.risco.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {**TEST_CLOUD_DATA, CONF_USERNAME: "new_user"}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "reauth_successful"
|
||||
assert cloud_config_entry.data[CONF_USERNAME] == "new_user"
|
||||
assert cloud_config_entry.unique_id == "new_user"
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_local_form(hass):
|
||||
"""Test we get the local form."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
|
Loading…
Reference in New Issue