Implement additional backend features and improve data models: Comments System: - Create Comment model with user and post relationships - Add comments routes: GET /api/posts/:postId/comments (paginated), POST (create), DELETE (own comments) - Update Post model with commentsCount field - Emit Socket.IO events for newComment and commentDeleted - Pagination support for comment lists - Authorization checks (users can only delete own comments) - 500 character limit on comments Image Upload System: - Implement Cloudinary configuration (config/cloudinary.js) - Add uploadImage() and deleteImage() helper functions - Image optimization: max 1000x1000, auto quality, auto format (WebP) - Integrate image upload in users routes (profile pictures) - Integrate image upload in posts routes (post images with add/update endpoints) - File validation: 5MB limit, JPG/PNG/GIF/WebP only - Automatic image deletion when removing posts/reports Data Consistency Improvements: - Add cascade deletes in Street model (remove from user, delete associated tasks) - Add cascade deletes in Task model (remove from user completedTasks) - Add cascade deletes in Post model (remove from user posts) - Update user relationships on save (adoptedStreets, completedTasks, posts, events) - Add proper indexes for performance (2dsphere for location, compound indexes) - Add virtual relationships and toJSON configurations Model Updates: - Street: Add cascade hooks, location 2dsphere index - Task: Add cascade hooks, compound indexes for queries - Post: Add imageUrl, cloudinaryPublicId, commentsCount fields - Event: Add participants tracking - Report: Add image upload support - User: Add earnedBadges virtual, profilePicture, cloudinaryPublicId 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
91 lines
2.3 KiB
JavaScript
91 lines
2.3 KiB
JavaScript
const express = require("express");
|
|
const User = require("../models/User");
|
|
const auth = require("../middleware/auth");
|
|
const { asyncHandler } = require("../middleware/errorHandler");
|
|
const { userIdValidation } = require("../middleware/validators/userValidator");
|
|
const { upload, handleUploadError } = require("../middleware/upload");
|
|
const { uploadImage, deleteImage } = require("../config/cloudinary");
|
|
|
|
const router = express.Router();
|
|
|
|
// Get user by ID
|
|
router.get(
|
|
"/:id",
|
|
auth,
|
|
userIdValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const user = await User.findById(req.params.id).populate("adoptedStreets");
|
|
if (!user) {
|
|
return res.status(404).json({ msg: "User not found" });
|
|
}
|
|
res.json(user);
|
|
}),
|
|
);
|
|
|
|
// Upload profile picture
|
|
router.post(
|
|
"/profile-picture",
|
|
auth,
|
|
upload.single("image"),
|
|
handleUploadError,
|
|
asyncHandler(async (req, res) => {
|
|
if (!req.file) {
|
|
return res.status(400).json({ msg: "No image file provided" });
|
|
}
|
|
|
|
const user = await User.findById(req.user.id);
|
|
if (!user) {
|
|
return res.status(404).json({ msg: "User not found" });
|
|
}
|
|
|
|
// Delete old profile picture if exists
|
|
if (user.cloudinaryPublicId) {
|
|
await deleteImage(user.cloudinaryPublicId);
|
|
}
|
|
|
|
// Upload new image to Cloudinary
|
|
const result = await uploadImage(
|
|
req.file.buffer,
|
|
"adopt-a-street/profiles",
|
|
);
|
|
|
|
// Update user with new profile picture
|
|
user.profilePicture = result.url;
|
|
user.cloudinaryPublicId = result.publicId;
|
|
await user.save();
|
|
|
|
res.json({
|
|
msg: "Profile picture updated successfully",
|
|
profilePicture: user.profilePicture,
|
|
});
|
|
}),
|
|
);
|
|
|
|
// Delete profile picture
|
|
router.delete(
|
|
"/profile-picture",
|
|
auth,
|
|
asyncHandler(async (req, res) => {
|
|
const user = await User.findById(req.user.id);
|
|
if (!user) {
|
|
return res.status(404).json({ msg: "User not found" });
|
|
}
|
|
|
|
if (!user.cloudinaryPublicId) {
|
|
return res.status(400).json({ msg: "No profile picture to delete" });
|
|
}
|
|
|
|
// Delete image from Cloudinary
|
|
await deleteImage(user.cloudinaryPublicId);
|
|
|
|
// Remove from user
|
|
user.profilePicture = undefined;
|
|
user.cloudinaryPublicId = undefined;
|
|
await user.save();
|
|
|
|
res.json({ msg: "Profile picture deleted successfully" });
|
|
}),
|
|
);
|
|
|
|
module.exports = router;
|