Gerichtnamen, Essenszeiten und Allergen-/Zusatzstoff-Bezeichnungen sind jetzt genauso dynamisch mehrsprachig wie die Bedienoberfläche aus v1.10.0, statt fest auf Englisch/Polnisch begrenzt zu sein. Neue Übersetzungstabellen ersetzen die alten name_en/name_pl-Spalten, DeepL-Auto-Übersetzung und CSV-Import/-Export unterstützen jetzt beliebig viele aktive Sprachen.
57 lines
2.1 KiB
TypeScript
57 lines
2.1 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { importCodes, type CodeImportRow } from "@/lib/db/code-lists";
|
|
import { listActiveLanguageCodes } from "@/lib/db/languages";
|
|
import { authErrorResponse, requireRole } from "@/lib/auth/session";
|
|
import { isSameOrigin } from "@/lib/origin";
|
|
import { parseCsvWithHeader } from "@/lib/csv";
|
|
|
|
export async function POST(request: Request) {
|
|
if (!isSameOrigin(request)) {
|
|
return NextResponse.json({ error: "Nicht erlaubt." }, { status: 403 });
|
|
}
|
|
try {
|
|
await requireRole(["staff", "admin"]);
|
|
const form = await request.formData();
|
|
const file = form.get("file");
|
|
if (!(file instanceof File)) {
|
|
return NextResponse.json({ error: "invalid_input" }, { status: 400 });
|
|
}
|
|
|
|
const { header, rows: cells } = parseCsvWithHeader(await file.text());
|
|
const codeIdx = header.indexOf("code");
|
|
const nameIdx = header.indexOf("name");
|
|
if (codeIdx === -1 || nameIdx === -1) {
|
|
return NextResponse.json({ error: "missing_columns" }, { status: 400 });
|
|
}
|
|
const activeCodes = (await listActiveLanguageCodes()).filter((c) => c !== "de");
|
|
const langCols = activeCodes
|
|
.map((code) => ({ code, idx: header.indexOf(`name_${code}`) }))
|
|
.filter((c) => c.idx !== -1);
|
|
|
|
const rows: CodeImportRow[] = [];
|
|
const skipped: { row: number; reason: string }[] = [];
|
|
cells.forEach((c, i) => {
|
|
const rowNum = i + 2; // 1-indexiert + Kopfzeile
|
|
const code = (c[codeIdx] ?? "").trim();
|
|
const name = (c[nameIdx] ?? "").trim();
|
|
if (!code || !name) {
|
|
skipped.push({ row: rowNum, reason: "Kürzel oder Bezeichnung fehlt" });
|
|
return;
|
|
}
|
|
const translations: Record<string, string> = {};
|
|
for (const { code: lang, idx } of langCols) {
|
|
const value = c[idx]?.trim();
|
|
if (value) translations[lang] = value;
|
|
}
|
|
rows.push({ code, name, translations });
|
|
});
|
|
|
|
const result = rows.length > 0 ? await importCodes("additives", rows) : { created: 0, updated: 0 };
|
|
return NextResponse.json({ ...result, skipped });
|
|
} catch (err) {
|
|
const res = authErrorResponse(err);
|
|
if (res) return res;
|
|
throw err;
|
|
}
|
|
}
|