mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-23 10:32:17 -08:00
feat(core): Set up endpoint for all existing roles with license flag (#7834)
https://linear.app/n8n/issue/PAY-1034/create-endpoint-to-list-all-existing-roles
This commit is contained in:
parent
4074107511
commit
2356fb0f0c
|
@ -223,6 +223,10 @@ export class License {
|
|||
return this.isFeatureEnabled(LICENSE_FEATURES.ADVANCED_EXECUTION_FILTERS);
|
||||
}
|
||||
|
||||
isAdvancedPermissionsLicensed() {
|
||||
return this.isFeatureEnabled(LICENSE_FEATURES.ADVANCED_PERMISSIONS);
|
||||
}
|
||||
|
||||
isDebugInEditorLicensed() {
|
||||
return this.isFeatureEnabled(LICENSE_FEATURES.DEBUG_IN_EDITOR);
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ import { OrchestrationController } from './controllers/orchestration.controller'
|
|||
import { WorkflowHistoryController } from './workflows/workflowHistory/workflowHistory.controller.ee';
|
||||
import { InvitationController } from './controllers/invitation.controller';
|
||||
import { CollaborationService } from './collaboration/collaboration.service';
|
||||
import { RoleController } from './controllers/role.controller';
|
||||
import { BadRequestError } from './errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from './errors/response-errors/not-found.error';
|
||||
|
||||
|
@ -298,6 +299,7 @@ export class Server extends AbstractServer {
|
|||
postHog,
|
||||
),
|
||||
Container.get(VariablesController),
|
||||
Container.get(RoleController),
|
||||
];
|
||||
|
||||
if (isLdapEnabled()) {
|
||||
|
|
|
@ -81,6 +81,7 @@ export const LICENSE_FEATURES = {
|
|||
BINARY_DATA_S3: 'feat:binaryDataS3',
|
||||
MULTIPLE_MAIN_INSTANCES: 'feat:multipleMainInstances',
|
||||
WORKER_VIEW: 'feat:workerView',
|
||||
ADVANCED_PERMISSIONS: 'feat:advancedPermissions',
|
||||
} as const;
|
||||
|
||||
export const LICENSE_QUOTAS = {
|
||||
|
|
|
@ -71,6 +71,7 @@ export class E2EController {
|
|||
[LICENSE_FEATURES.BINARY_DATA_S3]: false,
|
||||
[LICENSE_FEATURES.MULTIPLE_MAIN_INSTANCES]: false,
|
||||
[LICENSE_FEATURES.WORKER_VIEW]: false,
|
||||
[LICENSE_FEATURES.ADVANCED_PERMISSIONS]: false,
|
||||
};
|
||||
|
||||
constructor(
|
||||
|
|
24
packages/cli/src/controllers/role.controller.ts
Normal file
24
packages/cli/src/controllers/role.controller.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { License } from '@/License';
|
||||
import { Get, RestController } from '@/decorators';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { Service } from 'typedi';
|
||||
|
||||
@Service()
|
||||
@RestController('/roles')
|
||||
export class RoleController {
|
||||
constructor(
|
||||
private readonly roleService: RoleService,
|
||||
private readonly license: License,
|
||||
) {}
|
||||
|
||||
@Get('/')
|
||||
async listRoles() {
|
||||
return this.roleService.listRoles().map((role) => {
|
||||
if (role.scope === 'global' && role.name === 'admin') {
|
||||
return { ...role, isAvailable: this.license.isAdvancedPermissionsLicensed() };
|
||||
}
|
||||
|
||||
return { ...role, isAvailable: true };
|
||||
});
|
||||
}
|
||||
}
|
|
@ -56,6 +56,10 @@ export class RoleService {
|
|||
{ scope: 'workflow', name: 'editor' },
|
||||
];
|
||||
|
||||
listRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
private isValid(scope: RoleScopes, name: RoleNames) {
|
||||
return this.roles.some((r) => r.scope === scope && r.name === name);
|
||||
}
|
||||
|
|
82
packages/cli/test/integration/role.api.test.ts
Normal file
82
packages/cli/test/integration/role.api.test.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { License } from '@/License';
|
||||
|
||||
import * as utils from './shared/utils/';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { mockInstance } from '../shared/mocking';
|
||||
import { createAdmin, createMember, createOwner } from './shared/db/users';
|
||||
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import type { User } from '@db/entities/User';
|
||||
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['role'] });
|
||||
|
||||
const license = mockInstance(License, {
|
||||
isAdvancedPermissionsLicensed: jest.fn().mockReturnValue(true),
|
||||
isWithinUsersLimit: jest.fn().mockReturnValue(true),
|
||||
});
|
||||
|
||||
describe('GET /roles', () => {
|
||||
let owner: User;
|
||||
let admin: User;
|
||||
let member: User;
|
||||
|
||||
let ownerAgent: SuperAgentTest;
|
||||
let adminAgent: SuperAgentTest;
|
||||
let memberAgent: SuperAgentTest;
|
||||
|
||||
let toAgent: Record<string, SuperAgentTest> = {};
|
||||
|
||||
beforeAll(async () => {
|
||||
await testDb.truncate(['User']);
|
||||
|
||||
owner = await createOwner();
|
||||
admin = await createAdmin();
|
||||
member = await createMember();
|
||||
|
||||
ownerAgent = testServer.authAgentFor(owner);
|
||||
adminAgent = testServer.authAgentFor(admin);
|
||||
memberAgent = testServer.authAgentFor(member);
|
||||
|
||||
toAgent = {
|
||||
owner: ownerAgent,
|
||||
admin: adminAgent,
|
||||
member: memberAgent,
|
||||
};
|
||||
});
|
||||
|
||||
describe('with advanced permissions licensed', () => {
|
||||
test.each(['owner', 'admin', 'member'])('should return all roles to %s', async (user) => {
|
||||
license.isAdvancedPermissionsLicensed.mockReturnValue(true);
|
||||
|
||||
const response = await toAgent[user].get('/roles').expect(200);
|
||||
|
||||
expect(response.body.data).toEqual([
|
||||
{ scope: 'global', name: 'owner', isAvailable: true },
|
||||
{ scope: 'global', name: 'member', isAvailable: true },
|
||||
{ scope: 'global', name: 'admin', isAvailable: true },
|
||||
{ scope: 'workflow', name: 'owner', isAvailable: true },
|
||||
{ scope: 'credential', name: 'owner', isAvailable: true },
|
||||
{ scope: 'credential', name: 'user', isAvailable: true },
|
||||
{ scope: 'workflow', name: 'editor', isAvailable: true },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with advanced permissions not licensed', () => {
|
||||
test.each(['owner', 'admin', 'member'])('should return all roles to %s', async (user) => {
|
||||
license.isAdvancedPermissionsLicensed.mockReturnValue(false);
|
||||
|
||||
const response = await toAgent[user].get('/roles').expect(200);
|
||||
|
||||
expect(response.body.data).toEqual([
|
||||
{ scope: 'global', name: 'owner', isAvailable: true },
|
||||
{ scope: 'global', name: 'member', isAvailable: true },
|
||||
{ scope: 'global', name: 'admin', isAvailable: false },
|
||||
{ scope: 'workflow', name: 'owner', isAvailable: true },
|
||||
{ scope: 'credential', name: 'owner', isAvailable: true },
|
||||
{ scope: 'credential', name: 'user', isAvailable: true },
|
||||
{ scope: 'workflow', name: 'editor', isAvailable: true },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -30,6 +30,7 @@ type EndpointGroup =
|
|||
| 'executions'
|
||||
| 'workflowHistory'
|
||||
| 'binaryData'
|
||||
| 'role'
|
||||
| 'invitations';
|
||||
|
||||
export interface SetupProps {
|
||||
|
|
|
@ -295,6 +295,11 @@ export const setupTestServer = ({
|
|||
const { BinaryDataController } = await import('@/controllers/binaryData.controller');
|
||||
registerController(app, config, Container.get(BinaryDataController));
|
||||
break;
|
||||
|
||||
case 'role':
|
||||
const { RoleController } = await import('@/controllers/role.controller');
|
||||
registerController(app, config, Container.get(RoleController));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue