fix: bound organization aggregate responses
This commit is contained in:
@@ -55,6 +55,8 @@ from .schemas import (
|
||||
|
||||
|
||||
router = APIRouter(prefix="/organizations", tags=["organizations"])
|
||||
ORGANIZATION_MODEL_COLLECTION_LIMIT = 5_000
|
||||
ORGANIZATION_MODEL_TOTAL_LIMIT = 20_000
|
||||
|
||||
ORG_READ_SCOPES = (
|
||||
"organizations:model:read",
|
||||
@@ -335,15 +337,90 @@ def get_organization_model(
|
||||
principal: ApiPrincipal = Depends(require_any_scope(*ORG_READ_SCOPES)),
|
||||
) -> OrganizationModelResponse:
|
||||
tenant_id = _tenant_id(principal)
|
||||
return OrganizationModelResponse(
|
||||
unit_types=[_item_unit_type(item) for item in session.query(OrganizationUnitType).filter(OrganizationUnitType.tenant_id == tenant_id).order_by(OrganizationUnitType.name.asc()).all()],
|
||||
structures=[_item_structure(item) for item in session.query(OrganizationStructure).filter(OrganizationStructure.tenant_id == tenant_id).order_by(OrganizationStructure.name.asc()).all()],
|
||||
relation_types=[_item_relation_type(item) for item in session.query(OrganizationRelationType).filter(OrganizationRelationType.tenant_id == tenant_id).order_by(OrganizationRelationType.name.asc()).all()],
|
||||
units=[_item_unit(item) for item in session.query(OrganizationUnit).filter(OrganizationUnit.tenant_id == tenant_id).order_by(OrganizationUnit.name.asc()).all()],
|
||||
relations=[_item_relation(item) for item in session.query(OrganizationRelation).filter(OrganizationRelation.tenant_id == tenant_id).order_by(OrganizationRelation.created_at.asc()).all()],
|
||||
function_types=[_item_function_type(item) for item in session.query(OrganizationFunctionType).filter(OrganizationFunctionType.tenant_id == tenant_id).order_by(OrganizationFunctionType.name.asc()).all()],
|
||||
functions=[_item_function(item) for item in session.query(OrganizationFunction).filter(OrganizationFunction.tenant_id == tenant_id).order_by(OrganizationFunction.name.asc()).all()],
|
||||
unit_types = _bounded_organization_rows(
|
||||
session.query(OrganizationUnitType)
|
||||
.filter(OrganizationUnitType.tenant_id == tenant_id)
|
||||
.order_by(OrganizationUnitType.name.asc()),
|
||||
"unit types",
|
||||
)
|
||||
structures = _bounded_organization_rows(
|
||||
session.query(OrganizationStructure)
|
||||
.filter(OrganizationStructure.tenant_id == tenant_id)
|
||||
.order_by(OrganizationStructure.name.asc()),
|
||||
"structures",
|
||||
)
|
||||
relation_types = _bounded_organization_rows(
|
||||
session.query(OrganizationRelationType)
|
||||
.filter(OrganizationRelationType.tenant_id == tenant_id)
|
||||
.order_by(OrganizationRelationType.name.asc()),
|
||||
"relation types",
|
||||
)
|
||||
units = _bounded_organization_rows(
|
||||
session.query(OrganizationUnit)
|
||||
.filter(OrganizationUnit.tenant_id == tenant_id)
|
||||
.order_by(OrganizationUnit.name.asc()),
|
||||
"units",
|
||||
)
|
||||
relations = _bounded_organization_rows(
|
||||
session.query(OrganizationRelation)
|
||||
.filter(OrganizationRelation.tenant_id == tenant_id)
|
||||
.order_by(OrganizationRelation.created_at.asc()),
|
||||
"relations",
|
||||
)
|
||||
function_types = _bounded_organization_rows(
|
||||
session.query(OrganizationFunctionType)
|
||||
.filter(OrganizationFunctionType.tenant_id == tenant_id)
|
||||
.order_by(OrganizationFunctionType.name.asc()),
|
||||
"function types",
|
||||
)
|
||||
functions = _bounded_organization_rows(
|
||||
session.query(OrganizationFunction)
|
||||
.filter(OrganizationFunction.tenant_id == tenant_id)
|
||||
.order_by(OrganizationFunction.name.asc()),
|
||||
"functions",
|
||||
)
|
||||
if sum(
|
||||
len(items)
|
||||
for items in (
|
||||
unit_types,
|
||||
structures,
|
||||
relation_types,
|
||||
units,
|
||||
relations,
|
||||
function_types,
|
||||
functions,
|
||||
)
|
||||
) > ORGANIZATION_MODEL_TOTAL_LIMIT:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
|
||||
detail=(
|
||||
"The organization model is too large for the aggregate "
|
||||
"endpoint and cannot be returned as one response."
|
||||
),
|
||||
)
|
||||
return OrganizationModelResponse(
|
||||
unit_types=[_item_unit_type(item) for item in unit_types],
|
||||
structures=[_item_structure(item) for item in structures],
|
||||
relation_types=[_item_relation_type(item) for item in relation_types],
|
||||
units=[_item_unit(item) for item in units],
|
||||
relations=[_item_relation(item) for item in relations],
|
||||
function_types=[_item_function_type(item) for item in function_types],
|
||||
functions=[_item_function(item) for item in functions],
|
||||
)
|
||||
|
||||
|
||||
def _bounded_organization_rows(query: Any, label: str) -> list[Any]:
|
||||
rows = query.limit(ORGANIZATION_MODEL_COLLECTION_LIMIT + 1).all()
|
||||
if len(rows) > ORGANIZATION_MODEL_COLLECTION_LIMIT:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
|
||||
detail=(
|
||||
f"The organization model has more than "
|
||||
f"{ORGANIZATION_MODEL_COLLECTION_LIMIT} {label} and cannot "
|
||||
"be returned as one response."
|
||||
),
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
@router.post("/unit-types", response_model=OrganizationUnitTypeItem, status_code=status.HTTP_201_CREATED)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"lucide-react": "^1.23.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-router-dom": "^7.1.1",
|
||||
"react-router-dom": ">=7.18.2 <8",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^6.0.6"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user