diff --git a/backend/app/routers/devices.py b/backend/app/routers/devices.py index 8cc7916..8dadc8b 100644 --- a/backend/app/routers/devices.py +++ b/backend/app/routers/devices.py @@ -1,9 +1,10 @@ import csv import io +from datetime import datetime, timezone from typing import Annotated from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile, status -from sqlalchemy import select +from sqlalchemy import select, update as sa_update from sqlalchemy.orm import selectinload from sqlalchemy.ext.asyncio import AsyncSession @@ -24,6 +25,12 @@ from app.services import crypto router = APIRouter(prefix="/api/v1/objects/{obj_id}/devices", tags=["devices"]) +async def _touch_object(db: AsyncSession, obj_id: int) -> None: + await db.execute( + sa_update(Object).where(Object.id == obj_id).values(updated_at=datetime.now(timezone.utc)) + ) + + async def _get_object(db: AsyncSession, obj_id: int) -> Object: result = await db.execute(select(Object).where(Object.id == obj_id)) obj = result.scalar_one_or_none() @@ -90,6 +97,7 @@ async def create_device( db.add(device) await db.flush() await db.refresh(device) + await _touch_object(db, obj_id) # reload with rack relationship result = await db.execute( select(Device).options(selectinload(Device.rack)).where(Device.id == device.id) @@ -117,6 +125,7 @@ async def import_csv( ): await _get_object(db, obj_id) preview = await _parse_csv_import(db, obj_id, file, dry_run=False) + await _touch_object(db, obj_id) return DeviceImportResult( created=len(preview.would_create), updated=len(preview.would_update), @@ -241,6 +250,7 @@ async def update_device( await db.flush() await db.refresh(device) + await _touch_object(db, obj_id) return device @@ -254,6 +264,7 @@ async def delete_all_devices( result = await db.execute(select(Device).where(Device.object_id == obj_id)) for device in result.scalars().all(): await db.delete(device) + await _touch_object(db, obj_id) @router.delete("/{device_id}", status_code=status.HTTP_204_NO_CONTENT) @@ -265,3 +276,4 @@ async def delete_device( ): device = await _get_device(db, obj_id, device_id) await db.delete(device) + await _touch_object(db, obj_id) diff --git a/backend/app/routers/racks.py b/backend/app/routers/racks.py index e05853b..48bf422 100644 --- a/backend/app/routers/racks.py +++ b/backend/app/routers/racks.py @@ -1,5 +1,7 @@ +from datetime import datetime, timezone + from fastapi import APIRouter, Depends, HTTPException, status -from sqlalchemy import select +from sqlalchemy import select, update as sa_update from sqlalchemy.orm import selectinload from sqlalchemy.ext.asyncio import AsyncSession @@ -12,6 +14,12 @@ from app.schemas.rack import RackCreate, RackRead, RackUpdate router = APIRouter(prefix="/api/v1/objects/{obj_id}/racks", tags=["racks"]) +async def _touch_object(db: AsyncSession, obj_id: int) -> None: + await db.execute( + sa_update(Object).where(Object.id == obj_id).values(updated_at=datetime.now(timezone.utc)) + ) + + async def _get_object(db: AsyncSession, obj_id: int) -> Object: obj = await db.get(Object, obj_id) if obj is None: @@ -58,6 +66,7 @@ async def create_rack( rack = Rack(object_id=obj_id, **body.model_dump()) db.add(rack) await db.flush() + await _touch_object(db, obj_id) result = await db.execute( select(Rack).options(selectinload(Rack.zone)).where(Rack.id == rack.id) ) @@ -76,6 +85,7 @@ async def update_rack( for field, value in body.model_dump(exclude_unset=True).items(): setattr(rack, field, value) await db.flush() + await _touch_object(db, obj_id) result = await db.execute( select(Rack).options(selectinload(Rack.zone)).where(Rack.id == rack.id) ) @@ -91,3 +101,4 @@ async def delete_rack( ): rack = await _load_rack(db, obj_id, rack_id) await db.delete(rack) + await _touch_object(db, obj_id) diff --git a/backend/app/routers/zones.py b/backend/app/routers/zones.py index 451a307..b6c687c 100644 --- a/backend/app/routers/zones.py +++ b/backend/app/routers/zones.py @@ -1,5 +1,7 @@ +from datetime import datetime, timezone + from fastapi import APIRouter, Depends, HTTPException, status -from sqlalchemy import select +from sqlalchemy import select, update as sa_update from sqlalchemy.ext.asyncio import AsyncSession from app.dependencies import get_current_user, get_db @@ -11,6 +13,12 @@ from app.schemas.zone import ZoneCreate, ZoneRead, ZoneUpdate router = APIRouter(prefix="/api/v1/objects/{obj_id}/zones", tags=["zones"]) +async def _touch_object(db: AsyncSession, obj_id: int) -> None: + await db.execute( + sa_update(Object).where(Object.id == obj_id).values(updated_at=datetime.now(timezone.utc)) + ) + + async def _get_object(db: AsyncSession, obj_id: int) -> Object: obj = await db.get(Object, obj_id) if obj is None: @@ -53,6 +61,7 @@ async def create_zone( db.add(zone) await db.flush() await db.refresh(zone) + await _touch_object(db, obj_id) return zone @@ -69,6 +78,7 @@ async def update_zone( setattr(zone, field, value) await db.flush() await db.refresh(zone) + await _touch_object(db, obj_id) return zone @@ -81,3 +91,4 @@ async def delete_zone( ): zone = await _get_zone(db, obj_id, zone_id) await db.delete(zone) + await _touch_object(db, obj_id)