From e94ed2878cc3749486774c9c48f4d70aadca97e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannick=20Fran=C3=A7ois?= Date: Thu, 21 Nov 2024 10:55:09 +0100 Subject: [PATCH] :recycle: refactor: extract admin route to results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andreia Pena Co-authored-by: Jérémy Pluquet Co-authored-by: Alexandre Coin Co-Authored-By: GUL --- .../certification-course-controller.js | 13 ---- .../application/certification-course-route.js | 32 --------- .../certification-results-controller.js | 14 ++++ .../certification-results-route.js | 30 ++++++++ .../certified-profile-repository.js | 0 .../certified-profile-serializer.js | 0 .../certified-profile-repository_test.js | 2 +- .../certification-courses-route_test.js | 16 ----- .../certification-results-controller_test.js | 63 +++++++++++++++++ .../certification-results-route_test.js | 17 +++++ .../certified-profile-serializer_test.js | 4 +- .../certification-course-controller_test.js | 68 +------------------ 12 files changed, 128 insertions(+), 131 deletions(-) rename api/src/certification/{evaluation => results}/infrastructure/repositories/certified-profile-repository.js (100%) rename api/src/certification/{evaluation => results}/infrastructure/serializers/certified-profile-serializer.js (100%) rename api/tests/certification/{evaluation/integration => results/unit/infrastructure}/serializers/certified-profile-serializer_test.js (95%) diff --git a/api/src/certification/evaluation/application/certification-course-controller.js b/api/src/certification/evaluation/application/certification-course-controller.js index 32b3dada21a..ef2c6b84091 100644 --- a/api/src/certification/evaluation/application/certification-course-controller.js +++ b/api/src/certification/evaluation/application/certification-course-controller.js @@ -1,9 +1,7 @@ import { extractLocaleFromRequest } from '../../../shared/infrastructure/utils/request-response-utils.js'; import { usecases as certificationSharedUsecases } from '../../shared/domain/usecases/index.js'; import { usecases } from '../domain/usecases/index.js'; -import * as certifiedProfileRepository from '../infrastructure/repositories/certified-profile-repository.js'; import * as certificationCourseSerializer from '../infrastructure/serializers/certification-course-serializer.js'; -import * as certifiedProfileSerializer from '../infrastructure/serializers/certified-profile-serializer.js'; const save = async function (request, h, dependencies = { extractLocaleFromRequest, certificationCourseSerializer }) { const userId = request.auth.credentials.userId; @@ -29,20 +27,9 @@ const get = async function (request, h, dependencies = { certificationCourseSeri return dependencies.certificationCourseSerializer.serialize(certificationCourse); }; -const getCertifiedProfile = async function ( - request, - h, - dependencies = { certifiedProfileRepository, certifiedProfileSerializer }, -) { - const certificationCourseId = request.params.id; - const certifiedProfile = await dependencies.certifiedProfileRepository.get(certificationCourseId); - return dependencies.certifiedProfileSerializer.serialize(certifiedProfile); -}; - const certificationCourseController = { save, get, - getCertifiedProfile, }; export { certificationCourseController }; diff --git a/api/src/certification/evaluation/application/certification-course-route.js b/api/src/certification/evaluation/application/certification-course-route.js index 2ab40a7e19c..1db53aacc95 100644 --- a/api/src/certification/evaluation/application/certification-course-route.js +++ b/api/src/certification/evaluation/application/certification-course-route.js @@ -5,39 +5,7 @@ import { identifiersType } from '../../../shared/domain/types/identifiers-type.j import { certificationCourseController } from './certification-course-controller.js'; const register = async function (server) { - const adminRoutes = [ - { - method: 'GET', - path: '/api/admin/certifications/{id}/certified-profile', - config: { - pre: [ - { - method: (request, h) => - securityPreHandlers.hasAtLeastOneAccessOf([ - securityPreHandlers.checkAdminMemberHasRoleSuperAdmin, - securityPreHandlers.checkAdminMemberHasRoleCertif, - securityPreHandlers.checkAdminMemberHasRoleSupport, - securityPreHandlers.checkAdminMemberHasRoleMetier, - ])(request, h), - assign: 'hasAuthorizationToAccessAdminScope', - }, - ], - validate: { - params: Joi.object({ - id: identifiersType.certificationCourseId, - }), - }, - handler: certificationCourseController.getCertifiedProfile, - tags: ['api'], - notes: [ - 'Cette route est utilisé par Pix Admin', - 'Elle permet de récupérer le profil certifié pour une certification donnée', - ], - }, - }, - ]; server.route([ - ...adminRoutes, { method: 'POST', path: '/api/certification-courses', diff --git a/api/src/certification/results/application/certification-results-controller.js b/api/src/certification/results/application/certification-results-controller.js index 74a6366c6f3..57aefea10cc 100644 --- a/api/src/certification/results/application/certification-results-controller.js +++ b/api/src/certification/results/application/certification-results-controller.js @@ -2,6 +2,8 @@ import dayjs from 'dayjs'; import { tokenService } from '../../../shared/domain/services/token-service.js'; import { usecases } from '../domain/usecases/index.js'; +import * as certifiedProfileRepository from '../infrastructure/repositories/certified-profile-repository.js'; +import * as certifiedProfileSerializer from '../infrastructure/serializers/certified-profile-serializer.js'; import { getCleaCertifiedCandidateCsv } from '../infrastructure/utils/csv/certification-results/get-clea-certified-candidate-csv.js'; import { getSessionCertificationResultsCsv } from '../infrastructure/utils/csv/certification-results/get-session-certification-results-csv.js'; @@ -69,10 +71,22 @@ const getSessionResultsToDownload = async function ( .header('Content-Disposition', `attachment; filename=${csvResult.filename}`); }; +const getCertifiedProfile = async function ( + request, + h, + dependencies = { certifiedProfileRepository, certifiedProfileSerializer }, +) { + const certificationCourseId = request.params.id; + //TODO add passthrough usecase to remove link between application and infrastructure + const certifiedProfile = await dependencies.certifiedProfileRepository.get(certificationCourseId); + return dependencies.certifiedProfileSerializer.serialize(certifiedProfile); +}; + const certificationResultsController = { getCleaCertifiedCandidateDataCsv, getSessionResultsByRecipientEmail, getSessionResultsToDownload, + getCertifiedProfile, }; export { certificationResultsController }; diff --git a/api/src/certification/results/application/certification-results-route.js b/api/src/certification/results/application/certification-results-route.js index a8e1b31615a..f8f05f104d3 100644 --- a/api/src/certification/results/application/certification-results-route.js +++ b/api/src/certification/results/application/certification-results-route.js @@ -1,11 +1,41 @@ import Joi from 'joi'; +import { securityPreHandlers } from '../../../shared/application/security-pre-handlers.js'; import { identifiersType } from '../../../shared/domain/types/identifiers-type.js'; import { authorization } from '../../shared/application/pre-handlers/authorization.js'; import { certificationResultsController } from './certification-results-controller.js'; const register = async function (server) { server.route([ + { + method: 'GET', + path: '/api/admin/certifications/{id}/certified-profile', + config: { + pre: [ + { + method: (request, h) => + securityPreHandlers.hasAtLeastOneAccessOf([ + securityPreHandlers.checkAdminMemberHasRoleSuperAdmin, + securityPreHandlers.checkAdminMemberHasRoleCertif, + securityPreHandlers.checkAdminMemberHasRoleSupport, + securityPreHandlers.checkAdminMemberHasRoleMetier, + ])(request, h), + assign: 'hasAuthorizationToAccessAdminScope', + }, + ], + validate: { + params: Joi.object({ + id: identifiersType.certificationCourseId, + }), + }, + handler: certificationResultsController.getCertifiedProfile, + tags: ['api'], + notes: [ + 'Cette route est utilisé par Pix Admin', + 'Elle permet de récupérer le profil certifié pour une certification donnée', + ], + }, + }, { method: 'GET', path: '/api/sessions/{sessionId}/certified-clea-candidate-data', diff --git a/api/src/certification/evaluation/infrastructure/repositories/certified-profile-repository.js b/api/src/certification/results/infrastructure/repositories/certified-profile-repository.js similarity index 100% rename from api/src/certification/evaluation/infrastructure/repositories/certified-profile-repository.js rename to api/src/certification/results/infrastructure/repositories/certified-profile-repository.js diff --git a/api/src/certification/evaluation/infrastructure/serializers/certified-profile-serializer.js b/api/src/certification/results/infrastructure/serializers/certified-profile-serializer.js similarity index 100% rename from api/src/certification/evaluation/infrastructure/serializers/certified-profile-serializer.js rename to api/src/certification/results/infrastructure/serializers/certified-profile-serializer.js diff --git a/api/tests/certification/evaluation/integration/infrastructure/repositories/certified-profile-repository_test.js b/api/tests/certification/evaluation/integration/infrastructure/repositories/certified-profile-repository_test.js index 5dd9e985335..8002452b48f 100644 --- a/api/tests/certification/evaluation/integration/infrastructure/repositories/certified-profile-repository_test.js +++ b/api/tests/certification/evaluation/integration/infrastructure/repositories/certified-profile-repository_test.js @@ -1,4 +1,4 @@ -import * as certifiedProfileRepository from '../../../../../../src/certification/evaluation/infrastructure/repositories/certified-profile-repository.js'; +import * as certifiedProfileRepository from '../../../../../../src/certification/results/infrastructure/repositories/certified-profile-repository.js'; import { NotFoundError } from '../../../../../../src/shared/domain/errors.js'; import { KnowledgeElement } from '../../../../../../src/shared/domain/models/KnowledgeElement.js'; import { CertifiedProfile } from '../../../../../../src/shared/domain/read-models/CertifiedProfile.js'; diff --git a/api/tests/certification/evaluation/unit/application/certification-courses-route_test.js b/api/tests/certification/evaluation/unit/application/certification-courses-route_test.js index 3c9b824518f..71f1f7f9a19 100644 --- a/api/tests/certification/evaluation/unit/application/certification-courses-route_test.js +++ b/api/tests/certification/evaluation/unit/application/certification-courses-route_test.js @@ -4,22 +4,6 @@ import { securityPreHandlers } from '../../../../../src/shared/application/secur import { expect, HttpTestServer, sinon } from '../../../../test-helper.js'; describe('Unit | Application | Certifications Course | Route', function () { - describe('GET /api/admin/certifications/{id}/certified-profile', function () { - it('should exist', async function () { - // given - sinon.stub(securityPreHandlers, 'hasAtLeastOneAccessOf').returns(() => true); - sinon.stub(certificationCoursesController, 'getCertifiedProfile').returns('ok'); - const httpTestServer = new HttpTestServer(); - await httpTestServer.register(moduleUnderTest); - - // when - const response = await httpTestServer.request('GET', '/api/admin/certifications/1234/certified-profile'); - - // then - expect(response.statusCode).to.equal(200); - }); - }); - describe('POST /api/certification-courses', function () { it('should return OK (200)', async function () { // given diff --git a/api/tests/certification/results/unit/application/certification-results-controller_test.js b/api/tests/certification/results/unit/application/certification-results-controller_test.js index 1f061b191f5..8267ef524b7 100644 --- a/api/tests/certification/results/unit/application/certification-results-controller_test.js +++ b/api/tests/certification/results/unit/application/certification-results-controller_test.js @@ -130,4 +130,67 @@ describe('Certification | Results | Unit | Controller | certification results', expect(response.headers['Content-Disposition']).to.equal(`attachment; filename=${fileName}`); }); }); + + describe('#getCertifiedProfile', function () { + it('should fetch the associated certified profile serialized as JSONAPI', async function () { + const certifiedProfileSerializer = { + serialize: sinon.stub(), + }; + const certifiedProfileRepository = { + get: sinon.stub(), + }; + const skill1 = domainBuilder.buildCertifiedSkill({ + id: 'recSkill1', + name: 'skill_1', + hasBeenAskedInCertif: false, + tubeId: 'recTube1', + difficulty: 1, + }); + const skill2 = domainBuilder.buildCertifiedSkill({ + id: 'recSkill2', + name: 'skill_2', + hasBeenAskedInCertif: true, + tubeId: 'recTube1', + difficulty: 2, + }); + const tube1 = domainBuilder.buildCertifiedTube({ + id: 'recTube1', + name: 'tube_1', + competenceId: 'recCompetence1', + }); + const competence1 = domainBuilder.buildCertifiedCompetence({ + id: 'recCompetence1', + name: 'competence_1', + areaId: 'recArea1', + origin: 'Pix', + }); + const area1 = domainBuilder.buildCertifiedArea({ + id: 'recArea1', + name: 'area_1', + color: 'someColor', + }); + const certifiedProfile = domainBuilder.buildCertifiedProfile({ + id: 123, + userId: 456, + certifiedSkills: [skill1, skill2], + certifiedTubes: [tube1], + certifiedCompetences: [competence1], + certifiedAreas: [area1], + }); + certifiedProfileRepository.get.withArgs(123).resolves(certifiedProfile); + certifiedProfileSerializer.serialize.withArgs(certifiedProfile).resolves('ok'); + const request = { + params: { id: 123 }, + }; + + // when + const response = await certificationResultsController.getCertifiedProfile(request, hFake, { + certifiedProfileRepository, + certifiedProfileSerializer, + }); + + // then + expect(response).to.deep.equal('ok'); + }); + }); }); diff --git a/api/tests/certification/results/unit/application/certification-results-route_test.js b/api/tests/certification/results/unit/application/certification-results-route_test.js index f5f98c96a60..d89ae33f34e 100644 --- a/api/tests/certification/results/unit/application/certification-results-route_test.js +++ b/api/tests/certification/results/unit/application/certification-results-route_test.js @@ -1,9 +1,26 @@ import { certificationResultsController } from '../../../../../src/certification/results/application/certification-results-controller.js'; import * as moduleUnderTest from '../../../../../src/certification/results/application/certification-results-route.js'; import { authorization } from '../../../../../src/certification/shared/application/pre-handlers/authorization.js'; +import { securityPreHandlers } from '../../../../../src/shared/application/security-pre-handlers.js'; import { expect, HttpTestServer, sinon } from '../../../../test-helper.js'; describe('Certification | Results | Unit | Application | Certification Results Route', function () { + describe('GET /api/admin/certifications/{id}/certified-profile', function () { + it('should exist', async function () { + // given + sinon.stub(securityPreHandlers, 'hasAtLeastOneAccessOf').returns(() => true); + sinon.stub(certificationResultsController, 'getCertifiedProfile').returns('ok'); + const httpTestServer = new HttpTestServer(); + await httpTestServer.register(moduleUnderTest); + + // when + const response = await httpTestServer.request('GET', '/api/admin/certifications/1234/certified-profile'); + + // then + expect(response.statusCode).to.equal(200); + }); + }); + describe('GET /api/sessions/{sessionId}/certified-clea-candidate-data', function () { it('should exist', async function () { // given diff --git a/api/tests/certification/evaluation/integration/serializers/certified-profile-serializer_test.js b/api/tests/certification/results/unit/infrastructure/serializers/certified-profile-serializer_test.js similarity index 95% rename from api/tests/certification/evaluation/integration/serializers/certified-profile-serializer_test.js rename to api/tests/certification/results/unit/infrastructure/serializers/certified-profile-serializer_test.js index 4c397d826a7..47fadbb22c2 100644 --- a/api/tests/certification/evaluation/integration/serializers/certified-profile-serializer_test.js +++ b/api/tests/certification/results/unit/infrastructure/serializers/certified-profile-serializer_test.js @@ -1,5 +1,5 @@ -import * as serializer from '../../../../../src/certification/evaluation/infrastructure/serializers/certified-profile-serializer.js'; -import { domainBuilder, expect } from '../../../../test-helper.js'; +import * as serializer from '../../../../../../src/certification/results/infrastructure/serializers/certified-profile-serializer.js'; +import { domainBuilder, expect } from '../../../../../test-helper.js'; describe('Unit | Serializer | JSONAPI | certified-profile-serializer', function () { describe('#serialize', function () { diff --git a/api/tests/unit/application/certification-courses/certification-course-controller_test.js b/api/tests/unit/application/certification-courses/certification-course-controller_test.js index e6de91a1fd1..10b0c84a17c 100644 --- a/api/tests/unit/application/certification-courses/certification-course-controller_test.js +++ b/api/tests/unit/application/certification-courses/certification-course-controller_test.js @@ -2,12 +2,10 @@ import { certificationCourseController } from '../../../../src/certification/eva import { usecases } from '../../../../src/certification/evaluation/domain/usecases/index.js'; import { CertificationCourse } from '../../../../src/certification/shared/domain/models/CertificationCourse.js'; import { usecases as certificationSharedUsecases } from '../../../../src/certification/shared/domain/usecases/index.js'; -import { domainBuilder, expect, generateValidRequestAuthorizationHeader, hFake, sinon } from '../../../test-helper.js'; +import { expect, generateValidRequestAuthorizationHeader, hFake, sinon } from '../../../test-helper.js'; describe('Unit | Controller | certification-course-controller', function () { let certificationCourseSerializer; - let certifiedProfileSerializer; - let certifiedProfileRepository; let requestResponseUtils; beforeEach(function () { @@ -16,12 +14,6 @@ describe('Unit | Controller | certification-course-controller', function () { serializeFromCertificationCourse: sinon.stub(), deserializeCertificationCandidateModificationCommand: sinon.stub(), }; - certifiedProfileSerializer = { - serialize: sinon.stub(), - }; - certifiedProfileRepository = { - get: sinon.stub(), - }; requestResponseUtils = { extractLocaleFromRequest: sinon.stub() }; }); @@ -111,62 +103,4 @@ describe('Unit | Controller | certification-course-controller', function () { expect(response).to.deep.equal(certificationCourse); }); }); - - describe('#getCertifiedProfile', function () { - it('should fetch the associated certified profile serialized as JSONAPI', async function () { - // given - const skill1 = domainBuilder.buildCertifiedSkill({ - id: 'recSkill1', - name: 'skill_1', - hasBeenAskedInCertif: false, - tubeId: 'recTube1', - difficulty: 1, - }); - const skill2 = domainBuilder.buildCertifiedSkill({ - id: 'recSkill2', - name: 'skill_2', - hasBeenAskedInCertif: true, - tubeId: 'recTube1', - difficulty: 2, - }); - const tube1 = domainBuilder.buildCertifiedTube({ - id: 'recTube1', - name: 'tube_1', - competenceId: 'recCompetence1', - }); - const competence1 = domainBuilder.buildCertifiedCompetence({ - id: 'recCompetence1', - name: 'competence_1', - areaId: 'recArea1', - origin: 'Pix', - }); - const area1 = domainBuilder.buildCertifiedArea({ - id: 'recArea1', - name: 'area_1', - color: 'someColor', - }); - const certifiedProfile = domainBuilder.buildCertifiedProfile({ - id: 123, - userId: 456, - certifiedSkills: [skill1, skill2], - certifiedTubes: [tube1], - certifiedCompetences: [competence1], - certifiedAreas: [area1], - }); - certifiedProfileRepository.get.withArgs(123).resolves(certifiedProfile); - certifiedProfileSerializer.serialize.withArgs(certifiedProfile).resolves('ok'); - const request = { - params: { id: 123 }, - }; - - // when - const response = await certificationCourseController.getCertifiedProfile(request, hFake, { - certifiedProfileRepository, - certifiedProfileSerializer, - }); - - // then - expect(response).to.deep.equal('ok'); - }); - }); });