US05-01: Validate Credentials and Upload Readiness

This commit is contained in:
2026-08-16 12:27:19 +02:00
parent 799e58ca21
commit c7ddb253a9
7 changed files with 970 additions and 0 deletions

View File

@@ -25,6 +25,7 @@ from photo_pipeline.api.routes import (
renames,
safety,
thumbnails,
uploads,
workflow,
)
@@ -67,6 +68,7 @@ def create_app(config: Config | None = None) -> FastAPI:
app.include_router(library.router, prefix="/api/v1")
app.include_router(albums.router, prefix="/api/v1")
app.include_router(renames.router, prefix="/api/v1")
app.include_router(uploads.router, prefix="/api/v1")
# Static single-page app (hash-routed). Mounted last so /api/v1 wins.
if FRONTEND_DIR.is_dir():
app.mount("/app", StaticFiles(directory=FRONTEND_DIR, html=True), name="app")

View File

@@ -0,0 +1,39 @@
"""Upload preflight API (US05-01).
Preflight is a command, not a resource read: it contacts the Immich server, hashes
the current bytes, and issues a token. It uploads nothing — starting a batch is
US05-02, so there is deliberately no start endpoint here.
"""
from __future__ import annotations
from fastapi import APIRouter, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from photo_pipeline.services.uploads import UploadError, UploadService
router = APIRouter(tags=["uploads"])
class PreflightRequest(BaseModel):
# ``None`` means every album; an explicit list scopes the check.
albums: list[str] | None = None
# Approving a partial upload is an explicit act, never a default.
allow_partial: bool = False
def _service(request: Request) -> UploadService:
return UploadService(request.app.state.session_factory, config=request.app.state.config)
@router.post("/upload-preflight")
def preflight(request: Request, body: PreflightRequest | None = None):
body = body or PreflightRequest()
try:
return _service(request).preflight(body.albums, allow_partial=body.allow_partial)
except UploadError as error:
return JSONResponse(
status_code=422,
content={"error": {"code": "unknown_album", "message": str(error)}},
)