0.3.5 共享功能修复
This commit is contained in:
@@ -62,6 +62,8 @@ export const listByDocument = query({
|
||||
username: user?.name ?? null,
|
||||
permission: share.permission,
|
||||
includeDescendants: share.include_descendants,
|
||||
disableDownload: Boolean((share as any).disable_download),
|
||||
disableCopy: Boolean((share as any).disable_copy),
|
||||
createdAt: share.created_at,
|
||||
updatedAt: share.updated_at,
|
||||
});
|
||||
@@ -77,6 +79,8 @@ export const upsert = mutation({
|
||||
username: v.string(),
|
||||
permission,
|
||||
includeDescendants: v.optional(v.boolean()),
|
||||
disableDownload: v.optional(v.boolean()),
|
||||
disableCopy: v.optional(v.boolean()),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const userId = await requireUserId(ctx);
|
||||
@@ -86,6 +90,8 @@ export const upsert = mutation({
|
||||
|
||||
const ts = nowIso();
|
||||
const includeDescendants = Boolean(args.includeDescendants);
|
||||
const disableDownload = Boolean(args.disableDownload);
|
||||
const disableCopy = Boolean(args.disableCopy);
|
||||
|
||||
// 确保对方成为 workspace member(否则无法看到该 workspace 的数据)
|
||||
const existingMember = await ctx.db
|
||||
@@ -113,6 +119,8 @@ export const upsert = mutation({
|
||||
await ctx.db.patch(existingShare._id, {
|
||||
permission: args.permission,
|
||||
include_descendants: includeDescendants,
|
||||
disable_download: disableDownload,
|
||||
disable_copy: disableCopy,
|
||||
updated_at: ts,
|
||||
});
|
||||
} else {
|
||||
@@ -122,6 +130,8 @@ export const upsert = mutation({
|
||||
shared_with_user_id: sharedWithUserId,
|
||||
permission: args.permission,
|
||||
include_descendants: includeDescendants,
|
||||
disable_download: disableDownload,
|
||||
disable_copy: disableCopy,
|
||||
created_by: userId,
|
||||
created_at: ts,
|
||||
updated_at: ts,
|
||||
@@ -210,3 +220,137 @@ export const listShareRootsByWorkspace = query({
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const listMyShareRoots = query({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const userId = await requireUserId(ctx);
|
||||
|
||||
const incomingRows = await ctx.db
|
||||
.query("document_shares")
|
||||
.withIndex("by_shared_with_user", (q: any) => q.eq("shared_with_user_id", userId))
|
||||
.collect();
|
||||
|
||||
// 说明:只统计“我共享出去的”(自己是 created_by);用于顶部共享面板展示摘要。
|
||||
const outgoingRows = await ctx.db
|
||||
.query("document_shares")
|
||||
.withIndex("by_created_by", (q: any) => q.eq("created_by", userId))
|
||||
.collect();
|
||||
|
||||
// 说明:去重/合并:同一页面共享给多个用户时,只展示一条,并累计 sharedWithCount。
|
||||
const outgoingByKey = new Map<
|
||||
string,
|
||||
{
|
||||
workspaceId: string;
|
||||
documentId: string;
|
||||
includeDescendants: boolean;
|
||||
sharedWithCount: number;
|
||||
updatedAt: string;
|
||||
}
|
||||
>();
|
||||
|
||||
for (const row of outgoingRows) {
|
||||
const key = `${row.workspace_id}:${row.document_id}`;
|
||||
const existing = outgoingByKey.get(key);
|
||||
if (!existing) {
|
||||
outgoingByKey.set(key, {
|
||||
workspaceId: row.workspace_id,
|
||||
documentId: row.document_id,
|
||||
includeDescendants: Boolean(row.include_descendants),
|
||||
sharedWithCount: 1,
|
||||
updatedAt: String(row.updated_at ?? ""),
|
||||
});
|
||||
} else {
|
||||
existing.includeDescendants = existing.includeDescendants || Boolean(row.include_descendants);
|
||||
existing.sharedWithCount += 1;
|
||||
const u = String(row.updated_at ?? "");
|
||||
if (u && u.localeCompare(existing.updatedAt) > 0) {
|
||||
existing.updatedAt = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const workspaceNameCache = new Map<string, string | null>();
|
||||
const getWorkspaceName = async (workspaceId: string): Promise<string | null> => {
|
||||
const cached = workspaceNameCache.get(workspaceId);
|
||||
if (workspaceNameCache.has(workspaceId)) return cached ?? null;
|
||||
const ws = await ctx.db
|
||||
.query("workspaces")
|
||||
.withIndex("by_workspace_id", (q: any) => q.eq("id", workspaceId))
|
||||
.first();
|
||||
const name = ws?.name ?? null;
|
||||
workspaceNameCache.set(workspaceId, name);
|
||||
return name;
|
||||
};
|
||||
|
||||
const documentCache = new Map<
|
||||
string,
|
||||
{ exists: boolean; deleted: boolean; title: string | null }
|
||||
>();
|
||||
const getDocumentInfo = async (
|
||||
documentId: string,
|
||||
): Promise<{ exists: boolean; deleted: boolean; title: string | null }> => {
|
||||
const cached = documentCache.get(documentId);
|
||||
if (documentCache.has(documentId)) {
|
||||
return cached ?? { exists: false, deleted: true, title: null };
|
||||
}
|
||||
const doc = await ctx.db
|
||||
.query("documents")
|
||||
.withIndex("by_document_id", (q: any) => q.eq("id", documentId))
|
||||
.first();
|
||||
const info = doc
|
||||
? { exists: true, deleted: doc.deleted_at != null, title: (doc.title ?? null) as string | null }
|
||||
: { exists: false, deleted: true, title: null };
|
||||
documentCache.set(documentId, info);
|
||||
return info;
|
||||
};
|
||||
|
||||
const incoming = [];
|
||||
for (const row of incomingRows) {
|
||||
// 说明:若对方仅写入了 share 但没把我加入 workspace,则这里会被文档/页面接口挡住;
|
||||
// 为避免面板出现“打不开的幽灵分享”,这里要求我确实是 workspace member。
|
||||
const member = await ctx.db
|
||||
.query("workspace_members")
|
||||
.withIndex("by_workspace_user", (q: any) => q.eq("workspace_id", row.workspace_id).eq("user_id", userId))
|
||||
.first();
|
||||
if (!member) continue;
|
||||
|
||||
const docInfo = await getDocumentInfo(row.document_id);
|
||||
if (!docInfo.exists) continue;
|
||||
if (docInfo.deleted) continue;
|
||||
|
||||
incoming.push({
|
||||
workspaceId: row.workspace_id,
|
||||
workspaceName: await getWorkspaceName(row.workspace_id),
|
||||
documentId: row.document_id,
|
||||
documentTitle: docInfo.title,
|
||||
permission: row.permission,
|
||||
includeDescendants: row.include_descendants,
|
||||
createdBy: row.created_by,
|
||||
updatedAt: row.updated_at,
|
||||
});
|
||||
}
|
||||
|
||||
const outgoing = [];
|
||||
for (const v of outgoingByKey.values()) {
|
||||
const docInfo = await getDocumentInfo(v.documentId);
|
||||
if (!docInfo.exists) continue;
|
||||
if (docInfo.deleted) continue;
|
||||
|
||||
outgoing.push({
|
||||
workspaceId: v.workspaceId,
|
||||
workspaceName: await getWorkspaceName(v.workspaceId),
|
||||
documentId: v.documentId,
|
||||
documentTitle: docInfo.title,
|
||||
includeDescendants: v.includeDescendants,
|
||||
sharedWithCount: v.sharedWithCount,
|
||||
updatedAt: v.updatedAt,
|
||||
});
|
||||
}
|
||||
|
||||
incoming.sort((a: any, b: any) => String(b.updatedAt ?? "").localeCompare(String(a.updatedAt ?? "")));
|
||||
outgoing.sort((a: any, b: any) => String(b.updatedAt ?? "").localeCompare(String(a.updatedAt ?? "")));
|
||||
|
||||
return { incoming, outgoing };
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user