Skip to content

Commit

Permalink
[FEATURE] Ajoute un encart sur les attestations sur la page de fin de…
Browse files Browse the repository at this point in the history
… parcours (PIX-13826).

 #10411
  • Loading branch information
pix-service-auto-merge authored Nov 18, 2024
2 parents 525d19a + 082f046 commit 5dfbcdb
Show file tree
Hide file tree
Showing 22 changed files with 743 additions and 67 deletions.
309 changes: 254 additions & 55 deletions api/db/seeds/data/team-prescription/build-quests.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,97 @@
import { ATTESTATIONS } from '../../../../src/profile/domain/constants.js';
import { REWARD_TYPES } from '../../../../src/quest/domain/constants.js';
import { COMPARISON } from '../../../../src/quest/domain/models/Quest.js';
import { Assessment, Tag } from '../../../../src/shared/domain/models/index.js';
import { temporaryStorage } from '../../../../src/shared/infrastructure/temporary-storage/index.js';
import { TARGET_PROFILE_BADGES_STAGES_ID } from './constants.js';

async function createAttestationQuest(databasebuilder) {
const campaigns = await retrieveCampaigns(databasebuilder);
const evaluatedSkills = await retrieveEvaluatedSkills(databasebuilder, campaigns);
const successfulUsers = await retrieveSuccessfulUsers(databasebuilder, campaigns);
const profileRewardTemporaryStorage = temporaryStorage.withPrefix('profile-rewards:');

const { id: rewardId } = await databasebuilder.factory.buildAttestation({
templateName: 'sixth-grade-attestation-template',
key: ATTESTATIONS.SIXTH_GRADE,
});
const USERS = [
{
firstName: 'attestation-success',
lastName: 'attestation',
email: '[email protected]',
},
{
firstName: 'attestation-failed',
lastName: 'attestation',
email: '[email protected]',
},
{
firstName: 'attestation-pending',
lastName: 'attestation',
email: '[email protected]',
},
{
firstName: 'attestation-blank',
lastName: 'attestation',
email: '[email protected]',
},
];
const ORGANIZATION = { name: 'attestation', type: 'SCO', isManagingStudents: true };
const ORGANIZATION_TAG = Tag.AEFE;
const CAMPAIGN = { code: 'ATESTTEST', multipleSendings: true };

const TUBES = [
{
id: 'tube2e715GxaaWzNK6',
level: 2,
},
{
id: 'recs1vdbHxX8X55G9',
level: 2,
},
{
id: 'reccqGUKgzIOK8f9U',
level: 2,
},
{
id: 'recBbCIEKgrQi7eb6',
level: 2,
},
{
id: 'recpe7Y8Wq2D56q6I',
level: 2,
},
{
id: 'recPOjwrHFhM21yGE',
level: 2,
},
];

const SKILLS = [
'skill2wQfMYrOHlL6HI',
'skill1QAVccgLO16Rx8',
'skillX5Rpk2rucNfnF',
'skill1aj7jVAKrVgUye',
'reczOCGv8pz976Acl',
'skill2mIMdudcltFsaz',
];

const buildUsers = (databaseBuilder) => USERS.map((user) => databaseBuilder.factory.buildUser.withRawPassword(user));

const buildOrganization = (databaseBuilder) => databaseBuilder.factory.buildOrganization(ORGANIZATION);

const buildOrganizationLearners = (databaseBuilder, organization, users) =>
users.map((user) =>
databaseBuilder.factory.buildOrganizationLearner({
userId: user.id,
organizationId: organization.id,
}),
);

const buildCampaignParticipations = (databaseBuilder, campaignId, users) =>
users.map(({ user, organizationLearner }) =>
databaseBuilder.factory.buildCampaignParticipation({
userId: user.id,
campaignId,
masteryRate: 1,
organizationLearnerId: organizationLearner.id,
}),
);

const buildQuest = (databaseBuilder, rewardId, targetProfileId) => {
const questEligibilityRequirements = [
{
type: 'organization',
Expand All @@ -25,80 +104,200 @@ async function createAttestationQuest(databasebuilder) {
type: 'organization',
data: {
isManagingStudents: true,
tags: ['AEFE'],
tags: [ORGANIZATION_TAG],
},
comparison: COMPARISON.ONE_OF,
},
{
type: 'organizationLearner',
data: {
MEFCode: '10010012110',
},
comparison: COMPARISON.ALL,
},
{
type: 'campaignParticipations',
data: {
targetProfileIds: [TARGET_PROFILE_BADGES_STAGES_ID],
targetProfileIds: [targetProfileId],
},
comparison: COMPARISON.ALL,
},
];

const questSuccessRequirements = [
{
type: 'skill',
data: {
ids: evaluatedSkills.map((skill) => skill.skillId),
ids: SKILLS,
threshold: 50,
},
},
];

await databasebuilder.factory.buildQuest({
databaseBuilder.factory.buildQuest({
rewardType: REWARD_TYPES.ATTESTATION,
rewardId,
eligibilityRequirements: questEligibilityRequirements,
successRequirements: questSuccessRequirements,
});
};

const buildFirstStages = async (
databaseBuilder,
successUser,
successParticipation,
failedUser,
failedParticipation,
pendingUser,
pendingParticipation,
) => {
const stages = await databaseBuilder.knex('stages').where({ targetProfileId: TARGET_PROFILE_BADGES_STAGES_ID });

const stageZero = stages.find((stage) => stage.level === 0 || stage.threshold === 0);

databaseBuilder.factory.buildStageAcquisition({
stageId: stageZero.id,
userId: successUser.id,
campaignParticipationId: successParticipation.id,
});
databaseBuilder.factory.buildStageAcquisition({
stageId: stageZero.id,
userId: failedUser.id,
campaignParticipationId: failedParticipation.id,
});
databaseBuilder.factory.buildStageAcquisition({
stageId: stageZero.id,
userId: pendingUser.id,
campaignParticipationId: pendingParticipation.id,
});
};

const buildTargetProfile = (databaseBuilder, organization) => {
const targetProfile = databaseBuilder.factory.buildTargetProfile({
description: 'parcours attestation 6 eme',
name: 'parcours attestation 6 eme',
ownerOrganizationId: organization.id,
});

TUBES.map(({ tubeId, level }) =>
databaseBuilder.factory.buildTargetProfileTube({
targetProfileId: targetProfile.id,
tubeId,
level,
}),
);

return targetProfile;
};

export const buildQuests = async (databaseBuilder) => {
// Create USERS

const [successUser, failedUser, pendingUser, blankUser] = buildUsers(databaseBuilder);

// Create organization

const organization = buildOrganization(databaseBuilder);

// Get organization tag id

const { id: tagId } = await databaseBuilder.knex('tags').select('id').where({ name: ORGANIZATION_TAG }).first();

// Associate tag to organization

databaseBuilder.factory.buildOrganizationTag({ organizationId: organization.id, tagId: tagId });

// Create organizationLearners

const [successOrganizationLearner, failedOrganizationLearner, pendingOrganizationLearner] = buildOrganizationLearners(
databaseBuilder,
organization,
[successUser, failedUser, pendingUser, blankUser],
);

// Create target profile

const targetProfile = buildTargetProfile(databaseBuilder, organization);

// Create campaigns

const { id: campaignId } = databaseBuilder.factory.buildCampaign({
...CAMPAIGN,
targetProfileId: targetProfile.id,
organizationId: organization.id,
});

await Promise.all(
successfulUsers.map(({ userId }) => {
return databasebuilder.factory.buildProfileReward({
userId,
rewardType: REWARD_TYPES.ATTESTATION,
rewardId,
});
SKILLS.map((skillId) =>
databaseBuilder.factory.buildCampaignSkill({
campaignId,
skillId,
}),
);
}

export function buildQuests(databaseBuilder) {
return createAttestationQuest(databaseBuilder);
}
// Create campaignParticipations

const [successParticipation, failedParticipation, pendingParticipation] = buildCampaignParticipations(
databaseBuilder,
campaignId,
[
{
user: successUser,
organizationLearner: successOrganizationLearner,
},
{
user: failedUser,
organizationLearner: failedOrganizationLearner,
},
{
user: pendingUser,
organizationLearner: pendingOrganizationLearner,
},
],
);

// Create assessments

databaseBuilder.factory.buildAssessment({
userId: successUser.id,
type: Assessment.types.CAMPAIGN,
campaignParticipationId: successParticipation.id,
});
databaseBuilder.factory.buildAssessment({
userId: failedUser.id,
type: Assessment.types.CAMPAIGN,
campaignParticipationId: failedParticipation.id,
});
databaseBuilder.factory.buildAssessment({
userId: pendingUser.id,
type: Assessment.types.CAMPAIGN,
campaignParticipationId: pendingParticipation.id,
});

// Create first stage

await buildFirstStages(
databaseBuilder,
successUser,
successParticipation,
failedUser,
failedParticipation,
pendingUser,
pendingParticipation,
);

// Create attestation quest

const { id: rewardId } = databaseBuilder.factory.buildAttestation({
templateName: 'sixth-grade-attestation-template',
key: ATTESTATIONS.SIXTH_GRADE,
});

// Create quest

buildQuest(databaseBuilder, rewardId, targetProfile.id);

// Create reward for success user

async function retrieveCampaigns(databaseBuilder) {
return databaseBuilder.knex('campaigns').select('id').where({
targetProfileId: TARGET_PROFILE_BADGES_STAGES_ID,
databaseBuilder.factory.buildProfileReward({
userId: successUser.id,
rewardType: REWARD_TYPES.ATTESTATION,
rewardId,
});
}

async function retrieveEvaluatedSkills(databaseBuilder, campaigns) {
return databaseBuilder
.knex('campaign_skills')
.distinct('skillId')
.whereIn(
'campaignId',
campaigns.map((campaign) => campaign.id),
);
}

async function retrieveSuccessfulUsers(databaseBuilder, campaigns) {
return databaseBuilder
.knex('campaign-participations')
.distinct('userId')
.whereIn(
'campaignId',
campaigns.map((campaign) => campaign.id),
)
.andWhere('masteryRate', '>=', 0.5);
}

// Insert job count in temporary storage for pending user

profileRewardTemporaryStorage.increment(pendingUser.id);
};
4 changes: 2 additions & 2 deletions api/src/profile/application/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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 { securityPreHandlers } from '../../shared/application/security-pre-handlers.js';
import { attestationController } from './attestation-controller.js';
import { profileController } from './profile-controller.js';

Expand All @@ -26,7 +26,7 @@ const register = async function (server) {
handler: attestationController.getUserAttestation,
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" +
"- Récupération de l'attestation utilisateur" +
'- L’id demandé doit correspondre à celui de l’utilisateur authentifié',
],
tags: ['api', 'user', 'profile'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ class TemporaryStorage {
},

increment(key) {
return storage.increment({ key: prefix + key });
return storage.increment(prefix + key);
},

decrement(key) {
return storage.decrement({ key: prefix + key });
return storage.decrement(prefix + key);
},

ttl(key) {
Expand Down
Loading

0 comments on commit 5dfbcdb

Please sign in to comment.