Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TECH] Refacto des badges des certifications complémentaires (PIX-9862) #7447

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@ import { buildComplementaryCertification } from './build-complementary-certifica
import { buildCertificationCourse } from './build-certification-course.js';
import _ from 'lodash';
import { ComplementaryCertificationCourseResult } from '../../../lib/domain/models/ComplementaryCertificationCourseResult.js';
import { buildBadge } from './build-badge.js';
import { buildComplementaryCertificationBadge } from './build-complementary-certification-badge.js';

const buildComplementaryCertificationCourseResult = function ({
id,
complementaryCertificationCourseId,
partnerKey,
complementaryCertificationBadgeId,
source = ComplementaryCertificationCourseResult.sources.PIX,
acquired = true,
}) {
id = id ?? databaseBuffer.getNextId();
complementaryCertificationCourseId = _.isUndefined(complementaryCertificationCourseId)
? _buildComplementaryCertificationCourse().id
: complementaryCertificationCourseId;
complementaryCertificationBadgeId = _.isUndefined(complementaryCertificationBadgeId)
? _buildComplementaryCertificationBadge().id
: complementaryCertificationBadgeId;
return databaseBuffer.pushInsertable({
tableName: 'complementary-certification-course-results',
values: { id, complementaryCertificationCourseId, partnerKey, source, acquired },
values: { id, complementaryCertificationCourseId, complementaryCertificationBadgeId, source, acquired },
});
};

Expand All @@ -32,3 +37,9 @@ function _buildComplementaryCertificationCourse() {
certificationCourseId,
});
}

function _buildComplementaryCertificationBadge() {
const { id: badgeId } = buildBadge();
const { id: complementaryCertificationId } = buildComplementaryCertification();
return buildComplementaryCertificationBadge({ badgeId, complementaryCertificationId });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const TABLE_NAME = 'complementary-certification-course-results';
const REF_TABLE_NAME = 'complementary-certification-badges';
const COLUMN_NAME = 'complementaryCertificationBadgeId';

const up = async function (knex) {
await knex.schema.table(TABLE_NAME, function (table) {
table
.integer(COLUMN_NAME)
.defaultTo(null)
.references(`${REF_TABLE_NAME}.id`)
.withKeyName('cccresults-ccbadgeId_foreignkey');
});

await knex(TABLE_NAME).update({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pas trop d'inquiétude à se faire niveau perf de cette migration ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a moins de 3000 lignes à mettre à jour, c'est OK

[COLUMN_NAME]: knex(`${REF_TABLE_NAME}`)
.select(`${REF_TABLE_NAME}.id`)
.innerJoin('badges', 'badges.id', `${REF_TABLE_NAME}.badgeId`)
// eslint-disable-next-line knex/avoid-injections
.where('badges.key', '=', knex.raw(`"${TABLE_NAME}"."partnerKey"`)),
});
};

const down = async function (knex) {
await knex.schema.table(TABLE_NAME, function (table) {
table.dropColumn(COLUMN_NAME);
});
};

export { up, down };
2 changes: 2 additions & 0 deletions api/db/seeds/data/common/tooling/session-tooling.js
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,8 @@ function _makeCandidatesPassCertification({
}).id;
databaseBuilder.factory.buildComplementaryCertificationCourseResult({
partnerKey: certificationCandidate.complementaryCertificationBadgeInfo.partnerKey,
complementaryCertificationBadgeId:
certificationCandidate.complementaryCertificationBadgeInfo.complementaryCertificationBadgeId,
acquired: true,
source: 'PIX',
complementaryCertificationCourseId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Joi from 'joi';
import { identifiersType } from '../../domain/types/identifiers-type.js';
import { securityPreHandlers } from '../security-pre-handlers.js';
import { complementaryCertificationCourseResultsController } from './complementary-certification-course-results-controller.js';
import { juryOptions } from '../../domain/models/ComplementaryCertificationCourseResult.js';

const register = async function (server) {
server.route([
Expand All @@ -13,7 +14,12 @@ const register = async function (server) {
payload: Joi.object({
data: {
attributes: {
juryLevel: Joi.string().required(),
juryLevel: Joi.alternatives()
.try(
identifiersType.complementaryCertificationBadgeId,
Joi.string().valid(juryOptions.REJECTED).valid(juryOptions.UNSET),
Comment on lines +19 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah oui le juryLevel ça peut soit être un id soit une string dans le cas d'un jury échoué ou en attente ?

)
.required(),
complementaryCertificationCourseId: identifiersType.complementaryCertificationCourseId,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ async function handleComplementaryCertificationsScoring({
const {
minimumReproducibilityRate,
complementaryCertificationCourseId,
complementaryCertificationBadgeId,
complementaryCertificationBadgeKey,
hasComplementaryReferential,
minimumEarnedPix,
Expand All @@ -49,6 +50,7 @@ async function handleComplementaryCertificationsScoring({
_buildComplementaryCertificationScoringWithReferential(
minimumReproducibilityRate,
complementaryCertificationCourseId,
complementaryCertificationBadgeId,
pixPlusChallenges,
pixPlusAnswers,
complementaryCertificationBadgeKey,
Expand All @@ -58,6 +60,7 @@ async function handleComplementaryCertificationsScoring({
complementaryCertificationScoringWithComplementaryReferential =
new ComplementaryCertificationScoringWithoutComplementaryReferential({
complementaryCertificationCourseId,
complementaryCertificationBadgeId,
complementaryCertificationBadgeKey,
reproducibilityRate: assessmentResult.reproducibilityRate,
pixScore: assessmentResult.pixScore,
Expand All @@ -69,6 +72,7 @@ async function handleComplementaryCertificationsScoring({
await complementaryCertificationCourseResultRepository.save(
ComplementaryCertificationCourseResult.from({
...complementaryCertificationScoringWithComplementaryReferential,
source: ComplementaryCertificationCourseResult.sources.PIX,
aceol marked this conversation as resolved.
Show resolved Hide resolved
acquired: complementaryCertificationScoringWithComplementaryReferential.isAcquired(),
}),
);
Expand All @@ -78,6 +82,7 @@ async function handleComplementaryCertificationsScoring({
function _buildComplementaryCertificationScoringWithReferential(
minimumReproducibilityRate,
complementaryCertificationCourseId,
complementaryCertificationBadgeId,
challenges,
answers,
complementaryCertificationBadgeKey,
Expand All @@ -92,6 +97,7 @@ function _buildComplementaryCertificationScoringWithReferential(
return new ComplementaryCertificationScoringWithComplementaryReferential({
minimumReproducibilityRate,
complementaryCertificationCourseId,
complementaryCertificationBadgeId,
reproducibilityRate,
complementaryCertificationBadgeKey,
hasAcquiredPixCertification: assessmentResult.isValidated(),
Expand Down
4 changes: 0 additions & 4 deletions api/lib/domain/models/CertificationResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ class CertificationResult {
),
];
}

_getCertificationCourseResultByPartnerKeys(partnerKeys) {
AndreiaPena marked this conversation as resolved.
Show resolved Hide resolved
return this.complementaryCertificationCourseResults.find(({ partnerKey }) => partnerKeys.includes(partnerKey));
}
}

CertificationResult.status = status;
Expand Down
16 changes: 8 additions & 8 deletions api/lib/domain/models/ComplementaryCertificationCourseResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,37 @@ const juryOptions = {
};

class ComplementaryCertificationCourseResult {
constructor({ complementaryCertificationCourseId, partnerKey, source, acquired, label } = {}) {
constructor({ complementaryCertificationCourseId, complementaryCertificationBadgeId, source, acquired, label } = {}) {
this.complementaryCertificationCourseId = complementaryCertificationCourseId;
this.partnerKey = partnerKey;
this.complementaryCertificationBadgeId = complementaryCertificationBadgeId;
this.acquired = acquired;
this.source = source;
this.label = label;
}

static from({ complementaryCertificationCourseId, partnerKey, acquired, source, label }) {
static from({ complementaryCertificationCourseId, complementaryCertificationBadgeId, acquired, source, label }) {
return new ComplementaryCertificationCourseResult({
complementaryCertificationCourseId,
partnerKey,
complementaryCertificationBadgeId,
acquired,
source,
label,
});
}

static buildFromJuryLevel({ complementaryCertificationCourseId, juryLevel, pixPartnerKey }) {
if (juryLevel === juryOptions.REJECTED) {
static buildFromJuryLevel({ complementaryCertificationCourseId, complementaryCertificationBadgeId, juryLevel }) {
if (juryLevel === 'REJECTED') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question : Je ne sais pas dans quel contexte on se trouve ici mais il n'y a pas un risque d'avoir un juryLevel à UNSET ici et qu'il finisse à la ligne 42 ?

return new ComplementaryCertificationCourseResult({
complementaryCertificationCourseId,
partnerKey: pixPartnerKey,
complementaryCertificationBadgeId,
acquired: false,
source: sources.EXTERNAL,
});
}

return new ComplementaryCertificationCourseResult({
complementaryCertificationCourseId,
partnerKey: juryLevel,
complementaryCertificationBadgeId: juryLevel,
P-Jeremy marked this conversation as resolved.
Show resolved Hide resolved
acquired: true,
source: sources.EXTERNAL,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ class ComplementaryCertificationScoringCriteria {
complementaryCertificationCourseId,
minimumReproducibilityRate,
complementaryCertificationBadgeKey,
complementaryCertificationBadgeId,
hasComplementaryReferential,
minimumEarnedPix,
} = {}) {
this.complementaryCertificationCourseId = complementaryCertificationCourseId;
this.minimumReproducibilityRate = minimumReproducibilityRate;
this.complementaryCertificationBadgeId = complementaryCertificationBadgeId;
this.complementaryCertificationBadgeKey = complementaryCertificationBadgeKey;
this.hasComplementaryReferential = hasComplementaryReferential;
this.minimumEarnedPix = minimumEarnedPix;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { PartnerCertificationScoring } from './PartnerCertificationScoring.js';
class ComplementaryCertificationScoringWithComplementaryReferential extends PartnerCertificationScoring {
constructor({
complementaryCertificationCourseId,
complementaryCertificationBadgeId,
complementaryCertificationBadgeKey,
reproducibilityRate,
hasAcquiredPixCertification,
minimumReproducibilityRate,
} = {}) {
super({
complementaryCertificationCourseId,
complementaryCertificationBadgeId,
partnerKey: complementaryCertificationBadgeKey,
source: ComplementaryCertificationCourseResult.sources.PIX,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@ import { PartnerCertificationScoring } from './PartnerCertificationScoring.js';
class ComplementaryCertificationScoringWithoutComplementaryReferential extends PartnerCertificationScoring {
constructor({
complementaryCertificationCourseId,
complementaryCertificationBadgeKey,
complementaryCertificationBadgeId,
reproducibilityRate,
pixScore,
minimumEarnedPix,
minimumReproducibilityRate,
} = {}) {
super({
complementaryCertificationCourseId,
partnerKey: complementaryCertificationBadgeKey,
complementaryCertificationBadgeId,
});

this.complementaryCertificationCourseId = complementaryCertificationCourseId;
this.reproducibilityRate = reproducibilityRate;
this.pixScore = pixScore;
this.minimumEarnedPix = minimumEarnedPix;
Expand Down
6 changes: 3 additions & 3 deletions api/lib/domain/models/PartnerCertificationScoring.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ const SOURCES = {
};

class PartnerCertificationScoring {
constructor({ complementaryCertificationCourseId, partnerKey, source = SOURCES.PIX } = {}) {
constructor({ complementaryCertificationCourseId, complementaryCertificationBadgeId, source = SOURCES.PIX } = {}) {
this.complementaryCertificationCourseId = complementaryCertificationCourseId;
this.partnerKey = partnerKey;
this.complementaryCertificationBadgeId = complementaryCertificationBadgeId;
this.source = source;
const schema = Joi.object({
complementaryCertificationCourseId: Joi.number().integer().required(),
partnerKey: Joi.string().allow(null).required(),
complementaryCertificationBadgeId: Joi.number().integer().required(),
source: Joi.string()
.required()
.valid(...Object.values(SOURCES)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@ const complementaryCertificationStatus = {
};

class ComplementaryCertificationCourseResultForJuryCertification {
constructor({ id, partnerKey, acquired, label }) {
constructor({ id, complementaryCertificationBadgeId, acquired, label }) {
this.id = id;
this.partnerKey = partnerKey;
this.complementaryCertificationBadgeId = complementaryCertificationBadgeId;
this.acquired = acquired;
this.label = label;
}

static from({ id, partnerKey, acquired, label }) {
return new ComplementaryCertificationCourseResultForJuryCertification({ id, partnerKey, acquired, label });
static from({ id, complementaryCertificationBadgeId, acquired, label }) {
return new ComplementaryCertificationCourseResultForJuryCertification({
id,
complementaryCertificationBadgeId,
acquired,
label,
});
}

get status() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@ const { EXTERNAL, PIX } = sources;
class ComplementaryCertificationCourseResultForJuryCertificationWithExternal {
constructor({
complementaryCertificationCourseId,
pixPartnerKey,
pixComplementaryCertificationBadgeId,
pixLabel,
pixAcquired,
pixLevel,
externalPartnerKey,
externalComplementaryCertificationBadgeId,
externalLabel,
externalAcquired,
externalLevel,
allowedExternalLevels,
}) {
this.complementaryCertificationCourseId = complementaryCertificationCourseId;
this.pixSection = new Section({
partnerKey: pixPartnerKey,
complementaryCertificationBadgeId: pixComplementaryCertificationBadgeId,
label: pixLabel,
acquired: pixAcquired,
level: pixLevel,
});
this.externalSection = new Section({
partnerKey: externalPartnerKey,
complementaryCertificationBadgeId: externalComplementaryCertificationBadgeId,
label: externalLabel,
acquired: externalAcquired,
level: externalLevel,
Expand All @@ -36,7 +36,7 @@ class ComplementaryCertificationCourseResultForJuryCertificationWithExternal {
this.defaultJuryOptions = Object.values(juryOptions);
}

static from(complementaryCertificationCourseResultWithExternal, badgesKeyAndLabel) {
static from(complementaryCertificationCourseResultWithExternal, badgesIdAndLabels) {
if (!complementaryCertificationCourseResultWithExternal.length) {
return;
}
Expand All @@ -47,16 +47,18 @@ class ComplementaryCertificationCourseResultForJuryCertificationWithExternal {
({ source }) => source === EXTERNAL,
);

const allowedExternalLevels = badgesKeyAndLabel.map(({ key, label }) => ({ label, value: key }));
const allowedExternalLevels = badgesIdAndLabels.map(({ id, label }) => ({ label, value: id }));

return new ComplementaryCertificationCourseResultForJuryCertificationWithExternal({
complementaryCertificationCourseId:
complementaryCertificationCourseResultWithExternal[0].complementaryCertificationCourseId,
pixPartnerKey: pixComplementaryCertificationCourseResult?.partnerKey,
pixComplementaryCertificationBadgeId:
pixComplementaryCertificationCourseResult?.complementaryCertificationBadgeId,
pixLabel: pixComplementaryCertificationCourseResult?.label,
pixAcquired: pixComplementaryCertificationCourseResult?.acquired,
pixLevel: pixComplementaryCertificationCourseResult?.level,
externalPartnerKey: externalComplementaryCertificationCourseResult?.partnerKey,
externalComplementaryCertificationBadgeId:
externalComplementaryCertificationCourseResult?.complementaryCertificationBadgeId,
externalLabel: externalComplementaryCertificationCourseResult?.label,
externalAcquired: externalComplementaryCertificationCourseResult?.acquired,
externalLevel: externalComplementaryCertificationCourseResult?.level,
Expand Down Expand Up @@ -86,15 +88,15 @@ class ComplementaryCertificationCourseResultForJuryCertificationWithExternal {
}

class Section {
constructor({ partnerKey, label, acquired, level }) {
this.partnerKey = partnerKey;
constructor({ complementaryCertificationBadgeId, label, acquired, level }) {
this.complementaryCertificationBadgeId = complementaryCertificationBadgeId;
this.label = label;
this.acquired = acquired ?? false;
this.level = level;
}

get isEvaluated() {
return Boolean(this.partnerKey);
return Boolean(this.complementaryCertificationBadgeId);
}
}

Expand Down
1 change: 1 addition & 0 deletions api/lib/domain/types/identifiers-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const typesPositiveInteger32bits = [
'certificationIssueReportId',
'complementaryCertificationId',
'complementaryCertificationCourseId',
'complementaryCertificationBadgeId',
'certificationCenterInvitationId',
'membershipId',
'organizationId',
Expand Down
Loading