119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { promises as fs } from "fs";
|
|
import path from "path";
|
|
import { prisma } from "../../../../lib/prisma";
|
|
import { isSuperAdminSession, requireSession } from "../../../../lib/auth-helpers";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
export const revalidate = 0;
|
|
|
|
const DATA_DIR = path.join(process.cwd(), "prisma", "data");
|
|
const UPLOADS_DIR = path.join(DATA_DIR, "uploads");
|
|
|
|
const MIME_TO_EXT: Record<string, string> = {
|
|
"image/png": "png",
|
|
"image/jpeg": "jpg",
|
|
"image/webp": "webp",
|
|
"image/svg+xml": "svg"
|
|
};
|
|
|
|
const resolveLogoPath = (relativePath: string) => {
|
|
const absolutePath = path.join(DATA_DIR, relativePath);
|
|
if (!absolutePath.startsWith(DATA_DIR)) {
|
|
throw new Error("Ungültiger Pfad.");
|
|
}
|
|
return absolutePath;
|
|
};
|
|
|
|
const getLogoSetting = async () =>
|
|
prisma.setting.findUnique({ where: { key: "app_logo_path" } });
|
|
|
|
const getLogoTypeSetting = async () =>
|
|
prisma.setting.findUnique({ where: { key: "app_logo_type" } });
|
|
|
|
export async function POST(request: Request) {
|
|
const { session } = await requireSession();
|
|
if (!session) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
if (!isSuperAdminSession(session)) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
const formData = await request.formData();
|
|
const file = formData.get("file");
|
|
|
|
if (!file || !(file instanceof File)) {
|
|
return NextResponse.json({ error: "Datei fehlt." }, { status: 400 });
|
|
}
|
|
|
|
const extension = MIME_TO_EXT[file.type];
|
|
if (!extension) {
|
|
return NextResponse.json({ error: "Dateityp nicht unterstützt." }, { status: 400 });
|
|
}
|
|
|
|
await fs.mkdir(UPLOADS_DIR, { recursive: true });
|
|
|
|
const previousSetting = await getLogoSetting();
|
|
const previousTypeSetting = await getLogoTypeSetting();
|
|
|
|
const filename = `app-logo.${extension}`;
|
|
const relativePath = path.join("uploads", filename);
|
|
const absolutePath = resolveLogoPath(relativePath);
|
|
|
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
await fs.writeFile(absolutePath, buffer);
|
|
|
|
if (previousSetting?.value && previousSetting.value !== relativePath) {
|
|
try {
|
|
await fs.unlink(resolveLogoPath(previousSetting.value));
|
|
} catch {
|
|
// ignore missing old file
|
|
}
|
|
}
|
|
|
|
await prisma.setting.upsert({
|
|
where: { key: "app_logo_path" },
|
|
update: { value: relativePath },
|
|
create: { key: "app_logo_path", value: relativePath }
|
|
});
|
|
|
|
await prisma.setting.upsert({
|
|
where: { key: "app_logo_type" },
|
|
update: { value: file.type },
|
|
create: { key: "app_logo_type", value: file.type }
|
|
});
|
|
|
|
return NextResponse.json({ ok: true });
|
|
}
|
|
|
|
export async function DELETE() {
|
|
const { session } = await requireSession();
|
|
if (!session) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
if (!isSuperAdminSession(session)) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
const logoSetting = await getLogoSetting();
|
|
const typeSetting = await getLogoTypeSetting();
|
|
|
|
if (logoSetting?.value) {
|
|
try {
|
|
await fs.unlink(resolveLogoPath(logoSetting.value));
|
|
} catch {
|
|
// ignore missing file
|
|
}
|
|
}
|
|
|
|
if (logoSetting) {
|
|
await prisma.setting.delete({ where: { key: "app_logo_path" } });
|
|
}
|
|
if (typeSetting) {
|
|
await prisma.setting.delete({ where: { key: "app_logo_type" } });
|
|
}
|
|
|
|
return NextResponse.json({ ok: true });
|
|
}
|