spomeni/src/app/api/publish/route.ts
2026-07-24 04:11:40 +02:00

105 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from "next/server";
import { auth } from "@clerk/nextjs/server";
import { revalidateTag } from "next/cache";
import { prisma } from "@/lib/prisma";
import { generateMonumentQR } from "@/lib/qrcode";
import { getPublicUrl } from "@/lib/upload";
export async function POST(req: NextRequest) {
const { userId } = await auth();
if (!userId) {
return NextResponse.json({ error: "Неавторизирано" }, { status: 401 });
}
try {
const body = await req.json();
const { title, description, bornDate, passedDate, subdomain, templateId, images } = body;
if (!title?.trim()) {
return NextResponse.json({ error: "Името е задолжително" }, { status: 400 });
}
if (!subdomain || subdomain.length < 3) {
return NextResponse.json({ error: "Поддоменот мора да има најмалку 3 карактери" }, { status: 400 });
}
if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(subdomain)) {
return NextResponse.json({ error: "Поддоменот може да содржи само мали букви, цифри и цртички" }, { status: 400 });
}
if (templateId < 1 || templateId > 3) {
return NextResponse.json({ error: "Невалиден шаблон" }, { status: 400 });
}
if (!images || images.length === 0 || images.length > 3) {
return NextResponse.json({ error: "Потребни се 1-3 фотографии" }, { status: 400 });
}
const existing = await prisma.user.findUnique({ where: { subdomain } });
if (existing && existing.clerkId !== userId) {
return NextResponse.json({ error: "Поддоменот е веќе зафатен" }, { status: 409 });
}
const existingUser = await prisma.user.findUnique({ where: { clerkId: userId } });
let user;
if (existingUser) {
if (existingUser.subdomain !== subdomain) {
revalidateTag(`memorial-${existingUser.subdomain}`);
}
await prisma.image.deleteMany({ where: { userId: existingUser.id } });
user = await prisma.user.update({
where: { clerkId: userId },
data: {
title,
description,
bornDate: bornDate || null,
passedDate: passedDate || null,
subdomain,
templateId,
published: true,
images: {
create: images.map((img: { key: string }, i: number) => ({
url: getPublicUrl(img.key),
key: img.key,
order: i + 1,
})),
},
},
include: { images: true },
});
} else {
user = await prisma.user.create({
data: {
clerkId: userId,
title,
description,
bornDate: bornDate || null,
passedDate: passedDate || null,
subdomain,
templateId,
published: true,
images: {
create: images.map((img: { key: string }, i: number) => ({
url: getPublicUrl(img.key),
key: img.key,
order: i + 1,
})),
},
},
include: { images: true },
});
}
revalidateTag("memorial");
revalidateTag(`memorial-${subdomain}`);
const qrCode = await generateMonumentQR(subdomain);
return NextResponse.json({
success: true,
monumentUrl: `https://${subdomain}.${process.env.NEXT_PUBLIC_APP_DOMAIN}`,
qrCode,
user,
});
} catch (error) {
console.error("Publish error:", error);
return NextResponse.json({ error: "Внатрешна грешка на серверот" }, { status: 500 });
}
}