shinkan-jinkendo/backend/routers/platform_media_storage.py
Lars 7284c577d7
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 24s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Successful in 27s
feat: enhance media management and governance in the project
- Added new documentation for media assets and lifecycle management, establishing a single source of truth in MEDIA_ASSETS_AND_ARCHIVE_SPEC.md.
- Updated project status to reflect the addition of media archive and lifecycle governance.
- Introduced a new API endpoint for platform media storage, allowing superadmin access for media management.
- Enhanced exercise media handling with improved database integration for media assets, including deduplication and effective media root resolution.
- Updated frontend API utilities to support new media storage functionalities, ensuring seamless integration with the backend.
- Incremented version to 0.8.41, reflecting the latest changes and improvements in media handling.
2026-05-07 12:36:46 +02:00

98 lines
3.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Superadmin: Speicherpfad-Konfiguration (§7.1 MEDIA_ASSETS_AND_ARCHIVE_SPEC.md)."""
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from club_tenancy import is_platform_admin
from db import get_db, get_cursor, r2d
from auth import require_auth
from media_storage import _default_media_root, get_effective_media_root, normalize_local_relative_root
router = APIRouter(prefix="/api/admin", tags=["admin", "media-storage"])
class PlatformMediaStorageUpdate(BaseModel):
local_relative_root: str = Field(
"",
description="Relativer Unterordner unter MEDIA_ROOT (z. B. nas/videos). Leer = nur MEDIA_ROOT.",
max_length=512,
)
class PlatformMediaStorageOut(BaseModel):
storage_backend: str
local_relative_root: str
media_root_env: str
effective_media_root: str
def _require_superadmin(session: dict) -> None:
role = (session.get("role") or "").strip().lower()
if role != "superadmin":
raise HTTPException(status_code=403, detail="Nur Superadmin")
@router.get("/platform-media-storage", response_model=PlatformMediaStorageOut)
def get_platform_media_storage(session: dict = Depends(require_auth)):
"""Lesen: Plattform-Admin (admin/superadmin) Hilfe für Betrieb."""
role = (session.get("role") or "").strip().lower()
if not is_platform_admin(role):
raise HTTPException(status_code=403, detail="Keine Berechtigung")
with get_db() as conn:
cur = get_cursor(conn)
cur.execute(
"""SELECT storage_backend, local_relative_root
FROM platform_media_storage WHERE id = 1""",
)
row = cur.fetchone()
if not row:
backend, rel = "local", ""
else:
d = r2d(row)
backend = d.get("storage_backend") or "local"
rel = str(d.get("local_relative_root") or "")
eff = get_effective_media_root(cur)
return PlatformMediaStorageOut(
storage_backend=backend,
local_relative_root=rel,
media_root_env=str(_default_media_root().resolve()),
effective_media_root=str(eff),
)
@router.put("/platform-media-storage", response_model=PlatformMediaStorageOut)
def put_platform_media_storage(
body: PlatformMediaStorageUpdate,
session: dict = Depends(require_auth),
):
"""Schreiben: nur superadmin."""
_require_superadmin(session)
profile_id = session["profile_id"]
try:
rel_norm = normalize_local_relative_root(body.local_relative_root)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e)) from e
with get_db() as conn:
cur = get_cursor(conn)
cur.execute(
"""UPDATE platform_media_storage
SET local_relative_root = %s, updated_at = NOW(), updated_by_profile_id = %s
WHERE id = 1
RETURNING storage_backend, local_relative_root""",
(rel_norm, profile_id),
)
row = cur.fetchone()
conn.commit()
if not row:
raise HTTPException(status_code=500, detail="platform_media_storage fehlt")
d = r2d(row)
eff = get_effective_media_root(cur)
return PlatformMediaStorageOut(
storage_backend=str(d.get("storage_backend") or "local"),
local_relative_root=str(d.get("local_relative_root") or ""),
media_root_env=str(_default_media_root().resolve()),
effective_media_root=str(eff),
)