Skip to content

Commit 59c7156

Browse files
committed
WIP WIP
1 parent ab76aed commit 59c7156

14 files changed

Lines changed: 185 additions & 167 deletions

File tree

api/package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170
"@ls-lint/ls-lint": "^2.3.1",
171171
"chai": "^6.0.0",
172172
"chai-as-promised": "^8.0.0",
173+
"chai-exclude": "^3.0.1",
173174
"dependency-cruiser": "^17.4.0",
174175
"eslint": "^9.39.2",
175176
"eslint-plugin-chai-expect": "^4.0.0",

api/src/certification/configuration/application/certification-version-controller.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,18 @@ const deleteCertificationVersion = async function (request, h) {
3131
return h.response().code(204);
3232
};
3333

34-
const createCertificationVersion = async function (request, h) {
34+
const createDraft = async function (request, h) {
3535
const { scope } = request.params;
3636
const { tubeIds } = request.payload.data.attributes;
3737

38-
const createdCertificationId = await usecases.createCertificationVersion({ scope, tubeIds });
38+
const draftVersionId = await usecases.createDraft({ scope, tubeIds });
3939

40-
return h.response({ data: { id: createdCertificationId, type: 'certification-version' } }).code(201);
40+
// todo serialize avec la méthode
41+
return h.response({ data: { id: draftVersionId, type: 'certification-versions' } }).code(201);
4142
};
4243

4344
const certificationVersionController = {
44-
createCertificationVersion,
45+
createDraft,
4546
getVersionById,
4647
deleteCertificationVersion,
4748
update,

api/src/certification/configuration/application/certification-version-route.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,11 @@ const register = async function (server) {
138138
},
139139
}),
140140
},
141-
handler: certificationVersionController.createCertificationVersion,
141+
handler: certificationVersionController.createDraft,
142142
tags: ['api', 'admin'],
143143
notes: [
144144
'Cette route est restreinte aux utilisateurs authentifiés avec le rôle Super Admin',
145-
'Elle permet de créer une nouvelle version de référentiel de certification',
145+
"Elle permet de créer un nouveau millésime draft d'un référentiel de certification",
146146
],
147147
},
148148
},

api/src/certification/configuration/domain/errors.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ export class CertificationVersionForbiddenDeletionError extends DomainError {
1818
super('Il est interdit de supprimer une version de référentiel de certification qui a déjà été activée.');
1919
}
2020
}
21+
22+
export class CertificationVersionDraftAlreadyExistError extends DomainError {
23+
constructor() {
24+
super('Il est interdit de créer une nouvelle version en mode draft si une exist existe déjà');
25+
}
26+
}

api/src/certification/configuration/domain/usecases/create-certification-version.js

Lines changed: 0 additions & 111 deletions
This file was deleted.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @typedef {import ('../../../shared/domain/models/Scopes.js').SCOPES} SCOPES
3+
* @typedef {import ('./index.js').ChallengeRepository} ChallengeRepository
4+
* @typedef {import ('./index.js').VersionRepository} VersionRepository
5+
*/
6+
7+
import { DomainTransaction } from '../../../../shared/domain/DomainTransaction.js';
8+
import { ENGLISH_SPOKEN, FRENCH_FRANCE, FRENCH_SPOKEN } from '../../../../shared/domain/services/locale-service.js';
9+
import {
10+
DEFAULT_MINIMUM_ANSWERS_REQUIRED_TO_VALIDATE_A_CERTIFICATION,
11+
DEFAULT_PROBABILITY_TO_PICK_CHALLENGE,
12+
DEFAULT_SESSION_DURATION_MINUTES,
13+
} from '../../../shared/domain/constants.js';
14+
import { FlashAssessmentAlgorithmConfiguration } from '../../../shared/domain/models/FlashAssessmentAlgorithmConfiguration.js';
15+
import { SCOPES } from '../../../shared/domain/models/Scopes.js';
16+
import {CertificationVersionDraftAlreadyExistError} from '../errors.js'
17+
import { Version } from '../models/Version.js';
18+
import { FRAMEWORK_HISTORY_STATUSES } from '../read-models/FrameworkHistoryEntry.js';
19+
20+
/**
21+
* @param {object} params
22+
* @param {SCOPES} params.scope
23+
* @param {Array<string>} params.tubeIds
24+
* @param {ChallengeRepository} params.challengeRepository
25+
* @param {VersionRepository} params.versionRepository
26+
*/
27+
export async function createDraft({ scope, tubeIds, challengeRepository, versionRepository, frameworkChallengesRepository }) {
28+
const allVersions = await versionRepository.findAll();
29+
const scopeVersions = allVersions.filter((version) => version.scope === scope);
30+
const hasDraft = scopeVersions.some((version) => version.status === FRAMEWORK_HISTORY_STATUSES.DRAFT);
31+
if (hasDraft) {
32+
throw new CertificationVersionDraftAlreadyExistError;
33+
}
34+
35+
const activeVersion = scopeVersions.some((version) => version.status === FRAMEWORK_HISTORY_STATUSES.ACTIVE);
36+
const locales = scope === SCOPES.CORE ? [FRENCH_SPOKEN, ENGLISH_SPOKEN, FRENCH_FRANCE] : [FRENCH_FRANCE];
37+
const challengeIds = await challengeRepository.findValidatedIdsByTubeIdsAndLocales(tubeIds, locales);
38+
39+
const version = _buildNewVersion({
40+
scope,
41+
activeVersion,
42+
versionRepository,
43+
});
44+
45+
let versionId;
46+
await DomainTransaction.execute(async () => {
47+
versionId = await versionRepository.create({ version, challengeIds });
48+
await frameworkChallengesRepository.createFromChallengeIds({ versionId, challengeIds })
49+
})
50+
51+
return versionId;
52+
}
53+
54+
/**
55+
* @param {object} params
56+
* @param {SCOPES} params.scope
57+
* @param {Version} params.activeVersion
58+
*/
59+
const _buildNewVersion = ({ scope, activeVersion }) => {
60+
return new Version({
61+
scope,
62+
startDate: null,
63+
expirationDate: null,
64+
assessmentDuration: activeVersion?.assessmentDuration ?? DEFAULT_SESSION_DURATION_MINUTES,
65+
minimumAnswersRequiredToValidateACertification:
66+
activeVersion?.minimumAnswersRequiredToValidateACertification ??
67+
DEFAULT_MINIMUM_ANSWERS_REQUIRED_TO_VALIDATE_A_CERTIFICATION,
68+
challengesConfiguration: new FlashAssessmentAlgorithmConfiguration({
69+
challengesBetweenSameCompetence: 0,
70+
maximumAssessmentLength: 32,
71+
variationPercent: 1,
72+
defaultCandidateCapacity: 0,
73+
defaultProbabilityToPickChallenge: DEFAULT_PROBABILITY_TO_PICK_CHALLENGE,
74+
limitToOneQuestionPerTube: true,
75+
enablePassageByAllCompetences: true,
76+
}),
77+
});
78+
};

api/src/certification/configuration/domain/usecases/index.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import * as mailService from '../../../../../src/certification/shared/domain/services/mail-service.js';
22
import * as challengeRepository from '../../../../shared/infrastructure/repositories/challenge-repository.js';
3-
import * as skillRepository from '../../../../shared/infrastructure/repositories/skill-repository.js';
4-
import * as tubeRepository from '../../../../shared/infrastructure/repositories/tube-repository.js';
53
import { injectDependencies } from '../../../../shared/infrastructure/utils/dependency-injection.js';
64
import * as targetProfileHistoryRepository from '../../../shared/infrastructure/repositories/target-profile-history-repository.js';
75
import * as activeCalibratedChallengeRepository from '../../infrastructure/repositories/active-calibrated-challenge-repository.js';
@@ -17,7 +15,7 @@ import * as ScoBlockedAccessDatesRepository from '../../infrastructure/repositor
1715
import * as versionRepository from '../../infrastructure/repositories/version-repository.js';
1816
import { attachBadges } from './attach-badges.js';
1917
import { calibrateFrameworkVersion } from './calibrate-framework-version.js';
20-
import { createCertificationVersion } from './create-certification-version.js';
18+
import { createDraft } from './create-draft.js';
2119
import { deleteCertificationVersion } from './delete-certification-version.js';
2220
import { exportScoWhitelist } from './export-sco-whitelist.js';
2321
import { findCertificationFrameworks } from './find-certification-frameworks.js';
@@ -49,8 +47,6 @@ import { updateVersion } from './update-version.js';
4947
* @typedef {learningContentRepository} LearningContentRepository
5048
* @typedef {mailService} MailService
5149
* @typedef {organizationRepository} OrganizationRepository
52-
* @typedef {skillRepository} SkillRepository
53-
* @typedef {tubeRepository} TubeRepository
5450
* @typedef {ScoBlockedAccessDatesRepository} ScoBlockedAccessDatesRepository
5551
* @typedef {versionRepository} VersionRepository
5652
**/
@@ -67,16 +63,14 @@ const dependencies = {
6763
learningContentRepository,
6864
mailService,
6965
organizationRepository,
70-
skillRepository,
7166
targetProfileHistoryRepository,
72-
tubeRepository,
7367
versionRepository,
7468
};
7569

7670
const usecasesWithoutInjectedDependencies = {
7771
attachBadges,
7872
calibrateFrameworkVersion,
79-
createCertificationVersion,
73+
createDraft,
8074
deleteCertificationVersion,
8175
exportScoWhitelist,
8276
findCertificationFrameworks,

api/src/certification/configuration/infrastructure/repositories/framework-challenges-repository.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@ import { DomainTransaction } from '../../../../shared/domain/DomainTransaction.j
33
import { NotFoundError } from '../../../../shared/domain/errors.js';
44
import { CertificationFrameworksChallenge } from '../../domain/models/CertificationFrameworksChallenge.js';
55

6+
7+
/**
8+
* @param {object} params
9+
* @returns {Promise<Array<string>>}
10+
* @throws {NotFoundError}
11+
*/
12+
export async function createFromChallengeIds({ versionId, challengeIds = [] }) {
13+
const knexConn = DomainTransaction.getConnection();
14+
15+
const certificationFrameworksChallenge = challengeIds.map((challengeId) => {
16+
return {
17+
versionId,
18+
challengeId
19+
}
20+
})
21+
22+
return await knexConn.batchInsert(('certification-frameworks-challenges'), certificationFrameworksChallenge).returning('id')
23+
}
24+
625
/**
726
* @param {object} params
827
* @param {number} params.versionId

0 commit comments

Comments
 (0)