Newer
Older
gn-synapse / app / api / routes.py
"""API-роуты скелета: healthz/readyz и пример admin-endpoint с гейтом ролей."""

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from redis import Redis
from sqlalchemy import text

from app.auth.deps import AuthenticatedUser, require_admin
from app.config import get_settings
from app.database import SessionLocal

router = APIRouter(prefix="/api")


@router.get("/healthz")
def healthz() -> dict:
    """Liveness: процесс жив, конфигурация не проверяется."""
    return {"status": "ok", "service": "synapse"}


@router.get("/readyz")
def readyz() -> dict:
    """Readiness: доступность зависимостей (Postgres, Redis)."""
    components: dict[str, str] = {}

    try:
        with SessionLocal() as db:
            db.execute(text("SELECT 1"))
        components["postgres"] = "ok"
    except Exception as exc:
        components["postgres"] = f"fail: {exc.__class__.__name__}"

    try:
        Redis.from_url(get_settings().redis_url, socket_connect_timeout=2).ping()
        components["redis"] = "ok"
    except Exception as exc:
        components["redis"] = f"fail: {exc.__class__.__name__}"

    ready = all(v == "ok" for v in components.values())
    return {"ready": ready, "components": components}


class AdminMe(BaseModel):
    sub: str
    email: str | None
    system_role: str
    # Профиль gnexus-auth (scope profile) — для карточки пользователя в SPA.
    username: str | None = None
    display_name: str | None = None
    avatar_url: str | None = None
    # Страница профиля на сервере gnexus-auth (ссылка из навигации).
    account_url: str = ""


@router.get("/v1/admin/me")
def admin_me(user: AuthenticatedUser = Depends(require_admin)) -> AdminMe:
    """Проверка гейта админки: 401 без токена, 403 без роли admin."""
    return AdminMe(
        sub=str(user.user_id),
        email=user.email,
        system_role=user.system_role or "unknown",
        username=user.profile.get("username"),
        display_name=user.profile.get("display_name"),
        avatar_url=user.profile.get("avatar_url"),
        account_url=f"{get_settings().gauth_base_url.rstrip('/')}/account/profile",
    )