feat(server): filter docs by access role (#12311)

close CLOUD-208

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Enhanced document access control with batch permission checks, enabling efficient filtering of documents based on user roles and permissions.
  - Added detailed document-level role and permission management for workspace users.
- **Bug Fixes**
  - Improved accuracy in filtering search results to only display documents users have permission to read.
- **Tests**
  - Added comprehensive tests for document-level permission filtering and search result accuracy.
  - Introduced new mock utilities to support permission-related test scenarios.
- **Refactor**
  - Simplified and optimized permission logic for determining user roles and document access.
- **Documentation**
  - Updated type definitions for improved clarity in permission handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
fengmk2
2025-05-19 03:28:22 +00:00
parent 85bb728ca8
commit 1e7774929c
16 changed files with 703 additions and 87 deletions

View File

@@ -378,6 +378,26 @@ export class DocModel extends BaseModel {
});
}
async findDefaultRoles(workspaceId: string, docIds: string[]) {
const docs = await this.findMetas(
docIds.map(docId => ({
workspaceId,
docId,
})),
{
select: {
defaultRole: true,
public: true,
},
}
);
return docs.map(doc => ({
external: doc?.public ? DocRole.External : null,
workspace: doc?.defaultRole ?? DocRole.Manager,
}));
}
async findAuthors(ids: { workspaceId: string; docId: string }[]) {
const rows = await this.db.snapshot.findMany({
where: {
@@ -401,13 +421,29 @@ export class DocModel extends BaseModel {
);
}
async findMetas(ids: { workspaceId: string; docId: string }[]) {
const rows = await this.db.workspaceDoc.findMany({
async findMetas<Select extends Prisma.WorkspaceDocSelect>(
ids: { workspaceId: string; docId: string }[],
options?: { select?: Select }
) {
let select = options?.select;
if (select) {
// add workspaceId and docId to the select
select = {
...select,
workspaceId: true,
docId: true,
};
}
const rows = (await this.db.workspaceDoc.findMany({
where: {
workspaceId: { in: ids.map(id => id.workspaceId) },
docId: { in: ids.map(id => id.docId) },
},
});
select,
})) as (Prisma.WorkspaceDocGetPayload<{ select: Select }> & {
workspaceId: string;
docId: string;
})[];
const resultMap = new Map(
rows.map(row => [`${row.workspaceId}-${row.docId}`, row])
);