Skip to content

Commit 4ddc43a

Browse files
jpbedefrenck
authored andcommitted
Fix double space quoting in WebDAV (#140364)
1 parent e6dea41 commit 4ddc43a

File tree

9 files changed

+154
-7
lines changed

9 files changed

+154
-7
lines changed

homeassistant/components/webdav/__init__.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
from homeassistant.exceptions import ConfigEntryError, ConfigEntryNotReady
1414

1515
from .const import CONF_BACKUP_PATH, DATA_BACKUP_AGENT_LISTENERS, DOMAIN
16-
from .helpers import async_create_client, async_ensure_path_exists
16+
from .helpers import (
17+
async_create_client,
18+
async_ensure_path_exists,
19+
async_migrate_wrong_folder_path,
20+
)
1721

1822
type WebDavConfigEntry = ConfigEntry[Client]
1923

@@ -46,10 +50,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: WebDavConfigEntry) -> bo
4650
translation_key="cannot_connect",
4751
)
4852

53+
path = entry.data.get(CONF_BACKUP_PATH, "/")
54+
await async_migrate_wrong_folder_path(client, path)
55+
4956
# Ensure the backup directory exists
50-
if not await async_ensure_path_exists(
51-
client, entry.data.get(CONF_BACKUP_PATH, "/")
52-
):
57+
if not await async_ensure_path_exists(client, path):
5358
raise ConfigEntryNotReady(
5459
translation_domain=DOMAIN,
5560
translation_key="cannot_access_or_create_backup_path",

homeassistant/components/webdav/helpers.py

+29
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
"""Helper functions for the WebDAV component."""
22

3+
import logging
4+
35
from aiowebdav2.client import Client, ClientOptions
6+
from aiowebdav2.exceptions import WebDavError
47

58
from homeassistant.core import HomeAssistant, callback
9+
from homeassistant.exceptions import ConfigEntryNotReady
610
from homeassistant.helpers.aiohttp_client import async_get_clientsession
711

12+
from .const import DOMAIN
13+
14+
_LOGGER = logging.getLogger(__name__)
15+
816

917
@callback
1018
def async_create_client(
@@ -36,3 +44,24 @@ async def async_ensure_path_exists(client: Client, path: str) -> bool:
3644
return False
3745

3846
return True
47+
48+
49+
async def async_migrate_wrong_folder_path(client: Client, path: str) -> None:
50+
"""Migrate the wrong encoded folder path to the correct one."""
51+
wrong_path = path.replace(" ", "%20")
52+
if await client.check(wrong_path):
53+
try:
54+
await client.move(wrong_path, path)
55+
except WebDavError as err:
56+
raise ConfigEntryNotReady(
57+
translation_domain=DOMAIN,
58+
translation_key="failed_to_migrate_folder",
59+
translation_placeholders={
60+
"wrong_path": wrong_path,
61+
"correct_path": path,
62+
},
63+
) from err
64+
65+
_LOGGER.debug(
66+
"Migrated wrong encoded folder path from %s to %s", wrong_path, path
67+
)

homeassistant/components/webdav/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"iot_class": "cloud_polling",
99
"loggers": ["aiowebdav2"],
1010
"quality_scale": "bronze",
11-
"requirements": ["aiowebdav2==0.4.1"]
11+
"requirements": ["aiowebdav2==0.4.2"]
1212
}

homeassistant/components/webdav/strings.json

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
},
3737
"cannot_access_or_create_backup_path": {
3838
"message": "Cannot access or create backup path. Please check the path and permissions."
39+
},
40+
"failed_to_migrate_folder": {
41+
"message": "Failed to migrate wrong encoded folder \"{wrong_path}\" to \"{correct_path}\"."
3942
}
4043
}
4144
}

requirements_all.txt

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

requirements_test_all.txt

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/components/webdav/__init__.py

+13
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
11
"""Tests for the WebDAV integration."""
2+
3+
from homeassistant.core import HomeAssistant
4+
5+
from tests.common import MockConfigEntry
6+
7+
8+
async def setup_integration(
9+
hass: HomeAssistant, mock_config_entry: MockConfigEntry
10+
) -> None:
11+
"""Set up the WebDAV integration for testing."""
12+
mock_config_entry.add_to_hass(hass)
13+
await hass.config_entries.async_setup(mock_config_entry.entry_id)
14+
await hass.async_block_till_done()

tests/components/webdav/conftest.py

+1
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,5 @@ def mock_webdav_client() -> Generator[AsyncMock]:
6262
mock.download_iter.side_effect = _download_mock
6363
mock.upload_iter.return_value = None
6464
mock.clean.return_value = None
65+
mock.move.return_value = None
6566
yield mock

tests/components/webdav/test_init.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
"""Test WebDAV component setup."""
2+
3+
from unittest.mock import AsyncMock
4+
5+
from aiowebdav2.exceptions import WebDavError
6+
import pytest
7+
8+
from homeassistant.components.webdav.const import CONF_BACKUP_PATH, DOMAIN
9+
from homeassistant.config_entries import ConfigEntryState
10+
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME
11+
from homeassistant.core import HomeAssistant
12+
13+
from . import setup_integration
14+
15+
from tests.common import MockConfigEntry
16+
17+
18+
async def test_migrate_wrong_path(
19+
hass: HomeAssistant, webdav_client: AsyncMock
20+
) -> None:
21+
"""Test migration of wrong encoded folder path."""
22+
webdav_client.list_with_properties.return_value = [
23+
{"/wrong%20path": []},
24+
]
25+
26+
config_entry = MockConfigEntry(
27+
title="user@webdav.demo",
28+
domain=DOMAIN,
29+
data={
30+
CONF_URL: "https://webdav.demo",
31+
CONF_USERNAME: "user",
32+
CONF_PASSWORD: "supersecretpassword",
33+
CONF_BACKUP_PATH: "/wrong path",
34+
},
35+
entry_id="01JKXV07ASC62D620DGYNG2R8H",
36+
)
37+
await setup_integration(hass, config_entry)
38+
39+
webdav_client.move.assert_called_once_with("/wrong%20path", "/wrong path")
40+
41+
42+
async def test_migrate_non_wrong_path(
43+
hass: HomeAssistant, webdav_client: AsyncMock
44+
) -> None:
45+
"""Test no migration of correct folder path."""
46+
webdav_client.list_with_properties.return_value = [
47+
{"/correct path": []},
48+
]
49+
webdav_client.check.side_effect = lambda path: path == "/correct path"
50+
51+
config_entry = MockConfigEntry(
52+
title="user@webdav.demo",
53+
domain=DOMAIN,
54+
data={
55+
CONF_URL: "https://webdav.demo",
56+
CONF_USERNAME: "user",
57+
CONF_PASSWORD: "supersecretpassword",
58+
CONF_BACKUP_PATH: "/correct path",
59+
},
60+
entry_id="01JKXV07ASC62D620DGYNG2R8H",
61+
)
62+
63+
await setup_integration(hass, config_entry)
64+
65+
webdav_client.move.assert_not_called()
66+
67+
68+
async def test_migrate_error(
69+
hass: HomeAssistant,
70+
webdav_client: AsyncMock,
71+
caplog: pytest.LogCaptureFixture,
72+
) -> None:
73+
"""Test migration of wrong encoded folder path with error."""
74+
webdav_client.list_with_properties.return_value = [
75+
{"/wrong%20path": []},
76+
]
77+
webdav_client.move.side_effect = WebDavError("Failed to move")
78+
79+
config_entry = MockConfigEntry(
80+
title="user@webdav.demo",
81+
domain=DOMAIN,
82+
data={
83+
CONF_URL: "https://webdav.demo",
84+
CONF_USERNAME: "user",
85+
CONF_PASSWORD: "supersecretpassword",
86+
CONF_BACKUP_PATH: "/wrong path",
87+
},
88+
entry_id="01JKXV07ASC62D620DGYNG2R8H",
89+
)
90+
await setup_integration(hass, config_entry)
91+
92+
assert config_entry.state is ConfigEntryState.SETUP_RETRY
93+
assert (
94+
'Failed to migrate wrong encoded folder "/wrong%20path" to "/wrong path"'
95+
in caplog.text
96+
)

0 commit comments

Comments
 (0)