const express = require("express"); const mongoose = require("mongoose"); const Comment = require("../models/Comment"); const Post = require("../models/Post"); const auth = require("../middleware/auth"); const { paginate, buildPaginatedResponse } = require("../middleware/pagination"); const { asyncHandler } = require("../middleware/errorHandler"); const router = express.Router(); /** * GET /api/posts/:postId/comments * Get all comments for a post (paginated) */ router.get( "/:postId/comments", paginate, asyncHandler(async (req, res) => { const { postId } = req.params; const { skip, limit, page } = req.pagination; // Verify post exists const post = await Post.findById(postId); if (!post) { return res.status(404).json({ msg: "Post not found" }); } // Get comments with pagination const comments = await Comment.find({ post: postId }) .sort({ createdAt: -1 }) .skip(skip) .limit(limit) .populate("user", ["name", "profilePicture"]); const totalCount = await Comment.countDocuments({ post: postId }); res.json(buildPaginatedResponse(comments, totalCount, page, limit)); }) ); /** * POST /api/posts/:postId/comments * Create a new comment on a post */ router.post( "/:postId/comments", auth, asyncHandler(async (req, res) => { const { postId } = req.params; const { content } = req.body; // Validate content if (!content || content.trim().length === 0) { return res.status(400).json({ msg: "Comment content is required" }); } if (content.length > 500) { return res .status(400) .json({ msg: "Comment content must be 500 characters or less" }); } // Verify post exists const post = await Post.findById(postId); if (!post) { return res.status(404).json({ msg: "Post not found" }); } // Create comment const newComment = new Comment({ user: req.user.id, post: postId, content: content.trim(), }); const comment = await newComment.save(); // Update post's comment count await Post.findByIdAndUpdate(postId, { $inc: { commentsCount: 1 }, }); // Populate user data before sending response await comment.populate("user", ["name", "profilePicture"]); // Emit Socket.IO event for new comment const io = req.app.get("io"); if (io) { io.to(`post_${postId}`).emit("newComment", { postId, comment, }); } res.status(201).json(comment); }) ); /** * DELETE /api/posts/:postId/comments/:commentId * Delete own comment */ router.delete( "/:postId/comments/:commentId", auth, asyncHandler(async (req, res) => { const { postId, commentId } = req.params; // Find comment const comment = await Comment.findById(commentId); if (!comment) { return res.status(404).json({ msg: "Comment not found" }); } // Verify comment belongs to the post if (comment.post.toString() !== postId) { return res.status(400).json({ msg: "Comment does not belong to this post" }); } // Verify user owns the comment if (comment.user.toString() !== req.user.id) { return res.status(403).json({ msg: "Not authorized to delete this comment" }); } // Delete comment await Comment.findByIdAndDelete(commentId); // Update post's comment count await Post.findByIdAndUpdate(postId, { $inc: { commentsCount: -1 }, }); // Emit Socket.IO event for deleted comment const io = req.app.get("io"); if (io) { io.to(`post_${postId}`).emit("commentDeleted", { postId, commentId, }); } res.json({ msg: "Comment deleted successfully" }); }) ); module.exports = router;