feat: add read-only inventory API
This commit is contained in:
1 parent
979885bbdd
commit
51aec1b404
7 files changed
+346
-6
No files matched your search
@@ -0,0 +1,8 @@
|
||||
"""Dependency construction for the Inventory domain."""
|
||||
|
||||
from app.inventory.repository import InventoryRepository
|
||||
from app.inventory.service import InventoryService
|
||||
|
||||
|
||||
def get_inventory_service() -> InventoryService:
|
||||
return InventoryService(InventoryRepository())
|
||||
@@ -84,3 +84,21 @@ class InventorySearchFilters(BaseModel):
|
||||
tags: list[str] = Field(default_factory=list)
|
||||
limit: int = Field(default=100, ge=1, le=500)
|
||||
offset: int = Field(default=0, ge=0)
|
||||
|
||||
|
||||
class InventoryListMeta(BaseModel):
|
||||
limit: int
|
||||
offset: int
|
||||
returned: int
|
||||
|
||||
|
||||
class InventoryMinerListResponse(BaseModel):
|
||||
data: list[InventoryMinerSummary]
|
||||
meta: InventoryListMeta
|
||||
error: None = None
|
||||
|
||||
|
||||
class InventoryMinerDetailResponse(BaseModel):
|
||||
data: InventoryMinerDetail
|
||||
meta: dict[str, object] = Field(default_factory=dict)
|
||||
error: None = None
|
||||
@@ -0,0 +1,71 @@
|
||||
"""Read-only HTTP routes for the Inventory domain."""
|
||||
|
||||
from typing import Annotated
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
|
||||
from app.identity import require_permission
|
||||
from app.inventory.dependencies import get_inventory_service
|
||||
from app.inventory.exceptions import InventoryValidationError, MinerNotFound
|
||||
from app.inventory.models import (
|
||||
InventoryListMeta,
|
||||
InventoryMinerDetailResponse,
|
||||
InventoryMinerListResponse,
|
||||
InventorySearchFilters,
|
||||
)
|
||||
from app.inventory.service import InventoryService
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/inventory/miners", tags=["inventory"])
|
||||
require_inventory_read = require_permission("miners.view")
|
||||
|
||||
InventoryServiceDependency = Annotated[
|
||||
InventoryService,
|
||||
Depends(get_inventory_service),
|
||||
]
|
||||
InventoryReadUser = Annotated[dict, Depends(require_inventory_read)]
|
||||
InventoryQuery = Annotated[InventorySearchFilters, Query()]
|
||||
|
||||
|
||||
@router.get("", response_model=InventoryMinerListResponse)
|
||||
def list_inventory_miners(
|
||||
filters: InventoryQuery,
|
||||
service: InventoryServiceDependency,
|
||||
current_user: InventoryReadUser,
|
||||
) -> InventoryMinerListResponse:
|
||||
del current_user
|
||||
try:
|
||||
miners = service.search_miners(filters)
|
||||
except InventoryValidationError as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=str(exc),
|
||||
) from exc
|
||||
|
||||
return InventoryMinerListResponse(
|
||||
data=miners,
|
||||
meta=InventoryListMeta(
|
||||
limit=filters.limit,
|
||||
offset=filters.offset,
|
||||
returned=len(miners),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{miner_id}", response_model=InventoryMinerDetailResponse)
|
||||
def get_inventory_miner(
|
||||
miner_id: UUID,
|
||||
service: InventoryServiceDependency,
|
||||
current_user: InventoryReadUser,
|
||||
) -> InventoryMinerDetailResponse:
|
||||
del current_user
|
||||
try:
|
||||
miner = service.get_miner(miner_id)
|
||||
except MinerNotFound as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Miner not found",
|
||||
) from exc
|
||||
|
||||
return InventoryMinerDetailResponse(data=miner)
|
||||
Reference in new issue
Block a user