fix(api): return 503 instead of 500 when Jellyfin/SSH not configured
On a fresh deploy with no Jellyfin service configured yet, get_jellyfin_client (and get_user_id / get_ssh_client) raised a plain RuntimeError, which bubbled up as a 500 traceback on every Jellyfin-dependent route (dashboard counts/libraries/activity, media, users). Convert those RuntimeErrors to HTTPException(503) with a clear detail message so FastAPI returns a clean 503 JSON response instead of a 500, and the frontend can render a not-configured state. - dependencies.py: get_jellyfin_client (no service / missing creds), get_user_id (no users discovered), and get_ssh_client (no SSH machine + no legacy key path) now raise HTTPException(503, detail=...). - tests/test_api.py: added TestDashboard.test_jellyfin_endpoints_return_503_when_not_configured covering /api/dashboard/counts and /activity. ruff clean; 240 backend tests pass.
This commit is contained in:
@@ -163,11 +163,17 @@ def get_jellyfin_client(request: Request = None) -> JellyfinClient:
|
||||
service_id = _request_jellyfin_service_id(request)
|
||||
service = _service_record(store, "jellyfin", service_id)
|
||||
if service is None:
|
||||
raise RuntimeError("No Jellyfin service is configured. Add a Jellyfin service on the Services page.")
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="No Jellyfin service is configured. Add a Jellyfin service on the Services page.",
|
||||
)
|
||||
base_url = str(service.get("config", {}).get("base_url") or "")
|
||||
api_key = str(service.get("secrets", {}).get("api_key") or "")
|
||||
if not base_url or not api_key:
|
||||
raise RuntimeError("Jellyfin service is missing base_url or api_key. Edit it on the Services page.")
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="Jellyfin service is missing base_url or api_key. Edit it on the Services page.",
|
||||
)
|
||||
cache_key = (service["id"], base_url, api_key)
|
||||
return _jellyfin_client_for(cache_key)
|
||||
|
||||
@@ -244,7 +250,10 @@ def get_ssh_client(request: Request = None):
|
||||
"set" if settings.ssh_password else "missing",
|
||||
)
|
||||
if not settings.ssh_key_path:
|
||||
raise RuntimeError("No SSH machine is configured and SSH key settings must be configured")
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="No SSH machine is configured and SSH key settings must be configured",
|
||||
)
|
||||
return _ssh_client_for(
|
||||
(
|
||||
"legacy",
|
||||
@@ -280,5 +289,8 @@ def get_user_id(request: Request = None) -> str:
|
||||
client = get_jellyfin_client(request)
|
||||
users = client.users()
|
||||
if not users:
|
||||
raise RuntimeError("No Jellyfin users found and no user_id configured on the service")
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="No Jellyfin users found and no user_id configured on the service",
|
||||
)
|
||||
return users[0]["Id"]
|
||||
|
||||
@@ -211,6 +211,22 @@ class TestDashboard:
|
||||
data = response.json()
|
||||
assert len(data) == 2
|
||||
|
||||
def test_jellyfin_endpoints_return_503_when_not_configured(self, test_client):
|
||||
# Remove the mocked Jellyfin dependency so the real one runs; with no
|
||||
# Jellyfin service seeded, endpoints must degrade to 503, not 500.
|
||||
app.dependency_overrides.pop(get_jellyfin_client, None)
|
||||
app.dependency_overrides.pop(get_user_id, None)
|
||||
try:
|
||||
for path in ("/api/dashboard/counts", "/api/dashboard/activity"):
|
||||
response = test_client.get(path)
|
||||
assert response.status_code == 503, path
|
||||
detail = response.json()["detail"]
|
||||
assert "configured" in detail, path
|
||||
finally:
|
||||
# Restore the mocks for subsequent tests in this fixture session.
|
||||
app.dependency_overrides[get_jellyfin_client] = lambda: MagicMock()
|
||||
app.dependency_overrides[get_user_id] = lambda: "user123"
|
||||
|
||||
|
||||
# --- Settings reset ---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user