Validate URL

This commit is contained in:
Erik 2023-01-17 16:33:19 +01:00
parent eea98b22e0
commit 5d21b6e7a7
6 changed files with 78 additions and 11 deletions

View File

@ -1,12 +1,14 @@
"""Config flow for the Open Thread Border Router integration.""" """Config flow for the Open Thread Border Router integration."""
from __future__ import annotations from __future__ import annotations
import python_otbr_api
import voluptuous as vol import voluptuous as vol
from homeassistant.components.hassio import HassioServiceInfo from homeassistant.components.hassio import HassioServiceInfo
from homeassistant.config_entries import ConfigFlow from homeassistant.config_entries import ConfigFlow
from homeassistant.const import CONF_URL from homeassistant.const import CONF_URL
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN from .const import DOMAIN
@ -23,14 +25,26 @@ class OTBRConfigFlow(ConfigFlow, domain=DOMAIN):
if self._async_current_entries(): if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")
errors = {}
if user_input is not None: if user_input is not None:
return self.async_create_entry( url = user_input[CONF_URL]
title="Thread", api = python_otbr_api.OTBR(url, async_get_clientsession(self.hass), 10)
data={"url": user_input[CONF_URL]}, try:
) await api.get_active_dataset_tlvs()
except python_otbr_api.OTBRError:
errors["base"] = "cannot_connect"
else:
await self.async_set_unique_id(url)
return self.async_create_entry(
title="Thread",
data={"url": url},
)
data_schema = vol.Schema({CONF_URL: str}) data_schema = vol.Schema({CONF_URL: str})
return self.async_show_form(step_id="user", data_schema=data_schema) return self.async_show_form(
step_id="user", data_schema=data_schema, errors=errors
)
async def async_step_hassio(self, discovery_info: HassioServiceInfo) -> FlowResult: async def async_step_hassio(self, discovery_info: HassioServiceInfo) -> FlowResult:
"""Handle hassio discovery.""" """Handle hassio discovery."""
@ -38,7 +52,9 @@ class OTBRConfigFlow(ConfigFlow, domain=DOMAIN):
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")
config = discovery_info.config config = discovery_info.config
url = f"http://{config['host']}:{config['port']}"
await self.async_set_unique_id(url)
return self.async_create_entry( return self.async_create_entry(
title="Thread", title="Thread",
data={"url": f"http://{config['host']}:{config['port']}"}, data={"url": url},
) )

View File

@ -3,7 +3,7 @@
"after_dependencies": ["hassio"], "after_dependencies": ["hassio"],
"domain": "otbr", "domain": "otbr",
"iot_class": "local_polling", "iot_class": "local_polling",
"config_flow": false, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/otbr", "documentation": "https://www.home-assistant.io/integrations/otbr",
"integration_type": "system", "integration_type": "system",
"name": "Thread", "name": "Thread",

View File

@ -8,6 +8,9 @@
"description": "Provide URL for the Open Thread Border Router's REST API" "description": "Provide URL for the Open Thread Border Router's REST API"
} }
}, },
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
},
"abort": { "abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]" "already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
} }

View File

@ -0,0 +1,18 @@
{
"config": {
"abort": {
"already_configured": "Service is already configured"
},
"error": {
"cannot_connect": "Failed to connect"
},
"step": {
"user": {
"data": {
"url": "URL"
},
"description": "Provide URL for the Open Thread Border Router's REST API"
}
}
}
}

View File

@ -304,6 +304,7 @@ FLOWS = {
"openuv", "openuv",
"openweathermap", "openweathermap",
"oralb", "oralb",
"otbr",
"overkiz", "overkiz",
"ovo_energy", "ovo_energy",
"owntracks", "owntracks",

View File

@ -1,4 +1,5 @@
"""Test the Open Thread Border Router config flow.""" """Test the Open Thread Border Router config flow."""
from http import HTTPStatus
from unittest.mock import patch from unittest.mock import patch
from homeassistant.components import hassio, otbr from homeassistant.components import hassio, otbr
@ -6,6 +7,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry, MockModule, mock_integration from tests.common import MockConfigEntry, MockModule, mock_integration
from tests.test_util.aiohttp import AiohttpClientMocker
HASSIO_DATA = hassio.HassioServiceInfo( HASSIO_DATA = hassio.HassioServiceInfo(
config={"host": "blah", "port": "bluh"}, config={"host": "blah", "port": "bluh"},
@ -14,16 +16,20 @@ HASSIO_DATA = hassio.HassioServiceInfo(
) )
async def test_user_flow(hass: HomeAssistant) -> None: async def test_user_flow(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the user flow.""" """Test the user flow."""
url = "http://custom_url:1234"
aioclient_mock.get(f"{url}/node/dataset/active", text="aa")
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
otbr.DOMAIN, context={"source": "user"} otbr.DOMAIN, context={"source": "user"}
) )
expected_data = {"url": "http://custom_url:1234"} expected_data = {"url": url}
assert result["type"] == FlowResultType.FORM assert result["type"] == FlowResultType.FORM
assert result["errors"] is None assert result["errors"] == {}
with patch( with patch(
"homeassistant.components.otbr.async_setup_entry", "homeassistant.components.otbr.async_setup_entry",
@ -32,7 +38,7 @@ async def test_user_flow(hass: HomeAssistant) -> None:
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{ {
"url": "http://custom_url:1234", "url": url,
}, },
) )
assert result["type"] == FlowResultType.CREATE_ENTRY assert result["type"] == FlowResultType.CREATE_ENTRY
@ -48,6 +54,29 @@ async def test_user_flow(hass: HomeAssistant) -> None:
assert config_entry.unique_id is None assert config_entry.unique_id is None
async def test_user_flow_404(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the user flow."""
url = "http://custom_url:1234"
aioclient_mock.get(f"{url}/node/dataset/active", status=HTTPStatus.NOT_FOUND)
result = await hass.config_entries.flow.async_init(
otbr.DOMAIN, context={"source": "user"}
)
assert result["type"] == FlowResultType.FORM
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"url": url,
},
)
assert result["type"] == FlowResultType.FORM
assert result["errors"] == {"base": "cannot_connect"}
async def test_hassio_discovery_flow(hass: HomeAssistant) -> None: async def test_hassio_discovery_flow(hass: HomeAssistant) -> None:
"""Test the hassio discovery flow.""" """Test the hassio discovery flow."""
with patch( with patch(