Attiva il form footer, API subscribe/confirm/unsubscribe e endpoint admin protetti, riusando Resend per le email. Co-authored-by: Cursor <cursoragent@cursor.com>
86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import type { APIRoute } from 'astro';
|
|
import {
|
|
getNewsletterDb,
|
|
getRuntimeEnv,
|
|
readEnv,
|
|
required,
|
|
type NewsletterSubscriber,
|
|
} from '../../../lib/newsletter';
|
|
|
|
export const prerender = false;
|
|
|
|
async function unsubscribeByToken(
|
|
locals: unknown,
|
|
token: string,
|
|
): Promise<'ok' | 'missing' | 'not_found' | 'no_db'> {
|
|
if (!token) return 'missing';
|
|
|
|
const runtimeEnv = getRuntimeEnv(locals);
|
|
const mode = (readEnv('NEWSLETTER_MODE', runtimeEnv) || readEnv('CONTACT_FORM_MODE', runtimeEnv) || 'dev').toLowerCase();
|
|
|
|
if (mode !== 'live') {
|
|
console.info('[newsletter:dev] Unsubscribe token received', { token: token.slice(0, 8) + '…' });
|
|
return 'ok';
|
|
}
|
|
|
|
const db = getNewsletterDb(runtimeEnv);
|
|
if (!db) return 'no_db';
|
|
|
|
const row = await db
|
|
.prepare(
|
|
`SELECT * FROM newsletter_subscribers
|
|
WHERE unsubscribe_token = ?
|
|
LIMIT 1`,
|
|
)
|
|
.bind(token)
|
|
.first<NewsletterSubscriber>();
|
|
|
|
if (!row) return 'not_found';
|
|
|
|
if (row.status !== 'unsubscribed') {
|
|
await db
|
|
.prepare(
|
|
`UPDATE newsletter_subscribers
|
|
SET status = 'unsubscribed',
|
|
unsubscribed_at = datetime('now'),
|
|
confirm_token = NULL
|
|
WHERE id = ?`,
|
|
)
|
|
.bind(row.id)
|
|
.run();
|
|
}
|
|
|
|
return 'ok';
|
|
}
|
|
|
|
export const GET: APIRoute = async ({ locals, url }) => {
|
|
const token = required(url.searchParams.get('token'));
|
|
const result = await unsubscribeByToken(locals, token);
|
|
|
|
if (result === 'no_db') {
|
|
return new Response('Newsletter database binding NEWSLETTER_DB is not configured.', {
|
|
status: 500,
|
|
});
|
|
}
|
|
|
|
const path =
|
|
result === 'ok' ? '/newsletter/disiscrizione' : '/newsletter/disiscrizione-errore';
|
|
return Response.redirect(new URL(path, url).toString(), 303);
|
|
};
|
|
|
|
export const POST: APIRoute = async ({ request, locals, url }) => {
|
|
const form = await request.formData();
|
|
const token = required(form.get('token')) || required(url.searchParams.get('token'));
|
|
const result = await unsubscribeByToken(locals, token);
|
|
|
|
if (result === 'no_db') {
|
|
return new Response('Newsletter database binding NEWSLETTER_DB is not configured.', {
|
|
status: 500,
|
|
});
|
|
}
|
|
|
|
const path =
|
|
result === 'ok' ? '/newsletter/disiscrizione' : '/newsletter/disiscrizione-errore';
|
|
return Response.redirect(new URL(path, url).toString(), 303);
|
|
};
|