feat(server): doc level permission (#9760)

close CLOUD-89 CLOUD-90 CLOUD-91 CLOUD-92
This commit is contained in:
Brooooooklyn
2025-02-05 07:06:57 +00:00
parent 64de83b13d
commit abeff8bb1a
36 changed files with 2257 additions and 324 deletions

View File

@@ -1,3 +1,2 @@
export * from './feature';
export * from './page';
export * from './permission';

View File

@@ -1,6 +0,0 @@
export enum Permission {
Read = 0,
Write = 1,
Admin = 10,
Owner = 99,
}

View File

@@ -5,9 +5,9 @@ import {
type WorkspacePageUserPermission as PageUserPermission,
} from '@prisma/client';
import { WorkspaceRole } from '../core/permission';
import { BaseModel } from './base';
import { Permission, PublicPageMode } from './common';
import { PublicPageMode } from './common';
export type { Page };
export type UpdatePageInput = {
mode?: PublicPageMode;
@@ -93,7 +93,7 @@ export class PageModel extends BaseModel {
workspaceId: string,
pageId: string,
userId: string,
permission: Permission = Permission.Read
permission: WorkspaceRole = WorkspaceRole.Collaborator
): Promise<PageUserPermission> {
let data = await this.db.workspacePageUserPermission.findUnique({
where: {
@@ -134,15 +134,15 @@ export class PageModel extends BaseModel {
}
// If the new permission is owner, we need to revoke old owner
if (permission === Permission.Owner) {
if (permission === WorkspaceRole.Owner) {
await this.db.workspacePageUserPermission.updateMany({
where: {
workspaceId,
pageId,
type: Permission.Owner,
type: WorkspaceRole.Owner,
userId: { not: userId },
},
data: { type: Permission.Admin },
data: { type: WorkspaceRole.Admin },
});
this.logger.log(
`Change owner of workspace ${workspaceId} page ${pageId} to user ${userId}`
@@ -163,7 +163,7 @@ export class PageModel extends BaseModel {
workspaceId: string,
pageId: string,
userId: string,
permission: Permission = Permission.Read
permission: WorkspaceRole = WorkspaceRole.Collaborator
) {
const count = await this.db.workspacePageUserPermission.count({
where: {
@@ -190,7 +190,7 @@ export class PageModel extends BaseModel {
userId,
type: {
// We shouldn't revoke owner permission, should auto deleted by workspace/user delete cascading
not: Permission.Owner,
not: WorkspaceRole.Owner,
},
},
});

View File

@@ -8,8 +8,8 @@ import {
import { groupBy } from 'lodash-es';
import { EventBus } from '../base';
import { WorkspaceRole } from '../core/permission';
import { BaseModel } from './base';
import { Permission } from './common';
declare global {
interface Events {
@@ -90,7 +90,7 @@ export class WorkspaceModel extends BaseModel {
public: false,
permissions: {
create: {
type: Permission.Owner,
type: WorkspaceRole.Owner,
userId: userId,
accepted: true,
status: WorkspaceMemberStatus.Accepted,
@@ -141,7 +141,7 @@ export class WorkspaceModel extends BaseModel {
const rows = await this.db.workspaceUserPermission.findMany({
where: {
userId,
type: Permission.Owner,
type: WorkspaceRole.Owner,
OR: this.acceptedCondition,
},
select: {
@@ -177,7 +177,7 @@ export class WorkspaceModel extends BaseModel {
async grantMember(
workspaceId: string,
userId: string,
permission: Permission = Permission.Read,
permission: WorkspaceRole = WorkspaceRole.Collaborator,
status: WorkspaceMemberStatus = WorkspaceMemberStatus.Pending
): Promise<WorkspaceUserPermission> {
const data = await this.db.workspaceUserPermission.findUnique({
@@ -191,17 +191,19 @@ export class WorkspaceModel extends BaseModel {
if (!data) {
// Create a new permission
// TODO(fengmk2): should we check the permission here? Like owner can't be pending?
const created = await this.db.workspaceUserPermission.create({
data: {
workspaceId,
userId,
type: permission,
status,
status:
permission === WorkspaceRole.Owner
? WorkspaceMemberStatus.Accepted
: status,
},
});
this.logger.log(
`Granted workspace ${workspaceId} member ${userId} with permission ${permission}`
`Granted workspace ${workspaceId} member ${userId} with permission ${WorkspaceRole[permission]}`
);
await this.notifyMembersUpdated(workspaceId);
return created;
@@ -216,14 +218,14 @@ export class WorkspaceModel extends BaseModel {
data: { type: permission },
});
// If the new permission is owner, we need to revoke old owner
if (permission === Permission.Owner) {
if (permission === WorkspaceRole.Owner) {
await this.db.workspaceUserPermission.updateMany({
where: {
workspaceId,
type: Permission.Owner,
type: WorkspaceRole.Owner,
userId: { not: userId },
},
data: { type: Permission.Admin },
data: { type: WorkspaceRole.Admin },
});
this.logger.log(
`Change owner of workspace ${workspaceId} to ${userId}`
@@ -318,7 +320,7 @@ export class WorkspaceModel extends BaseModel {
async isMember(
workspaceId: string,
userId: string,
permission: Permission = Permission.Read
permission: WorkspaceRole = WorkspaceRole.Collaborator
) {
const count = await this.db.workspaceUserPermission.count({
where: {
@@ -340,7 +342,7 @@ export class WorkspaceModel extends BaseModel {
return await this.db.workspaceUserPermission.findFirst({
where: {
workspaceId,
type: Permission.Owner,
type: WorkspaceRole.Owner,
OR: this.acceptedCondition,
},
include: {
@@ -356,7 +358,7 @@ export class WorkspaceModel extends BaseModel {
return await this.db.workspaceUserPermission.findMany({
where: {
workspaceId,
type: Permission.Admin,
type: WorkspaceRole.Admin,
OR: this.acceptedCondition,
},
include: {
@@ -394,7 +396,7 @@ export class WorkspaceModel extends BaseModel {
// We shouldn't revoke owner permission
// should auto deleted by workspace/user delete cascading
if (!member || member.type === Permission.Owner) {
if (!member || member.type === WorkspaceRole.Owner) {
return false;
}