Calendario: il PDF e' un file vero, generato dal server
"Scarica in PDF" non apre piu' la stampa del browser: e' un link a /calendario/<id>.pdf che restituisce un documento disegnato dal dato con PDFKit, con Content-Disposition attachment. Serve perche' il calendario si gira su WhatsApp, ed e' cosi' che questo centro parla coi clienti: chi lo riceve non ha il sito aperto davanti. Niente browser headless: Chromium in un container da 2 vCPU costa centinaia di megabyte e un processo per richiesta, per una griglia di sette colonne. Le linee della griglia si tracciano in una passata a parte, dopo i riempimenti: disegnandole riga per riga, il riempimento della riga seguente copriva quella appena fatta e due lezioni uguali in fasce consecutive si leggevano come un blocco unico lungo il doppio. Quattro test: intestazione %PDF- e coda %%EOF (un documento non chiuso arriva monco e il browser mostra una pagina bianca invece di un errore), una pagina sola, nomi di file distinti. Un id sconosciuto e' 404, non un PDF vuoto. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { calendari } from '../../data/calendari';
|
||||
import { generaCalendarioPdf, nomeFilePdf } from '../../lib/calendario-pdf';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
// Il PDF del calendario, come file scaricabile: `/calendario/<id>.pdf`.
|
||||
//
|
||||
// Pubblico come il resto del sito — è lo stesso orario che chiunque legge nel popup, e un file
|
||||
// dietro autenticazione non si potrebbe girare su WhatsApp, che è come questo centro
|
||||
// comunica coi clienti.
|
||||
export const GET: APIRoute = async ({ params }) => {
|
||||
const cal = calendari.find((c) => c.id === params.id);
|
||||
// Un id sconosciuto è 404, non un PDF vuoto: un file che si apre e non contiene niente fa
|
||||
// credere che il calendario sia vuoto.
|
||||
if (!cal) return new Response('Calendario inesistente.', { status: 404 });
|
||||
|
||||
const pdf = await generaCalendarioPdf(cal);
|
||||
return new Response(new Uint8Array(pdf), {
|
||||
headers: {
|
||||
'Content-Type': 'application/pdf',
|
||||
// `attachment` perché il bottone dice "scarica": senza, il browser lo aprirebbe in una
|
||||
// scheda e su telefono resterebbe lì, senza finire fra i file.
|
||||
'Content-Disposition': `attachment; filename="${nomeFilePdf(cal)}"`,
|
||||
'Content-Length': String(pdf.length),
|
||||
// Il calendario cambia solo quando cambia il dato, cioè con un deploy: un'ora di cache
|
||||
// basta a non rigenerarlo a ogni click, e non abbastanza da servire un orario vecchio.
|
||||
'Cache-Control': 'public, max-age=3600',
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user