refactor(server): permission (#10449)

This commit is contained in:
liuyi
2025-03-05 15:57:00 +08:00
committed by GitHub
parent bf7b1646b3
commit 61162c59fc
61 changed files with 2680 additions and 3562 deletions

View File

@@ -31,7 +31,7 @@ import {
} from '../../base';
import { CurrentUser } from '../../core/auth';
import { Admin } from '../../core/common';
import { PermissionService } from '../../core/permission';
import { AccessController } from '../../core/permission';
import { UserType } from '../../core/user';
import { PromptService } from './prompt';
import { ChatSessionService } from './session';
@@ -299,7 +299,7 @@ export class CopilotType {
@Resolver(() => CopilotType)
export class CopilotResolver {
constructor(
private readonly permissions: PermissionService,
private readonly ac: AccessController,
private readonly mutex: RequestMutex,
private readonly chatSession: ChatSessionService,
private readonly storage: CopilotStorage
@@ -339,7 +339,11 @@ export class CopilotResolver {
@Args('options', { nullable: true }) options?: QueryChatSessionsInput
) {
if (!copilot.workspaceId) return [];
await this.permissions.checkCloudWorkspace(copilot.workspaceId, user.id);
await this.ac
.user(user.id)
.workspace(copilot.workspaceId)
.allowLocal()
.assert('Workspace.Copilot');
return await this.chatSession.listSessions(
user.id,
copilot.workspaceId,
@@ -360,14 +364,17 @@ export class CopilotResolver {
if (!workspaceId) {
return [];
} else if (docId) {
await this.permissions.checkCloudPagePermission(
workspaceId,
docId,
'Doc.Read',
user.id
);
await this.ac
.user(user.id)
.doc({ workspaceId, docId })
.allowLocal()
.assert('Doc.Read');
} else {
await this.permissions.checkCloudWorkspace(workspaceId, user.id);
await this.ac
.user(user.id)
.workspace(workspaceId)
.allowLocal()
.assert('Workspace.Copilot');
}
const histories = await this.chatSession.listHistories(
@@ -393,12 +400,7 @@ export class CopilotResolver {
@Args({ name: 'options', type: () => CreateChatSessionInput })
options: CreateChatSessionInput
) {
await this.permissions.checkCloudPagePermission(
options.workspaceId,
options.docId,
'Doc.Update',
user.id
);
await this.ac.user(user.id).doc(options).allowLocal().assert('Doc.Update');
const lockFlag = `${COPILOT_LOCKER}:session:${user.id}:${options.workspaceId}`;
await using lock = await this.mutex.acquire(lockFlag);
if (!lock) {
@@ -432,12 +434,11 @@ export class CopilotResolver {
throw new CopilotSessionNotFound();
}
const { workspaceId, docId } = session.config;
await this.permissions.checkCloudPagePermission(
workspaceId,
docId,
'Doc.Update',
user.id
);
await this.ac
.user(user.id)
.doc(workspaceId, docId)
.allowLocal()
.assert('Doc.Update');
const lockFlag = `${COPILOT_LOCKER}:session:${user.id}:${workspaceId}`;
await using lock = await this.mutex.acquire(lockFlag);
if (!lock) {
@@ -460,12 +461,7 @@ export class CopilotResolver {
@Args({ name: 'options', type: () => ForkChatSessionInput })
options: ForkChatSessionInput
) {
await this.permissions.checkCloudPagePermission(
options.workspaceId,
options.docId,
'Doc.Update',
user.id
);
await this.ac.user(user.id).doc(options).allowLocal().assert('Doc.Update');
const lockFlag = `${COPILOT_LOCKER}:session:${user.id}:${options.workspaceId}`;
await using lock = await this.mutex.acquire(lockFlag);
if (!lock) {
@@ -494,12 +490,7 @@ export class CopilotResolver {
@Args({ name: 'options', type: () => DeleteSessionInput })
options: DeleteSessionInput
) {
await this.permissions.checkCloudPagePermission(
options.workspaceId,
options.docId,
'Doc.Update',
user.id
);
await this.ac.user(user.id).doc(options).allowLocal().assert('Doc.Update');
if (!options.sessionIds.length) {
return new NotFoundException('Session not found');
}
@@ -567,7 +558,7 @@ export class CopilotResolver {
@Throttle()
@Resolver(() => UserType)
export class UserCopilotResolver {
constructor(private readonly permissions: PermissionService) {}
constructor(private readonly ac: AccessController) {}
@ResolveField(() => CopilotType)
async copilot(
@@ -575,7 +566,11 @@ export class UserCopilotResolver {
@Args('workspaceId', { nullable: true }) workspaceId?: string
) {
if (workspaceId) {
await this.permissions.checkCloudWorkspace(workspaceId, user.id);
await this.ac
.user(user.id)
.workspace(workspaceId)
.allowLocal()
.assert('Workspace.Copilot');
}
return { workspaceId };
}

View File

@@ -11,7 +11,7 @@ import {
import { ActionForbidden, Config } from '../../base';
import { CurrentUser } from '../../core/auth';
import { PermissionService, WorkspaceRole } from '../../core/permission';
import { AccessController } from '../../core/permission';
import { WorkspaceType } from '../../core/workspaces';
import { SubscriptionRecurring } from '../payment/types';
import { LicenseService } from './service';
@@ -39,7 +39,7 @@ export class LicenseResolver {
constructor(
private readonly config: Config,
private readonly service: LicenseService,
private readonly permission: PermissionService
private readonly ac: AccessController
) {}
@ResolveField(() => License, {
@@ -58,12 +58,10 @@ export class LicenseResolver {
return null;
}
await this.permission.checkWorkspaceIs(
workspace.id,
user.id,
WorkspaceRole.Owner
);
await this.ac
.user(user.id)
.workspace(workspace.id)
.assert('Workspace.Payment.Manage');
return this.service.getLicense(workspace.id);
}
@@ -77,11 +75,10 @@ export class LicenseResolver {
throw new ActionForbidden();
}
await this.permission.checkWorkspaceIs(
workspaceId,
user.id,
WorkspaceRole.Owner
);
await this.ac
.user(user.id)
.workspace(workspaceId)
.assert('Workspace.Payment.Manage');
return this.service.activateTeamLicense(workspaceId, license);
}
@@ -95,11 +92,10 @@ export class LicenseResolver {
throw new ActionForbidden();
}
await this.permission.checkWorkspaceIs(
workspaceId,
user.id,
WorkspaceRole.Owner
);
await this.ac
.user(user.id)
.workspace(workspaceId)
.assert('Workspace.Payment.Manage');
return this.service.deactivateTeamLicense(workspaceId);
}
@@ -113,11 +109,10 @@ export class LicenseResolver {
throw new ActionForbidden();
}
await this.permission.checkWorkspaceIs(
workspaceId,
user.id,
WorkspaceRole.Owner
);
await this.ac
.user(user.id)
.workspace(workspaceId)
.assert('Workspace.Payment.Manage');
const { url } = await this.service.createCustomerPortal(workspaceId);

View File

@@ -11,7 +11,6 @@ import {
UserFriendlyError,
WorkspaceLicenseAlreadyExists,
} from '../../base';
import { PermissionService } from '../../core/permission';
import { Models } from '../../models';
import { SubscriptionPlan, SubscriptionRecurring } from '../payment/types';
@@ -30,7 +29,6 @@ export class LicenseService implements OnModuleInit {
private readonly config: Config,
private readonly db: PrismaClient,
private readonly event: EventBus,
private readonly permission: PermissionService,
private readonly models: Models
) {}
@@ -63,7 +61,7 @@ export class LicenseService implements OnModuleInit {
memberLimit: quantity,
}
);
await this.permission.refreshSeatStatus(workspaceId, quantity);
await this.models.workspaceUser.refresh(workspaceId, quantity);
break;
default:
break;

View File

@@ -11,6 +11,7 @@ import {
SubscriptionPlanNotFound,
URLHelper,
} from '../../../base';
import { Models } from '../../../models';
import {
KnownStripeInvoice,
KnownStripePrice,
@@ -48,7 +49,8 @@ export class WorkspaceSubscriptionManager extends SubscriptionManager {
stripe: Stripe,
db: PrismaClient,
private readonly url: URLHelper,
private readonly event: EventBus
private readonly event: EventBus,
private readonly models: Models
) {
super(stripe, db);
}
@@ -101,11 +103,7 @@ export class WorkspaceSubscriptionManager extends SubscriptionManager {
return { allow_promotion_codes: true };
})();
const count = await this.db.workspaceUserPermission.count({
where: {
workspaceId: args.workspaceId,
},
});
const count = await this.models.workspaceUser.count(args.workspaceId);
return this.stripe.checkout.sessions.create({
customer: customer.stripeCustomerId,

View File

@@ -1,7 +1,6 @@
import { Injectable } from '@nestjs/common';
import { OnEvent } from '../../base';
import { PermissionService } from '../../core/permission';
import { WorkspaceService } from '../../core/workspaces/resolvers';
import { Models } from '../../models';
import { SubscriptionPlan } from './types';
@@ -9,7 +8,6 @@ import { SubscriptionPlan } from './types';
@Injectable()
export class QuotaOverride {
constructor(
private readonly permission: PermissionService,
private readonly workspace: WorkspaceService,
private readonly models: Models
) {}
@@ -32,7 +30,7 @@ export class QuotaOverride {
memberLimit: quantity,
}
);
await this.permission.refreshSeatStatus(workspaceId, quantity);
await this.models.workspaceUser.refresh(workspaceId, quantity);
if (!isTeam) {
// this event will triggered when subscription is activated or changed
// we only send emails when the team workspace is activated

View File

@@ -27,7 +27,7 @@ import {
WorkspaceIdRequiredToUpdateTeamSubscription,
} from '../../base';
import { CurrentUser, Public } from '../../core/auth';
import { PermissionService, WorkspaceRole } from '../../core/permission';
import { AccessController } from '../../core/permission';
import { UserType } from '../../core/user';
import { WorkspaceType } from '../../core/workspaces';
import { Invoice, Subscription, WorkspaceSubscriptionManager } from './manager';
@@ -520,7 +520,7 @@ export class WorkspaceSubscriptionResolver {
constructor(
private readonly service: WorkspaceSubscriptionManager,
private readonly db: PrismaClient,
private readonly permission: PermissionService
private readonly ac: AccessController
) {}
@ResolveField(() => SubscriptionType, {
@@ -542,11 +542,11 @@ export class WorkspaceSubscriptionResolver {
@CurrentUser() me: CurrentUser,
@Parent() workspace: WorkspaceType
) {
await this.permission.checkWorkspace(
workspace.id,
me.id,
WorkspaceRole.Owner
);
await this.ac
.user(me.id)
.workspace(workspace.id)
.assert('Workspace.Payment.Manage');
return this.db.invoice.count({
where: {
targetId: workspace.id,
@@ -562,11 +562,10 @@ export class WorkspaceSubscriptionResolver {
take: number,
@Args('skip', { type: () => Int, nullable: true }) skip?: number
) {
await this.permission.checkWorkspace(
workspace.id,
me.id,
WorkspaceRole.Owner
);
await this.ac
.user(me.id)
.workspace(workspace.id)
.assert('Workspace.Payment.Manage');
return this.db.invoice.findMany({
where: {