Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 90 additions & 9 deletions homeassistant/components/plex/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,33 @@
from homeassistant import config_entries
from homeassistant.components.http.view import HomeAssistantView
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
from homeassistant.const import CONF_TOKEN, CONF_URL, CONF_VERIFY_SSL
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
CONF_SSL,
CONF_TOKEN,
CONF_URL,
CONF_VERIFY_SSL,
)
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv

from .const import ( # pylint: disable=unused-import
AUTH_CALLBACK_NAME,
AUTH_CALLBACK_PATH,
AUTOMATIC_SETUP_STRING,
CONF_CLIENT_IDENTIFIER,
CONF_IGNORE_NEW_SHARED_USERS,
CONF_MONITORED_USERS,
CONF_SERVER,
CONF_SERVER_IDENTIFIER,
CONF_USE_EPISODE_ART,
DEFAULT_PORT,
DEFAULT_SSL,
DEFAULT_VERIFY_SSL,
DOMAIN,
MANUAL_SETUP_STRING,
PLEX_SERVER_CONFIG,
SERVERS,
X_PLEX_DEVICE_NAME,
Expand Down Expand Up @@ -68,14 +79,77 @@ def __init__(self):
self.plexauth = None
self.token = None
self.client_id = None
self._manual = False

async def async_step_user(self, user_input=None):
async def async_step_user(self, user_input=None, errors=None):
"""Handle a flow initialized by the user."""
return self.async_show_form(step_id="start_website_auth")
if user_input is not None:
return await self.async_step_plex_website_auth()
if self.show_advanced_options:
return await self.async_step_user_advanced(errors=errors)
return self.async_show_form(step_id="user", errors=errors)

async def async_step_start_website_auth(self, user_input=None):
"""Show a form before starting external authentication."""
return await self.async_step_plex_website_auth()
async def async_step_user_advanced(self, user_input=None, errors=None):
"""Handle an advanced mode flow initialized by the user."""
if user_input is not None:
if user_input.get("setup_method") == MANUAL_SETUP_STRING:
self._manual = True
return await self.async_step_manual_setup()
return await self.async_step_plex_website_auth()

data_schema = vol.Schema(
{
vol.Required("setup_method", default=AUTOMATIC_SETUP_STRING): vol.In(
[AUTOMATIC_SETUP_STRING, MANUAL_SETUP_STRING]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh idea. We could call async_get_translations from helpers/translation.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I guess we don't have the used language, never mind.

Copy link
Copy Markdown
Member

@balloob balloob May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a better solution for translating a vol.In (in a future PR)

)
}
)
return self.async_show_form(
step_id="user_advanced", data_schema=data_schema, errors=errors
)

async def async_step_manual_setup(self, user_input=None, errors=None):
"""Begin manual configuration."""
if user_input is not None and errors is None:
user_input.pop(CONF_URL, None)
host = user_input.get(CONF_HOST)
if host:
port = user_input[CONF_PORT]
prefix = "https" if user_input.get(CONF_SSL) else "http"
user_input[CONF_URL] = f"{prefix}://{host}:{port}"
elif CONF_TOKEN not in user_input:
return await self.async_step_manual_setup(
user_input=user_input, errors={"base": "host_or_token"}
)
return await self.async_step_server_validate(user_input)

previous_input = user_input or {}

data_schema = vol.Schema(
{
vol.Optional(
CONF_HOST,
description={"suggested_value": previous_input.get(CONF_HOST)},
): str,
vol.Required(
CONF_PORT, default=previous_input.get(CONF_PORT, DEFAULT_PORT)
): int,
vol.Required(
CONF_SSL, default=previous_input.get(CONF_SSL, DEFAULT_SSL)
): bool,
vol.Required(
CONF_VERIFY_SSL,
default=previous_input.get(CONF_VERIFY_SSL, DEFAULT_VERIFY_SSL),
): bool,
vol.Optional(
CONF_TOKEN,
description={"suggested_value": previous_input.get(CONF_TOKEN)},
): str,
}
)
return self.async_show_form(
step_id="manual_setup", data_schema=data_schema, errors=errors
)

async def async_step_server_validate(self, server_config):
"""Validate a provided configuration."""
Expand All @@ -95,13 +169,16 @@ async def async_step_server_validate(self, server_config):
errors["base"] = "no_servers"
except (plexapi.exceptions.BadRequest, plexapi.exceptions.Unauthorized):
_LOGGER.error("Invalid credentials provided, config not created")
errors["base"] = "faulty_credentials"
errors[CONF_TOKEN] = "faulty_credentials"
except requests.exceptions.SSLError as error:
_LOGGER.error("SSL certificate error: [%s]", error)
errors["base"] = "ssl_error"
except (plexapi.exceptions.NotFound, requests.exceptions.ConnectionError):
server_identifier = (
server_config.get(CONF_URL) or plex_server.server_choice or "Unknown"
)
_LOGGER.error("Plex server could not be reached: %s", server_identifier)
errors["base"] = "not_found"
errors[CONF_HOST] = "not_found"

except ServerNotSpecified as available_servers:
if is_importing:
Expand All @@ -119,7 +196,11 @@ async def async_step_server_validate(self, server_config):
if errors:
if is_importing:
return self.async_abort(reason="non-interactive")
return self.async_show_form(step_id="start_website_auth", errors=errors)
if self._manual:
return await self.async_step_manual_setup(
user_input=server_config, errors=errors
)
return await self.async_step_user(errors=errors)

server_id = plex_server.machine_identifier

Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/plex/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@
X_PLEX_PLATFORM = "Home Assistant"
X_PLEX_PRODUCT = "Home Assistant"
X_PLEX_VERSION = __version__

AUTOMATIC_SETUP_STRING = "Obtain a new token from plex.tv"
MANUAL_SETUP_STRING = "Configure Plex server manually"
2 changes: 2 additions & 0 deletions homeassistant/components/plex/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ def _update_plexdirect_hostname():
)
_update_plexdirect_hostname()
config_entry_update_needed = True
else:
raise
else:
raise
else:
Expand Down
32 changes: 25 additions & 7 deletions homeassistant/components/plex/strings.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
{
"config": {
"step": {
"user": {
"title": "Plex Media Server",
"description": "Continue to [plex.tv](https://plex.tv) to link a Plex server."
},
"user_advanced": {
"title": "Plex Media Server",
"data": {
"setup_method": "Setup method"
}
},
"manual_setup": {
"title": "Manual Plex Configuration",
"data": {
"host": "Host (Optional if Token provided)",
"port": "Port",
"ssl": "Use SSL",
"verify_ssl": "Verify SSL certificate",
"token": "Token (Optional)"
}
},
"select_server": {
"title": "Select Plex server",
"description": "Multiple servers available, select one:",
"data": { "server": "Server" }
},
"start_website_auth": {
"title": "Connect Plex server",
"description": "Continue to authorize at plex.tv."
}
},
"error": {
"faulty_credentials": "Authorization failed",
"no_servers": "No servers linked to account",
"not_found": "Plex server not found"
"faulty_credentials": "Authorization failed, verify Token",
"host_or_token": "Must provide at least one of Host or Token",
"no_servers": "No servers linked to Plex account",
"not_found": "Plex server not found",
"ssl_error": "SSL certificate issue"
},
"abort": {
"all_configured": "All linked servers already configured",
Expand Down
Loading