Ali2206 commited on
Commit
92c74a9
·
verified ·
1 Parent(s): f9eed38

Update api/routes.py

Browse files
Files changed (1) hide show
  1. api/routes.py +77 -37
api/routes.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi import APIRouter, HTTPException, Depends, Body
2
  from fastapi.security import OAuth2PasswordRequestForm
3
  from models.schemas import SignupForm, TokenResponse, PatientCreate, DoctorCreate, AppointmentCreate
4
  from db.mongo import users_collection, patients_collection, appointments_collection
@@ -6,8 +6,12 @@ from core.security import hash_password, verify_password, create_access_token, g
6
  from datetime import datetime
7
  from bson import ObjectId
8
  from bson.errors import InvalidId
9
- from typing import Optional
10
  from pydantic import BaseModel
 
 
 
 
11
 
12
  router = APIRouter()
13
 
@@ -88,7 +92,7 @@ async def get_me(current_user: dict = Depends(get_current_user)):
88
  raise HTTPException(status_code=404, detail="User not found")
89
 
90
  return {
91
- "id": str(user["_id"]), # ✅ needed in frontend to submit appointment
92
  "email": user["email"],
93
  "full_name": user.get("full_name", ""),
94
  "role": user.get("role", "unknown"),
@@ -118,15 +122,15 @@ async def list_patients(current_user: dict = Depends(get_current_user)):
118
  if current_user.get("role") != "doctor":
119
  raise HTTPException(status_code=403, detail="Only doctors can view patients")
120
 
121
- patients_cursor = patients_collection.find({"created_by": current_user["email"]})
122
  patients = []
123
- async for patient in patients_cursor:
124
  patients.append({
125
- "id": str(patient["_id"]),
126
- "full_name": patient.get("full_name", ""),
127
- "date_of_birth": patient.get("date_of_birth"),
128
- "gender": patient.get("gender", ""),
129
- "notes": patient.get("notes", "")
130
  })
131
  return patients
132
 
@@ -144,16 +148,14 @@ async def create_appointment(data: AppointmentCreate, current_user: dict = Depen
144
  if current_user.get("role") != "patient":
145
  raise HTTPException(status_code=403, detail="Only patients can book appointments")
146
 
147
- # Get patient user info
148
  patient_user = await users_collection.find_one({"email": current_user["email"]})
149
  if not patient_user:
150
  raise HTTPException(status_code=404, detail="Patient user not found")
151
 
152
- # Insert appointment
153
  appointment_doc = {
154
  "patient_id": patient_user["_id"],
155
  "doctor_id": ObjectId(data.doctor_id),
156
- "date": data.date,"date": datetime.combine(data.date, datetime.min.time()),
157
  "time": data.time.strftime("%H:%M:%S"),
158
  "reason": data.reason,
159
  "created_by": current_user["email"],
@@ -161,30 +163,8 @@ async def create_appointment(data: AppointmentCreate, current_user: dict = Depen
161
  }
162
  await appointments_collection.insert_one(appointment_doc)
163
 
164
- # Auto-add to doctor's patient list if not already
165
- existing = await patients_collection.find_one({
166
- "user_email": current_user["email"],
167
- "created_by": await get_doctor_email_by_id(data.doctor_id)
168
- })
169
- if not existing:
170
- await patients_collection.insert_one({
171
- "full_name": patient_user.get("full_name", ""),
172
- "user_email": patient_user["email"],
173
- "gender": "",
174
- "created_by": await get_doctor_email_by_id(data.doctor_id),
175
- "created_at": datetime.utcnow()
176
- })
177
-
178
  return {"message": "Appointment booked successfully"}
179
 
180
- # --- Helper function ---
181
- async def get_doctor_email_by_id(doctor_id: str) -> Optional[str]:
182
- try:
183
- doc = await users_collection.find_one({"_id": ObjectId(doctor_id), "role": "doctor"})
184
- return doc["email"] if doc else None
185
- except Exception:
186
- return None
187
-
188
  # --- LIST DOCTOR'S APPOINTMENTS ---
189
  @router.get("/appointments/doctor")
190
  async def list_doctor_appointments(current_user: dict = Depends(get_current_user)):
@@ -193,13 +173,11 @@ async def list_doctor_appointments(current_user: dict = Depends(get_current_user
193
 
194
  cursor = appointments_collection.find({"doctor_id": ObjectId(current_user["_id"])})
195
  appointments = []
196
-
197
  async for a in cursor:
198
  try:
199
  patient_id = a.get("patient_id")
200
  if not isinstance(patient_id, ObjectId):
201
  patient_id = ObjectId(patient_id)
202
-
203
  patient = await users_collection.find_one({"_id": patient_id})
204
  except Exception:
205
  patient = None
@@ -231,3 +209,65 @@ async def list_my_appointments(current_user: dict = Depends(get_current_user)):
231
  patient_id = user.get("_id")
232
  cursor = appointments_collection.find({"patient_id": patient_id})
233
  return [{**a, "_id": str(a["_id"]), "patient_id": str(a["patient_id"]), "doctor_id": str(a["doctor_id"])} async for a in cursor]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException, Depends, Body, UploadFile, File
2
  from fastapi.security import OAuth2PasswordRequestForm
3
  from models.schemas import SignupForm, TokenResponse, PatientCreate, DoctorCreate, AppointmentCreate
4
  from db.mongo import users_collection, patients_collection, appointments_collection
 
6
  from datetime import datetime
7
  from bson import ObjectId
8
  from bson.errors import InvalidId
9
+ from typing import Optional, List
10
  from pydantic import BaseModel
11
+ from pathlib import Path
12
+ import csv
13
+ import io
14
+ import json
15
 
16
  router = APIRouter()
17
 
 
92
  raise HTTPException(status_code=404, detail="User not found")
93
 
94
  return {
95
+ "id": str(user["_id"]),
96
  "email": user["email"],
97
  "full_name": user.get("full_name", ""),
98
  "role": user.get("role", "unknown"),
 
122
  if current_user.get("role") != "doctor":
123
  raise HTTPException(status_code=403, detail="Only doctors can view patients")
124
 
125
+ cursor = patients_collection.find({"created_by": current_user["email"]})
126
  patients = []
127
+ async for p in cursor:
128
  patients.append({
129
+ "id": str(p["_id"]),
130
+ "full_name": p.get("full_name", ""),
131
+ "date_of_birth": p.get("date_of_birth"),
132
+ "gender": p.get("gender", ""),
133
+ "notes": p.get("notes", "")
134
  })
135
  return patients
136
 
 
148
  if current_user.get("role") != "patient":
149
  raise HTTPException(status_code=403, detail="Only patients can book appointments")
150
 
 
151
  patient_user = await users_collection.find_one({"email": current_user["email"]})
152
  if not patient_user:
153
  raise HTTPException(status_code=404, detail="Patient user not found")
154
 
 
155
  appointment_doc = {
156
  "patient_id": patient_user["_id"],
157
  "doctor_id": ObjectId(data.doctor_id),
158
+ "date": datetime.combine(data.date, datetime.min.time()),
159
  "time": data.time.strftime("%H:%M:%S"),
160
  "reason": data.reason,
161
  "created_by": current_user["email"],
 
163
  }
164
  await appointments_collection.insert_one(appointment_doc)
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  return {"message": "Appointment booked successfully"}
167
 
 
 
 
 
 
 
 
 
168
  # --- LIST DOCTOR'S APPOINTMENTS ---
169
  @router.get("/appointments/doctor")
170
  async def list_doctor_appointments(current_user: dict = Depends(get_current_user)):
 
173
 
174
  cursor = appointments_collection.find({"doctor_id": ObjectId(current_user["_id"])})
175
  appointments = []
 
176
  async for a in cursor:
177
  try:
178
  patient_id = a.get("patient_id")
179
  if not isinstance(patient_id, ObjectId):
180
  patient_id = ObjectId(patient_id)
 
181
  patient = await users_collection.find_one({"_id": patient_id})
182
  except Exception:
183
  patient = None
 
209
  patient_id = user.get("_id")
210
  cursor = appointments_collection.find({"patient_id": patient_id})
211
  return [{**a, "_id": str(a["_id"]), "patient_id": str(a["patient_id"]), "doctor_id": str(a["doctor_id"])} async for a in cursor]
212
+
213
+ # === UTIL: Parse Synthea CSV ===
214
+ def parse_synthea_patient_csv(file: UploadFile) -> List[dict]:
215
+ decoded = file.file.read().decode("utf-8")
216
+ reader = csv.DictReader(io.StringIO(decoded))
217
+ patients = []
218
+
219
+ for row in reader:
220
+ patients.append({
221
+ "synthea_id": row.get("Id"),
222
+ "full_name": f"{row.get('FIRST', '')} {row.get('LAST', '')}".strip(),
223
+ "gender": row.get("GENDER"),
224
+ "date_of_birth": datetime.strptime(row.get("BIRTHDATE"), "%Y-%m-%dT%H:%M:%SZ"),
225
+ "address": row.get("ADDRESS"),
226
+ "city": row.get("CITY"),
227
+ "state": row.get("STATE"),
228
+ "zip": row.get("ZIP"),
229
+ "created_at": datetime.utcnow()
230
+ })
231
+
232
+ return patients
233
+
234
+ # === API: Upload and import patients.csv ===
235
+ @router.post("/ehr/import-patients")
236
+ async def import_synthea_patients(file: UploadFile = File(...)):
237
+ if not file.filename.endswith(".csv"):
238
+ raise HTTPException(status_code=400, detail="Only CSV files are supported")
239
+
240
+ try:
241
+ patients = parse_synthea_patient_csv(file)
242
+ result = await patients_collection.insert_many(patients)
243
+ return {"inserted_count": len(result.inserted_ids)}
244
+ except Exception as e:
245
+ raise HTTPException(status_code=500, detail=str(e))
246
+
247
+ # === GET all Synthea patients ===
248
+ @router.get("/ehr/synthea-patients")
249
+ async def list_synthea_patients():
250
+ cursor = patients_collection.find({"synthea_id": {"$exists": True}})
251
+ patients = []
252
+ async for p in cursor:
253
+ patients.append({
254
+ "id": str(p["_id"]),
255
+ "synthea_id": p.get("synthea_id"),
256
+ "full_name": p.get("full_name"),
257
+ "gender": p.get("gender"),
258
+ "date_of_birth": p.get("date_of_birth"),
259
+ })
260
+ return patients
261
+
262
+ # === GET individual Synthea patient ===
263
+ @router.get("/ehr/synthea-patient/{id}")
264
+ async def get_synthea_patient(id: str):
265
+ try:
266
+ patient = await patients_collection.find_one({"_id": ObjectId(id)})
267
+ if not patient:
268
+ raise HTTPException(status_code=404, detail="Patient not found")
269
+ patient["id"] = str(patient["_id"])
270
+ del patient["_id"]
271
+ return patient
272
+ except Exception:
273
+ raise HTTPException(status_code=400, detail="Invalid patient ID")