import { ComicBubble, Prisma } from '@prisma/client'; import { NextApiRequest, NextApiResponse } from 'next'; import { unstable_getServerSession } from 'next-auth'; import { z } from 'zod'; import { auditPageUpdate } from '../../src/audit'; import { prisma } from '../../src/db'; import { authOptions } from './auth/[...nextauth]'; const PageBubblesSchema = z.object({ bubbles: z.array( z.object({ area: z.object({ x: z.number(), y: z.number(), width: z.number(), height: z.number(), }), character: z.number(), index: z.number(), text: z.string(), }) ), comicId: z.number(), pageId: z.number(), }); export type PageBubbles = z.infer; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method !== 'PUT') return res.status(405).json({ error: 'method not allowed' }); const session = await unstable_getServerSession(req, res, authOptions); if (!session || !session.user) return res.status(401).json({ error: 'authentication required' }); const data = PageBubblesSchema.parse(req.body); const page = await prisma.comicPage.findFirst({ where: { comicId: data.comicId, id: data.pageId, }, include: { bubbles: true, }, }); if (!page) return res.status(404).json({ error: 'not found' }); const existingCharacters: number[] = []; const ops: Prisma.Prisma__ComicBubbleClient[] = []; for (const bubble of data.bubbles) { if (!existingCharacters.includes(bubble.character)) { const char = await prisma.comicCharacter.findFirst({ where: { id: bubble.character, }, }); if (!char) { return res.status(400).json({ message: 'bad request' }); } } const op = prisma.comicBubble.upsert({ where: { comicId_pageId_idx: { comicId: data.comicId, pageId: data.pageId, idx: bubble.index, }, }, update: { areaX: bubble.area.x, areaY: bubble.area.y, areaWidth: bubble.area.width, areaHeight: bubble.area.height, characterId: bubble.character, content: bubble.text, }, create: { comicId: data.comicId, pageId: data.pageId, idx: bubble.index, areaX: bubble.area.x, areaY: bubble.area.y, areaWidth: bubble.area.width, areaHeight: bubble.area.height, characterId: bubble.character, content: bubble.text, }, }); ops.push(op); } await prisma.$transaction(ops); const after = await prisma.comicPage.update({ where: { comicId_id: { comicId: page.comicId, id: page.id, }, }, data: { lastEditedById: session.user.id, }, include: { bubbles: true, }, }); await auditPageUpdate(page, after, data, session.user); res.status(201).json({}); }