import Event from "../../../models/event.js"; import Member from "../../../models/member.js"; import { connectDB } from "../../../utils/mongoose.js"; import { sendEventRegistrationEmail } from "../../../utils/resend.js"; import { validateBody } from "../../../utils/validateBody.js"; import { eventRegistrationSchema } from "../../../utils/schemas.js"; import { hasMemberAccess } from "../../../utils/tickets.js"; import mongoose from "mongoose"; export default defineEventHandler(async (event) => { try { // Ensure database connection await connectDB(); const identifier = getRouterParam(event, "id"); const body = await validateBody(event, eventRegistrationSchema); if (!identifier) { throw createError({ statusCode: 400, statusMessage: "Event identifier is required", }); } // Fetch the event - try by slug first, then by ID let eventData; // Check if identifier is a valid MongoDB ObjectId if (mongoose.Types.ObjectId.isValid(identifier)) { eventData = await Event.findById(identifier); } // If not found by ID or not a valid ObjectId, try by slug if (!eventData) { eventData = await Event.findOne({ slug: identifier }); } if (!eventData) { throw createError({ statusCode: 404, statusMessage: "Event not found", }); } // Check if event is full if ( eventData.maxAttendees && eventData.registrations.length >= eventData.maxAttendees ) { throw createError({ statusCode: 400, statusMessage: "Event is full", }); } // Check if already registered const alreadyRegistered = eventData.registrations.some( (reg) => reg.email.toLowerCase() === body.email.toLowerCase(), ); if (alreadyRegistered) { throw createError({ statusCode: 400, statusMessage: "You are already registered for this event", }); } // Check member status and handle different registration scenarios. // Member access is decoupled from payment status: active and pending_payment // both confer access; guest, suspended, and cancelled do not. const member = await Member.findOne({ email: body.email.toLowerCase() }); const memberHasAccess = hasMemberAccess(member); if (eventData.membersOnly && !memberHasAccess) { throw createError({ statusCode: 403, statusMessage: "This event is for members only. Please become a member to register.", }); } // If event requires payment and user is not a member, redirect to payment flow if ( eventData.pricing?.paymentRequired && !eventData.pricing?.isFree && !memberHasAccess ) { throw createError({ statusCode: 402, // Payment Required statusMessage: "This event requires payment. Please use the payment registration endpoint.", }); } // Set member status and membership level let isMember = false; let membershipLevel = "non-member"; if (memberHasAccess) { isMember = true; membershipLevel = `${member.circle}-${member.contributionTier}`; } // Add registration const registration = { memberId: member ? member._id : null, name: body.name, email: body.email.toLowerCase(), membershipLevel, isMember, paymentStatus: "not_required", // Free events or member registrations amountPaid: 0, dietary: body.dietary || false, registeredAt: new Date(), }; // Use $push to avoid re-validating the whole document (e.g. legacy location formats) const result = await Event.findByIdAndUpdate( eventData._id, { $push: { registrations: registration } }, { new: true, runValidators: false }, ); const newRegistration = result.registrations[result.registrations.length - 1]; // Log activity if (member) { logActivity(member._id, 'event_registered', { eventId: eventData._id, eventTitle: eventData.title, eventSlug: eventData.slug }) } // Send confirmation email — respect member notification preferences const shouldSendEventEmail = !member || member.notifications?.events !== false; if (shouldSendEventEmail) { try { await sendEventRegistrationEmail(registration, eventData); if (member) { logActivity(member._id, 'email_sent', { emailType: 'event_registration', subject: `You're registered for ${eventData.title}` }) } } catch (emailError) { console.error("Failed to send confirmation email:", emailError); } } return { success: true, message: "Successfully registered for the event", registrationId: newRegistration._id, }; } catch (error) { console.error("Error registering for event:", error); if (error.statusCode) { throw error; } throw createError({ statusCode: 500, statusMessage: "Failed to register for event", }); } });