Initialize consent state from cookie synchronously so the banner only shows when no choice was made. fix(api): fail-soft when DB schema missing Return null/empty content for CMS endpoints when migrations are not applied instead of crashing with Prisma P2021/P2022. fix(n8n): parse status response defensively Handle empty/invalid JSON bodies from n8n to prevent activity feed from getting stuck. Co-authored-by: dennis <dennis@konkol.net>
83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import { prisma } from "@/lib/prisma";
|
|
import type { Prisma } from "@prisma/client";
|
|
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
|
|
|
|
export async function getSiteSettings() {
|
|
return prisma.siteSettings.findUnique({ where: { id: 1 } });
|
|
}
|
|
|
|
export async function getContentByKey(opts: { key: string; locale: string }) {
|
|
const { key, locale } = opts;
|
|
try {
|
|
const page = await prisma.contentPage.findUnique({
|
|
where: { key },
|
|
include: {
|
|
translations: {
|
|
where: { locale },
|
|
take: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (page?.translations?.[0]) return page.translations[0];
|
|
|
|
const settings = await getSiteSettings();
|
|
const fallbackLocale = settings?.defaultLocale || "en";
|
|
|
|
const fallback = await prisma.contentPageTranslation.findFirst({
|
|
where: {
|
|
page: { key },
|
|
locale: fallbackLocale,
|
|
},
|
|
});
|
|
|
|
return fallback;
|
|
} catch (error) {
|
|
// If migrations haven't been applied yet, don't crash the app.
|
|
// Let callers fall back to static translations.
|
|
if (error instanceof PrismaClientKnownRequestError && (error.code === "P2021" || error.code === "P2022")) {
|
|
return null;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function upsertContentByKey(opts: {
|
|
key: string;
|
|
locale: string;
|
|
title?: string | null;
|
|
slug?: string | null;
|
|
content: unknown;
|
|
metaDescription?: string | null;
|
|
keywords?: string | null;
|
|
}) {
|
|
const { key, locale, title, slug, content, metaDescription, keywords } = opts;
|
|
|
|
const page = await prisma.contentPage.upsert({
|
|
where: { key },
|
|
create: { key, status: "PUBLISHED" },
|
|
update: {},
|
|
});
|
|
|
|
return prisma.contentPageTranslation.upsert({
|
|
where: { pageId_locale: { pageId: page.id, locale } },
|
|
create: {
|
|
pageId: page.id,
|
|
locale,
|
|
title: title ?? undefined,
|
|
slug: slug ?? undefined,
|
|
content: content as Prisma.InputJsonValue, // JSON
|
|
metaDescription: metaDescription ?? undefined,
|
|
keywords: keywords ?? undefined,
|
|
},
|
|
update: {
|
|
title: title ?? undefined,
|
|
slug: slug ?? undefined,
|
|
content: content as Prisma.InputJsonValue, // JSON
|
|
metaDescription: metaDescription ?? undefined,
|
|
keywords: keywords ?? undefined,
|
|
},
|
|
});
|
|
}
|
|
|