From 104a0633f1528447c402a5d68e504e7fb9f05516 Mon Sep 17 00:00:00 2001 From: NguyenND Date: Fri, 17 Apr 2026 14:06:07 -0400 Subject: [PATCH] 04/17 Update: sends email to each IT Staff when a new ticket created --- app/services/notification_service.py | 48 ++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/app/services/notification_service.py b/app/services/notification_service.py index ee3ba19..3660738 100644 --- a/app/services/notification_service.py +++ b/app/services/notification_service.py @@ -135,11 +135,20 @@ def send_email(subject, recipients, html_body): # ─── Ticket Event Helpers ───────────────────────────────────────────────────── def notify_new_ticket(ticket): - """Notify IT staff (email + in-app) and confirm receipt to the creator.""" + """Notify IT staff (email + in-app) and confirm receipt to the creator. + + Email fan-out strategy: + - The department alias (IT_DEPT_EMAIL) always receives one consolidated email. + - Each active IT staff / admin user who has email_notif=True also receives an + individual email so that personal notification preferences are respected. + - In-app notifications are created for every active IT staff / admin user + regardless of their email_notif setting. + """ base_url = current_app.config.get('APP_BASE_URL', '') ticket_url = f"{base_url}/tickets/{ticket.id}" - # Email IT staff + # Build the shared HTML body once — reused for both the dept alias and + # individual staff emails to avoid rendering the template multiple times. html = render_template_string(_NEW_TICKET_EMAIL, ticket_number = ticket.ticket_number, title = ticket.title, @@ -150,15 +159,25 @@ def notify_new_ticket(ticket): submitted_by = ticket.creator.full_name, ticket_url = ticket_url, ) - it_email = current_app.config.get('IT_DEPT_EMAIL') - send_email(f'[New Ticket] {ticket.ticket_number} – {ticket.title}', [it_email], html) + subject = f'[New Ticket] {ticket.ticket_number} – {ticket.title}' - # In-app: all IT staff + # --- Department alias email (existing behaviour, preserved) --------------- + it_email = current_app.config.get('IT_DEPT_EMAIL') + if it_email: + send_email(subject, [it_email], html) + logger.info(f'[NEW TICKET NOTIFY] Dept alias email sent to {it_email} for ticket_id={ticket.id}') + else: + logger.warning('[NEW TICKET NOTIFY] IT_DEPT_EMAIL is not configured — dept alias email skipped') + + # --- Per-staff individual emails + in-app notifications ------------------ it_users = User.query.filter( User.role.in_([UserRole.IT_STAFF, UserRole.ADMIN]), User.is_active == True, ).all() + + email_sent_count = 0 for staff in it_users: + # In-app notification — sent regardless of email preference create_notification( user_id = staff.id, notif_type= NotificationType.TICKET_CREATED, @@ -168,7 +187,22 @@ def notify_new_ticket(ticket): link = f'/tickets/{ticket.id}', ) - # Confirm to creator + # Individual email — only if the staff member has opted in + if staff.email_notif: + send_email(subject, [staff.email], html) + email_sent_count += 1 + logger.info( + f'[NEW TICKET NOTIFY] Individual email sent to staff user_id={staff.id} ' + f'email={staff.email} for ticket_id={ticket.id}' + ) + + logger.info( + f'[NEW TICKET NOTIFY] ticket_id={ticket.id} number={ticket.ticket_number} — ' + f'in-app notifications sent to {len(it_users)} IT staff; ' + f'individual emails sent to {email_sent_count} of {len(it_users)} staff (email_notif=True)' + ) + + # --- Confirm receipt to ticket creator ----------------------------------- create_notification( user_id = ticket.created_by_id, notif_type= NotificationType.TICKET_CREATED, @@ -470,4 +504,4 @@ def send_satisfaction_survey(ticket): t = Thread(target=_send, daemon=True) t.start() - logger.info(f'[SURVEY] Email thread started for ticket_id={ticket_id}') + logger.info(f'[SURVEY] Email thread started for ticket_id={ticket_id}') \ No newline at end of file