Refactor Dewar service methods and improve field handling

Updated Dewar API methods to use protected endpoints for enhanced security and consistency. Added `pgroups` handling in various frontend components and modified the LogisticsView contact field for clarity. Simplified backend router imports for better readability.
This commit is contained in:
GotthardG 2025-01-30 13:39:49 +01:00
parent 44582cf38e
commit c2215860bf
20 changed files with 304 additions and 262 deletions

View File

@ -9,6 +9,7 @@ from app.models import (
DewarType,
DewarSerialNumber,
SampleEvent,
LogisticsEvent,
)
from datetime import datetime, timedelta
import random
@ -196,11 +197,11 @@ dewars = [
tracking_number="TRACK123",
return_address_id=1,
contact_id=1,
status="Ready for Shipping",
ready_date=datetime.strptime("2023-09-30", "%Y-%m-%d"),
shipping_date=None,
arrival_date=None,
returning_date=None,
status="active",
# ready_date=datetime.strptime("2023-09-30", "%Y-%m-%d"),
# shipping_date=None,
# arrival_date=None,
# returning_date=None,
unique_id=generate_unique_id(),
),
Dewar(
@ -212,11 +213,11 @@ dewars = [
tracking_number="TRACK124",
return_address_id=2,
contact_id=2,
status="In Preparation",
ready_date=None,
shipping_date=None,
arrival_date=None,
returning_date=None,
status="active",
# ready_date=None,
# shipping_date=None,
# arrival_date=None,
# returning_date=None,
unique_id=generate_unique_id(),
),
Dewar(
@ -228,11 +229,11 @@ dewars = [
tracking_number="TRACK125",
return_address_id=1,
contact_id=3,
status="Not Shipped",
ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
shipping_date=None,
arrival_date=None,
returning_date=None,
status="active",
# ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
# shipping_date=None,
# arrival_date=None,
# returning_date=None,
unique_id=None,
),
Dewar(
@ -244,11 +245,11 @@ dewars = [
tracking_number="",
return_address_id=1,
contact_id=3,
status="Delayed",
ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
shipping_date=datetime.strptime("2024-01-02", "%Y-%m-%d"),
arrival_date=None,
returning_date=None,
status="active",
# ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
# shipping_date=datetime.strptime("2024-01-02", "%Y-%m-%d"),
# arrival_date=None,
# returning_date=None,
unique_id=None,
),
Dewar(
@ -257,16 +258,103 @@ dewars = [
dewar_name="Dewar Five",
dewar_type_id=1,
dewar_serial_number_id=1,
tracking_number="",
tracking_number="TRACK126",
return_address_id=1,
contact_id=3,
status="Returned",
arrival_date=datetime.strptime("2024-01-03", "%Y-%m-%d"),
returning_date=datetime.strptime("2024-01-07", "%Y-%m-%d"),
status="active",
# arrival_date=datetime.strptime("2024-01-03", "%Y-%m-%d"),
# returning_date=datetime.strptime("2024-01-07", "%Y-%m-%d"),
unique_id=None,
),
]
logistics_events = [
LogisticsEvent(
id=1,
event_type="in preparation",
dewar_id=1,
timestamp=datetime.strptime("2024-12-03", "%Y-%m-%d"),
),
LogisticsEvent(
id=2,
event_type="ready for shipping",
dewar_id=1,
timestamp=datetime.strptime("2024-12-03", "%Y-%m-%d"),
),
LogisticsEvent(
id=3,
event_type="shipped",
dewar_id=1,
timestamp=datetime.strptime("2024-12-04", "%Y-%m-%d"),
),
LogisticsEvent(
id=4,
event_type="arrived",
dewar_id=1,
timestamp=datetime.strptime("2024-12-06", "%Y-%m-%d"),
),
LogisticsEvent(
id=5,
event_type="returned",
dewar_id=1,
timestamp=datetime.strptime("2024-12-12", "%Y-%m-%d"),
),
LogisticsEvent(
id=6,
event_type="in preparation",
dewar_id=2,
timestamp=datetime.strptime("2025-01-06", "%Y-%m-%d"),
),
LogisticsEvent(
id=7,
event_type="ready",
dewar_id=2,
timestamp=datetime.strptime("2025-01-06", "%Y-%m-%d"),
),
LogisticsEvent(
id=8,
event_type="shipped",
dewar_id=2,
timestamp=datetime.strptime("2025-01-06", "%Y-%m-%d"),
),
LogisticsEvent(
id=9,
event_type="in preparation",
dewar_id=3,
timestamp=datetime.strptime("2025-01-06", "%Y-%m-%d"),
),
LogisticsEvent(
id=10,
event_type="ready",
dewar_id=3,
timestamp=datetime.strptime("2025-01-07", "%Y-%m-%d"),
),
LogisticsEvent(
id=11,
event_type="in preparation",
dewar_id=4,
timestamp=datetime.strptime("2025-01-12", "%Y-%m-%d"),
),
LogisticsEvent(
id=12,
event_type="ready",
dewar_id=5,
timestamp=datetime.strptime("2025-01-12", "%Y-%m-%d"),
),
LogisticsEvent(
id=12,
event_type="shipped",
dewar_id=5,
timestamp=datetime.strptime("2025-01-13", "%Y-%m-%d"),
),
LogisticsEvent(
id=12,
event_type="delayed",
dewar_id=5,
timestamp=datetime.strptime("2025-01-15", "%Y-%m-%d"),
),
]
# Define proposals
proposals = [
Proposal(id=1, number="202400125"),

View File

@ -86,13 +86,9 @@ class Dewar(Base):
dewar_serial_number_id = Column(
Integer, ForeignKey("dewar_serial_numbers.id"), nullable=True
)
tracking_number = Column(String(255), nullable=True)
status = Column(String(255), nullable=True)
ready_date = Column(Date, nullable=True)
shipping_date = Column(Date, nullable=True)
arrival_date = Column(Date, nullable=True)
returning_date = Column(Date, nullable=True)
unique_id = Column(String(255), unique=True, index=True, nullable=True)
tracking_number = Column(String(255), nullable=True)
shipment_id = Column(Integer, ForeignKey("shipments.id"))
return_address_id = Column(Integer, ForeignKey("addresses.id"))
contact_id = Column(Integer, ForeignKey("contacts.id"))

View File

@ -1,7 +1,7 @@
from .address import address_router
from .contact import contact_router
from .proposal import router as proposal_router
from .dewar import router as dewar_router
from .dewar import dewar_router
from .shipment import shipment_router
from .auth import router as auth_router
from .protected_router import protected_router as protected_router

View File

@ -9,7 +9,6 @@ from typing import List
import logging
from sqlalchemy.exc import SQLAlchemyError
from app.schemas import (
Dewar as DewarSchema,
DewarCreate,
DewarUpdate,
DewarType as DewarTypeSchema,
@ -21,7 +20,8 @@ from app.schemas import (
SampleUpdate,
Sample,
Puck,
SampleEventResponse, # Clearer name for schema
SampleEventResponse,
DewarSchema, # Clearer name for schema
)
from app.models import (
Dewar as DewarModel,
@ -42,11 +42,11 @@ from reportlab.lib.pagesizes import A5, landscape
from reportlab.lib.units import cm
from reportlab.pdfgen import canvas
from app.crud import (
get_shipments,
get_shipment_by_id,
) # Import CRUD functions for shipment
)
router = APIRouter()
dewar_router = APIRouter()
def generate_unique_id(db: Session, length: int = 16) -> str:
@ -63,12 +63,12 @@ def generate_unique_id(db: Session, length: int = 16) -> str:
return unique_id
@router.post("/", response_model=DewarSchema, status_code=status.HTTP_201_CREATED)
@dewar_router.post("/", response_model=Dewar, status_code=status.HTTP_201_CREATED)
async def create_or_update_dewar(
shipment_id: int,
dewar: DewarCreate,
db: Session = Depends(get_db),
) -> DewarSchema:
):
try:
# Query existing dewar by name within the shipment
existing_dewar = (
@ -170,14 +170,11 @@ async def create_or_update_dewar(
# Create a completely new dewar if none exists
dewar_obj = DewarModel(
pgroups=dewar.pgroups,
dewar_name=dewar.dewar_name,
tracking_number=dewar.tracking_number,
status=dewar.status,
ready_date=dewar.ready_date,
shipping_date=dewar.shipping_date,
arrival_date=dewar.arrival_date,
returning_date=dewar.returning_date,
contact_person_id=dewar.contact_person_id,
contact_id=dewar.contact_id,
return_address_id=dewar.return_address_id,
shipment_id=shipment_id, # Associate with the shipment
)
@ -220,7 +217,7 @@ async def create_or_update_dewar(
raise HTTPException(status_code=500, detail="Internal server error")
@router.post("/{dewar_id}/generate-qrcode")
@dewar_router.post("/{dewar_id}/generate-qrcode")
async def generate_dewar_qrcode(dewar_id: int, db: Session = Depends(get_db)):
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
if not dewar:
@ -365,7 +362,7 @@ def generate_label(dewar):
return buffer
@router.get("/{dewar_id}/download-label", response_class=Response)
@dewar_router.get("/{dewar_id}/download-label", response_class=Response)
async def download_dewar_label(dewar_id: int, db: Session = Depends(get_db)):
dewar = (
db.query(DewarModel)
@ -397,7 +394,7 @@ async def download_dewar_label(dewar_id: int, db: Session = Depends(get_db)):
)
@router.put("/samples/{sample_id}", response_model=Sample)
@dewar_router.put("/samples/{sample_id}", response_model=Sample)
async def update_sample(
sample_id: int,
sample_update: SampleUpdate,
@ -431,7 +428,7 @@ async def update_sample(
return Sample.from_orm(sample)
@router.get("/dewars/{dewar_id}/samples", response_model=Dewar)
@dewar_router.get("/dewars/{dewar_id}/samples", response_model=Dewar)
async def get_dewar_samples(dewar_id: int, db: Session = Depends(get_db)):
# Fetch the Dewar with nested relationships
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
@ -441,6 +438,7 @@ async def get_dewar_samples(dewar_id: int, db: Session = Depends(get_db)):
# Explicitly map nested relationships
dewar_data = {
"id": dewar.id,
"pgroups": dewar.pgroups,
"dewar_name": dewar.dewar_name,
"tracking_number": dewar.tracking_number,
"status": dewar.status,
@ -448,14 +446,10 @@ async def get_dewar_samples(dewar_id: int, db: Session = Depends(get_db)):
"number_of_samples": sum(
len(puck.samples) for puck in dewar.pucks
), # Calculate total samples
"ready_date": dewar.ready_date,
"shipping_date": dewar.shipping_date,
"arrival_date": dewar.arrival_date,
"returning_date": dewar.returning_date,
"contact_person_id": dewar.contact_person.id if dewar.contact_person else None,
"contact_id": dewar.contact.id if dewar.contact else None,
"return_address_id": dewar.return_address.id if dewar.return_address else None,
"shipment_id": dewar.shipment_id,
"contact_person": dewar.contact_person,
"contact": dewar.contact,
"return_address": dewar.return_address,
"pucks": [
Puck(
@ -492,7 +486,7 @@ async def get_dewar_samples(dewar_id: int, db: Session = Depends(get_db)):
return Dewar(**dewar_data)
@router.get("/", response_model=List[DewarSchema])
@dewar_router.get("/", response_model=List[Dewar])
async def get_dewars(db: Session = Depends(get_db)):
try:
dewars = db.query(DewarModel).options(joinedload(DewarModel.pucks)).all()
@ -502,12 +496,12 @@ async def get_dewars(db: Session = Depends(get_db)):
raise HTTPException(status_code=500, detail="Internal server error")
@router.get("/dewar-types", response_model=List[DewarTypeSchema])
@dewar_router.get("/dewar-types", response_model=List[DewarTypeSchema])
def get_dewar_types(db: Session = Depends(get_db)):
return db.query(DewarTypeModel).all()
@router.get(
@dewar_router.get(
"/dewar-types/{type_id}/serial-numbers",
response_model=List[DewarSerialNumberSchema],
)
@ -519,7 +513,7 @@ def get_serial_numbers(type_id: int, db: Session = Depends(get_db)):
)
@router.post("/dewar-types", response_model=DewarTypeSchema)
@dewar_router.post("/dewar-types", response_model=DewarTypeSchema)
def create_dewar_type(dewar_type: DewarTypeCreate, db: Session = Depends(get_db)):
db_type = DewarTypeModel(**dewar_type.dict())
db.add(db_type)
@ -528,7 +522,7 @@ def create_dewar_type(dewar_type: DewarTypeCreate, db: Session = Depends(get_db)
return db_type
@router.post("/dewar-serial-numbers", response_model=DewarSerialNumberSchema)
@dewar_router.post("/dewar-serial-numbers", response_model=DewarSerialNumberSchema)
def create_dewar_serial_number(
serial_number: DewarSerialNumberCreate, db: Session = Depends(get_db)
):
@ -539,7 +533,7 @@ def create_dewar_serial_number(
return db_serial
@router.get("/dewar-serial-numbers", response_model=List[DewarSerialNumberSchema])
@dewar_router.get("/dewar-serial-numbers", response_model=List[DewarSerialNumberSchema])
def get_all_serial_numbers(db: Session = Depends(get_db)):
try:
serial_numbers = db.query(DewarSerialNumberModel).all()
@ -549,13 +543,13 @@ def get_all_serial_numbers(db: Session = Depends(get_db)):
raise HTTPException(status_code=500, detail="Internal server error")
@router.get("/{dewar_id}", response_model=DewarSchema)
@dewar_router.get("/{dewar_id}", response_model=Dewar)
async def get_dewar(dewar_id: int, db: Session = Depends(get_db)):
dewar = (
db.query(DewarModel)
.options(
joinedload(DewarModel.pucks).joinedload(PuckModel.samples),
joinedload(DewarModel.contact_person),
joinedload(DewarModel.contact),
joinedload(DewarModel.return_address),
joinedload(DewarModel.shipment),
)
@ -569,10 +563,10 @@ async def get_dewar(dewar_id: int, db: Session = Depends(get_db)):
return DewarSchema.from_orm(dewar)
@router.put("/{dewar_id}", response_model=DewarSchema)
@dewar_router.put("/{dewar_id}", response_model=Dewar)
async def update_dewar(
dewar_id: int, dewar_update: DewarUpdate, db: Session = Depends(get_db)
) -> DewarSchema:
) -> Dewar:
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
if not dewar:
@ -587,7 +581,7 @@ async def update_dewar(
return dewar
@router.delete("/{dewar_id}", status_code=status.HTTP_204_NO_CONTENT)
@dewar_router.delete("/{dewar_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_dewar(dewar_id: int, db: Session = Depends(get_db)):
# Fetch the Dewar from the database
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
@ -642,18 +636,7 @@ async def delete_dewar(dewar_id: int, db: Session = Depends(get_db)):
return
# New routes for shipments
@router.get("/shipments", response_model=List[ShipmentSchema])
async def get_all_shipments(db: Session = Depends(get_db)):
try:
shipments = get_shipments(db)
return shipments
except SQLAlchemyError as e:
logging.error(f"Database error occurred: {e}")
raise HTTPException(status_code=500, detail="Internal server error")
@router.get("/shipments/{id}", response_model=ShipmentSchema)
@dewar_router.get("/shipments/{id}", response_model=ShipmentSchema)
async def get_single_shipment(id: int, db: Session = Depends(get_db)):
try:
shipment = get_shipment_by_id(db, id)

View File

@ -263,9 +263,9 @@ async def get_all_slots(db: Session = Depends(get_db)):
# Correct the contact_person assignment
contact_person = None
if slot.dewar and slot.dewar.contact_person:
first_name = slot.dewar.contact_person.firstname
last_name = slot.dewar.contact_person.lastname
if slot.dewar and slot.dewar.contact:
first_name = slot.dewar.contact.firstname
last_name = slot.dewar.contact.lastname
contact_person = f"{first_name} {last_name}"
# Prepare the slot data for the response
@ -287,7 +287,7 @@ async def get_all_slots(db: Session = Depends(get_db)):
if slot.dewar and slot.dewar.shipment
else None
),
contact_person=contact_person,
contact=contact_person,
local_contact="local contact placeholder",
)
# Add updated slot data to the response list

View File

@ -4,6 +4,7 @@ from app.routers.auth import get_current_user
from app.routers.address import address_router
from app.routers.contact import contact_router
from app.routers.shipment import shipment_router
from app.routers.dewar import dewar_router
protected_router = APIRouter(
dependencies=[Depends(get_current_user)] # Applies to all routes
@ -14,3 +15,4 @@ protected_router.include_router(contact_router, prefix="/contacts", tags=["conta
protected_router.include_router(
shipment_router, prefix="/shipments", tags=["shipments"]
)
protected_router.include_router(dewar_router, prefix="/dewars", tags=["dewars"])

View File

@ -251,6 +251,9 @@ async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
dewar_name=str(dewar.dewar_name)
if dewar and dewar.dewar_name
else None,
pgroup=str(dewar.pgroups)
if dewar.pgroups
else None, # will be replaced later by puck pgroup
samples=[
Sample(
id=sample.id,
@ -413,6 +416,7 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
dewar_ids = [dewar.id for dewar in dewars]
dewar_map = {dewar.id: dewar.dewar_name for dewar in dewars}
dewar_pgroups = {dewar.id: dewar.pgroups for dewar in dewars}
# Subquery to fetch the latest event for each puck (any type of event)
latest_event_subquery = (
@ -430,9 +434,9 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
PuckModel,
PuckEventModel.event_type,
PuckEventModel.tell_position,
DewarModel, # Include DewarModel
)
.join( # Join pucks with the latest event
# (outer join to include pucks without events)
latest_event_subquery,
PuckModel.id == latest_event_subquery.c.puck_id,
isouter=True,
@ -443,6 +447,11 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
& (PuckEventModel.timestamp == latest_event_subquery.c.latest_event_time),
isouter=True,
)
.join( # Join with DewarModel to get dewar details
DewarModel,
PuckModel.dewar_id == DewarModel.id,
isouter=True,
)
.filter(PuckModel.dewar_id.in_(dewar_ids)) # Restrict pucks to relevant dewars
.all()
)
@ -458,13 +467,16 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
# Prepare the final response
results = []
for puck, event_type, tell_position in pucks_with_latest_events:
for puck, event_type, dewar, tell_position in pucks_with_latest_events:
logger.debug(
f"Puck ID: {puck.id}, Name: {puck.puck_name}, Event Type: {event_type}, "
f"Tell Position: {tell_position}"
)
dewar_name = dewar_map.get(puck.dewar_id, "Unknown")
pgroup = dewar_pgroups.get(
puck.dewar_id
) # will be replaced later by puck pgroup
# For pucks with no events or whose latest event is `puck_removed`, set
# `tell_position` to None
@ -475,6 +487,7 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
results.append(
PuckWithTellPosition(
id=puck.id,
pgroup=pgroup,
puck_name=puck.puck_name,
puck_type=puck.puck_type,
puck_location_in_dewar=int(puck.puck_location_in_dewar)

View File

@ -111,7 +111,7 @@ async def upload_sample_images(
raise HTTPException(status_code=404, detail="Sample not found")
# 2. Define Directory Structure
username = "e16371" # Hardcoded username; replace with dynamic logic if applicable
pgroup = sample.puck.dewar.pgroups
today = datetime.now().strftime("%Y-%m-%d")
dewar_name = (
sample.puck.dewar.dewar_name
@ -120,7 +120,7 @@ async def upload_sample_images(
)
puck_name = sample.puck.puck_name if sample.puck else "default_puck"
position = sample.position if sample.position else "default_position"
base_dir = Path(f"images/{username}/{today}/{dewar_name}/{puck_name}/{position}")
base_dir = Path(f"images/{pgroup}/{today}/{dewar_name}/{puck_name}/{position}")
base_dir.mkdir(parents=True, exist_ok=True)
# 3. Process and Save Each File

View File

@ -3,6 +3,8 @@ from sqlalchemy.orm import Session
from typing import List
from datetime import date
import json
import logging
from sqlalchemy.exc import SQLAlchemyError
from app.models import (
Shipment as ShipmentModel,
@ -20,11 +22,11 @@ from app.schemas import (
Shipment as ShipmentSchema,
Contact as ContactSchema,
Sample as SampleSchema,
DewarSchema,
loginData,
Dewar,
)
from app.database import get_db
from app.crud import get_shipment_by_id
from app.crud import get_shipment_by_id, get_shipments
from app.routers.auth import get_current_user
shipment_router = APIRouter()
@ -59,7 +61,17 @@ async def fetch_shipments(
return shipments
@shipment_router.get("/{shipment_id}/dewars", response_model=List[DewarSchema])
@shipment_router.get("/shipments", response_model=List[ShipmentSchema])
async def get_all_shipments(db: Session = Depends(get_db)):
try:
shipments = get_shipments(db)
return shipments
except SQLAlchemyError as e:
logging.error(f"Database error occurred: {e}")
raise HTTPException(status_code=500, detail="Internal server error")
@shipment_router.get("/{shipment_id}/dewars", response_model=List[Dewar])
async def get_dewars_by_shipment_id(shipment_id: int, db: Session = Depends(get_db)):
shipment = db.query(ShipmentModel).filter(ShipmentModel.id == shipment_id).first()
if not shipment:

View File

@ -429,7 +429,7 @@ class Sample(BaseModel):
priority: Optional[int] = None
comments: Optional[str] = None
data_collection_parameters: Optional[DataCollectionParameters]
events: List[SampleEventResponse]
events: List[SampleEventResponse] = []
mount_count: Optional[int] = None
unmount_count: Optional[int] = None
# results: Optional[Results] = None
@ -497,6 +497,7 @@ class Puck(BaseModel):
class DewarBase(BaseModel):
pgroups: str
dewar_name: str
dewar_type_id: Optional[int] = None
dewar_serial_number_id: Optional[int] = None
@ -505,10 +506,6 @@ class DewarBase(BaseModel):
number_of_pucks: Optional[int] = None
number_of_samples: Optional[int] = None
status: str
ready_date: Optional[date]
shipping_date: Optional[date]
arrival_date: Optional[date]
returning_date: Optional[date]
contact_id: Optional[int]
return_address_id: Optional[int]
pucks: List[PuckCreate] = []
@ -534,22 +531,20 @@ class Dewar(DewarBase):
class DewarUpdate(BaseModel):
pgroups: str
dewar_name: Optional[str] = None
dewar_type_id: Optional[int] = None
dewar_serial_number_id: Optional[int] = None
unique_id: Optional[str] = None
tracking_number: Optional[str] = None
status: Optional[str] = None
ready_date: Optional[date] = None
shipping_date: Optional[date] = None
arrival_date: Optional[date] = None
returning_date: Optional[date] = None
contact_id: Optional[int] = None
address_id: Optional[int] = None
class DewarSchema(BaseModel):
id: int
pgroups: str
dewar_name: str
tracking_number: str
status: str
@ -559,6 +554,9 @@ class DewarSchema(BaseModel):
class Config:
from_attributes = True
# shipping status etc will become a logistics event.
# Tracking will also become an event
class Proposal(BaseModel):
id: int
@ -681,7 +679,7 @@ class PuckWithTellPosition(BaseModel):
dewar_name: Optional[
str
] # was changed to optional but probably needs to be not optional
user: str = "e16371"
pgroup: str
samples: Optional[List[Sample]] = None
tell_position: Optional[str]

View File

@ -7,7 +7,6 @@ from fastapi.middleware.cors import CORSMiddleware
from app import ssl_heidi
from app.routers import (
proposal,
dewar,
puck,
spreadsheet,
logistics,
@ -137,8 +136,8 @@ def on_startup():
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)
if environment == "dev":
from app.database import load_sample_data
@ -152,10 +151,9 @@ def on_startup():
# Include routers with correct configuration
app.include_router(protected_router, prefix="/protected", tags=["protected"])
app.include_router(protected_router, prefix="/protected")
app.include_router(auth.router, prefix="/auth", tags=["auth"])
app.include_router(proposal.router, prefix="/proposals", tags=["proposals"])
app.include_router(dewar.router, prefix="/dewars", tags=["dewars"])
app.include_router(puck.router, prefix="/pucks", tags=["pucks"])
app.include_router(spreadsheet.router, tags=["spreadsheet"])
app.include_router(logistics.router, prefix="/logistics", tags=["logistics"])

View File

@ -117,7 +117,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
useEffect(() => {
const fetchDewarTypes = async () => {
try {
const response = await DewarsService.getDewarTypesDewarsDewarTypesGet();
const response = await DewarsService.getDewarTypesProtectedDewarsDewarTypesGet();
setKnownDewarTypes(response ?? []);
} catch (error) {
setFeedbackMessage('Failed to fetch dewar types.');
@ -132,7 +132,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
useEffect(() => {
const fetchSerialNumbers = async () => {
try {
const response = await DewarsService.getAllSerialNumbersDewarsDewarSerialNumbersGet();
const response = await DewarsService.getAllSerialNumbersProtectedDewarsDewarSerialNumbersGet();
setKnownSerialNumbers(response ?? []);
} catch (error) {
setFeedbackMessage('Failed to fetch serial numbers.');
@ -248,8 +248,8 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
const handleSaveNewDewarTypeAndSerialNumber = async () => {
if (newDewarType) {
try {
const typeResponse = await DewarsService.createDewarTypeDewarsDewarTypesPost({ dewar_type: newDewarType });
const serialResponse = await DewarsService.createDewarSerialNumberDewarsDewarSerialNumbersPost({
const typeResponse = await DewarsService.createDewarTypeProtectedDewarsDewarTypesPost({ dewar_type: newDewarType });
const serialResponse = await DewarsService.createDewarSerialNumberProtectedDewarsDewarSerialNumbersPost({
serial_number: newDewarSerialNumber,
dewar_type_id: typeResponse.id,
});
@ -266,7 +266,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
}
} else if (newDewarSerialNumber && selectedDewarType) {
try {
const response = await DewarsService.createDewarSerialNumberDewarsDewarSerialNumbersPost({
const response = await DewarsService.createDewarSerialNumberProtectedDewarsDewarSerialNumbersPost({
serial_number: newDewarSerialNumber,
dewar_type_id: parseInt(selectedDewarType, 10),
});
@ -371,6 +371,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
try {
const payload = {
pgroups: activePgroup,
dewar_name: dewar.dewar_name,
dewar_type_id: parseInt(selectedDewarType, 10),
dewar_serial_number_id: parseInt(selectedSerialNumber, 10),
@ -378,15 +379,11 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
number_of_pucks: dewar.number_of_pucks,
number_of_samples: dewar.number_of_samples,
status: dewar.status,
ready_date: formatDate(dewar.ready_date),
shipping_date: formatDate(dewar.shipping_date),
arrival_date: dewar.arrival_date,
returning_date: dewar.returning_date,
return_address_id: parseInt(selectedReturnAddress ?? '', 10),
contact_id: parseInt(selectedContact ?? '', 10),
};
await DewarsService.updateDewarDewarsDewarIdPut(dewarId, payload);
await DewarsService.updateDewarProtectedDewarsDewarIdPut(dewarId, payload);
setFeedbackMessage('Changes saved successfully.');
setChangesMade(false);
} catch (error) {
@ -408,7 +405,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
if (!dewar) return;
try {
const response = await DewarsService.generateDewarQrcodeDewarsDewarIdGenerateQrcodePost(dewar.id);
const response = await DewarsService.generateDewarQrcodeProtectedDewarsDewarIdGenerateQrcodePost(dewar.id);
const newQrCodeValue = response.unique_id;
setQrCodeValue(newQrCodeValue);
setIsQRCodeGenerated(true);
@ -426,7 +423,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
if (!dewar) return;
try {
const response = await DewarsService.downloadDewarLabelDewarsDewarIdDownloadLabelGet(dewar.id);
const response = await DewarsService.downloadDewarLabelProtectedDewarsDewarIdDownloadLabelGet(dewar.id);
// The response object might need parsing
const blob = new Blob([response as any], { type: 'application/pdf' });

View File

@ -19,7 +19,7 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
const fetchSamples = async () => {
try {
const response = await DewarsService.getDewarSamplesDewarsDewarsDewarIdSamplesGet(dewarId);
const response = await DewarsService.getDewarSamplesProtectedDewarsDewarsDewarIdSamplesGet(dewarId);
console.log("Response from backend:", response);
const dewarData = response; // Assume response is already in correct structure
@ -173,7 +173,7 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
);
// API call to persist changes
await DewarsService.updateSampleDewarsSamplesSampleIdPut(Number(id), updatedSample);
await DewarsService.updateSampleProtectedDewarsSamplesSampleIdPut(Number(id), updatedSample);
console.log(`Sample with ID ${id} successfully updated.`);
} catch (error) {
@ -237,7 +237,7 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
);
// Send the payload to the backend
await DewarsService.updateSampleDewarsSamplesSampleIdPut(Number(newRow.id), payload);
await DewarsService.updateSampleProtectedDewarsSamplesSampleIdPut(Number(newRow.id), payload);
console.log(`Successfully updated sample with ID ${newRow.id}.`);
return payload; // Return the updated row

View File

@ -48,11 +48,6 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
tracking_number: '',
number_of_pucks: 0,
number_of_samples: 0,
status: 'In preparation',
ready_date: null,
shipping_date: null,
arrival_date: null,
returning_date: null,
contact_id: selectedShipment?.contact?.id,
return_address_id: selectedShipment?.return_address?.id,
};
@ -126,16 +121,18 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
const newDewarToPost: Dewar = {
...initialNewDewarState,
...newDewar,
pgroups:activePgroup,
dewar_name: newDewar.dewar_name.trim(),
contact_id: selectedShipment?.contact?.id,
return_address_id: selectedShipment?.return_address?.id
return_address_id: selectedShipment?.return_address?.id,
status: 'active',
} as Dewar;
if (!newDewarToPost.dewar_name || !newDewarToPost.status) {
throw new Error('Missing required fields');
}
const createdDewar = await DewarsService.createOrUpdateDewarDewarsPost(selectedShipment.id, newDewarToPost);
const createdDewar = await DewarsService.createOrUpdateDewarProtectedDewarsPost(selectedShipment.id, newDewarToPost);
if (createdDewar && selectedShipment) {
const updatedShipment = await ShipmentsService.addDewarToShipmentProtectedShipmentsShipmentIdAddDewarPost(selectedShipment.id, createdDewar.id);

View File

@ -197,6 +197,7 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
);
})}
<UploadDialog
activePgroup={activePgroup}
open={uploadDialogOpen}
onClose={closeUploadDialog}
selectedShipment={selectedShipment}

View File

@ -31,6 +31,7 @@ const SpreadsheetTable = ({
fileBlob,
selectedShipment,
addinfo,
activePgroup,
}) => {
const [localErrors, setLocalErrors] = useState(errors || []);
const [editingCell, setEditingCell] = useState({});
@ -59,17 +60,14 @@ const SpreadsheetTable = ({
console.log("Addinfo:", addinfo);
}, [correctionMetadata, addinfo]);
const initialNewDewarState = {
pgroups: activePgroup,
number_of_pucks: 0,
number_of_samples: 0,
ready_date: null,
shipping_date: null,
arrival_date: null,
returning_date: null,
contact_id: selectedShipment?.contact?.id,
return_address_id: selectedShipment?.return_address?.id,
dewar_name: '',
tracking_number: 'UNKNOWN',
status: 'In preparation',
status: 'active',
pucks: [] // Ensure 'pucks' array exists
};
@ -242,7 +240,7 @@ const SpreadsheetTable = ({
try {
// Fetch dewars related to the current shipment via API
const shipDewars = await ShipmentsService.getDewarsByShipmentIdShipmentsShipmentIdDewarsGet(selectedShipment.id);
const shipDewars = await ShipmentsService.getDewarsByShipmentIdProtectedShipmentsShipmentIdDewarsGet(selectedShipment.id);
// Search for dewar by name within the shipment
const existingDewar = shipDewars.find((d) => d.dewar_name === dewarName);
@ -258,8 +256,8 @@ const SpreadsheetTable = ({
}
};
const createOrUpdateDewarsFromSheet = async (data, contactPerson, returnAddress) => {
if (!contact?.id || !returnAddress?.id) {
const createOrUpdateDewarsFromSheet = async (data, contact, address) => {
if (!contact?.id || !address?.id) {
console.error('contact_id or return_address_id is missing');
return null;
}
@ -287,9 +285,10 @@ const SpreadsheetTable = ({
// Initialize new dewar object
dewar = {
...initialNewDewarState,
pgroups: activePgroup,
dewar_name: dewarName,
contact_id: contactPerson.id,
return_address_id: returnAddress.id,
contact_id: contact.id,
return_address_id: address.id,
pucks: [],
};
dewars.set(dewarName, dewar);
@ -442,7 +441,7 @@ const SpreadsheetTable = ({
const { number_of_pucks, number_of_samples, ...payload } = dewar;
// Attempt to create or update a dewar
await DewarsService.createOrUpdateDewarDewarsPost(selectedShipment.id, payload);
await DewarsService.createOrUpdateDewarProtectedDewarsPost(selectedShipment.id, payload);
console.log(`Dewar "${dewar.dewar_name}" created/updated successfully.`);
} catch (error: any) {

View File

@ -12,12 +12,13 @@ import SpreadsheetTable from './SpreadsheetTable';
import Modal from './Modal';
interface UploadDialogProps {
activePgroup: string;
open: boolean;
onClose: () => void;
selectedShipment: any;
}
const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShipment }) => {
const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShipment, activePgroup }) => {
const [uploadError, setUploadError] = useState<string | null>(null);
const [fileSummary, setFileSummary] = useState<any>(null);
const [fileBlob, setFileBlob] = useState<Blob | null>(null);
@ -180,6 +181,7 @@ const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShip
onCancel={handleCancel}
fileBlob={fileBlob}
selectedShipment={selectedShipment}
activePgroup={activePgroup}
addinfo={fileSummary.addinfo}
/>
</Modal>

View File

@ -53,7 +53,7 @@ interface SlotData extends SlotSchema {
retrievedTimestamp?: string;
beamlineLocation?: string;
shipment_name?: string;
contact_person?: string;
contact?: string;
local_contact?: string;
}
@ -155,7 +155,7 @@ const LogisticsView: React.FC = () => {
needsRefillWarning: true,
beamlineLocation: undefined,
shipmnet_name: undefined,
contact_person: undefined,
contact: undefined,
local_contact: undefined,
};
} else {
@ -174,7 +174,7 @@ const LogisticsView: React.FC = () => {
needsRefillWarning: !associatedDewar || slot.time_until_refill === undefined,
beamlineLocation: slot.beamlineLocation,
shipment_name: slot.shipment_name,
contact_person: slot.contact_person,
contact: slot.contact,
local_contact: slot.local_contact,
};
});
@ -456,7 +456,7 @@ const LogisticsView: React.FC = () => {
<Typography variant="h6">{selectedSlotData.label}</Typography>
<Typography variant="body2">{`Shipment: ${selectedSlotData.shipment_name}`}</Typography>
<Typography variant="body2">{`Dewar: ${selectedSlotData.dewar_name || 'N/A'}`}</Typography>
<Typography variant="body2">{`Contact Person: ${selectedSlotData.contact_person}`}</Typography>
<Typography variant="body2">{`Contact Person: ${selectedSlotData.contact}`}</Typography>
<Typography variant="body2">{`QR Code: ${selectedSlotData.qr_code}`}</Typography>
<Typography variant="body2">{`Occupied: ${selectedSlotData.occupied ? 'Yes' : 'No'}`}</Typography>
<Typography variant="body2">{`Needs Refill: ${selectedSlotData.needsRefillWarning ? 'Yes' : 'No'}`}</Typography>

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "aareDB"
version = "0.1.0a19"
version = "0.1.0a20"
description = "Backend for next gen sample management system"
authors = [{name = "Guillaume Gotthard", email = "guillaume.gotthard@psi.ch"}]
license = {text = "MIT"}

View File

@ -6,8 +6,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2025-01-20T14:44:37.526742Z",
"start_time": "2025-01-20T14:44:37.522704Z"
"end_time": "2025-01-30T11:29:38.703954Z",
"start_time": "2025-01-30T11:29:38.307050Z"
}
},
"source": [
@ -42,18 +42,18 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0.1.0a19\n",
"0.1.0a20\n",
"https://127.0.0.1:8000\n"
]
}
],
"execution_count": 2
"execution_count": 1
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-01-20T14:44:58.875370Z",
"start_time": "2025-01-20T14:44:58.805520Z"
"end_time": "2025-01-30T11:07:14.795059Z",
"start_time": "2025-01-30T11:07:14.783786Z"
}
},
"cell_type": "code",
@ -95,52 +95,11 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Shipment ID: 2, Shipment Name: Shipment from Mordor\n",
" Dewar ID: 1, Dewar Name: Dewar One, Dewar Unique ID: 83041c3f8844ff39 \n",
" Puck ID: 1, Puck Name: PUCK-001\n",
" Puck ID: 2, Puck Name: PUCK002\n",
" Puck ID: 3, Puck Name: PUCK003\n",
" Puck ID: 4, Puck Name: PUCK004\n",
" Puck ID: 5, Puck Name: PUCK005\n",
" Puck ID: 6, Puck Name: PUCK006\n",
" Puck ID: 7, Puck Name: PUCK007\n",
" Dewar ID: 2, Dewar Name: Dewar Two, Dewar Unique ID: 62baccecdd37c033 \n",
" Puck ID: 8, Puck Name: PK001\n",
" Puck ID: 9, Puck Name: PK002\n",
" Puck ID: 10, Puck Name: PK003\n",
" Puck ID: 11, Puck Name: PK004\n",
" Puck ID: 12, Puck Name: PK005\n",
" Puck ID: 13, Puck Name: PK006\n",
"Shipment ID: 3, Shipment Name: Shipment from Mordor\n",
" Dewar ID: 3, Dewar Name: Dewar Three, Dewar Unique ID: None \n",
" Puck ID: 14, Puck Name: P001\n",
" Puck ID: 15, Puck Name: P002\n",
" Puck ID: 16, Puck Name: P003\n",
" Puck ID: 17, Puck Name: P004\n",
" Puck ID: 18, Puck Name: P005\n",
" Puck ID: 19, Puck Name: P006\n",
" Puck ID: 20, Puck Name: P007\n",
" Dewar ID: 4, Dewar Name: Dewar Four, Dewar Unique ID: None \n",
" Puck ID: 21, Puck Name: PC002\n",
" Puck ID: 22, Puck Name: PC003\n",
" Puck ID: 23, Puck Name: PC004\n",
" Puck ID: 24, Puck Name: PC005\n",
" Puck ID: 25, Puck Name: PC006\n",
" Puck ID: 26, Puck Name: PC007\n",
"Shipment ID: 1, Shipment Name: Shipment from Mordor\n",
" Dewar ID: 5, Dewar Name: Dewar Five, Dewar Unique ID: 15e3dbe05e78ee83 \n",
" Puck ID: 27, Puck Name: PKK004\n",
" Puck ID: 28, Puck Name: PKK005\n",
" Puck ID: 29, Puck Name: PKK006\n",
" Puck ID: 30, Puck Name: PKK007\n",
"Shipment ID: 4, Shipment Name: testship\n",
" Dewar ID: 6, Dewar Name: Dewar_test, Dewar Unique ID: f352529444d64dd5 \n",
" Puck ID: 43, Puck Name: CPS-4093\n",
" Puck ID: 44, Puck Name: CPS-4178\n",
" Puck ID: 45, Puck Name: PSIMX-122\n",
" Puck ID: 46, Puck Name: CPS-6597\n",
" Puck ID: 47, Puck Name: PSIMX-078\n",
" Puck ID: 48, Puck Name: 1002\n"
"Exception when calling ShipmentsApi->fetch_shipments_shipments_get: (404)\n",
"Reason: Not Found\n",
"HTTP response headers: HTTPHeaderDict({'date': 'Thu, 30 Jan 2025 11:07:14 GMT', 'server': 'uvicorn', 'content-length': '22', 'content-type': 'application/json'})\n",
"HTTP response body: {\"detail\":\"Not Found\"}\n",
"\n"
]
},
{
@ -152,7 +111,7 @@
]
}
],
"execution_count": 3
"execution_count": 6
},
{
"metadata": {
@ -253,8 +212,8 @@
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-01-17T14:07:51.580993Z",
"start_time": "2025-01-17T14:07:51.565128Z"
"end_time": "2025-01-30T11:35:20.036682Z",
"start_time": "2025-01-30T11:35:20.018284Z"
}
},
"cell_type": "code",
@ -283,12 +242,13 @@
"text": [
"The response of PucksApi->get_pucks_by_slot_pucks_slot_slot_identifier_get:\n",
"\n",
"[PuckWithTellPosition(id=43, puck_name='CPS-4093', puck_type='unipuck', puck_location_in_dewar=1, dewar_id=6, dewar_name='Dewar_test', user='e16371', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=44, puck_name='CPS-4178', puck_type='unipuck', puck_location_in_dewar=2, dewar_id=6, dewar_name='Dewar_test', user='e16371', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=45, puck_name='PSIMX-122', puck_type='unipuck', puck_location_in_dewar=3, dewar_id=6, dewar_name='Dewar_test', user='e16371', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=46, puck_name='CPS-6597', puck_type='unipuck', puck_location_in_dewar=4, dewar_id=6, dewar_name='Dewar_test', user='e16371', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=47, puck_name='PSIMX-078', puck_type='unipuck', puck_location_in_dewar=5, dewar_id=6, dewar_name='Dewar_test', user='e16371', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=48, puck_name='1002', puck_type='unipuck', puck_location_in_dewar=6, dewar_id=6, dewar_name='Dewar_test', user='e16371', samples=None, tell_position=None)]\n"
"[PuckWithTellPosition(id=1, puck_name='PUCK-001', puck_type='Unipuck', puck_location_in_dewar=1, dewar_id=1, dewar_name='Dewar One', pgroup='p20001', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=2, puck_name='PUCK002', puck_type='Unipuck', puck_location_in_dewar=2, dewar_id=1, dewar_name='Dewar One', pgroup='p20001', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=3, puck_name='PUCK003', puck_type='Unipuck', puck_location_in_dewar=3, dewar_id=1, dewar_name='Dewar One', pgroup='p20001', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=4, puck_name='PUCK004', puck_type='Unipuck', puck_location_in_dewar=4, dewar_id=1, dewar_name='Dewar One', pgroup='p20001', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=5, puck_name='PUCK005', puck_type='Unipuck', puck_location_in_dewar=5, dewar_id=1, dewar_name='Dewar One', pgroup='p20001', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=6, puck_name='PUCK006', puck_type='Unipuck', puck_location_in_dewar=6, dewar_id=1, dewar_name='Dewar One', pgroup='p20001', samples=None, tell_position=None),\n",
" PuckWithTellPosition(id=7, puck_name='PUCK007', puck_type='Unipuck', puck_location_in_dewar=7, dewar_id=1, dewar_name='Dewar One', pgroup='p20001', samples=None, tell_position=None)]\n"
]
},
{
@ -300,17 +260,19 @@
]
}
],
"execution_count": 42
"execution_count": 5
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-01-17T14:09:55.141237Z",
"start_time": "2025-01-17T14:09:55.117843Z"
"end_time": "2025-01-30T12:30:46.242711Z",
"start_time": "2025-01-30T12:30:46.215343Z"
}
},
"cell_type": "code",
"source": [
"from aareDBclient import SetTellPosition\n",
"\n",
"# Attribute a puck to a position in the TELL dewar\n",
"\n",
"with aareDBclient.ApiClient(configuration) as api_client:\n",
@ -321,7 +283,7 @@
" # This part is commented but will be used to attribute a puck to a position of the TELL\n",
" # Define the puck ID and payload\n",
"\n",
" payload = [SetTellPosition(puck_name='CPS-4178', segment='A', puck_in_segment=2),SetTellPosition(puck_name='PSIMX122', segment='C', puck_in_segment=3)]\n",
" payload = [SetTellPosition(puck_name='PUCK006', segment='A', puck_in_segment=2),SetTellPosition(puck_name='PUCK005', segment='C', puck_in_segment=3)]\n",
" #payload = []\n",
"\n",
" try:\n",
@ -344,12 +306,12 @@
"[{'message': 'The tell_position was updated successfully.',\n",
" 'new_position': 'A2',\n",
" 'previous_position': None,\n",
" 'puck_name': 'CPS-4178',\n",
" 'puck_name': 'PUCK006',\n",
" 'status': 'updated'},\n",
" {'message': 'The tell_position was updated successfully.',\n",
" 'new_position': 'C3',\n",
" 'previous_position': None,\n",
" 'puck_name': 'PSIMX-122',\n",
" 'puck_name': 'PUCK005',\n",
" 'status': 'updated'}]\n"
]
},
@ -362,13 +324,13 @@
]
}
],
"execution_count": 43
"execution_count": 8
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-01-20T10:00:34.361066Z",
"start_time": "2025-01-20T10:00:34.339557Z"
"end_time": "2025-01-30T12:35:40.734188Z",
"start_time": "2025-01-30T12:35:40.679071Z"
}
},
"cell_type": "code",
@ -412,34 +374,28 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Puck ID: 44, Puck Name: CPS-4178\n",
" Sample ID: 433, Sample Name: Dtpase_1\n",
" Sample ID: 434, Sample Name: Dtpase_2\n",
" Sample ID: 435, Sample Name: Dtpase_3\n",
" Sample ID: 436, Sample Name: Dtpase_4\n",
" Sample ID: 437, Sample Name: Dtpase_5\n",
" Sample ID: 438, Sample Name: Dtpase_6\n",
" Sample ID: 439, Sample Name: Dtpase_7\n",
" Sample ID: 440, Sample Name: Fckase_1\n",
" Sample ID: 441, Sample Name: Fckase_2\n",
" Sample ID: 442, Sample Name: Fckase_3\n",
" Sample ID: 443, Sample Name: Fckase_4\n",
" Sample ID: 444, Sample Name: Fckase_5\n",
" Sample ID: 445, Sample Name: Fckase_6\n",
" Sample ID: 446, Sample Name: Fckase_7\n",
" Sample ID: 447, Sample Name: Fckase_8\n",
" Sample ID: 448, Sample Name: Fckase_9\n",
"Puck ID: 45, Puck Name: PSIMX-122\n",
" Sample ID: 449, Sample Name: PopoI_1\n",
" Sample ID: 450, Sample Name: PopoI_2\n",
" Sample ID: 451, Sample Name: PopoI_3\n",
" Sample ID: 452, Sample Name: PopoI_4\n",
" Sample ID: 453, Sample Name: PopoI_5\n",
" Sample ID: 454, Sample Name: PopoI_6\n",
" Sample ID: 455, Sample Name: PopoI_7\n",
" Sample ID: 456, Sample Name: PopoI_8\n",
" Sample ID: 457, Sample Name: PopoI_9\n",
" Sample ID: 458, Sample Name: PopoI_10\n"
"Puck ID: 6, Puck Name: PUCK006\n",
" Sample ID: 28, Sample Name: Sample028\n",
" Sample ID: 29, Sample Name: Sample029\n",
" Sample ID: 30, Sample Name: Sample030\n",
" Sample ID: 31, Sample Name: Sample031\n",
" Sample ID: 32, Sample Name: Sample032\n",
" Sample ID: 33, Sample Name: Sample033\n",
" Sample ID: 34, Sample Name: Sample034\n",
" Sample ID: 35, Sample Name: Sample035\n",
" Sample ID: 36, Sample Name: Sample036\n",
" Sample ID: 37, Sample Name: Sample037\n",
" Sample ID: 38, Sample Name: Sample038\n",
" Sample ID: 39, Sample Name: Sample039\n",
" Sample ID: 40, Sample Name: Sample040\n",
"Puck ID: 5, Puck Name: PUCK005\n",
" Sample ID: 21, Sample Name: Sample021\n",
" Sample ID: 22, Sample Name: Sample022\n",
" Sample ID: 23, Sample Name: Sample023\n",
" Sample ID: 24, Sample Name: Sample024\n",
" Sample ID: 25, Sample Name: Sample025\n",
" Sample ID: 26, Sample Name: Sample026\n",
" Sample ID: 27, Sample Name: Sample027\n"
]
},
{
@ -451,13 +407,13 @@
]
}
],
"execution_count": 53
"execution_count": 10
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-01-20T14:45:11.812597Z",
"start_time": "2025-01-20T14:45:11.793309Z"
"end_time": "2025-01-30T12:36:50.600728Z",
"start_time": "2025-01-30T12:36:50.581752Z"
}
},
"cell_type": "code",
@ -473,8 +429,8 @@
" try:\n",
" # Define the payload with only `event_type`\n",
" sample_event_create = SampleEventCreate(\n",
" sample_id=433,\n",
" event_type=\"Mounted\" # Valid event type\n",
" sample_id=27,\n",
" event_type=\"Unmounted\" # Valid event type\n",
" )\n",
"\n",
" # Debug the payload before sending\n",
@ -483,7 +439,7 @@
"\n",
" # Call the API\n",
" api_response = api_instance.create_sample_event_samples_samples_sample_id_events_post(\n",
" sample_id=433, # Ensure this matches a valid sample ID in the database\n",
" sample_id=27, # Ensure this matches a valid sample ID in the database\n",
" sample_event_create=sample_event_create\n",
" )\n",
"\n",
@ -503,9 +459,9 @@
"output_type": "stream",
"text": [
"Payload being sent to API:\n",
"{\"event_type\":\"Mounted\"}\n",
"{\"event_type\":\"Unmounted\"}\n",
"API response:\n",
"Sample(id=433, sample_name='Dtpase_1', position=1, puck_id=44, crystalname=None, proteinname=None, positioninpuck=None, priority=1, comments=None, data_collection_parameters=DataCollectionParameters(directory='{sgPuck}/{sgPosition}', oscillation=None, exposure=None, totalrange=None, transmission=None, targetresolution=None, aperture=None, datacollectiontype=None, processingpipeline='', spacegroupnumber=None, cellparameters=None, rescutkey=None, rescutvalue=None, userresolution=None, pdbid='', autoprocfull=False, procfull=False, adpenabled=False, noano=False, ffcscampaign=False, trustedhigh=None, autoprocextraparams=None, chiphiangles=None, dose=None), events=[SampleEventResponse(id=386, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 11, 35, 38)), SampleEventResponse(id=387, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 11, 40, 11)), SampleEventResponse(id=388, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 11, 45, 4)), SampleEventResponse(id=389, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 11, 45, 24)), SampleEventResponse(id=390, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 11, 50, 38)), SampleEventResponse(id=391, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 11, 52, 28)), SampleEventResponse(id=392, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 12, 10, 20)), SampleEventResponse(id=393, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 13, 39, 24)), SampleEventResponse(id=394, sample_id=433, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 20, 15, 45, 12))], mount_count=9, unmount_count=0)\n"
"Sample(id=27, sample_name='Sample027', position=15, puck_id=5, crystalname=None, proteinname=None, positioninpuck=None, priority=None, comments=None, data_collection_parameters=None, events=[SampleEventResponse(id=406, sample_id=27, event_type='Mounted', timestamp=datetime.datetime(2025, 1, 30, 13, 36, 34)), SampleEventResponse(id=407, sample_id=27, event_type='Unmounted', timestamp=datetime.datetime(2025, 1, 30, 13, 36, 51))], mount_count=1, unmount_count=1)\n"
]
},
{
@ -517,13 +473,13 @@
]
}
],
"execution_count": 4
"execution_count": 13
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-01-16T19:45:46.332149Z",
"start_time": "2025-01-16T19:45:46.320963Z"
"end_time": "2025-01-30T12:37:14.520342Z",
"start_time": "2025-01-30T12:37:14.508460Z"
}
},
"cell_type": "code",
@ -545,24 +501,24 @@
"id": "6a808ee09f97ae13",
"outputs": [
{
"ename": "NameError",
"evalue": "name 'aareDBclient' is not defined",
"ename": "AttributeError",
"evalue": "'SamplesApi' object has no attribute 'get_last_sample_event_samples_samples_sample_id_events_last_get'",
"output_type": "error",
"traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[7], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m \u001B[43maareDBclient\u001B[49m\u001B[38;5;241m.\u001B[39mApiClient(configuration) \u001B[38;5;28;01mas\u001B[39;00m api_client:\n\u001B[1;32m 2\u001B[0m \u001B[38;5;66;03m# Create an instance of the Samples API class\u001B[39;00m\n\u001B[1;32m 3\u001B[0m api_instance \u001B[38;5;241m=\u001B[39m aareDBclient\u001B[38;5;241m.\u001B[39mSamplesApi(api_client)\n\u001B[1;32m 5\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m 6\u001B[0m \u001B[38;5;66;03m# Get the last sample event\u001B[39;00m\n",
"\u001B[0;31mNameError\u001B[0m: name 'aareDBclient' is not defined"
"\u001B[0;31mAttributeError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[14], line 7\u001B[0m\n\u001B[1;32m 3\u001B[0m api_instance \u001B[38;5;241m=\u001B[39m aareDBclient\u001B[38;5;241m.\u001B[39mSamplesApi(api_client)\n\u001B[1;32m 5\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m 6\u001B[0m \u001B[38;5;66;03m# Get the last sample event\u001B[39;00m\n\u001B[0;32m----> 7\u001B[0m last_event_response \u001B[38;5;241m=\u001B[39m \u001B[43mapi_instance\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget_last_sample_event_samples_samples_sample_id_events_last_get\u001B[49m(\u001B[38;5;241m14\u001B[39m)\n\u001B[1;32m 8\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mThe response of get_last_sample_event:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m 9\u001B[0m pprint(last_event_response)\n",
"\u001B[0;31mAttributeError\u001B[0m: 'SamplesApi' object has no attribute 'get_last_sample_event_samples_samples_sample_id_events_last_get'"
]
}
],
"execution_count": 7
"execution_count": 14
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-01-20T15:43:54.575154Z",
"start_time": "2025-01-20T15:43:54.539295Z"
"end_time": "2025-01-30T12:38:46.149389Z",
"start_time": "2025-01-30T12:38:46.110767Z"
}
},
"cell_type": "code",
@ -575,7 +531,7 @@
"file_path = \"backend/tests/sample_image/IMG_1942.jpg\"\n",
"\n",
"# Sample ID\n",
"sample_id = 433 # Replace with a valid sample_id from your FastAPI backend\n",
"sample_id = 27 # Replace with a valid sample_id from your FastAPI backend\n",
"\n",
"# Initialize the API client\n",
"with ApiClient(configuration) as api_client:\n",
@ -613,18 +569,18 @@
"traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mValueError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[77], line 22\u001B[0m\n\u001B[1;32m 19\u001B[0m mime_type, _ \u001B[38;5;241m=\u001B[39m mimetypes\u001B[38;5;241m.\u001B[39mguess_type(file_path)\n\u001B[1;32m 21\u001B[0m \u001B[38;5;66;03m# Call the API method for uploading sample images\u001B[39;00m\n\u001B[0;32m---> 22\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mapi_instance\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mupload_sample_images_samples_samples_sample_id_upload_images_post\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 23\u001B[0m \u001B[43m \u001B[49m\u001B[43msample_id\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msample_id\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 24\u001B[0m \u001B[43m \u001B[49m\u001B[43muploaded_files\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\u001B[43mfile\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mread\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m]\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# Pass raw bytes as a list\u001B[39;49;00m\n\u001B[1;32m 25\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 27\u001B[0m \u001B[38;5;66;03m# Print the response from the API\u001B[39;00m\n\u001B[1;32m 28\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mAPI Response:\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
"Cell \u001B[0;32mIn[19], line 22\u001B[0m\n\u001B[1;32m 19\u001B[0m mime_type, _ \u001B[38;5;241m=\u001B[39m mimetypes\u001B[38;5;241m.\u001B[39mguess_type(file_path)\n\u001B[1;32m 21\u001B[0m \u001B[38;5;66;03m# Call the API method for uploading sample images\u001B[39;00m\n\u001B[0;32m---> 22\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mapi_instance\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mupload_sample_images_samples_samples_sample_id_upload_images_post\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 23\u001B[0m \u001B[43m \u001B[49m\u001B[43msample_id\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msample_id\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 24\u001B[0m \u001B[43m \u001B[49m\u001B[43muploaded_files\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\u001B[43mfile\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mread\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m]\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# Pass raw bytes as a list\u001B[39;49;00m\n\u001B[1;32m 25\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 27\u001B[0m \u001B[38;5;66;03m# Print the response from the API\u001B[39;00m\n\u001B[1;32m 28\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mAPI Response:\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
"File \u001B[0;32m/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pydantic/validate_call_decorator.py:60\u001B[0m, in \u001B[0;36mvalidate_call.<locals>.validate.<locals>.wrapper_function\u001B[0;34m(*args, **kwargs)\u001B[0m\n\u001B[1;32m 58\u001B[0m \u001B[38;5;129m@functools\u001B[39m\u001B[38;5;241m.\u001B[39mwraps(function)\n\u001B[1;32m 59\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21mwrapper_function\u001B[39m(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[0;32m---> 60\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mvalidate_call_wrapper\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43margs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n",
"File \u001B[0;32m/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pydantic/_internal/_validate_call.py:96\u001B[0m, in \u001B[0;36mValidateCallWrapper.__call__\u001B[0;34m(self, *args, **kwargs)\u001B[0m\n\u001B[1;32m 95\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21m__call__\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39margs: Any, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs: Any) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m Any:\n\u001B[0;32m---> 96\u001B[0m res \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__pydantic_validator__\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mvalidate_python\u001B[49m\u001B[43m(\u001B[49m\u001B[43mpydantic_core\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mArgsKwargs\u001B[49m\u001B[43m(\u001B[49m\u001B[43margs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 97\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m__return_pydantic_validator__:\n\u001B[1;32m 98\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m__return_pydantic_validator__(res)\n",
"File \u001B[0;32m~/PycharmProjects/heidi-v2/backend/aareDBclient/api/samples_api.py:875\u001B[0m, in \u001B[0;36mSamplesApi.upload_sample_images_samples_samples_sample_id_upload_images_post\u001B[0;34m(self, sample_id, uploaded_files, _request_timeout, _request_auth, _content_type, _headers, _host_index)\u001B[0m\n\u001B[1;32m 827\u001B[0m \u001B[38;5;129m@validate_call\u001B[39m\n\u001B[1;32m 828\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21mupload_sample_images_samples_samples_sample_id_upload_images_post\u001B[39m(\n\u001B[1;32m 829\u001B[0m \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 843\u001B[0m _host_index: Annotated[StrictInt, Field(ge\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m0\u001B[39m, le\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m0\u001B[39m)] \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0\u001B[39m,\n\u001B[1;32m 844\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28mobject\u001B[39m:\n\u001B[1;32m 845\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"Upload Sample Images\u001B[39;00m\n\u001B[1;32m 846\u001B[0m \n\u001B[1;32m 847\u001B[0m \u001B[38;5;124;03m 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 (Union[List[UploadFile], List[bytes]]): List of image files (as UploadFile or raw bytes). db (Session): SQLAlchemy database session.\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 872\u001B[0m \u001B[38;5;124;03m :return: Returns the result object.\u001B[39;00m\n\u001B[1;32m 873\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[0;32m--> 875\u001B[0m _param \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_upload_sample_images_samples_samples_sample_id_upload_images_post_serialize\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 876\u001B[0m \u001B[43m \u001B[49m\u001B[43msample_id\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msample_id\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 877\u001B[0m \u001B[43m \u001B[49m\u001B[43muploaded_files\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43muploaded_files\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 878\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_auth\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_auth\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 879\u001B[0m \u001B[43m \u001B[49m\u001B[43m_content_type\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_content_type\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 880\u001B[0m \u001B[43m \u001B[49m\u001B[43m_headers\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_headers\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 881\u001B[0m \u001B[43m \u001B[49m\u001B[43m_host_index\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_host_index\u001B[49m\n\u001B[1;32m 882\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 884\u001B[0m _response_types_map: Dict[\u001B[38;5;28mstr\u001B[39m, Optional[\u001B[38;5;28mstr\u001B[39m]] \u001B[38;5;241m=\u001B[39m {\n\u001B[1;32m 885\u001B[0m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124m200\u001B[39m\u001B[38;5;124m'\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mobject\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m 886\u001B[0m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124m422\u001B[39m\u001B[38;5;124m'\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mHTTPValidationError\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m 887\u001B[0m }\n\u001B[1;32m 888\u001B[0m response_data \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mapi_client\u001B[38;5;241m.\u001B[39mcall_api(\n\u001B[1;32m 889\u001B[0m \u001B[38;5;241m*\u001B[39m_param,\n\u001B[1;32m 890\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout\n\u001B[1;32m 891\u001B[0m )\n",
"File \u001B[0;32m~/PycharmProjects/heidi-v2/backend/aareDBclient/api/samples_api.py:1099\u001B[0m, in \u001B[0;36mSamplesApi._upload_sample_images_samples_samples_sample_id_upload_images_post_serialize\u001B[0;34m(self, sample_id, uploaded_files, _request_auth, _content_type, _headers, _host_index)\u001B[0m\n\u001B[1;32m 1095\u001B[0m \u001B[38;5;66;03m# authentication setting\u001B[39;00m\n\u001B[1;32m 1096\u001B[0m _auth_settings: List[\u001B[38;5;28mstr\u001B[39m] \u001B[38;5;241m=\u001B[39m [\n\u001B[1;32m 1097\u001B[0m ]\n\u001B[0;32m-> 1099\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mapi_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mparam_serialize\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 1100\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mPOST\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1101\u001B[0m \u001B[43m \u001B[49m\u001B[43mresource_path\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m/samples/samples/\u001B[39;49m\u001B[38;5;132;43;01m{sample_id}\u001B[39;49;00m\u001B[38;5;124;43m/upload-images\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1102\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_path_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1103\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_query_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1104\u001B[0m \u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_header_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1105\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_body_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1106\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_form_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1107\u001B[0m \u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_files\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1108\u001B[0m \u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_auth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1109\u001B[0m \u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_collection_formats\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1110\u001B[0m \u001B[43m \u001B[49m\u001B[43m_host\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_host\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1111\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_auth\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_auth\u001B[49m\n\u001B[1;32m 1112\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n",
"File \u001B[0;32m~/PycharmProjects/heidi-v2/backend/aareDBclient/api/samples_api.py:874\u001B[0m, in \u001B[0;36mSamplesApi.upload_sample_images_samples_samples_sample_id_upload_images_post\u001B[0;34m(self, sample_id, uploaded_files, _request_timeout, _request_auth, _content_type, _headers, _host_index)\u001B[0m\n\u001B[1;32m 827\u001B[0m \u001B[38;5;129m@validate_call\u001B[39m\n\u001B[1;32m 828\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21mupload_sample_images_samples_samples_sample_id_upload_images_post\u001B[39m(\n\u001B[1;32m 829\u001B[0m \u001B[38;5;28mself\u001B[39m,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 843\u001B[0m _host_index: Annotated[StrictInt, Field(ge\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m0\u001B[39m, le\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m0\u001B[39m)] \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0\u001B[39m,\n\u001B[1;32m 844\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28mobject\u001B[39m:\n\u001B[1;32m 845\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"Upload Sample Images\u001B[39;00m\n\u001B[1;32m 846\u001B[0m \n\u001B[1;32m 847\u001B[0m \n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 871\u001B[0m \u001B[38;5;124;03m :return: Returns the result object.\u001B[39;00m\n\u001B[1;32m 872\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[0;32m--> 874\u001B[0m _param \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_upload_sample_images_samples_samples_sample_id_upload_images_post_serialize\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 875\u001B[0m \u001B[43m \u001B[49m\u001B[43msample_id\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msample_id\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 876\u001B[0m \u001B[43m \u001B[49m\u001B[43muploaded_files\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43muploaded_files\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 877\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_auth\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_auth\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 878\u001B[0m \u001B[43m \u001B[49m\u001B[43m_content_type\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_content_type\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 879\u001B[0m \u001B[43m \u001B[49m\u001B[43m_headers\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_headers\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 880\u001B[0m \u001B[43m \u001B[49m\u001B[43m_host_index\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_host_index\u001B[49m\n\u001B[1;32m 881\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 883\u001B[0m _response_types_map: Dict[\u001B[38;5;28mstr\u001B[39m, Optional[\u001B[38;5;28mstr\u001B[39m]] \u001B[38;5;241m=\u001B[39m {\n\u001B[1;32m 884\u001B[0m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124m200\u001B[39m\u001B[38;5;124m'\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mobject\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m 885\u001B[0m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124m422\u001B[39m\u001B[38;5;124m'\u001B[39m: \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mHTTPValidationError\u001B[39m\u001B[38;5;124m\"\u001B[39m,\n\u001B[1;32m 886\u001B[0m }\n\u001B[1;32m 887\u001B[0m response_data \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mapi_client\u001B[38;5;241m.\u001B[39mcall_api(\n\u001B[1;32m 888\u001B[0m \u001B[38;5;241m*\u001B[39m_param,\n\u001B[1;32m 889\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout\n\u001B[1;32m 890\u001B[0m )\n",
"File \u001B[0;32m~/PycharmProjects/heidi-v2/backend/aareDBclient/api/samples_api.py:1096\u001B[0m, in \u001B[0;36mSamplesApi._upload_sample_images_samples_samples_sample_id_upload_images_post_serialize\u001B[0;34m(self, sample_id, uploaded_files, _request_auth, _content_type, _headers, _host_index)\u001B[0m\n\u001B[1;32m 1092\u001B[0m \u001B[38;5;66;03m# authentication setting\u001B[39;00m\n\u001B[1;32m 1093\u001B[0m _auth_settings: List[\u001B[38;5;28mstr\u001B[39m] \u001B[38;5;241m=\u001B[39m [\n\u001B[1;32m 1094\u001B[0m ]\n\u001B[0;32m-> 1096\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mapi_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mparam_serialize\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 1097\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mPOST\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1098\u001B[0m \u001B[43m \u001B[49m\u001B[43mresource_path\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m/samples/samples/\u001B[39;49m\u001B[38;5;132;43;01m{sample_id}\u001B[39;49;00m\u001B[38;5;124;43m/upload-images\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1099\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_path_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1100\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_query_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1101\u001B[0m \u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_header_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1102\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_body_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1103\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_form_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1104\u001B[0m \u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_files\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1105\u001B[0m \u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_auth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1106\u001B[0m \u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_collection_formats\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1107\u001B[0m \u001B[43m \u001B[49m\u001B[43m_host\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_host\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 1108\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_auth\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_auth\u001B[49m\n\u001B[1;32m 1109\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n",
"File \u001B[0;32m~/PycharmProjects/heidi-v2/backend/aareDBclient/api_client.py:214\u001B[0m, in \u001B[0;36mApiClient.param_serialize\u001B[0;34m(self, method, resource_path, path_params, query_params, header_params, body, post_params, files, auth_settings, collection_formats, _host, _request_auth)\u001B[0m\n\u001B[1;32m 209\u001B[0m post_params \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mparameters_to_tuples(\n\u001B[1;32m 210\u001B[0m post_params,\n\u001B[1;32m 211\u001B[0m collection_formats\n\u001B[1;32m 212\u001B[0m )\n\u001B[1;32m 213\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m files:\n\u001B[0;32m--> 214\u001B[0m post_params\u001B[38;5;241m.\u001B[39mextend(\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mfiles_parameters\u001B[49m\u001B[43m(\u001B[49m\u001B[43mfiles\u001B[49m\u001B[43m)\u001B[49m)\n\u001B[1;32m 216\u001B[0m \u001B[38;5;66;03m# auth setting\u001B[39;00m\n\u001B[1;32m 217\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mupdate_params_for_auth(\n\u001B[1;32m 218\u001B[0m header_params,\n\u001B[1;32m 219\u001B[0m query_params,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 224\u001B[0m request_auth\u001B[38;5;241m=\u001B[39m_request_auth\n\u001B[1;32m 225\u001B[0m )\n",
"File \u001B[0;32m~/PycharmProjects/heidi-v2/backend/aareDBclient/api_client.py:554\u001B[0m, in \u001B[0;36mApiClient.files_parameters\u001B[0;34m(self, files)\u001B[0m\n\u001B[1;32m 552\u001B[0m filedata \u001B[38;5;241m=\u001B[39m v\n\u001B[1;32m 553\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m--> 554\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mUnsupported file value\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m 555\u001B[0m mimetype \u001B[38;5;241m=\u001B[39m (\n\u001B[1;32m 556\u001B[0m mimetypes\u001B[38;5;241m.\u001B[39mguess_type(filename)[\u001B[38;5;241m0\u001B[39m]\n\u001B[1;32m 557\u001B[0m \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mapplication/octet-stream\u001B[39m\u001B[38;5;124m'\u001B[39m\n\u001B[1;32m 558\u001B[0m )\n\u001B[1;32m 559\u001B[0m params\u001B[38;5;241m.\u001B[39mappend(\n\u001B[1;32m 560\u001B[0m \u001B[38;5;28mtuple\u001B[39m([k, \u001B[38;5;28mtuple\u001B[39m([filename, filedata, mimetype])])\n\u001B[1;32m 561\u001B[0m )\n",
"\u001B[0;31mValueError\u001B[0m: Unsupported file value"
]
}
],
"execution_count": 77
"execution_count": 19
},
{
"metadata": {