generated from gitea_admin/default
ajout de bouton réserver et ajout du formulaire lycée
This commit is contained in:
163
server/api/projet-lycee.post.js
Normal file
163
server/api/projet-lycee.post.js
Normal file
@@ -0,0 +1,163 @@
|
||||
import { createError, readBody } from "h3"
|
||||
import { getMysqlPool } from "~~/server/utils/mysql"
|
||||
import { sendProjetLyceeEmails } from "~~/server/utils/mailer"
|
||||
|
||||
function normalizeValue(value) {
|
||||
return typeof value === "string" ? value.trim() : ""
|
||||
}
|
||||
|
||||
function normalizePositiveInteger(value) {
|
||||
const number = Number(value)
|
||||
return Number.isInteger(number) && number > 0 ? number : null
|
||||
}
|
||||
|
||||
function normalizePriority(value) {
|
||||
const normalized = normalizeValue(value)
|
||||
if (!normalized) return null
|
||||
|
||||
const match = normalized.match(/_(\d)$/)
|
||||
if (!match) return null
|
||||
|
||||
const priority = Number(match[1])
|
||||
return priority >= 0 && priority <= 4 ? priority : null
|
||||
}
|
||||
|
||||
function isValidEmail(email) {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
|
||||
}
|
||||
|
||||
function withTimeout(promise, delay, message) {
|
||||
return Promise.race([
|
||||
promise,
|
||||
new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error(message)), delay)
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event)
|
||||
|
||||
const payload = {
|
||||
schoolName: normalizeValue(body?.schoolName),
|
||||
department: normalizeValue(body?.department),
|
||||
city: normalizeValue(body?.city),
|
||||
coordinatorName: normalizeValue(body?.coordinatorName),
|
||||
email: normalizeValue(body?.email),
|
||||
phone: normalizeValue(body?.phone),
|
||||
discipline: normalizeValue(body?.discipline),
|
||||
classLevel: normalizeValue(body?.classLevel),
|
||||
studentCount: normalizePositiveInteger(body?.studentCount),
|
||||
concertRencontrePriority: normalizePriority(body?.concertRencontrePriority),
|
||||
immersionPriority: normalizePriority(body?.immersionPriority),
|
||||
eacPriority: normalizePriority(body?.eacPriority),
|
||||
concertCommentePriority: normalizePriority(body?.concertCommentePriority),
|
||||
projectPeriod: normalizeValue(body?.projectPeriod),
|
||||
}
|
||||
|
||||
if (
|
||||
!payload.schoolName ||
|
||||
!payload.department ||
|
||||
!payload.city ||
|
||||
!payload.coordinatorName ||
|
||||
!payload.email ||
|
||||
!payload.phone ||
|
||||
!payload.discipline ||
|
||||
!payload.classLevel ||
|
||||
!payload.studentCount ||
|
||||
!payload.projectPeriod
|
||||
) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Tous les champs obligatoires doivent être remplis.",
|
||||
})
|
||||
}
|
||||
|
||||
if (!isValidEmail(payload.email)) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "L’adresse email n’est pas valide.",
|
||||
})
|
||||
}
|
||||
|
||||
if (!/^\d{2}$/.test(payload.department)) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Le département n’est pas valide.",
|
||||
})
|
||||
}
|
||||
|
||||
if (payload.projectPeriod.length > 5000) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "La période souhaitée est trop longue.",
|
||||
})
|
||||
}
|
||||
|
||||
const db = getMysqlPool()
|
||||
|
||||
try {
|
||||
const [result] = await db.execute(
|
||||
`
|
||||
INSERT INTO projet_lycee_demandes (
|
||||
nom_etablissement,
|
||||
departement,
|
||||
ville,
|
||||
coordinateur_nom,
|
||||
email,
|
||||
telephone,
|
||||
discipline,
|
||||
niveau_classe,
|
||||
nombre_eleves,
|
||||
priorite_concert_rencontre,
|
||||
priorite_immersion,
|
||||
priorite_eac,
|
||||
priorite_concert_commente,
|
||||
periode_souhaitee
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
[
|
||||
payload.schoolName,
|
||||
payload.department,
|
||||
payload.city,
|
||||
payload.coordinatorName,
|
||||
payload.email,
|
||||
payload.phone,
|
||||
payload.discipline,
|
||||
payload.classLevel,
|
||||
payload.studentCount,
|
||||
payload.concertRencontrePriority,
|
||||
payload.immersionPriority,
|
||||
payload.eacPriority,
|
||||
payload.concertCommentePriority,
|
||||
payload.projectPeriod,
|
||||
]
|
||||
)
|
||||
|
||||
let emailsSent = false
|
||||
|
||||
try {
|
||||
emailsSent = await withTimeout(
|
||||
sendProjetLyceeEmails(payload),
|
||||
15000,
|
||||
"Délai dépassé pour l'envoi email projet-lycee."
|
||||
)
|
||||
} catch (mailError) {
|
||||
console.error("Erreur envoi email projet-lycee:", mailError)
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
id: result.insertId,
|
||||
emailsSent,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Erreur API projet-lycee:", error)
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Impossible d’enregistrer la candidature pour le moment.",
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -27,6 +27,9 @@ function getTransporter() {
|
||||
host: config.smtpHost,
|
||||
port: Number(config.smtpPort),
|
||||
secure: String(config.smtpSecure).toLowerCase() === "true",
|
||||
connectionTimeout: 10000,
|
||||
greetingTimeout: 10000,
|
||||
socketTimeout: 15000,
|
||||
auth: {
|
||||
user: config.smtpUser,
|
||||
pass: config.smtpPassword,
|
||||
@@ -96,3 +99,93 @@ export async function sendParcDemandEmails(payload) {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function formatProjetLyceePriority(priority) {
|
||||
if (priority === null || priority === undefined) return "Non renseigné"
|
||||
if (priority === 0) return "Non souhaité"
|
||||
return `Priorité ${priority}`
|
||||
}
|
||||
|
||||
function getProjetLyceeSummary(payload) {
|
||||
const projectWishes = [
|
||||
["Concert-rencontre", payload.concertRencontrePriority],
|
||||
["Parcours Entrer dans la peau d'un professionnel du spectacle", payload.immersionPriority],
|
||||
["Parcours EAC", payload.eacPriority],
|
||||
["Concert commente", payload.concertCommentePriority],
|
||||
]
|
||||
.filter(([, priority]) => priority >= 1 && priority <= 4)
|
||||
.map(([label, priority]) => `${label} : ${formatProjetLyceePriority(priority)}`)
|
||||
|
||||
return [
|
||||
`Etablissement scolaire : ${payload.schoolName}`,
|
||||
`Departement : ${payload.department}`,
|
||||
`Ville : ${payload.city}`,
|
||||
`Enseignant coordinateur : ${payload.coordinatorName}`,
|
||||
`Email : ${payload.email}`,
|
||||
`Telephone : ${payload.phone}`,
|
||||
`Discipline enseignee : ${payload.discipline}`,
|
||||
`Niveau de classe : ${payload.classLevel}`,
|
||||
`Nombre probable d'eleves concernes : ${payload.studentCount}`,
|
||||
...(projectWishes.length ? ["", "Souhaits de projet :", ...projectWishes] : []),
|
||||
"",
|
||||
"Periode souhaitee :",
|
||||
payload.projectPeriod,
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
export async function sendProjetLyceeEmails(payload) {
|
||||
const config = useRuntimeConfig()
|
||||
const mailer = getTransporter()
|
||||
|
||||
if (!mailer) {
|
||||
console.warn("Email projet lycée non envoyé: configuration SMTP incomplète.")
|
||||
return false
|
||||
}
|
||||
|
||||
if (!config.scolaireRequestRecipientEmail) {
|
||||
console.warn("Email projet lycée non envoyé: destinataire scolaire manquant.")
|
||||
return false
|
||||
}
|
||||
|
||||
const from = config.smtpFromName
|
||||
? `"${config.smtpFromName}" <${config.smtpFromEmail}>`
|
||||
: config.smtpFromEmail
|
||||
|
||||
const summary = getProjetLyceeSummary(payload)
|
||||
|
||||
const adminSubject = `WONDIF - Candidature projet lycee - ${payload.schoolName}`
|
||||
const adminText = [
|
||||
"Une nouvelle candidature a été envoyée depuis le formulaire Projet lycée.",
|
||||
"",
|
||||
summary,
|
||||
].join("\n")
|
||||
|
||||
const userSubject = "ONDIF - Confirmation de votre candidature - Projet lycée"
|
||||
const userText = [
|
||||
`Bonjour ${payload.coordinatorName},`,
|
||||
"",
|
||||
"Votre candidature à un projet avec l'Orchestre national d'Île-de-France a bien été transmise.",
|
||||
"L'équipe d'action culturelle reviendra vers vous d'ici fin juin 2026 afin de vous informer de la suite donnée à votre candidature.",
|
||||
"",
|
||||
"Recapitulatif :",
|
||||
summary,
|
||||
].join("\n")
|
||||
|
||||
await Promise.all([
|
||||
mailer.sendMail({
|
||||
from,
|
||||
to: config.scolaireRequestRecipientEmail,
|
||||
replyTo: payload.email,
|
||||
subject: adminSubject,
|
||||
text: adminText,
|
||||
}),
|
||||
mailer.sendMail({
|
||||
from,
|
||||
to: payload.email,
|
||||
subject: userSubject,
|
||||
text: userText,
|
||||
}),
|
||||
])
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user