Files
nav-carte/server/api/report-general.post.ts
2026-04-28 14:00:05 +02:00

95 lines
3.1 KiB
TypeScript

/**
* POST /api/report-general
*
* Signalement général (bug, contenu inapproprié, suggestion)
*
* Body : { category: string, description: string, email?: string }
* Rate limit : 5/IP/jour
* Envoi vers jules@trans-former.fr via Resend API
*/
import { checkRateLimitJson } from '~/server/utils/rateLimitJson'
const EMAIL_JULES = process.env.EMAIL_JULES || 'jules@trans-former.fr'
const VALID_CATEGORIES = ['Une fiche', 'Le chatbot', 'La carte', 'Autre'] as const
export default defineEventHandler(async (event) => {
// 1. IP
const ip =
getHeader(event, 'x-forwarded-for')?.split(',')[0].trim() ||
event.node.req.socket?.remoteAddress ||
'0.0.0.0'
// 2. Rate limit 5/IP/jour
const allowed = checkRateLimitJson(ip, 'report-general', 5)
if (!allowed) {
throw createError({
statusCode: 429,
statusMessage: 'Limite de 5 signalements par jour atteinte.',
})
}
// 3. Lire le body
const body = await readBody(event)
const category: string = (body?.category ?? '').trim()
const description: string = (body?.description ?? '').trim()
const email: string = (body?.email ?? '').trim()
// 4. Validation
if (!VALID_CATEGORIES.includes(category as any)) {
throw createError({ statusCode: 400, statusMessage: 'Catégorie invalide.' })
}
if (!description || description.length < 5 || description.length > 500) {
throw createError({ statusCode: 400, statusMessage: 'Description requise (5-500 caractères).' })
}
if (email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(email)) {
throw createError({ statusCode: 400, statusMessage: 'Email invalide.' })
}
}
// 5. Envoi via Resend
const resendApiKey = process.env.RESEND_API_KEY
if (!resendApiKey) {
console.error('[report-general] RESEND_API_KEY manquante')
throw createError({ statusCode: 500, statusMessage: 'Configuration email manquante.' })
}
const submittedAt = new Date().toLocaleString('fr-FR', { timeZone: 'Europe/Paris' })
try {
await $fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${resendApiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'AEP Signalement <noreply@trans-former.fr>',
to: EMAIL_JULES,
subject: `[AEP] Signalement — ${category}`,
html: `
<h2>Signalement AEP — ${category}</h2>
<p><strong>Date :</strong> ${submittedAt}</p>
<p><strong>Catégorie :</strong> ${category}</p>
${email ? `<p><strong>Email expéditeur :</strong> ${email}</p>` : '<p><em>Pas d\'email fourni</em></p>'}
<p><strong>Description :</strong></p>
<blockquote style="border-left:3px solid #ccc;padding-left:12px;color:#555;">
${description.replace(/\n/g, '<br/>')}
</blockquote>
`,
}),
})
} catch (e: any) {
console.error('[report-general] Erreur Resend:', e?.message ?? e)
throw createError({
statusCode: 502,
statusMessage: 'Erreur envoi email — réessaie dans quelques instants.',
})
}
return { ok: true, message: 'Signalement envoyé, merci !' }
})