2025-12-05 13:53:29 +01:00

121 lines
3.5 KiB
TypeScript

// app/api/profile/avatar/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth-options';
import { prisma } from '@/lib/prisma';
import fs from 'fs';
import path from 'path';
export async function POST(req: NextRequest) {
const session = await getServerSession(authOptions);
const user = session?.user as any | undefined;
const nwkennung: string | undefined = user?.nwkennung;
if (!session || !nwkennung) {
return NextResponse.json({ error: 'UNAUTHORIZED' }, { status: 401 });
}
const formData = await req.formData();
const file = formData.get('avatar');
if (!file || !(file instanceof Blob)) {
return NextResponse.json({ error: 'NO_FILE' }, { status: 400 });
}
const MAX_SIZE = 5 * 1024 * 1024; // 5 MB
const mime = file.type || '';
if (!mime.startsWith('image/')) {
return NextResponse.json({ error: 'INVALID_TYPE' }, { status: 400 });
}
const size: number | undefined = file.size;
if (typeof size === 'number' && size > MAX_SIZE) {
return NextResponse.json(
{ error: 'TOO_LARGE', maxSizeBytes: MAX_SIZE },
{ status: 413 },
);
}
// Dateiendung bestimmen
let ext = '';
if ('name' in file) {
const name = (file as any).name as string;
ext = path.extname(name);
}
if (!ext) {
if (mime === 'image/jpeg') ext = '.jpg';
else if (mime === 'image/png') ext = '.png';
else if (mime === 'image/gif') ext = '.gif';
else ext = '.img';
}
const avatarsDir = path.join(process.cwd(), 'public', 'avatars');
await fs.promises.mkdir(avatarsDir, { recursive: true });
// alte Avatare löschen
const existingFiles = await fs.promises.readdir(avatarsDir);
await Promise.all(
existingFiles
.filter((f) => f.startsWith(`${nwkennung}-`))
.map((f) => fs.promises.unlink(path.join(avatarsDir, f))),
);
// Neuer, eindeutiger Dateiname
const timestamp = Date.now();
const fileName = `${nwkennung}-${timestamp}${ext.toLowerCase()}`;
const filePath = path.join(avatarsDir, fileName);
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
await fs.promises.writeFile(filePath, buffer);
const avatarUrl = `/avatars/${fileName}`;
await prisma.user.update({
where: { nwkennung },
data: { avatarUrl },
});
return NextResponse.json({ ok: true, avatarUrl });
}
// 👇 Neu: Profilbild löschen
export async function DELETE(req: NextRequest) {
const session = await getServerSession(authOptions);
const user = session?.user as any | undefined;
const nwkennung: string | undefined = user?.nwkennung;
if (!session || !nwkennung) {
return NextResponse.json({ error: 'UNAUTHORIZED' }, { status: 401 });
}
const avatarsDir = path.join(process.cwd(), 'public', 'avatars');
// Dateien löschen (falls vorhanden)
try {
const existingFiles = await fs.promises.readdir(avatarsDir);
const userFiles = existingFiles.filter((f) =>
f.startsWith(`${nwkennung}-`),
);
await Promise.all(
userFiles.map((f) => fs.promises.unlink(path.join(avatarsDir, f))),
);
} catch (err: any) {
// Wenn es den Ordner nicht gibt, ignorieren
if (err?.code !== 'ENOENT') {
console.error('[DELETE /api/profile/avatar] cleanup error', err);
}
}
// avatarUrl in DB auf null setzen
await prisma.user.update({
where: { nwkennung },
data: { avatarUrl: null },
});
return NextResponse.json({ ok: true, avatarUrl: null });
}