feat(crud): full CRUD endpoints for NetObject (POST/PUT/PATCH/DELETE)
CI / basic-check (push) Has been cancelled
CI / basic-check (push) Has been cancelled
This commit is contained in:
@@ -1,14 +1,25 @@
|
||||
import re
|
||||
from datetime import datetime, timezone
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import NetObjectModel
|
||||
from app.schemas import EntityResponse, ListResponse, NetObject
|
||||
from app.schemas import EntityResponse, ListResponse, NetObject, NetObjectCreate, NetObjectUpdate
|
||||
from app.services.inventory import _to_net_object
|
||||
|
||||
router = APIRouter(prefix='/objects', tags=['objects'])
|
||||
|
||||
|
||||
def _slugify(name: str) -> str:
|
||||
slug = name.lower().strip()
|
||||
slug = re.sub(r'[^\w\s-]', '', slug)
|
||||
slug = re.sub(r'[\s_-]+', '-', slug)
|
||||
return slug.strip('-')
|
||||
|
||||
|
||||
@router.get('', response_model=ListResponse[NetObject])
|
||||
def list_objects(db: Session = Depends(get_db)):
|
||||
rows = db.query(NetObjectModel).all()
|
||||
@@ -21,3 +32,89 @@ def get_object(object_id: str, db: Session = Depends(get_db)):
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail='Object not found')
|
||||
return EntityResponse(item=_to_net_object(row))
|
||||
|
||||
|
||||
@router.post('', response_model=EntityResponse[NetObject], status_code=201)
|
||||
def create_object(body: NetObjectCreate, db: Session = Depends(get_db)):
|
||||
if body.parent_id:
|
||||
parent = db.query(NetObjectModel).filter(NetObjectModel.id == body.parent_id).first()
|
||||
if not parent:
|
||||
raise HTTPException(status_code=422, detail=f'parent_id {body.parent_id!r} not found')
|
||||
now = datetime.now(timezone.utc)
|
||||
obj = NetObjectModel(
|
||||
id=f'obj_{uuid4().hex[:8]}',
|
||||
name=body.name,
|
||||
slug=_slugify(body.name),
|
||||
type=body.type,
|
||||
parent_id=body.parent_id,
|
||||
status=body.status,
|
||||
vendor=body.vendor,
|
||||
model=body.model,
|
||||
serial=body.serial,
|
||||
notes=body.notes,
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
)
|
||||
db.add(obj)
|
||||
db.commit()
|
||||
db.refresh(obj)
|
||||
return EntityResponse(item=_to_net_object(obj))
|
||||
|
||||
|
||||
@router.put('/{object_id}', response_model=EntityResponse[NetObject])
|
||||
def replace_object(object_id: str, body: NetObjectCreate, db: Session = Depends(get_db)):
|
||||
row = db.query(NetObjectModel).filter(NetObjectModel.id == object_id).first()
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail='Object not found')
|
||||
if body.parent_id and body.parent_id != row.parent_id:
|
||||
parent = db.query(NetObjectModel).filter(NetObjectModel.id == body.parent_id).first()
|
||||
if not parent:
|
||||
raise HTTPException(status_code=422, detail=f'parent_id {body.parent_id!r} not found')
|
||||
row.name = body.name
|
||||
row.slug = _slugify(body.name)
|
||||
row.type = body.type
|
||||
row.parent_id = body.parent_id
|
||||
row.status = body.status
|
||||
row.vendor = body.vendor
|
||||
row.model = body.model
|
||||
row.serial = body.serial
|
||||
row.notes = body.notes
|
||||
row.updated_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return EntityResponse(item=_to_net_object(row))
|
||||
|
||||
|
||||
@router.patch('/{object_id}', response_model=EntityResponse[NetObject])
|
||||
def update_object(object_id: str, body: NetObjectUpdate, db: Session = Depends(get_db)):
|
||||
row = db.query(NetObjectModel).filter(NetObjectModel.id == object_id).first()
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail='Object not found')
|
||||
data = body.model_dump(exclude_unset=True)
|
||||
if 'parent_id' in data and data['parent_id']:
|
||||
parent = db.query(NetObjectModel).filter(NetObjectModel.id == data['parent_id']).first()
|
||||
if not parent:
|
||||
raise HTTPException(status_code=422, detail=f'parent_id {data["parent_id"]!r} not found')
|
||||
if 'name' in data:
|
||||
row.slug = _slugify(data['name'])
|
||||
for field, value in data.items():
|
||||
setattr(row, field, value)
|
||||
row.updated_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return EntityResponse(item=_to_net_object(row))
|
||||
|
||||
|
||||
@router.delete('/{object_id}', status_code=204)
|
||||
def delete_object(object_id: str, db: Session = Depends(get_db)):
|
||||
row = db.query(NetObjectModel).filter(NetObjectModel.id == object_id).first()
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail='Object not found')
|
||||
children = db.query(NetObjectModel).filter(NetObjectModel.parent_id == object_id).count()
|
||||
if children:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail=f'Cannot delete: object has {children} child object(s). Remove or re-parent them first.',
|
||||
)
|
||||
db.delete(row)
|
||||
db.commit()
|
||||
|
||||
Reference in New Issue
Block a user