Files
mnote/wolai-frontend/convex/pages.ts
T
2026-04-13 19:21:42 +08:00

151 lines
3.8 KiB
TypeScript

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;
}
export const getById = query({
args: {
userId: v.string(),
workspaceId: v.string(),
id: v.string(),
},
handler: async (ctx, args) => {
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
return await ctx.db
.query("pages")
.withIndex("by_page_id", (q) => q.eq("id", args.id))
.first();
},
});
export const listByWorkspace = query({
args: {
userId: v.string(),
workspaceId: v.string(),
},
handler: async (ctx, args) => {
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
return await ctx.db
.query("pages")
.withIndex("by_workspace", (q) => q.eq("workspace_id", args.workspaceId))
.collect();
},
});
export const create = mutation({
args: {
userId: v.string(),
id: v.string(),
workspaceId: v.string(),
parentId: v.union(v.string(), v.null()),
title: v.string(),
accessScope: v.union(
v.literal("private"),
v.literal("shared"),
v.literal("public"),
),
},
handler: async (ctx, args) => {
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
const ts = nowIso();
await ctx.db.insert("pages", {
id: args.id,
workspace_id: args.workspaceId,
parent_id: args.parentId,
title: args.title,
access_scope: args.accessScope,
block_ids: [],
child_page_ids: [],
asset_ids: [],
created_by: args.userId,
created_at: ts,
updated_at: ts,
deleted_at: null,
});
return { ok: true, id: args.id };
},
});
export const rename = mutation({
args: {
userId: v.string(),
workspaceId: v.string(),
id: v.string(),
title: v.string(),
},
handler: async (ctx, args) => {
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
const page = await ctx.db
.query("pages")
.withIndex("by_page_id", (q) => q.eq("id", args.id))
.first();
if (!page) throw new Error("页面不存在");
await ctx.db.patch(page._id, {
title: args.title,
updated_at: nowIso(),
});
return { ok: true };
},
});
export const move = mutation({
args: {
userId: v.string(),
workspaceId: v.string(),
id: v.string(),
parentId: v.union(v.string(), v.null()),
},
handler: async (ctx, args) => {
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
const page = await ctx.db
.query("pages")
.withIndex("by_page_id", (q) => q.eq("id", args.id))
.first();
if (!page) throw new Error("页面不存在");
await ctx.db.patch(page._id, {
parent_id: args.parentId,
updated_at: nowIso(),
});
return { ok: true };
},
});
export const archive = mutation({
args: {
userId: v.string(),
workspaceId: v.string(),
id: v.string(),
},
handler: async (ctx, args) => {
await assertWorkspaceMember(ctx, args.userId, args.workspaceId);
const page = await ctx.db
.query("pages")
.withIndex("by_page_id", (q) => q.eq("id", args.id))
.first();
if (!page) throw new Error("页面不存在");
const ts = nowIso();
await ctx.db.patch(page._id, {
deleted_at: ts,
updated_at: ts,
});
return { ok: true };
},
});