Backend: drop users router, backups service attribution, named dashboards (Slice 3)
Users router removed: - Delete routers/users.py + users_impl.py (Jellyfin-backed user directory, Jellyfin-email message compose, Jellyseerr enrichment). - Drop orphaned get_jellyseerr_client dep from dependencies.py (get_user_id stays; used by dashboard/media/media_index_worker). - clients/jellyseerr.py stays (still imported by widgets/sources.py). - test_api.py TestUsers block + mock_jellyseerr fixture removed. Backups service attribution: - backup_jobs gains a nullable service_id column (PRAGMA migration). - _resolve_backup_service_id helper: explicit service_id wins, else first-wins an enabled backups instance, else empty (backward-compat). - Both report endpoints accept ?service_id= and persist it on the job. - Dashboard summary + poller aggregate across all jobs unchanged. Named dashboards backend: - named_dashboards table (id, label, slug UNIQUE, sort_order, payload_json, timestamps) with full CRUD methods + _slugify/_unique_slug helpers. - models/dashboards.py (NamedDashboardInput/NamedDashboard). - routers/dashboards.py: GET/POST/PUT/DELETE /api/dashboards. - Router registered in main.py. Tests: test_dashboards.py (CRUD, slug collision, explicit slug, 404); test_api.py trimmed. 271 backend tests pass (was 268; +6 dashboards -3 users); ruff clean. Refs openspec/changes/services-as-hub-ia/ (spec R5/R6.1, tasks slice 3).
This commit is contained in:
@@ -15,7 +15,23 @@ from ..services.settings_store import SettingsStore, get_settings_store
|
||||
router = APIRouter(prefix="/api/backups", tags=["backups"])
|
||||
|
||||
|
||||
def _get_or_create_job(store: SettingsStore, report: BackupReportRequest) -> dict[str, Any]:
|
||||
def _resolve_backup_service_id(store: SettingsStore, explicit: str | None = None) -> str:
|
||||
"""Return the service_id for backup attribution.
|
||||
|
||||
First-wins: if no explicit service_id is given, pick the first enabled
|
||||
``backups`` service instance (spec R6.1). Returns an empty string when
|
||||
none is configured (backward-compatible with pre-service reports).
|
||||
"""
|
||||
if explicit:
|
||||
return explicit
|
||||
candidates = store.list_services("backups")
|
||||
for svc in candidates:
|
||||
if svc.get("enabled"):
|
||||
return svc["id"]
|
||||
return ""
|
||||
|
||||
|
||||
def _get_or_create_job(store: SettingsStore, report: BackupReportRequest, service_id: str = "") -> dict[str, Any]:
|
||||
job = store.get_backup_job_by_name(report.name)
|
||||
if not job:
|
||||
job = store.upsert_backup_job(
|
||||
@@ -24,6 +40,7 @@ def _get_or_create_job(store: SettingsStore, report: BackupReportRequest) -> dic
|
||||
"source": report.source,
|
||||
"target": report.target,
|
||||
"schedule_interval_seconds": report.schedule_interval_seconds,
|
||||
"service_id": service_id,
|
||||
}
|
||||
)
|
||||
elif report.schedule_interval_seconds:
|
||||
@@ -34,6 +51,7 @@ def _get_or_create_job(store: SettingsStore, report: BackupReportRequest) -> dic
|
||||
"source": report.source,
|
||||
"target": report.target,
|
||||
"schedule_interval_seconds": report.schedule_interval_seconds,
|
||||
"service_id": service_id,
|
||||
}
|
||||
)
|
||||
job = store.get_backup_job(job["id"])
|
||||
@@ -43,10 +61,12 @@ def _get_or_create_job(store: SettingsStore, report: BackupReportRequest) -> dic
|
||||
@router.post("/report")
|
||||
def post_backup_report(
|
||||
report: BackupReportRequest,
|
||||
service_id: str | None = None,
|
||||
store: SettingsStore = Depends(get_settings_store),
|
||||
_auth: str = Depends(require_api_key),
|
||||
) -> BackupRunResponse:
|
||||
job = _get_or_create_job(store, report)
|
||||
resolved_service_id = _resolve_backup_service_id(store, service_id)
|
||||
job = _get_or_create_job(store, report, resolved_service_id)
|
||||
|
||||
# Check for duplicate (same job + started_at within 1s)
|
||||
existing_runs = store.list_backup_runs(job_id=job["id"], limit=5)
|
||||
@@ -88,10 +108,12 @@ def post_backup_report(
|
||||
@router.post("/report/start")
|
||||
def post_backup_start(
|
||||
report: BackupReportRequest,
|
||||
service_id: str | None = None,
|
||||
store: SettingsStore = Depends(get_settings_store),
|
||||
_auth: str = Depends(require_api_key),
|
||||
) -> BackupRunResponse:
|
||||
job = _get_or_create_job(store, report)
|
||||
resolved_service_id = _resolve_backup_service_id(store, service_id)
|
||||
job = _get_or_create_job(store, report, resolved_service_id)
|
||||
|
||||
run_data = {
|
||||
"job_id": job["id"],
|
||||
|
||||
Reference in New Issue
Block a user