301 lines
9.1 KiB
Python
301 lines
9.1 KiB
Python
"""HTTP mapping for explicit repair workflows."""
|
|
|
|
from typing import Annotated
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
|
|
from app.identity import require_permission
|
|
from app.repairs.dependencies import get_repair_service
|
|
from app.repairs.exceptions import (
|
|
ControlBoardReplacementActorRequired,
|
|
InvalidMacAddress,
|
|
RepairActorRequired,
|
|
RepairCompletionActorRequired,
|
|
RepairConflict,
|
|
RepairMinerNotFound,
|
|
RepairNotFound,
|
|
RepairPartActorRequired,
|
|
RepairPartComponentNotFound,
|
|
RepairPartNotFound,
|
|
RepairPartValidationError,
|
|
)
|
|
from app.repairs.models import (
|
|
BeginRepairRequest,
|
|
ControlBoardReplacementRequest,
|
|
ControlBoardReplacementResponse,
|
|
BeginRepairResponse,
|
|
RepairCompleteRequest,
|
|
RepairDetailResponse,
|
|
RepairTimelineResponse,
|
|
RepairPartListResponse,
|
|
RepairPartRecordRequest,
|
|
RepairPartResponse,
|
|
RepairPartVoidRequest,
|
|
)
|
|
from app.repairs.service import RepairService
|
|
|
|
|
|
router = APIRouter(prefix="/api/repairs", tags=["repairs"])
|
|
control_board_router = APIRouter(prefix="/api/miners", tags=["miners"])
|
|
require_repair_create = require_permission("repairs.create")
|
|
require_repair_read = require_permission("repairs.read")
|
|
require_repair_complete = require_permission("repairs.complete")
|
|
require_repair_parts_manage = require_permission("repairs.parts.manage")
|
|
require_control_board_replace = require_permission("miners.replace_control_board")
|
|
|
|
RepairServiceDependency = Annotated[
|
|
RepairService,
|
|
Depends(get_repair_service),
|
|
]
|
|
RepairCreateUser = Annotated[dict, Depends(require_repair_create)]
|
|
RepairReadUser = Annotated[dict, Depends(require_repair_read)]
|
|
RepairCompleteUser = Annotated[dict, Depends(require_repair_complete)]
|
|
RepairPartsManageUser = Annotated[dict, Depends(require_repair_parts_manage)]
|
|
ControlBoardReplaceUser = Annotated[dict, Depends(require_control_board_replace)]
|
|
|
|
|
|
@control_board_router.post(
|
|
"/{miner_id}/replace-control-board",
|
|
response_model=ControlBoardReplacementResponse,
|
|
)
|
|
def replace_control_board(
|
|
miner_id: UUID,
|
|
request: ControlBoardReplacementRequest,
|
|
service: RepairServiceDependency,
|
|
current_user: ControlBoardReplaceUser,
|
|
) -> ControlBoardReplacementResponse:
|
|
try:
|
|
result = service.replace_control_board(
|
|
miner_id, request,
|
|
actor_user_id=UUID(str(current_user["id"])),
|
|
)
|
|
except RepairMinerNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND, detail="Miner not found"
|
|
) from exc
|
|
except RepairConflict as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT, detail=str(exc)
|
|
) from exc
|
|
except (InvalidMacAddress, ControlBoardReplacementActorRequired) as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)
|
|
) from exc
|
|
return ControlBoardReplacementResponse(data=result)
|
|
|
|
|
|
@router.post(
|
|
"",
|
|
response_model=BeginRepairResponse,
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
def begin_repair(
|
|
request: BeginRepairRequest,
|
|
service: RepairServiceDependency,
|
|
current_user: RepairCreateUser,
|
|
) -> BeginRepairResponse:
|
|
try:
|
|
repair = service.begin_repair(
|
|
request,
|
|
actor_user_id=UUID(str(current_user["id"])),
|
|
)
|
|
except RepairMinerNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Miner not found",
|
|
) from exc
|
|
except RepairConflict as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail=str(exc),
|
|
) from exc
|
|
except RepairActorRequired as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=str(exc),
|
|
) from exc
|
|
|
|
return BeginRepairResponse(data=repair)
|
|
|
|
|
|
@router.post(
|
|
"/{repair_id}/complete",
|
|
response_model=RepairDetailResponse,
|
|
)
|
|
def complete_repair(
|
|
repair_id: UUID,
|
|
request: RepairCompleteRequest,
|
|
service: RepairServiceDependency,
|
|
current_user: RepairCompleteUser,
|
|
) -> RepairDetailResponse:
|
|
try:
|
|
repair = service.complete_repair(
|
|
repair_id,
|
|
request,
|
|
actor_user_id=UUID(str(current_user["id"])),
|
|
)
|
|
except RepairNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Repair not found",
|
|
) from exc
|
|
except RepairMinerNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail="Repair miner no longer exists",
|
|
) from exc
|
|
except RepairConflict as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail=str(exc),
|
|
) from exc
|
|
except RepairCompletionActorRequired as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=str(exc),
|
|
) from exc
|
|
|
|
return RepairDetailResponse(data=repair)
|
|
|
|
|
|
@router.get(
|
|
"/{repair_id}/parts",
|
|
response_model=RepairPartListResponse,
|
|
)
|
|
def list_repair_parts(
|
|
repair_id: UUID,
|
|
service: RepairServiceDependency,
|
|
current_user: RepairReadUser,
|
|
) -> RepairPartListResponse:
|
|
del current_user
|
|
try:
|
|
parts = service.list_repair_parts(repair_id)
|
|
except RepairNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Repair not found",
|
|
) from exc
|
|
return RepairPartListResponse(data=parts)
|
|
|
|
|
|
@router.post(
|
|
"/{repair_id}/parts",
|
|
response_model=RepairPartResponse,
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
def record_repair_part(
|
|
repair_id: UUID,
|
|
request: RepairPartRecordRequest,
|
|
service: RepairServiceDependency,
|
|
current_user: RepairPartsManageUser,
|
|
) -> RepairPartResponse:
|
|
try:
|
|
part = service.record_repair_part(
|
|
repair_id,
|
|
request,
|
|
actor_user_id=UUID(str(current_user["id"])),
|
|
)
|
|
except (RepairNotFound, RepairPartComponentNotFound) as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=str(exc),
|
|
) from exc
|
|
except RepairMinerNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail="Repair miner no longer exists",
|
|
) from exc
|
|
except RepairConflict as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail=str(exc),
|
|
) from exc
|
|
except (RepairPartActorRequired, RepairPartValidationError) as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=str(exc),
|
|
) from exc
|
|
return RepairPartResponse(data=part)
|
|
|
|
|
|
@router.post(
|
|
"/{repair_id}/parts/{repair_part_id}/void",
|
|
response_model=RepairPartResponse,
|
|
)
|
|
def void_repair_part(
|
|
repair_id: UUID,
|
|
repair_part_id: UUID,
|
|
request: RepairPartVoidRequest,
|
|
service: RepairServiceDependency,
|
|
current_user: RepairPartsManageUser,
|
|
) -> RepairPartResponse:
|
|
try:
|
|
part = service.void_repair_part(
|
|
repair_id,
|
|
repair_part_id,
|
|
request,
|
|
actor_user_id=UUID(str(current_user["id"])),
|
|
)
|
|
except (RepairNotFound, RepairPartNotFound) as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=str(exc),
|
|
) from exc
|
|
except RepairMinerNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail="Repair miner no longer exists",
|
|
) from exc
|
|
except RepairConflict as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail=str(exc),
|
|
) from exc
|
|
except (RepairPartActorRequired, RepairPartValidationError) as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=str(exc),
|
|
) from exc
|
|
return RepairPartResponse(data=part)
|
|
|
|
|
|
@router.get(
|
|
"/{repair_id}",
|
|
response_model=RepairDetailResponse,
|
|
)
|
|
def get_repair(
|
|
repair_id: UUID,
|
|
service: RepairServiceDependency,
|
|
current_user: RepairReadUser,
|
|
) -> RepairDetailResponse:
|
|
del current_user
|
|
try:
|
|
repair = service.get_repair(repair_id)
|
|
except RepairNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Repair not found",
|
|
) from exc
|
|
return RepairDetailResponse(data=repair)
|
|
|
|
|
|
@router.get(
|
|
"/{repair_id}/events",
|
|
response_model=RepairTimelineResponse,
|
|
)
|
|
def get_repair_events(
|
|
repair_id: UUID,
|
|
service: RepairServiceDependency,
|
|
current_user: RepairReadUser,
|
|
) -> RepairTimelineResponse:
|
|
del current_user
|
|
try:
|
|
timeline = service.get_repair_timeline(repair_id)
|
|
except RepairNotFound as exc:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Repair not found",
|
|
) from exc
|
|
return RepairTimelineResponse(data=timeline)
|