mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 20:38:52 +00:00
feat(server): make permission a standalone module (#7880)
This commit is contained in:
@@ -11,10 +11,9 @@ import {
|
||||
DocNotFound,
|
||||
metrics,
|
||||
OnEvent,
|
||||
WorkspaceNotFound,
|
||||
} from '../../fundamentals';
|
||||
import { PermissionService } from '../permission';
|
||||
import { QuotaService } from '../quota';
|
||||
import { Permission } from '../workspaces/types';
|
||||
import { isEmptyBuffer } from './manager';
|
||||
|
||||
@Injectable()
|
||||
@@ -23,7 +22,8 @@ export class DocHistoryManager {
|
||||
constructor(
|
||||
private readonly config: Config,
|
||||
private readonly db: PrismaClient,
|
||||
private readonly quota: QuotaService
|
||||
private readonly quota: QuotaService,
|
||||
private readonly permission: PermissionService
|
||||
) {}
|
||||
|
||||
@OnEvent('workspace.deleted')
|
||||
@@ -235,21 +235,8 @@ export class DocHistoryManager {
|
||||
}
|
||||
|
||||
async getExpiredDateFromNow(workspaceId: string) {
|
||||
const permission = await this.db.workspaceUserPermission.findFirst({
|
||||
select: {
|
||||
userId: true,
|
||||
},
|
||||
where: {
|
||||
workspaceId,
|
||||
type: Permission.Owner,
|
||||
},
|
||||
});
|
||||
|
||||
if (!permission) {
|
||||
throw new WorkspaceNotFound({ workspaceId });
|
||||
}
|
||||
|
||||
const quota = await this.quota.getUserQuota(permission.userId);
|
||||
const owner = await this.permission.getWorkspaceOwner(workspaceId);
|
||||
const quota = await this.quota.getUserQuota(owner.id);
|
||||
return quota.feature.historyPeriodFromNow;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ import './config';
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { PermissionModule } from '../permission';
|
||||
import { QuotaModule } from '../quota';
|
||||
import { DocHistoryManager } from './history';
|
||||
import { DocManager } from './manager';
|
||||
|
||||
@Module({
|
||||
imports: [QuotaModule],
|
||||
imports: [QuotaModule, PermissionModule],
|
||||
providers: [DocManager, DocHistoryManager],
|
||||
exports: [DocManager, DocHistoryManager],
|
||||
})
|
||||
|
||||
12
packages/backend/server/src/core/permission/index.ts
Normal file
12
packages/backend/server/src/core/permission/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { PermissionService } from './service';
|
||||
|
||||
@Module({
|
||||
providers: [PermissionService],
|
||||
exports: [PermissionService],
|
||||
})
|
||||
export class PermissionModule {}
|
||||
|
||||
export { PermissionService } from './service';
|
||||
export { Permission, PublicPageMode } from './types';
|
||||
@@ -2,13 +2,12 @@ import { Injectable } from '@nestjs/common';
|
||||
import type { Prisma } from '@prisma/client';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
import { DocAccessDenied, WorkspaceAccessDenied } from '../../fundamentals';
|
||||
import { Permission } from './types';
|
||||
|
||||
export enum PublicPageMode {
|
||||
Page,
|
||||
Edgeless,
|
||||
}
|
||||
import {
|
||||
DocAccessDenied,
|
||||
WorkspaceAccessDenied,
|
||||
WorkspaceOwnerNotFound,
|
||||
} from '../../fundamentals';
|
||||
import { Permission, PublicPageMode } from './types';
|
||||
|
||||
@Injectable()
|
||||
export class PermissionService {
|
||||
@@ -59,7 +58,7 @@ export class PermissionService {
|
||||
}
|
||||
|
||||
async getWorkspaceOwner(workspaceId: string) {
|
||||
return this.prisma.workspaceUserPermission.findFirstOrThrow({
|
||||
const owner = await this.prisma.workspaceUserPermission.findFirst({
|
||||
where: {
|
||||
workspaceId,
|
||||
type: Permission.Owner,
|
||||
@@ -68,6 +67,12 @@ export class PermissionService {
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!owner) {
|
||||
throw new WorkspaceOwnerNotFound({ workspaceId });
|
||||
}
|
||||
|
||||
return owner.user;
|
||||
}
|
||||
|
||||
async tryGetWorkspaceOwner(workspaceId: string) {
|
||||
@@ -195,6 +200,17 @@ export class PermissionService {
|
||||
return false;
|
||||
}
|
||||
|
||||
async allowUrlPreview(ws: string) {
|
||||
const count = await this.prisma.workspace.count({
|
||||
where: {
|
||||
id: ws,
|
||||
public: true,
|
||||
},
|
||||
});
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
async grant(
|
||||
ws: string,
|
||||
user: string,
|
||||
11
packages/backend/server/src/core/permission/types.ts
Normal file
11
packages/backend/server/src/core/permission/types.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export enum Permission {
|
||||
Read = 0,
|
||||
Write = 1,
|
||||
Admin = 10,
|
||||
Owner = 99,
|
||||
}
|
||||
|
||||
export enum PublicPageMode {
|
||||
Page,
|
||||
Edgeless,
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { FeatureModule } from '../features';
|
||||
import { PermissionModule } from '../permission';
|
||||
import { StorageModule } from '../storage';
|
||||
import { PermissionService } from '../workspaces/permission';
|
||||
import { QuotaManagementResolver } from './resolver';
|
||||
import { QuotaService } from './service';
|
||||
import { QuotaManagementService } from './storage';
|
||||
@@ -14,13 +14,8 @@ import { QuotaManagementService } from './storage';
|
||||
* - quota statistics
|
||||
*/
|
||||
@Module({
|
||||
imports: [FeatureModule, StorageModule],
|
||||
providers: [
|
||||
PermissionService,
|
||||
QuotaService,
|
||||
QuotaManagementResolver,
|
||||
QuotaManagementService,
|
||||
],
|
||||
imports: [FeatureModule, StorageModule, PermissionModule],
|
||||
providers: [QuotaService, QuotaManagementResolver, QuotaManagementService],
|
||||
exports: [QuotaService, QuotaManagementService],
|
||||
})
|
||||
export class QuotaModule {}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { WorkspaceOwnerNotFound } from '../../fundamentals';
|
||||
import { FeatureService, FeatureType } from '../features';
|
||||
import { PermissionService } from '../permission';
|
||||
import { WorkspaceBlobStorage } from '../storage';
|
||||
import { PermissionService } from '../workspaces/permission';
|
||||
import { OneGB } from './constant';
|
||||
import { QuotaService } from './service';
|
||||
import { formatSize, QuotaQueryType } from './types';
|
||||
@@ -113,9 +112,7 @@ export class QuotaManagementService {
|
||||
// get workspace's owner quota and total size of used
|
||||
// quota was apply to owner's account
|
||||
async getWorkspaceUsage(workspaceId: string): Promise<QuotaBusinessType> {
|
||||
const { user: owner } =
|
||||
await this.permissions.getWorkspaceOwner(workspaceId);
|
||||
if (!owner) throw new WorkspaceOwnerNotFound({ workspaceId });
|
||||
const owner = await this.permissions.getWorkspaceOwner(workspaceId);
|
||||
const {
|
||||
feature: {
|
||||
name,
|
||||
|
||||
@@ -23,9 +23,8 @@ import {
|
||||
} from '../../../fundamentals';
|
||||
import { Auth, CurrentUser } from '../../auth';
|
||||
import { DocManager } from '../../doc';
|
||||
import { Permission, PermissionService } from '../../permission';
|
||||
import { DocID } from '../../utils/doc';
|
||||
import { PermissionService } from '../../workspaces/permission';
|
||||
import { Permission } from '../../workspaces/types';
|
||||
|
||||
const SubscribeMessage = (event: string) =>
|
||||
applyDecorators(
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { DocModule } from '../../doc';
|
||||
import { PermissionService } from '../../workspaces/permission';
|
||||
import { PermissionModule } from '../../permission';
|
||||
import { EventsGateway } from './events.gateway';
|
||||
|
||||
@Module({
|
||||
imports: [DocModule],
|
||||
providers: [EventsGateway, PermissionService],
|
||||
imports: [DocModule, PermissionModule],
|
||||
providers: [EventsGateway],
|
||||
})
|
||||
export class EventsModule {}
|
||||
|
||||
@@ -13,10 +13,9 @@ import {
|
||||
} from '../../fundamentals';
|
||||
import { CurrentUser, Public } from '../auth';
|
||||
import { DocHistoryManager, DocManager } from '../doc';
|
||||
import { Permission, PermissionService, PublicPageMode } from '../permission';
|
||||
import { WorkspaceBlobStorage } from '../storage';
|
||||
import { DocID } from '../utils/doc';
|
||||
import { PermissionService, PublicPageMode } from './permission';
|
||||
import { Permission } from './types';
|
||||
|
||||
@Controller('/api/workspaces')
|
||||
export class WorkspacesController {
|
||||
|
||||
@@ -2,12 +2,12 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { DocModule } from '../doc';
|
||||
import { FeatureModule } from '../features';
|
||||
import { PermissionModule } from '../permission';
|
||||
import { QuotaModule } from '../quota';
|
||||
import { StorageModule } from '../storage';
|
||||
import { UserModule } from '../user';
|
||||
import { WorkspacesController } from './controller';
|
||||
import { WorkspaceManagementResolver } from './management';
|
||||
import { PermissionService } from './permission';
|
||||
import {
|
||||
DocHistoryResolver,
|
||||
PagePermissionResolver,
|
||||
@@ -16,17 +16,22 @@ import {
|
||||
} from './resolvers';
|
||||
|
||||
@Module({
|
||||
imports: [DocModule, FeatureModule, QuotaModule, StorageModule, UserModule],
|
||||
imports: [
|
||||
DocModule,
|
||||
FeatureModule,
|
||||
QuotaModule,
|
||||
StorageModule,
|
||||
UserModule,
|
||||
PermissionModule,
|
||||
],
|
||||
controllers: [WorkspacesController],
|
||||
providers: [
|
||||
WorkspaceResolver,
|
||||
WorkspaceManagementResolver,
|
||||
PermissionService,
|
||||
PagePermissionResolver,
|
||||
DocHistoryResolver,
|
||||
WorkspaceBlobResolver,
|
||||
],
|
||||
exports: [PermissionService],
|
||||
})
|
||||
export class WorkspaceModule {}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ActionForbidden } from '../../fundamentals';
|
||||
import { CurrentUser } from '../auth';
|
||||
import { Admin } from '../common';
|
||||
import { FeatureManagementService, FeatureType } from '../features';
|
||||
import { PermissionService } from './permission';
|
||||
import { PermissionService } from '../permission';
|
||||
import { WorkspaceType } from './types';
|
||||
|
||||
@Resolver(() => WorkspaceType)
|
||||
@@ -61,7 +61,7 @@ export class WorkspaceManagementResolver {
|
||||
|
||||
const owner = await this.permission.getWorkspaceOwner(workspaceId);
|
||||
const availableFeatures = await this.availableFeatures(user);
|
||||
if (owner.user.id !== user.id || !availableFeatures.includes(feature)) {
|
||||
if (owner.id !== user.id || !availableFeatures.includes(feature)) {
|
||||
throw new ActionForbidden();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ import {
|
||||
PreventCache,
|
||||
} from '../../../fundamentals';
|
||||
import { CurrentUser } from '../../auth';
|
||||
import { Permission, PermissionService } from '../../permission';
|
||||
import { QuotaManagementService } from '../../quota';
|
||||
import { WorkspaceBlobStorage } from '../../storage';
|
||||
import { PermissionService } from '../permission';
|
||||
import { Permission, WorkspaceBlobSizes, WorkspaceType } from '../types';
|
||||
import { WorkspaceBlobSizes, WorkspaceType } from '../types';
|
||||
|
||||
@UseGuards(CloudThrottlerGuard)
|
||||
@Resolver(() => WorkspaceType)
|
||||
|
||||
@@ -13,9 +13,9 @@ import type { SnapshotHistory } from '@prisma/client';
|
||||
|
||||
import { CurrentUser } from '../../auth';
|
||||
import { DocHistoryManager } from '../../doc';
|
||||
import { Permission, PermissionService } from '../../permission';
|
||||
import { DocID } from '../../utils/doc';
|
||||
import { PermissionService } from '../permission';
|
||||
import { Permission, WorkspaceType } from '../types';
|
||||
import { WorkspaceType } from '../types';
|
||||
|
||||
@ObjectType()
|
||||
class DocHistoryType implements Partial<SnapshotHistory> {
|
||||
|
||||
@@ -17,9 +17,13 @@ import {
|
||||
PageIsNotPublic,
|
||||
} from '../../../fundamentals';
|
||||
import { CurrentUser } from '../../auth';
|
||||
import {
|
||||
Permission,
|
||||
PermissionService,
|
||||
PublicPageMode,
|
||||
} from '../../permission';
|
||||
import { DocID } from '../../utils/doc';
|
||||
import { PermissionService, PublicPageMode } from '../permission';
|
||||
import { Permission, WorkspaceType } from '../types';
|
||||
import { WorkspaceType } from '../types';
|
||||
|
||||
registerEnumType(PublicPageMode, {
|
||||
name: 'PublicPageMode',
|
||||
|
||||
@@ -26,17 +26,15 @@ import {
|
||||
UserNotFound,
|
||||
WorkspaceAccessDenied,
|
||||
WorkspaceNotFound,
|
||||
WorkspaceOwnerNotFound,
|
||||
} from '../../../fundamentals';
|
||||
import { CurrentUser, Public } from '../../auth';
|
||||
import { Permission, PermissionService } from '../../permission';
|
||||
import { QuotaManagementService, QuotaQueryType } from '../../quota';
|
||||
import { WorkspaceBlobStorage } from '../../storage';
|
||||
import { UserService, UserType } from '../../user';
|
||||
import { PermissionService } from '../permission';
|
||||
import {
|
||||
InvitationType,
|
||||
InviteUserType,
|
||||
Permission,
|
||||
UpdateWorkspaceInput,
|
||||
WorkspaceType,
|
||||
} from '../types';
|
||||
@@ -101,9 +99,7 @@ export class WorkspaceResolver {
|
||||
complexity: 2,
|
||||
})
|
||||
async owner(@Parent() workspace: WorkspaceType) {
|
||||
const data = await this.permissions.getWorkspaceOwner(workspace.id);
|
||||
|
||||
return data.user;
|
||||
return this.permissions.getWorkspaceOwner(workspace.id);
|
||||
}
|
||||
|
||||
@ResolveField(() => [InviteUserType], {
|
||||
@@ -449,7 +445,7 @@ export class WorkspaceResolver {
|
||||
avatar: avatar || defaultWorkspaceAvatar,
|
||||
id: workspaceId,
|
||||
},
|
||||
user: owner.user,
|
||||
user: owner,
|
||||
invitee: invitee.user,
|
||||
};
|
||||
}
|
||||
@@ -507,12 +503,8 @@ export class WorkspaceResolver {
|
||||
|
||||
const owner = await this.permissions.getWorkspaceOwner(workspaceId);
|
||||
|
||||
if (!owner.user) {
|
||||
throw new WorkspaceOwnerNotFound({ workspaceId: workspaceId });
|
||||
}
|
||||
|
||||
if (sendLeaveMail) {
|
||||
await this.mailer.sendLeaveWorkspaceEmail(owner.user.email, {
|
||||
await this.mailer.sendLeaveWorkspaceEmail(owner.email, {
|
||||
workspaceName,
|
||||
inviteeName: user.name,
|
||||
});
|
||||
|
||||
@@ -11,15 +11,9 @@ import {
|
||||
import type { Workspace } from '@prisma/client';
|
||||
import { SafeIntResolver } from 'graphql-scalars';
|
||||
|
||||
import { Permission } from '../permission';
|
||||
import { UserType } from '../user/types';
|
||||
|
||||
export enum Permission {
|
||||
Read = 0,
|
||||
Write = 1,
|
||||
Admin = 10,
|
||||
Owner = 99,
|
||||
}
|
||||
|
||||
registerEnumType(Permission, {
|
||||
name: 'Permission',
|
||||
description: 'User permission in workspace',
|
||||
|
||||
Reference in New Issue
Block a user