mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: add service method to retrieve group and project access for all users (#4708)
This commit is contained in:
parent
4b90fe7790
commit
10afbc8a9e
@ -12,7 +12,7 @@ import {
|
||||
IUserRole,
|
||||
IUserWithProjectRoles,
|
||||
} from '../types/stores/access-store';
|
||||
import { IPermission } from '../types/model';
|
||||
import { IPermission, IUserAccessOverview } from '../types/model';
|
||||
import NotFoundError from '../error/notfound-error';
|
||||
import {
|
||||
ENVIRONMENT_PERMISSION_TYPE,
|
||||
@ -758,4 +758,40 @@ export class AccessStore implements IAccessStore {
|
||||
[destinationEnvironment, sourceEnvironment],
|
||||
);
|
||||
}
|
||||
|
||||
async getUserAccessOverview(): Promise<IUserAccessOverview[]> {
|
||||
const result = await this.db
|
||||
.raw(`SELECT u.id, u.created_at, u.name, u.email, u.seen_at, up.p_array as projects, gr.p_array as groups, r.name as root_role
|
||||
FROM users u, LATERAL (
|
||||
SELECT ARRAY (
|
||||
SELECT ru.project
|
||||
FROM role_user ru
|
||||
WHERE ru.user_id = u.id
|
||||
) AS p_array
|
||||
) up, LATERAL (
|
||||
SELECT r.name
|
||||
FROM role_user ru
|
||||
inner join roles r on ru.role_id = r.id
|
||||
where ru.user_id = u.id and r.type='root'
|
||||
) r, LATERAL (
|
||||
SELECT ARRAY (
|
||||
select g.name from group_user gu
|
||||
left join groups g on g.id = gu.group_id
|
||||
WHERE gu.user_id = u.id
|
||||
) AS p_array
|
||||
) gr
|
||||
order by u.id;`);
|
||||
return result.rows.map((row) => {
|
||||
return {
|
||||
userId: row.id,
|
||||
createdAt: row.created_at,
|
||||
userName: row.name,
|
||||
userEmail: row.email,
|
||||
lastSeen: row.seen_at,
|
||||
accessibleProjects: row.projects,
|
||||
groups: row.groups,
|
||||
rootRole: row.root_role,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ import InvalidOperationError from '../error/invalid-operation-error';
|
||||
import BadDataError from '../error/bad-data-error';
|
||||
import { IGroup } from '../types/group';
|
||||
import { GroupService } from './group-service';
|
||||
import { IFlagResolver, IUnleashConfig } from 'lib/types';
|
||||
import { IFlagResolver, IUnleashConfig, IUserAccessOverview } from 'lib/types';
|
||||
|
||||
const { ADMIN } = permissions;
|
||||
|
||||
@ -736,4 +736,8 @@ export class AccessService {
|
||||
await this.validateRoleIsUnique(role.name, existingId);
|
||||
return cleanedRole;
|
||||
}
|
||||
|
||||
async getUserAccessOverview(): Promise<IUserAccessOverview[]> {
|
||||
return this.store.getUserAccessOverview();
|
||||
}
|
||||
}
|
||||
|
@ -459,3 +459,14 @@ export interface IFeatureStrategySegment {
|
||||
featureStrategyId: string;
|
||||
segmentId: number;
|
||||
}
|
||||
|
||||
export interface IUserAccessOverview {
|
||||
userId: number;
|
||||
createdAt?: Date;
|
||||
userName?: string;
|
||||
userEmail: number;
|
||||
lastSeen?: Date;
|
||||
accessibleProjects: string[];
|
||||
groups: string[];
|
||||
rootRole: string;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { PermissionRef } from 'lib/services/access-service';
|
||||
import { IGroupModelWithProjectRole } from '../group';
|
||||
import { IPermission, IUserWithRole } from '../model';
|
||||
import { IPermission, IUserAccessOverview, IUserWithRole } from '../model';
|
||||
import { Store } from './store';
|
||||
|
||||
export interface IUserPermission {
|
||||
@ -200,4 +200,5 @@ export interface IAccessStore extends Store<IRole, number> {
|
||||
): Promise<number[]>;
|
||||
removeUserAccess(projectId: string, userId: number): Promise<void>;
|
||||
removeGroupAccess(projectId: string, groupId: number): Promise<void>;
|
||||
getUserAccessOverview(): Promise<IUserAccessOverview[]>;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
ICreateGroupUserModel,
|
||||
IPermission,
|
||||
IUnleashStores,
|
||||
IUserAccessOverview,
|
||||
} from '../../../lib/types';
|
||||
import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
||||
import ProjectService from '../../../lib/services/project-service';
|
||||
@ -1851,3 +1852,65 @@ test('remove group access should remove all project roles, while leaving root ro
|
||||
expect(newAssignedPermissions.length).toBe(1);
|
||||
expect(newAssignedPermissions[0].permission).toBe(permissions.ADMIN);
|
||||
});
|
||||
|
||||
test('access overview should have admin access and default project for admin user', async () => {
|
||||
const email = 'a-person@places.com';
|
||||
|
||||
const { userStore } = stores;
|
||||
const user = await userStore.insert({
|
||||
name: 'Some User',
|
||||
email,
|
||||
});
|
||||
|
||||
await accessService.setUserRootRole(user.id, adminRole.id);
|
||||
|
||||
const accessOverView: IUserAccessOverview[] =
|
||||
await accessService.getUserAccessOverview();
|
||||
const userAccess = accessOverView.find(
|
||||
(overviewRow) => overviewRow.userId == user.id,
|
||||
)!;
|
||||
|
||||
expect(userAccess.userId).toBe(user.id);
|
||||
|
||||
expect(userAccess.rootRole).toBe('Admin');
|
||||
expect(userAccess.accessibleProjects).toStrictEqual(['default']);
|
||||
});
|
||||
|
||||
test('access overview should have group access for groups that they are in', async () => {
|
||||
const email = 'a-nother-person@places.com';
|
||||
|
||||
const { userStore } = stores;
|
||||
const user = await userStore.insert({
|
||||
name: 'Some Other User',
|
||||
email,
|
||||
});
|
||||
|
||||
await accessService.setUserRootRole(user.id, adminRole.id);
|
||||
|
||||
const group = await stores.groupStore.create({
|
||||
name: 'Test Group',
|
||||
});
|
||||
|
||||
await stores.groupStore.addUsersToGroup(
|
||||
group.id,
|
||||
[
|
||||
{
|
||||
user: {
|
||||
id: user.id,
|
||||
},
|
||||
},
|
||||
],
|
||||
'Admin',
|
||||
);
|
||||
|
||||
const accessOverView: IUserAccessOverview[] =
|
||||
await accessService.getUserAccessOverview();
|
||||
const userAccess = accessOverView.find(
|
||||
(overviewRow) => overviewRow.userId == user.id,
|
||||
)!;
|
||||
|
||||
expect(userAccess.userId).toBe(user.id);
|
||||
|
||||
expect(userAccess.rootRole).toBe('Admin');
|
||||
expect(userAccess.groups).toStrictEqual(['Test Group']);
|
||||
});
|
||||
|
6
src/test/fixtures/fake-access-store.ts
vendored
6
src/test/fixtures/fake-access-store.ts
vendored
@ -10,7 +10,7 @@ import {
|
||||
IUserWithProjectRoles,
|
||||
} from '../../lib/types/stores/access-store';
|
||||
import { IPermission } from 'lib/types/model';
|
||||
import { IRoleStore } from 'lib/types';
|
||||
import { IRoleStore, IUserAccessOverview } from 'lib/types';
|
||||
import FakeRoleStore from './fake-role-store';
|
||||
import { PermissionRef } from 'lib/services/access-service';
|
||||
|
||||
@ -289,6 +289,10 @@ class AccessStoreMock implements IAccessStore {
|
||||
removeGroupAccess(projectId: string, groupId: number): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
getUserAccessOverview(): Promise<IUserAccessOverview[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AccessStoreMock;
|
||||
|
Loading…
Reference in New Issue
Block a user