feat: closes #5867, dont email if user already read notification

instead of immediately sending emails, put them in ttl cache, once cache entry expires check if the user already read the notification, if its read dont send the email
This commit is contained in:
Barış Soner Uşaklı
2026-02-11 19:27:47 -05:00
parent fd43368a92
commit a55651d12f
5 changed files with 24 additions and 12 deletions

View File

@@ -10,8 +10,6 @@
"max-chat-room-name-length": "Maximum length of chat room names",
"max-room-size": "Maximum number of users in chat rooms",
"delay": "Time between chat messages (ms)",
"notification-delay": "Notification delay for chat messages",
"notification-delay-help": "Additional messages sent between this time are collated, and the user is notified once per delay period. Set this to 0 to disable the delay.",
"restrictions.seconds-edit-after": "Number of seconds a chat message will remain editable.",
"restrictions.seconds-delete-after": "Number of seconds a chat message will remain deletable."
}

View File

@@ -3,5 +3,7 @@
"welcome-notification": "Welcome Notification",
"welcome-notification-link": "Welcome Notification Link",
"welcome-notification-uid": "Welcome Notification User (UID)",
"post-queue-notification-uid": "Post Queue User (UID)"
"post-queue-notification-uid": "Post Queue User (UID)",
"notification-delay": "Delay for sending notification emails (seconds)",
"notification-delay-help": "If the user has read the notification within this time, the email will not be sent.<br/>Default: 60 seconds."
}

View File

@@ -282,7 +282,10 @@ async function pushToUids(uids, notification) {
notificationCache.delete(cacheKey);
}
} else {
await sendEmail({ uids: results.uidsToEmail, notification });
notificationCache.set(`delayed:nid:${notification.nid}`, {
uids: results.uidsToEmail,
notification,
});
}
}
@@ -294,11 +297,22 @@ async function pushToUids(uids, notification) {
});
}
async function sendEmail({ uids, notification }, mergeId, reason) {
async function sendEmail({ uids, notification }, cacheKey, reason) {
if ((reason && reason === 'set') || !uids.length) {
return;
}
// check if notification already read by users
// if so don't send email, https://github.com/NodeBB/NodeBB/issues/5867
const hasRead = await db.isMemberOfSortedSets(
uids.map(uid => `uid:${uid}:notifications:read`),
notification.nid
);
uids = uids.filter((uid, index) => !hasRead[index]);
if (!uids.length) {
return;
}
// Update CTA messaging (as not all notification types need custom text)
if (['new-reply', 'new-chat'].includes(notification.type)) {
notification['cta-type'] = notification.type;

View File

@@ -59,12 +59,6 @@
<label class="form-label" for="chatMessageDelay">[[admin/settings/chat:delay]]</label>
<input id="chatMessageDelay" type="text" class="form-control" data-field="chatMessageDelay">
</div>
<div class="mb-3">
<label class="form-label" for="notificationSendDelay">[[admin/settings/chat:notification-delay]]</label>
<input id="notificationSendDelay" type="text" class="form-control" value="60" data-field="notificationSendDelay">
<p class="form-text">[[admin/settings/chat:notification-delay-help]]</p>
</div>
</div>
</div>
<!-- IMPORT admin/partials/settings/toc.tpl -->

View File

@@ -21,7 +21,11 @@
<label class="form-label">[[admin/settings/notifications:post-queue-notification-uid]]</label>
<input type="text" class="form-control" data-field="postQueueNotificationUid">
</div>
<div class="mb-3">
<label class="form-label" for="notificationSendDelay">[[admin/settings/notifications:notification-delay]]</label>
<input id="notificationSendDelay" type="text" class="form-control" value="60" data-field="notificationSendDelay">
<p class="form-text">[[admin/settings/notifications:notification-delay-help]]</p>
</div>
</div>
</div>