04/27 Fixed notification hasn't been sent when submitting inspection

This commit is contained in:
2026-04-27 17:40:55 -04:00
parent 74fd9f7ce6
commit 9733dab925
+43 -23
View File
@@ -171,23 +171,33 @@ def notify(
inspection_id: int = None, inspection_id: int = None,
event_type: str = None, event_type: str = None,
send_email: bool = True, send_email: bool = True,
respect_preferences: bool = True,
): ):
"""Create an in-app Notification record and optionally send an email. """Create an in-app Notification record and optionally send an email.
Parameters Parameters
---------- ----------
recipient : User ORM instance recipient : User ORM instance
title : Short notification headline title : Short notification headline
body : Full notification message body : Full notification message
link : Relative URL for the 'View Details' button/link link : Relative URL for the 'View Details' button/link
issue_id : FK to issues.id (optional) issue_id : FK to issues.id (optional)
inspection_id: FK to inspections.id (optional) inspection_id : FK to inspections.id (optional)
event_type : One of the EVENT_* constants from models.notification event_type : One of the EVENT_* constants from models.notification
Used to look up the user's preference for this event. Used to look up the user's preference for this event.
send_email : Master switch — set False to suppress all email (overrides prefs) send_email : Master switch — set False to suppress all email (overrides prefs)
respect_preferences : When True (default), per-user email preferences gate delivery.
Set False for matrix-routed broadcasts — the matrix is the
authority; individual opt-out should not override admin config.
""" """
# Determine digest flag before creating the record # Determine digest flag before creating the record.
hold_for_digest = send_email and bool(event_type) and _digest_mode_for(recipient, event_type) # Digest mode is only respected when individual preferences are in effect.
hold_for_digest = (
respect_preferences
and send_email
and bool(event_type)
and _digest_mode_for(recipient, event_type)
)
# ── 1. Persist in-app notification ────────────────────────────────────── # ── 1. Persist in-app notification ──────────────────────────────────────
notif = Notification( notif = Notification(
@@ -210,9 +220,18 @@ def notify(
# ── 2. Send immediate email if applicable ──────────────────────────────── # ── 2. Send immediate email if applicable ────────────────────────────────
if send_email and not hold_for_digest: if send_email and not hold_for_digest:
should_send = ( if respect_preferences:
event_type is None or _email_enabled_for(recipient, event_type) # Per-user opt-in/opt-out gate — used for direct notifications
) # (issue assignment, SLA alerts, follower updates, etc.)
should_send = (
event_type is None or _email_enabled_for(recipient, event_type)
)
else:
# Matrix-routed broadcast — the admin matrix is the authority.
# Individual preference rows must not override it, otherwise an
# admin or director who once clicked "Pause All" would silently
# stop receiving inspection completion and other broadcast events.
should_send = True
if should_send and recipient.email and current_app.config.get('MAIL_SERVER'): if should_send and recipient.email and current_app.config.get('MAIL_SERVER'):
_send_single_email(recipient, title, body, link) _send_single_email(recipient, title, body, link)
@@ -547,14 +566,15 @@ def notify_by_matrix(
if user.id in exclude or user.id in notified: if user.id in exclude or user.id in notified:
continue continue
notify( notify(
recipient = user, recipient = user,
title = title, title = title,
body = body, body = body,
link = link, link = link,
issue_id = issue_id, issue_id = issue_id,
inspection_id = inspection_id, inspection_id = inspection_id,
event_type = event_type, event_type = event_type,
send_email = True, send_email = True,
respect_preferences = False, # matrix is the authority for broadcasts
) )
notified.add(user.id) notified.add(user.id)
@@ -607,4 +627,4 @@ def _send_custom_email(to_email: str, title: str, body: str, link: str = None):
logger.error('CUSTOM EMAIL FAILED | to=%s | error=%s', to_email, exc) logger.error('CUSTOM EMAIL FAILED | to=%s | error=%s', to_email, exc)
import threading import threading
threading.Thread(target=_send, daemon=True).start() threading.Thread(target=_send, daemon=True).start()