- Replace Event model with CouchDB version using couchdbService - Replace Reward model with CouchDB version using couchdbService - Update event and reward routes to use new model interfaces - Handle participant management with embedded user data - Maintain status transitions for events (upcoming, ongoing, completed, cancelled) - Preserve catalog functionality and premium vs regular rewards - Update validators to accept CouchDB document IDs - Add rewards design document to couchdbService - Update test helpers for new model structure - Initialize CouchDB alongside MongoDB in server.js for backward compatibility - Fix linting issues in migrated routes 🤖 Generated with [AI Assistant] Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
253 lines
6.0 KiB
JavaScript
253 lines
6.0 KiB
JavaScript
const express = require("express");
|
|
const Reward = require("../models/Reward");
|
|
const auth = require("../middleware/auth");
|
|
const { asyncHandler } = require("../middleware/errorHandler");
|
|
const {
|
|
createRewardValidation,
|
|
rewardIdValidation,
|
|
} = require("../middleware/validators/rewardValidator");
|
|
const { paginate, buildPaginatedResponse } = require("../middleware/pagination");
|
|
|
|
const router = express.Router();
|
|
|
|
// Get all rewards (with pagination)
|
|
router.get(
|
|
"/",
|
|
paginate,
|
|
asyncHandler(async (req, res) => {
|
|
const { page, limit } = req.pagination;
|
|
|
|
const result = await Reward.getAllPaginated(page, limit);
|
|
res.json(buildPaginatedResponse(result.rewards, result.pagination.totalCount, page, limit));
|
|
}),
|
|
);
|
|
|
|
// Create a reward
|
|
router.post(
|
|
"/",
|
|
auth,
|
|
createRewardValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const { name, description, cost, isPremium } = req.body;
|
|
|
|
const reward = await Reward.create({
|
|
name,
|
|
description,
|
|
cost,
|
|
isPremium,
|
|
});
|
|
|
|
res.json(reward);
|
|
}),
|
|
);
|
|
|
|
// Redeem a reward
|
|
router.post(
|
|
"/redeem/:id",
|
|
auth,
|
|
rewardIdValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const rewardId = req.params.id;
|
|
const userId = req.user.id;
|
|
|
|
try {
|
|
const result = await Reward.redeemReward(userId, rewardId);
|
|
|
|
res.json({
|
|
msg: "Reward redeemed successfully",
|
|
pointsDeducted: result.pointsDeducted,
|
|
newBalance: result.newBalance,
|
|
redemption: result.redemption
|
|
});
|
|
} catch (error) {
|
|
if (error.message === "Reward not found") {
|
|
return res.status(404).json({ msg: "Reward not found" });
|
|
}
|
|
if (error.message === "Reward is not available") {
|
|
return res.status(400).json({ msg: "Reward is not available" });
|
|
}
|
|
if (error.message === "User not found") {
|
|
return res.status(404).json({ msg: "User not found" });
|
|
}
|
|
if (error.message === "Not enough points") {
|
|
return res.status(400).json({ msg: "Not enough points" });
|
|
}
|
|
if (error.message === "Premium reward not available") {
|
|
return res.status(403).json({ msg: "Premium reward not available" });
|
|
}
|
|
throw error;
|
|
}
|
|
}),
|
|
);
|
|
|
|
// Get reward by ID
|
|
router.get(
|
|
"/:id",
|
|
rewardIdValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const reward = await Reward.findById(req.params.id);
|
|
if (!reward) {
|
|
return res.status(404).json({ msg: "Reward not found" });
|
|
}
|
|
res.json(reward);
|
|
})
|
|
);
|
|
|
|
// Update reward
|
|
router.put(
|
|
"/:id",
|
|
auth,
|
|
rewardIdValidation,
|
|
createRewardValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const { name, description, cost, isPremium, isActive } = req.body;
|
|
|
|
const reward = await Reward.findById(req.params.id);
|
|
if (!reward) {
|
|
return res.status(404).json({ msg: "Reward not found" });
|
|
}
|
|
|
|
const updateData = { name, description, cost, isPremium };
|
|
if (isActive !== undefined) {
|
|
updateData.isActive = isActive;
|
|
}
|
|
|
|
const updatedReward = await Reward.update(req.params.id, updateData);
|
|
res.json(updatedReward);
|
|
})
|
|
);
|
|
|
|
// Delete reward
|
|
router.delete(
|
|
"/:id",
|
|
auth,
|
|
rewardIdValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const reward = await Reward.findById(req.params.id);
|
|
if (!reward) {
|
|
return res.status(404).json({ msg: "Reward not found" });
|
|
}
|
|
|
|
await Reward.delete(req.params.id);
|
|
res.json({ msg: "Reward deleted successfully" });
|
|
})
|
|
);
|
|
|
|
// Get active rewards only
|
|
router.get(
|
|
"/active/list",
|
|
asyncHandler(async (req, res) => {
|
|
const rewards = await Reward.getActiveRewards();
|
|
res.json(rewards);
|
|
})
|
|
);
|
|
|
|
// Get premium rewards
|
|
router.get(
|
|
"/premium/list",
|
|
asyncHandler(async (req, res) => {
|
|
const rewards = await Reward.getPremiumRewards();
|
|
res.json(rewards);
|
|
})
|
|
);
|
|
|
|
// Get regular rewards
|
|
router.get(
|
|
"/regular/list",
|
|
asyncHandler(async (req, res) => {
|
|
const rewards = await Reward.getRegularRewards();
|
|
res.json(rewards);
|
|
})
|
|
);
|
|
|
|
// Get rewards by cost range
|
|
router.get(
|
|
"/cost-range/:min/:max",
|
|
asyncHandler(async (req, res) => {
|
|
const { min, max } = req.params;
|
|
const rewards = await Reward.findByCostRange(parseInt(min), parseInt(max));
|
|
res.json(rewards);
|
|
})
|
|
);
|
|
|
|
// Get user's redemption history
|
|
router.get(
|
|
"/redemptions/user/:userId",
|
|
auth,
|
|
asyncHandler(async (req, res) => {
|
|
const { userId } = req.params;
|
|
const { limit = 20 } = req.query;
|
|
|
|
// Only allow users to see their own redemption history
|
|
if (userId !== req.user.id) {
|
|
return res.status(403).json({ msg: "Access denied" });
|
|
}
|
|
|
|
const redemptions = await Reward.getUserRedemptions(userId, parseInt(limit));
|
|
res.json(redemptions);
|
|
})
|
|
);
|
|
|
|
// Get reward statistics
|
|
router.get(
|
|
"/stats/:id",
|
|
rewardIdValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const stats = await Reward.getRewardStats(req.params.id);
|
|
res.json(stats);
|
|
})
|
|
);
|
|
|
|
// Get catalog statistics
|
|
router.get(
|
|
"/catalog/stats",
|
|
auth,
|
|
asyncHandler(async (req, res) => {
|
|
const stats = await Reward.getCatalogStats();
|
|
res.json(stats);
|
|
})
|
|
);
|
|
|
|
// Search rewards
|
|
router.get(
|
|
"/search/:term",
|
|
asyncHandler(async (req, res) => {
|
|
const { term } = req.params;
|
|
const { limit = 20 } = req.query;
|
|
|
|
const rewards = await Reward.searchRewards(term, { limit: parseInt(limit) });
|
|
res.json(rewards);
|
|
})
|
|
);
|
|
|
|
// Toggle reward active status
|
|
router.patch(
|
|
"/:id/toggle",
|
|
auth,
|
|
rewardIdValidation,
|
|
asyncHandler(async (req, res) => {
|
|
const updatedReward = await Reward.toggleActiveStatus(req.params.id);
|
|
res.json(updatedReward);
|
|
})
|
|
);
|
|
|
|
// Bulk create rewards (admin only)
|
|
router.post(
|
|
"/bulk",
|
|
auth,
|
|
asyncHandler(async (req, res) => {
|
|
const { rewards } = req.body;
|
|
|
|
if (!Array.isArray(rewards) || rewards.length === 0) {
|
|
return res.status(400).json({ msg: "Invalid rewards array" });
|
|
}
|
|
|
|
const result = await Reward.bulkCreate(rewards);
|
|
res.json({
|
|
msg: `Created ${result.length} rewards`,
|
|
rewards: result
|
|
});
|
|
})
|
|
);
|
|
|
|
module.exports = router; |