Add validations and logging for puck beamtime assignment.
Introduced checks to prevent reassigning beamtime if puck samples have recorded events. Updated logging in beamline-related methods to provide more insight. Simplified data structure updates for dewars, pucks, and samples, ensuring consistency with beamtime assignments.
This commit is contained in:
@ -709,9 +709,18 @@ dewar_to_beamtime = {
|
||||
for dewar in dewars # Or use actual beamtime ids
|
||||
}
|
||||
|
||||
# Update dewars and their pucks with consistent beamtime
|
||||
for dewar in dewars:
|
||||
dewar.beamtime_id = dewar_to_beamtime[dewar.id]
|
||||
assigned_beamtime_obj = next(
|
||||
b for b in beamtimes if b.id == dewar_to_beamtime[dewar.id]
|
||||
)
|
||||
dewar.beamtimes = [assigned_beamtime_obj]
|
||||
|
||||
for puck in pucks:
|
||||
assigned_beamtime_obj = next(
|
||||
b for b in beamtimes if b.id == dewar_to_beamtime[puck.dewar_id]
|
||||
)
|
||||
puck.beamtimes = [assigned_beamtime_obj]
|
||||
|
||||
|
||||
for puck in pucks:
|
||||
dewar_id = puck.dewar_id # Assuming puck has dewar_id
|
||||
|
@ -51,6 +51,8 @@ from app.crud import (
|
||||
)
|
||||
from app.routers.auth import get_current_user
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
dewar_router = APIRouter()
|
||||
|
||||
@ -599,6 +601,19 @@ async def assign_beamtime_to_dewar(
|
||||
if not dewar:
|
||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||
|
||||
# Check if any sample (in any puck on this dewar) has sample events
|
||||
for puck in dewar.pucks:
|
||||
for sample in puck.samples:
|
||||
sample_event_exists = (
|
||||
db.query(SampleEvent).filter(SampleEvent.sample_id == sample.id).first()
|
||||
)
|
||||
if sample_event_exists:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Cannot change beamtime:"
|
||||
"at least one sample has events recorded.",
|
||||
)
|
||||
|
||||
# Find the Beamtime instance, if not unassigning
|
||||
beamtime = (
|
||||
db.query(BeamtimeModel).filter(BeamtimeModel.id == beamtime_id).first()
|
||||
@ -609,9 +624,7 @@ async def assign_beamtime_to_dewar(
|
||||
if beamtime_id == 0:
|
||||
dewar.beamtimes = []
|
||||
else:
|
||||
dewar.beamtimes = [
|
||||
beamtime
|
||||
] # assign one; append if you want to support multiple
|
||||
dewar.beamtimes = [beamtime]
|
||||
|
||||
db.commit()
|
||||
db.refresh(dewar)
|
||||
@ -621,15 +634,11 @@ async def assign_beamtime_to_dewar(
|
||||
else:
|
||||
puck.beamtimes = [beamtime]
|
||||
for sample in puck.samples:
|
||||
has_sample_event = (
|
||||
db.query(SampleEvent).filter(SampleEvent.sample_id == sample.id).count()
|
||||
> 0
|
||||
)
|
||||
if not has_sample_event:
|
||||
if beamtime_id == 0:
|
||||
sample.beamtimes = []
|
||||
else:
|
||||
sample.beamtimes = [beamtime]
|
||||
# Can assume all have no events because of previous check
|
||||
if beamtime_id == 0:
|
||||
sample.beamtimes = []
|
||||
else:
|
||||
sample.beamtimes = [beamtime]
|
||||
|
||||
db.commit()
|
||||
return {"status": "success", "dewar_id": dewar.id, "beamtime_id": beamtime_id}
|
||||
@ -746,6 +755,7 @@ async def get_single_shipment(id: int, db: Session = Depends(get_db)):
|
||||
operation_id="get_dewars_by_beamtime",
|
||||
)
|
||||
async def get_dewars_by_beamtime(beamtime_id: int, db: Session = Depends(get_db)):
|
||||
logger.info(f"get_dewars_by_beamtime called with beamtime_id={beamtime_id}")
|
||||
beamtime = (
|
||||
db.query(BeamtimeModel)
|
||||
.options(joinedload(BeamtimeModel.dewars))
|
||||
@ -753,5 +763,9 @@ async def get_dewars_by_beamtime(beamtime_id: int, db: Session = Depends(get_db)
|
||||
.first()
|
||||
)
|
||||
if not beamtime:
|
||||
logger.warning(f"Beamtime {beamtime_id} not found")
|
||||
raise HTTPException(status_code=404, detail="Beamtime not found")
|
||||
logger.info(
|
||||
f"Returning {len(beamtime.dewars)} dewars: {[d.id for d in beamtime.dewars]}"
|
||||
)
|
||||
return beamtime.dewars
|
||||
|
@ -665,13 +665,25 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
|
||||
@router.patch("/puck/{puck_id}/assign-beamtime", operation_id="assignPuckToBeamtime")
|
||||
async def assign_beamtime_to_puck(
|
||||
puck_id: int,
|
||||
beamtime_id: int, # expects ?beamtime_id=123 in the query
|
||||
beamtime_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
puck = db.query(PuckModel).filter(PuckModel.id == puck_id).first()
|
||||
if not puck:
|
||||
raise HTTPException(status_code=404, detail="Puck not found")
|
||||
|
||||
# Check if any sample in this puck has sample events
|
||||
for sample in puck.samples:
|
||||
sample_event_exists = (
|
||||
db.query(SampleEvent).filter(SampleEvent.sample_id == sample.id).first()
|
||||
)
|
||||
if sample_event_exists:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Cannot change beamtime:"
|
||||
"at least one sample has events recorded.",
|
||||
)
|
||||
|
||||
beamtime = (
|
||||
db.query(BeamtimeModel).filter(BeamtimeModel.id == beamtime_id).first()
|
||||
if beamtime_id
|
||||
@ -681,22 +693,15 @@ async def assign_beamtime_to_puck(
|
||||
if beamtime_id == 0:
|
||||
puck.beamtimes = []
|
||||
else:
|
||||
puck.beamtimes = [
|
||||
beamtime
|
||||
] # or use .append(beamtime) if you want to support multiple
|
||||
puck.beamtimes = [beamtime]
|
||||
|
||||
db.commit()
|
||||
db.refresh(puck)
|
||||
# Update samples as well
|
||||
for sample in puck.samples:
|
||||
has_sample_event = (
|
||||
db.query(SampleEvent).filter(SampleEvent.sample_id == sample.id).count() > 0
|
||||
)
|
||||
if not has_sample_event:
|
||||
if beamtime_id == 0:
|
||||
sample.beamtimes = []
|
||||
else:
|
||||
sample.beamtimes = [beamtime]
|
||||
if beamtime_id == 0:
|
||||
sample.beamtimes = []
|
||||
else:
|
||||
sample.beamtimes = [beamtime]
|
||||
db.commit()
|
||||
return {"status": "success", "puck_id": puck.id, "beamtime_id": beamtime_id}
|
||||
|
||||
@ -707,6 +712,7 @@ async def assign_beamtime_to_puck(
|
||||
operation_id="get_pucks_by_beamtime",
|
||||
)
|
||||
async def get_pucks_by_beamtime(beamtime_id: int, db: Session = Depends(get_db)):
|
||||
logger.info(f"get_pucks_by_beamtime called with beamtime_id={beamtime_id}")
|
||||
beamtime = (
|
||||
db.query(BeamtimeModel)
|
||||
.options(joinedload(BeamtimeModel.pucks)) # eager load pucks
|
||||
@ -714,5 +720,9 @@ async def get_pucks_by_beamtime(beamtime_id: int, db: Session = Depends(get_db))
|
||||
.first()
|
||||
)
|
||||
if not beamtime:
|
||||
logger.warning(f"Beamtime {beamtime_id} not found")
|
||||
raise HTTPException(status_code=404, detail="Beamtime not found")
|
||||
logger.info(
|
||||
f"Returning {len(beamtime.pucks)} pucks: {[p.id for p in beamtime.pucks]}"
|
||||
)
|
||||
return beamtime.pucks
|
||||
|
@ -168,8 +168,8 @@ async def lifespan(app: FastAPI):
|
||||
load_slots_data(db)
|
||||
else: # dev or test environments
|
||||
print(f"{environment.capitalize()} environment: Regenerating database.")
|
||||
# Base.metadata.drop_all(bind=engine)
|
||||
# Base.metadata.create_all(bind=engine)
|
||||
Base.metadata.drop_all(bind=engine)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
# from sqlalchemy.engine import reflection
|
||||
# from app.models import ExperimentParameters # adjust the import as needed
|
||||
# inspector = reflection.Inspector.from_engine(engine)
|
||||
|
Reference in New Issue
Block a user