Skip to content
Snippets Groups Projects
Unverified Commit 109bcd86 authored by Christopher Fenner's avatar Christopher Fenner Committed by GitHub
Browse files

Add reauth flow to ViCare integration (#103109)


Co-authored-by: default avatarRobert Resch <robert@resch.dev>
parent 1e375352
No related branches found
No related tags found
No related merge requests found
......@@ -10,10 +10,15 @@ from typing import Any
from PyViCare.PyViCare import PyViCare
from PyViCare.PyViCareDevice import Device
from PyViCare.PyViCareUtils import (
PyViCareInvalidConfigurationError,
PyViCareInvalidCredentialsError,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_CLIENT_ID, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.storage import STORAGE_DIR
from .const import (
......@@ -53,7 +58,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN] = {}
hass.data[DOMAIN][entry.entry_id] = {}
await hass.async_add_executor_job(setup_vicare_api, hass, entry)
try:
await hass.async_add_executor_job(setup_vicare_api, hass, entry)
except (PyViCareInvalidConfigurationError, PyViCareInvalidCredentialsError) as err:
raise ConfigEntryAuthFailed("Authentication failed") from err
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
......
"""Config flow for ViCare integration."""
from __future__ import annotations
from collections.abc import Mapping
import logging
from typing import Any
......@@ -28,11 +29,28 @@ from .const import (
_LOGGER = logging.getLogger(__name__)
REAUTH_SCHEMA = vol.Schema(
{
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_CLIENT_ID): cv.string,
}
)
USER_SCHEMA = REAUTH_SCHEMA.extend(
{
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_HEATING_TYPE, default=DEFAULT_HEATING_TYPE.value): vol.In(
[e.value for e in HeatingType]
),
}
)
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for ViCare."""
VERSION = 1
entry: config_entries.ConfigEntry | None
async def async_step_user(
self, user_input: dict[str, Any] | None = None
......@@ -41,14 +59,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
data_schema = {
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_CLIENT_ID): cv.string,
vol.Required(CONF_HEATING_TYPE, default=DEFAULT_HEATING_TYPE.value): vol.In(
[e.value for e in HeatingType]
),
}
errors: dict[str, str] = {}
if user_input is not None:
......@@ -63,7 +73,45 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(data_schema),
data_schema=USER_SCHEMA,
errors=errors,
)
async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult:
"""Handle re-authentication with ViCare."""
self.entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Confirm re-authentication with ViCare."""
errors: dict[str, str] = {}
assert self.entry is not None
if user_input:
data = {
**self.entry.data,
**user_input,
}
try:
await self.hass.async_add_executor_job(vicare_login, self.hass, data)
except (PyViCareInvalidConfigurationError, PyViCareInvalidCredentialsError):
errors["base"] = "invalid_auth"
else:
self.hass.config_entries.async_update_entry(
self.entry,
data=data,
)
await self.hass.config_entries.async_reload(self.entry.entry_id)
return self.async_abort(reason="reauth_successful")
return self.async_show_form(
step_id="reauth_confirm",
data_schema=self.add_suggested_values_to_schema(
REAUTH_SCHEMA, self.entry.data
),
errors=errors,
)
......
......@@ -10,6 +10,13 @@
"client_id": "Client ID",
"heating_type": "Heating type"
}
},
"reauth_confirm": {
"description": "Please verify credentials.",
"data": {
"password": "[%key:common::config_flow::data::password%]",
"client_id": "[%key:component::vicare::config::step::user::data::client_id%]"
}
}
},
"error": {
......@@ -17,6 +24,7 @@
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
}
},
......
......@@ -10,7 +10,7 @@ from syrupy.assertion import SnapshotAssertion
from homeassistant.components import dhcp
from homeassistant.components.vicare.const import DOMAIN
from homeassistant.config_entries import SOURCE_DHCP, SOURCE_USER
from homeassistant.config_entries import SOURCE_DHCP, SOURCE_REAUTH, SOURCE_USER
from homeassistant.const import CONF_CLIENT_ID, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
......@@ -93,6 +93,61 @@ async def test_user_create_entry(
mock_setup_entry.assert_called_once()
async def test_step_reauth(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
"""Test reauth flow."""
new_password = "ABCD"
new_client_id = "EFGH"
config_entry = MockConfigEntry(
domain=DOMAIN,
data=VALID_CONFIG,
)
config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH, "entry_id": config_entry.entry_id},
data=VALID_CONFIG,
)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "reauth_confirm"
# test PyViCareInvalidConfigurationError
with patch(
f"{MODULE}.config_flow.vicare_login",
side_effect=PyViCareInvalidConfigurationError(
{"error": "foo", "error_description": "bar"}
),
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_PASSWORD: new_password, CONF_CLIENT_ID: new_client_id},
)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "reauth_confirm"
assert result["errors"] == {"base": "invalid_auth"}
# test success
with patch(
f"{MODULE}.config_flow.vicare_login",
return_value=None,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_PASSWORD: new_password, CONF_CLIENT_ID: new_client_id},
)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "reauth_successful"
assert len(hass.config_entries.async_entries()) == 1
assert (
hass.config_entries.async_entries()[0].data[CONF_PASSWORD] == new_password
)
assert (
hass.config_entries.async_entries()[0].data[CONF_CLIENT_ID] == new_client_id
)
await hass.async_block_till_done()
async def test_form_dhcp(
hass: HomeAssistant, mock_setup_entry: AsyncMock, snapshot: SnapshotAssertion
) -> None:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment