Admin interface to review, filter, and batch-invite the 95 pre-registrants from Baby Ghosts. Accept-invitation page pre-fills their data and collects circle, pronouns, motivation, contribution tier, and agreement before creating their member record.
46 lines
1.4 KiB
JavaScript
46 lines
1.4 KiB
JavaScript
import jwt from 'jsonwebtoken'
|
|
import PreRegistration from '../../models/preRegistration.js'
|
|
import { connectDB } from '../../utils/mongoose.js'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const { token } = await validateBody(event, inviteVerifySchema)
|
|
const config = useRuntimeConfig(event)
|
|
await connectDB()
|
|
|
|
let decoded
|
|
try {
|
|
decoded = jwt.verify(token, config.jwtSecret)
|
|
} catch {
|
|
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
|
|
}
|
|
|
|
if (decoded.type !== 'prereg-invite') {
|
|
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
|
|
}
|
|
|
|
const preReg = await PreRegistration.findById(decoded.preRegistrationId)
|
|
if (!preReg) {
|
|
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
|
|
}
|
|
|
|
if (preReg.status === 'accepted') {
|
|
throw createError({ statusCode: 400, statusMessage: 'This invitation has already been accepted' })
|
|
}
|
|
|
|
// Single-use enforcement
|
|
if (!decoded.jti || decoded.jti !== preReg.magicLinkJti || preReg.magicLinkJtiUsed) {
|
|
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
|
|
}
|
|
|
|
// Burn the token
|
|
await PreRegistration.findByIdAndUpdate(preReg._id, {
|
|
$set: { magicLinkJtiUsed: true }
|
|
})
|
|
|
|
return {
|
|
preRegistrationId: preReg._id,
|
|
name: preReg.name,
|
|
email: preReg.email,
|
|
city: preReg.city,
|
|
}
|
|
})
|