350 lines
11 KiB
Python
350 lines
11 KiB
Python
from __future__ import annotations
|
|
|
|
from app.repositories.scheme_groups import list_scheme_version_groups
|
|
from app.repositories.scheme_seats import list_scheme_version_seats
|
|
from app.repositories.scheme_sectors import list_scheme_version_sectors
|
|
from app.services.api_errors import raise_unprocessable
|
|
|
|
|
|
def _raise_uniqueness_error(message: str, detail: dict | None = None) -> None:
|
|
if detail:
|
|
code = detail.pop("code", "editor_uniqueness_error")
|
|
msg = detail.pop("message", message)
|
|
raise_unprocessable(code=code, message=msg, details=detail)
|
|
else:
|
|
raise_unprocessable(code="editor_uniqueness_error", message=message)
|
|
|
|
|
|
def _raise_reference_error(message: str, detail: dict | None = None) -> None:
|
|
if detail:
|
|
code = detail.pop("code", "editor_reference_error")
|
|
msg = detail.pop("message", message)
|
|
raise_unprocessable(code=code, message=msg, details=detail)
|
|
else:
|
|
raise_unprocessable(code="editor_reference_error", message=message)
|
|
|
|
|
|
async def validate_single_seat_patch_uniqueness(
|
|
*,
|
|
scheme_version_id: str,
|
|
seat_record_id: str,
|
|
new_seat_id: str | None,
|
|
) -> None:
|
|
if not new_seat_id:
|
|
return
|
|
|
|
seats = await list_scheme_version_seats(scheme_version_id)
|
|
for row in seats:
|
|
if row.seat_record_id == seat_record_id:
|
|
continue
|
|
if row.seat_id == new_seat_id:
|
|
_raise_uniqueness_error(
|
|
f"Seat id already exists in current draft version: {new_seat_id}",
|
|
{
|
|
"code": "duplicate_seat_id",
|
|
"message": "Seat id already exists in current draft version",
|
|
"seat_id": new_seat_id,
|
|
"conflict_seat_record_id": row.seat_record_id,
|
|
},
|
|
)
|
|
|
|
|
|
async def validate_bulk_seat_patch_uniqueness(
|
|
*,
|
|
scheme_version_id: str,
|
|
items: list[dict],
|
|
) -> None:
|
|
seats = await list_scheme_version_seats(scheme_version_id)
|
|
|
|
existing_by_seat_id: dict[str, str] = {
|
|
row.seat_id: row.seat_record_id
|
|
for row in seats
|
|
if row.seat_id
|
|
}
|
|
|
|
seen_new_ids: dict[str, str] = {}
|
|
|
|
for item in items:
|
|
seat_record_id = item["seat_record_id"]
|
|
seat_id = item.get("seat_id")
|
|
|
|
if not seat_id:
|
|
continue
|
|
|
|
existing_record_id = existing_by_seat_id.get(seat_id)
|
|
if existing_record_id and existing_record_id != seat_record_id:
|
|
_raise_uniqueness_error(
|
|
f"Seat id already exists in current draft version: {seat_id}",
|
|
{
|
|
"code": "duplicate_seat_id",
|
|
"message": "Seat id already exists in current draft version",
|
|
"seat_id": seat_id,
|
|
"conflict_seat_record_id": existing_record_id,
|
|
"input_seat_record_id": seat_record_id,
|
|
},
|
|
)
|
|
|
|
seen_record_id = seen_new_ids.get(seat_id)
|
|
if seen_record_id and seen_record_id != seat_record_id:
|
|
_raise_uniqueness_error(
|
|
f"Seat id is duplicated inside bulk payload: {seat_id}",
|
|
{
|
|
"code": "duplicate_seat_id_in_payload",
|
|
"message": "Seat id is duplicated inside bulk payload",
|
|
"seat_id": seat_id,
|
|
"first_seat_record_id": seen_record_id,
|
|
"second_seat_record_id": seat_record_id,
|
|
},
|
|
)
|
|
|
|
seen_new_ids[seat_id] = seat_record_id
|
|
|
|
|
|
async def validate_sector_patch_uniqueness(
|
|
*,
|
|
scheme_version_id: str,
|
|
sector_record_id: str,
|
|
new_sector_id: str | None,
|
|
) -> None:
|
|
if not new_sector_id:
|
|
return
|
|
|
|
rows = await list_scheme_version_sectors(scheme_version_id)
|
|
for row in rows:
|
|
if row.sector_record_id == sector_record_id:
|
|
continue
|
|
if row.sector_id == new_sector_id:
|
|
_raise_uniqueness_error(
|
|
f"Sector id already exists in current draft version: {new_sector_id}",
|
|
{
|
|
"code": "duplicate_sector_id",
|
|
"message": "Sector id already exists in current draft version",
|
|
"sector_id": new_sector_id,
|
|
"conflict_sector_record_id": row.sector_record_id,
|
|
},
|
|
)
|
|
|
|
|
|
async def validate_group_patch_uniqueness(
|
|
*,
|
|
scheme_version_id: str,
|
|
group_record_id: str,
|
|
new_group_id: str | None,
|
|
) -> None:
|
|
if not new_group_id:
|
|
return
|
|
|
|
rows = await list_scheme_version_groups(scheme_version_id)
|
|
for row in rows:
|
|
if row.group_record_id == group_record_id:
|
|
continue
|
|
if row.group_id == new_group_id:
|
|
_raise_uniqueness_error(
|
|
f"Group id already exists in current draft version: {new_group_id}",
|
|
{
|
|
"code": "duplicate_group_id",
|
|
"message": "Group id already exists in current draft version",
|
|
"group_id": new_group_id,
|
|
"conflict_group_record_id": row.group_record_id,
|
|
},
|
|
)
|
|
|
|
|
|
async def validate_create_sector_uniqueness(
|
|
*,
|
|
scheme_version_id: str,
|
|
sector_id: str,
|
|
element_id: str | None,
|
|
) -> None:
|
|
rows = await list_scheme_version_sectors(scheme_version_id)
|
|
|
|
for row in rows:
|
|
if row.sector_id == sector_id:
|
|
_raise_uniqueness_error(
|
|
f"Sector id already exists in current draft version: {sector_id}",
|
|
{
|
|
"code": "duplicate_sector_id",
|
|
"message": "Sector id already exists in current draft version",
|
|
"sector_id": sector_id,
|
|
"conflict_sector_record_id": row.sector_record_id,
|
|
},
|
|
)
|
|
|
|
if element_id is None:
|
|
return
|
|
|
|
for row in rows:
|
|
if row.element_id == element_id:
|
|
_raise_uniqueness_error(
|
|
f"Sector element binding already exists in current draft version: {element_id}",
|
|
{
|
|
"code": "duplicate_sector_element_id",
|
|
"message": "Sector element binding already exists in current draft version",
|
|
"element_id": element_id,
|
|
"conflict_sector_record_id": row.sector_record_id,
|
|
},
|
|
)
|
|
|
|
|
|
async def validate_create_group_uniqueness(
|
|
*,
|
|
scheme_version_id: str,
|
|
group_id: str,
|
|
element_id: str | None,
|
|
) -> None:
|
|
rows = await list_scheme_version_groups(scheme_version_id)
|
|
|
|
for row in rows:
|
|
if row.group_id == group_id:
|
|
_raise_uniqueness_error(
|
|
f"Group id already exists in current draft version: {group_id}",
|
|
{
|
|
"code": "duplicate_group_id",
|
|
"message": "Group id already exists in current draft version",
|
|
"group_id": group_id,
|
|
"conflict_group_record_id": row.group_record_id,
|
|
},
|
|
)
|
|
|
|
if element_id is None:
|
|
return
|
|
|
|
for row in rows:
|
|
if row.element_id == element_id:
|
|
_raise_uniqueness_error(
|
|
f"Group element binding already exists in current draft version: {element_id}",
|
|
{
|
|
"code": "duplicate_group_element_id",
|
|
"message": "Group element binding already exists in current draft version",
|
|
"element_id": element_id,
|
|
"conflict_group_record_id": row.group_record_id,
|
|
},
|
|
)
|
|
|
|
|
|
async def validate_single_seat_patch_references(
|
|
*,
|
|
scheme_version_id: str,
|
|
sector_id: str | None,
|
|
group_id: str | None,
|
|
) -> None:
|
|
sector_ids = {
|
|
row.sector_id
|
|
for row in await list_scheme_version_sectors(scheme_version_id)
|
|
if row.sector_id
|
|
}
|
|
group_ids = {
|
|
row.group_id
|
|
for row in await list_scheme_version_groups(scheme_version_id)
|
|
if row.group_id
|
|
}
|
|
|
|
if sector_id is not None and sector_id not in sector_ids:
|
|
_raise_reference_error(
|
|
f"Sector id does not exist in current draft version: {sector_id}",
|
|
{
|
|
"code": "unknown_sector_id",
|
|
"message": "Sector id does not exist in current draft version",
|
|
"sector_id": sector_id,
|
|
},
|
|
)
|
|
|
|
if group_id is not None and group_id not in group_ids:
|
|
_raise_reference_error(
|
|
f"Group id does not exist in current draft version: {group_id}",
|
|
{
|
|
"code": "unknown_group_id",
|
|
"message": "Group id does not exist in current draft version",
|
|
"group_id": group_id,
|
|
},
|
|
)
|
|
|
|
|
|
async def validate_bulk_seat_patch_references(
|
|
*,
|
|
scheme_version_id: str,
|
|
items: list[dict],
|
|
) -> None:
|
|
sector_ids = {
|
|
row.sector_id
|
|
for row in await list_scheme_version_sectors(scheme_version_id)
|
|
if row.sector_id
|
|
}
|
|
group_ids = {
|
|
row.group_id
|
|
for row in await list_scheme_version_groups(scheme_version_id)
|
|
if row.group_id
|
|
}
|
|
|
|
unknown_sector_refs = sorted(
|
|
{
|
|
item["sector_id"]
|
|
for item in items
|
|
if item.get("sector_id") is not None and item["sector_id"] not in sector_ids
|
|
}
|
|
)
|
|
if unknown_sector_refs:
|
|
_raise_reference_error(
|
|
"Bulk payload contains unknown sector_id values",
|
|
{
|
|
"code": "unknown_sector_ids",
|
|
"message": "Bulk payload contains unknown sector_id values",
|
|
"sector_ids": unknown_sector_refs,
|
|
},
|
|
)
|
|
|
|
unknown_group_refs = sorted(
|
|
{
|
|
item["group_id"]
|
|
for item in items
|
|
if item.get("group_id") is not None and item["group_id"] not in group_ids
|
|
}
|
|
)
|
|
if unknown_group_refs:
|
|
_raise_reference_error(
|
|
"Bulk payload contains unknown group_id values",
|
|
{
|
|
"code": "unknown_group_ids",
|
|
"message": "Bulk payload contains unknown group_id values",
|
|
"group_ids": unknown_group_refs,
|
|
},
|
|
)
|
|
|
|
|
|
async def validate_remap_target_references(
|
|
*,
|
|
scheme_version_id: str,
|
|
to_sector_id: str | None,
|
|
to_group_id: str | None,
|
|
) -> None:
|
|
sector_ids = {
|
|
row.sector_id
|
|
for row in await list_scheme_version_sectors(scheme_version_id)
|
|
if row.sector_id
|
|
}
|
|
group_ids = {
|
|
row.group_id
|
|
for row in await list_scheme_version_groups(scheme_version_id)
|
|
if row.group_id
|
|
}
|
|
|
|
if to_sector_id is not None and to_sector_id not in sector_ids:
|
|
_raise_reference_error(
|
|
f"Target sector_id does not exist in current draft version: {to_sector_id}",
|
|
{
|
|
"code": "unknown_target_sector_id",
|
|
"message": "Target sector_id does not exist in current draft version",
|
|
"sector_id": to_sector_id,
|
|
},
|
|
)
|
|
|
|
if to_group_id is not None and to_group_id not in group_ids:
|
|
_raise_reference_error(
|
|
f"Target group_id does not exist in current draft version: {to_group_id}",
|
|
{
|
|
"code": "unknown_target_group_id",
|
|
"message": "Target group_id does not exist in current draft version",
|
|
"group_id": to_group_id,
|
|
},
|
|
)
|