From 9e06181f37ee3155cca0015035450e77adac959f Mon Sep 17 00:00:00 2001 From: Javaxman Date: Wed, 29 Jul 2026 17:01:44 +0200 Subject: [PATCH] Mostra errori utente generici sul form contatti. I dettagli di configurazione restano solo nei log Worker, non sulla landing. Co-authored-by: Cursor --- src/pages/api/contact.ts | 71 ++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/src/pages/api/contact.ts b/src/pages/api/contact.ts index 8b7ce17..6bd9d57 100644 --- a/src/pages/api/contact.ts +++ b/src/pages/api/contact.ts @@ -37,6 +37,9 @@ function wantsJson(request: Request): boolean { return (request.headers.get('Accept') || '').includes('application/json'); } +const USER_SEND_ERROR = + 'Impossibile inviare il messaggio in questo momento. Riprova più tardi.'; + function fail(request: Request, message: string, status: number): Response { if (wantsJson(request)) { return Response.json({ ok: false, error: message }, { status }); @@ -51,38 +54,21 @@ function succeed(request: Request, redirectTarget: string): Response { return Response.redirect(redirectTarget, 303); } -function emailErrorMessage(error: unknown): string { - const code = - error && typeof error === 'object' && 'code' in error - ? String((error as { code?: unknown }).code || '') - : ''; - const message = - error instanceof Error - ? error.message - : error && typeof error === 'object' && 'message' in error - ? String((error as { message?: unknown }).message || '') - : ''; +function emailErrorCode(error: unknown): string { + if (error && typeof error === 'object' && 'code' in error) { + return String((error as { code?: unknown }).code || ''); + } + return ''; +} +function userEmailErrorMessage(error: unknown): string { + const code = emailErrorCode(error); switch (code) { - case 'E_SENDER_NOT_VERIFIED': - case 'E_SENDER_DOMAIN_NOT_AVAILABLE': - return 'Dominio mittente non verificato su Cloudflare Email Service.'; - case 'E_RECIPIENT_NOT_ALLOWED': - return 'Destinatario non autorizzato dal binding email.'; - case 'E_RECIPIENT_SUPPRESSED': - return 'Destinatario in lista di soppressione (bounce/spam).'; case 'E_RATE_LIMIT_EXCEEDED': case 'E_DAILY_LIMIT_EXCEEDED': - return 'Limite di invio email raggiunto. Riprova più tardi.'; - case 'E_VALIDATION_ERROR': - case 'E_FIELD_MISSING': - return message - ? `Dati email non validi: ${message}` - : 'Dati email non validi.'; + return 'Troppe richieste al momento. Riprova tra poco.'; default: - return code - ? `Invio email non riuscito (${code}). Riprova più tardi.` - : 'Invio email non riuscito. Riprova più tardi.'; + return USER_SEND_ERROR; } } @@ -146,7 +132,7 @@ export const POST: APIRoute = async ({ request, url }) => { const message = required(form.get('message')); if (!name || !email || !country || !message) { - return fail(request, 'Missing required contact fields.', 400); + return fail(request, 'Compila tutti i campi obbligatori.', 400); } const turnstileToken = required(form.get('cf-turnstile-response')); @@ -157,7 +143,11 @@ export const POST: APIRoute = async ({ request, url }) => { request.headers.get('CF-Connecting-IP'), ); if (!isHuman) { - return fail(request, 'Turnstile verification failed.', 400); + return fail( + request, + 'Completa il controllo anti-spam e riprova.', + 400, + ); } } @@ -179,18 +169,16 @@ export const POST: APIRoute = async ({ request, url }) => { if (!emailBinding || !fromEmail || !toEmail) { const missing = [ !emailBinding ? 'EMAIL binding' : '', - !fromEmail ? 'CONTACT_FORM_FROM_EMAIL (o NEWSLETTER_FROM_EMAIL)' : '', - !toEmail ? 'CONTACT_FORM_TO_EMAIL (o NEWSLETTER_NOTIFY_TO_EMAIL)' : '', + !fromEmail ? 'CONTACT_FORM_FROM_EMAIL|NEWSLETTER_FROM_EMAIL' : '', + !toEmail ? 'CONTACT_FORM_TO_EMAIL|NEWSLETTER_NOTIFY_TO_EMAIL' : '', ].filter(Boolean); - return fail( - request, - `Config email incompleta: manca ${missing.join(', ')}. Imposta le variabili runtime del Worker (Settings → Variables and Secrets), non Build.`, - 500, - ); + console.error('[contact] incomplete email config', { missing }); + return fail(request, USER_SEND_ERROR, 500); } const destination = resolveDepartmentRecipient(runtimeEnv, toEmail, department); if (!destination) { - return fail(request, 'Nessun destinatario configurato per il reparto selezionato.', 500); + console.error('[contact] empty department recipient', { department }); + return fail(request, USER_SEND_ERROR, 500); } try { @@ -212,8 +200,11 @@ export const POST: APIRoute = async ({ request, url }) => { text, }); } catch (retryError) { - console.error('[contact] email retry failed', retryError); - return fail(request, emailErrorMessage(retryError), 502); + console.error('[contact] email retry failed', { + code: emailErrorCode(retryError), + error: retryError, + }); + return fail(request, userEmailErrorMessage(retryError), 502); } } } else { @@ -230,6 +221,6 @@ export const POST: APIRoute = async ({ request, url }) => { return succeed(request, redirectTarget); } catch (error) { console.error('[contact] unexpected error', error); - return fail(request, 'Errore interno. Riprova più tardi.', 500); + return fail(request, USER_SEND_ERROR, 500); } }; -- 2.49.0