Skip to content

Commit

Permalink
feat(core): Set up endpoint for all existing roles with license flag (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ivov authored Nov 28, 2023
1 parent 4074107 commit 2356fb0
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/cli/src/License.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -298,6 +299,7 @@ export class Server extends AbstractServer {
postHog,
),
Container.get(VariablesController),
Container.get(RoleController),
];

if (isLdapEnabled()) {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/controllers/e2e.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/controllers/role.controller.ts
Original file line number Diff line number Diff line change
@@ -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 };
});
}
}
4 changes: 4 additions & 0 deletions packages/cli/src/services/role.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
82 changes: 82 additions & 0 deletions packages/cli/test/integration/role.api.test.ts
Original file line number Diff line number Diff line change
@@ -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 },
]);
});
});
});
1 change: 1 addition & 0 deletions packages/cli/test/integration/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type EndpointGroup =
| 'executions'
| 'workflowHistory'
| 'binaryData'
| 'role'
| 'invitations';

export interface SetupProps {
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/test/integration/shared/utils/testServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand Down

0 comments on commit 2356fb0

Please sign in to comment.