Mostra errori utente generici sul form contatti. (#22)
I dettagli di configurazione restano solo nei log Worker, non sulla landing. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -37,6 +37,9 @@ function wantsJson(request: Request): boolean {
|
|||||||
return (request.headers.get('Accept') || '').includes('application/json');
|
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 {
|
function fail(request: Request, message: string, status: number): Response {
|
||||||
if (wantsJson(request)) {
|
if (wantsJson(request)) {
|
||||||
return Response.json({ ok: false, error: message }, { status });
|
return Response.json({ ok: false, error: message }, { status });
|
||||||
@ -51,38 +54,21 @@ function succeed(request: Request, redirectTarget: string): Response {
|
|||||||
return Response.redirect(redirectTarget, 303);
|
return Response.redirect(redirectTarget, 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
function emailErrorMessage(error: unknown): string {
|
function emailErrorCode(error: unknown): string {
|
||||||
const code =
|
if (error && typeof error === 'object' && 'code' in error) {
|
||||||
error && typeof error === 'object' && 'code' in error
|
return String((error as { code?: unknown }).code || '');
|
||||||
? String((error as { code?: unknown }).code || '')
|
}
|
||||||
: '';
|
return '';
|
||||||
const message =
|
}
|
||||||
error instanceof Error
|
|
||||||
? error.message
|
|
||||||
: error && typeof error === 'object' && 'message' in error
|
|
||||||
? String((error as { message?: unknown }).message || '')
|
|
||||||
: '';
|
|
||||||
|
|
||||||
|
function userEmailErrorMessage(error: unknown): string {
|
||||||
|
const code = emailErrorCode(error);
|
||||||
switch (code) {
|
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_RATE_LIMIT_EXCEEDED':
|
||||||
case 'E_DAILY_LIMIT_EXCEEDED':
|
case 'E_DAILY_LIMIT_EXCEEDED':
|
||||||
return 'Limite di invio email raggiunto. Riprova più tardi.';
|
return 'Troppe richieste al momento. Riprova tra poco.';
|
||||||
case 'E_VALIDATION_ERROR':
|
|
||||||
case 'E_FIELD_MISSING':
|
|
||||||
return message
|
|
||||||
? `Dati email non validi: ${message}`
|
|
||||||
: 'Dati email non validi.';
|
|
||||||
default:
|
default:
|
||||||
return code
|
return USER_SEND_ERROR;
|
||||||
? `Invio email non riuscito (${code}). Riprova più tardi.`
|
|
||||||
: 'Invio email non riuscito. Riprova più tardi.';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +132,7 @@ export const POST: APIRoute = async ({ request, url }) => {
|
|||||||
const message = required(form.get('message'));
|
const message = required(form.get('message'));
|
||||||
|
|
||||||
if (!name || !email || !country || !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'));
|
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'),
|
request.headers.get('CF-Connecting-IP'),
|
||||||
);
|
);
|
||||||
if (!isHuman) {
|
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) {
|
if (!emailBinding || !fromEmail || !toEmail) {
|
||||||
const missing = [
|
const missing = [
|
||||||
!emailBinding ? 'EMAIL binding' : '',
|
!emailBinding ? 'EMAIL binding' : '',
|
||||||
!fromEmail ? 'CONTACT_FORM_FROM_EMAIL (o NEWSLETTER_FROM_EMAIL)' : '',
|
!fromEmail ? 'CONTACT_FORM_FROM_EMAIL|NEWSLETTER_FROM_EMAIL' : '',
|
||||||
!toEmail ? 'CONTACT_FORM_TO_EMAIL (o NEWSLETTER_NOTIFY_TO_EMAIL)' : '',
|
!toEmail ? 'CONTACT_FORM_TO_EMAIL|NEWSLETTER_NOTIFY_TO_EMAIL' : '',
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
return fail(
|
console.error('[contact] incomplete email config', { missing });
|
||||||
request,
|
return fail(request, USER_SEND_ERROR, 500);
|
||||||
`Config email incompleta: manca ${missing.join(', ')}. Imposta le variabili runtime del Worker (Settings → Variables and Secrets), non Build.`,
|
|
||||||
500,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const destination = resolveDepartmentRecipient(runtimeEnv, toEmail, department);
|
const destination = resolveDepartmentRecipient(runtimeEnv, toEmail, department);
|
||||||
if (!destination) {
|
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 {
|
try {
|
||||||
@ -212,8 +200,11 @@ export const POST: APIRoute = async ({ request, url }) => {
|
|||||||
text,
|
text,
|
||||||
});
|
});
|
||||||
} catch (retryError) {
|
} catch (retryError) {
|
||||||
console.error('[contact] email retry failed', retryError);
|
console.error('[contact] email retry failed', {
|
||||||
return fail(request, emailErrorMessage(retryError), 502);
|
code: emailErrorCode(retryError),
|
||||||
|
error: retryError,
|
||||||
|
});
|
||||||
|
return fail(request, userEmailErrorMessage(retryError), 502);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -230,6 +221,6 @@ export const POST: APIRoute = async ({ request, url }) => {
|
|||||||
return succeed(request, redirectTarget);
|
return succeed(request, redirectTarget);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[contact] unexpected error', error);
|
console.error('[contact] unexpected error', error);
|
||||||
return fail(request, 'Errore interno. Riprova più tardi.', 500);
|
return fail(request, USER_SEND_ERROR, 500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user