Dineshpopuri commited on
Commit
416b9b6
·
verified ·
1 Parent(s): 6188263

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -31
app.py CHANGED
@@ -154,7 +154,7 @@ def create_salesforce_record(score, checklist_summary, missing_summary, status,
154
  "Status__c": status,
155
  "Summarized_Missing_Items__c": summarized_missing,
156
  "Alert_Sent__c": alert_sent,
157
- "Client_PDF_Pack_URL__c": pdf_url if pdf_url else "", # Use the publicly accessible URL
158
  "Closure_Pack_URL__c": "",
159
  "Escalation_Flag__c": escalation_flag,
160
  "Evaluated_At__c": evaluated_at,
@@ -181,11 +181,15 @@ def create_salesforce_record(score, checklist_summary, missing_summary, status,
181
  logging.error(f"Failed to create Salesforce Project_Closure_Handover__c record: {str(e)}")
182
  return f"Error creating record: {str(e)}"
183
 
184
- # Clean input to prevent injection attacks
185
  def sanitize_input(text):
186
  if not text or not isinstance(text, str):
187
  return ""
188
- return bleach.clean(text.strip())
 
 
 
 
189
 
190
  # Rule-based completeness engine with weighted scoring
191
  def evaluate_readiness(logs, qa_report, punch_list_text):
@@ -261,73 +265,127 @@ def evaluate_readiness(logs, qa_report, punch_list_text):
261
  # Generate PDF report with signature slots and return a publicly accessible URL
262
  def generate_pdf(score, checklist_summary, missing_summary, checklist_status, logs, qa_report, punch_list_text):
263
  try:
264
- # Sanitize inputs
265
  logging.info("Sanitizing inputs for PDF generation")
266
  score = str(float(score)) if score is not None else "0"
267
- checklist_summary = str(checklist_summary) if checklist_summary is not None else ""
268
- checklist_status = str(checklist_status) if checklist_status is not None else ""
269
-
270
- checklist_summary = checklist_summary.encode('ascii', 'ignore').decode('ascii')
271
- checklist_status = checklist_status.encode('ascii', 'ignore').decode('ascii')
272
-
 
 
273
  pdf_path = "readiness_report.pdf"
274
- logging.info(f"Creating PDF at {pdf_path}")
275
 
 
 
 
 
 
 
 
276
  c = canvas.Canvas(pdf_path, pagesize=letter)
277
 
278
- c.setFont("Times-Bold", 16)
 
 
 
 
 
 
279
  c.drawString(50, 750, "Project Closure Readiness Report")
280
 
281
- c.setFont("Times-Roman", 12)
 
 
 
 
 
 
282
  c.drawString(50, 720, f"Readiness Score: {score}%")
283
  c.drawString(50, 700, f"Status: {checklist_status}")
284
  c.drawString(50, 680, "Checklist Summary:")
285
 
 
 
286
  y = 660
287
  BOTTOM_MARGIN = 50
288
- for line in checklist_summary.split("\n"):
 
 
 
 
 
 
 
289
  if y < BOTTOM_MARGIN:
290
  logging.info("Y position below margin, creating new page")
291
  c.showPage()
292
- c.setFont("Times-Roman", 12)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  y = 750
294
  c.drawString(50, y, line)
295
- y -= 20
296
 
 
 
 
297
  if y - 40 < BOTTOM_MARGIN:
298
  logging.info("Y position below margin, creating new page")
299
  c.showPage()
300
- c.setFont("Times-Roman", 12)
 
 
 
301
  y = 750
302
- c.drawString(50, y - 40, "Stakeholder Signature: ____________________")
303
 
 
304
  if y - 60 < BOTTOM_MARGIN:
305
  logging.info("Y position below margin, creating new page")
306
  c.showPage()
307
- c.setFont("Times-Roman", 12)
 
 
 
308
  y = 750
309
- c.drawString(50, y - 60, "Date: ____________________")
310
 
 
 
311
  c.save()
312
 
 
313
  if not os.path.exists(pdf_path):
314
  logging.error(f"PDF file {pdf_path} was not created")
315
  raise FileNotFoundError(f"PDF file {pdf_path} was not created")
316
 
317
  # Simulate uploading the PDF to a publicly accessible location
318
- # In a real implementation, you'd upload to a service like AWS S3, Google Drive, or a file-sharing service
319
- # and get a publicly accessible URL. For this example, we'll simulate a URL.
320
- # Replace this with actual upload logic as needed.
321
  simulated_public_url = f"https://example.com/pdf/readiness_report_{int(time.time())}.pdf"
322
  logging.info(f"Simulated public URL for PDF: {simulated_public_url}")
323
-
324
- # TODO: Implement actual file upload to a service like AWS S3 or Google Drive
325
- # Example with AWS S3 (requires boto3 and AWS credentials):
326
- # import boto3
327
- # s3 = boto3.client('s3', aws_access_key_id='YOUR_KEY', aws_secret_access_key='YOUR_SECRET')
328
- # bucket_name = 'your-bucket'
329
- # s3.upload_file(pdf_path, bucket_name, f"readiness_report_{int(time.time())}.pdf", ExtraArgs={'ACL': 'public-read'})
330
- # public_url = f"https://{bucket_name}.s3.amazonaws.com/readiness_report_{int(time.time())}.pdf"
331
 
332
  logging.info(f"PDF generated successfully at {pdf_path}")
333
  return simulated_public_url, "PDF generation completed. Click the link to download."
 
154
  "Status__c": status,
155
  "Summarized_Missing_Items__c": summarized_missing,
156
  "Alert_Sent__c": alert_sent,
157
+ "Client_PDF_Pack_URL__c": pdf_url if pdf_url else "",
158
  "Closure_Pack_URL__c": "",
159
  "Escalation_Flag__c": escalation_flag,
160
  "Evaluated_At__c": evaluated_at,
 
181
  logging.error(f"Failed to create Salesforce Project_Closure_Handover__c record: {str(e)}")
182
  return f"Error creating record: {str(e)}"
183
 
184
+ # Clean input to prevent injection attacks and ensure PDF compatibility
185
  def sanitize_input(text):
186
  if not text or not isinstance(text, str):
187
  return ""
188
+ # Clean HTML and strip whitespace
189
+ cleaned = bleach.clean(text.strip(), tags=[], attributes={})
190
+ # Replace non-ASCII characters with a space
191
+ cleaned = cleaned.encode('ascii', 'replace').decode('ascii').replace('?', ' ')
192
+ return cleaned
193
 
194
  # Rule-based completeness engine with weighted scoring
195
  def evaluate_readiness(logs, qa_report, punch_list_text):
 
265
  # Generate PDF report with signature slots and return a publicly accessible URL
266
  def generate_pdf(score, checklist_summary, missing_summary, checklist_status, logs, qa_report, punch_list_text):
267
  try:
268
+ # Sanitize inputs and handle None values
269
  logging.info("Sanitizing inputs for PDF generation")
270
  score = str(float(score)) if score is not None else "0"
271
+ checklist_summary = sanitize_input(checklist_summary) if checklist_summary else "No checklist summary provided"
272
+ missing_summary = sanitize_input(missing_summary) if missing_summary else "None"
273
+ checklist_status = sanitize_input(checklist_status) if checklist_status else "Unknown"
274
+ logs = sanitize_input(logs) if logs else "No logs provided"
275
+ qa_report = sanitize_input(qa_report) if qa_report else "No QA report provided"
276
+ punch_list_text = sanitize_input(punch_list_text) if punch_list_text else "No punch list provided"
277
+
278
+ # Define the temporary file path
279
  pdf_path = "readiness_report.pdf"
280
+ logging.info(f"Attempting to create PDF at {pdf_path}")
281
 
282
+ # Ensure the directory is writable
283
+ pdf_dir = os.path.dirname(pdf_path) or "."
284
+ if not os.access(pdf_dir, os.W_OK):
285
+ logging.error(f"No write permissions in directory: {pdf_dir}")
286
+ raise PermissionError(f"No write permissions in directory: {pdf_dir}")
287
+
288
+ # Create the PDF using reportlab
289
  c = canvas.Canvas(pdf_path, pagesize=letter)
290
 
291
+ # Set initial font and draw title
292
+ logging.info("Setting font to Times-Bold for title")
293
+ try:
294
+ c.setFont("Times-Bold", 16)
295
+ except Exception as e:
296
+ logging.error(f"Font error: {str(e)}. Falling back to default font.")
297
+ c.setFont("Helvetica-Bold", 16) # Fallback font
298
  c.drawString(50, 750, "Project Closure Readiness Report")
299
 
300
+ # Draw basic fields
301
+ logging.info("Drawing basic fields")
302
+ try:
303
+ c.setFont("Times-Roman", 12)
304
+ except Exception as e:
305
+ logging.error(f"Font error: {str(e)}. Falling back to default font.")
306
+ c.setFont("Helvetica", 12) # Fallback font
307
  c.drawString(50, 720, f"Readiness Score: {score}%")
308
  c.drawString(50, 700, f"Status: {checklist_status}")
309
  c.drawString(50, 680, "Checklist Summary:")
310
 
311
+ # Draw checklist summary with Y-position overflow handling
312
+ logging.info("Drawing checklist summary")
313
  y = 660
314
  BOTTOM_MARGIN = 50
315
+ LINE_HEIGHT = 20
316
+ lines = checklist_summary.split("\n")
317
+ if not lines:
318
+ lines = ["No checklist summary available"]
319
+ for line in lines:
320
+ # Truncate long lines to prevent overflow
321
+ if len(line) > 80: # Approximate character limit per line
322
+ line = line[:77] + "..."
323
  if y < BOTTOM_MARGIN:
324
  logging.info("Y position below margin, creating new page")
325
  c.showPage()
326
+ try:
327
+ c.setFont("Times-Roman", 12)
328
+ except:
329
+ c.setFont("Helvetica", 12)
330
+ y = 750
331
+ c.drawString(50, y, line)
332
+ y -= LINE_HEIGHT
333
+
334
+ # Draw additional sections
335
+ logging.info("Drawing missing summary")
336
+ y -= 20
337
+ c.drawString(50, y, "Missing Items:")
338
+ y -= LINE_HEIGHT
339
+ missing_lines = missing_summary.split("\n") if missing_summary else ["None"]
340
+ for line in missing_lines:
341
+ if len(line) > 80:
342
+ line = line[:77] + "..."
343
+ if y < BOTTOM_MARGIN:
344
+ c.showPage()
345
+ try:
346
+ c.setFont("Times-Roman", 12)
347
+ except:
348
+ c.setFont("Helvetica", 12)
349
  y = 750
350
  c.drawString(50, y, line)
351
+ y -= LINE_HEIGHT
352
 
353
+ # Draw signature slots
354
+ logging.info("Drawing signature slots")
355
+ y -= 20
356
  if y - 40 < BOTTOM_MARGIN:
357
  logging.info("Y position below margin, creating new page")
358
  c.showPage()
359
+ try:
360
+ c.setFont("Times-Roman", 12)
361
+ except:
362
+ c.setFont("Helvetica", 12)
363
  y = 750
364
+ c.drawString(50, y - 20, "Stakeholder Signature: ____________________")
365
 
366
+ y -= 20
367
  if y - 60 < BOTTOM_MARGIN:
368
  logging.info("Y position below margin, creating new page")
369
  c.showPage()
370
+ try:
371
+ c.setFont("Times-Roman", 12)
372
+ except:
373
+ c.setFont("Helvetica", 12)
374
  y = 750
375
+ c.drawString(50, y - 40, "Date: ____________________")
376
 
377
+ # Finalize the PDF
378
+ logging.info("Finalizing PDF")
379
  c.save()
380
 
381
+ # Confirm the file exists
382
  if not os.path.exists(pdf_path):
383
  logging.error(f"PDF file {pdf_path} was not created")
384
  raise FileNotFoundError(f"PDF file {pdf_path} was not created")
385
 
386
  # Simulate uploading the PDF to a publicly accessible location
 
 
 
387
  simulated_public_url = f"https://example.com/pdf/readiness_report_{int(time.time())}.pdf"
388
  logging.info(f"Simulated public URL for PDF: {simulated_public_url}")
 
 
 
 
 
 
 
 
389
 
390
  logging.info(f"PDF generated successfully at {pdf_path}")
391
  return simulated_public_url, "PDF generation completed. Click the link to download."