Skip to content

Commit a57c65f

Browse files
authored
Add reconfigure flow in Google Drive (#165926)
1 parent 7140826 commit a57c65f

File tree

4 files changed

+108
-8
lines changed

4 files changed

+108
-8
lines changed

homeassistant/components/google_drive/config_flow.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88

99
from google_drive_api.exceptions import GoogleDriveApiError
1010

11-
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult
11+
from homeassistant.config_entries import (
12+
SOURCE_REAUTH,
13+
SOURCE_RECONFIGURE,
14+
ConfigFlowResult,
15+
)
1216
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_TOKEN
1317
from homeassistant.helpers import config_entry_oauth2_flow, instance_id
1418
from homeassistant.helpers.aiohttp_client import async_get_clientsession
@@ -44,6 +48,12 @@ def extra_authorize_data(self) -> dict[str, Any]:
4448
"prompt": "consent",
4549
}
4650

51+
async def async_step_reconfigure(
52+
self, user_input: dict[str, Any] | None = None
53+
) -> ConfigFlowResult:
54+
"""Handle a reconfiguration flow."""
55+
return await self.async_step_user(user_input)
56+
4757
async def async_step_reauth(
4858
self, entry_data: Mapping[str, Any]
4959
) -> ConfigFlowResult:
@@ -81,13 +91,16 @@ async def async_oauth_create_entry(self, data: dict[str, Any]) -> ConfigFlowResu
8191

8292
await self.async_set_unique_id(email_address)
8393

84-
if self.source == SOURCE_REAUTH:
85-
reauth_entry = self._get_reauth_entry()
94+
if self.source in (SOURCE_REAUTH, SOURCE_RECONFIGURE):
95+
if self.source == SOURCE_REAUTH:
96+
entry = self._get_reauth_entry()
97+
else:
98+
entry = self._get_reconfigure_entry()
8699
self._abort_if_unique_id_mismatch(
87100
reason="wrong_account",
88-
description_placeholders={"email": cast(str, reauth_entry.unique_id)},
101+
description_placeholders={"email": cast(str, entry.unique_id)},
89102
)
90-
return self.async_update_reload_and_abort(reauth_entry, data=data)
103+
return self.async_update_reload_and_abort(entry, data=data)
91104

92105
self._abort_if_unique_id_configured()
93106

homeassistant/components/google_drive/quality_scale.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ rules:
6565
entity-translations: done
6666
exception-translations: done
6767
icon-translations: done
68-
reconfiguration-flow:
69-
status: exempt
70-
comment: No configuration options.
68+
reconfiguration-flow: done
7169
repair-issues:
7270
status: exempt
7371
comment: No repairs.

homeassistant/components/google_drive/strings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]",
1919
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
2020
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
21+
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]",
2122
"unknown": "[%key:common::config_flow::error::unknown%]",
2223
"user_rejected_authorize": "[%key:common::config_flow::abort::oauth2_user_rejected_authorize%]",
2324
"wrong_account": "Wrong account: Please authenticate with {email}."

tests/components/google_drive/test_config_flow.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,94 @@ async def test_reauth(
310310
assert config_entry.data["token"].get("refresh_token") == "mock-refresh-token"
311311

312312

313+
@pytest.mark.usefixtures("current_request_with_host")
314+
@pytest.mark.parametrize(
315+
(
316+
"new_email",
317+
"expected_abort_reason",
318+
"expected_placeholders",
319+
"expected_access_token",
320+
"expected_setup_calls",
321+
),
322+
[
323+
(TEST_USER_EMAIL, "reconfigure_successful", None, "updated-access-token", 1),
324+
(
325+
"other.user@domain.com",
326+
"wrong_account",
327+
{"email": TEST_USER_EMAIL},
328+
"mock-access-token",
329+
0,
330+
),
331+
],
332+
ids=["reconfigure_successful", "wrong_account"],
333+
)
334+
async def test_reconfigure(
335+
hass: HomeAssistant,
336+
hass_client_no_auth: ClientSessionGenerator,
337+
config_entry: MockConfigEntry,
338+
aioclient_mock: AiohttpClientMocker,
339+
mock_api: MagicMock,
340+
new_email: str,
341+
expected_abort_reason: str,
342+
expected_placeholders: dict[str, str] | None,
343+
expected_access_token: str,
344+
expected_setup_calls: int,
345+
) -> None:
346+
"""Test the reconfiguration flow."""
347+
config_entry.add_to_hass(hass)
348+
result = await config_entry.start_reconfigure_flow(hass)
349+
350+
state = config_entry_oauth2_flow._encode_jwt(
351+
hass,
352+
{
353+
"flow_id": result["flow_id"],
354+
"redirect_uri": "https://example.com/auth/external/callback",
355+
},
356+
)
357+
assert result["url"] == (
358+
f"{GOOGLE_AUTH_URI}?response_type=code&client_id={CLIENT_ID}"
359+
"&redirect_uri=https://example.com/auth/external/callback"
360+
f"&state={state}&scope=https://www.googleapis.com/auth/drive.file"
361+
"&access_type=offline&prompt=consent"
362+
)
363+
client = await hass_client_no_auth()
364+
resp = await client.get(f"/auth/external/callback?code=abcd&state={state}")
365+
assert resp.status == 200
366+
assert resp.headers["content-type"] == "text/html; charset=utf-8"
367+
368+
# Prepare API responses
369+
mock_api.get_user = AsyncMock(return_value={"user": {"emailAddress": new_email}})
370+
aioclient_mock.post(
371+
GOOGLE_TOKEN_URI,
372+
json={
373+
"refresh_token": "mock-refresh-token",
374+
"access_token": "updated-access-token",
375+
"type": "Bearer",
376+
"expires_in": 60,
377+
},
378+
)
379+
380+
with patch(
381+
"homeassistant.components.google_drive.async_setup_entry", return_value=True
382+
) as mock_setup:
383+
result = await hass.config_entries.flow.async_configure(result["flow_id"])
384+
await hass.async_block_till_done()
385+
386+
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
387+
assert len(mock_setup.mock_calls) == expected_setup_calls
388+
389+
assert result.get("type") is FlowResultType.ABORT
390+
assert result.get("reason") == expected_abort_reason
391+
assert result.get("description_placeholders") == expected_placeholders
392+
393+
assert config_entry.unique_id == TEST_USER_EMAIL
394+
assert "token" in config_entry.data
395+
396+
# Verify access token is refreshed
397+
assert config_entry.data["token"].get("access_token") == expected_access_token
398+
assert config_entry.data["token"].get("refresh_token") == "mock-refresh-token"
399+
400+
313401
@pytest.mark.usefixtures("current_request_with_host")
314402
async def test_already_configured(
315403
hass: HomeAssistant,

0 commit comments

Comments
 (0)