Can mark a comment as the answer, some layout changes

This commit is contained in:
jackiettran
2025-11-11 18:23:11 -05:00
parent 825389228d
commit b045fbeb01
11 changed files with 379 additions and 323 deletions

View File

@@ -29,7 +29,7 @@ const ForumPost = sequelize.define('ForumPost', {
defaultValue: 'general_discussion'
},
status: {
type: DataTypes.ENUM('open', 'solved', 'closed'),
type: DataTypes.ENUM('open', 'answered', 'closed'),
defaultValue: 'open'
},
viewCount: {
@@ -43,6 +43,14 @@ const ForumPost = sequelize.define('ForumPost', {
isPinned: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
acceptedAnswerId: {
type: DataTypes.UUID,
allowNull: true,
references: {
model: 'ForumComments',
key: 'id'
}
}
});

View File

@@ -156,9 +156,11 @@ router.get('/posts/:id', async (req, res) => {
as: 'author',
attributes: ['id', 'username', 'firstName', 'lastName']
}
],
order: [['createdAt', 'ASC']]
]
}
],
order: [
[{ model: ForumComment, as: 'comments' }, 'createdAt', 'ASC']
]
});
@@ -370,7 +372,7 @@ router.patch('/posts/:id/status', authenticateToken, async (req, res) => {
return res.status(403).json({ error: 'Only the author can update post status' });
}
if (!['open', 'solved', 'closed'].includes(status)) {
if (!['open', 'answered', 'closed'].includes(status)) {
return res.status(400).json({ error: 'Invalid status value' });
}
@@ -411,6 +413,82 @@ router.patch('/posts/:id/status', authenticateToken, async (req, res) => {
}
});
// PATCH /api/forum/posts/:id/accept-answer - Mark/unmark comment as accepted answer
router.patch('/posts/:id/accept-answer', authenticateToken, async (req, res) => {
try {
const { commentId } = req.body;
const post = await ForumPost.findByPk(req.params.id);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
if (post.authorId !== req.user.id) {
return res.status(403).json({ error: 'Only the post author can mark answers' });
}
// If commentId is provided, validate it
if (commentId) {
const comment = await ForumComment.findByPk(commentId);
if (!comment) {
return res.status(404).json({ error: 'Comment not found' });
}
if (comment.postId !== post.id) {
return res.status(400).json({ error: 'Comment does not belong to this post' });
}
if (comment.isDeleted) {
return res.status(400).json({ error: 'Cannot mark deleted comment as answer' });
}
if (comment.parentCommentId) {
return res.status(400).json({ error: 'Only top-level comments can be marked as answers' });
}
}
// Update the post with accepted answer
await post.update({
acceptedAnswerId: commentId || null,
status: commentId ? 'answered' : 'open'
});
const updatedPost = await ForumPost.findByPk(post.id, {
include: [
{
model: User,
as: 'author',
attributes: ['id', 'username', 'firstName', 'lastName']
},
{
model: PostTag,
as: 'tags',
attributes: ['tagName']
}
]
});
const reqLogger = logger.withRequestId(req.id);
reqLogger.info("Answer marked/unmarked", {
postId: req.params.id,
commentId: commentId || 'unmarked',
authorId: req.user.id
});
res.json(updatedPost);
} catch (error) {
const reqLogger = logger.withRequestId(req.id);
reqLogger.error("Mark answer failed", {
error: error.message,
stack: error.stack,
postId: req.params.id,
authorId: req.user.id
});
res.status(500).json({ error: error.message });
}
});
// POST /api/forum/posts/:id/comments - Add comment/reply
router.post('/posts/:id/comments', authenticateToken, async (req, res) => {
try {