import { Request, Response } from 'express'; import Event, { IEvent } from '../models/Event'; import mongoose from 'mongoose'; /** * Get all events with optional filtering */ export const getEvents = async (req: Request, res: Response) => { try { const { status, category, search, startDate, endDate, page = 1, limit = 10 } = req.query; // Build query const query: any = {}; // Filter by status if provided if (status && status !== 'all') { query.status = status; } // Filter by category if provided if (category && category !== 'all') { query.category = category; } // Filter by date range if provided if (startDate || endDate) { query.date = {}; if (startDate) { query.date.$gte = new Date(startDate as string); } if (endDate) { query.date.$lte = new Date(endDate as string); } } // Text search if provided if (search) { query.$text = { $search: search as string }; } // Calculate pagination const skip = ((Number(page) || 1) - 1) * (Number(limit) || 10); // Execute query with pagination const events = await Event.find(query) .sort({ date: 1 }) // Sort by date ascending .skip(skip) .limit(Number(limit)); // Get total count for pagination const total = await Event.countDocuments(query); return res.status(200).json({ events, pagination: { total, page: Number(page), limit: Number(limit), pages: Math.ceil(total / Number(limit)) } }); } catch (error) { console.error('Error fetching events:', error); return res.status(500).json({ error: { message: 'Failed to fetch events' } }); } }; /** * Get a single event by ID */ export const getEventById = async (req: Request, res: Response) => { try { const { id } = req.params; // Validate ID format if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: { message: 'Invalid event ID format' } }); } // Find event const event = await Event.findById(id); // Check if event exists if (!event) { return res.status(404).json({ error: { message: 'Event not found' } }); } return res.status(200).json({ event }); } catch (error) { console.error('Error fetching event:', error); return res.status(500).json({ error: { message: 'Failed to fetch event' } }); } }; /** * Create a new event */ export const createEvent = async (req: Request, res: Response) => { try { const { title, description, date, time, location, category, status, registrationRequired, maxAttendees, recurring, recurrencePattern, tags } = req.body; // Create new event const event = new Event({ title, description, date, time, location, category, status: status || 'draft', registrationRequired: registrationRequired || false, registeredCount: 0, maxAttendees, recurring: recurring || false, recurrencePattern, tags }); // Save event to database await event.save(); return res.status(201).json({ message: 'Event created successfully', event }); } catch (error) { console.error('Error creating event:', error); // Handle validation errors if (error instanceof mongoose.Error.ValidationError) { return res.status(400).json({ error: { message: 'Validation error', details: error.errors } }); } return res.status(500).json({ error: { message: 'Failed to create event' } }); } }; /** * Update an existing event */ export const updateEvent = async (req: Request, res: Response) => { try { const { id } = req.params; const updateData = req.body; // Validate ID format if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: { message: 'Invalid event ID format' } }); } // Find and update event const event = await Event.findByIdAndUpdate( id, updateData, { new: true, runValidators: true } ); // Check if event exists if (!event) { return res.status(404).json({ error: { message: 'Event not found' } }); } return res.status(200).json({ message: 'Event updated successfully', event }); } catch (error) { console.error('Error updating event:', error); // Handle validation errors if (error instanceof mongoose.Error.ValidationError) { return res.status(400).json({ error: { message: 'Validation error', details: error.errors } }); } return res.status(500).json({ error: { message: 'Failed to update event' } }); } }; /** * Delete an event */ export const deleteEvent = async (req: Request, res: Response) => { try { const { id } = req.params; // Validate ID format if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: { message: 'Invalid event ID format' } }); } // Find and delete event const event = await Event.findByIdAndDelete(id); // Check if event exists if (!event) { return res.status(404).json({ error: { message: 'Event not found' } }); } return res.status(200).json({ message: 'Event deleted successfully' }); } catch (error) { console.error('Error deleting event:', error); return res.status(500).json({ error: { message: 'Failed to delete event' } }); } }; /** * Register for an event */ export const registerForEvent = async (req: Request, res: Response) => { try { const { id } = req.params; const { userId } = req.body; // Validate ID format if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: { message: 'Invalid event ID format' } }); } // Find event const event = await Event.findById(id); // Check if event exists if (!event) { return res.status(404).json({ error: { message: 'Event not found' } }); } // Check if registration is required if (!event.registrationRequired) { return res.status(400).json({ error: { message: 'Registration is not required for this event' } }); } // Check if event is at capacity if (event.maxAttendees && event.registeredCount >= event.maxAttendees) { return res.status(400).json({ error: { message: 'Event is at full capacity' } }); } // Increment registered count event.registeredCount += 1; await event.save(); // TODO: In a real implementation, we would also save the user's registration // in a separate EventRegistration collection return res.status(200).json({ message: 'Successfully registered for event', event }); } catch (error) { console.error('Error registering for event:', error); return res.status(500).json({ error: { message: 'Failed to register for event' } }); } }; /** * Cancel registration for an event */ export const cancelRegistration = async (req: Request, res: Response) => { try { const { id } = req.params; const { userId } = req.body; // Validate ID format if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: { message: 'Invalid event ID format' } }); } // Find event const event = await Event.findById(id); // Check if event exists if (!event) { return res.status(404).json({ error: { message: 'Event not found' } }); } // Check if registration is required if (!event.registrationRequired) { return res.status(400).json({ error: { message: 'Registration is not required for this event' } }); } // Decrement registered count (ensure it doesn't go below 0) if (event.registeredCount > 0) { event.registeredCount -= 1; await event.save(); } // TODO: In a real implementation, we would also remove the user's registration // from a separate EventRegistration collection return res.status(200).json({ message: 'Successfully cancelled registration', event }); } catch (error) { console.error('Error cancelling registration:', error); return res.status(500).json({ error: { message: 'Failed to cancel registration' } }); } };