feat: Migrate Street and Task models from MongoDB to CouchDB
- Replace Street model with CouchDB-based implementation - Replace Task model with CouchDB-based implementation - Update routes to use new model interfaces - Handle geospatial queries with CouchDB design documents - Maintain adoption functionality and middleware - Use denormalized document structure with embedded data - Update test files to work with new models - Ensure API compatibility while using CouchDB underneath 🤖 Generated with [AI Assistant] Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
const express = require("express");
|
||||
const mongoose = require("mongoose");
|
||||
const Street = require("../models/Street");
|
||||
const User = require("../models/User");
|
||||
const couchdbService = require("../services/couchdbService");
|
||||
const auth = require("../middleware/auth");
|
||||
const { asyncHandler } = require("../middleware/errorHandler");
|
||||
const {
|
||||
createStreetValidation,
|
||||
streetIdValidation,
|
||||
} = require("../middleware/validators/streetValidator");
|
||||
const {
|
||||
awardStreetAdoptionPoints,
|
||||
checkAndAwardBadges,
|
||||
} = require("../services/gamificationService");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -19,7 +15,7 @@ const router = express.Router();
|
||||
router.get(
|
||||
"/",
|
||||
asyncHandler(async (req, res) => {
|
||||
const { paginate, buildPaginatedResponse } = require("../middleware/pagination");
|
||||
const { buildPaginatedResponse } = require("../middleware/pagination");
|
||||
|
||||
// Parse pagination params
|
||||
const page = parseInt(req.query.page) || 1;
|
||||
@@ -27,10 +23,16 @@ router.get(
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
const streets = await Street.find()
|
||||
.sort({ name: 1 })
|
||||
.sort([{ name: "asc" }])
|
||||
.skip(skip)
|
||||
.limit(limit)
|
||||
.populate("adoptedBy", ["name", "profilePicture"]);
|
||||
.limit(limit);
|
||||
|
||||
// Populate adoptedBy information
|
||||
for (const street of streets) {
|
||||
if (street.adoptedBy && street.adoptedBy.userId) {
|
||||
await street.populate("adoptedBy");
|
||||
}
|
||||
}
|
||||
|
||||
const totalCount = await Street.countDocuments();
|
||||
|
||||
@@ -47,6 +49,12 @@ router.get(
|
||||
if (!street) {
|
||||
return res.status(404).json({ msg: "Street not found" });
|
||||
}
|
||||
|
||||
// Populate adoptedBy information if exists
|
||||
if (street.adoptedBy && street.adoptedBy.userId) {
|
||||
await street.populate("adoptedBy");
|
||||
}
|
||||
|
||||
res.json(street);
|
||||
}),
|
||||
);
|
||||
@@ -59,12 +67,11 @@ router.post(
|
||||
asyncHandler(async (req, res) => {
|
||||
const { name, location } = req.body;
|
||||
|
||||
const newStreet = new Street({
|
||||
const street = await Street.create({
|
||||
name,
|
||||
location,
|
||||
});
|
||||
|
||||
const street = await newStreet.save();
|
||||
res.json(street);
|
||||
}),
|
||||
);
|
||||
@@ -75,64 +82,63 @@ router.put(
|
||||
auth,
|
||||
streetIdValidation,
|
||||
asyncHandler(async (req, res) => {
|
||||
const session = await mongoose.startSession();
|
||||
session.startTransaction();
|
||||
|
||||
try {
|
||||
const street = await Street.findById(req.params.id).session(session);
|
||||
await couchdbService.initialize();
|
||||
|
||||
const street = await Street.findById(req.params.id);
|
||||
if (!street) {
|
||||
await session.abortTransaction();
|
||||
session.endSession();
|
||||
return res.status(404).json({ msg: "Street not found" });
|
||||
}
|
||||
|
||||
if (street.status === "adopted") {
|
||||
await session.abortTransaction();
|
||||
session.endSession();
|
||||
return res.status(400).json({ msg: "Street already adopted" });
|
||||
}
|
||||
|
||||
// Check if user has already adopted this street
|
||||
const user = await User.findById(req.user.id).session(session);
|
||||
const user = await User.findById(req.user.id);
|
||||
if (user.adoptedStreets.includes(req.params.id)) {
|
||||
await session.abortTransaction();
|
||||
session.endSession();
|
||||
return res
|
||||
.status(400)
|
||||
.json({ msg: "You have already adopted this street" });
|
||||
}
|
||||
|
||||
// Get user details for embedding
|
||||
const userDetails = {
|
||||
userId: user._id,
|
||||
name: user.name,
|
||||
profilePicture: user.profilePicture || ''
|
||||
};
|
||||
|
||||
// Update street
|
||||
street.adoptedBy = req.user.id;
|
||||
street.adoptedBy = userDetails;
|
||||
street.status = "adopted";
|
||||
await street.save({ session });
|
||||
await street.save();
|
||||
|
||||
// Update user's adoptedStreets array
|
||||
user.adoptedStreets.push(street._id);
|
||||
await user.save({ session });
|
||||
user.stats.streetsAdopted = user.adoptedStreets.length;
|
||||
await user.save();
|
||||
|
||||
// Award points for street adoption
|
||||
const { transaction } = await awardStreetAdoptionPoints(
|
||||
// Award points for street adoption using CouchDB service
|
||||
const updatedUser = await couchdbService.updateUserPoints(
|
||||
req.user.id,
|
||||
street._id,
|
||||
session,
|
||||
50,
|
||||
'Street adoption',
|
||||
{
|
||||
entityType: 'Street',
|
||||
entityId: street._id,
|
||||
entityName: street.name
|
||||
}
|
||||
);
|
||||
|
||||
// Check and award badges
|
||||
const newBadges = await checkAndAwardBadges(req.user.id, session);
|
||||
|
||||
await session.commitTransaction();
|
||||
session.endSession();
|
||||
|
||||
res.json({
|
||||
street,
|
||||
pointsAwarded: transaction.amount,
|
||||
newBalance: transaction.balanceAfter,
|
||||
badgesEarned: newBadges,
|
||||
pointsAwarded: 50,
|
||||
newBalance: updatedUser.points,
|
||||
badgesEarned: [], // Badges are handled automatically in CouchDB service
|
||||
});
|
||||
} catch (err) {
|
||||
await session.abortTransaction();
|
||||
session.endSession();
|
||||
console.error("Error adopting street:", err.message);
|
||||
throw err;
|
||||
}
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user