diff --git a/src/lib/db/access-store.ts b/src/lib/db/access-store.ts index e0d3a90910..22c06773df 100644 --- a/src/lib/db/access-store.ts +++ b/src/lib/db/access-store.ts @@ -163,14 +163,27 @@ export class AccessStore implements IAccessStore { return rows; } - async getPermissionsForRole(roleId: number): Promise { + async getPermissionsForRole(roleId: number): Promise { const stopTimer = this.timer('getPermissionsForRole'); const rows = await this.db - .select('project', 'permission', 'environment') - .from(`${T.ROLE_PERMISSION}`) - .where('role_id', '=', roleId); + .select('p.id', 'p.permission', 'p.environment', 'pt.display_name') + .from(`${T.ROLE_PERMISSION} as rp`) + .join(`${T.PERMISSIONS} as p`, 'p.id', 'rp.permission_id') + .join( + `${T.PERMISSION_TYPES} as pt`, + 'pt.permission', + 'p.permission', + ) + .where('rp.role_id', '=', roleId); stopTimer(); - return rows; + return rows.map((permission) => { + return { + id: permission.id, + name: permission.permission, + environment: permission.environment, + displayName: permission.display_name, + }; + }); } async getRoles(): Promise { @@ -338,6 +351,13 @@ export class AccessStore implements IAccessStore { `SELECT id FROM ${T.PERMISSIONS} where environment = ? and permission = ANY(?)`, [environment, permissions], ); + + console.log( + 'Adding permissions to table', + role_id, + permissions, + environment, + ); const ids = result.rows.map((x) => x.id); const rows = ids.map((permission_id) => ({ @@ -345,19 +365,29 @@ export class AccessStore implements IAccessStore { permission_id, })); + console.log('Final inssert', rows); return this.db.batchInsert(T.ROLE_PERMISSION, rows); } async removePermissionFromRole( - roleId: number, + role_id: number, permission: string, - projectId?: string, + environment?: string, ): Promise { + const result = await this.db.raw( + `SELECT id FROM ${T.PERMISSIONS} where environment = ? and permission = ?`, + [environment, permission], + ); + + console.log('Gett results for ', environment, permission); + console.log('My result is', result); + + const permissionId = result.first(); + return this.db(T.ROLE_PERMISSION) .where({ - role_id: roleId, - permission, - project: projectId, + role_id, + permissionId, }) .delete(); } diff --git a/src/lib/db/role-store.ts b/src/lib/db/role-store.ts index d9e9b52a76..e05e51c8d0 100644 --- a/src/lib/db/role-store.ts +++ b/src/lib/db/role-store.ts @@ -6,13 +6,13 @@ import { ICustomRole } from 'lib/types/model'; import { ICustomRoleInsert } from 'lib/types/stores/role-store'; const TABLE = 'roles'; -const COLUMNS = ['id', 'name', 'description', 'created_at']; +const COLUMNS = ['id', 'name', 'description', 'type']; interface IRoleRow { id: number; name: string; description: string; - created_at: Date; + type: string; } export default class RoleStore { @@ -79,7 +79,7 @@ export default class RoleStore { id: row.id, name: row.name, description: row.description, - createdAt: row.created_at, + type: row.type, }; } diff --git a/src/lib/services/access-service.ts b/src/lib/services/access-service.ts index 2cab232343..f56f35edcf 100644 --- a/src/lib/services/access-service.ts +++ b/src/lib/services/access-service.ts @@ -198,14 +198,18 @@ export class AccessService { async addPermissionToRole( roleId: number, permission: string, - projectId?: string, + environment?: string, ): Promise { - if (isProjectPermission(permission) && !projectId) { + if (isProjectPermission(permission) && !environment) { throw new Error( `ProjectId cannot be empty for permission=${permission}`, ); } - return this.store.addPermissionsToRole(roleId, [permission], projectId); + return this.store.addPermissionsToRole( + roleId, + [permission], + environment, + ); } async removePermissionFromRole( diff --git a/src/lib/services/role-service.ts b/src/lib/services/role-service.ts index 6392a4c7c0..60140acddc 100644 --- a/src/lib/services/role-service.ts +++ b/src/lib/services/role-service.ts @@ -1,7 +1,10 @@ import { IUnleashConfig } from 'lib/server-impl'; import { IUnleashStores } from 'lib/types'; import { ICustomRole, IPermission } from 'lib/types/model'; -import { IAccessStore } from 'lib/types/stores/access-store'; +import { + IAccessStore, + IRoleWithPermissions, +} from 'lib/types/stores/access-store'; import { IRoleStore } from 'lib/types/stores/role-store'; import { Logger } from '../logger'; @@ -34,8 +37,15 @@ export default class RoleService { return this.store.getAll(); } - async get(id: number): Promise { - return this.store.get(id); + async get(id: number): Promise { + const role = await this.store.get(id); + const permissions = await this.accessStore.getPermissionsForRole( + role.id, + ); + return { + ...role, + permissions, + }; } async create(role: IRoleCreation): Promise { diff --git a/src/lib/types/model.ts b/src/lib/types/model.ts index 2ab134e000..ab61814be8 100644 --- a/src/lib/types/model.ts +++ b/src/lib/types/model.ts @@ -1,6 +1,6 @@ import { ITagType } from './stores/tag-type-store'; import { LogProvider } from '../logger'; -import { IRole, IUserPermission } from './stores/access-store'; +import { IRole } from './stores/access-store'; import { IUser } from './user'; export interface IConstraint { @@ -212,7 +212,7 @@ export interface IUserWithRole { export interface IRoleData { role: IRole; users: IUser[]; - permissions: IUserPermission[]; + permissions: IPermission[]; } export interface IAvailablePermissions { @@ -224,6 +224,7 @@ export interface IPermission { id: number; name: string; displayName: string; + environment?: string; } export interface IEnvironmentPermission { @@ -328,7 +329,7 @@ export interface ICustomRole { id: number; name: string; description: string; - createdAt: Date; + type: string; } export interface IProjectWithCount extends IProject { diff --git a/src/lib/types/stores/access-store.ts b/src/lib/types/stores/access-store.ts index a6d4390dc5..29abf0d292 100644 --- a/src/lib/types/stores/access-store.ts +++ b/src/lib/types/stores/access-store.ts @@ -14,6 +14,10 @@ export interface IRole { type: string; } +export interface IRoleWithPermissions extends IRole { + permissions: IPermission[]; +} + export interface IRoleDescriptor { name: string; description?: string; @@ -28,7 +32,7 @@ export interface IAccessStore extends Store { getRoleByName(name: string): Promise; getAvailablePermissions(): Promise; getPermissionsForUser(userId: number): Promise; - getPermissionsForRole(roleId: number): Promise; + getPermissionsForRole(roleId: number): Promise; getRoles(): Promise; getRolesForProject(projectId: string): Promise; unlinkUserRoles(userId: number): Promise; diff --git a/src/test/e2e/services/access-service.e2e.test.ts b/src/test/e2e/services/access-service.e2e.test.ts index e71f049b3f..f0f6c86bcf 100644 --- a/src/test/e2e/services/access-service.e2e.test.ts +++ b/src/test/e2e/services/access-service.e2e.test.ts @@ -4,6 +4,7 @@ import getLogger from '../../fixtures/no-logger'; // eslint-disable-next-line import/no-unresolved import { AccessService, + ALL_ENVS, ALL_PROJECTS, } from '../../../lib/services/access-service'; @@ -177,13 +178,13 @@ test('should remove CREATE_FEATURE on all projects', async () => { await accessService.addPermissionToRole( editorRole.id, permissions.CREATE_FEATURE, - ALL_PROJECTS, + ALL_ENVS, ); await accessService.removePermissionFromRole( editorRole.id, permissions.CREATE_FEATURE, - ALL_PROJECTS, + ALL_ENVS, ); expect( diff --git a/src/test/fixtures/fake-access-store.ts b/src/test/fixtures/fake-access-store.ts index dd78a7562c..581e735f9b 100644 --- a/src/test/fixtures/fake-access-store.ts +++ b/src/test/fixtures/fake-access-store.ts @@ -54,7 +54,7 @@ class AccessStoreMock implements IAccessStore { return Promise.resolve([]); } - getPermissionsForRole(roleId: number): Promise { + getPermissionsForRole(roleId: number): Promise { throw new Error('Method not implemented.'); } diff --git a/src/test/fixtures/fake-role-store.ts b/src/test/fixtures/fake-role-store.ts index a22c27ea43..22d158ad8b 100644 --- a/src/test/fixtures/fake-role-store.ts +++ b/src/test/fixtures/fake-role-store.ts @@ -12,7 +12,7 @@ export default class FakeRoleStore implements IRoleStore { id: 1, name: 'Role', description: 'Hello', - createdAt: new Date(), + type: 'custom', }); } @@ -22,7 +22,7 @@ export default class FakeRoleStore implements IRoleStore { id: 1, name: 'Role', description: 'Hello', - createdAt: new Date(), + type: 'custom', }, ]); } @@ -36,7 +36,7 @@ export default class FakeRoleStore implements IRoleStore { id: 1, name: 'Role', description: 'Hello', - createdAt: new Date(), + type: 'custom', }); }