docs(api): add internal API contract and expose response schemas in swagger
This commit is contained in:
@@ -4,6 +4,7 @@ from sqlalchemy.orm import Session
|
|||||||
from app.core.config import get_settings
|
from app.core.config import get_settings
|
||||||
from app.db.session import get_db
|
from app.db.session import get_db
|
||||||
from app.repositories.permissions_repo import PermissionsRepository
|
from app.repositories.permissions_repo import PermissionsRepository
|
||||||
|
from app.schemas.internal import InternalUpsertUserBySubResponse
|
||||||
from app.repositories.users_repo import UsersRepository
|
from app.repositories.users_repo import UsersRepository
|
||||||
from app.schemas.authentik_admin import AuthentikEnsureUserRequest, AuthentikEnsureUserResponse
|
from app.schemas.authentik_admin import AuthentikEnsureUserRequest, AuthentikEnsureUserResponse
|
||||||
from app.schemas.permissions import PermissionSnapshotResponse
|
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 = 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(
|
def upsert_user_by_sub(
|
||||||
payload: UserUpsertBySubRequest,
|
payload: UserUpsertBySubRequest,
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
) -> dict[str, str | bool | None]:
|
) -> InternalUpsertUserBySubResponse:
|
||||||
repo = UsersRepository(db)
|
repo = UsersRepository(db)
|
||||||
user = repo.upsert_by_sub(
|
user = repo.upsert_by_sub(
|
||||||
authentik_sub=payload.sub,
|
authentik_sub=payload.sub,
|
||||||
|
|||||||
@@ -7,28 +7,35 @@ from app.repositories.modules_repo import ModulesRepository
|
|||||||
from app.repositories.sites_repo import SitesRepository
|
from app.repositories.sites_repo import SitesRepository
|
||||||
from app.repositories.systems_repo import SystemsRepository
|
from app.repositories.systems_repo import SystemsRepository
|
||||||
from app.repositories.users_repo import UsersRepository
|
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
|
from app.security.api_client_auth import require_api_client
|
||||||
|
|
||||||
router = APIRouter(prefix="/internal", tags=["internal"], dependencies=[Depends(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(
|
def internal_list_systems(
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
limit: int = Query(default=200, ge=1, le=1000),
|
limit: int = Query(default=200, ge=1, le=1000),
|
||||||
offset: int = Query(default=0, ge=0),
|
offset: int = Query(default=0, ge=0),
|
||||||
) -> dict:
|
) -> InternalSystemListResponse:
|
||||||
repo = SystemsRepository(db)
|
repo = SystemsRepository(db)
|
||||||
items, total = repo.list(limit=limit, offset=offset)
|
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}
|
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(
|
def internal_list_modules(
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
limit: int = Query(default=500, ge=1, le=2000),
|
limit: int = Query(default=500, ge=1, le=2000),
|
||||||
offset: int = Query(default=0, ge=0),
|
offset: int = Query(default=0, ge=0),
|
||||||
) -> dict:
|
) -> InternalModuleListResponse:
|
||||||
modules_repo = ModulesRepository(db)
|
modules_repo = ModulesRepository(db)
|
||||||
items, total = modules_repo.list(limit=limit, offset=offset)
|
items, total = modules_repo.list(limit=limit, offset=offset)
|
||||||
return {
|
return {
|
||||||
@@ -48,25 +55,25 @@ def internal_list_modules(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/companies")
|
@router.get("/companies", response_model=InternalCompanyListResponse)
|
||||||
def internal_list_companies(
|
def internal_list_companies(
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
keyword: str | None = Query(default=None),
|
keyword: str | None = Query(default=None),
|
||||||
limit: int = Query(default=500, ge=1, le=2000),
|
limit: int = Query(default=500, ge=1, le=2000),
|
||||||
offset: int = Query(default=0, ge=0),
|
offset: int = Query(default=0, ge=0),
|
||||||
) -> dict:
|
) -> InternalCompanyListResponse:
|
||||||
repo = CompaniesRepository(db)
|
repo = CompaniesRepository(db)
|
||||||
items, total = repo.list(keyword=keyword, limit=limit, offset=offset)
|
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}
|
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(
|
def internal_list_sites(
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
company_key: str | None = Query(default=None),
|
company_key: str | None = Query(default=None),
|
||||||
limit: int = Query(default=500, ge=1, le=2000),
|
limit: int = Query(default=500, ge=1, le=2000),
|
||||||
offset: int = Query(default=0, ge=0),
|
offset: int = Query(default=0, ge=0),
|
||||||
) -> dict:
|
) -> InternalSiteListResponse:
|
||||||
companies_repo = CompaniesRepository(db)
|
companies_repo = CompaniesRepository(db)
|
||||||
sites_repo = SitesRepository(db)
|
sites_repo = SitesRepository(db)
|
||||||
company_id = None
|
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}
|
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(
|
def internal_list_members(
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
keyword: str | None = Query(default=None),
|
keyword: str | None = Query(default=None),
|
||||||
limit: int = Query(default=500, ge=1, le=2000),
|
limit: int = Query(default=500, ge=1, le=2000),
|
||||||
offset: int = Query(default=0, ge=0),
|
offset: int = Query(default=0, ge=0),
|
||||||
) -> dict:
|
) -> InternalMemberListResponse:
|
||||||
repo = UsersRepository(db)
|
repo = UsersRepository(db)
|
||||||
items, total = repo.list(keyword=keyword, limit=limit, offset=offset)
|
items, total = repo.list(keyword=keyword, limit=limit, offset=offset)
|
||||||
return {
|
return {
|
||||||
|
|||||||
85
app/schemas/internal.py
Normal file
85
app/schemas/internal.py
Normal 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
|
||||||
Reference in New Issue
Block a user