Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
La-toile-cosmique committed Sep 23, 2024
1 parent 43927ad commit def3fb5
Show file tree
Hide file tree
Showing 15 changed files with 183 additions and 166 deletions.
51 changes: 0 additions & 51 deletions api/lib/application/users/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,6 @@ const register = async function (server) {
tags: ['api', 'admin', 'user'],
},
},
{
method: 'GET',
path: '/api/admin/users/{id}/profile',
config: {
pre: [
{
method: (request, h) =>
securityPreHandlers.hasAtLeastOneAccessOf([
securityPreHandlers.checkAdminMemberHasRoleSuperAdmin,
securityPreHandlers.checkAdminMemberHasRoleCertif,
securityPreHandlers.checkAdminMemberHasRoleSupport,
securityPreHandlers.checkAdminMemberHasRoleMetier,
])(request, h),
},
],
validate: {
params: Joi.object({
id: identifiersType.userId,
}),
},
handler: userController.getProfileForAdmin,
notes: [
"- Permet à un administrateur de récupérer le nombre total de Pix d'un utilisateur\n et de ses scorecards",
],
tags: ['api', 'user', 'profile'],
},
},
{
method: 'GET',
path: '/api/admin/users/{id}/organizations',
Expand Down Expand Up @@ -351,30 +324,6 @@ const register = async function (server) {
tags: ['api'],
},
},
{
method: 'GET',
path: '/api/users/{id}/profile',
config: {
pre: [
{
method: securityPreHandlers.checkRequestedUserIsAuthenticatedUser,
assign: 'requestedUserIsAuthenticatedUser',
},
],
validate: {
params: Joi.object({
id: identifiersType.userId,
}),
},
handler: userController.getProfile,
notes: [
'- **Cette route est restreinte aux utilisateurs authentifiés**\n' +
"- Récupération du nombre total de Pix de l'utilisateur\n et de ses scorecards" +
'- L’id demandé doit correspondre à celui de l’utilisateur authentifié',
],
tags: ['api', 'user', 'profile'],
},
},
{
method: 'GET',
path: '/api/users/{userId}/campaigns/{campaignId}/profile',
Expand Down
19 changes: 0 additions & 19 deletions api/lib/application/users/user-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { DomainTransaction } from '../../infrastructure/DomainTransaction.js';
import * as campaignParticipationOverviewSerializer from '../../infrastructure/serializers/jsonapi/campaign-participation-overview-serializer.js';
import * as certificationCenterMembershipSerializer from '../../infrastructure/serializers/jsonapi/certification-center-membership-serializer.js';
import * as participantResultSerializer from '../../infrastructure/serializers/jsonapi/participant-result-serializer.js';
import * as profileSerializer from '../../infrastructure/serializers/jsonapi/profile-serializer.js';
import * as sharedProfileForCampaignSerializer from '../../infrastructure/serializers/jsonapi/shared-profile-for-campaign-serializer.js';
import * as userAnonymizedDetailsForAdminSerializer from '../../infrastructure/serializers/jsonapi/user-anonymized-details-for-admin-serializer.js';
import * as userDetailsForAdminSerializer from '../../infrastructure/serializers/jsonapi/user-details-for-admin-serializer.js';
Expand Down Expand Up @@ -112,22 +111,6 @@ const getCampaignParticipationOverviews = async function (
);
};

const getProfile = function (request, h, dependencies = { profileSerializer, requestResponseUtils }) {
const authenticatedUserId = request.auth.credentials.userId;
const locale = dependencies.requestResponseUtils.extractLocaleFromRequest(request);

return usecases
.getUserProfile({ userId: authenticatedUserId, locale })
.then(dependencies.profileSerializer.serialize);
};

const getProfileForAdmin = function (request, h, dependencies = { profileSerializer, requestResponseUtils }) {
const userId = request.params.id;
const locale = dependencies.requestResponseUtils.extractLocaleFromRequest(request);

return usecases.getUserProfile({ userId, locale }).then(dependencies.profileSerializer.serialize);
};

const resetScorecard = function (request, h, dependencies = { scorecardSerializer, requestResponseUtils }) {
const authenticatedUserId = request.auth.credentials.userId;
const competenceId = request.params.competenceId;
Expand Down Expand Up @@ -279,8 +262,6 @@ const userController = {
findUserOrganizationsForAdmin,
getCampaignParticipationOverviews,
getCampaignParticipations,
getProfile,
getProfileForAdmin,
getUserCampaignAssessmentResult,
getUserCampaignParticipationToCampaign,
getUserDetailsForAdmin,
Expand Down
2 changes: 2 additions & 0 deletions api/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { learnerManagementRoutes } from './src/prescription/learner-management/r
import { organizationLearnerRoutes } from './src/prescription/organization-learner/routes.js';
import { organizationPlaceRoutes } from './src/prescription/organization-place/routes.js';
import { targetProfileRoutes } from './src/prescription/target-profile/routes.js';
import { profileRoutes } from './src/profile/routes.js';
import { schoolRoutes } from './src/school/routes.js';
import { config } from './src/shared/config.js';
import { monitoringTools } from './src/shared/infrastructure/monitoring-tools.js';
Expand Down Expand Up @@ -150,6 +151,7 @@ const setupRoutesAndPlugins = async function (server) {
identityAccessManagementRoutes,
organizationalEntitiesRoutes,
sharedRoutes,
profileRoutes,
evaluationRoutes,
flashCertificationRoutes,
devcompRoutes,
Expand Down
64 changes: 64 additions & 0 deletions api/src/profile/application/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Joi from 'joi';

import { securityPreHandlers } from '../../../src/shared/application/security-pre-handlers.js';
import { identifiersType } from '../../../src/shared/domain/types/identifiers-type.js';
import { profileController } from './profile-controller.js';

const register = async function (server) {
server.route([
{
method: 'GET',
path: '/api/users/{id}/profile',
config: {
pre: [
{
method: securityPreHandlers.checkRequestedUserIsAuthenticatedUser,
assign: 'requestedUserIsAuthenticatedUser',
},
],
validate: {
params: Joi.object({
id: identifiersType.userId,
}),
},
handler: profileController.getProfile,
notes: [
'- **Cette route est restreinte aux utilisateurs authentifiés**\n' +
"- Récupération du nombre total de Pix de l'utilisateur\n et de ses scorecards" +
'- L’id demandé doit correspondre à celui de l’utilisateur authentifié',
],
tags: ['api', 'user', 'profile'],
},
},
{
method: 'GET',
path: '/api/admin/users/{id}/profile',
config: {
pre: [
{
method: (request, h) =>
securityPreHandlers.hasAtLeastOneAccessOf([
securityPreHandlers.checkAdminMemberHasRoleSuperAdmin,
securityPreHandlers.checkAdminMemberHasRoleCertif,
securityPreHandlers.checkAdminMemberHasRoleSupport,
securityPreHandlers.checkAdminMemberHasRoleMetier,
])(request, h),
},
],
validate: {
params: Joi.object({
id: identifiersType.userId,
}),
},
handler: profileController.getProfileForAdmin,
notes: [
"- Permet à un administrateur de récupérer le nombre total de Pix d'un utilisateur\n et de ses scorecards",
],
tags: ['api', 'user', 'profile'],
},
},
]);
};

const name = 'profile-api';
export { name, register };
26 changes: 26 additions & 0 deletions api/src/profile/application/profile-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as requestResponseUtils from '../../../src/shared/infrastructure/utils/request-response-utils.js';
import { usecases } from '../domain/usecases/index.js';
import * as profileSerializer from '../infrastructure/serializers/jsonapi/profile-serializer.js';

const getProfile = function (request, h, dependencies = { profileSerializer, requestResponseUtils }) {
const authenticatedUserId = request.auth.credentials.userId;
const locale = dependencies.requestResponseUtils.extractLocaleFromRequest(request);

return usecases
.getUserProfile({ userId: authenticatedUserId, locale })
.then(dependencies.profileSerializer.serialize);
};

const getProfileForAdmin = function (request, h, dependencies = { profileSerializer, requestResponseUtils }) {
const userId = request.params.id;
const locale = dependencies.requestResponseUtils.extractLocaleFromRequest(request);

return usecases.getUserProfile({ userId, locale }).then(dependencies.profileSerializer.serialize);
};

const profileController = {
getProfile,
getProfileForAdmin,
};

export { profileController };
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _ from 'lodash';

import { Scorecard } from '../../../src/evaluation/domain/models/Scorecard.js';
import { constants } from '../../../src/shared/domain/constants.js';
import { Scorecard } from '../../../evaluation/domain/models/Scorecard.js';
import { constants } from '../../../shared/domain/constants.js';

const getUserProfile = async function ({
userId,
Expand Down
8 changes: 8 additions & 0 deletions api/src/profile/domain/usecases/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';

import * as knowledgeElementRepository from '../../../../lib/infrastructure/repositories/knowledge-element-repository.js';
import * as competenceEvaluationRepository from '../../../evaluation/infrastructure/repositories/competence-evaluation-repository.js';
import * as profileRewardRepository from '../../../profile/infrastructure/repositories/profile-reward-repository.js';
import * as areaRepository from '../../../shared/infrastructure/repositories/area-repository.js';
import * as competenceRepository from '../../../shared/infrastructure/repositories/competence-repository.js';
import { injectDependencies } from '../../../shared/infrastructure/utils/dependency-injection.js';
import { importNamedExportsFromDirectory } from '../../../shared/infrastructure/utils/import-named-exports-from-directory.js';

Expand All @@ -12,6 +16,10 @@ const usecasesWithoutInjectedDependencies = {
};

const dependencies = {
competenceRepository,
areaRepository,
competenceEvaluationRepository,
knowledgeElementRepository,
profileRewardRepository,
};

Expand Down
5 changes: 5 additions & 0 deletions api/src/profile/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as profileRoute from './application/index.js';

const profileRoutes = [profileRoute];

export { profileRoutes };
27 changes: 27 additions & 0 deletions api/tests/profile/unit/application/index_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as moduleUnderTest from '../../../../src/profile/application/index.js';
import { profileController } from '../../../../src/profile/application/profile-controller.js';
import { securityPreHandlers } from '../../../../src/shared/application/security-pre-handlers.js';
import { HttpTestServer, sinon } from '../../../../tests/test-helper.js';

describe('Unit | Router | user-router', function () {
describe('GET /api/users/{id}/profile', function () {
const method = 'GET';
const url = '/api/users/42/profile';

it('exists', async function () {
// given
sinon.stub(profileController, 'getProfile').returns('ok');
sinon
.stub(securityPreHandlers, 'checkRequestedUserIsAuthenticatedUser')
.callsFake((request, h) => h.response(true));
const httpTestServer = new HttpTestServer();
await httpTestServer.register(moduleUnderTest);

// when
await httpTestServer.request(method, url);

// then
sinon.assert.calledOnce(profileController.getProfile);
});
});
});
41 changes: 41 additions & 0 deletions api/tests/profile/unit/application/profile-controller_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { profileController } from '../../../../src/profile/application/profile-controller.js';
import { usecases } from '../../../../src/profile/domain/usecases/index.js';
import * as requestResponseUtils from '../../../../src/shared/infrastructure/utils/request-response-utils.js';
import { expect, hFake, sinon } from '../../../test-helper.js';

describe('Profile | Unit | Controller | profile-controller', function () {
describe('#getProfile', function () {
beforeEach(function () {
sinon.stub(usecases, 'getUserProfile').resolves({
pixScore: 3,
scorecards: [],
});
});

it('should call the expected usecase', async function () {
// given
const profileSerializer = { serialize: sinon.stub() };
profileSerializer.serialize.resolves();
const userId = '12';
const locale = 'fr';

const request = {
auth: {
credentials: {
userId,
},
},
params: {
id: userId,
},
headers: { 'accept-language': locale },
};

// when
await profileController.getProfile(request, hFake, { profileSerializer, requestResponseUtils });

// then
expect(usecases.getUserProfile).to.have.been.calledWithExactly({ userId, locale });
});
});
});
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import _ from 'lodash';

import { getUserProfile } from '../../../../lib/domain/usecases/get-user-profile.js';
import { Scorecard } from '../../../../src/evaluation/domain/models/Scorecard.js';
import { constants } from '../../../../src/shared/domain/constants.js';
import { domainBuilder, expect, sinon } from '../../../test-helper.js';
import { Scorecard } from '../../../../../src/evaluation/domain/models/Scorecard.js';
import { getUserProfile } from '../../../../../src/profile/domain/usecases/get-user-profile.js';
import { constants } from '../../../../../src/shared/domain/constants.js';
import { domainBuilder, expect, sinon } from '../../../../test-helper.js';

function assertScorecard(userScorecard, expectedUserScorecard) {
expect(userScorecard.earnedPix).to.equal(expectedUserScorecard.earnedPix);
Expand All @@ -12,7 +12,7 @@ function assertScorecard(userScorecard, expectedUserScorecard) {
expect(userScorecard.status).to.equal(expectedUserScorecard.status);
}

describe('Unit | UseCase | get-user-profile', function () {
describe('Profile | Unit | UseCase | get-user-profile', function () {
let competenceRepository;
let areaRepository;
let knowledgeElementRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as serializer from '../../../../../lib/infrastructure/serializers/jsonapi/profile-serializer.js';
import { MAX_REACHABLE_LEVEL } from '../../../../../src/shared/domain/constants.js';
import { domainBuilder, expect } from '../../../../test-helper.js';
import * as serializer from '../../../../../../src/profile/infrastructure/serializers/jsonapi/profile-serializer.js';
import { MAX_REACHABLE_LEVEL } from '../../../../../../src/shared/domain/constants.js';
import { domainBuilder, expect } from '../../../../../test-helper.js';

describe('Unit | Serializer | JSONAPI | profile', function () {
describe('#serialize()', function () {
Expand Down
21 changes: 0 additions & 21 deletions api/tests/unit/application/users/index_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,6 @@ const CODE_IDENTITY_PROVIDER_POLE_EMPLOI = OidcIdentityProviders.POLE_EMPLOI.cod
const oidcProviderCode = 'genericOidcProviderCode';

describe('Unit | Router | user-router', function () {
describe('GET /api/users/{id}/profile', function () {
const method = 'GET';
const url = '/api/users/42/profile';

it('exists', async function () {
// given
sinon.stub(userController, 'getProfile').returns('ok');
sinon
.stub(securityPreHandlers, 'checkRequestedUserIsAuthenticatedUser')
.callsFake((request, h) => h.response(true));
const httpTestServer = new HttpTestServer();
await httpTestServer.register(moduleUnderTest);

// when
await httpTestServer.request(method, url);

// then
sinon.assert.calledOnce(userController.getProfile);
});
});

describe('GET /api/users/{userId}/campaigns/{campaignId}/profile', function () {
const method = 'GET';

Expand Down
Loading

0 comments on commit def3fb5

Please sign in to comment.