import { cookies } from 'next/headers' import { getIronSession } from 'iron-session' import sharp from 'sharp' import { prisma } from '@/lib/prisma' import { SessionData, sessionOptions } from '@/lib/session' import { enforceUserRateLimit } from '@/lib/rate-limit' const MAX_BYTES = 12 * 1024 * 1024 const ALLOWED_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp']) async function getSession() { return getIronSession(await cookies(), sessionOptions) } export async function POST(request: Request) { const session = await getSession() if (!session.userId) { return Response.json({ error: 'Niet ingelogd' }, { status: 401 }) } if (session.isDemo) { return Response.json({ error: 'Niet beschikbaar in demo-modus' }, { status: 403 }) } const limited = enforceUserRateLimit('upload-avatar', session.userId) if (limited) return Response.json({ error: limited.error }, { status: 429 }) const formData = await request.formData() const file = formData.get('avatar') as File | null if (!file || file.size === 0) { return Response.json({ error: 'Geen bestand ontvangen' }, { status: 400 }) } if (!ALLOWED_TYPES.has(file.type)) { return Response.json({ error: 'Alleen JPEG, PNG en WebP zijn toegestaan' }, { status: 422 }) } if (file.size > MAX_BYTES) { return Response.json({ error: 'Bestand is groter dan 12 MB' }, { status: 422 }) } const input = Buffer.from(await file.arrayBuffer()) const processed = await sharp(input) .resize(700, 700, { fit: 'inside', withoutEnlargement: true }) .webp({ quality: 85 }) .toBuffer() await prisma.user.update({ where: { id: session.userId }, data: { avatar_data: new Uint8Array(processed) }, }) return Response.json({ ok: true }) } export async function GET() { const session = await getSession() if (!session.userId) { return new Response(null, { status: 401 }) } const user = await prisma.user.findUnique({ where: { id: session.userId }, select: { avatar_data: true }, }) if (!user?.avatar_data) { return new Response(null, { status: 404 }) } return new Response(user.avatar_data, { headers: { 'Content-Type': 'image/webp', 'Cache-Control': 'private, max-age=3600', }, }) }