first
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
"""CRUD APIs for Artifacts — the heart of the ASF domain model."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
|
||||
from asf_domain import (
|
||||
Artifact,
|
||||
ArtifactCreate,
|
||||
ArtifactUpdate,
|
||||
ArtifactType,
|
||||
ArtifactRelationship,
|
||||
)
|
||||
from ...repositories import NotFoundError, TenantMismatchError
|
||||
from .deps import artifact_service, relationship_service
|
||||
from ...services import ArtifactService, RelationshipService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=list[Artifact], summary="List artifacts (tenant scoped)")
|
||||
async def list_artifacts(
|
||||
project_id: Optional[UUID] = Query(None),
|
||||
type: Optional[ArtifactType] = Query(None),
|
||||
status: Optional[str] = Query(None),
|
||||
search: Optional[str] = Query(None, description="Case insensitive regex on title+content"),
|
||||
limit: int = Query(50, ge=1, le=500),
|
||||
offset: int = Query(0, ge=0),
|
||||
svc: ArtifactService = Depends(artifact_service),
|
||||
) -> list[Artifact]:
|
||||
return await svc.list(
|
||||
project_id=project_id,
|
||||
artifact_type=type,
|
||||
status=status,
|
||||
search=search,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"",
|
||||
response_model=Artifact,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
summary="Create a new artifact",
|
||||
)
|
||||
async def create_artifact(
|
||||
body: ArtifactCreate,
|
||||
svc: ArtifactService = Depends(artifact_service),
|
||||
) -> Artifact:
|
||||
try:
|
||||
return await svc.create(body)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.get("/{artifact_id}", response_model=Artifact, summary="Get artifact by id")
|
||||
async def get_artifact(
|
||||
artifact_id: UUID,
|
||||
svc: ArtifactService = Depends(artifact_service),
|
||||
) -> Artifact:
|
||||
a = await svc.get(artifact_id)
|
||||
if a is None:
|
||||
raise HTTPException(status_code=404, detail=f"Artifact {artifact_id} not found")
|
||||
return a
|
||||
|
||||
|
||||
@router.patch("/{artifact_id}", response_model=Artifact, summary="Update an artifact")
|
||||
async def update_artifact(
|
||||
artifact_id: UUID,
|
||||
body: ArtifactUpdate,
|
||||
svc: ArtifactService = Depends(artifact_service),
|
||||
) -> Artifact:
|
||||
try:
|
||||
return await svc.update(artifact_id, body)
|
||||
except (NotFoundError, TenantMismatchError) as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{artifact_id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
summary="Delete an artifact",
|
||||
)
|
||||
async def delete_artifact(
|
||||
artifact_id: UUID,
|
||||
svc: ArtifactService = Depends(artifact_service),
|
||||
) -> None:
|
||||
try:
|
||||
await svc.delete(artifact_id)
|
||||
except (NotFoundError, TenantMismatchError) as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
return None
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{artifact_id}/relationships",
|
||||
response_model=list[ArtifactRelationship],
|
||||
summary="List all relationships (in + out) for an artifact — convenience wrapper for /relationships/for-artifact/{id}",
|
||||
)
|
||||
async def artifact_relationships(
|
||||
artifact_id: UUID,
|
||||
limit: int = Query(200, ge=1, le=500),
|
||||
rel_svc: RelationshipService = Depends(relationship_service),
|
||||
) -> list[ArtifactRelationship]:
|
||||
return await rel_svc.for_artifact(artifact_id, limit=limit)
|
||||
Reference in New Issue
Block a user