58 lines
2.9 KiB
TypeScript
58 lines
2.9 KiB
TypeScript
import { and, desc, eq, lte } from "drizzle-orm";
|
|
import { NextResponse } from "next/server";
|
|
import { z } from "zod";
|
|
import { auth } from "@/app/(auth)/auth";
|
|
import { db } from "@/lib/db";
|
|
import { tvstarSession } from "@/lib/db/schema";
|
|
import { ownsTaskProject } from "@/lib/video-canvas/task-store";
|
|
import { tvstarSessionSchema } from "@/lib/video-canvas/tvstar-session";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
async function authorize(projectId: string) {
|
|
const session = await auth();
|
|
if (!session?.user?.id) return { error: NextResponse.json({ error: "未登录" }, { status: 401 }) };
|
|
if (!z.string().uuid().safeParse(projectId).success || !await ownsTaskProject(session.user.id, projectId)) {
|
|
return { error: NextResponse.json({ error: "画布不存在" }, { status: 404 }) };
|
|
}
|
|
return { userId: session.user.id };
|
|
}
|
|
|
|
export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
const { id } = await params;
|
|
const access = await authorize(id);
|
|
if (access.error) return access.error;
|
|
const rows = await db.select({ snapshot: tvstarSession.snapshot, shareToken: tvstarSession.shareToken })
|
|
.from(tvstarSession)
|
|
.where(and(eq(tvstarSession.userId, access.userId!), eq(tvstarSession.projectId, id)))
|
|
.orderBy(desc(tvstarSession.clientUpdatedAt)).limit(20);
|
|
return NextResponse.json({ sessions: rows.map(({ snapshot, shareToken }) => ({
|
|
...(snapshot as Record<string, unknown>), shareToken: shareToken || undefined,
|
|
})) }, { headers: { "Cache-Control": "no-store" } });
|
|
}
|
|
|
|
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
const { id } = await params;
|
|
const access = await authorize(id);
|
|
if (access.error) return access.error;
|
|
const raw = await request.text();
|
|
if (raw.length > 900_000) return NextResponse.json({ error: "对话记录过大" }, { status: 413 });
|
|
let body: unknown;
|
|
try { body = JSON.parse(raw); } catch { return NextResponse.json({ error: "请求格式无效" }, { status: 400 }); }
|
|
const parsed = z.object({ sessions: z.array(tvstarSessionSchema).max(20) }).safeParse(body);
|
|
if (!parsed.success) return NextResponse.json({ error: "对话记录格式无效" }, { status: 400 });
|
|
for (const session of parsed.data.sessions) {
|
|
const clientUpdatedAt = new Date(Math.min(session.updatedAt, Date.now() + 60_000));
|
|
await db.insert(tvstarSession).values({
|
|
id: session.id, projectId: id, userId: access.userId!, title: session.title,
|
|
snapshot: session, clientUpdatedAt,
|
|
}).onConflictDoNothing({ target: tvstarSession.id });
|
|
await db.update(tvstarSession).set({ title: session.title, snapshot: session, clientUpdatedAt, updatedAt: new Date() })
|
|
.where(and(
|
|
eq(tvstarSession.id, session.id), eq(tvstarSession.projectId, id), eq(tvstarSession.userId, access.userId!),
|
|
lte(tvstarSession.clientUpdatedAt, clientUpdatedAt),
|
|
));
|
|
}
|
|
return NextResponse.json({ ok: true });
|
|
}
|