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, DewarType,
DewarSerialNumber, DewarSerialNumber,
SampleEvent, SampleEvent,
LogisticsEvent,
) )
from datetime import datetime, timedelta from datetime import datetime, timedelta
import random import random
@ -196,11 +197,11 @@ dewars = [
tracking_number="TRACK123", tracking_number="TRACK123",
return_address_id=1, return_address_id=1,
contact_id=1, contact_id=1,
status="Ready for Shipping", status="active",
ready_date=datetime.strptime("2023-09-30", "%Y-%m-%d"), # ready_date=datetime.strptime("2023-09-30", "%Y-%m-%d"),
shipping_date=None, # shipping_date=None,
arrival_date=None, # arrival_date=None,
returning_date=None, # returning_date=None,
unique_id=generate_unique_id(), unique_id=generate_unique_id(),
), ),
Dewar( Dewar(
@ -212,11 +213,11 @@ dewars = [
tracking_number="TRACK124", tracking_number="TRACK124",
return_address_id=2, return_address_id=2,
contact_id=2, contact_id=2,
status="In Preparation", status="active",
ready_date=None, # ready_date=None,
shipping_date=None, # shipping_date=None,
arrival_date=None, # arrival_date=None,
returning_date=None, # returning_date=None,
unique_id=generate_unique_id(), unique_id=generate_unique_id(),
), ),
Dewar( Dewar(
@ -228,11 +229,11 @@ dewars = [
tracking_number="TRACK125", tracking_number="TRACK125",
return_address_id=1, return_address_id=1,
contact_id=3, contact_id=3,
status="Not Shipped", status="active",
ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"), # ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
shipping_date=None, # shipping_date=None,
arrival_date=None, # arrival_date=None,
returning_date=None, # returning_date=None,
unique_id=None, unique_id=None,
), ),
Dewar( Dewar(
@ -244,11 +245,11 @@ dewars = [
tracking_number="", tracking_number="",
return_address_id=1, return_address_id=1,
contact_id=3, contact_id=3,
status="Delayed", status="active",
ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"), # ready_date=datetime.strptime("2024-01-01", "%Y-%m-%d"),
shipping_date=datetime.strptime("2024-01-02", "%Y-%m-%d"), # shipping_date=datetime.strptime("2024-01-02", "%Y-%m-%d"),
arrival_date=None, # arrival_date=None,
returning_date=None, # returning_date=None,
unique_id=None, unique_id=None,
), ),
Dewar( Dewar(
@ -257,16 +258,103 @@ dewars = [
dewar_name="Dewar Five", dewar_name="Dewar Five",
dewar_type_id=1, dewar_type_id=1,
dewar_serial_number_id=1, dewar_serial_number_id=1,
tracking_number="", tracking_number="TRACK126",
return_address_id=1, return_address_id=1,
contact_id=3, contact_id=3,
status="Returned", status="active",
arrival_date=datetime.strptime("2024-01-03", "%Y-%m-%d"), # arrival_date=datetime.strptime("2024-01-03", "%Y-%m-%d"),
returning_date=datetime.strptime("2024-01-07", "%Y-%m-%d"), # returning_date=datetime.strptime("2024-01-07", "%Y-%m-%d"),
unique_id=None, 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 # Define proposals
proposals = [ proposals = [
Proposal(id=1, number="202400125"), Proposal(id=1, number="202400125"),

View File

@ -86,13 +86,9 @@ class Dewar(Base):
dewar_serial_number_id = Column( dewar_serial_number_id = Column(
Integer, ForeignKey("dewar_serial_numbers.id"), nullable=True Integer, ForeignKey("dewar_serial_numbers.id"), nullable=True
) )
tracking_number = Column(String(255), nullable=True)
status = 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) 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")) shipment_id = Column(Integer, ForeignKey("shipments.id"))
return_address_id = Column(Integer, ForeignKey("addresses.id")) return_address_id = Column(Integer, ForeignKey("addresses.id"))
contact_id = Column(Integer, ForeignKey("contacts.id")) contact_id = Column(Integer, ForeignKey("contacts.id"))

View File

@ -1,7 +1,7 @@
from .address import address_router from .address import address_router
from .contact import contact_router from .contact import contact_router
from .proposal import router as proposal_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 .shipment import shipment_router
from .auth import router as auth_router from .auth import router as auth_router
from .protected_router import protected_router as protected_router from .protected_router import protected_router as protected_router

View File

@ -9,7 +9,6 @@ from typing import List
import logging import logging
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from app.schemas import ( from app.schemas import (
Dewar as DewarSchema,
DewarCreate, DewarCreate,
DewarUpdate, DewarUpdate,
DewarType as DewarTypeSchema, DewarType as DewarTypeSchema,
@ -21,7 +20,8 @@ from app.schemas import (
SampleUpdate, SampleUpdate,
Sample, Sample,
Puck, Puck,
SampleEventResponse, # Clearer name for schema SampleEventResponse,
DewarSchema, # Clearer name for schema
) )
from app.models import ( from app.models import (
Dewar as DewarModel, Dewar as DewarModel,
@ -42,11 +42,11 @@ from reportlab.lib.pagesizes import A5, landscape
from reportlab.lib.units import cm from reportlab.lib.units import cm
from reportlab.pdfgen import canvas from reportlab.pdfgen import canvas
from app.crud import ( from app.crud import (
get_shipments,
get_shipment_by_id, get_shipment_by_id,
) # Import CRUD functions for shipment )
router = APIRouter()
dewar_router = APIRouter()
def generate_unique_id(db: Session, length: int = 16) -> str: 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 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( async def create_or_update_dewar(
shipment_id: int, shipment_id: int,
dewar: DewarCreate, dewar: DewarCreate,
db: Session = Depends(get_db), db: Session = Depends(get_db),
) -> DewarSchema: ):
try: try:
# Query existing dewar by name within the shipment # Query existing dewar by name within the shipment
existing_dewar = ( existing_dewar = (
@ -170,14 +170,11 @@ async def create_or_update_dewar(
# Create a completely new dewar if none exists # Create a completely new dewar if none exists
dewar_obj = DewarModel( dewar_obj = DewarModel(
pgroups=dewar.pgroups,
dewar_name=dewar.dewar_name, dewar_name=dewar.dewar_name,
tracking_number=dewar.tracking_number, tracking_number=dewar.tracking_number,
status=dewar.status, status=dewar.status,
ready_date=dewar.ready_date, contact_id=dewar.contact_id,
shipping_date=dewar.shipping_date,
arrival_date=dewar.arrival_date,
returning_date=dewar.returning_date,
contact_person_id=dewar.contact_person_id,
return_address_id=dewar.return_address_id, return_address_id=dewar.return_address_id,
shipment_id=shipment_id, # Associate with the shipment 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") 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)): async def generate_dewar_qrcode(dewar_id: int, db: Session = Depends(get_db)):
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first() dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
if not dewar: if not dewar:
@ -365,7 +362,7 @@ def generate_label(dewar):
return buffer 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)): async def download_dewar_label(dewar_id: int, db: Session = Depends(get_db)):
dewar = ( dewar = (
db.query(DewarModel) 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( async def update_sample(
sample_id: int, sample_id: int,
sample_update: SampleUpdate, sample_update: SampleUpdate,
@ -431,7 +428,7 @@ async def update_sample(
return Sample.from_orm(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)): async def get_dewar_samples(dewar_id: int, db: Session = Depends(get_db)):
# Fetch the Dewar with nested relationships # Fetch the Dewar with nested relationships
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first() 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 # Explicitly map nested relationships
dewar_data = { dewar_data = {
"id": dewar.id, "id": dewar.id,
"pgroups": dewar.pgroups,
"dewar_name": dewar.dewar_name, "dewar_name": dewar.dewar_name,
"tracking_number": dewar.tracking_number, "tracking_number": dewar.tracking_number,
"status": dewar.status, "status": dewar.status,
@ -448,14 +446,10 @@ async def get_dewar_samples(dewar_id: int, db: Session = Depends(get_db)):
"number_of_samples": sum( "number_of_samples": sum(
len(puck.samples) for puck in dewar.pucks len(puck.samples) for puck in dewar.pucks
), # Calculate total samples ), # Calculate total samples
"ready_date": dewar.ready_date, "contact_id": dewar.contact.id if dewar.contact else None,
"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,
"return_address_id": dewar.return_address.id if dewar.return_address else None, "return_address_id": dewar.return_address.id if dewar.return_address else None,
"shipment_id": dewar.shipment_id, "shipment_id": dewar.shipment_id,
"contact_person": dewar.contact_person, "contact": dewar.contact,
"return_address": dewar.return_address, "return_address": dewar.return_address,
"pucks": [ "pucks": [
Puck( Puck(
@ -492,7 +486,7 @@ async def get_dewar_samples(dewar_id: int, db: Session = Depends(get_db)):
return Dewar(**dewar_data) 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)): async def get_dewars(db: Session = Depends(get_db)):
try: try:
dewars = db.query(DewarModel).options(joinedload(DewarModel.pucks)).all() 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") 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)): def get_dewar_types(db: Session = Depends(get_db)):
return db.query(DewarTypeModel).all() return db.query(DewarTypeModel).all()
@router.get( @dewar_router.get(
"/dewar-types/{type_id}/serial-numbers", "/dewar-types/{type_id}/serial-numbers",
response_model=List[DewarSerialNumberSchema], 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)): def create_dewar_type(dewar_type: DewarTypeCreate, db: Session = Depends(get_db)):
db_type = DewarTypeModel(**dewar_type.dict()) db_type = DewarTypeModel(**dewar_type.dict())
db.add(db_type) db.add(db_type)
@ -528,7 +522,7 @@ def create_dewar_type(dewar_type: DewarTypeCreate, db: Session = Depends(get_db)
return db_type 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( def create_dewar_serial_number(
serial_number: DewarSerialNumberCreate, db: Session = Depends(get_db) serial_number: DewarSerialNumberCreate, db: Session = Depends(get_db)
): ):
@ -539,7 +533,7 @@ def create_dewar_serial_number(
return db_serial 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)): def get_all_serial_numbers(db: Session = Depends(get_db)):
try: try:
serial_numbers = db.query(DewarSerialNumberModel).all() 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") 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)): async def get_dewar(dewar_id: int, db: Session = Depends(get_db)):
dewar = ( dewar = (
db.query(DewarModel) db.query(DewarModel)
.options( .options(
joinedload(DewarModel.pucks).joinedload(PuckModel.samples), joinedload(DewarModel.pucks).joinedload(PuckModel.samples),
joinedload(DewarModel.contact_person), joinedload(DewarModel.contact),
joinedload(DewarModel.return_address), joinedload(DewarModel.return_address),
joinedload(DewarModel.shipment), joinedload(DewarModel.shipment),
) )
@ -569,10 +563,10 @@ async def get_dewar(dewar_id: int, db: Session = Depends(get_db)):
return DewarSchema.from_orm(dewar) return DewarSchema.from_orm(dewar)
@router.put("/{dewar_id}", response_model=DewarSchema) @dewar_router.put("/{dewar_id}", response_model=Dewar)
async def update_dewar( async def update_dewar(
dewar_id: int, dewar_update: DewarUpdate, db: Session = Depends(get_db) dewar_id: int, dewar_update: DewarUpdate, db: Session = Depends(get_db)
) -> DewarSchema: ) -> Dewar:
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first() dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
if not dewar: if not dewar:
@ -587,7 +581,7 @@ async def update_dewar(
return 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)): async def delete_dewar(dewar_id: int, db: Session = Depends(get_db)):
# Fetch the Dewar from the database # Fetch the Dewar from the database
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first() 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 return
# New routes for shipments @dewar_router.get("/shipments/{id}", response_model=ShipmentSchema)
@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)
async def get_single_shipment(id: int, db: Session = Depends(get_db)): async def get_single_shipment(id: int, db: Session = Depends(get_db)):
try: try:
shipment = get_shipment_by_id(db, id) 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 # Correct the contact_person assignment
contact_person = None contact_person = None
if slot.dewar and slot.dewar.contact_person: if slot.dewar and slot.dewar.contact:
first_name = slot.dewar.contact_person.firstname first_name = slot.dewar.contact.firstname
last_name = slot.dewar.contact_person.lastname last_name = slot.dewar.contact.lastname
contact_person = f"{first_name} {last_name}" contact_person = f"{first_name} {last_name}"
# Prepare the slot data for the response # 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 if slot.dewar and slot.dewar.shipment
else None else None
), ),
contact_person=contact_person, contact=contact_person,
local_contact="local contact placeholder", local_contact="local contact placeholder",
) )
# Add updated slot data to the response list # 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.address import address_router
from app.routers.contact import contact_router from app.routers.contact import contact_router
from app.routers.shipment import shipment_router from app.routers.shipment import shipment_router
from app.routers.dewar import dewar_router
protected_router = APIRouter( protected_router = APIRouter(
dependencies=[Depends(get_current_user)] # Applies to all routes 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( protected_router.include_router(
shipment_router, prefix="/shipments", tags=["shipments"] 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) dewar_name=str(dewar.dewar_name)
if dewar and dewar.dewar_name if dewar and dewar.dewar_name
else None, else None,
pgroup=str(dewar.pgroups)
if dewar.pgroups
else None, # will be replaced later by puck pgroup
samples=[ samples=[
Sample( Sample(
id=sample.id, 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_ids = [dewar.id for dewar in dewars]
dewar_map = {dewar.id: dewar.dewar_name 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) # Subquery to fetch the latest event for each puck (any type of event)
latest_event_subquery = ( latest_event_subquery = (
@ -430,9 +434,9 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
PuckModel, PuckModel,
PuckEventModel.event_type, PuckEventModel.event_type,
PuckEventModel.tell_position, PuckEventModel.tell_position,
DewarModel, # Include DewarModel
) )
.join( # Join pucks with the latest event .join( # Join pucks with the latest event
# (outer join to include pucks without events)
latest_event_subquery, latest_event_subquery,
PuckModel.id == latest_event_subquery.c.puck_id, PuckModel.id == latest_event_subquery.c.puck_id,
isouter=True, 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), & (PuckEventModel.timestamp == latest_event_subquery.c.latest_event_time),
isouter=True, 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 .filter(PuckModel.dewar_id.in_(dewar_ids)) # Restrict pucks to relevant dewars
.all() .all()
) )
@ -458,13 +467,16 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
# Prepare the final response # Prepare the final response
results = [] 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( logger.debug(
f"Puck ID: {puck.id}, Name: {puck.puck_name}, Event Type: {event_type}, " f"Puck ID: {puck.id}, Name: {puck.puck_name}, Event Type: {event_type}, "
f"Tell Position: {tell_position}" f"Tell Position: {tell_position}"
) )
dewar_name = dewar_map.get(puck.dewar_id, "Unknown") 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 # For pucks with no events or whose latest event is `puck_removed`, set
# `tell_position` to None # `tell_position` to None
@ -475,6 +487,7 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
results.append( results.append(
PuckWithTellPosition( PuckWithTellPosition(
id=puck.id, id=puck.id,
pgroup=pgroup,
puck_name=puck.puck_name, puck_name=puck.puck_name,
puck_type=puck.puck_type, puck_type=puck.puck_type,
puck_location_in_dewar=int(puck.puck_location_in_dewar) 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") raise HTTPException(status_code=404, detail="Sample not found")
# 2. Define Directory Structure # 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") today = datetime.now().strftime("%Y-%m-%d")
dewar_name = ( dewar_name = (
sample.puck.dewar.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" puck_name = sample.puck.puck_name if sample.puck else "default_puck"
position = sample.position if sample.position else "default_position" 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) base_dir.mkdir(parents=True, exist_ok=True)
# 3. Process and Save Each File # 3. Process and Save Each File

View File

@ -3,6 +3,8 @@ from sqlalchemy.orm import Session
from typing import List from typing import List
from datetime import date from datetime import date
import json import json
import logging
from sqlalchemy.exc import SQLAlchemyError
from app.models import ( from app.models import (
Shipment as ShipmentModel, Shipment as ShipmentModel,
@ -20,11 +22,11 @@ from app.schemas import (
Shipment as ShipmentSchema, Shipment as ShipmentSchema,
Contact as ContactSchema, Contact as ContactSchema,
Sample as SampleSchema, Sample as SampleSchema,
DewarSchema,
loginData, loginData,
Dewar,
) )
from app.database import get_db 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 from app.routers.auth import get_current_user
shipment_router = APIRouter() shipment_router = APIRouter()
@ -59,7 +61,17 @@ async def fetch_shipments(
return 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)): 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() shipment = db.query(ShipmentModel).filter(ShipmentModel.id == shipment_id).first()
if not shipment: if not shipment:

View File

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

View File

@ -7,7 +7,6 @@ from fastapi.middleware.cors import CORSMiddleware
from app import ssl_heidi from app import ssl_heidi
from app.routers import ( from app.routers import (
proposal, proposal,
dewar,
puck, puck,
spreadsheet, spreadsheet,
logistics, logistics,
@ -137,8 +136,8 @@ def on_startup():
load_slots_data(db) load_slots_data(db)
else: # dev or test environments else: # dev or test environments
print(f"{environment.capitalize()} environment: Regenerating database.") print(f"{environment.capitalize()} environment: Regenerating database.")
Base.metadata.drop_all(bind=engine) # Base.metadata.drop_all(bind=engine)
Base.metadata.create_all(bind=engine) # Base.metadata.create_all(bind=engine)
if environment == "dev": if environment == "dev":
from app.database import load_sample_data from app.database import load_sample_data
@ -152,10 +151,9 @@ def on_startup():
# Include routers with correct configuration # 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(auth.router, prefix="/auth", tags=["auth"])
app.include_router(proposal.router, prefix="/proposals", tags=["proposals"]) 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(puck.router, prefix="/pucks", tags=["pucks"])
app.include_router(spreadsheet.router, tags=["spreadsheet"]) app.include_router(spreadsheet.router, tags=["spreadsheet"])
app.include_router(logistics.router, prefix="/logistics", tags=["logistics"]) app.include_router(logistics.router, prefix="/logistics", tags=["logistics"])

View File

@ -117,7 +117,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
useEffect(() => { useEffect(() => {
const fetchDewarTypes = async () => { const fetchDewarTypes = async () => {
try { try {
const response = await DewarsService.getDewarTypesDewarsDewarTypesGet(); const response = await DewarsService.getDewarTypesProtectedDewarsDewarTypesGet();
setKnownDewarTypes(response ?? []); setKnownDewarTypes(response ?? []);
} catch (error) { } catch (error) {
setFeedbackMessage('Failed to fetch dewar types.'); setFeedbackMessage('Failed to fetch dewar types.');
@ -132,7 +132,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
useEffect(() => { useEffect(() => {
const fetchSerialNumbers = async () => { const fetchSerialNumbers = async () => {
try { try {
const response = await DewarsService.getAllSerialNumbersDewarsDewarSerialNumbersGet(); const response = await DewarsService.getAllSerialNumbersProtectedDewarsDewarSerialNumbersGet();
setKnownSerialNumbers(response ?? []); setKnownSerialNumbers(response ?? []);
} catch (error) { } catch (error) {
setFeedbackMessage('Failed to fetch serial numbers.'); setFeedbackMessage('Failed to fetch serial numbers.');
@ -248,8 +248,8 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
const handleSaveNewDewarTypeAndSerialNumber = async () => { const handleSaveNewDewarTypeAndSerialNumber = async () => {
if (newDewarType) { if (newDewarType) {
try { try {
const typeResponse = await DewarsService.createDewarTypeDewarsDewarTypesPost({ dewar_type: newDewarType }); const typeResponse = await DewarsService.createDewarTypeProtectedDewarsDewarTypesPost({ dewar_type: newDewarType });
const serialResponse = await DewarsService.createDewarSerialNumberDewarsDewarSerialNumbersPost({ const serialResponse = await DewarsService.createDewarSerialNumberProtectedDewarsDewarSerialNumbersPost({
serial_number: newDewarSerialNumber, serial_number: newDewarSerialNumber,
dewar_type_id: typeResponse.id, dewar_type_id: typeResponse.id,
}); });
@ -266,7 +266,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
} }
} else if (newDewarSerialNumber && selectedDewarType) { } else if (newDewarSerialNumber && selectedDewarType) {
try { try {
const response = await DewarsService.createDewarSerialNumberDewarsDewarSerialNumbersPost({ const response = await DewarsService.createDewarSerialNumberProtectedDewarsDewarSerialNumbersPost({
serial_number: newDewarSerialNumber, serial_number: newDewarSerialNumber,
dewar_type_id: parseInt(selectedDewarType, 10), dewar_type_id: parseInt(selectedDewarType, 10),
}); });
@ -371,6 +371,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
try { try {
const payload = { const payload = {
pgroups: activePgroup,
dewar_name: dewar.dewar_name, dewar_name: dewar.dewar_name,
dewar_type_id: parseInt(selectedDewarType, 10), dewar_type_id: parseInt(selectedDewarType, 10),
dewar_serial_number_id: parseInt(selectedSerialNumber, 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_pucks: dewar.number_of_pucks,
number_of_samples: dewar.number_of_samples, number_of_samples: dewar.number_of_samples,
status: dewar.status, 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), return_address_id: parseInt(selectedReturnAddress ?? '', 10),
contact_id: parseInt(selectedContact ?? '', 10), contact_id: parseInt(selectedContact ?? '', 10),
}; };
await DewarsService.updateDewarDewarsDewarIdPut(dewarId, payload); await DewarsService.updateDewarProtectedDewarsDewarIdPut(dewarId, payload);
setFeedbackMessage('Changes saved successfully.'); setFeedbackMessage('Changes saved successfully.');
setChangesMade(false); setChangesMade(false);
} catch (error) { } catch (error) {
@ -408,7 +405,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
if (!dewar) return; if (!dewar) return;
try { try {
const response = await DewarsService.generateDewarQrcodeDewarsDewarIdGenerateQrcodePost(dewar.id); const response = await DewarsService.generateDewarQrcodeProtectedDewarsDewarIdGenerateQrcodePost(dewar.id);
const newQrCodeValue = response.unique_id; const newQrCodeValue = response.unique_id;
setQrCodeValue(newQrCodeValue); setQrCodeValue(newQrCodeValue);
setIsQRCodeGenerated(true); setIsQRCodeGenerated(true);
@ -426,7 +423,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
if (!dewar) return; if (!dewar) return;
try { try {
const response = await DewarsService.downloadDewarLabelDewarsDewarIdDownloadLabelGet(dewar.id); const response = await DewarsService.downloadDewarLabelProtectedDewarsDewarIdDownloadLabelGet(dewar.id);
// The response object might need parsing // The response object might need parsing
const blob = new Blob([response as any], { type: 'application/pdf' }); 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 () => { const fetchSamples = async () => {
try { try {
const response = await DewarsService.getDewarSamplesDewarsDewarsDewarIdSamplesGet(dewarId); const response = await DewarsService.getDewarSamplesProtectedDewarsDewarsDewarIdSamplesGet(dewarId);
console.log("Response from backend:", response); console.log("Response from backend:", response);
const dewarData = response; // Assume response is already in correct structure 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 // 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.`); console.log(`Sample with ID ${id} successfully updated.`);
} catch (error) { } catch (error) {
@ -237,7 +237,7 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
); );
// Send the payload to the backend // 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}.`); console.log(`Successfully updated sample with ID ${newRow.id}.`);
return payload; // Return the updated row return payload; // Return the updated row

View File

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

View File

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

View File

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

View File

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

View File

@ -53,7 +53,7 @@ interface SlotData extends SlotSchema {
retrievedTimestamp?: string; retrievedTimestamp?: string;
beamlineLocation?: string; beamlineLocation?: string;
shipment_name?: string; shipment_name?: string;
contact_person?: string; contact?: string;
local_contact?: string; local_contact?: string;
} }
@ -155,7 +155,7 @@ const LogisticsView: React.FC = () => {
needsRefillWarning: true, needsRefillWarning: true,
beamlineLocation: undefined, beamlineLocation: undefined,
shipmnet_name: undefined, shipmnet_name: undefined,
contact_person: undefined, contact: undefined,
local_contact: undefined, local_contact: undefined,
}; };
} else { } else {
@ -174,7 +174,7 @@ const LogisticsView: React.FC = () => {
needsRefillWarning: !associatedDewar || slot.time_until_refill === undefined, needsRefillWarning: !associatedDewar || slot.time_until_refill === undefined,
beamlineLocation: slot.beamlineLocation, beamlineLocation: slot.beamlineLocation,
shipment_name: slot.shipment_name, shipment_name: slot.shipment_name,
contact_person: slot.contact_person, contact: slot.contact,
local_contact: slot.local_contact, local_contact: slot.local_contact,
}; };
}); });
@ -456,7 +456,7 @@ const LogisticsView: React.FC = () => {
<Typography variant="h6">{selectedSlotData.label}</Typography> <Typography variant="h6">{selectedSlotData.label}</Typography>
<Typography variant="body2">{`Shipment: ${selectedSlotData.shipment_name}`}</Typography> <Typography variant="body2">{`Shipment: ${selectedSlotData.shipment_name}`}</Typography>
<Typography variant="body2">{`Dewar: ${selectedSlotData.dewar_name || 'N/A'}`}</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">{`QR Code: ${selectedSlotData.qr_code}`}</Typography>
<Typography variant="body2">{`Occupied: ${selectedSlotData.occupied ? 'Yes' : 'No'}`}</Typography> <Typography variant="body2">{`Occupied: ${selectedSlotData.occupied ? 'Yes' : 'No'}`}</Typography>
<Typography variant="body2">{`Needs Refill: ${selectedSlotData.needsRefillWarning ? '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] [project]
name = "aareDB" name = "aareDB"
version = "0.1.0a19" version = "0.1.0a20"
description = "Backend for next gen sample management system" description = "Backend for next gen sample management system"
authors = [{name = "Guillaume Gotthard", email = "guillaume.gotthard@psi.ch"}] authors = [{name = "Guillaume Gotthard", email = "guillaume.gotthard@psi.ch"}]
license = {text = "MIT"} license = {text = "MIT"}

View File

@ -6,8 +6,8 @@
"metadata": { "metadata": {
"collapsed": true, "collapsed": true,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-20T14:44:37.526742Z", "end_time": "2025-01-30T11:29:38.703954Z",
"start_time": "2025-01-20T14:44:37.522704Z" "start_time": "2025-01-30T11:29:38.307050Z"
} }
}, },
"source": [ "source": [
@ -42,18 +42,18 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"0.1.0a19\n", "0.1.0a20\n",
"https://127.0.0.1:8000\n" "https://127.0.0.1:8000\n"
] ]
} }
], ],
"execution_count": 2 "execution_count": 1
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-20T14:44:58.875370Z", "end_time": "2025-01-30T11:07:14.795059Z",
"start_time": "2025-01-20T14:44:58.805520Z" "start_time": "2025-01-30T11:07:14.783786Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@ -95,52 +95,11 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Shipment ID: 2, Shipment Name: Shipment from Mordor\n", "Exception when calling ShipmentsApi->fetch_shipments_shipments_get: (404)\n",
" Dewar ID: 1, Dewar Name: Dewar One, Dewar Unique ID: 83041c3f8844ff39 \n", "Reason: Not Found\n",
" Puck ID: 1, Puck Name: PUCK-001\n", "HTTP response headers: HTTPHeaderDict({'date': 'Thu, 30 Jan 2025 11:07:14 GMT', 'server': 'uvicorn', 'content-length': '22', 'content-type': 'application/json'})\n",
" Puck ID: 2, Puck Name: PUCK002\n", "HTTP response body: {\"detail\":\"Not Found\"}\n",
" Puck ID: 3, Puck Name: PUCK003\n", "\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"
] ]
}, },
{ {
@ -152,7 +111,7 @@
] ]
} }
], ],
"execution_count": 3 "execution_count": 6
}, },
{ {
"metadata": { "metadata": {
@ -253,8 +212,8 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-17T14:07:51.580993Z", "end_time": "2025-01-30T11:35:20.036682Z",
"start_time": "2025-01-17T14:07:51.565128Z" "start_time": "2025-01-30T11:35:20.018284Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@ -283,12 +242,13 @@
"text": [ "text": [
"The response of PucksApi->get_pucks_by_slot_pucks_slot_slot_identifier_get:\n", "The response of PucksApi->get_pucks_by_slot_pucks_slot_slot_identifier_get:\n",
"\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=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=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=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=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=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=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=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=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=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=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=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": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-17T14:09:55.141237Z", "end_time": "2025-01-30T12:30:46.242711Z",
"start_time": "2025-01-17T14:09:55.117843Z" "start_time": "2025-01-30T12:30:46.215343Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"from aareDBclient import SetTellPosition\n",
"\n",
"# Attribute a puck to a position in the TELL dewar\n", "# Attribute a puck to a position in the TELL dewar\n",
"\n", "\n",
"with aareDBclient.ApiClient(configuration) as api_client:\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", " # 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", " # Define the puck ID and payload\n",
"\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", " #payload = []\n",
"\n", "\n",
" try:\n", " try:\n",
@ -344,12 +306,12 @@
"[{'message': 'The tell_position was updated successfully.',\n", "[{'message': 'The tell_position was updated successfully.',\n",
" 'new_position': 'A2',\n", " 'new_position': 'A2',\n",
" 'previous_position': None,\n", " 'previous_position': None,\n",
" 'puck_name': 'CPS-4178',\n", " 'puck_name': 'PUCK006',\n",
" 'status': 'updated'},\n", " 'status': 'updated'},\n",
" {'message': 'The tell_position was updated successfully.',\n", " {'message': 'The tell_position was updated successfully.',\n",
" 'new_position': 'C3',\n", " 'new_position': 'C3',\n",
" 'previous_position': None,\n", " 'previous_position': None,\n",
" 'puck_name': 'PSIMX-122',\n", " 'puck_name': 'PUCK005',\n",
" 'status': 'updated'}]\n" " 'status': 'updated'}]\n"
] ]
}, },
@ -362,13 +324,13 @@
] ]
} }
], ],
"execution_count": 43 "execution_count": 8
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-20T10:00:34.361066Z", "end_time": "2025-01-30T12:35:40.734188Z",
"start_time": "2025-01-20T10:00:34.339557Z" "start_time": "2025-01-30T12:35:40.679071Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@ -412,34 +374,28 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Puck ID: 44, Puck Name: CPS-4178\n", "Puck ID: 6, Puck Name: PUCK006\n",
" Sample ID: 433, Sample Name: Dtpase_1\n", " Sample ID: 28, Sample Name: Sample028\n",
" Sample ID: 434, Sample Name: Dtpase_2\n", " Sample ID: 29, Sample Name: Sample029\n",
" Sample ID: 435, Sample Name: Dtpase_3\n", " Sample ID: 30, Sample Name: Sample030\n",
" Sample ID: 436, Sample Name: Dtpase_4\n", " Sample ID: 31, Sample Name: Sample031\n",
" Sample ID: 437, Sample Name: Dtpase_5\n", " Sample ID: 32, Sample Name: Sample032\n",
" Sample ID: 438, Sample Name: Dtpase_6\n", " Sample ID: 33, Sample Name: Sample033\n",
" Sample ID: 439, Sample Name: Dtpase_7\n", " Sample ID: 34, Sample Name: Sample034\n",
" Sample ID: 440, Sample Name: Fckase_1\n", " Sample ID: 35, Sample Name: Sample035\n",
" Sample ID: 441, Sample Name: Fckase_2\n", " Sample ID: 36, Sample Name: Sample036\n",
" Sample ID: 442, Sample Name: Fckase_3\n", " Sample ID: 37, Sample Name: Sample037\n",
" Sample ID: 443, Sample Name: Fckase_4\n", " Sample ID: 38, Sample Name: Sample038\n",
" Sample ID: 444, Sample Name: Fckase_5\n", " Sample ID: 39, Sample Name: Sample039\n",
" Sample ID: 445, Sample Name: Fckase_6\n", " Sample ID: 40, Sample Name: Sample040\n",
" Sample ID: 446, Sample Name: Fckase_7\n", "Puck ID: 5, Puck Name: PUCK005\n",
" Sample ID: 447, Sample Name: Fckase_8\n", " Sample ID: 21, Sample Name: Sample021\n",
" Sample ID: 448, Sample Name: Fckase_9\n", " Sample ID: 22, Sample Name: Sample022\n",
"Puck ID: 45, Puck Name: PSIMX-122\n", " Sample ID: 23, Sample Name: Sample023\n",
" Sample ID: 449, Sample Name: PopoI_1\n", " Sample ID: 24, Sample Name: Sample024\n",
" Sample ID: 450, Sample Name: PopoI_2\n", " Sample ID: 25, Sample Name: Sample025\n",
" Sample ID: 451, Sample Name: PopoI_3\n", " Sample ID: 26, Sample Name: Sample026\n",
" Sample ID: 452, Sample Name: PopoI_4\n", " Sample ID: 27, Sample Name: Sample027\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"
] ]
}, },
{ {
@ -451,13 +407,13 @@
] ]
} }
], ],
"execution_count": 53 "execution_count": 10
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-20T14:45:11.812597Z", "end_time": "2025-01-30T12:36:50.600728Z",
"start_time": "2025-01-20T14:45:11.793309Z" "start_time": "2025-01-30T12:36:50.581752Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@ -473,8 +429,8 @@
" try:\n", " try:\n",
" # Define the payload with only `event_type`\n", " # Define the payload with only `event_type`\n",
" sample_event_create = SampleEventCreate(\n", " sample_event_create = SampleEventCreate(\n",
" sample_id=433,\n", " sample_id=27,\n",
" event_type=\"Mounted\" # Valid event type\n", " event_type=\"Unmounted\" # Valid event type\n",
" )\n", " )\n",
"\n", "\n",
" # Debug the payload before sending\n", " # Debug the payload before sending\n",
@ -483,7 +439,7 @@
"\n", "\n",
" # Call the API\n", " # Call the API\n",
" api_response = api_instance.create_sample_event_samples_samples_sample_id_events_post(\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", " sample_event_create=sample_event_create\n",
" )\n", " )\n",
"\n", "\n",
@ -503,9 +459,9 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Payload being sent to API:\n", "Payload being sent to API:\n",
"{\"event_type\":\"Mounted\"}\n", "{\"event_type\":\"Unmounted\"}\n",
"API response:\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": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-16T19:45:46.332149Z", "end_time": "2025-01-30T12:37:14.520342Z",
"start_time": "2025-01-16T19:45:46.320963Z" "start_time": "2025-01-30T12:37:14.508460Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@ -545,24 +501,24 @@
"id": "6a808ee09f97ae13", "id": "6a808ee09f97ae13",
"outputs": [ "outputs": [
{ {
"ename": "NameError", "ename": "AttributeError",
"evalue": "name 'aareDBclient' is not defined", "evalue": "'SamplesApi' object has no attribute 'get_last_sample_event_samples_samples_sample_id_events_last_get'",
"output_type": "error", "output_type": "error",
"traceback": [ "traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)", "\u001B[0;31mAttributeError\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", "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;31mNameError\u001B[0m: name 'aareDBclient' is not defined" "\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": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-01-20T15:43:54.575154Z", "end_time": "2025-01-30T12:38:46.149389Z",
"start_time": "2025-01-20T15:43:54.539295Z" "start_time": "2025-01-30T12:38:46.110767Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@ -575,7 +531,7 @@
"file_path = \"backend/tests/sample_image/IMG_1942.jpg\"\n", "file_path = \"backend/tests/sample_image/IMG_1942.jpg\"\n",
"\n", "\n",
"# Sample ID\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", "\n",
"# Initialize the API client\n", "# Initialize the API client\n",
"with ApiClient(configuration) as api_client:\n", "with ApiClient(configuration) as api_client:\n",
@ -613,18 +569,18 @@
"traceback": [ "traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mValueError\u001B[0m Traceback (most recent call last)", "\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/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/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: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: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: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: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", "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" "\u001B[0;31mValueError\u001B[0m: Unsupported file value"
] ]
} }
], ],
"execution_count": 77 "execution_count": 19
}, },
{ {
"metadata": { "metadata": {