Ali2206 commited on
Commit
174303b
·
verified ·
1 Parent(s): 5f1d2c0

Update api/routes/pdf.py

Browse files
Files changed (1) hide show
  1. api/routes/pdf.py +30 -31
api/routes/pdf.py CHANGED
@@ -22,14 +22,17 @@ router = APIRouter()
22
 
23
  @router.get("/{patient_id}/pdf", response_class=Response)
24
  async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get_current_user)):
25
- # Suppress logging for this route
26
- logger.setLevel(logging.CRITICAL)
 
 
 
 
 
 
 
27
 
28
  try:
29
- if current_user.get('role') not in ['doctor', 'admin']:
30
- raise HTTPException(status_code=403, detail="Only clinicians can generate patient PDFs")
31
-
32
- # Determine if patient_id is ObjectId or fhir_id
33
  try:
34
  obj_id = ObjectId(patient_id)
35
  query = {"$or": [{"_id": obj_id}, {"fhir_id": patient_id}]}
@@ -38,9 +41,12 @@ async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get
38
 
39
  patient = await patients_collection.find_one(query)
40
  if not patient:
41
- raise HTTPException(status_code=404, detail="Patient not found")
 
 
 
 
42
 
43
- # Prepare table content with proper LaTeX formatting
44
  def prepare_table_content(items, columns, default_message):
45
  if not items:
46
  return f"\\multicolumn{{{columns}}}{{l}}{{{default_message}}} \\\\"
@@ -54,7 +60,6 @@ async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get
54
  content.append(" & ".join(row) + " \\\\")
55
  return "\n".join(content)
56
 
57
- # Notes table
58
  notes = patient.get("notes", [])
59
  notes_content = prepare_table_content(
60
  [{
@@ -66,7 +71,6 @@ async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get
66
  "No notes available"
67
  )
68
 
69
- # Conditions table
70
  conditions = patient.get("conditions", [])
71
  conditions_content = prepare_table_content(
72
  [{
@@ -80,7 +84,6 @@ async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get
80
  "No conditions available"
81
  )
82
 
83
- # Medications table
84
  medications = patient.get("medications", [])
85
  medications_content = prepare_table_content(
86
  [{
@@ -94,7 +97,6 @@ async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get
94
  "No medications available"
95
  )
96
 
97
- # Encounters table
98
  encounters = patient.get("encounters", [])
99
  encounters_content = prepare_table_content(
100
  [{
@@ -108,7 +110,6 @@ async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get
108
  "No encounters available"
109
  )
110
 
111
- # LaTeX template with improved table formatting
112
  latex_template = Template(r"""
113
  \documentclass[a4paper,12pt]{article}
114
  \usepackage[utf8]{inputenc}
@@ -189,8 +190,7 @@ $encounters
189
  \end{document}
190
  """)
191
 
192
- # Set the generated_on date to 02:54 PM CET, May 17, 2025
193
- generated_on = datetime.strptime("2025-05-17 14:54:00+02:00", "%Y-%m-%d %H:%M:%S%z").strftime("%A, %B %d, %Y at %I:%M %p %Z")
194
 
195
  latex_filled = latex_template.substitute(
196
  generated_on=generated_on,
@@ -214,7 +214,6 @@ $encounters
214
  encounters=encounters_content
215
  )
216
 
217
- # Compile LaTeX in a temporary directory
218
  with TemporaryDirectory() as tmpdir:
219
  tex_path = os.path.join(tmpdir, "report.tex")
220
  pdf_path = os.path.join(tmpdir, "report.pdf")
@@ -223,7 +222,6 @@ $encounters
223
  f.write(latex_filled)
224
 
225
  try:
226
- # Run latexmk twice to ensure proper table rendering
227
  for _ in range(2):
228
  result = subprocess.run(
229
  ["latexmk", "-pdf", "-interaction=nonstopmode", tex_path],
@@ -234,43 +232,44 @@ $encounters
234
  )
235
 
236
  if result.returncode != 0:
 
237
  raise HTTPException(
238
- status_code=500,
239
- detail=f"LaTeX compilation failed: stdout={result.stdout}, stderr={result.stderr}"
240
  )
241
 
242
  except subprocess.CalledProcessError as e:
 
243
  raise HTTPException(
244
- status_code=500,
245
- detail=f"LaTeX compilation failed: stdout={e.stdout}, stderr={e.stderr}"
246
  )
247
 
248
  if not os.path.exists(pdf_path):
 
249
  raise HTTPException(
250
- status_code=500,
251
  detail="PDF file was not generated"
252
  )
253
 
254
  with open(pdf_path, "rb") as f:
255
  pdf_bytes = f.read()
256
 
257
- response = Response(
 
258
  content=pdf_bytes,
259
  media_type="application/pdf",
260
  headers={"Content-Disposition": f"attachment; filename=patient_{patient.get('fhir_id', 'unknown')}_report.pdf"}
261
  )
262
- return response
263
 
264
- except HTTPException as http_error:
265
- raise http_error
266
  except Exception as e:
 
267
  raise HTTPException(
268
- status_code=500,
269
  detail=f"Unexpected error generating PDF: {str(e)}"
270
  )
271
- finally:
272
- # Restore the logger level for other routes
273
- logger.setLevel(logging.INFO)
274
 
275
- # Export the router as 'pdf' for api.__init__.py
276
  pdf = router
 
22
 
23
  @router.get("/{patient_id}/pdf", response_class=Response)
24
  async def generate_patient_pdf(patient_id: str, current_user: dict = Depends(get_current_user)):
25
+ logger.info(f"Generating PDF for patient {patient_id} by {current_user.get('email')}")
26
+
27
+ if current_user.get('role') not in ['doctor', 'admin']:
28
+ logger.warning(f"Unauthorized PDF generation attempt by {current_user.get('email')}")
29
+ raise HTTPException(
30
+ status_code=status.HTTP_403_FORBIDDEN,
31
+ detail="Only clinicians can generate patient PDFs",
32
+ headers={"WWW-Authenticate": "Bearer"}
33
+ )
34
 
35
  try:
 
 
 
 
36
  try:
37
  obj_id = ObjectId(patient_id)
38
  query = {"$or": [{"_id": obj_id}, {"fhir_id": patient_id}]}
 
41
 
42
  patient = await patients_collection.find_one(query)
43
  if not patient:
44
+ logger.warning(f"Patient not found: {patient_id}")
45
+ raise HTTPException(
46
+ status_code=status.HTTP_404_NOT_FOUND,
47
+ detail="Patient not found"
48
+ )
49
 
 
50
  def prepare_table_content(items, columns, default_message):
51
  if not items:
52
  return f"\\multicolumn{{{columns}}}{{l}}{{{default_message}}} \\\\"
 
60
  content.append(" & ".join(row) + " \\\\")
61
  return "\n".join(content)
62
 
 
63
  notes = patient.get("notes", [])
64
  notes_content = prepare_table_content(
65
  [{
 
71
  "No notes available"
72
  )
73
 
 
74
  conditions = patient.get("conditions", [])
75
  conditions_content = prepare_table_content(
76
  [{
 
84
  "No conditions available"
85
  )
86
 
 
87
  medications = patient.get("medications", [])
88
  medications_content = prepare_table_content(
89
  [{
 
97
  "No medications available"
98
  )
99
 
 
100
  encounters = patient.get("encounters", [])
101
  encounters_content = prepare_table_content(
102
  [{
 
110
  "No encounters available"
111
  )
112
 
 
113
  latex_template = Template(r"""
114
  \documentclass[a4paper,12pt]{article}
115
  \usepackage[utf8]{inputenc}
 
190
  \end{document}
191
  """)
192
 
193
+ generated_on = datetime.utcnow().strftime("%A, %B %d, %Y at %I:%M %p UTC")
 
194
 
195
  latex_filled = latex_template.substitute(
196
  generated_on=generated_on,
 
214
  encounters=encounters_content
215
  )
216
 
 
217
  with TemporaryDirectory() as tmpdir:
218
  tex_path = os.path.join(tmpdir, "report.tex")
219
  pdf_path = os.path.join(tmpdir, "report.pdf")
 
222
  f.write(latex_filled)
223
 
224
  try:
 
225
  for _ in range(2):
226
  result = subprocess.run(
227
  ["latexmk", "-pdf", "-interaction=nonstopmode", tex_path],
 
232
  )
233
 
234
  if result.returncode != 0:
235
+ logger.error(f"LaTeX compilation failed: stdout={result.stdout}, stderr={result.stderr}")
236
  raise HTTPException(
237
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
238
+ detail=f"LaTeX compilation failed: {result.stderr}"
239
  )
240
 
241
  except subprocess.CalledProcessError as e:
242
+ logger.error(f"LaTeX compilation error: stdout={e.stdout}, stderr={e.stderr}")
243
  raise HTTPException(
244
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
245
+ detail=f"LaTeX compilation failed: {e.stderr}"
246
  )
247
 
248
  if not os.path.exists(pdf_path):
249
+ logger.error("PDF file was not generated")
250
  raise HTTPException(
251
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
252
  detail="PDF file was not generated"
253
  )
254
 
255
  with open(pdf_path, "rb") as f:
256
  pdf_bytes = f.read()
257
 
258
+ logger.info(f"PDF generated successfully for patient {patient_id} by {current_user.get('email')}")
259
+ return Response(
260
  content=pdf_bytes,
261
  media_type="application/pdf",
262
  headers={"Content-Disposition": f"attachment; filename=patient_{patient.get('fhir_id', 'unknown')}_report.pdf"}
263
  )
 
264
 
265
+ except HTTPException:
266
+ raise
267
  except Exception as e:
268
+ logger.error(f"Unexpected error generating PDF for patient {patient_id}: {str(e)}")
269
  raise HTTPException(
270
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
271
  detail=f"Unexpected error generating PDF: {str(e)}"
272
  )
 
 
 
273
 
274
+ # Export the router
275
  pdf = router