Skip to content

Commit

Permalink
Fix #51 - config_flow object was not initialized correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
elad-bar committed Apr 19, 2020
1 parent 75e0997 commit 6a0ea6a
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 149 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 2020-04-19

**Fixed bugs:**

- Fix issue [\#51](https://github.com/elad-bar/ha-bleuiris/issues/51) in config_flow
- Validation of server existence made 2 calls to server instead of 1

## 2020-04-18

**Implemented enhancements:**
Expand Down
52 changes: 30 additions & 22 deletions custom_components/blueiris/api/blue_iris_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import json
import hashlib
import logging
from typing import Optional

import aiohttp

from datetime import datetime
Expand All @@ -21,7 +23,7 @@ class BlueIrisApi:
"""The Class for handling the data retrieval."""

is_logged_in: bool
session_id: str
session_id: Optional[str]
session: ClientSession
data: dict
status: dict
Expand All @@ -36,6 +38,7 @@ def __init__(self, hass: HomeAssistant, config_manager: ConfigManager):
self._last_update = datetime.now()
self.hass = hass
self.config_manager = config_manager
self.session_id = None

except Exception as ex:
exc_type, exc_obj, tb = sys.exc_info()
Expand Down Expand Up @@ -134,7 +137,11 @@ async def load_session_id(self):

response = await self.async_post(request_data)

self.session_id = response.get("session")
self.session_id = None

if response is not None:
self.session_id = response.get("session")

self.is_logged_in = False

async def login(self):
Expand All @@ -145,33 +152,34 @@ async def login(self):
try:
await self.load_session_id()

config_data = self.config_manager.data
username = config_data.username
password = config_data.password_clear_text
if self.session_id is not None:
config_data = self.config_manager.data
username = config_data.username
password = config_data.password_clear_text

token_request = f"{username}:{self.session_id}:{password}"
m = hashlib.md5()
m.update(token_request.encode('utf-8'))
token = m.hexdigest()
token_request = f"{username}:{self.session_id}:{password}"
m = hashlib.md5()
m.update(token_request.encode('utf-8'))
token = m.hexdigest()

request_data = {
"cmd": "login",
"session": self.session_id,
"response": token
}
request_data = {
"cmd": "login",
"session": self.session_id,
"response": token
}

result = await self.async_post(request_data)
result = await self.async_post(request_data)

if result is not None:
result_status = result.get("result")
if result is not None:
result_status = result.get("result")

if result_status == "success":
logged_in = True
if result_status == "success":
logged_in = True

data = result.get("data", {})
data = result.get("data", {})

for key in data:
self.data[key] = data[key]
for key in data:
self.data[key] = data[key]

except Exception as ex:
exc_type, exc_obj, tb = sys.exc_info()
Expand Down
153 changes: 26 additions & 127 deletions custom_components/blueiris/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,27 @@

from homeassistant import config_entries
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import callback, HomeAssistant
from homeassistant.core import callback

from . import get_ha
from .managers.configuration_manager import ConfigManager
from .managers.password_manager import PasswordManager
from .api.blue_iris_api import BlueIrisApi
from .managers.config_flow_manager import ConfigFlowManager
from .helpers.const import *
from .models.config_data import ConfigData

_LOGGER = logging.getLogger(__name__)


class BlueIrisConfigFlow:
config_manager: ConfigManager
password_manager: PasswordManager
is_initialized: bool = False

def initialize(self, hass: HomeAssistant):
if not self.is_initialized:
self.password_manager = PasswordManager(hass)
self.config_manager = ConfigManager(self.password_manager)

self.is_initialized = True

def update_config_data(self, data: dict, options: dict = None):
entry = ConfigEntry(0, "", "", data, "", "", {}, options=options)

self.config_manager.update(entry)

async def valid_login(self, hass):
errors = None

config_data = self.config_manager.data

api = BlueIrisApi(hass, self.config_manager)
await api.initialize()

if not api.is_logged_in:
_LOGGER.warning(f"Failed to access BlueIris Server ({config_data.host})")
errors = {
"base": "invalid_server_details"
}
else:
has_credentials = config_data.has_credentials

if has_credentials and not api.data.get("admin", False):
_LOGGER.warning(f"Failed to login BlueIris ({config_data.host}) due to invalid credentials")
errors = {
"base": "invalid_admin_credentials"
}

return {
"logged-in": errors is None,
"errors": errors
}


@config_entries.HANDLERS.register(DOMAIN)
class BlueIrisFlowHandler(config_entries.ConfigFlow, BlueIrisConfigFlow):
class BlueIrisFlowHandler(config_entries.ConfigFlow):
"""Handle a BlueIris config flow."""

VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL

def __init__(self):
super().__init__()

self._config_flow = ConfigFlowManager()

@staticmethod
@callback
def async_get_options_flow(config_entry):
Expand All @@ -84,21 +41,17 @@ async def async_step_user(self, user_input=None):

errors = None

self.initialize(self.hass)
self._config_flow.initialize(self.hass)

if user_input is not None:
if CONF_PASSWORD in user_input:
password = user_input[CONF_PASSWORD]
user_input[CONF_PASSWORD] = self.password_manager.encrypt(password)

self.update_config_data(user_input)
self._config_flow.update_data(user_input, True)

host = self._config_flow.config_data.host

ha = get_ha(self.hass, host)

if ha is None:
result = await self.valid_login(self.hass)
result = await self._config_flow.valid_login(self.hass)
errors = result.get("errors")
else:
_LOGGER.warning(f"{DEFAULT_NAME} ({host}) already configured")
Expand All @@ -107,106 +60,52 @@ async def async_step_user(self, user_input=None):
description_placeholders=user_input)

if errors is None:
return self.async_create_entry(title=self.config_manager.data.host, data=user_input)
return self.async_create_entry(title=self._config_flow.config_data.host, data=user_input)

data_schema = self._config_flow.get_default_data()

return self.async_show_form(step_id="user", data_schema=vol.Schema(CONFIG_FIELDS), errors=errors)
return self.async_show_form(step_id="user", data_schema=data_schema, errors=errors)

async def async_step_import(self, info):
"""Import existing configuration from BlueIris."""
_LOGGER.debug(f"Starting async_step_import of {DOMAIN}")
title = f"{DEFAULT_NAME} (import from configuration.yaml)"

return self.async_create_entry(
title="BlueIris (import from configuration.yaml)",
data={
CONF_HOST: info.get(CONF_HOST),
CONF_PORT: info.get(CONF_PORT, DEFAULT_PORT),
CONF_USERNAME: info.get(CONF_USERNAME, ""),
CONF_PASSWORD: info.get(CONF_PASSWORD, ""),
CONF_SSL: info.get(CONF_SSL)
},
)
return self.async_create_entry(title=title, data=info)


class BlueIrisOptionsFlowHandler(config_entries.OptionsFlow, BlueIrisConfigFlow):
class BlueIrisOptionsFlowHandler(config_entries.OptionsFlow):
"""Handle BlueIris options."""

def __init__(self, config_entry: ConfigEntry):
"""Initialize BlueIris options flow."""
super().__init__()

self.options = {}
self._data = {}

for key in config_entry.options.keys():
self.options[key] = config_entry.options[key]

for key in config_entry.data.keys():
self._data[key] = config_entry.data[key]
self._config_flow = ConfigFlowManager(config_entry)

async def async_step_init(self, user_input=None):
"""Manage the EdgeOS options."""
"""Manage the BlueIris options."""
return await self.async_step_blue_iris_additional_settings(user_input)

def get_value(self, key, default=None):
if default is None:
default = ""

value = self._data.get(key, default)

if key in self.options:
value = self.options.get(key, False)

return value

async def async_step_blue_iris_additional_settings(self, user_input=None):
errors = None

self.initialize(self.hass)
self._config_flow.initialize(self.hass)

if user_input is not None:
clear_credentials = user_input.get(CONF_CLEAR_CREDENTIALS, False)

if clear_credentials:
del user_input[CONF_USERNAME]
del user_input[CONF_PASSWORD]
else:
if CONF_PASSWORD in user_input:
password = user_input[CONF_PASSWORD]
user_input[CONF_PASSWORD] = self.password_manager.encrypt(password)

self.update_config_data(self._data, user_input)
self._config_flow.update_options(user_input, True)

result = await self.valid_login(self.hass)
result = await self._config_flow.valid_login(self.hass)
errors = result.get("errors")

if errors is None:
return self.async_create_entry(title="", data=user_input)

self.update_config_data(self._data, self.options)
config_data = self.config_manager.data

options = {
CONF_USERNAME: config_data.username,
CONF_PASSWORD: config_data.password_clear_text,
CONF_EXCLUDE_SYSTEM_CAMERA: config_data.exclude_system_camera
}

fields = {}
for option in options:
current_value = options[option]
obj_type = str
if option in [CONF_EXCLUDE_SYSTEM_CAMERA, CONF_CLEAR_CREDENTIALS]:
obj_type = bool

fields[vol.Optional(option, default=current_value)] = obj_type

fields[vol.Optional(CONF_CLEAR_CREDENTIALS, default=False)] = bool
data_schema = self._config_flow.get_default_options()

return self.async_show_form(
step_id="blue_iris_additional_settings",
data_schema=vol.Schema(fields),
data_schema=data_schema,
errors=errors,
description_placeholders={
CONF_HOST: config_data.host
}
description_placeholders=self._config_flow.data
)
Loading

0 comments on commit 6a0ea6a

Please sign in to comment.