Files
adopt-a-street/backend/routes/users.js
William Valentin df94c17e1f feat: complete MongoDB to CouchDB migration
- Migrate Report model to CouchDB with embedded street/user data
- Migrate UserBadge model to CouchDB with badge population
- Update all remaining routes (reports, users, badges, payments) to use CouchDB
- Add CouchDB health check and graceful shutdown to server.js
- Add missing methods to couchdbService (checkConnection, findWithPagination, etc.)
- Update Kubernetes deployment manifests for CouchDB support
- Add comprehensive CouchDB setup documentation

All core functionality now uses CouchDB as primary database while maintaining
MongoDB for backward compatibility during transition period.

🤖 Generated with [AI Assistant]

Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
2025-11-01 13:29:48 -07:00

117 lines
3.0 KiB
JavaScript

const express = require("express");
const User = require("../models/User");
const Street = require("../models/Street");
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);
if (!user) {
return res.status(404).json({ msg: "User not found" });
}
// Get adopted streets data
let adoptedStreets = [];
if (user.adoptedStreets && user.adoptedStreets.length > 0) {
adoptedStreets = await Promise.all(
user.adoptedStreets.map(async (streetId) => {
const street = await Street.findById(streetId);
return street ? {
_id: street._id,
name: street.name,
location: street.location,
status: street.status,
} : null;
})
);
adoptedStreets = adoptedStreets.filter(Boolean);
}
const userWithStreets = {
...user,
adoptedStreets,
};
res.json(userWithStreets);
}),
);
// 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
const updatedUser = await User.update(req.user.id, {
profilePicture: result.url,
cloudinaryPublicId: result.publicId,
});
res.json({
msg: "Profile picture updated successfully",
profilePicture: updatedUser.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
await User.update(req.user.id, {
profilePicture: undefined,
cloudinaryPublicId: undefined,
});
res.json({ msg: "Profile picture deleted successfully" });
}),
);
module.exports = router;