CampVerse CI
Deploy backend from GitHub Actions
4234229
Raw History Blame Contribute Delete
7.54 kB
const mongoose = require('mongoose');
const Event = require('../Models/Event');
const User = require('../Models/User');
const EventParticipationLog = require('../Models/EventParticipationLog');
const { asyncHandler } = require('../Middleware/errorHandler');
// Host dashboard: list events and detailed analytics
const getHostDashboard = asyncHandler(async (req, res) => {
const userId = req.user.id;
// Optimized: Use a single aggregation pipeline to fetch events and their analytics
const eventsWithAnalytics = await Event.aggregate([
{ $match: { hostUserId: new mongoose.Types.ObjectId(userId) } },
{
$lookup: {
from: 'eventparticipationlogs',
localField: '_id',
foreignField: 'eventId',
as: 'logs'
}
},
{
$project: {
title: 1,
date: 1,
location: 1,
status: 1,
capacity: 1,
type: 1,
isPaid: 1,
price: 1,
bannerURL: 1,
logoURL: 1,
verificationStatus: 1,
createdAt: 1,
updatedAt: 1,
analytics: {
totalRegistered: { $size: '$logs' },
totalAttended: {
$size: {
$filter: {
input: '$logs',
as: 'log',
cond: { $eq: ['$$log.status', 'attended'] }
}
}
},
totalWaitlisted: {
$size: {
$filter: {
input: '$logs',
as: 'log',
cond: { $eq: ['$$log.status', 'waitlisted'] }
}
}
},
totalPaid: {
$size: {
$filter: {
input: '$logs',
as: 'log',
cond: { $eq: ['$$log.paymentType', 'paid'] }
}
}
},
totalFree: {
$size: {
$filter: {
input: '$logs',
as: 'log',
cond: { $eq: ['$$log.paymentType', 'free'] }
}
}
}
}
}
},
{
$addFields: {
'analytics.attendanceRate': {
$cond: [
{ $gt: ['$analytics.totalRegistered', 0] },
{
$multiply: [
{ $divide: ['$analytics.totalAttended', '$analytics.totalRegistered'] },
100
]
},
0
]
}
}
}
]);
const totalEvents = eventsWithAnalytics.length;
const totalParticipants = eventsWithAnalytics.reduce(
(sum, e) => sum + e.analytics.totalRegistered,
0,
);
const totalAttendedCount = eventsWithAnalytics.reduce(
(sum, e) => sum + e.analytics.totalAttended,
0,
);
const upcomingEventsCount = eventsWithAnalytics.filter(
(e) => e.date && new Date(e.date) > new Date()
).length;
// Formatting attendanceRate to string as per original implementation
eventsWithAnalytics.forEach(event => {
event.analytics.attendanceRate = event.analytics.attendanceRate.toFixed(2);
});
return res.json({
totalEvents,
totalParticipants,
totalAttended: totalAttendedCount,
upcomingEvents: upcomingEventsCount,
events: eventsWithAnalytics,
});
});
// Create a new event (host only)
const createEvent = asyncHandler(async (req, res) => {
const userId = req.user.id;
const eventData = req.body;
eventData.hostUserId = userId;
const event = await Event.create(eventData);
// Optionally add event to user's eventHistory.hosted
await User.findByIdAndUpdate(userId, {
$push: { 'eventHistory.hosted': event._id },
});
return res.status(201).json(event);
});
// Update an event (host only)
const updateEvent = asyncHandler(async (req, res) => {
const userId = req.user.id;
const eventId = req.params.id;
const event = await Event.findOne({ _id: eventId, hostUserId: userId });
if (!event)
return res
.status(404)
.json({ error: 'Event not found or not owned by user.' });
// Whitelist allow-able fields
const allowedUpdates = [
'title', 'description', 'type', 'organizationName',
'location', 'capacity', 'date', 'isPaid', 'price',
'tags', 'requirements', 'audienceType', 'features',
'sessions', 'about', 'socialLinks'
];
allowedUpdates.forEach((field) => {
if (req.body[field] !== undefined) {
event[field] = req.body[field];
}
});
// Handle special cases safely if needed (e.g. nested objects)
// For now, the direct assignment works for top-level schema fields.
await event.save();
return res.json(event);
});
// Delete an event (host only)
const deleteEvent = asyncHandler(async (req, res) => {
const userId = req.user.id;
const eventId = req.params.id;
const event = await Event.findOneAndDelete({
_id: eventId,
hostUserId: userId,
});
if (!event)
return res
.status(404)
.json({ error: 'Event not found or not owned by user.' });
// Optionally remove from user's eventHistory.hosted
await User.findByIdAndUpdate(userId, {
$pull: { 'eventHistory.hosted': eventId },
});
return res.json({ message: 'Event deleted.' });
});
// List all events hosted by the current user
const getMyEvents = asyncHandler(async (req, res) => {
const userId = req.user.id;
const events = await Event.find({
$or: [
{ hostUserId: userId },
{ coHosts: userId }
]
}).lean();
const eventIds = events.map(e => e._id);
const logs = await EventParticipationLog.find({ eventId: { $in: eventIds } }).lean();
const users = await User.find({ _id: { $in: logs.map(l => l.userId) } }).lean();
const userMap = {};
users.forEach(u => { userMap[u._id.toString()] = u; });
const eventParticipantsMap = {};
logs.forEach(log => {
if (!eventParticipantsMap[log.eventId]) eventParticipantsMap[log.eventId] = [];
eventParticipantsMap[log.eventId].push({
userId: log.userId,
name: userMap[log.userId.toString()]?.name,
email: userMap[log.userId.toString()]?.email,
phone: userMap[log.userId.toString()]?.phone,
status: log.status,
paymentType: log.paymentType,
paymentStatus: log.paymentStatus,
attendanceTimestamp: log.attendanceTimestamp,
timestamp: log.timestamp,
});
});
const eventsWithParticipants = events.map(event => ({
...event,
participants: eventParticipantsMap[event._id] || []
}));
return res.json(eventsWithParticipants);
});
// Get participants for a given event (host only)
const getEventParticipants = asyncHandler(async (req, res) => {
const userId = req.user.id;
const eventId = req.params.id;
const event = await Event.findOne({ _id: eventId, hostUserId: userId });
if (!event)
return res
.status(404)
.json({ error: 'Event not found or not owned by user.' });
// Get detailed participant information from EventParticipationLog
const logs = await EventParticipationLog.find({ eventId }).populate(
'userId',
'name email phone',
);
const participants = logs.map((log) => ({
userId: log.userId._id,
name: log.userId.name,
email: log.userId.email,
phone: log.userId.phone,
status: log.status,
paymentType: log.paymentType,
paymentStatus: log.paymentStatus,
attendanceTimestamp: log.attendanceTimestamp,
timestamp: log.timestamp,
}));
return res.json({ participants });
});
module.exports = {
getHostDashboard,
createEvent,
updateEvent,
deleteEvent,
getMyEvents,
getEventParticipants,
};