96 lines
3.8 KiB
Python
96 lines
3.8 KiB
Python
|
|
from typing import Annotated
|
||
|
|
from uuid import UUID
|
||
|
|
|
||
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
|
||
|
|
from app.core.deps import get_session, get_tenant_context, require_min_role
|
||
|
|
from app.crud.plant import crud_plant, crud_plant_family
|
||
|
|
from app.models.user import TenantRole
|
||
|
|
from app.schemas.plant import PlantCreate, PlantFamilyRead, PlantRead, PlantUpdate
|
||
|
|
|
||
|
|
router = APIRouter(tags=["Pflanzen"])
|
||
|
|
|
||
|
|
TenantCtx = Annotated[tuple, Depends(get_tenant_context)]
|
||
|
|
WriteCtx = Annotated[tuple, Depends(require_min_role(TenantRole.READ_WRITE))]
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/plant-families", response_model=list[PlantFamilyRead])
|
||
|
|
async def list_plant_families(
|
||
|
|
db: Annotated[AsyncSession, Depends(get_session)],
|
||
|
|
_: TenantCtx,
|
||
|
|
) -> list[PlantFamilyRead]:
|
||
|
|
families = await crud_plant_family.get_all(db)
|
||
|
|
return [PlantFamilyRead.model_validate(f) for f in families]
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/plants", response_model=list[PlantRead])
|
||
|
|
async def list_plants(
|
||
|
|
db: Annotated[AsyncSession, Depends(get_session)],
|
||
|
|
ctx: TenantCtx,
|
||
|
|
) -> list[PlantRead]:
|
||
|
|
_, tenant_id = ctx
|
||
|
|
plants = await crud_plant.get_multi_for_tenant(db, tenant_id=tenant_id)
|
||
|
|
return [PlantRead.model_validate(p) for p in plants]
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/plants/{plant_id}", response_model=PlantRead)
|
||
|
|
async def get_plant(
|
||
|
|
plant_id: UUID,
|
||
|
|
db: Annotated[AsyncSession, Depends(get_session)],
|
||
|
|
_: TenantCtx,
|
||
|
|
) -> PlantRead:
|
||
|
|
plant = await crud_plant.get(db, id=plant_id)
|
||
|
|
if not plant:
|
||
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Pflanze nicht gefunden.")
|
||
|
|
return PlantRead.model_validate(plant)
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/plants", response_model=PlantRead, status_code=status.HTTP_201_CREATED)
|
||
|
|
async def create_plant(
|
||
|
|
body: PlantCreate,
|
||
|
|
db: Annotated[AsyncSession, Depends(get_session)],
|
||
|
|
ctx: WriteCtx,
|
||
|
|
) -> PlantRead:
|
||
|
|
_, tenant_id, _ = ctx
|
||
|
|
plant = await crud_plant.create_for_tenant(db, obj_in=body, tenant_id=tenant_id)
|
||
|
|
return PlantRead.model_validate(plant)
|
||
|
|
|
||
|
|
|
||
|
|
@router.put("/plants/{plant_id}", response_model=PlantRead)
|
||
|
|
async def update_plant(
|
||
|
|
plant_id: UUID,
|
||
|
|
body: PlantUpdate,
|
||
|
|
db: Annotated[AsyncSession, Depends(get_session)],
|
||
|
|
ctx: WriteCtx,
|
||
|
|
) -> PlantRead:
|
||
|
|
user, tenant_id, _ = ctx
|
||
|
|
plant = await crud_plant.get(db, id=plant_id)
|
||
|
|
if not plant:
|
||
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Pflanze nicht gefunden.")
|
||
|
|
# Global plants: only superadmin
|
||
|
|
if plant.tenant_id is None and not user.is_superadmin:
|
||
|
|
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Globale Pflanzen können nur von Superadmins bearbeitet werden.")
|
||
|
|
# Tenant plants: must belong to current tenant
|
||
|
|
if plant.tenant_id is not None and plant.tenant_id != tenant_id:
|
||
|
|
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Kein Zugriff auf diese Pflanze.")
|
||
|
|
updated = await crud_plant.update(db, db_obj=plant, obj_in=body)
|
||
|
|
return PlantRead.model_validate(updated)
|
||
|
|
|
||
|
|
|
||
|
|
@router.delete("/plants/{plant_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||
|
|
async def delete_plant(
|
||
|
|
plant_id: UUID,
|
||
|
|
db: Annotated[AsyncSession, Depends(get_session)],
|
||
|
|
ctx: WriteCtx,
|
||
|
|
) -> None:
|
||
|
|
user, tenant_id, _ = ctx
|
||
|
|
plant = await crud_plant.get(db, id=plant_id)
|
||
|
|
if not plant:
|
||
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Pflanze nicht gefunden.")
|
||
|
|
if plant.tenant_id is None and not user.is_superadmin:
|
||
|
|
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Globale Pflanzen können nur von Superadmins gelöscht werden.")
|
||
|
|
if plant.tenant_id is not None and plant.tenant_id != tenant_id:
|
||
|
|
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Kein Zugriff auf diese Pflanze.")
|
||
|
|
await crud_plant.remove(db, id=plant_id)
|