1 """Onboarding views."""
3 from __future__
import annotations
6 from collections.abc
import Coroutine
7 from http
import HTTPStatus
8 from typing
import TYPE_CHECKING, Any, cast
10 from aiohttp
import web
11 from aiohttp.web_exceptions
import HTTPUnauthorized
12 import voluptuous
as vol
30 from .
import OnboardingData, OnboardingStorage, OnboardingStoreData
44 hass: HomeAssistant, data: OnboardingStoreData, store: OnboardingStorage
46 """Set up the onboarding view."""
56 """Return the onboarding status."""
59 url =
"/api/onboarding"
60 name =
"api:onboarding"
62 def __init__(self, data: OnboardingStoreData, store: OnboardingStorage) ->
None:
63 """Initialize the onboarding view."""
67 async
def get(self, request: web.Request) -> web.Response:
68 """Return the onboarding status."""
70 [{
"step": key,
"done": key
in self.
_data_data[
"done"]}
for key
in STEPS]
75 """Return the installation type during onboarding."""
78 url =
"/api/onboarding/installation_type"
79 name =
"api:onboarding:installation_type"
81 def __init__(self, data: OnboardingStoreData) ->
None:
82 """Initialize the onboarding installation type view."""
85 async
def get(self, request: web.Request) -> web.Response:
86 """Return the onboarding status."""
87 if self.
_data_data[
"done"]:
88 raise HTTPUnauthorized
90 hass = request.app[KEY_HASS]
92 return self.json({
"installation_type": info[
"installation_type"]})
96 """Base class for onboarding."""
100 def __init__(self, data: OnboardingStoreData, store: OnboardingStorage) ->
None:
101 """Initialize the onboarding view."""
108 """Return if this step is done."""
109 return self.step
in self.
_data_data[
"done"]
112 """Mark step as done."""
113 self.
_data_data[
"done"].append(self.step)
116 if set(self.
_data_data[
"done"]) == set(STEPS):
117 data: OnboardingData = hass.data[DOMAIN]
118 data.onboarded =
True
119 for listener
in data.listeners:
124 """View to handle create user onboarding step."""
126 url =
"/api/onboarding/users"
127 name =
"api:onboarding:users"
128 requires_auth =
False
131 @RequestDataValidator(
vol.Schema(
{
vol.Required("name"): str,
132 vol.Required(
"username"): str,
133 vol.Required(
"password"): str,
134 vol.Required(
"client_id"): str,
135 vol.Required(
"language"): str,
139 async
def post(self, request: web.Request, data: dict[str, str]) -> web.Response:
140 """Handle user creation, area creation."""
141 hass = request.app[KEY_HASS]
143 async
with self.
_lock_lock:
145 return self.json_message(
"User step already done", HTTPStatus.FORBIDDEN)
148 await provider.async_initialize()
150 user = await hass.auth.async_create_user(
151 data[
"name"], group_ids=[GROUP_ID_ADMIN]
153 await provider.async_add_auth(data[
"username"], data[
"password"])
154 credentials = await provider.async_get_or_create_credentials(
155 {
"username": data[
"username"]}
157 await hass.auth.async_link_user(user, credentials)
158 if "person" in hass.config.components:
159 await person.async_create_person(hass, data[
"name"], user_id=user.id)
163 hass, data[
"language"],
"area", {DOMAIN}
166 area_registry = ar.async_get(hass)
168 for area
in DEFAULT_AREAS:
169 name = translations[f
"component.onboarding.area.{area}"]
172 if not area_registry.async_get_area_by_name(name):
173 area_registry.async_create(name)
183 return self.json({
"auth_code": auth_code})
187 """View to finish core config onboarding step."""
189 url =
"/api/onboarding/core_config"
190 name =
"api:onboarding:core_config"
191 step = STEP_CORE_CONFIG
193 async
def post(self, request: web.Request) -> web.Response:
194 """Handle finishing core config step."""
195 hass = request.app[KEY_HASS]
197 async
with self.
_lock_lock:
199 return self.json_message(
200 "Core config step already done", HTTPStatus.FORBIDDEN
206 onboard_integrations = [
218 and (core_info := hassio.get_core_info(hass))
219 and "raspberrypi" in core_info[
"machine"]
221 onboard_integrations.append(
"rpi_power")
223 coros: list[Coroutine[Any, Any, Any]] = [
224 hass.config_entries.flow.async_init(
225 domain, context={
"source":
"onboarding"}
227 for domain
in onboard_integrations
230 if "analytics" not in hass.config.components:
238 await asyncio.gather(*(create_eager_task(coro)
for coro
in coros))
244 """View to finish integration onboarding step."""
246 url =
"/api/onboarding/integration"
247 name =
"api:onboarding:integration"
248 step = STEP_INTEGRATION
250 @RequestDataValidator(
vol.Schema({vol.Required("client_id"): str, vol.Required(
"redirect_uri"): str})
252 async
def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
253 """Handle token creation."""
254 hass = request.app[KEY_HASS]
255 refresh_token_id = request[KEY_HASS_REFRESH_TOKEN_ID]
257 async
with self.
_lock_lock:
259 return self.json_message(
260 "Integration step already done", HTTPStatus.FORBIDDEN
266 if not await indieauth.verify_redirect_uri(
267 request.app[KEY_HASS], data[
"client_id"], data[
"redirect_uri"]
269 return self.json_message(
270 "invalid client id or redirect uri", HTTPStatus.BAD_REQUEST
273 refresh_token = hass.auth.async_get_refresh_token(refresh_token_id)
274 if refresh_token
is None or refresh_token.credential
is None:
275 return self.json_message(
276 "Credentials for user not available", HTTPStatus.FORBIDDEN
284 hass, data[
"client_id"], refresh_token.credential
286 return self.json({
"auth_code": auth_code})
290 """View to finish analytics onboarding step."""
292 url =
"/api/onboarding/analytics"
293 name =
"api:onboarding:analytics"
294 step = STEP_ANALYTICS
296 async
def post(self, request: web.Request) -> web.Response:
297 """Handle finishing analytics step."""
298 hass = request.app[KEY_HASS]
302 return self.json_message(
303 "Analytics config step already done", HTTPStatus.FORBIDDEN
313 """Get the Home Assistant auth provider."""
314 for prv
in hass.auth.auth_providers:
315 if prv.type ==
"homeassistant":
316 return cast(HassAuthProvider, prv)
318 raise RuntimeError(
"No Home Assistant provider found")
319
web.Response post(self, web.Request request)
web.Response post(self, web.Request request)
web.Response get(self, web.Request request)
None __init__(self, OnboardingStoreData data)
web.Response post(self, web.Request request, dict[str, Any] data)
None __init__(self, OnboardingStoreData data, OnboardingStorage store)
web.Response get(self, web.Request request)
web.Response post(self, web.Request request, dict[str, str] data)
None _async_mark_done(self, HomeAssistant hass)
bool _async_is_done(self)
None __init__(self, OnboardingStoreData data, OnboardingStorage store)
str create_auth_code(HomeAssistant hass, str client_id, Credentials credential)
bool is_hassio(HomeAssistant hass)
HassAuthProvider _async_get_hass_provider(HomeAssistant hass)
None async_setup(HomeAssistant hass, OnboardingStoreData data, OnboardingStorage store)
None async_save(self, _T data)
dict[str, Any] async_get_system_info(HomeAssistant hass)
dict[str, str] async_get_translations(HomeAssistant hass, str language, str category, Iterable[str]|None integrations=None, bool|None config_flow=None)
bool async_setup_component(core.HomeAssistant hass, str domain, ConfigType config)