fix: SSE 认证 + 收藏去重 + 数据库索引和级联删除

- #7: SSE events 接口校验 userId 房间成员身份,start() 加 try/catch
- #9: Favorite 新增 restaurantId 字段做精确去重,不再用 JSON contains
- #10: 补齐 Decision/Favorite/Room/BlindBoxIdea 缺失索引
- #11: Decision/Favorite/BlindBoxMember/BlindBoxIdea 加 onDelete Cascade
This commit is contained in:
2026-02-26 20:15:45 +08:00
parent 9c7f18e0fa
commit 508903b67d
3 changed files with 67 additions and 34 deletions
+26 -24
View File
@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { Prisma } from "@prisma/client";
import { apiHandler, ApiError, requireUserId, requireUser } from "@/lib/api";
export const GET = apiHandler(async (req) => {
@@ -13,11 +14,11 @@ export const GET = apiHandler(async (req) => {
});
return NextResponse.json(
favorites.map((f) => ({
id: f.id,
restaurantData: JSON.parse(f.restaurantData),
createdAt: f.createdAt.toISOString(),
})),
favorites.map((f) => {
let restaurantData = {};
try { restaurantData = JSON.parse(f.restaurantData); } catch { /* ignore */ }
return { id: f.id, restaurantData, createdAt: f.createdAt.toISOString() };
}),
);
});
@@ -25,29 +26,30 @@ export const POST = apiHandler(async (req) => {
const { userId, restaurant } = await req.json();
requireUserId(userId);
if (!restaurant) throw new ApiError("缺少必要字段");
if (!restaurant?.id || typeof restaurant.id !== "string") {
throw new ApiError("缺少必要字段");
}
await requireUser(userId);
const existing = await prisma.favorite.findFirst({
where: {
userId,
restaurantData: { contains: `"id":"${restaurant.id}"` },
},
});
if (existing) {
return NextResponse.json({ id: existing.id, alreadyExists: true });
try {
const fav = await prisma.favorite.create({
data: {
userId,
restaurantId: restaurant.id,
restaurantData: JSON.stringify(restaurant),
},
});
return NextResponse.json({ id: fav.id });
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") {
const existing = await prisma.favorite.findFirst({
where: { userId, restaurantId: restaurant.id },
});
return NextResponse.json({ id: existing?.id ?? "", alreadyExists: true });
}
throw e;
}
const fav = await prisma.favorite.create({
data: {
userId,
restaurantData: JSON.stringify(restaurant),
},
});
return NextResponse.json({ id: fav.id });
});
export const DELETE = apiHandler(async (req) => {