integrated email is forum posts/comments

This commit is contained in:
jackiettran
2025-11-14 15:51:25 -05:00
parent 105f257c5f
commit 629f0055a1
6 changed files with 1647 additions and 61 deletions

View File

@@ -4,6 +4,7 @@ const { ForumPost, ForumComment, PostTag, User } = require('../models');
const { authenticateToken } = require('../middleware/auth');
const { uploadForumPostImages, uploadForumCommentImages } = require('../middleware/upload');
const logger = require('../utils/logger');
const emailService = require('../services/emailService');
const router = express.Router();
// Helper function to build nested comment tree
@@ -468,6 +469,46 @@ router.patch('/posts/:id/accept-answer', authenticateToken, async (req, res) =>
status: commentId ? 'answered' : 'open'
});
// Send email notification if marking an answer (not unmarking)
if (commentId) {
(async () => {
try {
const comment = await ForumComment.findByPk(commentId, {
include: [
{
model: User,
as: 'author',
attributes: ['id', 'username', 'firstName', 'lastName', 'email']
}
]
});
const postAuthor = await User.findByPk(req.user.id, {
attributes: ['id', 'username', 'firstName', 'lastName', 'email']
});
// Only send email if not marking your own comment as answer
if (comment && comment.authorId !== req.user.id) {
await emailService.sendForumAnswerAcceptedNotification(
comment.author,
postAuthor,
post,
comment
);
}
} catch (emailError) {
// Email errors don't block answer marking
logger.error("Failed to send answer accepted notification email", {
error: emailError.message,
stack: emailError.stack,
commentId: commentId,
postId: req.params.id
});
console.error("Email notification error:", emailError);
}
})();
}
const updatedPost = await ForumPost.findByPk(post.id, {
include: [
{
@@ -540,11 +581,107 @@ router.post('/posts/:id/comments', authenticateToken, uploadForumCommentImages,
{
model: User,
as: 'author',
attributes: ['id', 'username', 'firstName', 'lastName']
attributes: ['id', 'username', 'firstName', 'lastName', 'email']
}
]
});
// Send email notifications (non-blocking)
(async () => {
try {
const commenter = commentWithDetails.author;
const notifiedUserIds = new Set();
// Reload post with author details for email
const postWithAuthor = await ForumPost.findByPk(req.params.id, {
include: [
{
model: User,
as: 'author',
attributes: ['id', 'username', 'firstName', 'lastName', 'email']
}
]
});
// If this is a reply, send reply notification to parent comment author
if (parentCommentId) {
const parentComment = await ForumComment.findByPk(parentCommentId, {
include: [
{
model: User,
as: 'author',
attributes: ['id', 'username', 'firstName', 'lastName', 'email']
}
]
});
// Send reply notification if not replying to yourself
if (parentComment && parentComment.authorId !== req.user.id) {
await emailService.sendForumReplyNotification(
parentComment.author,
commenter,
postWithAuthor,
commentWithDetails,
parentComment
);
notifiedUserIds.add(parentComment.authorId);
}
} else {
// Send comment notification to post author if not commenting on your own post
if (postWithAuthor.authorId !== req.user.id) {
await emailService.sendForumCommentNotification(
postWithAuthor.author,
commenter,
postWithAuthor,
commentWithDetails
);
notifiedUserIds.add(postWithAuthor.authorId);
}
}
// Get all unique participants who have commented on this post (excluding commenter and already notified)
const participants = await ForumComment.findAll({
where: {
postId: req.params.id,
authorId: {
[Op.notIn]: [req.user.id, ...Array.from(notifiedUserIds)]
},
isDeleted: false
},
attributes: ['authorId'],
include: [
{
model: User,
as: 'author',
attributes: ['id', 'username', 'firstName', 'lastName', 'email']
}
],
group: ['ForumComment.authorId', 'author.id']
});
// Send thread activity notifications to all unique participants
for (const participant of participants) {
if (participant.author) {
await emailService.sendForumThreadActivityNotification(
participant.author,
commenter,
postWithAuthor,
commentWithDetails
);
}
}
} catch (emailError) {
// Email errors don't block comment creation
logger.error("Failed to send forum comment notification emails", {
error: emailError.message,
stack: emailError.stack,
commentId: comment.id,
postId: req.params.id
});
console.error("Email notification error:", emailError);
}
})();
const reqLogger = logger.withRequestId(req.id);
reqLogger.info("Forum comment created", {
postId: req.params.id,