rairo commited on
Commit
e4b2442
·
verified ·
1 Parent(s): 45d6d2f

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +23 -20
main.py CHANGED
@@ -10,7 +10,7 @@ from flask_apscheduler import APScheduler
10
  import firebase_admin
11
  from firebase_admin import credentials, db, auth as firebase_auth
12
  from resend import Emails
13
- from resend.exceptions import ResendError # <-- Keep this import
14
  import logging
15
  from logging.handlers import RotatingFileHandler
16
  import time
@@ -36,7 +36,6 @@ root_logger.addHandler(file_handler)
36
  root_logger.addHandler(console_handler)
37
 
38
  # === ENV Config ===
39
- # CRITICAL: Double-check this list in your environment or code for hidden spaces!
40
  ADMIN_EMAILS = ["rairorr@gmail.com", "nharingosheperd@gmail.com"]
41
  RESEND_API_KEY = os.getenv("RESEND_API_KEY")
42
  FIREBASE_CRED_JSON = json.loads(os.getenv("FIREBASE"))
@@ -63,40 +62,32 @@ Emails.api_key = RESEND_API_KEY
63
  logger.info("Flask, APScheduler, and Resend initialized.")
64
 
65
 
66
- # === DEFINITIVELY FIXED FUNCTION (send_email) ===
67
  def send_email(to, subject, html):
68
- """Sends an email with sanitized input and robust error logging."""
69
  try:
70
- # Sanitize the email address to remove leading/trailing whitespace
71
- clean_to = to.strip()
72
- if not clean_to:
73
- logger.error("Attempted to send email to an empty address.")
74
- return None
75
-
76
  response = Emails.send({
77
  "from": "Admin <admin@resend.dev>",
78
- "to": clean_to, # Use the cleaned email address
79
  "subject": subject,
80
  "html": html
81
  })
82
  if response is None:
83
- logger.warning(f"Email API returned None for recipient {clean_to}. Check Resend dashboard for suppression list.")
84
  return None
85
- logger.info(f"Email sent successfully to {clean_to}. Response ID: {response.get('id')}")
86
  return response
87
  except ResendError as e:
88
- # --- FIX: Convert the entire exception to a string. ---
89
- # This is robust and will not crash even if attributes are missing.
90
  logger.error(f"A Resend API error occurred for recipient '{to}'. The error is: {str(e)}", exc_info=True)
91
  return None
92
  except Exception as e:
93
- # Fallback for any other unexpected errors
94
  logger.error(f"An unexpected exception occurred while sending email to '{to}': {str(e)}", exc_info=True)
95
  return None
96
 
97
 
 
98
  def send_rotation_notification(job_id, shift_record):
99
- """Sends email notification for rotation to all admins."""
100
  try:
101
  job_ref = db.reference(f"jobs/{job_id}")
102
  job_data = job_ref.get()
@@ -133,10 +124,22 @@ def send_rotation_notification(job_id, shift_record):
133
  html_content += "</tbody></table><p><em>This is an automated notification from the Guard Rotation System.</em></p>"
134
 
135
  subject = f"Guard Rotation - {job_name} (Shift {shift_number})"
 
136
  for admin_email in ADMIN_EMAILS:
137
- logger.info(f"Sending rotation notification to {admin_email}...")
138
- send_email(admin_email, subject, html_content)
139
- time.sleep(1) # Rate-limit prevention
 
 
 
 
 
 
 
 
 
 
 
140
  except Exception as e:
141
  logger.error(f"Error building rotation notification for job {job_id}", exc_info=True)
142
 
 
10
  import firebase_admin
11
  from firebase_admin import credentials, db, auth as firebase_auth
12
  from resend import Emails
13
+ from resend.exceptions import ResendError
14
  import logging
15
  from logging.handlers import RotatingFileHandler
16
  import time
 
36
  root_logger.addHandler(console_handler)
37
 
38
  # === ENV Config ===
 
39
  ADMIN_EMAILS = ["rairorr@gmail.com", "nharingosheperd@gmail.com"]
40
  RESEND_API_KEY = os.getenv("RESEND_API_KEY")
41
  FIREBASE_CRED_JSON = json.loads(os.getenv("FIREBASE"))
 
62
  logger.info("Flask, APScheduler, and Resend initialized.")
63
 
64
 
 
65
  def send_email(to, subject, html):
66
+ """Sends an email with robust error logging."""
67
  try:
68
+ # Note: Sanitization is now handled by the caller function
 
 
 
 
 
69
  response = Emails.send({
70
  "from": "Admin <admin@resend.dev>",
71
+ "to": to,
72
  "subject": subject,
73
  "html": html
74
  })
75
  if response is None:
76
+ logger.warning(f"Email API returned None for recipient {to}. Check Resend dashboard for suppression list.")
77
  return None
78
+ logger.info(f"Email sent successfully to {to}. Response ID: {response.get('id')}")
79
  return response
80
  except ResendError as e:
 
 
81
  logger.error(f"A Resend API error occurred for recipient '{to}'. The error is: {str(e)}", exc_info=True)
82
  return None
83
  except Exception as e:
 
84
  logger.error(f"An unexpected exception occurred while sending email to '{to}': {str(e)}", exc_info=True)
85
  return None
86
 
87
 
88
+ # === DEFINITIVELY FIXED FUNCTION (send_rotation_notification) ===
89
  def send_rotation_notification(job_id, shift_record):
90
+ """Builds and sends email notifications with aggressive sanitization and debugging."""
91
  try:
92
  job_ref = db.reference(f"jobs/{job_id}")
93
  job_data = job_ref.get()
 
124
  html_content += "</tbody></table><p><em>This is an automated notification from the Guard Rotation System.</em></p>"
125
 
126
  subject = f"Guard Rotation - {job_name} (Shift {shift_number})"
127
+
128
  for admin_email in ADMIN_EMAILS:
129
+ # --- ULTIMATE DEBUGGING AND SANITIZATION ---
130
+ # 1. Log the raw state of the string
131
+ logger.debug(f"RAW email string | Length: {len(admin_email)} | Representation: {repr(admin_email)}")
132
+
133
+ # 2. Aggressively sanitize the string by re-encoding it. This removes hidden characters.
134
+ sanitized_email = admin_email.encode('utf-8', 'ignore').decode('utf-8').strip()
135
+
136
+ # 3. Log the sanitized state
137
+ logger.debug(f"SANITIZED email string | Length: {len(sanitized_email)} | Representation: {repr(sanitized_email)}")
138
+
139
+ logger.info(f"Sending rotation notification to {sanitized_email}...")
140
+ send_email(sanitized_email, subject, html_content) # Use the sanitized email
141
+ time.sleep(1)
142
+
143
  except Exception as e:
144
  logger.error(f"Error building rotation notification for job {job_id}", exc_info=True)
145