Create central dashboard with statistics and quick actions Build events management with filtering and CRUD UI Implement members management with bulk actions Develop video management with accessibility indicators Add document repository with visibility controls Create content management with WYSIWYG editor Add settings interface for site configuration Additional improvements: Implement full Events Management System with CRUD Enhance frontend architecture with TypeScript Improve accessibility in navigation menu Add comprehensive test suite for Events API
410 lines
8.8 KiB
TypeScript
410 lines
8.8 KiB
TypeScript
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'
|
|
}
|
|
});
|
|
}
|
|
};
|