55 lines
1.8 KiB
Python
55 lines
1.8 KiB
Python
"""Settings endpoints.
|
|
|
|
The browser never sees a real token: `GET` masks every secret, and a `PUT` that
|
|
sends the mask back untouched keeps the stored value.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Body, HTTPException
|
|
from pydantic import ValidationError
|
|
|
|
from app.api.deps import DbSession, Settings
|
|
from app.services import blocker_service, settings_service
|
|
from app.settings_schema import AppSettings
|
|
|
|
router = APIRouter(prefix="/api/settings", tags=["settings"])
|
|
|
|
|
|
@router.get("")
|
|
def get_settings(settings: Settings) -> dict:
|
|
return {
|
|
"settings": settings_service.mask_secrets(settings.model_dump(mode="json")),
|
|
"defaults": {
|
|
"blocked_domains": blocker_service.DEFAULT_DOMAINS,
|
|
"blocked_apps": blocker_service.DEFAULT_APPS,
|
|
},
|
|
}
|
|
|
|
|
|
@router.put("")
|
|
def put_settings(session: DbSession, patch: dict[str, Any] = Body(...)) -> dict:
|
|
try:
|
|
updated = settings_service.apply_patch(session, patch)
|
|
except ValidationError as exc:
|
|
# `exc.errors()` can carry exception objects in `ctx`, which JSON cannot
|
|
# take; pydantic's own `json()` renders them as text.
|
|
raise HTTPException(status_code=422, detail=json.loads(exc.json())) from exc
|
|
return {"settings": settings_service.mask_secrets(updated.model_dump(mode="json"))}
|
|
|
|
|
|
@router.post("/reset")
|
|
def reset_settings(session: DbSession) -> dict:
|
|
"""Back to defaults, re-seeded from the environment."""
|
|
updated = settings_service.save_settings(session, settings_service.settings_from_env())
|
|
return {"settings": settings_service.mask_secrets(updated.model_dump(mode="json"))}
|
|
|
|
|
|
@router.get("/schema")
|
|
def settings_schema() -> dict:
|
|
"""The JSON Schema, so a client can render the settings form generically."""
|
|
return AppSettings.model_json_schema()
|