feat: webdav download via httpx mit basic-auth
This commit is contained in:
21
app/ingest/webdav.py
Normal file
21
app/ingest/webdav.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import httpx
|
||||||
|
|
||||||
|
|
||||||
|
class WebDAVError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def download_file(base_url: str, user: str, password: str, file_path: str, *, timeout: float = 60.0) -> bytes:
|
||||||
|
"""Fetch a file from Nextcloud WebDAV. Returns the raw bytes."""
|
||||||
|
base = base_url.rstrip("/")
|
||||||
|
rel = file_path.lstrip("/")
|
||||||
|
url = f"{base}/{rel}"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(auth=(user, password), timeout=timeout) as client:
|
||||||
|
response = await client.get(url)
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise WebDAVError(
|
||||||
|
f"WebDAV GET {file_path} failed: status={response.status_code}"
|
||||||
|
)
|
||||||
|
return response.content
|
||||||
44
tests/test_webdav.py
Normal file
44
tests/test_webdav.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import pytest
|
||||||
|
import httpx
|
||||||
|
import respx
|
||||||
|
|
||||||
|
from app.ingest.webdav import download_file, WebDAVError
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_download_file_returns_bytes():
|
||||||
|
base = "https://nc.example.com/remote.php/dav/files/u"
|
||||||
|
file_path = "Documents/THB/Studium/2.Semester/Databases/x.pdf"
|
||||||
|
expected_url = f"{base}/{file_path}"
|
||||||
|
|
||||||
|
with respx.mock(base_url=base) as mock:
|
||||||
|
mock.get(expected_url).mock(return_value=httpx.Response(200, content=b"PDFBYTES"))
|
||||||
|
data = await download_file(base, "u", "pw", file_path)
|
||||||
|
assert data == b"PDFBYTES"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_download_file_404_raises():
|
||||||
|
base = "https://nc.example.com/remote.php/dav/files/u"
|
||||||
|
file_path = "missing.pdf"
|
||||||
|
expected_url = f"{base}/{file_path}"
|
||||||
|
|
||||||
|
with respx.mock(base_url=base) as mock:
|
||||||
|
mock.get(expected_url).mock(return_value=httpx.Response(404))
|
||||||
|
with pytest.raises(WebDAVError):
|
||||||
|
await download_file(base, "u", "pw", file_path)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_download_file_handles_url_encoding():
|
||||||
|
base = "https://nc.example.com/remote.php/dav/files/u"
|
||||||
|
file_path = "Documents/Folder With Space/file.pdf"
|
||||||
|
|
||||||
|
with respx.mock(base_url=base) as mock:
|
||||||
|
# httpx will percent-encode the spaces
|
||||||
|
route = mock.get(url__regex=r".*/Folder%20With%20Space/file\.pdf").mock(
|
||||||
|
return_value=httpx.Response(200, content=b"OK")
|
||||||
|
)
|
||||||
|
data = await download_file(base, "u", "pw", file_path)
|
||||||
|
assert data == b"OK"
|
||||||
|
assert route.called
|
||||||
Reference in New Issue
Block a user