Ali2206 commited on
Commit
6109265
·
verified ·
1 Parent(s): b84b4a7

Update api/routes/patients.py

Browse files
Files changed (1) hide show
  1. api/routes/patients.py +19 -32
api/routes/patients.py CHANGED
@@ -7,7 +7,7 @@ from models.entities import Note
7
  from datetime import datetime
8
  from bson import ObjectId
9
  from bson.errors import InvalidId
10
- from typing import Optional, List
11
  from pymongo import UpdateOne
12
  from pymongo.errors import BulkWriteError
13
  import json
@@ -41,6 +41,7 @@ async def process_synthea_patient(bundle: dict, file_path: str) -> Optional[dict
41
  medications = []
42
  encounters = []
43
 
 
44
  if not isinstance(bundle, dict) or 'entry' not in bundle:
45
  logger.error(f"Invalid FHIR bundle structure in {file_path}")
46
  return None
@@ -58,6 +59,7 @@ async def process_synthea_patient(bundle: dict, file_path: str) -> Optional[dict
58
  name = resource.get('name', [{}])[0]
59
  address = resource.get('address', [{}])[0]
60
 
 
61
  raw_full_name = f"{' '.join(name.get('given', ['']))} {name.get('family', '')}".strip()
62
  clean_full_name = re.sub(r'\d+', '', raw_full_name).strip()
63
 
@@ -147,8 +149,7 @@ async def import_patients(
147
  logger.warning(f"Unauthorized import attempt by {current_user.get('email')}")
148
  raise HTTPException(
149
  status_code=status.HTTP_403_FORBIDDEN,
150
- detail="Only administrators and doctors can import data",
151
- headers={"WWW-Authenticate": "Bearer"}
152
  )
153
 
154
  try:
@@ -161,6 +162,7 @@ async def import_patients(
161
  detail="Data directory not found"
162
  )
163
 
 
164
  files = [
165
  f for f in glob.glob(str(SYNTHEA_DATA_DIR / "*.json"))
166
  if not re.search(r'(hospitalInformation|practitionerInformation)\d+\.json$', f)
@@ -182,11 +184,13 @@ async def import_patients(
182
  try:
183
  logger.debug(f"Processing file: {file_path}")
184
 
 
185
  if not os.path.exists(file_path):
186
  logger.error(f"File not found: {file_path}")
187
  errors.append(f"File not found: {file_path}")
188
  continue
189
 
 
190
  file_size = os.path.getsize(file_path)
191
  if file_size == 0:
192
  logger.warning(f"Empty file: {file_path}")
@@ -274,22 +278,13 @@ async def import_patients(
274
 
275
  @router.get("/patients", response_model=List[dict])
276
  async def list_patients(
277
- current_user: dict = Depends(get_current_user),
278
  search: Optional[str] = Query(None),
279
  min_notes: int = Query(0, ge=0),
280
  min_conditions: int = Query(0, ge=0),
281
  limit: int = Query(100, ge=1, le=500),
282
  skip: int = Query(0, ge=0)
283
  ):
284
- logger.info(f"Listing patients with search: {search}, limit: {limit}, skip: {skip} by {current_user.get('email')}")
285
- if current_user.get('role') not in ['admin', 'doctor']:
286
- logger.warning(f"Unauthorized patient list access by {current_user.get('email')}")
287
- raise HTTPException(
288
- status_code=status.HTTP_403_FORBIDDEN,
289
- detail="Only administrators and doctors can list patients",
290
- headers={"WWW-Authenticate": "Bearer"}
291
- )
292
-
293
  query = {"source": "synthea"}
294
 
295
  if search:
@@ -304,6 +299,7 @@ async def list_patients(
304
  if min_conditions > 0:
305
  query[f"conditions.{min_conditions-1}"] = {"$exists": True}
306
 
 
307
  projection = {
308
  "fhir_id": 1,
309
  "full_name": 1,
@@ -342,27 +338,19 @@ async def list_patients(
342
  }
343
  })
344
 
345
- logger.info(f"Retrieved {len(patients)} patients for {current_user.get('email')}")
346
  return patients
347
 
348
  except Exception as e:
349
- logger.error(f"Failed to list patients for {current_user.get('email')}: {str(e)}")
350
  raise HTTPException(
351
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
352
  detail=f"Failed to retrieve patients: {str(e)}"
353
  )
354
 
355
  @router.get("/patients/{patient_id}", response_model=dict)
356
- async def get_patient(patient_id: str, current_user: dict = Depends(get_current_user)):
357
- logger.info(f"Retrieving patient {patient_id} for {current_user.get('email')}")
358
- if current_user.get('role') not in ['admin', 'doctor']:
359
- logger.warning(f"Unauthorized patient access by {current_user.get('email')}")
360
- raise HTTPException(
361
- status_code=status.HTTP_403_FORBIDDEN,
362
- detail="Only administrators and doctors can view patient details",
363
- headers={"WWW-Authenticate": "Bearer"}
364
- )
365
-
366
  try:
367
  patient = await patients_collection.find_one({
368
  "$or": [
@@ -409,7 +397,7 @@ async def get_patient(patient_id: str, current_user: dict = Depends(get_current_
409
  }
410
  }
411
 
412
- logger.info(f"Successfully retrieved patient {patient_id} for {current_user.get('email')}")
413
  return response
414
 
415
  except ValueError as ve:
@@ -419,7 +407,7 @@ async def get_patient(patient_id: str, current_user: dict = Depends(get_current_
419
  detail="Invalid patient ID format"
420
  )
421
  except Exception as e:
422
- logger.error(f"Failed to retrieve patient {patient_id} for {current_user.get('email')}: {str(e)}")
423
  raise HTTPException(
424
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
425
  detail=f"Failed to retrieve patient: {str(e)}"
@@ -436,8 +424,7 @@ async def add_note(
436
  logger.warning(f"Unauthorized note addition attempt by {current_user.get('email')}")
437
  raise HTTPException(
438
  status_code=status.HTTP_403_FORBIDDEN,
439
- detail="Only clinicians can add notes",
440
- headers={"WWW-Authenticate": "Bearer"}
441
  )
442
 
443
  try:
@@ -465,7 +452,7 @@ async def add_note(
465
  detail="Patient not found"
466
  )
467
 
468
- logger.info(f"Note added successfully for patient {patient_id} by {current_user.get('email')}")
469
  return {"status": "success", "message": "Note added"}
470
 
471
  except ValueError as ve:
@@ -475,11 +462,11 @@ async def add_note(
475
  detail="Invalid patient ID format"
476
  )
477
  except Exception as e:
478
- logger.error(f"Failed to add note for patient {patient_id} by {current_user.get('email')}: {str(e)}")
479
  raise HTTPException(
480
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
481
  detail=f"Failed to add note: {str(e)}"
482
  )
483
 
484
- # Export the router
485
  patients = router
 
7
  from datetime import datetime
8
  from bson import ObjectId
9
  from bson.errors import InvalidId
10
+ from typing import Optional, List, Dict
11
  from pymongo import UpdateOne
12
  from pymongo.errors import BulkWriteError
13
  import json
 
41
  medications = []
42
  encounters = []
43
 
44
+ # Validate bundle structure
45
  if not isinstance(bundle, dict) or 'entry' not in bundle:
46
  logger.error(f"Invalid FHIR bundle structure in {file_path}")
47
  return None
 
59
  name = resource.get('name', [{}])[0]
60
  address = resource.get('address', [{}])[0]
61
 
62
+ # Construct full name and remove numbers
63
  raw_full_name = f"{' '.join(name.get('given', ['']))} {name.get('family', '')}".strip()
64
  clean_full_name = re.sub(r'\d+', '', raw_full_name).strip()
65
 
 
149
  logger.warning(f"Unauthorized import attempt by {current_user.get('email')}")
150
  raise HTTPException(
151
  status_code=status.HTTP_403_FORBIDDEN,
152
+ detail="Only administrators and doctors can import data"
 
153
  )
154
 
155
  try:
 
162
  detail="Data directory not found"
163
  )
164
 
165
+ # Filter out non-patient files
166
  files = [
167
  f for f in glob.glob(str(SYNTHEA_DATA_DIR / "*.json"))
168
  if not re.search(r'(hospitalInformation|practitionerInformation)\d+\.json$', f)
 
184
  try:
185
  logger.debug(f"Processing file: {file_path}")
186
 
187
+ # Check file accessibility
188
  if not os.path.exists(file_path):
189
  logger.error(f"File not found: {file_path}")
190
  errors.append(f"File not found: {file_path}")
191
  continue
192
 
193
+ # Check file size
194
  file_size = os.path.getsize(file_path)
195
  if file_size == 0:
196
  logger.warning(f"Empty file: {file_path}")
 
278
 
279
  @router.get("/patients", response_model=List[dict])
280
  async def list_patients(
 
281
  search: Optional[str] = Query(None),
282
  min_notes: int = Query(0, ge=0),
283
  min_conditions: int = Query(0, ge=0),
284
  limit: int = Query(100, ge=1, le=500),
285
  skip: int = Query(0, ge=0)
286
  ):
287
+ logger.info(f"Listing patients with search: {search}, limit: {limit}, skip: {skip}")
 
 
 
 
 
 
 
 
288
  query = {"source": "synthea"}
289
 
290
  if search:
 
299
  if min_conditions > 0:
300
  query[f"conditions.{min_conditions-1}"] = {"$exists": True}
301
 
302
+ # Removed $slice to return full arrays for the frontend
303
  projection = {
304
  "fhir_id": 1,
305
  "full_name": 1,
 
338
  }
339
  })
340
 
341
+ logger.info(f"Retrieved {len(patients)} patients")
342
  return patients
343
 
344
  except Exception as e:
345
+ logger.error(f"Failed to list patients: {str(e)}")
346
  raise HTTPException(
347
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
348
  detail=f"Failed to retrieve patients: {str(e)}"
349
  )
350
 
351
  @router.get("/patients/{patient_id}", response_model=dict)
352
+ async def get_patient(patient_id: str):
353
+ logger.info(f"Retrieving patient: {patient_id}")
 
 
 
 
 
 
 
 
354
  try:
355
  patient = await patients_collection.find_one({
356
  "$or": [
 
397
  }
398
  }
399
 
400
+ logger.info(f"Successfully retrieved patient: {patient_id}")
401
  return response
402
 
403
  except ValueError as ve:
 
407
  detail="Invalid patient ID format"
408
  )
409
  except Exception as e:
410
+ logger.error(f"Failed to retrieve patient {patient_id}: {str(e)}")
411
  raise HTTPException(
412
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
413
  detail=f"Failed to retrieve patient: {str(e)}"
 
424
  logger.warning(f"Unauthorized note addition attempt by {current_user.get('email')}")
425
  raise HTTPException(
426
  status_code=status.HTTP_403_FORBIDDEN,
427
+ detail="Only clinicians can add notes"
 
428
  )
429
 
430
  try:
 
452
  detail="Patient not found"
453
  )
454
 
455
+ logger.info(f"Note added successfully for patient {patient_id}")
456
  return {"status": "success", "message": "Note added"}
457
 
458
  except ValueError as ve:
 
462
  detail="Invalid patient ID format"
463
  )
464
  except Exception as e:
465
+ logger.error(f"Failed to add note for patient {patient_id}: {str(e)}")
466
  raise HTTPException(
467
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
468
  detail=f"Failed to add note: {str(e)}"
469
  )
470
 
471
+ # Export the router as 'patients' for api.__init__.py
472
  patients = router