mirror of
https://github.com/docmost/docmost.git
synced 2026-08-28 09:17:06 +08:00
feat: feature flag upgrade
This commit is contained in:
@@ -91,15 +91,6 @@ export function extractBearerTokenFromHeader(
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
}
|
||||
|
||||
export function hasLicenseOrEE(opts: {
|
||||
licenseKey: string;
|
||||
plan: string;
|
||||
isCloud: boolean;
|
||||
}): boolean {
|
||||
const { licenseKey, plan, isCloud } = opts;
|
||||
return Boolean(licenseKey) || (isCloud && plan === 'business');
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a database URL for postgres.js compatibility.
|
||||
* - Removes `sslmode=no-verify` (not supported by postgres.js), keeps other sslmode values
|
||||
|
||||
@@ -28,8 +28,7 @@ import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
||||
import { Public } from '../../common/decorators/public.decorator';
|
||||
import { ShareRepo } from '@docmost/db/repos/share/share.repo';
|
||||
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
|
||||
import { EnvironmentService } from '../../integrations/environment/environment.service';
|
||||
import { hasLicenseOrEE } from '../../common/helpers';
|
||||
import { LicenseCheckService } from '../../integrations/environment/license-check.service';
|
||||
import { AuditEvent, AuditResource } from '../../common/events/audit-events';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
@@ -45,7 +44,7 @@ export class ShareController {
|
||||
private readonly pageRepo: PageRepo,
|
||||
private readonly pagePermissionRepo: PagePermissionRepo,
|
||||
private readonly pageAccessService: PageAccessService,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
private readonly licenseCheckService: LicenseCheckService,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
@@ -81,11 +80,10 @@ export class ShareController {
|
||||
|
||||
return {
|
||||
...shareData,
|
||||
hasLicenseKey: hasLicenseOrEE({
|
||||
licenseKey: workspace.licenseKey,
|
||||
isCloud: this.environmentService.isCloud(),
|
||||
plan: workspace.plan,
|
||||
}),
|
||||
features: this.licenseCheckService.resolveFeatures(
|
||||
workspace.licenseKey,
|
||||
workspace.plan,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -259,11 +257,10 @@ export class ShareController {
|
||||
|
||||
return {
|
||||
...treeData,
|
||||
hasLicenseKey: hasLicenseOrEE({
|
||||
licenseKey: workspace.licenseKey,
|
||||
isCloud: this.environmentService.isCloud(),
|
||||
plan: workspace.plan,
|
||||
}),
|
||||
features: this.licenseCheckService.resolveFeatures(
|
||||
workspace.licenseKey,
|
||||
workspace.plan,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,10 +139,10 @@ export class SpaceService {
|
||||
});
|
||||
|
||||
if (
|
||||
!this.licenseCheckService.isValidEELicense(workspace.licenseKey)
|
||||
!this.licenseCheckService.hasFeature(workspace.licenseKey, 'security:settings')
|
||||
) {
|
||||
throw new ForbiddenException(
|
||||
'This feature requires a valid enterprise license',
|
||||
'This feature requires a valid license',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
||||
import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator';
|
||||
import { User, Workspace } from '@docmost/db/types/entity.types';
|
||||
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||
import { LicenseCheckService } from '../../integrations/environment/license-check.service';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('users')
|
||||
@@ -20,6 +21,7 @@ export class UserController {
|
||||
constructor(
|
||||
private readonly userService: UserService,
|
||||
private readonly workspaceRepo: WorkspaceRepo,
|
||||
private readonly licenseCheckService: LicenseCheckService,
|
||||
) {}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@@ -34,10 +36,16 @@ export class UserController {
|
||||
|
||||
const { licenseKey, ...rest } = workspace;
|
||||
|
||||
const features = this.licenseCheckService.resolveFeatures(
|
||||
licenseKey,
|
||||
rest.plan,
|
||||
);
|
||||
|
||||
const workspaceInfo = {
|
||||
...rest,
|
||||
memberCount,
|
||||
hasLicenseKey: Boolean(licenseKey),
|
||||
features,
|
||||
};
|
||||
|
||||
return { user: authUser, workspace: workspaceInfo };
|
||||
|
||||
@@ -85,7 +85,7 @@ export class WorkspaceService {
|
||||
async getWorkspacePublicData(workspaceId: string) {
|
||||
const workspace = await this.db
|
||||
.selectFrom('workspaces')
|
||||
.select(['id', 'name', 'logo', 'hostname', 'enforceSso', 'licenseKey'])
|
||||
.select(['id', 'name', 'logo', 'hostname', 'enforceSso', 'licenseKey', 'plan'])
|
||||
.select((eb) =>
|
||||
jsonArrayFrom(
|
||||
eb
|
||||
@@ -111,6 +111,7 @@ export class WorkspaceService {
|
||||
return {
|
||||
...rest,
|
||||
hasLicenseKey: Boolean(licenseKey),
|
||||
features: this.licenseCheckService.resolveFeatures(licenseKey, rest.plan),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -336,9 +337,9 @@ export class WorkspaceService {
|
||||
.where('id', '=', workspaceId)
|
||||
.executeTakeFirst();
|
||||
|
||||
if (!this.licenseCheckService.isValidEELicense(ws.licenseKey)) {
|
||||
if (!this.licenseCheckService.hasFeature(ws.licenseKey, 'security:settings')) {
|
||||
throw new ForbiddenException(
|
||||
'This feature requires a valid enterprise license',
|
||||
'This feature requires a valid license',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -506,6 +507,7 @@ export class WorkspaceService {
|
||||
return {
|
||||
...rest,
|
||||
hasLicenseKey: Boolean(licenseKey),
|
||||
features: this.licenseCheckService.resolveFeatures(licenseKey, rest.plan),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule apps/server/src/ee updated: 8b7ae8cf1b...a132758491
@@ -25,4 +25,48 @@ export class LicenseCheckService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
hasFeature(licenseKey: string, feature: string): boolean {
|
||||
if (this.environmentService.isCloud()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const LicenseModule = require('../../ee/licence/license.service');
|
||||
const licenseService = this.moduleRef.get(LicenseModule.LicenseService, {
|
||||
strict: false,
|
||||
});
|
||||
return licenseService.hasFeature(licenseKey, feature);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
getFeatures(licenseKey: string): string[] {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const LicenseModule = require('../../ee/licence/license.service');
|
||||
const licenseService = this.moduleRef.get(LicenseModule.LicenseService, {
|
||||
strict: false,
|
||||
});
|
||||
return licenseService.getFeatures(licenseKey);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
resolveFeatures(licenseKey: string, plan: string): string[] {
|
||||
if (this.environmentService.isCloud()) {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const { getFeaturesForCloudPlan } = require('../../ee/licence/feature-registry');
|
||||
return [...getFeaturesForCloudPlan(plan)];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return this.getFeatures(licenseKey);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user