mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-09-11 19:47:35 +03:00
parent
a59fe1b49e
commit
0d7ffb0511
@ -42,9 +42,22 @@ export class EarlyAccessFeatureConfig extends FeatureConfig {
|
||||
}
|
||||
}
|
||||
|
||||
export class UnlimitedWorkspaceFeatureConfig extends FeatureConfig {
|
||||
override config!: Feature & { feature: FeatureType.UnlimitedWorkspace };
|
||||
|
||||
constructor(data: any) {
|
||||
super(data);
|
||||
|
||||
if (this.config.feature !== FeatureType.UnlimitedWorkspace) {
|
||||
throw new Error('Invalid feature config: type is not EarlyAccess');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FeatureConfigMap = {
|
||||
[FeatureType.Copilot]: CopilotFeatureConfig,
|
||||
[FeatureType.EarlyAccess]: EarlyAccessFeatureConfig,
|
||||
[FeatureType.UnlimitedWorkspace]: UnlimitedWorkspaceFeatureConfig,
|
||||
};
|
||||
|
||||
export type FeatureConfigType<F extends FeatureType> = InstanceType<
|
||||
|
@ -3,6 +3,7 @@ import { registerEnumType } from '@nestjs/graphql';
|
||||
export enum FeatureType {
|
||||
Copilot = 'copilot',
|
||||
EarlyAccess = 'early_access',
|
||||
UnlimitedWorkspace = 'unlimited_workspace',
|
||||
}
|
||||
|
||||
registerEnumType(FeatureType, {
|
||||
|
@ -3,6 +3,7 @@ import { z } from 'zod';
|
||||
import { FeatureType } from './common';
|
||||
import { featureCopilot } from './copilot';
|
||||
import { featureEarlyAccess } from './early-access';
|
||||
import { featureUnlimitedWorkspace } from './unlimited-workspace';
|
||||
|
||||
/// ======== common schema ========
|
||||
|
||||
@ -43,6 +44,12 @@ export const Features: Feature[] = [
|
||||
version: 2,
|
||||
configs: {},
|
||||
},
|
||||
{
|
||||
feature: FeatureType.UnlimitedWorkspace,
|
||||
type: FeatureKind.Feature,
|
||||
version: 1,
|
||||
configs: {},
|
||||
},
|
||||
];
|
||||
|
||||
/// ======== schema infer ========
|
||||
@ -51,7 +58,13 @@ export const FeatureSchema = commonFeatureSchema
|
||||
.extend({
|
||||
type: z.literal(FeatureKind.Feature),
|
||||
})
|
||||
.and(z.discriminatedUnion('feature', [featureCopilot, featureEarlyAccess]));
|
||||
.and(
|
||||
z.discriminatedUnion('feature', [
|
||||
featureCopilot,
|
||||
featureEarlyAccess,
|
||||
featureUnlimitedWorkspace,
|
||||
])
|
||||
);
|
||||
|
||||
export type Feature = z.infer<typeof FeatureSchema>;
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FeatureType } from './common';
|
||||
|
||||
export const featureUnlimitedWorkspace = z.object({
|
||||
feature: z.literal(FeatureType.UnlimitedWorkspace),
|
||||
configs: z.object({}),
|
||||
});
|
@ -28,6 +28,7 @@ import type { FileUpload } from '../../../types';
|
||||
import { Auth, CurrentUser, Public } from '../../auth';
|
||||
import { MailService } from '../../auth/mailer';
|
||||
import { AuthService } from '../../auth/service';
|
||||
import { FeatureManagementService, FeatureType } from '../../features';
|
||||
import { QuotaManagementService } from '../../quota';
|
||||
import { WorkspaceBlobStorage } from '../../storage';
|
||||
import { UsersService, UserType } from '../../users';
|
||||
@ -57,6 +58,7 @@ export class WorkspaceResolver {
|
||||
private readonly mailer: MailService,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly permissions: PermissionService,
|
||||
private readonly feature: FeatureManagementService,
|
||||
private readonly quota: QuotaManagementService,
|
||||
private readonly users: UsersService,
|
||||
private readonly event: EventEmitter,
|
||||
@ -325,20 +327,26 @@ export class WorkspaceResolver {
|
||||
throw new ForbiddenException('Cannot change owner');
|
||||
}
|
||||
|
||||
// member limit check
|
||||
const [memberCount, quota] = await Promise.all([
|
||||
this.prisma.workspaceUserPermission.count({
|
||||
where: { workspaceId },
|
||||
}),
|
||||
this.quota.getUserQuota(user.id),
|
||||
]);
|
||||
if (memberCount >= quota.memberLimit) {
|
||||
throw new GraphQLError('Workspace member limit reached', {
|
||||
extensions: {
|
||||
status: HttpStatus[HttpStatus.PAYLOAD_TOO_LARGE],
|
||||
code: HttpStatus.PAYLOAD_TOO_LARGE,
|
||||
},
|
||||
});
|
||||
const unlimited = await this.feature.hasWorkspaceFeature(
|
||||
workspaceId,
|
||||
FeatureType.UnlimitedWorkspace
|
||||
);
|
||||
if (!unlimited) {
|
||||
// member limit check
|
||||
const [memberCount, quota] = await Promise.all([
|
||||
this.prisma.workspaceUserPermission.count({
|
||||
where: { workspaceId },
|
||||
}),
|
||||
this.quota.getUserQuota(user.id),
|
||||
]);
|
||||
if (memberCount >= quota.memberLimit) {
|
||||
throw new GraphQLError('Workspace member limit reached', {
|
||||
extensions: {
|
||||
status: HttpStatus[HttpStatus.PAYLOAD_TOO_LARGE],
|
||||
code: HttpStatus.PAYLOAD_TOO_LARGE,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let target = await this.users.findUserByEmail(email);
|
||||
|
@ -152,6 +152,7 @@ type WorkspaceType {
|
||||
enum FeatureType {
|
||||
Copilot
|
||||
EarlyAccess
|
||||
UnlimitedWorkspace
|
||||
}
|
||||
|
||||
type InvitationWorkspaceType {
|
||||
|
@ -129,7 +129,11 @@ test.beforeEach(async t => {
|
||||
.overrideProvider(PrismaService)
|
||||
.useValue(FakePrisma)
|
||||
.overrideProvider(FeatureManagementService)
|
||||
.useValue({})
|
||||
.useValue({
|
||||
hasWorkspaceFeature() {
|
||||
return false;
|
||||
},
|
||||
})
|
||||
.compile();
|
||||
const app = module.createNestApplication();
|
||||
app.use(
|
||||
|
Loading…
Reference in New Issue
Block a user