57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import type { APIRoute } from 'astro';
|
||
import { getCVByHash, getProfileById } from '../../../lib/db';
|
||
|
||
// Öffentlicher Endpunkt – kein Login nötig, CV muss public=1 sein
|
||
export const GET: APIRoute = async ({ params, request }) => {
|
||
const cv = getCVByHash(params.hash!);
|
||
if (!cv) return new Response('Not Found', { status: 404 });
|
||
|
||
const profile = getProfileById(cv.profile_id);
|
||
if (!profile) return new Response('Profile Not Found', { status: 404 });
|
||
|
||
const name = [profile.data.personal.firstName, profile.data.personal.lastName]
|
||
.filter(Boolean).join(' ') || cv.title;
|
||
|
||
const origin = new URL(request.url).origin;
|
||
const targetUrl = `${origin}/cv/${cv.hash}`;
|
||
|
||
try {
|
||
const { default: puppeteer } = await import('puppeteer');
|
||
|
||
const browser = await puppeteer.launch({
|
||
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
||
});
|
||
|
||
const page = await browser.newPage();
|
||
await page.setViewport({ width: 794, height: 1123 });
|
||
await page.goto(targetUrl, { waitUntil: 'networkidle0', timeout: 20000 });
|
||
|
||
await page.addStyleTag({
|
||
content: `
|
||
.cv-public-bar { display: none !important; }
|
||
body { background: white !important; padding: 0 !important; }
|
||
.cv-public-wrap { padding: 0 !important; background: white !important; }
|
||
`
|
||
});
|
||
|
||
const pdf = await page.pdf({
|
||
format: 'A4',
|
||
margin: { top: '0mm', right: '0mm', bottom: '0mm', left: '0mm' },
|
||
printBackground: true,
|
||
displayHeaderFooter: false,
|
||
});
|
||
|
||
await browser.close();
|
||
|
||
return new Response(pdf, {
|
||
headers: {
|
||
'Content-Type': 'application/pdf',
|
||
'Content-Disposition': `attachment; filename="${encodeURIComponent(name)}.pdf"`,
|
||
},
|
||
});
|
||
|
||
} catch (err: any) {
|
||
console.error('[PDF Hash]', err.message);
|
||
return new Response(err.message, { status: 500 });
|
||
}
|
||
}; |