bd8ee9b647
Presigned URLs point at the internal minio:9000 host a browser can't reach. Add ObjectStore.get_object and a GET /media/{id}/content endpoint that resolves visibility and streams the bytes; MediaRead.url now points there. Keeps the object store private and downloads behind the privacy engine.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
"""Media upload/list/delete through the API (object store faked in conftest)."""
|
|
|
|
from tests.conftest import auth, register
|
|
|
|
|
|
async def _tree(client, email):
|
|
h = auth(await register(client, email))
|
|
tree_id = (await client.post("/api/v1/trees", json={"name": "M"}, headers=h)).json()["id"]
|
|
return h, tree_id
|
|
|
|
|
|
async def test_media_upload_list_delete(client):
|
|
h, tree_id = await _tree(client, "media1@example.com")
|
|
|
|
resp = await client.post(
|
|
f"/api/v1/trees/{tree_id}/media",
|
|
files={"file": ("scan.txt", b"hello world", "text/plain")},
|
|
data={"title": "A scan"},
|
|
headers=h,
|
|
)
|
|
assert resp.status_code == 201, resp.text
|
|
body = resp.json()
|
|
assert body["original_filename"] == "scan.txt"
|
|
assert body["byte_size"] == 11
|
|
assert body["url"] == f"/api/v1/trees/{tree_id}/media/{body['id']}/content"
|
|
media_id = body["id"]
|
|
|
|
listed = await client.get(f"/api/v1/trees/{tree_id}/media", headers=h)
|
|
assert listed.status_code == 200
|
|
assert len(listed.json()) == 1
|
|
|
|
# The content endpoint streams the bytes back.
|
|
content = await client.get(f"/api/v1/trees/{tree_id}/media/{media_id}/content", headers=h)
|
|
assert content.status_code == 200
|
|
assert content.content == b"hello world"
|
|
|
|
resp = await client.delete(f"/api/v1/trees/{tree_id}/media/{media_id}", headers=h)
|
|
assert resp.status_code == 204
|
|
assert len((await client.get(f"/api/v1/trees/{tree_id}/media", headers=h)).json()) == 0
|
|
|
|
|
|
async def test_non_member_cannot_upload(client):
|
|
h, tree_id = await _tree(client, "media2@example.com")
|
|
other = auth(await register(client, "media-intruder@example.com"))
|
|
resp = await client.post(
|
|
f"/api/v1/trees/{tree_id}/media",
|
|
files={"file": ("x.txt", b"x", "text/plain")},
|
|
headers=other,
|
|
)
|
|
assert resp.status_code == 403
|