Mobile App: Support rendering multiple templates at once (#21851)

* Support rendering multiple templates at once

* Only catch TemplateError and dont log the error
This commit is contained in:
Robbie Trencheny 2019-03-13 15:33:37 -07:00 committed by GitHub
parent acc44aaf6c
commit 5ef602bc2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 29 additions and 26 deletions

View File

@ -43,7 +43,6 @@ ATTR_WEBHOOK_TYPE = 'type'
ERR_ENCRYPTION_REQUIRED = 'encryption_required'
ERR_INVALID_COMPONENT = 'invalid_component'
ERR_RENDER_FAILURE = 'render_failure'
ERR_SAVE_FAILURE = 'save_failure'
WEBHOOK_TYPE_CALL_SERVICE = 'call_service'
@ -99,8 +98,10 @@ FIRE_EVENT_SCHEMA = vol.Schema({
})
RENDER_TEMPLATE_SCHEMA = vol.Schema({
vol.Required(ATTR_TEMPLATE): cv.string,
vol.Optional(ATTR_TEMPLATE_VARIABLES, default={}): dict,
str: {
vol.Required(ATTR_TEMPLATE): cv.template,
vol.Optional(ATTR_TEMPLATE_VARIABLES, default={}): dict,
}
})
WEBHOOK_SCHEMAS = {

View File

@ -15,7 +15,7 @@ from homeassistant.const import (ATTR_DOMAIN, ATTR_SERVICE, ATTR_SERVICE_DATA,
from homeassistant.core import EventOrigin
from homeassistant.exceptions import (HomeAssistantError, ServiceNotFound,
TemplateError)
from homeassistant.helpers import template
from homeassistant.helpers.template import attach
from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import HomeAssistantType
@ -26,10 +26,9 @@ from .const import (ATTR_APP_COMPONENT, ATTR_DEVICE_NAME, ATTR_EVENT_DATA,
ATTR_WEBHOOK_ENCRYPTED, ATTR_WEBHOOK_ENCRYPTED_DATA,
ATTR_WEBHOOK_TYPE, CONF_SECRET, DATA_DELETED_IDS,
DATA_REGISTRATIONS, DOMAIN, ERR_ENCRYPTION_REQUIRED,
ERR_RENDER_FAILURE, WEBHOOK_PAYLOAD_SCHEMA,
WEBHOOK_SCHEMAS, WEBHOOK_TYPE_CALL_SERVICE,
WEBHOOK_TYPE_FIRE_EVENT, WEBHOOK_TYPE_RENDER_TEMPLATE,
WEBHOOK_TYPE_UPDATE_LOCATION,
WEBHOOK_PAYLOAD_SCHEMA, WEBHOOK_SCHEMAS,
WEBHOOK_TYPE_CALL_SERVICE, WEBHOOK_TYPE_FIRE_EVENT,
WEBHOOK_TYPE_RENDER_TEMPLATE, WEBHOOK_TYPE_UPDATE_LOCATION,
WEBHOOK_TYPE_UPDATE_REGISTRATION)
from .helpers import (_decrypt_payload, empty_okay_response, error_response,
@ -132,17 +131,18 @@ async def handle_webhook(store: Store, hass: HomeAssistantType,
return empty_okay_response(headers=headers)
if webhook_type == WEBHOOK_TYPE_RENDER_TEMPLATE:
try:
tpl = template.Template(data[ATTR_TEMPLATE], hass)
rendered = tpl.async_render(data.get(ATTR_TEMPLATE_VARIABLES))
return webhook_response({"rendered": rendered},
registration=registration, headers=headers)
# noqa: E722 pylint: disable=broad-except
except (ValueError, TemplateError, Exception) as ex:
_LOGGER.error("Error when rendering template during mobile_app "
"webhook (device name: %s): %s",
registration[ATTR_DEVICE_NAME], ex)
return error_response(ERR_RENDER_FAILURE, str(ex), headers=headers)
resp = {}
for key, item in data.items():
try:
tpl = item[ATTR_TEMPLATE]
attach(hass, tpl)
resp[key] = tpl.async_render(item.get(ATTR_TEMPLATE_VARIABLES))
# noqa: E722 pylint: disable=broad-except
except TemplateError as ex:
resp[key] = {"error": str(ex)}
return webhook_response(resp, registration=registration,
headers=headers)
if webhook_type == WEBHOOK_TYPE_UPDATE_LOCATION:
try:

View File

@ -49,7 +49,9 @@ REGISTER_CLEARTEXT = {
RENDER_TEMPLATE = {
'type': 'render_template',
'data': {
'template': 'Hello world'
'one': {
'template': 'Hello world'
}
}
}

View File

@ -5,7 +5,7 @@ import pytest
from homeassistant.components.mobile_app.const import CONF_SECRET
from homeassistant.const import CONF_WEBHOOK_ID
from .const import REGISTER
from .const import REGISTER, RENDER_TEMPLATE
from . import authed_api_client # noqa: F401
@ -35,7 +35,7 @@ async def test_registration(hass_client, authed_api_client): # noqa: F811
key = key[:keylen]
key = key.ljust(keylen, b'\0')
payload = json.dumps({'template': 'Hello world'}).encode("utf-8")
payload = json.dumps(RENDER_TEMPLATE['data']).encode("utf-8")
data = SecretBox(key).encrypt(payload,
encoder=Base64Encoder).decode("utf-8")
@ -62,7 +62,7 @@ async def test_registration(hass_client, authed_api_client): # noqa: F811
encoder=Base64Encoder)
decrypted_data = decrypted_data.decode("utf-8")
assert json.loads(decrypted_data) == {'rendered': 'Hello world'}
assert json.loads(decrypted_data) == {'one': 'Hello world'}
async def test_register_invalid_component(authed_api_client): # noqa: F811

View File

@ -24,7 +24,7 @@ async def test_webhook_handle_render_template(webhook_client): # noqa: F811
assert resp.status == 200
json = await resp.json()
assert json == {'rendered': 'Hello world'}
assert json == {'one': 'Hello world'}
async def test_webhook_handle_call_services(hass, webhook_client): # noqa: E501 F811
@ -123,7 +123,7 @@ async def test_webhook_handle_decryption(webhook_client): # noqa: F811
key = key[:keylen]
key = key.ljust(keylen, b'\0')
payload = json.dumps({'template': 'Hello world'}).encode("utf-8")
payload = json.dumps(RENDER_TEMPLATE['data']).encode("utf-8")
data = SecretBox(key).encrypt(payload,
encoder=Base64Encoder).decode("utf-8")
@ -148,7 +148,7 @@ async def test_webhook_handle_decryption(webhook_client): # noqa: F811
encoder=Base64Encoder)
decrypted_data = decrypted_data.decode("utf-8")
assert json.loads(decrypted_data) == {'rendered': 'Hello world'}
assert json.loads(decrypted_data) == {'one': 'Hello world'}
async def test_webhook_requires_encryption(webhook_client): # noqa: F811