283 lines
6.7 KiB
TypeScript
283 lines
6.7 KiB
TypeScript
import { HttpStatusCode } from '@peertube/peertube-models'
|
|
import { isIdValid } from '@server/helpers/custom-validators/misc.js'
|
|
import { EventRegistrationModel } from '@server/models/video/event-registration.js'
|
|
import { EventModel } from '@server/models/video/event.js'
|
|
import { VideoChannelModel } from '@server/models/video/video-channel.js'
|
|
import express from 'express'
|
|
import { body, param } from 'express-validator'
|
|
import { areValidationErrors } from './shared/utils.js'
|
|
|
|
const phoneRegexp = /^[0-9+()\-\s]{7,20}$/
|
|
|
|
const requiredRegistrationFields = [
|
|
body('firstName')
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('First name is required'),
|
|
|
|
body('lastName')
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('Last name is required'),
|
|
|
|
body('email')
|
|
.trim()
|
|
.isEmail()
|
|
.withMessage('Email must be valid')
|
|
.bail()
|
|
.normalizeEmail(),
|
|
|
|
body('phone')
|
|
.trim()
|
|
.matches(phoneRegexp)
|
|
.withMessage('Phone must be valid'),
|
|
|
|
body('companyName')
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('Company name is required'),
|
|
|
|
body('jobTitle')
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('Job title is required'),
|
|
|
|
body('country')
|
|
.trim()
|
|
.isLength({ min: 2, max: 100 })
|
|
.withMessage('Country must be between 2 and 100 characters')
|
|
]
|
|
|
|
const optionalRegistrationFields = [
|
|
body('firstName')
|
|
.optional()
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('First name cannot be empty'),
|
|
|
|
body('lastName')
|
|
.optional()
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('Last name cannot be empty'),
|
|
|
|
body('email')
|
|
.optional()
|
|
.trim()
|
|
.isEmail()
|
|
.withMessage('Email must be valid')
|
|
.bail()
|
|
.normalizeEmail(),
|
|
|
|
body('phone')
|
|
.optional()
|
|
.trim()
|
|
.matches(phoneRegexp)
|
|
.withMessage('Phone must be valid'),
|
|
|
|
body('companyName')
|
|
.optional()
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('Company name cannot be empty'),
|
|
|
|
body('jobTitle')
|
|
.optional()
|
|
.trim()
|
|
.notEmpty()
|
|
.withMessage('Job title cannot be empty'),
|
|
|
|
body('country')
|
|
.optional()
|
|
.trim()
|
|
.isLength({ min: 2, max: 100 })
|
|
.withMessage('Country must be between 2 and 100 characters')
|
|
]
|
|
|
|
async function loadEventWithChannel (eventId: number) {
|
|
return EventModel.findByPk(eventId, {
|
|
include: [
|
|
{
|
|
model: VideoChannelModel.scope([ 'WITH_ACCOUNT' ]),
|
|
required: true
|
|
}
|
|
]
|
|
})
|
|
}
|
|
|
|
export const createEventRegistrationValidator = [
|
|
param('eventId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid event id'),
|
|
|
|
...requiredRegistrationFields,
|
|
|
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
if (areValidationErrors(req, res)) return
|
|
|
|
const eventId = parseInt(req.params.eventId)
|
|
const event = await loadEventWithChannel(eventId)
|
|
|
|
if (!event) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Event not found'
|
|
})
|
|
}
|
|
|
|
const resLocals = res.locals as any
|
|
resLocals.event = event
|
|
|
|
return next()
|
|
}
|
|
]
|
|
|
|
export const listEventRegistrationsValidator = [
|
|
param('eventId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid event id'),
|
|
|
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
if (areValidationErrors(req, res)) return
|
|
|
|
const event = await loadEventWithChannel(parseInt(req.params.eventId))
|
|
|
|
if (!event) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Event not found'
|
|
})
|
|
}
|
|
|
|
const resLocals = res.locals as any
|
|
resLocals.event = event
|
|
|
|
return next()
|
|
}
|
|
]
|
|
|
|
export const getEventRegistrationValidator = [
|
|
param('eventId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid event id'),
|
|
|
|
param('registrationId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid registration id'),
|
|
|
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
if (areValidationErrors(req, res)) return
|
|
|
|
const eventId = parseInt(req.params.eventId)
|
|
const registrationId = parseInt(req.params.registrationId)
|
|
const [ event, registration ] = await Promise.all([
|
|
loadEventWithChannel(eventId),
|
|
EventRegistrationModel.loadByIdAndEventId(registrationId, eventId)
|
|
])
|
|
|
|
if (!event) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Event not found'
|
|
})
|
|
}
|
|
|
|
if (!registration) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Registration not found'
|
|
})
|
|
}
|
|
|
|
const resLocals = res.locals as any
|
|
resLocals.event = event
|
|
resLocals.eventRegistration = registration
|
|
|
|
return next()
|
|
}
|
|
]
|
|
|
|
export const updateEventRegistrationValidator = [
|
|
param('eventId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid event id'),
|
|
|
|
param('registrationId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid registration id'),
|
|
|
|
...optionalRegistrationFields,
|
|
|
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
if (areValidationErrors(req, res)) return
|
|
|
|
const eventId = parseInt(req.params.eventId)
|
|
const registrationId = parseInt(req.params.registrationId)
|
|
const [ event, registration ] = await Promise.all([
|
|
loadEventWithChannel(eventId),
|
|
EventRegistrationModel.loadByIdAndEventId(registrationId, eventId)
|
|
])
|
|
|
|
if (!event) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Event not found'
|
|
})
|
|
}
|
|
|
|
if (!registration) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Registration not found'
|
|
})
|
|
}
|
|
|
|
const resLocals = res.locals as any
|
|
resLocals.event = event
|
|
resLocals.eventRegistration = registration
|
|
|
|
return next()
|
|
}
|
|
]
|
|
|
|
export const deleteEventRegistrationValidator = [
|
|
param('eventId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid event id'),
|
|
|
|
param('registrationId')
|
|
.custom(isIdValid)
|
|
.withMessage('Invalid registration id'),
|
|
|
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
if (areValidationErrors(req, res)) return
|
|
|
|
const eventId = parseInt(req.params.eventId)
|
|
const registrationId = parseInt(req.params.registrationId)
|
|
const [ event, registration ] = await Promise.all([
|
|
loadEventWithChannel(eventId),
|
|
EventRegistrationModel.loadByIdAndEventId(registrationId, eventId)
|
|
])
|
|
|
|
if (!event) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Event not found'
|
|
})
|
|
}
|
|
|
|
if (!registration) {
|
|
return res.fail({
|
|
status: HttpStatusCode.NOT_FOUND_404,
|
|
message: 'Registration not found'
|
|
})
|
|
}
|
|
|
|
const resLocals = res.locals as any
|
|
resLocals.event = event
|
|
resLocals.eventRegistration = registration
|
|
|
|
return next()
|
|
}
|
|
]
|