1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

chore: Minor code cleanups

This commit is contained in:
sighphyre 2022-01-06 10:59:41 +02:00 committed by Ivar Conradi Østhus
parent 26db43b248
commit b56ed05db1
No known key found for this signature in database
GPG Key ID: 31AC596886B0BD09
9 changed files with 98 additions and 54 deletions

View File

@ -11,6 +11,10 @@ import {
import { IPermission } from 'lib/types/model'; import { IPermission } from 'lib/types/model';
import { roundToNearestMinutesWithOptions } from 'date-fns/fp'; import { roundToNearestMinutesWithOptions } from 'date-fns/fp';
import NotFoundError from '../error/notfound-error'; import NotFoundError from '../error/notfound-error';
import {
ENVIRONMENT_PERMISSION_TYPE,
ROOT_PERMISSION_TYPE,
} from 'lib/util/constants';
const T = { const T = {
ROLE_USER: 'role_user', ROLE_USER: 'role_user',
@ -126,14 +130,17 @@ export class AccessStore implements IAccessStore {
// Since the editor should have access to the default project, // Since the editor should have access to the default project,
// we map the project to the project and environment specific // we map the project to the project and environment specific
// permissions that are connected to the editor role. // permissions that are connected to the editor role.
if (row.role_id === EDITOR_ID && row.type !== 'root') { if (row.role_id === EDITOR_ID && row.type !== ROOT_PERMISSION_TYPE) {
project = 'default'; project = 'default';
} else if (row.type !== 'root') { } else if (row.type !== ROOT_PERMISSION_TYPE) {
project = row.project ? row.project : undefined; project = row.project ? row.project : undefined;
} }
const environment = const environment =
row.type === 'environment' ? row.environment : undefined; row.type === ENVIRONMENT_PERMISSION_TYPE
? row.environment
: undefined;
return { return {
project, project,
environment, environment,
@ -170,11 +177,11 @@ export class AccessStore implements IAccessStore {
role_id: number, role_id: number,
permissions: IPermission[], permissions: IPermission[],
): Promise<void> { ): Promise<void> {
const rows = permissions.map((x) => { const rows = permissions.map((permission) => {
return { return {
role_id, role_id,
permission_id: x.id, permission_id: permission.id,
environment: x.environment, environment: permission.environment,
}; };
}); });
this.db.batchInsert(T.ROLE_PERMISSION, rows); this.db.batchInsert(T.ROLE_PERMISSION, rows);
@ -217,7 +224,7 @@ export class AccessStore implements IAccessStore {
return rows.map((r) => r.user_id); return rows.map((r) => r.user_id);
} }
async addUserToRole( async addUserToProjectRole(
userId: number, userId: number,
roleId: number, roleId: number,
projecId: string, projecId: string,
@ -229,7 +236,7 @@ export class AccessStore implements IAccessStore {
}); });
} }
async removeUserFromRole( async removeUserFromProjectRole(
userId: number, userId: number,
roleId: number, roleId: number,
projectId: string, projectId: string,

View File

@ -101,15 +101,6 @@ export default class RoleStore implements IRoleStore {
return result.length > 0; return result.length > 0;
} }
async roleExists(name: string): Promise<boolean> {
const result = await this.db.raw(
`SELECT EXISTS (SELECT 1 FROM ${T.ROLES} WHERE name = ?) AS present`,
[name],
);
const { present } = result.rows[0];
return present;
}
async deleteAll(): Promise<void> { async deleteAll(): Promise<void> {
return this.db(T.ROLES).del(); return this.db(T.ROLES).del();
} }
@ -181,8 +172,8 @@ export default class RoleStore implements IRoleStore {
.where('r.type', '=', 'root'); .where('r.type', '=', 'root');
return rows.map((row) => ({ return rows.map((row) => ({
roleId: +row.id, roleId: Number(row.id),
userId: +row.user_id, userId: Number(row.user_id),
})); }));
} }

View File

@ -158,8 +158,8 @@ export class AccessService {
const allEnvironmentPermissions = environments.map((env) => { const allEnvironmentPermissions = environments.map((env) => {
return { return {
name: env.name, name: env.name,
permissions: environmentPermissions.map((p) => { permissions: environmentPermissions.map((permission) => {
return { environment: env.name, ...p }; return { environment: env.name, ...permission };
}), }),
}; };
}); });
@ -170,12 +170,12 @@ export class AccessService {
}; };
} }
async addUserToRole( async addUserToProjectRole(
userId: number, userId: number,
roleId: number, roleId: number,
projectId: string, projectId: string,
): Promise<void> { ): Promise<void> {
return this.store.addUserToRole(userId, roleId, projectId); return this.store.addUserToProjectRole(userId, roleId, projectId);
} }
async getRoleByName(roleName: string): Promise<IRole> { async getRoleByName(roleName: string): Promise<IRole> {
@ -194,7 +194,7 @@ export class AccessService {
RoleType.ROOT, RoleType.ROOT,
); );
await this.store.addUserToRole( await this.store.addUserToProjectRole(
userId, userId,
newRootRole.id, newRootRole.id,
ALL_PROJECTS, ALL_PROJECTS,
@ -214,12 +214,12 @@ export class AccessService {
return userRoles.filter((r) => r.type === RoleType.ROOT); return userRoles.filter((r) => r.type === RoleType.ROOT);
} }
async removeUserFromRole( async removeUserFromProjectRole(
userId: number, userId: number,
roleId: number, roleId: number,
projectId: string, projectId: string,
): Promise<void> { ): Promise<void> {
return this.store.removeUserFromRole(userId, roleId, projectId); return this.store.removeUserFromProjectRole(userId, roleId, projectId);
} }
async addPermissionToRole( async addPermissionToRole(
@ -242,9 +242,9 @@ export class AccessService {
async removePermissionFromRole( async removePermissionFromRole(
roleId: number, roleId: number,
permission: string, permission: string,
projectId?: string, environment?: string,
): Promise<void> { ): Promise<void> {
if (isProjectPermission(permission) && !projectId) { if (isProjectPermission(permission) && !environment) {
throw new Error( throw new Error(
`ProjectId cannot be empty for permission=${permission}`, `ProjectId cannot be empty for permission=${permission}`,
); );
@ -252,7 +252,7 @@ export class AccessService {
return this.store.removePermissionFromRole( return this.store.removePermissionFromRole(
roleId, roleId,
permission, permission,
projectId, environment,
); );
} }
@ -349,7 +349,11 @@ export class AccessService {
this.logger.info( this.logger.info(
`Making ${owner.id} admin of ${projectId} via roleId=${ownerRole.id}`, `Making ${owner.id} admin of ${projectId} via roleId=${ownerRole.id}`,
); );
await this.store.addUserToRole(owner.id, ownerRole.id, projectId); await this.store.addUserToProjectRole(
owner.id,
ownerRole.id,
projectId,
);
} }
} }

View File

@ -300,7 +300,11 @@ export default class ProjectService {
throw new Error(`User already has access to project=${projectId}`); throw new Error(`User already has access to project=${projectId}`);
} }
await this.accessService.addUserToRole(userId, role.id, projectId); await this.accessService.addUserToProjectRole(
userId,
role.id,
projectId,
);
} }
// TODO: should be an event too // TODO: should be an event too
@ -324,7 +328,11 @@ export default class ProjectService {
} }
} }
await this.accessService.removeUserFromRole(userId, role.id, projectId); await this.accessService.removeUserFromProjectRole(
userId,
role.id,
projectId,
);
} }
async getMembers(projectId: string): Promise<number> { async getMembers(projectId: string): Promise<number> {

View File

@ -41,12 +41,12 @@ export interface IAccessStore extends Store<IRole, number> {
role_id: number, role_id: number,
permissions: IPermission[], permissions: IPermission[],
): Promise<void>; ): Promise<void>;
addUserToRole( addUserToProjectRole(
userId: number, userId: number,
roleId: number, roleId: number,
projectId: string, projectId: string,
): Promise<void>; ): Promise<void>;
removeUserFromRole( removeUserFromProjectRole(
userId: number, userId: number,
roleId: number, roleId: number,
projectId: string, projectId: string,

View File

@ -1 +1,5 @@
export const DEFAULT_ENV = 'default'; export const DEFAULT_ENV = 'default';
export const ROOT_PERMISSION_TYPE = 'root';
export const ENVIRONMENT_PERMISSION_TYPE = 'environment';
export const PROJECT_PERMISSION_TYPE = 'project';

View File

@ -28,14 +28,18 @@ let readRole;
const createUserEditorAccess = async (name, email) => { const createUserEditorAccess = async (name, email) => {
const { userStore } = stores; const { userStore } = stores;
const user = await userStore.insert({ name, email }); const user = await userStore.insert({ name, email });
await accessService.addUserToRole(user.id, editorRole.id, 'default'); await accessService.addUserToProjectRole(user.id, editorRole.id, 'default');
return user; return user;
}; };
const createUserViewerAccess = async (name, email) => { const createUserViewerAccess = async (name, email) => {
const { userStore } = stores; const { userStore } = stores;
const user = await userStore.insert({ name, email }); const user = await userStore.insert({ name, email });
await accessService.addUserToRole(user.id, readRole.id, ALL_PROJECTS); await accessService.addUserToProjectRole(
user.id,
readRole.id,
ALL_PROJECTS,
);
return user; return user;
}; };
@ -178,7 +182,11 @@ const createSuperUser = async () => {
name: 'Alice Admin', name: 'Alice Admin',
email: 'admin@getunleash.io', email: 'admin@getunleash.io',
}); });
await accessService.addUserToRole(user.id, adminRole.id, ALL_PROJECTS); await accessService.addUserToProjectRole(
user.id,
adminRole.id,
ALL_PROJECTS,
);
return user; return user;
}; };
@ -372,7 +380,7 @@ test('should grant user access to project', async () => {
await accessService.createDefaultProjectRoles(user, project); await accessService.createDefaultProjectRoles(user, project);
const projectRole = await accessService.getRoleByName(RoleName.MEMBER); const projectRole = await accessService.getRoleByName(RoleName.MEMBER);
await accessService.addUserToRole(sUser.id, projectRole.id, project); await accessService.addUserToProjectRole(sUser.id, projectRole.id, project);
// // Should be able to update feature toggles inside the project // // Should be able to update feature toggles inside the project
hasCommonProjectAccess(sUser, project, true); hasCommonProjectAccess(sUser, project, true);
@ -397,7 +405,7 @@ test('should not get access if not specifying project', async () => {
const projectRole = await accessService.getRoleByName(RoleName.MEMBER); const projectRole = await accessService.getRoleByName(RoleName.MEMBER);
await accessService.addUserToRole(sUser.id, projectRole.id, project); await accessService.addUserToProjectRole(sUser.id, projectRole.id, project);
// Should not be able to update feature toggles outside project // Should not be able to update feature toggles outside project
hasCommonProjectAccess(sUser, undefined, false); hasCommonProjectAccess(sUser, undefined, false);
@ -410,14 +418,18 @@ test('should remove user from role', async () => {
email: 'random123@getunleash.io', email: 'random123@getunleash.io',
}); });
await accessService.addUserToRole(user.id, editorRole.id, 'default'); await accessService.addUserToProjectRole(user.id, editorRole.id, 'default');
// check user has one role // check user has one role
const userRoles = await accessService.getRolesForUser(user.id); const userRoles = await accessService.getRolesForUser(user.id);
expect(userRoles.length).toBe(1); expect(userRoles.length).toBe(1);
expect(userRoles[0].name).toBe(RoleName.EDITOR); expect(userRoles[0].name).toBe(RoleName.EDITOR);
await accessService.removeUserFromRole(user.id, editorRole.id, 'default'); await accessService.removeUserFromProjectRole(
user.id,
editorRole.id,
'default',
);
const userRolesAfterRemove = await accessService.getRolesForUser(user.id); const userRolesAfterRemove = await accessService.getRolesForUser(user.id);
expect(userRolesAfterRemove.length).toBe(0); expect(userRolesAfterRemove.length).toBe(0);
}); });
@ -429,7 +441,7 @@ test('should return role with users', async () => {
email: 'random2223@getunleash.io', email: 'random2223@getunleash.io',
}); });
await accessService.addUserToRole(user.id, editorRole.id, 'default'); await accessService.addUserToProjectRole(user.id, editorRole.id, 'default');
const roleWithUsers = await accessService.getRoleData(editorRole.id); const roleWithUsers = await accessService.getRoleData(editorRole.id);
expect(roleWithUsers.role.name).toBe(RoleName.EDITOR); expect(roleWithUsers.role.name).toBe(RoleName.EDITOR);
@ -447,7 +459,7 @@ test('should return role with permissions and users', async () => {
email: 'random2244@getunleash.io', email: 'random2244@getunleash.io',
}); });
await accessService.addUserToRole(user.id, editorRole.id, 'default'); await accessService.addUserToProjectRole(user.id, editorRole.id, 'default');
const roleWithPermission = await accessService.getRoleData(editorRole.id); const roleWithPermission = await accessService.getRoleData(editorRole.id);
@ -536,7 +548,11 @@ test('should support permission with "ALL" environment requirement', async () =>
[CREATE_FEATURE_STRATEGY], [CREATE_FEATURE_STRATEGY],
'production', 'production',
); );
await accessStore.addUserToRole(user.id, customRole.id, ALL_PROJECTS); await accessStore.addUserToProjectRole(
user.id,
customRole.id,
ALL_PROJECTS,
);
const hasAccess = await accessService.hasPermission( const hasAccess = await accessService.hasPermission(
user, user,
@ -667,3 +683,17 @@ test('Should be denied access to delete a role that is in use', async () => {
); );
} }
}); });
test('Should be given full access to project created by user', async () => {
const user = editorUser;
const newProjectName = 'AWholeNewProject';
const project = {
id: newProjectName,
name: newProjectName,
description: 'Blah',
};
await projectService.createProject(project, user.id);
hasFullProjectAccess(user, newProjectName, true);
});

View File

@ -35,7 +35,7 @@ class AccessServiceMock extends AccessService {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
addUserToRole(userId: number, roleId: number): Promise<void> { addUserToProjectRole(userId: number, roleId: number): Promise<void> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
@ -43,10 +43,6 @@ class AccessServiceMock extends AccessService {
return Promise.resolve(); return Promise.resolve();
} }
removeUserFromRole(userId: number, roleId: number): Promise<void> {
throw new Error('Method not implemented.');
}
addPermissionToRole( addPermissionToRole(
roleId: number, roleId: number,
permission: string, permission: string,

View File

@ -9,6 +9,14 @@ import {
import { IAvailablePermissions, IPermission } from 'lib/types/model'; import { IAvailablePermissions, IPermission } from 'lib/types/model';
class AccessStoreMock implements IAccessStore { class AccessStoreMock implements IAccessStore {
removeUserFromProjectRole(
userId: number,
roleId: number,
projectId: string,
): Promise<void> {
throw new Error('Method not implemented.');
}
wipePermissionsFromRole(role_id: number): Promise<void> { wipePermissionsFromRole(role_id: number): Promise<void> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
@ -79,11 +87,7 @@ class AccessStoreMock implements IAccessStore {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
addUserToRole(userId: number, roleId: number): Promise<void> { addUserToProjectRole(userId: number, roleId: number): Promise<void> {
throw new Error('Method not implemented.');
}
removeUserFromRole(userId: number, roleId: number): Promise<void> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }