diff --git a/src/lib/features/personal-dashboard/createPersonalDashboardService.ts b/src/lib/features/personal-dashboard/createPersonalDashboardService.ts index ec830ab6dc..8f5955f970 100644 --- a/src/lib/features/personal-dashboard/createPersonalDashboardService.ts +++ b/src/lib/features/personal-dashboard/createPersonalDashboardService.ts @@ -16,6 +16,8 @@ import { AccountStore } from '../../db/account-store'; import { FakeAccountStore } from '../../../test/fixtures/fake-account-store'; import { OnboardingReadModel } from '../onboarding/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 = ( db: Db, @@ -34,6 +36,7 @@ export const createPersonalDashboardService = ( }), new PrivateProjectChecker(stores, config), new AccountStore(db, config.getLogger), + new AccessStore(db, config.eventBus, config.getLogger), ); }; @@ -50,5 +53,6 @@ export const createFakePersonalDashboardService = (config: IUnleashConfig) => { }), new FakePrivateProjectChecker(), new FakeAccountStore(), + new FakeAccessStore(), ); }; diff --git a/src/lib/features/personal-dashboard/personal-dashboard-controller.e2e.test.ts b/src/lib/features/personal-dashboard/personal-dashboard-controller.e2e.test.ts index ad46766963..acc6214afa 100644 --- a/src/lib/features/personal-dashboard/personal-dashboard-controller.e2e.test.ts +++ b/src/lib/features/personal-dashboard/personal-dashboard-controller.e2e.test.ts @@ -215,14 +215,15 @@ test('should return projects where users are part of a group', 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'); - await app.createFeature('log_feature_b'); - await app.createFeature('log_feature_c'); + const project = await createProject(`x${randomId()}`, user); + await app.createFeature('log_feature_a', project.id); + await app.createFeature('log_feature_b', project.id); + await app.createFeature('log_feature_c', project.id); const { body } = await app.request.get( - `/api/admin/personal-dashboard/default`, + `/api/admin/personal-dashboard/${project.id}`, ); expect(body).toMatchObject({ @@ -251,6 +252,12 @@ test('should return personal dashboard project details', async () => { '**new_user@test.com** created **[log_feature_a]', ), }, + { + createdBy: 'audit user', + summary: expect.stringContaining( + `**audit user** created project **[${project.id}]`, + ), + }, ], }); }); diff --git a/src/lib/features/personal-dashboard/personal-dashboard-controller.ts b/src/lib/features/personal-dashboard/personal-dashboard-controller.ts index 5594c39a54..0eed071379 100644 --- a/src/lib/features/personal-dashboard/personal-dashboard-controller.ts +++ b/src/lib/features/personal-dashboard/personal-dashboard-controller.ts @@ -106,6 +106,7 @@ export default class PersonalDashboardController extends Controller { const projectDetails = await this.personalDashboardService.getPersonalProjectDetails( + user.id, req.params.projectId, ); @@ -115,8 +116,6 @@ export default class PersonalDashboardController extends Controller { personalDashboardProjectDetailsSchema.$id, { ...projectDetails, - owners: [{ ownerType: 'user', name: 'placeholder' }], - roles: [{ name: 'placeholder', id: 0, type: 'project' }], }, ); } diff --git a/src/lib/features/personal-dashboard/personal-dashboard-service.ts b/src/lib/features/personal-dashboard/personal-dashboard-service.ts index b97f426393..fcbbe08733 100644 --- a/src/lib/features/personal-dashboard/personal-dashboard-service.ts +++ b/src/lib/features/personal-dashboard/personal-dashboard-service.ts @@ -10,6 +10,7 @@ import type { import type { IProjectReadModel } from '../project/project-read-model-type'; import type { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType'; import type { + IAccessStore, IAccountStore, IEventStore, IOnboardingReadModel, @@ -36,6 +37,8 @@ export class PersonalDashboardService { private onboardingReadModel: IOnboardingReadModel; + private accessStore: IAccessStore; + constructor( personalDashboardReadModel: IPersonalDashboardReadModel, projectOwnersReadModel: IProjectOwnersReadModel, @@ -45,6 +48,7 @@ export class PersonalDashboardService { featureEventFormatter: FeatureEventFormatter, privateProjectChecker: IPrivateProjectChecker, accountStore: IAccountStore, + accessStore: IAccessStore, ) { this.personalDashboardReadModel = personalDashboardReadModel; this.projectOwnersReadModel = projectOwnersReadModel; @@ -54,6 +58,7 @@ export class PersonalDashboardService { this.featureEventFormatter = featureEventFormatter; this.privateProjectChecker = privateProjectChecker; this.accountStore = accountStore; + this.accessStore = accessStore; } getPersonalFeatures(userId: number): Promise { @@ -95,6 +100,7 @@ export class PersonalDashboardService { } async getPersonalProjectDetails( + userId: number, projectId: string, ): Promise { const recentEvents = await this.eventStore.searchEvents( @@ -117,11 +123,24 @@ export class PersonalDashboardService { const owners = 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 { latestEvents: formattedEvents, onboardingStatus, owners, - roles: [], + roles: projectRoles, }; } diff --git a/src/lib/services/access-service.test.ts b/src/lib/services/access-service.test.ts index 5bfa3f229d..45b10e1526 100644 --- a/src/lib/services/access-service.test.ts +++ b/src/lib/services/access-service.test.ts @@ -12,7 +12,7 @@ import FakeGroupStore from '../../test/fixtures/fake-group-store'; import { FakeAccountStore } from '../../test/fixtures/fake-account-store'; import FakeRoleStore from '../../test/fixtures/fake-role-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 type { IRole } from '../../lib/types/stores/access-store'; 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 roleStore = new FakeRoleStore(); const environmentStore = new FakeEnvironmentStore(); - const accessStore = new AccessStoreMock(); + const accessStore = new FakeAccessStore(); accessStore.getGroupIdsForRole = groupIdResultOverride; accessStore.getUserIdsForRole = async (): Promise => { return []; diff --git a/src/test/fixtures/fake-access-store.ts b/src/test/fixtures/fake-access-store.ts index 54ff526766..737cd24a8a 100644 --- a/src/test/fixtures/fake-access-store.ts +++ b/src/test/fixtures/fake-access-store.ts @@ -19,7 +19,7 @@ import { import FakeRoleStore from './fake-role-store'; import type { PermissionRef } from '../../lib/services/access-service'; -class AccessStoreMock implements IAccessStore { +export class FakeAccessStore implements IAccessStore { fakeRolesStore: IRoleStore; userToRoleMap: Map = new Map(); @@ -327,6 +327,6 @@ class AccessStoreMock implements IAccessStore { } } -module.exports = AccessStoreMock; +module.exports = FakeAccessStore; -export default AccessStoreMock; +export default FakeAccessStore;