0.2.1 onlyoffice修复
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import { mutation, query } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
import { nowIso } from "./_utils/time";
|
||||
import type { MutationCtx, QueryCtx } from "./_generated/server";
|
||||
|
||||
async function assertWorkspaceMember(ctx: QueryCtx | MutationCtx, userId: string, workspaceId: string) {
|
||||
const membership = await ctx.db
|
||||
.query("workspace_members")
|
||||
.withIndex("by_workspace_user", (q) => q.eq("workspace_id", workspaceId).eq("user_id", userId))
|
||||
.first();
|
||||
if (!membership) {
|
||||
throw new Error("无权访问该工作空间");
|
||||
}
|
||||
return membership;
|
||||
}
|
||||
|
||||
const displayMode = v.union(v.literal("inline"), v.literal("embed"));
|
||||
|
||||
export const record = mutation({
|
||||
args: {
|
||||
userId: v.string(),
|
||||
workspaceId: v.string(),
|
||||
sourcePageId: v.string(),
|
||||
targetPageId: v.string(),
|
||||
sourceBlockId: v.union(v.string(), v.null()),
|
||||
alias: v.union(v.string(), v.null()),
|
||||
displayMode,
|
||||
isPreviewable: v.boolean(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
|
||||
|
||||
const ts = nowIso();
|
||||
const existing = await ctx.db
|
||||
.query("page_references")
|
||||
.withIndex("by_unique", (q) =>
|
||||
q
|
||||
.eq("workspace_id", args.workspaceId)
|
||||
.eq("source_page_id", args.sourcePageId)
|
||||
.eq("source_block_id", args.sourceBlockId)
|
||||
.eq("target_page_id", args.targetPageId)
|
||||
.eq("display_mode", args.displayMode),
|
||||
)
|
||||
.first();
|
||||
|
||||
if (existing) {
|
||||
await ctx.db.patch(existing._id, {
|
||||
alias: args.alias ?? null,
|
||||
is_previewable: Boolean(args.isPreviewable),
|
||||
updated_at: ts,
|
||||
});
|
||||
return {
|
||||
id: existing.id,
|
||||
workspace_id: existing.workspace_id,
|
||||
source_page_id: existing.source_page_id,
|
||||
source_block_id: existing.source_block_id,
|
||||
target_page_id: existing.target_page_id,
|
||||
alias: args.alias ?? null,
|
||||
display_mode: existing.display_mode,
|
||||
is_previewable: Boolean(args.isPreviewable),
|
||||
created_at: existing.created_at,
|
||||
updated_at: ts,
|
||||
};
|
||||
}
|
||||
|
||||
// 说明:id 使用可读的组合键,便于调试;并不要求前端依赖该规则。
|
||||
const id = `ref:${args.workspaceId}:${args.sourcePageId}:${args.sourceBlockId ?? "page"}:${args.targetPageId}:${args.displayMode}:${ts}`;
|
||||
|
||||
await ctx.db.insert("page_references", {
|
||||
id,
|
||||
workspace_id: args.workspaceId,
|
||||
source_page_id: args.sourcePageId,
|
||||
source_block_id: args.sourceBlockId ?? null,
|
||||
target_page_id: args.targetPageId,
|
||||
alias: args.alias ?? null,
|
||||
display_mode: args.displayMode,
|
||||
is_previewable: Boolean(args.isPreviewable),
|
||||
created_by: args.userId,
|
||||
created_at: ts,
|
||||
updated_at: ts,
|
||||
});
|
||||
|
||||
return {
|
||||
id,
|
||||
workspace_id: args.workspaceId,
|
||||
source_page_id: args.sourcePageId,
|
||||
source_block_id: args.sourceBlockId ?? null,
|
||||
target_page_id: args.targetPageId,
|
||||
alias: args.alias ?? null,
|
||||
display_mode: args.displayMode,
|
||||
is_previewable: Boolean(args.isPreviewable),
|
||||
created_at: ts,
|
||||
updated_at: ts,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const listBacklinks = query({
|
||||
args: {
|
||||
userId: v.string(),
|
||||
workspaceId: v.string(),
|
||||
pageId: v.string(),
|
||||
limit: v.optional(v.number()),
|
||||
offset: v.optional(v.number()),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
|
||||
|
||||
const limit = Math.max(1, Math.min(200, Math.floor(args.limit ?? 50)));
|
||||
const offset = Math.max(0, Math.floor(args.offset ?? 0));
|
||||
|
||||
const rows = await ctx.db
|
||||
.query("page_references")
|
||||
.withIndex("by_workspace_target", (q) => q.eq("workspace_id", args.workspaceId).eq("target_page_id", args.pageId))
|
||||
.order("desc")
|
||||
.take(limit + offset + 200);
|
||||
|
||||
const sliced = rows.slice(offset, offset + limit);
|
||||
const sourceIds = Array.from(new Set(sliced.map((r) => String((r as any).source_page_id ?? "")).filter(Boolean)));
|
||||
|
||||
const sourceTitleById = new Map<string, string | null>();
|
||||
for (const sid of sourceIds) {
|
||||
const doc = await ctx.db.query("documents").withIndex("by_document_id", (q) => q.eq("id", sid)).first();
|
||||
sourceTitleById.set(sid, doc ? (doc.title ?? null) : null);
|
||||
}
|
||||
|
||||
return sliced.map((row) => {
|
||||
const r = row as any;
|
||||
return {
|
||||
id: r.id,
|
||||
source_page_id: r.source_page_id,
|
||||
source_block_id: r.source_block_id ?? null,
|
||||
alias: r.alias ?? null,
|
||||
display_mode: r.display_mode,
|
||||
is_previewable: Boolean(r.is_previewable),
|
||||
created_at: r.created_at,
|
||||
updated_at: r.updated_at,
|
||||
source_title: sourceTitleById.get(String(r.source_page_id ?? "")) ?? null,
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user