fix: seed admin user on startup and run sync as background task

- Seed/update admin user from ADMIN_USERNAME/ADMIN_PASSWORD settings on
  startup (admin_users table was empty, login was impossible)
- POST /api/admin/sync now returns immediately and runs the equipment
  sync via BackgroundTasks (full sync took minutes and hit nginx 504)
- run_sync accepts optional sync_log_id to reuse a pre-created log entry
- Adapt admin router test to background sync behavior
This commit is contained in:
Agent Zero
2026-09-24 21:41:35 +02:00
parent 709190719f
commit e66bcc7058
4 changed files with 77 additions and 18 deletions
+31 -5
View File
@@ -1,5 +1,5 @@
"""Admin router: login, sync endpoints, sync log."""
from fastapi import APIRouter, Depends, HTTPException, Response, Query, status
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Response, Query, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Any
@@ -10,7 +10,9 @@ from app.schemas.auth import LoginRequest, TokenResponse, AdminInfo
from app.schemas.sync import SyncStatus, SyncLogEntry, SyncTriggerResponse
from app.auth import verify_password, create_access_token, get_current_user
from app.services.sync_service import SyncService
from app.database import async_session
from app.cache import cache
from datetime import datetime
router = APIRouter(prefix="/api/admin", tags=["admin"])
@@ -54,13 +56,37 @@ async def get_me(user: AdminUser = Depends(get_current_user)) -> Any:
@router.post("/sync", response_model=SyncTriggerResponse)
async def trigger_sync(
background_tasks: BackgroundTasks,
user: AdminUser = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> Any:
"""Trigger a manual equipment sync (admin only)."""
sync_service = SyncService(db)
result = await sync_service.run_sync()
return SyncTriggerResponse(sync_id=result["sync_id"], status=result["status"])
"""Trigger a manual equipment sync in the background (admin only).
Runs the sync via BackgroundTasks so the HTTP request returns immediately
(a full sync of 700+ items incl. image downloads takes minutes and
would otherwise hit proxy timeouts).
Poll GET /api/admin/sync-status for progress.
"""
log_entry = SyncLog(sync_type="equipment", status="running", started_at=datetime.utcnow())
db.add(log_entry)
await db.commit()
await db.refresh(log_entry)
async def _run_sync(sync_id: int) -> None:
async with async_session() as sync_db:
sync_service = SyncService(sync_db)
try:
await sync_service.run_sync(sync_log_id=sync_id)
except Exception as exc: # noqa: BLE001
log = await sync_db.get(SyncLog, sync_id)
if log:
log.status = "failed"
log.error_message = str(exc)
log.completed_at = datetime.utcnow()
await sync_db.commit()
background_tasks.add_task(_run_sync, log_entry.id)
return SyncTriggerResponse(sync_id=log_entry.id, status="running")
@router.get("/sync-status", response_model=SyncStatus)