docs(api): add internal API contract and expose response schemas in swagger

This commit is contained in:
Chris
2026-03-31 22:20:24 +08:00
parent ce8f9342de
commit ed5679948b
3 changed files with 105 additions and 12 deletions

View File

@@ -4,6 +4,7 @@ from sqlalchemy.orm import Session
from app.core.config import get_settings
from app.db.session import get_db
from app.repositories.permissions_repo import PermissionsRepository
from app.schemas.internal import InternalUpsertUserBySubResponse
from app.repositories.users_repo import UsersRepository
from app.schemas.authentik_admin import AuthentikEnsureUserRequest, AuthentikEnsureUserResponse
from app.schemas.permissions import PermissionSnapshotResponse
@@ -15,11 +16,11 @@ from app.services.permission_service import PermissionService
router = APIRouter(prefix="/internal", tags=["internal"], dependencies=[Depends(require_api_client)])
@router.post("/users/upsert-by-sub")
@router.post("/users/upsert-by-sub", response_model=InternalUpsertUserBySubResponse)
def upsert_user_by_sub(
payload: UserUpsertBySubRequest,
db: Session = Depends(get_db),
) -> dict[str, str | bool | None]:
) -> InternalUpsertUserBySubResponse:
repo = UsersRepository(db)
user = repo.upsert_by_sub(
authentik_sub=payload.sub,

View File

@@ -7,28 +7,35 @@ from app.repositories.modules_repo import ModulesRepository
from app.repositories.sites_repo import SitesRepository
from app.repositories.systems_repo import SystemsRepository
from app.repositories.users_repo import UsersRepository
from app.schemas.internal import (
InternalCompanyListResponse,
InternalMemberListResponse,
InternalModuleListResponse,
InternalSiteListResponse,
InternalSystemListResponse,
)
from app.security.api_client_auth import require_api_client
router = APIRouter(prefix="/internal", tags=["internal"], dependencies=[Depends(require_api_client)])
@router.get("/systems")
@router.get("/systems", response_model=InternalSystemListResponse)
def internal_list_systems(
db: Session = Depends(get_db),
limit: int = Query(default=200, ge=1, le=1000),
offset: int = Query(default=0, ge=0),
) -> dict:
) -> InternalSystemListResponse:
repo = SystemsRepository(db)
items, total = repo.list(limit=limit, offset=offset)
return {"items": [{"id": i.id, "system_key": i.system_key, "name": i.name, "status": i.status} for i in items], "total": total, "limit": limit, "offset": offset}
@router.get("/modules")
@router.get("/modules", response_model=InternalModuleListResponse)
def internal_list_modules(
db: Session = Depends(get_db),
limit: int = Query(default=500, ge=1, le=2000),
offset: int = Query(default=0, ge=0),
) -> dict:
) -> InternalModuleListResponse:
modules_repo = ModulesRepository(db)
items, total = modules_repo.list(limit=limit, offset=offset)
return {
@@ -48,25 +55,25 @@ def internal_list_modules(
}
@router.get("/companies")
@router.get("/companies", response_model=InternalCompanyListResponse)
def internal_list_companies(
db: Session = Depends(get_db),
keyword: str | None = Query(default=None),
limit: int = Query(default=500, ge=1, le=2000),
offset: int = Query(default=0, ge=0),
) -> dict:
) -> InternalCompanyListResponse:
repo = CompaniesRepository(db)
items, total = repo.list(keyword=keyword, limit=limit, offset=offset)
return {"items": [{"id": i.id, "company_key": i.company_key, "name": i.name, "status": i.status} for i in items], "total": total, "limit": limit, "offset": offset}
@router.get("/sites")
@router.get("/sites", response_model=InternalSiteListResponse)
def internal_list_sites(
db: Session = Depends(get_db),
company_key: str | None = Query(default=None),
limit: int = Query(default=500, ge=1, le=2000),
offset: int = Query(default=0, ge=0),
) -> dict:
) -> InternalSiteListResponse:
companies_repo = CompaniesRepository(db)
sites_repo = SitesRepository(db)
company_id = None
@@ -80,13 +87,13 @@ def internal_list_sites(
return {"items": [{"id": i.id, "site_key": i.site_key, "company_key": mapping.get(i.company_id), "name": i.name, "status": i.status} for i in items], "total": total, "limit": limit, "offset": offset}
@router.get("/members")
@router.get("/members", response_model=InternalMemberListResponse)
def internal_list_members(
db: Session = Depends(get_db),
keyword: str | None = Query(default=None),
limit: int = Query(default=500, ge=1, le=2000),
offset: int = Query(default=0, ge=0),
) -> dict:
) -> InternalMemberListResponse:
repo = UsersRepository(db)
items, total = repo.list(keyword=keyword, limit=limit, offset=offset)
return {

85
app/schemas/internal.py Normal file
View File

@@ -0,0 +1,85 @@
from pydantic import BaseModel
class InternalSystemItem(BaseModel):
id: str
system_key: str
name: str
status: str
class InternalSystemListResponse(BaseModel):
items: list[InternalSystemItem]
total: int
limit: int
offset: int
class InternalModuleItem(BaseModel):
id: str
module_key: str
system_key: str
name: str
status: str
class InternalModuleListResponse(BaseModel):
items: list[InternalModuleItem]
total: int
limit: int
offset: int
class InternalCompanyItem(BaseModel):
id: str
company_key: str
name: str
status: str
class InternalCompanyListResponse(BaseModel):
items: list[InternalCompanyItem]
total: int
limit: int
offset: int
class InternalSiteItem(BaseModel):
id: str
site_key: str
company_key: str | None = None
name: str
status: str
class InternalSiteListResponse(BaseModel):
items: list[InternalSiteItem]
total: int
limit: int
offset: int
class InternalMemberItem(BaseModel):
id: str
authentik_sub: str
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool
class InternalMemberListResponse(BaseModel):
items: list[InternalMemberItem]
total: int
limit: int
offset: int
class InternalUpsertUserBySubResponse(BaseModel):
id: str
sub: str
authentik_user_id: int | None = None
username: str | None = None
email: str | None = None
display_name: str | None = None
is_active: bool