Allow serienen/videoen in media handoff #58
2 changed files with 98 additions and 1 deletions
6
app.py
6
app.py
|
|
@ -4121,7 +4121,11 @@ async def media_handoff(payload: MediaHandoffPayload, request: Request):
|
||||||
_audit("/media/handoff", "POST", 403, f"caller={caller} action={payload.action}")
|
_audit("/media/handoff", "POST", 403, f"caller={caller} action={payload.action}")
|
||||||
raise HTTPException(403, "Media handoff caller is not allowed")
|
raise HTTPException(403, "Media handoff caller is not allowed")
|
||||||
|
|
||||||
allowed_categories = {"serien4k", "serien", "video4k", "video"}
|
# 16.09.2026: serienen/videoen ergaenzt. Die englischen Arr-Instanzen
|
||||||
|
# sonarrEN (Port 8991, Root /data/FHD/serienen) und radarrEN (Port 7880,
|
||||||
|
# Root /data/FHD/videoen) nutzen eigene SAB-Kategorien. Ohne sie brach der
|
||||||
|
# Handoff mit 422 ab und Releases blieben in /usenet/complete liegen.
|
||||||
|
allowed_categories = {"serien4k", "serien", "serienen", "video4k", "video", "videoen"}
|
||||||
if payload.action == "start":
|
if payload.action == "start":
|
||||||
if payload.category not in allowed_categories:
|
if payload.category not in allowed_categories:
|
||||||
raise HTTPException(422, "Unsupported media category")
|
raise HTTPException(422, "Unsupported media category")
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,99 @@ def test_media_handoff_rejects_wrong_category_path(monkeypatch):
|
||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_handoff_accepts_english_arr_categories(monkeypatch):
|
||||||
|
"""serienen/videoen muessen durchgehen (sonarrEN 8991 / radarrEN 7880).
|
||||||
|
|
||||||
|
16.09.2026: fehlten in allowed_categories -> HTTP 422 -> movetdarr.sh
|
||||||
|
brach mit "n8n-Handoff konnte nicht registriert werden" ab und liess
|
||||||
|
Mutiny.2026 x2 tagelang in /usenet/complete/videoen liegen.
|
||||||
|
"""
|
||||||
|
seen = []
|
||||||
|
|
||||||
|
class FakeResponse:
|
||||||
|
status_code = 200
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
return {"ok": True, "jobId": "test-job-5678", "state": "registered"}
|
||||||
|
|
||||||
|
class FakeClient:
|
||||||
|
def __init__(self, **_kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(self, *_args):
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def post(self, url, json, headers):
|
||||||
|
seen.append(json)
|
||||||
|
return FakeResponse()
|
||||||
|
|
||||||
|
monkeypatch.setattr(app.httpx, "AsyncClient", FakeClient)
|
||||||
|
with TestClient(app.app) as client:
|
||||||
|
monkeypatch.setattr(app, "SERVICES", {"n8n": {"url": "http://n8n:5678", "auth": "n8n"}})
|
||||||
|
for category in ("serienen", "videoen"):
|
||||||
|
response = client.post(
|
||||||
|
"/media/handoff",
|
||||||
|
headers={"Authorization": "Bearer test-token"},
|
||||||
|
json={
|
||||||
|
"action": "start",
|
||||||
|
"category": category,
|
||||||
|
"directory": f"/usenet/complete/{category}/Release.2026",
|
||||||
|
"release": "Release.2026-GRP",
|
||||||
|
"cleanName": "Release 2026",
|
||||||
|
"expectedFiles": 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert response.status_code == 200, (category, response.text)
|
||||||
|
assert response.json()["state"] == "registered", category
|
||||||
|
|
||||||
|
assert [item["category"] for item in seen] == ["serienen", "videoen"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_handoff_still_rejects_unknown_category(monkeypatch):
|
||||||
|
"""Fail-closed bleibt: eine frei erfundene Kategorie wird nicht geproxyt."""
|
||||||
|
monkeypatch.setattr(
|
||||||
|
app.httpx,
|
||||||
|
"AsyncClient",
|
||||||
|
lambda **_kwargs: (_ for _ in ()).throw(AssertionError("must not proxy")),
|
||||||
|
)
|
||||||
|
with TestClient(app.app) as client:
|
||||||
|
response = client.post(
|
||||||
|
"/media/handoff",
|
||||||
|
headers={"Authorization": "Bearer test-token"},
|
||||||
|
json={
|
||||||
|
"action": "start",
|
||||||
|
"category": "hoerbuecher",
|
||||||
|
"directory": "/usenet/complete/hoerbuecher/Buch",
|
||||||
|
"release": "Buch",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
|
def test_media_handoff_english_category_path_must_match(monkeypatch):
|
||||||
|
"""Pfadpruefung gilt auch fuer die neuen Kategorien."""
|
||||||
|
monkeypatch.setattr(
|
||||||
|
app.httpx,
|
||||||
|
"AsyncClient",
|
||||||
|
lambda **_kwargs: (_ for _ in ()).throw(AssertionError("must not proxy")),
|
||||||
|
)
|
||||||
|
with TestClient(app.app) as client:
|
||||||
|
response = client.post(
|
||||||
|
"/media/handoff",
|
||||||
|
headers={"Authorization": "Bearer test-token"},
|
||||||
|
json={
|
||||||
|
"action": "start",
|
||||||
|
"category": "videoen",
|
||||||
|
"directory": "/usenet/complete/video4k/Wrong",
|
||||||
|
"release": "Wrong",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
def test_paperless_import_queues_pdf_through_butler(monkeypatch):
|
def test_paperless_import_queues_pdf_through_butler(monkeypatch):
|
||||||
captured = {}
|
captured = {}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue