Aggiunge newsletter custom con D1, double opt-in e invio campagne.

Attiva il form footer, API subscribe/confirm/unsubscribe e endpoint admin protetti, riusando Resend per le email.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Javaxman
2026-07-28 23:23:19 +02:00
parent 9a8566a3f5
commit 7aff1abcfb
27 changed files with 1008 additions and 18 deletions

View File

@ -0,0 +1,85 @@
import type { APIRoute } from 'astro';
import {
getNewsletterDb,
getRuntimeEnv,
readEnv,
required,
sendWithResend,
type NewsletterSubscriber,
} from '../../../lib/newsletter';
export const prerender = false;
export const GET: APIRoute = async ({ request, locals, url }) => {
const runtimeEnv = getRuntimeEnv(locals);
const mode = (readEnv('NEWSLETTER_MODE', runtimeEnv) || readEnv('CONTACT_FORM_MODE', runtimeEnv) || 'dev').toLowerCase();
const token = required(url.searchParams.get('token'));
const okPath = '/newsletter/confermata';
const failPath = '/newsletter/conferma-errore';
if (!token) {
return Response.redirect(new URL(failPath, url).toString(), 303);
}
if (mode !== 'live') {
console.info('[newsletter:dev] Confirm token received', { token: token.slice(0, 8) + '…' });
return Response.redirect(new URL(okPath, url).toString(), 303);
}
const db = getNewsletterDb(runtimeEnv);
if (!db) {
return new Response('Newsletter database binding NEWSLETTER_DB is not configured.', {
status: 500,
});
}
const row = await db
.prepare(
`SELECT * FROM newsletter_subscribers
WHERE confirm_token = ? AND status = 'pending'
LIMIT 1`,
)
.bind(token)
.first<NewsletterSubscriber>();
if (!row) {
return Response.redirect(new URL(failPath, url).toString(), 303);
}
await db
.prepare(
`UPDATE newsletter_subscribers
SET status = 'active',
confirmed_at = datetime('now'),
confirm_token = NULL
WHERE id = ?`,
)
.bind(row.id)
.run();
const resendApiKey =
readEnv('NEWSLETTER_RESEND_API_KEY', runtimeEnv) ||
readEnv('CONTACT_FORM_RESEND_API_KEY', runtimeEnv);
const fromEmail =
readEnv('NEWSLETTER_FROM_EMAIL', runtimeEnv) ||
readEnv('CONTACT_FORM_FROM_EMAIL', runtimeEnv);
const notifyTo =
readEnv('NEWSLETTER_NOTIFY_TO_EMAIL', runtimeEnv) ||
readEnv('CONTACT_FORM_TO_EMAIL', runtimeEnv);
if (resendApiKey && fromEmail && notifyTo) {
try {
await sendWithResend({
apiKey: resendApiKey,
fromEmail,
toEmail: notifyTo,
subject: 'Iscrizione newsletter confermata — NexStudio',
text: `Lindirizzo ${row.email} ha confermato liscrizione alla newsletter.`,
});
} catch (error) {
console.warn('[newsletter] confirm notify failed', error);
}
}
return Response.redirect(new URL(okPath, request.url).toString(), 303);
};