mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-17 01:17:29 +02:00
feat: return project roles (#8314)
This PR updates the personal dashboard project endpoint to return owners and roles. It also adds the impl for getting roles (via the access store). I'm filtering the roles for a project to only include project roles for now, but we might wanna change this later. Tests and UI update will follow.
This commit is contained in:
parent
050e53e564
commit
96d8dc353a
@ -16,6 +16,8 @@ import { AccountStore } from '../../db/account-store';
|
|||||||
import { FakeAccountStore } from '../../../test/fixtures/fake-account-store';
|
import { FakeAccountStore } from '../../../test/fixtures/fake-account-store';
|
||||||
import { OnboardingReadModel } from '../onboarding/onboarding-read-model';
|
import { OnboardingReadModel } from '../onboarding/onboarding-read-model';
|
||||||
import { FakeOnboardingReadModel } from '../onboarding/fake-onboarding-read-model';
|
import { FakeOnboardingReadModel } from '../onboarding/fake-onboarding-read-model';
|
||||||
|
import { AccessStore } from '../../db/access-store';
|
||||||
|
import FakeAccessStore from '../../../test/fixtures/fake-access-store';
|
||||||
|
|
||||||
export const createPersonalDashboardService = (
|
export const createPersonalDashboardService = (
|
||||||
db: Db,
|
db: Db,
|
||||||
@ -34,6 +36,7 @@ export const createPersonalDashboardService = (
|
|||||||
}),
|
}),
|
||||||
new PrivateProjectChecker(stores, config),
|
new PrivateProjectChecker(stores, config),
|
||||||
new AccountStore(db, config.getLogger),
|
new AccountStore(db, config.getLogger),
|
||||||
|
new AccessStore(db, config.eventBus, config.getLogger),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,5 +53,6 @@ export const createFakePersonalDashboardService = (config: IUnleashConfig) => {
|
|||||||
}),
|
}),
|
||||||
new FakePrivateProjectChecker(),
|
new FakePrivateProjectChecker(),
|
||||||
new FakeAccountStore(),
|
new FakeAccountStore(),
|
||||||
|
new FakeAccessStore(),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -215,14 +215,15 @@ test('should return projects where users are part of a group', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return personal dashboard project details', async () => {
|
test('should return personal dashboard project details', async () => {
|
||||||
await loginUser('new_user@test.com');
|
const { body: user } = await loginUser('new_user@test.com');
|
||||||
|
|
||||||
await app.createFeature('log_feature_a');
|
const project = await createProject(`x${randomId()}`, user);
|
||||||
await app.createFeature('log_feature_b');
|
await app.createFeature('log_feature_a', project.id);
|
||||||
await app.createFeature('log_feature_c');
|
await app.createFeature('log_feature_b', project.id);
|
||||||
|
await app.createFeature('log_feature_c', project.id);
|
||||||
|
|
||||||
const { body } = await app.request.get(
|
const { body } = await app.request.get(
|
||||||
`/api/admin/personal-dashboard/default`,
|
`/api/admin/personal-dashboard/${project.id}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(body).toMatchObject({
|
expect(body).toMatchObject({
|
||||||
@ -251,6 +252,12 @@ test('should return personal dashboard project details', async () => {
|
|||||||
'**new_user@test.com** created **[log_feature_a]',
|
'**new_user@test.com** created **[log_feature_a]',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
createdBy: 'audit user',
|
||||||
|
summary: expect.stringContaining(
|
||||||
|
`**audit user** created project **[${project.id}]`,
|
||||||
|
),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -106,6 +106,7 @@ export default class PersonalDashboardController extends Controller {
|
|||||||
|
|
||||||
const projectDetails =
|
const projectDetails =
|
||||||
await this.personalDashboardService.getPersonalProjectDetails(
|
await this.personalDashboardService.getPersonalProjectDetails(
|
||||||
|
user.id,
|
||||||
req.params.projectId,
|
req.params.projectId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -115,8 +116,6 @@ export default class PersonalDashboardController extends Controller {
|
|||||||
personalDashboardProjectDetailsSchema.$id,
|
personalDashboardProjectDetailsSchema.$id,
|
||||||
{
|
{
|
||||||
...projectDetails,
|
...projectDetails,
|
||||||
owners: [{ ownerType: 'user', name: 'placeholder' }],
|
|
||||||
roles: [{ name: 'placeholder', id: 0, type: 'project' }],
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import type {
|
|||||||
import type { IProjectReadModel } from '../project/project-read-model-type';
|
import type { IProjectReadModel } from '../project/project-read-model-type';
|
||||||
import type { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType';
|
import type { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType';
|
||||||
import type {
|
import type {
|
||||||
|
IAccessStore,
|
||||||
IAccountStore,
|
IAccountStore,
|
||||||
IEventStore,
|
IEventStore,
|
||||||
IOnboardingReadModel,
|
IOnboardingReadModel,
|
||||||
@ -36,6 +37,8 @@ export class PersonalDashboardService {
|
|||||||
|
|
||||||
private onboardingReadModel: IOnboardingReadModel;
|
private onboardingReadModel: IOnboardingReadModel;
|
||||||
|
|
||||||
|
private accessStore: IAccessStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
personalDashboardReadModel: IPersonalDashboardReadModel,
|
personalDashboardReadModel: IPersonalDashboardReadModel,
|
||||||
projectOwnersReadModel: IProjectOwnersReadModel,
|
projectOwnersReadModel: IProjectOwnersReadModel,
|
||||||
@ -45,6 +48,7 @@ export class PersonalDashboardService {
|
|||||||
featureEventFormatter: FeatureEventFormatter,
|
featureEventFormatter: FeatureEventFormatter,
|
||||||
privateProjectChecker: IPrivateProjectChecker,
|
privateProjectChecker: IPrivateProjectChecker,
|
||||||
accountStore: IAccountStore,
|
accountStore: IAccountStore,
|
||||||
|
accessStore: IAccessStore,
|
||||||
) {
|
) {
|
||||||
this.personalDashboardReadModel = personalDashboardReadModel;
|
this.personalDashboardReadModel = personalDashboardReadModel;
|
||||||
this.projectOwnersReadModel = projectOwnersReadModel;
|
this.projectOwnersReadModel = projectOwnersReadModel;
|
||||||
@ -54,6 +58,7 @@ export class PersonalDashboardService {
|
|||||||
this.featureEventFormatter = featureEventFormatter;
|
this.featureEventFormatter = featureEventFormatter;
|
||||||
this.privateProjectChecker = privateProjectChecker;
|
this.privateProjectChecker = privateProjectChecker;
|
||||||
this.accountStore = accountStore;
|
this.accountStore = accountStore;
|
||||||
|
this.accessStore = accessStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPersonalFeatures(userId: number): Promise<PersonalFeature[]> {
|
getPersonalFeatures(userId: number): Promise<PersonalFeature[]> {
|
||||||
@ -95,6 +100,7 @@ export class PersonalDashboardService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getPersonalProjectDetails(
|
async getPersonalProjectDetails(
|
||||||
|
userId: number,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
): Promise<PersonalDashboardProjectDetailsSchema> {
|
): Promise<PersonalDashboardProjectDetailsSchema> {
|
||||||
const recentEvents = await this.eventStore.searchEvents(
|
const recentEvents = await this.eventStore.searchEvents(
|
||||||
@ -117,11 +123,24 @@ export class PersonalDashboardService {
|
|||||||
const owners =
|
const owners =
|
||||||
await this.projectOwnersReadModel.getProjectOwners(projectId);
|
await this.projectOwnersReadModel.getProjectOwners(projectId);
|
||||||
|
|
||||||
|
const allRoles = await this.accessStore.getAllProjectRolesForUser(
|
||||||
|
userId,
|
||||||
|
projectId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const projectRoles = allRoles
|
||||||
|
.filter((role) => ['project', 'custom'].includes(role.type))
|
||||||
|
.map((role) => ({
|
||||||
|
id: role.id,
|
||||||
|
name: role.name,
|
||||||
|
type: role.type as PersonalDashboardProjectDetailsSchema['roles'][number]['type'],
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
latestEvents: formattedEvents,
|
latestEvents: formattedEvents,
|
||||||
onboardingStatus,
|
onboardingStatus,
|
||||||
owners,
|
owners,
|
||||||
roles: [],
|
roles: projectRoles,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import FakeGroupStore from '../../test/fixtures/fake-group-store';
|
|||||||
import { FakeAccountStore } from '../../test/fixtures/fake-account-store';
|
import { FakeAccountStore } from '../../test/fixtures/fake-account-store';
|
||||||
import FakeRoleStore from '../../test/fixtures/fake-role-store';
|
import FakeRoleStore from '../../test/fixtures/fake-role-store';
|
||||||
import FakeEnvironmentStore from '../features/project-environments/fake-environment-store';
|
import FakeEnvironmentStore from '../features/project-environments/fake-environment-store';
|
||||||
import AccessStoreMock from '../../test/fixtures/fake-access-store';
|
import FakeAccessStore from '../../test/fixtures/fake-access-store';
|
||||||
import { GroupService } from '../services/group-service';
|
import { GroupService } from '../services/group-service';
|
||||||
import type { IRole } from '../../lib/types/stores/access-store';
|
import type { IRole } from '../../lib/types/stores/access-store';
|
||||||
import {
|
import {
|
||||||
@ -271,7 +271,7 @@ test('throws error when trying to delete a project role in use by group', async
|
|||||||
const accountStore = new FakeAccountStore();
|
const accountStore = new FakeAccountStore();
|
||||||
const roleStore = new FakeRoleStore();
|
const roleStore = new FakeRoleStore();
|
||||||
const environmentStore = new FakeEnvironmentStore();
|
const environmentStore = new FakeEnvironmentStore();
|
||||||
const accessStore = new AccessStoreMock();
|
const accessStore = new FakeAccessStore();
|
||||||
accessStore.getGroupIdsForRole = groupIdResultOverride;
|
accessStore.getGroupIdsForRole = groupIdResultOverride;
|
||||||
accessStore.getUserIdsForRole = async (): Promise<number[]> => {
|
accessStore.getUserIdsForRole = async (): Promise<number[]> => {
|
||||||
return [];
|
return [];
|
||||||
|
6
src/test/fixtures/fake-access-store.ts
vendored
6
src/test/fixtures/fake-access-store.ts
vendored
@ -19,7 +19,7 @@ import {
|
|||||||
import FakeRoleStore from './fake-role-store';
|
import FakeRoleStore from './fake-role-store';
|
||||||
import type { PermissionRef } from '../../lib/services/access-service';
|
import type { PermissionRef } from '../../lib/services/access-service';
|
||||||
|
|
||||||
class AccessStoreMock implements IAccessStore {
|
export class FakeAccessStore implements IAccessStore {
|
||||||
fakeRolesStore: IRoleStore;
|
fakeRolesStore: IRoleStore;
|
||||||
|
|
||||||
userToRoleMap: Map<number, number> = new Map();
|
userToRoleMap: Map<number, number> = new Map();
|
||||||
@ -327,6 +327,6 @@ class AccessStoreMock implements IAccessStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AccessStoreMock;
|
module.exports = FakeAccessStore;
|
||||||
|
|
||||||
export default AccessStoreMock;
|
export default FakeAccessStore;
|
||||||
|
Loading…
Reference in New Issue
Block a user