33 lines
1.3 KiB
Python
33 lines
1.3 KiB
Python
|
|
"""First-run install wizard.
|
||
|
|
|
||
|
|
`GET /api/setup/status` is public (the SPA uses it to decide whether to show the wizard). Every
|
||
|
|
mutating step goes through `require_setup`: it rejects once the instance is configured AND requires
|
||
|
|
the one-time setup token (printed to the container logs at first boot, carried by the wizard as the
|
||
|
|
X-Setup-Token header). The wizard steps themselves are added in epic 6c.
|
||
|
|
"""
|
||
|
|
from fastapi import APIRouter, Depends, Header, HTTPException
|
||
|
|
from sqlalchemy.orm import Session
|
||
|
|
|
||
|
|
from app import state
|
||
|
|
from app.db import get_db
|
||
|
|
|
||
|
|
router = APIRouter(prefix="/api/setup", tags=["setup"])
|
||
|
|
|
||
|
|
|
||
|
|
def require_setup(
|
||
|
|
x_setup_token: str | None = Header(default=None),
|
||
|
|
db: Session = Depends(get_db),
|
||
|
|
) -> Session:
|
||
|
|
"""Gate for setup steps. Returns the db session for the handler to reuse."""
|
||
|
|
if state.is_configured(db):
|
||
|
|
raise HTTPException(status_code=409, detail="This instance is already set up.")
|
||
|
|
if not state.check_setup_token(db, x_setup_token):
|
||
|
|
raise HTTPException(status_code=403, detail="Invalid or missing setup token.")
|
||
|
|
return db
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/status")
|
||
|
|
def setup_status(db: Session = Depends(get_db)) -> dict:
|
||
|
|
"""Public: whether the instance still needs first-run setup."""
|
||
|
|
return {"configured": state.is_configured(db)}
|