feat(server): page model (#9715)

This commit is contained in:
fengmk2
2025-01-17 06:16:51 +00:00
parent 5c934c64aa
commit 46aa25de0b
5 changed files with 441 additions and 0 deletions

View File

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

View File

@@ -0,0 +1,4 @@
export enum PublicPageMode {
Page,
Edgeless,
}

View File

@@ -8,6 +8,7 @@ import { ModuleRef } from '@nestjs/core';
import { ApplyType } from '../base';
import { FeatureModel } from './feature';
import { PageModel } from './page';
import { MODELS_SYMBOL } from './provider';
import { SessionModel } from './session';
import { UserModel } from './user';
@@ -20,6 +21,7 @@ const MODELS = {
verificationToken: VerificationTokenModel,
feature: FeatureModel,
workspace: WorkspaceModel,
page: PageModel,
};
type ModelsType = {
@@ -72,6 +74,7 @@ const ModelsSymbolProvider: ExistingProvider = {
export class ModelModules {}
export * from './feature';
export * from './page';
export * from './session';
export * from './user';
export * from './verification-token';

View File

@@ -0,0 +1,201 @@
import { Injectable } from '@nestjs/common';
import {
type WorkspacePage as Page,
type WorkspacePageUserPermission as PageUserPermission,
} from '@prisma/client';
import { BaseModel } from './base';
import { Permission, PublicPageMode } from './common';
export type { Page };
export type UpdatePageInput = {
mode?: PublicPageMode;
public?: boolean;
};
@Injectable()
export class PageModel extends BaseModel {
// #region page
/**
* Create or update the page.
*/
async upsert(workspaceId: string, pageId: string, data?: UpdatePageInput) {
return await this.db.workspacePage.upsert({
where: {
workspaceId_pageId: {
workspaceId,
pageId,
},
},
update: {
...data,
},
create: {
...data,
workspaceId,
pageId,
},
});
}
/**
* Get the page.
* @param isPublic: if true, only return the public page. If false, only return the private page.
* If not set, return public or private both.
*/
async get(workspaceId: string, pageId: string, isPublic?: boolean) {
return await this.db.workspacePage.findUnique({
where: {
workspaceId_pageId: {
workspaceId,
pageId,
},
public: isPublic,
},
});
}
/**
* Find the workspace public pages.
*/
async findPublics(workspaceId: string) {
return await this.db.workspacePage.findMany({
where: {
workspaceId,
public: true,
},
});
}
/**
* Get the workspace public pages count.
*/
async getPublicsCount(workspaceId: string) {
return await this.db.workspacePage.count({
where: {
workspaceId,
public: true,
},
});
}
// #endregion
// #region page member and permission
/**
* Grant the page member with the given permission.
*/
async grantMember(
workspaceId: string,
pageId: string,
userId: string,
permission: Permission = Permission.Read
): Promise<PageUserPermission> {
let data = await this.db.workspacePageUserPermission.findUnique({
where: {
workspaceId_pageId_userId: {
workspaceId,
pageId,
userId,
},
},
});
// If the user is already accepted and the new permission is owner, we need to revoke old owner
if (!data || data.type !== permission) {
return await this.db.$transaction(async tx => {
if (data) {
// Update the permission
data = await tx.workspacePageUserPermission.update({
where: {
workspaceId_pageId_userId: {
workspaceId,
pageId,
userId,
},
},
data: { type: permission },
});
} else {
// Create a new permission
data = await tx.workspacePageUserPermission.create({
data: {
workspaceId,
pageId,
userId,
type: permission,
// page permission does not require invitee to accept, the accepted field will be deprecated later.
accepted: true,
},
});
}
// If the new permission is owner, we need to revoke old owner
if (permission === Permission.Owner) {
await tx.workspacePageUserPermission.updateMany({
where: {
workspaceId,
pageId,
type: Permission.Owner,
userId: { not: userId },
},
data: { type: Permission.Admin },
});
this.logger.log(
`Change owner of workspace ${workspaceId} page ${pageId} to user ${userId}`
);
}
return data;
});
}
// nothing to do
return data;
}
/**
* Returns whether a given user is a member of a workspace and has the given or higher permission.
* Default to read permission.
*/
async isMember(
workspaceId: string,
pageId: string,
userId: string,
permission: Permission = Permission.Read
) {
const count = await this.db.workspacePageUserPermission.count({
where: {
workspaceId,
pageId,
userId,
type: {
gte: permission,
},
},
});
return count > 0;
}
/**
* Delete a page member
* Except the owner, the owner can't be deleted.
*/
async deleteMember(workspaceId: string, pageId: string, userId: string) {
const { count } = await this.db.workspacePageUserPermission.deleteMany({
where: {
workspaceId,
pageId,
userId,
type: {
// We shouldn't revoke owner permission, should auto deleted by workspace/user delete cascading
not: Permission.Owner,
},
},
});
return count;
}
// #endregion
}