mirror of
https://github.com/home-assistant/core.git
synced 2026-02-24 03:47:14 +00:00
Reconfiguration support for webhook flow helper (#151729)
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to the [webhook service of Dialogflow]({dialogflow_url}) and update the webhook with following settings:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) for further details.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send events to Home Assistant, you will need to set up the [webhook service of Dialogflow]({dialogflow_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) for further details."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Are you sure you want to reconfigure Dialogflow?",
|
||||
"title": "Reconfigure Dialogflow webhook"
|
||||
},
|
||||
"user": {
|
||||
"description": "Are you sure you want to set up Dialogflow?",
|
||||
"title": "Set up the Dialogflow webhook"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to the webhook feature in Geofency and update the webhook with the following settings:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send events to Home Assistant, you will need to set up the webhook feature in Geofency.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Are you sure you want to reconfigure the Geofency webhook?",
|
||||
"title": "Reconfigure Geofency webhook"
|
||||
},
|
||||
"user": {
|
||||
"description": "Are you sure you want to set up the Geofency webhook?",
|
||||
"title": "Set up the Geofency webhook"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to the webhook feature in GPSLogger and update the webhook with the following settings:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send events to Home Assistant, you will need to set up the webhook feature in GPSLogger.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Are you sure you want to reconfigure the GPSLogger webhook?",
|
||||
"title": "Reconfigure GPSLogger webhook"
|
||||
},
|
||||
"user": {
|
||||
"description": "Are you sure you want to set up the GPSLogger webhook?",
|
||||
"title": "Set up the GPSLogger webhook"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to the \"Make a web request\" action from the [IFTTT webhook applet]({applet_url}) and update the webhook with the following settings:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send events to Home Assistant, you will need to use the \"Make a web request\" action from the [IFTTT webhook applet]({applet_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Are you sure you want to reconfigure IFTTT?",
|
||||
"title": "Reconfigure IFTTT webhook applet"
|
||||
},
|
||||
"user": {
|
||||
"description": "Are you sure you want to set up IFTTT?",
|
||||
"title": "Set up the IFTTT webhook applet"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to webhooks in the Locative app and update webhook with the following settings:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send locations to Home Assistant, you will need to set up the webhook feature in the Locative app.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Do you want to start reconfiguration?",
|
||||
"title": "Reconfigure Locative webhook"
|
||||
},
|
||||
"user": {
|
||||
"description": "[%key:common::config_flow::description::confirm_setup%]",
|
||||
"title": "Set up the Locative webhook"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to [webhooks in Mailgun]({mailgun_url}) and update the webhook with the following settings:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send events to Home Assistant, you will need to set up a [webhook with Mailgun]({mailgun_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Are you sure you want to reconfigure Mailgun?",
|
||||
"title": "Reconfigure Mailgun webhook"
|
||||
},
|
||||
"user": {
|
||||
"description": "Are you sure you want to set up Mailgun?",
|
||||
"title": "Set up the Mailgun webhook"
|
||||
|
||||
@@ -2,12 +2,17 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nIn Sleep as Android go to *Settings → Services → Automation → Webhooks* and update the webhook with the following URL:\n\n`{webhook_url}`",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "To send events to Home Assistant, you will need to set up a webhook.\n\nOpen Sleep as Android and go to *Settings → Services → Automation → Webhooks*\n\nEnable *Webhooks* and fill in the following webhook in the URL field:\n\n`{webhook_url}`\n\nSee [the documentation]({docs_url}) for further details."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Are you sure you want to reconfigure the Sleep as Android integration?",
|
||||
"title": "Reconfigure Sleep as Android"
|
||||
},
|
||||
"user": {
|
||||
"description": "Are you sure you want to set up the Sleep as Android integration?",
|
||||
"title": "Set up Sleep as Android"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to webhooks in the Traccar Client and update the webhook with the following URL: `{webhook_url}`\n\nSee [the documentation]({docs_url}) for further details.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send events to Home Assistant, you will need to set up the webhook feature in Traccar Client.\n\nUse the following URL: `{webhook_url}`\n\nSee [the documentation]({docs_url}) for further details."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Are you sure you want to reconfigure the Traccar Client?",
|
||||
"title": "Reconfigure Traccar Client"
|
||||
},
|
||||
"user": {
|
||||
"description": "Are you sure you want to set up Traccar Client?",
|
||||
"title": "Set up Traccar Client"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"config": {
|
||||
"abort": {
|
||||
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
|
||||
"reconfigure_successful": "**Reconfiguration was successful**\n\nGo to [webhooks in Twilio]({twilio_url}) and update the webhook with the following settings:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"webhook_not_internet_accessible": "[%key:common::config_flow::abort::webhook_not_internet_accessible%]"
|
||||
},
|
||||
@@ -9,6 +10,10 @@
|
||||
"default": "To send events to Home Assistant, you will need to set up a [webhook with Twilio]({twilio_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data."
|
||||
},
|
||||
"step": {
|
||||
"reconfigure": {
|
||||
"description": "Do you want to start reconfiguration?",
|
||||
"title": "Reconfigure Twilio webhook"
|
||||
},
|
||||
"user": {
|
||||
"description": "[%key:common::config_flow::description::confirm_setup%]",
|
||||
"title": "Set up the Twilio webhook"
|
||||
|
||||
@@ -215,11 +215,19 @@ class WebhookFlowHandler(config_entries.ConfigFlow):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> config_entries.ConfigFlowResult:
|
||||
"""Handle a user initiated set up flow to create a webhook."""
|
||||
if not self._allow_multiple and self._async_current_entries():
|
||||
if (
|
||||
not self._allow_multiple
|
||||
and self._async_current_entries()
|
||||
and self.source != config_entries.SOURCE_RECONFIGURE
|
||||
):
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
|
||||
if user_input is None:
|
||||
return self.async_show_form(step_id="user")
|
||||
return self.async_show_form(
|
||||
step_id="reconfigure"
|
||||
if self.source == config_entries.SOURCE_RECONFIGURE
|
||||
else "user"
|
||||
)
|
||||
|
||||
# Local import to be sure cloud is loaded and setup
|
||||
from homeassistant.components.cloud import ( # noqa: PLC0415
|
||||
@@ -234,7 +242,11 @@ class WebhookFlowHandler(config_entries.ConfigFlow):
|
||||
async_generate_url,
|
||||
)
|
||||
|
||||
webhook_id = async_generate_id()
|
||||
if self.source == config_entries.SOURCE_RECONFIGURE:
|
||||
entry = self._get_reconfigure_entry()
|
||||
webhook_id = entry.data["webhook_id"]
|
||||
else:
|
||||
webhook_id = async_generate_id()
|
||||
|
||||
if "cloud" in self.hass.config.components and async_active_subscription(
|
||||
self.hass
|
||||
@@ -250,12 +262,30 @@ class WebhookFlowHandler(config_entries.ConfigFlow):
|
||||
|
||||
self._description_placeholder["webhook_url"] = webhook_url
|
||||
|
||||
if self.source == config_entries.SOURCE_RECONFIGURE:
|
||||
if self.hass.config_entries.async_update_entry(
|
||||
entry=entry,
|
||||
data={"webhook_id": webhook_id, "cloudhook": cloudhook},
|
||||
):
|
||||
self.hass.config_entries.async_schedule_reload(entry.entry_id)
|
||||
return self.async_abort(
|
||||
reason="reconfigure_successful",
|
||||
description_placeholders=self._description_placeholder,
|
||||
)
|
||||
|
||||
return self.async_create_entry(
|
||||
title=self._title,
|
||||
data={"webhook_id": webhook_id, "cloudhook": cloudhook},
|
||||
description_placeholders=self._description_placeholder,
|
||||
)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> config_entries.ConfigFlowResult:
|
||||
"""Handle a user initiated flow to re-configure a webhook."""
|
||||
|
||||
return await self.async_step_user(user_input)
|
||||
|
||||
|
||||
def register_webhook_flow(
|
||||
domain: str, title: str, description_placeholder: dict, allow_multiple: bool = False
|
||||
|
||||
@@ -510,3 +510,90 @@ async def test_webhook_create_cloudhook_aborts_not_connected(
|
||||
|
||||
assert result["type"] == data_entry_flow.FlowResultType.ABORT
|
||||
assert result["reason"] == "cloud_not_connected"
|
||||
|
||||
|
||||
async def test_webhook_reconfigure_flow(
|
||||
hass: HomeAssistant, webhook_flow_conf: None
|
||||
) -> None:
|
||||
"""Test webhook reconfigure flow."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain="test_single", data={"webhook_id": "12345", "cloudhook": False}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
flow = config_entries.HANDLERS["test_single"]()
|
||||
flow.hass = hass
|
||||
flow.context = {
|
||||
"source": config_entries.SOURCE_RECONFIGURE,
|
||||
"entry_id": config_entry.entry_id,
|
||||
}
|
||||
|
||||
await async_process_ha_core_config(
|
||||
hass,
|
||||
{"external_url": "https://example.com"},
|
||||
)
|
||||
|
||||
result = await flow.async_step_reconfigure()
|
||||
assert result["type"] is data_entry_flow.FlowResultType.FORM
|
||||
assert result["step_id"] == "reconfigure"
|
||||
|
||||
result = await flow.async_step_reconfigure(user_input={})
|
||||
|
||||
assert result["type"] == data_entry_flow.FlowResultType.ABORT
|
||||
assert result["reason"] == "reconfigure_successful"
|
||||
assert result["description_placeholders"] == {
|
||||
"webhook_url": "https://example.com/api/webhook/12345"
|
||||
}
|
||||
assert config_entry.data["webhook_id"] == "12345"
|
||||
assert config_entry.data["cloudhook"] is False
|
||||
|
||||
|
||||
async def test_webhook_reconfigure_cloudhook(
|
||||
hass: HomeAssistant, webhook_flow_conf: None
|
||||
) -> None:
|
||||
"""Test reconfigure updates to cloudhook if subscribed."""
|
||||
assert await setup.async_setup_component(hass, "cloud", {})
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
domain="test_single", data={"webhook_id": "12345", "cloudhook": False}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
flow = config_entries.HANDLERS["test_single"]()
|
||||
flow.hass = hass
|
||||
flow.context = {
|
||||
"source": config_entries.SOURCE_RECONFIGURE,
|
||||
"entry_id": config_entry.entry_id,
|
||||
}
|
||||
|
||||
result = await flow.async_step_reconfigure()
|
||||
assert result["type"] is data_entry_flow.FlowResultType.FORM
|
||||
assert result["step_id"] == "reconfigure"
|
||||
|
||||
with (
|
||||
patch(
|
||||
"hass_nabucasa.cloudhooks.Cloudhooks.async_create",
|
||||
return_value={"cloudhook_url": "https://example.com"},
|
||||
) as mock_create,
|
||||
patch(
|
||||
"hass_nabucasa.Cloud.subscription_expired",
|
||||
new_callable=PropertyMock(return_value=False),
|
||||
),
|
||||
patch(
|
||||
"hass_nabucasa.Cloud.is_logged_in",
|
||||
new_callable=PropertyMock(return_value=True),
|
||||
),
|
||||
patch(
|
||||
"hass_nabucasa.iot_base.BaseIoT.connected",
|
||||
new_callable=PropertyMock(return_value=True),
|
||||
),
|
||||
):
|
||||
result = await flow.async_step_reconfigure(user_input={})
|
||||
|
||||
assert result["type"] == data_entry_flow.FlowResultType.ABORT
|
||||
assert result["reason"] == "reconfigure_successful"
|
||||
assert result["description_placeholders"] == {"webhook_url": "https://example.com"}
|
||||
assert len(mock_create.mock_calls) == 1
|
||||
|
||||
assert config_entry.data["webhook_id"] == "12345"
|
||||
assert config_entry.data["cloudhook"] is True
|
||||
|
||||
Reference in New Issue
Block a user