Add image upload endpoint and fix puck location handling
Introduced `/samples/{sample_id}/upload-images` API for uploading images tied to samples, validating file types, and saving them in structured directories. Fixed `puck_location_in_dewar` type handling in puck routes. Updated project version in `pyproject.toml`.
This commit is contained in:
@ -244,7 +244,7 @@ async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
|
||||
id=int(puck.id),
|
||||
puck_name=str(puck.puck_name),
|
||||
puck_type=str(puck.puck_type),
|
||||
puck_location_in_dewar=str(puck.puck_location_in_dewar)
|
||||
puck_location_in_dewar=int(puck.puck_location_in_dewar)
|
||||
if puck.puck_location_in_dewar
|
||||
else None,
|
||||
dewar_id=int(puck.dewar_id) if puck.dewar_id else None,
|
||||
@ -477,7 +477,7 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
|
||||
id=puck.id,
|
||||
puck_name=puck.puck_name,
|
||||
puck_type=puck.puck_type,
|
||||
puck_location_in_dewar=str(puck.puck_location_in_dewar)
|
||||
puck_location_in_dewar=int(puck.puck_location_in_dewar)
|
||||
if puck.puck_location_in_dewar
|
||||
else None,
|
||||
dewar_id=puck.dewar_id,
|
||||
|
@ -1,7 +1,9 @@
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
|
||||
from sqlalchemy.orm import Session
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
import shutil
|
||||
from app.schemas import (
|
||||
Puck as PuckSchema,
|
||||
Sample as SampleSchema,
|
||||
@ -98,3 +100,81 @@ async def get_last_sample_event(sample_id: int, db: Session = Depends(get_db)):
|
||||
raise HTTPException(status_code=404, detail="No events found for the sample")
|
||||
|
||||
return last_event # Response will automatically use the SampleEventResponse schema
|
||||
|
||||
|
||||
@router.post("/samples/{sample_id}/upload-images")
|
||||
async def upload_sample_images(
|
||||
sample_id: int,
|
||||
uploaded_files: List[UploadFile] = File(...), # Accept multiple files
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Uploads images for a sample and stores them in a directory structure:
|
||||
images/user/date/dewar_name/puck_name/position/.
|
||||
|
||||
Args:
|
||||
sample_id (int): ID of the sample.
|
||||
uploaded_files (List[UploadFile]): List of image files to be uploaded.
|
||||
db (Session): SQLAlchemy database session.
|
||||
"""
|
||||
# Fetch sample details from the database
|
||||
sample = db.query(SampleModel).filter(SampleModel.id == sample_id).first()
|
||||
if not sample:
|
||||
raise HTTPException(status_code=404, detail="Sample not found")
|
||||
|
||||
# Retrieve associated dewar_name, puck_name and position
|
||||
puck = sample.puck
|
||||
if not puck:
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"No puck associated with sample ID {sample_id}"
|
||||
)
|
||||
|
||||
dewar_name = puck.dewar.dewar_name if puck.dewar else None
|
||||
if not dewar_name:
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"No dewar associated with puck ID {puck.id}"
|
||||
)
|
||||
|
||||
puck_name = puck.puck_name
|
||||
position = sample.position
|
||||
|
||||
# Retrieve username (hardcoded for now—can be fetched dynamically if needed)
|
||||
username = "e16371"
|
||||
|
||||
# Today's date in the format YYYY-MM-DD
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
# Generate the directory path based on the structure
|
||||
base_dir = (
|
||||
Path("images") / username / today / dewar_name / puck_name / str(position)
|
||||
)
|
||||
|
||||
# Create directories if they don't exist
|
||||
base_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Save each uploaded image to the directory
|
||||
for file in uploaded_files:
|
||||
# Validate file content type
|
||||
if not file.content_type.startswith("image/"):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Invalid file type: {file.filename}. Must be an image.",
|
||||
)
|
||||
|
||||
# Create a file path for storing the uploaded file
|
||||
file_path = base_dir / file.filename
|
||||
|
||||
try:
|
||||
# Save the file
|
||||
with file_path.open("wb") as buffer:
|
||||
shutil.copyfileobj(file.file, buffer)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Error saving file {file.filename}: {str(e)}",
|
||||
)
|
||||
|
||||
return {
|
||||
"message": f"{len(uploaded_files)} images uploaded successfully.",
|
||||
"path": str(base_dir), # Return the base directory for reference
|
||||
}
|
||||
|
Reference in New Issue
Block a user