Files
mnote/wolai-frontend/src/app/api/blocks/embed/route.ts
T
2026-01-18 05:13:53 +08:00

116 lines
4.0 KiB
TypeScript

import { randomUUID } from "crypto";
import { NextResponse } from "next/server";
import { createSupabaseRouteClient } from "@/lib/supabase/server";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { requireAuthContext } from "@/lib/auth/authContext";
import { getConvexHttpClient } from "@/lib/convex/server";
import { api } from "@/lib/convex/api";
import { getBlocksFromDocumentContent, findBlockInTree, withBlocksWrittenBack } from "@/lib/blocks";
type EmbedBlockPayload = {
sourceDocumentId: string;
blockId: string;
targetDocumentId: string;
position?: "end";
};
export async function POST(request: Request) {
const { sourceDocumentId, blockId, targetDocumentId }: EmbedBlockPayload = await request.json();
if (!sourceDocumentId || !blockId || !targetDocumentId) {
return NextResponse.json({ error: "缺少参数" }, { status: 400 });
}
if (sourceDocumentId === targetDocumentId) {
return NextResponse.json({ error: "禁止嵌入到当前页面" }, { status: 400 });
}
if (isConvexEnabled()) {
const auth = await requireAuthContext();
const client = getConvexHttpClient();
const source = await client.query(api.documents.getContent, { userId: auth.userId, id: sourceDocumentId });
if (!source) return NextResponse.json({ error: "源页面不存在或无权限" }, { status: 404 });
const sourceBlocks = getBlocksFromDocumentContent(source.content);
const hit = findBlockInTree(sourceBlocks, blockId);
if (!hit) return NextResponse.json({ error: "源块不存在或无权限" }, { status: 404 });
const target = await client.query(api.documents.getContent, { userId: auth.userId, id: targetDocumentId });
if (!target) return NextResponse.json({ error: "目标页面不存在或无权限" }, { status: 404 });
const targetBlocks = getBlocksFromDocumentContent(target.content);
const referenceBlock = {
id: randomUUID(),
type: "blockReference",
props: {
sourceDocumentId,
targetBlockId: blockId,
display: "embed",
},
content: [],
children: [],
};
const nextBlocks = [...targetBlocks, referenceBlock];
const payload = withBlocksWrittenBack(target.content, nextBlocks);
await client.mutation(api.documents.updateContent, { userId: auth.userId, id: targetDocumentId, content: payload });
return NextResponse.json({ ok: true });
}
const supabase = await createSupabaseRouteClient();
const {
data: { session },
} = await supabase.auth.getSession();
if (!session) {
return NextResponse.json({ error: "未登录" }, { status: 401 });
}
const { data: sourceDoc } = await supabase
.from("documents")
.select("id,content,user_id")
.eq("id", sourceDocumentId)
.eq("user_id", session.user.id)
.single();
if (!sourceDoc) return NextResponse.json({ error: "源页面不存在或无权限" }, { status: 404 });
const sourceBlocks = getBlocksFromDocumentContent(sourceDoc.content);
if (!findBlockInTree(sourceBlocks, blockId)) {
return NextResponse.json({ error: "源块不存在或无权限" }, { status: 404 });
}
const { data: targetDoc } = await supabase
.from("documents")
.select("id,content,user_id")
.eq("id", targetDocumentId)
.eq("user_id", session.user.id)
.single();
if (!targetDoc) return NextResponse.json({ error: "目标页面不存在或无权限" }, { status: 404 });
const targetBlocks = getBlocksFromDocumentContent(targetDoc.content);
const referenceBlock = {
id: randomUUID(),
type: "blockReference",
props: {
sourceDocumentId,
targetBlockId: blockId,
display: "embed",
},
content: [],
children: [],
};
const nextBlocks = [...targetBlocks, referenceBlock];
const payload = withBlocksWrittenBack(targetDoc.content, nextBlocks);
const { error } = await supabase
.from("documents")
.update({ content: payload })
.eq("id", targetDocumentId)
.eq("user_id", session.user.id);
if (error) return NextResponse.json({ error: error.message }, { status: 500 });
return NextResponse.json({ ok: true });
}