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

[FEATURE] Reprise mdl bien-ecrire-son-adresse-mail pour coval 16/10 (MODC-2) #10189

Closed
wants to merge 51 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
78e4423
feat(api): premieres modifs modc-225
RomainPennec Sep 24, 2024
67c5193
feat(api): suppr expression _a suivre_
RomainPennec Sep 24, 2024
07d9e85
feat(api): ameliorer recap
RomainPennec Sep 24, 2024
08eb70f
feat(api): modifs post review 2
RomainPennec Sep 25, 2024
35ef38c
feat(api): micro modifs
RomainPennec Sep 25, 2024
7b1bf5b
feat(api): mention accents modc-134
RomainPennec Sep 25, 2024
d64c942
feat(api): modif post review jte
RomainPennec Oct 2, 2024
4ad2c3f
fix + ajout consigne d'étude
RomainPennec Oct 7, 2024
da56acb
fix feedback vrai-faux
RomainPennec Oct 7, 2024
0d9e4fc
fix adresse mickael
RomainPennec Oct 7, 2024
f310783
feat(api): modifs avant preval
RomainPennec Oct 8, 2024
7aef7de
fix coquille
RomainPennec Oct 9, 2024
5b599da
feat(api): add candidate eligiblity verification when reconciling him
HEYGUL Sep 26, 2024
ab260fb
feat(api): resolves when candidate session is v2
P-Jeremy Sep 26, 2024
7e71314
refactor(api): refactor usecase
P-Jeremy Sep 27, 2024
81a32ad
refactor(api): invert reconcil and subscriptions check in service
P-Jeremy Oct 4, 2024
4ccf06c
feat(certif): handle candidate not eligible error
HEYGUL Sep 30, 2024
74545e5
:sparkles: api: rollback reconciliation if eligibility error
Steph0 Oct 4, 2024
f0ed5e7
:bug: api: if minimumEarnedPix is non existent, candidate must not be
Steph0 Oct 7, 2024
cc4dd01
:bug: api: add comment to point an issue in repo method
P-Jeremy Oct 8, 2024
082279c
:recycle: api: dissociating stack for outdated error against score error
P-Jeremy Oct 8, 2024
992bb1a
:recycle: api: renaming deprecated repository to ease transition to n…
Steph0 Oct 8, 2024
2a03827
:recycle: api: move getAllWithSameTargetProfile to shared context
Steph0 Oct 8, 2024
f6ad69c
:bug: api: use getAllWithSameTargetProfile to verify subscriptions
Steph0 Oct 8, 2024
0b8870e
:recycle: api: some cleanup
Steph0 Oct 8, 2024
8762d1c
feat(api): add tubesCount property for admin target profile
ThomasBazin Oct 7, 2024
7a6ff08
feat(admin): display tubes count on target profile details page
ThomasBazin Oct 8, 2024
ae36f8b
test?(admin): improve tests for target profile details page
ThomasBazin Oct 8, 2024
6fc3e80
refactor(orga): migrate target-profile-tooltip component to gjs file
Alexandre-Monney Oct 8, 2024
d39e999
refactor(orga): migrate view component to gjs file
Alexandre-Monney Oct 8, 2024
67298e5
refactor(orga): migrate badges component to gjs file
Alexandre-Monney Oct 8, 2024
13314b5
refactor(orga): migrate create-form component to gjs file
Alexandre-Monney Oct 8, 2024
34d8a54
refactor(orga): migrate empty-state component to gjs file
Alexandre-Monney Oct 8, 2024
76077a8
refactor(orga): migrate list-header component to gjs file
Alexandre-Monney Oct 8, 2024
c57de54
refactor(orga): migrate no-campaign-panel component to gjs file
Alexandre-Monney Oct 8, 2024
c2b89ab
refactor(orga): migrate target-profile-details component to gjs file
Alexandre-Monney Oct 8, 2024
a5e51a0
refactor(orga): migrate update-form component to gjs file
Alexandre-Monney Oct 8, 2024
f311776
[FEATURE] Mise à jour du wording lors du défocus pour candidats avec …
alexandrecoin Oct 9, 2024
271e1e0
[BUMP] Update dependency @1024pix/pix-ui to ^46.15.0 (certif)
renovate[bot] Oct 9, 2024
65d64c9
[BUMP] Update dependency @1024pix/pix-ui to ^46.14.0 (junior)
renovate[bot] Oct 1, 2024
f47f528
fix feedback
RomainPennec Oct 9, 2024
c71a4f0
feat(api): modifs post preval 1
RomainPennec Oct 10, 2024
2fbaeeb
fix emoji croix rouge
RomainPennec Oct 10, 2024
c73cc28
feat(api): completer alt texte modc-96
RomainPennec Oct 10, 2024
e23c135
fix emoji
RomainPennec Oct 10, 2024
9c731a0
fix pluriel adresse mail
RomainPennec Oct 10, 2024
cdb3c64
feat(api): ajout indice pour aidez à la saisie du arobase
RomainPennec Nov 7, 2024
856d2ba
feat(api): modifs evidentes post-coval
RomainPennec Nov 13, 2024
941c137
feat(api): nouvelle categorisation
RomainPennec Nov 13, 2024
0ae043e
fix(api): suppr fichier parasite
RomainPennec Nov 28, 2024
8ce3611
feat(api): ajout d'un distracteur
RomainPennec Dec 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions admin/app/components/target-profiles/target-profile.gjs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ export default class TargetProfile extends Component {
"pages.target-profiles.resettable-checkbox.label"
}}&#x20;:&#x20;</span>{{this.displayBooleanState this.areKnowledgeElementsResettable}}
</li>
<li><span class="bold">{{t
"pages.target-profiles.tubes-count"
}}&#x20;:&#x20;</span>{{@model.tubesCount}}</li>
{{#if @model.description}}
<li>
<span class="bold">Description&#x20;:&#x20;</span>
Expand Down
1 change: 1 addition & 0 deletions admin/app/models/target-profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default class TargetProfile extends Model {
@attr('boolean') hasLinkedCampaign;
@attr('boolean') hasLinkedAutonomousCourse;
@attr('number') maxLevel;
@attr('number') tubesCount;
@attr() cappedTubes;

@hasMany('badge', { async: true, inverse: null }) badges;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { render } from '@1024pix/ember-testing-library';
import { t } from 'ember-intl/test-support';
import TargetProfile from 'pix-admin/components/target-profiles/target-profile';
import { module, test } from 'qunit';

Expand All @@ -19,9 +20,29 @@ module('Integration | Component | TargetProfile', function (hooks) {
name: 'Dummy target-profile',
outdated: false,
ownerOrganizationId: '100',
tubesCount: 6,
};

module('campaign / autonomous course link', function () {
module('target profile overview section', function () {
module('basic informations', function () {
test('it should display target profile basic informations', async function (assert) {
//given
const model = { ...targetProfileSampleData };

// when
const screen = await render(<template><TargetProfile @model={{model}} /></template>);

// then
assert.ok(_findByListItemText(screen, `ID : ${model.id}`));
assert.ok(_findByListItemText(screen, `Organisation de référence : ${model.ownerOrganizationId}`));
assert.ok(_findByListItemText(screen, 'Date de création : 01/03/2024'));
assert.ok(_findByListItemText(screen, 'Obsolète : Non'));
assert.ok(_findByListItemText(screen, 'Parcours Accès Simplifié : Non'));
assert.ok(_findByListItemText(screen, `${t('pages.target-profiles.resettable-checkbox.label')} : Non`));
assert.ok(_findByListItemText(screen, `${t('pages.target-profiles.tubes-count')} : ${model.tubesCount}`));
});
});

module('when no campaign is linked', function () {
test('it should display a no-link information', async function (assert) {
// given
Expand Down
3 changes: 2 additions & 1 deletion admin/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,8 @@
},
"resettable-checkbox": {
"label": "Allow resetting for evaluation-type campaigns when multiple submissions are enabled for the organisation"
}
},
"tubes-count": "Number of subjects included in this target profile"
},
"trainings": {
"training": {
Expand Down
3 changes: 2 additions & 1 deletion admin/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,8 @@
},
"resettable-checkbox": {
"label": "Permettre la remise à zéro des acquis du profil cible"
}
},
"tubes-count": "Nombre de sujets compris dans ce profil cible"
},
"trainings": {
"training": {
Expand Down
2 changes: 1 addition & 1 deletion api/lib/domain/events/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import perf_hooks from 'node:perf_hooks';

import _ from 'lodash';

import * as complementaryCertificationBadgesRepository from '../../../src/certification/complementary-certification/infrastructure/repositories/complementary-certification-badge-repository.js';
import * as flashAlgorithmService from '../../../src/certification/flash-certification/domain/services/algorithm-methods/flash.js';
import { scoringDegradationService } from '../../../src/certification/scoring/domain/services/scoring-degradation-service.js';
import * as certificationAssessmentHistoryRepository from '../../../src/certification/scoring/infrastructure/repositories/certification-assessment-history-repository.js';
Expand All @@ -17,6 +16,7 @@ import * as certificationCenterRepository from '../../../src/certification/share
import * as certificationCourseRepository from '../../../src/certification/shared/infrastructure/repositories/certification-course-repository.js';
import * as certificationIssueReportRepository from '../../../src/certification/shared/infrastructure/repositories/certification-issue-report-repository.js';
import * as competenceMarkRepository from '../../../src/certification/shared/infrastructure/repositories/competence-mark-repository.js';
import * as complementaryCertificationBadgesRepository from '../../../src/certification/shared/infrastructure/repositories/complementary-certification-badge-repository.js';
import * as flashAlgorithmConfigurationRepository from '../../../src/certification/shared/infrastructure/repositories/flash-algorithm-configuration-repository.js';
import * as authenticationMethodRepository from '../../../src/identity-access-management/infrastructure/repositories/authentication-method.repository.js';
import * as userRepository from '../../../src/identity-access-management/infrastructure/repositories/user.repository.js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ const retrieveLastOrCreateCertificationCourse = async function ({
);

if (existingCertificationCourse) {
existingCertificationCourse.adjustForAccessibility(certificationCandidate.accessibilityAdjustmentNeeded);

return {
created: false,
certificationCourse: existingCertificationCourse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const serialize = function (certificationCourse) {
'firstName',
'lastName',
'version',
'isAdjustedForAccessibility',
],
assessment: {
ref: 'id',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const serialize = function ({ targetProfile, filter }) {
'stageCollection',
'areas',
'maxLevel',
'tubesCount',
'cappedTubes',
],
badges: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @typedef {import ('../../domain/usecases/index.js').ComplementaryCertificationBadgesRepository} ComplementaryCertificationBadgesRepository
* @typedef {import ('../models/ComplementaryCertification.js').ComplementaryCertification} ComplementaryCertification
* @typedef {import ('../models/ComplementaryCertificationBadge.js').ComplementaryCertificationBadge} ComplementaryCertificationBadge
* @typedef {import ('../../../shared/domain/models/ComplementaryCertificationBadge.js').ComplementaryCertificationBadge} ComplementaryCertificationBadge
*/
import lodash from 'lodash';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { knex } from '../../../../../db/knex-database-connection.js';
import { Badge } from '../../../../evaluation/domain/models/Badge.js';
import { DomainTransaction } from '../../../../shared/domain/DomainTransaction.js';
import { NotFoundError } from '../../../../shared/domain/errors.js';
import { ComplementaryCertificationBadge } from '../../domain/models/ComplementaryCertificationBadge.js';

const getAllIdsByTargetProfileId = async function ({ targetProfileId }) {
const knexConn = DomainTransaction.getConnection();
Expand Down Expand Up @@ -54,27 +52,6 @@ const findAttachableBadgesByIds = async function ({ ids }) {
});
};

const getAllWithSameTargetProfile = async function (complementaryCertificationBadgeId) {
const complementaryCertificationBadges = await knex('complementary-certification-badges')
.select('complementary-certification-badges.*')
.join('badges', 'badges.id', '=', 'complementary-certification-badges.badgeId')
.where(
'badges.targetProfileId',
'=',
knex('complementary-certification-badges')
.select('target-profiles.id')
.join('badges', 'badges.id', '=', 'complementary-certification-badges.badgeId')
.join('target-profiles', 'target-profiles.id', '=', 'badges.targetProfileId')
.where('complementary-certification-badges.id', '=', complementaryCertificationBadgeId),
);

if (complementaryCertificationBadges.length === 0) {
throw new NotFoundError('No complementary certification badge found');
}

return complementaryCertificationBadges.map(_toDomain);
};

const isRelatedToCertification = async function (badgeId) {
const knexConn = DomainTransaction.getConnection();
const complementaryCertificationBadge = await knexConn('complementary-certification-badges')
Expand All @@ -83,15 +60,4 @@ const isRelatedToCertification = async function (badgeId) {
return !!complementaryCertificationBadge;
};

function _toDomain(complementaryCertificationBadgeDTO) {
return new ComplementaryCertificationBadge(complementaryCertificationBadgeDTO);
}

export {
attach,
detachByIds,
findAttachableBadgesByIds,
getAllIdsByTargetProfileId,
getAllWithSameTargetProfile,
isRelatedToCertification,
};
export { attach, detachByIds, findAttachableBadgesByIds, getAllIdsByTargetProfileId, isRelatedToCertification };
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HttpErrors } from '../../../shared/application/http-errors.js';
import { DomainErrorMappingConfiguration } from '../../../shared/application/models/domain-error-mapping-configuration.js';
import {
CertificationCandidateEligibilityError,
CertificationCandidateForbiddenDeletionError,
CertificationCandidateNotFoundError,
InvalidCertificationCandidate,
Expand All @@ -26,6 +27,10 @@ const enrolmentDomainErrorMappingConfiguration = [
name: InvalidCertificationCandidate.name,
httpErrorFn: (error) => new HttpErrors.UnprocessableEntityError(error.message),
},
{
name: CertificationCandidateEligibilityError.name,
httpErrorFn: (error) => new HttpErrors.UnprocessableEntityError(error.message, error.code),
},
].map((domainErrorMappingConfiguration) => new DomainErrorMappingConfiguration(domainErrorMappingConfiguration));

export { enrolmentDomainErrorMappingConfiguration };
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @typedef {import ('../../domain/models/Candidate.js').Candidate} Candidate
*/

import { withTransaction } from '../../../../shared/domain/DomainTransaction.js';
import { usecases } from '../../domain/usecases/index.js';

/**
Expand All @@ -15,29 +15,31 @@ import { usecases } from '../../domain/usecases/index.js';
* @param {Function} params.normalizeStringFnc
* @returns {Promise<Candidate>}
*/
export const registerCandidateParticipation = async ({
userId,
sessionId,
firstName,
lastName,
birthdate,
normalizeStringFnc,
}) => {
const candidate = await usecases.verifyCandidateIdentity({
userId,
sessionId,
firstName,
lastName,
birthdate,
normalizeStringFnc,
});
export const registerCandidateParticipation = withTransaction(
async ({ userId, sessionId, firstName, lastName, birthdate, normalizeStringFnc }) => {
const candidate = await usecases.verifyCandidateIdentity({
userId,
sessionId,
firstName,
lastName,
birthdate,
normalizeStringFnc,
});

if (candidate.isReconciled()) {
return candidate;
}

const reconciliedCandidate = await usecases.reconcileCandidate({
userId,
candidate,
});

if (candidate.isReconciled()) {
return candidate;
}
await usecases.verifyCandidateSubscriptions({
candidate: reconciliedCandidate,
sessionId,
});

return usecases.reconcileCandidate({
userId,
candidate,
});
};
return reconciliedCandidate;
},
);
8 changes: 8 additions & 0 deletions api/src/certification/enrolment/domain/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,15 @@ class InvalidCertificationCandidate extends DomainError {
}
}

class CertificationCandidateEligibilityError extends DomainError {
constructor(message = "Le candidat n'est pas éligible") {
super(message);
this.code = 'CERTIFICATION_CANDIDATE_ELIGIBILITY_ERROR';
}
}

export {
CertificationCandidateEligibilityError,
CertificationCandidateForbiddenDeletionError,
CertificationCandidateNotFoundError,
InvalidCertificationCandidate,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export class ComplementaryCertificationBadge {
export class ComplementaryCertificationBadgeWithOffsetVersion {
constructor({ id, requiredPixScore, offsetVersion, currentAttachedComplementaryCertificationBadgeId }) {
this.id = id;
this.requiredPixScore = requiredPixScore;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
/**
* @typedef {import ('./index.js').ComplementaryCertificationBadgeWithOffsetVersionRepository} ComplementaryCertificationBadgeWithOffsetVersionRepository
*/
import _ from 'lodash';

import { AssessmentResult } from '../../../../shared/domain/models/index.js';
import { ComplementaryCertificationKeys } from '../../../shared/domain/models/ComplementaryCertificationKeys.js';
import { CertificationEligibility, UserCertificationEligibility } from '../read-models/UserCertificationEligibility.js';

/**
* @param {Object} params
* @param {ComplementaryCertificationBadgeWithOffsetVersionRepository} params.complementaryCertificationBadgeWithOffsetVersionRepository
*/
const getUserCertificationEligibility = async function ({
userId,
limitDate = new Date(),
placementProfileService,
certificationBadgesService,
complementaryCertificationCourseRepository,
pixCertificationRepository,
complementaryCertificationBadgeRepository,
complementaryCertificationBadgeWithOffsetVersionRepository,
}) {
const placementProfile = await placementProfileService.getPlacementProfile({ userId, limitDate });
const isCertifiable = placementProfile.isCertifiable();
Expand All @@ -25,7 +32,8 @@ const getUserCertificationEligibility = async function ({
userId,
});
const userPixCertifications = await pixCertificationRepository.findByUserId({ userId });
const allComplementaryCertificationBadges = await complementaryCertificationBadgeRepository.findAll();
const allComplementaryCertificationBadges =
await complementaryCertificationBadgeWithOffsetVersionRepository.findAll();

const certificationEligibilities = [];
for (const acquiredBadge of userAcquiredBadges) {
Expand Down
7 changes: 5 additions & 2 deletions api/src/certification/enrolment/domain/usecases/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as attendanceSheetPdfUtils from '../../../enrolment/infrastructure/util
import * as certificationBadgesService from '../../../shared/domain/services/certification-badges-service.js';
import * as certificationCpfService from '../../../shared/domain/services/certification-cpf-service.js';
import * as sessionValidator from '../../../shared/domain/validators/session-validator.js';
import * as complementaryCertificationBadgesRepository from '../../../shared/infrastructure/repositories/complementary-certification-badge-repository.js';
import { enrolmentRepositories } from '../../infrastructure/repositories/index.js';
import * as certificationCandidatesOdsService from '../services/certification-candidates-ods-service.js';
import * as sessionCodeService from '../services/session-code-service.js';
Expand All @@ -18,6 +19,7 @@ import * as temporarySessionsStorageForMassImportService from '../services/tempo

/**
* @typedef {import('../../infrastructure/repositories/index.js').ComplementaryCertificationRepository} ComplementaryCertificationRepository
* @typedef {import('../../infrastructure/repositories/index.js').ComplementaryCertificationBadgeWithOffsetVersionRepository} ComplementaryCertificationBadgeWithOffsetVersionRepository
* @typedef {import('../../infrastructure/repositories/index.js').SessionRepository} SessionRepository
* @typedef {import('../../infrastructure/repositories/index.js').CertificationCandidateRepository} CertificationCandidateRepository
* @typedef {import('../../../session-management/infrastructure/repositories/index.js').CertificationCandidateForSupervisingRepository} CertificationCandidateForSupervisingRepository
Expand All @@ -35,7 +37,6 @@ import * as temporarySessionsStorageForMassImportService from '../services/tempo
* @typedef {import('../../../shared/domain/services/certification-cpf-service.js')} CertificationCpfService
* @typedef {import('../../infrastructure/utils/pdf/attendance-sheet-pdf.js')} AttendanceSheetPdfUtils
* @typedef {import('../services/temporary-sessions-storage-for-mass-import-service.js').TemporarySessionsStorageForMassImportService} TemporarySessionsStorageForMassImportService
* @typedef {import('../../../shared/domain/services/certification-badges-service.js')} CertificationBadgesService
* @typedef {import('../services/certification-candidates-ods-service.js')} CertificationCandidatesOdsService
* @typedef {import('../../../../shared/domain/services/placement-profile-service.js')} PlacementProfileService
* @typedef {import('../../../../shared/domain/services/language-service.js')} languageService
Expand Down Expand Up @@ -64,10 +65,11 @@ import * as temporarySessionsStorageForMassImportService from '../services/tempo
* @typedef {TemporarySessionsStorageForMassImportService} TemporarySessionsStorageForMassImportService
* @typedef {SessionValidator} SessionValidator
* @typedef {AttendanceSheetPdfUtils} AttendanceSheetPdfUtils
* @typedef {CertificationBadgesService} CertificationBadgesService
* @typedef {certificationBadgesService} CertificationBadgesService
* @typedef {CertificationCandidatesOdsService} CertificationCandidatesOdsService
* @typedef {PlacementProfileService} PlacementProfileService
* @typedef {LanguageService} LanguageService
* @typedef {complementaryCertificationBadgesRepository} ComplementaryCertificationBadgesRepository
**/
const dependencies = {
certificationBadgesService,
Expand All @@ -81,6 +83,7 @@ const dependencies = {
certificationCandidatesOdsService,
placementProfileService,
languageService,
complementaryCertificationBadgesRepository,
};

const path = dirname(fileURLToPath(import.meta.url));
Expand Down
Loading
Loading