refactor(api): shared serializer + ownership + write-scope helpers (R6 S1a)
Establish the R6 API-contract infra before the S1b payload:dict migration: - iso(dt) in utils.py replaces the ~16 hand-rolled `x.isoformat() if x else None` serializer idioms across the routes. - get_or_404 / owned_or_404 in routes/_common.py — one 404 + existence-leak policy; plex's _own_playlist_or_404 and saved_views' _own_view now delegate to it. - require_write_scope dependency in auth.py collapses the inline has_write_scope→403 checks (channels subscribe/unsubscribe, playlists push/push-plan) that had drifted into three different messages into one; the conditional delete_playlist guard stays inline (its message was already canonical). No response-shape change (iso == isoformat for a present value). Gate: ruff clean, pytest 163 green (+ test_utils for iso).
This commit is contained in:
@@ -41,6 +41,8 @@ from app.models import (
|
||||
PlexState,
|
||||
User,
|
||||
)
|
||||
from app.routes._common import owned_or_404
|
||||
from app.utils import iso
|
||||
from app.plex import paths as plex_paths
|
||||
from app.plex import people as plex_people
|
||||
from app.plex import stream as plex_stream
|
||||
@@ -141,11 +143,7 @@ def _link_dict(link: PlexLink | None) -> dict:
|
||||
"sync_enabled": bool(link and link.sync_enabled),
|
||||
"uses_admin": bool(link and link.uses_admin),
|
||||
"initial_import_done": bool(link and link.initial_import_done),
|
||||
"last_watch_sync_at": (
|
||||
link.last_watch_sync_at.isoformat()
|
||||
if link and link.last_watch_sync_at
|
||||
else None
|
||||
),
|
||||
"last_watch_sync_at": iso(link.last_watch_sync_at) if link else None,
|
||||
}
|
||||
|
||||
|
||||
@@ -912,10 +910,7 @@ def collection_set_editable(
|
||||
|
||||
# --- Playlists (Siftlode-native, per-user, ordered — no Plex account needed; Plex sync is a later phase).
|
||||
def _own_playlist_or_404(db: Session, pid: int, user: User) -> PlexPlaylist:
|
||||
pl = db.query(PlexPlaylist).filter_by(id=pid, user_id=user.id).first()
|
||||
if pl is None:
|
||||
raise HTTPException(status_code=404, detail="Playlist not found")
|
||||
return pl
|
||||
return owned_or_404(db, PlexPlaylist, pid, user, detail="Playlist not found")
|
||||
|
||||
|
||||
def _playlist_card(pl: PlexPlaylist, count: int, thumb_rk: str | None) -> dict:
|
||||
|
||||
Reference in New Issue
Block a user