Add persistent notification for reauth config flows (#41811)

* add persistent notification for reauth config flow

* remove log

* Update homeassistant/config_entries.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update homeassistant/config_entries.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* fix logic for determining when to dismiss notification

* add comment

* improve tests to ensure notifications only get dismissed when all in progress config flows of a given type are complete

* Update homeassistant/config_entries.py

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* handle context is None when accessing source

* add guard to show_advanced_options

* Apply suggestions from code review

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: Chris Talkington <chris@talkingtontech.com>
This commit is contained in:
Raman Gupta 2020-10-15 16:46:27 -04:00 committed by GitHub
parent a220e74154
commit 0e20bba40a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 3 deletions

View file

@ -78,6 +78,8 @@ DISCOVERY_SOURCES = (
SOURCE_UNIGNORE,
)
RECONFIGURE_NOTIFICATION_ID = "config_entry_reconfigure"
EVENT_FLOW_DISCOVERED = "config_entry_discovered"
CONN_CLASS_CLOUD_PUSH = "cloud_push"
@ -566,6 +568,15 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager):
),
notification_id=DISCOVERY_NOTIFICATION_ID,
)
elif source == SOURCE_REAUTH:
self.hass.components.persistent_notification.async_create(
title="Integration requires reconfiguration",
message=(
"At least one of your integrations requires reconfiguration to "
"continue functioning. [Check it out](/config/integrations)"
),
notification_id=RECONFIGURE_NOTIFICATION_ID,
)
class ConfigEntries:
@ -1004,6 +1015,27 @@ class ConfigFlow(data_entry_flow.FlowHandler):
await self._async_handle_discovery_without_unique_id()
return await self.async_step_user()
@callback
def async_abort(
self, *, reason: str, description_placeholders: Optional[Dict] = None
) -> Dict[str, Any]:
"""Abort the config flow."""
assert self.hass
# Remove reauth notification if no reauth flows are in progress
if self.source == SOURCE_REAUTH and not any(
ent["context"]["source"] == SOURCE_REAUTH
for ent in self.hass.config_entries.flow.async_progress()
if ent["flow_id"] != self.flow_id
):
self.hass.components.persistent_notification.async_dismiss(
RECONFIGURE_NOTIFICATION_ID
)
return super().async_abort(
reason=reason, description_placeholders=description_placeholders
)
async_step_hassio = async_step_discovery
async_step_homekit = async_step_discovery
async_step_mqtt = async_step_discovery

View file

@ -261,11 +261,17 @@ class FlowHandler:
@property
def source(self) -> Optional[str]:
"""Source that initialized the flow."""
if not hasattr(self, "context"):
return None
return self.context.get("source", None)
@property
def show_advanced_options(self) -> bool:
"""If we should show advanced options."""
if not hasattr(self, "context"):
return False
return self.context.get("show_advanced_options", False)
@callback

View file

@ -609,7 +609,8 @@ async def test_discovery_notification(hass):
title="Test Title", data={"token": "abcd"}
)
result = await hass.config_entries.flow.async_init(
# Start first discovery flow to assert that reconfigure notification fires
flow1 = await hass.config_entries.flow.async_init(
"test", context={"source": config_entries.SOURCE_DISCOVERY}
)
@ -617,11 +618,92 @@ async def test_discovery_notification(hass):
state = hass.states.get("persistent_notification.config_entry_discovery")
assert state is not None
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
# Start a second discovery flow so we can finish the first and assert that
# the discovery notification persists until the second one is complete
flow2 = await hass.config_entries.flow.async_init(
"test", context={"source": config_entries.SOURCE_DISCOVERY}
)
flow1 = await hass.config_entries.flow.async_configure(flow1["flow_id"], {})
assert flow1["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
await hass.async_block_till_done()
state = hass.states.get("persistent_notification.config_entry_discovery")
assert state is not None
flow2 = await hass.config_entries.flow.async_configure(flow2["flow_id"], {})
assert flow2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
await hass.async_block_till_done()
state = hass.states.get("persistent_notification.config_entry_discovery")
assert state is None
async def test_reauth_notification(hass):
"""Test that we create/dismiss a notification when source is reauth."""
mock_integration(hass, MockModule("test"))
mock_entity_platform(hass, "config_flow.test", None)
await async_setup_component(hass, "persistent_notification", {})
with patch.dict(config_entries.HANDLERS):
class TestFlow(config_entries.ConfigFlow, domain="test"):
"""Test flow."""
VERSION = 5
async def async_step_user(self, user_input):
"""Test user step."""
return self.async_show_form(step_id="user_confirm")
async def async_step_user_confirm(self, user_input):
"""Test user confirm step."""
return self.async_show_form(step_id="user_confirm")
async def async_step_reauth(self, user_input):
"""Test reauth step."""
return self.async_show_form(step_id="reauth_confirm")
async def async_step_reauth_confirm(self, user_input):
"""Test reauth confirm step."""
return self.async_abort(reason="test")
# Start user flow to assert that reconfigure notification doesn't fire
await hass.config_entries.flow.async_init(
"test", context={"source": config_entries.SOURCE_USER}
)
await hass.async_block_till_done()
state = hass.states.get("persistent_notification.config_entry_reconfigure")
assert state is None
# Start first reauth flow to assert that reconfigure notification fires
flow1 = await hass.config_entries.flow.async_init(
"test", context={"source": config_entries.SOURCE_REAUTH}
)
await hass.async_block_till_done()
state = hass.states.get("persistent_notification.config_entry_reconfigure")
assert state is not None
# Start a second reauth flow so we can finish the first and assert that
# the reconfigure notification persists until the second one is complete
flow2 = await hass.config_entries.flow.async_init(
"test", context={"source": config_entries.SOURCE_REAUTH}
)
flow1 = await hass.config_entries.flow.async_configure(flow1["flow_id"], {})
assert flow1["type"] == data_entry_flow.RESULT_TYPE_ABORT
await hass.async_block_till_done()
state = hass.states.get("persistent_notification.config_entry_reconfigure")
assert state is not None
flow2 = await hass.config_entries.flow.async_configure(flow2["flow_id"], {})
assert flow2["type"] == data_entry_flow.RESULT_TYPE_ABORT
await hass.async_block_till_done()
state = hass.states.get("persistent_notification.config_entry_reconfigure")
assert state is None