fix(core): stabilize editor lifecycle, transactional versions, and runtime config
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, Query, Request
|
||||
|
||||
from app.core.config import settings
|
||||
from app.repositories.audit import create_audit_event
|
||||
@@ -508,6 +508,7 @@ async def delete_draft_group(
|
||||
|
||||
@router.patch(f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/seats/records/{{seat_record_id}}", response_model=SeatPatchResponse)
|
||||
async def patch_draft_seat(
|
||||
request: Request,
|
||||
scheme_id: str,
|
||||
seat_record_id: str,
|
||||
payload: SeatPatchRequest,
|
||||
@@ -530,14 +531,20 @@ async def patch_draft_seat(
|
||||
group_id=payload.group_id,
|
||||
)
|
||||
|
||||
raw_json = await request.json()
|
||||
update_data = {k: v for k, v in payload.model_dump(exclude_unset=True).items() if k in raw_json}
|
||||
for field in ("seat_id", "sector_id", "group_id"):
|
||||
if field in update_data and (update_data[field] is None or update_data[field] == ""):
|
||||
from app.services.api_errors import raise_unprocessable
|
||||
raise_unprocessable(
|
||||
code="business_identifier_nullification_forbidden",
|
||||
message=f"{field} cannot be nullified or explicitly cleared",
|
||||
)
|
||||
|
||||
row = await update_scheme_version_seat_by_record_id(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
seat_record_id=seat_record_id,
|
||||
seat_id=payload.seat_id,
|
||||
sector_id=payload.sector_id,
|
||||
group_id=payload.group_id,
|
||||
row_label=payload.row_label,
|
||||
seat_number=payload.seat_number,
|
||||
**update_data,
|
||||
)
|
||||
|
||||
await create_audit_event(
|
||||
@@ -569,6 +576,7 @@ async def patch_draft_seat(
|
||||
|
||||
@router.post(f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/seats/bulk", response_model=BulkSeatPatchResponse)
|
||||
async def bulk_patch_draft_seats(
|
||||
request: Request,
|
||||
scheme_id: str,
|
||||
payload: BulkSeatPatchRequest,
|
||||
expected_scheme_version_id: str | None = Query(default=None),
|
||||
@@ -579,7 +587,20 @@ async def bulk_patch_draft_seats(
|
||||
expected_scheme_version_id=expected_scheme_version_id,
|
||||
)
|
||||
|
||||
items = [item.model_dump() for item in payload.items]
|
||||
raw_json = await request.json()
|
||||
items = []
|
||||
for i, item in enumerate(payload.items):
|
||||
item_raw = raw_json.get("items", [])[i] if "items" in raw_json else {}
|
||||
items.append({k: item.model_dump(exclude_unset=True).get(k) for k in item_raw})
|
||||
|
||||
for item in items:
|
||||
for field in ("seat_id", "sector_id", "group_id"):
|
||||
if field in item and (item[field] is None or item[field] == ""):
|
||||
from app.services.api_errors import raise_unprocessable
|
||||
raise_unprocessable(
|
||||
code="business_identifier_nullification_forbidden",
|
||||
message=f"{field} cannot be nullified or explicitly cleared",
|
||||
)
|
||||
await validate_bulk_seat_patch_uniqueness(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
items=items,
|
||||
@@ -625,6 +646,7 @@ async def bulk_patch_draft_seats(
|
||||
|
||||
@router.patch(f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/sectors/records/{{sector_record_id}}", response_model=SectorPatchResponse)
|
||||
async def patch_draft_sector(
|
||||
request: Request,
|
||||
scheme_id: str,
|
||||
sector_record_id: str,
|
||||
payload: SectorPatchRequest,
|
||||
@@ -642,20 +664,28 @@ async def patch_draft_sector(
|
||||
new_sector_id=payload.sector_id,
|
||||
)
|
||||
|
||||
raw_json = await request.json()
|
||||
update_data = {k: v for k, v in payload.model_dump(exclude_unset=True).items() if k in raw_json}
|
||||
for field in ("sector_id",):
|
||||
if field in update_data and (update_data[field] is None or update_data[field] == ""):
|
||||
from app.services.api_errors import raise_unprocessable
|
||||
raise_unprocessable(
|
||||
code="business_identifier_nullification_forbidden",
|
||||
message=f"{field} cannot be nullified or explicitly cleared",
|
||||
)
|
||||
|
||||
row, old_sector_id = await update_scheme_version_sector_by_record_id(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
sector_record_id=sector_record_id,
|
||||
sector_id=payload.sector_id,
|
||||
name=payload.name,
|
||||
)
|
||||
cascaded_count = await cascade_update_seat_sector_reference(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
old_sector_id=old_sector_id,
|
||||
new_sector_id=payload.sector_id,
|
||||
)
|
||||
repair_result = await repair_structure_references(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
**update_data,
|
||||
)
|
||||
cascaded_count = 0
|
||||
if "sector_id" in update_data and update_data["sector_id"] and update_data["sector_id"] != old_sector_id:
|
||||
cascaded_count = await cascade_update_seat_sector_reference(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
old_sector_id=old_sector_id,
|
||||
new_sector_id=update_data["sector_id"],
|
||||
)
|
||||
|
||||
await create_audit_event(
|
||||
scheme_id=scheme.scheme_id,
|
||||
@@ -668,7 +698,6 @@ async def patch_draft_sector(
|
||||
"new_sector_id": payload.sector_id,
|
||||
"name": payload.name,
|
||||
"cascaded_seats_count": cascaded_count,
|
||||
"repair_result": repair_result,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -683,6 +712,7 @@ async def patch_draft_sector(
|
||||
|
||||
@router.patch(f"{settings.api_v1_prefix}/schemes/{{scheme_id}}/draft/groups/records/{{group_record_id}}", response_model=GroupPatchResponse)
|
||||
async def patch_draft_group(
|
||||
request: Request,
|
||||
scheme_id: str,
|
||||
group_record_id: str,
|
||||
payload: GroupPatchRequest,
|
||||
@@ -700,20 +730,28 @@ async def patch_draft_group(
|
||||
new_group_id=payload.group_id,
|
||||
)
|
||||
|
||||
raw_json = await request.json()
|
||||
update_data = {k: v for k, v in payload.model_dump(exclude_unset=True).items() if k in raw_json}
|
||||
for field in ("group_id",):
|
||||
if field in update_data and (update_data[field] is None or update_data[field] == ""):
|
||||
from app.services.api_errors import raise_unprocessable
|
||||
raise_unprocessable(
|
||||
code="business_identifier_nullification_forbidden",
|
||||
message=f"{field} cannot be nullified or explicitly cleared",
|
||||
)
|
||||
|
||||
row, old_group_id = await update_scheme_version_group_by_record_id(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
group_record_id=group_record_id,
|
||||
group_id=payload.group_id,
|
||||
name=payload.name,
|
||||
)
|
||||
cascaded_count = await cascade_update_seat_group_reference(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
old_group_id=old_group_id,
|
||||
new_group_id=payload.group_id,
|
||||
)
|
||||
repair_result = await repair_structure_references(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
**update_data,
|
||||
)
|
||||
cascaded_count = 0
|
||||
if "group_id" in update_data and update_data["group_id"] and update_data["group_id"] != old_group_id:
|
||||
cascaded_count = await cascade_update_seat_group_reference(
|
||||
scheme_version_id=version.scheme_version_id,
|
||||
old_group_id=old_group_id,
|
||||
new_group_id=update_data["group_id"],
|
||||
)
|
||||
|
||||
await create_audit_event(
|
||||
scheme_id=scheme.scheme_id,
|
||||
@@ -726,7 +764,6 @@ async def patch_draft_group(
|
||||
"new_group_id": payload.group_id,
|
||||
"name": payload.name,
|
||||
"cascaded_seats_count": cascaded_count,
|
||||
"repair_result": repair_result,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user