Skip to content

Commit

Permalink
feat(api): update usecase assessement csv to get extraRows
Browse files Browse the repository at this point in the history
  • Loading branch information
xav-car committed Sep 20, 2024
1 parent b7c5146 commit 7422e09
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { createOneCsvLine };
function createOneCsvLine({
organization,
campaign,
extraRows,
campaignParticipationInfo,
targetProfile,
learningContent,
Expand All @@ -20,6 +21,7 @@ function createOneCsvLine({
campaign,
campaignParticipationInfo,
targetProfile,
extraRows,
learningContent,
stageCollection,
participantKnowledgeElementsByCompetenceId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,35 @@ import { CampaignLearningContent } from '../../../../shared/domain/models/Campai
import * as csvSerializer from '../../../../shared/infrastructure/serializers/csv/csv-serializer.js';
import { PromiseUtils } from '../../../../shared/infrastructure/utils/promise-utils.js';

/**
* @typedef {import ('./index.js').CampaignRepository} CampaignRepository
* @typedef {import ('./index.js').CampaignParticipationInfoRepository} CampaignParticipationInfoRepository
* @typedef {import ('./index.js').OrganizationRepository} OrganizationRepository
* @typedef {import ('./index.js').KnowledgeElementSnapshotRepository} KnowledgeElementSnapshotRepository
* @typedef {import ('./index.js').CampaignCsvExportService} CampaignCsvExportService
* @typedef {import ('./index.js').TargetProfileRepository} TargetProfileRepository
* @typedef {import ('./index.js').LearningContentRepository} LearningContentRepository
* @typedef {import ('./index.js').StageCollectionRepository} StageCollectionRepository
* @typedef {import ('./index.js').OrganizationFeatureApi} OrganizationFeatureApi
* @typedef {import ('./index.js').OrganizationLearnerImportFormat} OrganizationLearnerImportFormat
*/

/**
* @param {Object} params
* @param {Number} params.campaignId
* @param {Object} params.writableStream
* @param {Object} params.i18n
* @param {CampaignRepository} params.campaignRepository
* @param {CampaignParticipationInfoRepository} params.campaignParticipationInfoRepository
* @param {OrganizationRepository} params.organizationRepository
* @param {KnowledgeElementSnapshotRepository} params.knowledgeElementSnapshotRepository
* @param {CampaignCsvExportService} params.campaignCsvExportService
* @param {TargetProfileRepository} params.targetProfileRepository
* @param {LearningContentRepository} params.learningContentRepository
* @param {StageCollectionRepository} params.stageCollectionRepository
* @param {OrganizationFeatureApi} params.organizationFeatureApi
* @param {OrganizationLearnerImportFormat} params.organizationLearnerImportFormatRepository
*/
const startWritingCampaignAssessmentResultsToStream = async function ({
campaignId,
writableStream,
Expand All @@ -28,7 +57,10 @@ const startWritingCampaignAssessmentResultsToStream = async function ({
targetProfileRepository,
learningContentRepository,
stageCollectionRepository,
organizationFeatureApi,
organizationLearnerImportFormatRepository,
}) {
let extraColumns = [];
const campaign = await campaignRepository.get(campaignId);
const translate = i18n.__;

Expand All @@ -44,15 +76,22 @@ const startWritingCampaignAssessmentResultsToStream = async function ({
const organization = await organizationRepository.get(campaign.organizationId);
const campaignParticipationInfos = await campaignParticipationInfoRepository.findByCampaignId(campaign.id);

const organizationFeatures = await organizationFeatureApi.getAllFeaturesFromOrganization(campaign.organizationId);
if (organizationFeatures.hasLearnersImportFeature) {
const importFormat = await organizationLearnerImportFormatRepository.get(campaign.organizationId);
extraColumns = importFormat.exportableColumns;
}

// Create HEADER of CSV
const headers = _createHeaderOfCSV(
const headers = _createHeaderOfCSV({
targetProfile,
campaign.idPixLabel,
idPixLabel: campaign.idPixLabel,
organization,
translate,
campaignLearningContent,
learningContent: campaignLearningContent,
stageCollection,
);
extraColumns,
});

// WHY: add \uFEFF the UTF-8 BOM at the start of the text, see:
// - https://en.wikipedia.org/wiki/Byte_order_mark
Expand Down Expand Up @@ -134,6 +173,7 @@ const startWritingCampaignAssessmentResultsToStream = async function ({
organization,
campaign,
campaignParticipationInfo,
extraRows: extraColumns,
targetProfile,
learningContent: campaignLearningContent,
stageCollection,
Expand Down Expand Up @@ -165,10 +205,20 @@ const startWritingCampaignAssessmentResultsToStream = async function ({

export { startWritingCampaignAssessmentResultsToStream };

function _createHeaderOfCSV(targetProfile, idPixLabel, organization, translate, learningContent, stageCollection) {
function _createHeaderOfCSV({
targetProfile,
idPixLabel,
organization,
translate,
learningContent,
stageCollection,
extraColumns,
}) {
const forSupStudents = organization.isSup && organization.isManagingStudents;
const displayDivision = organization.isSco && organization.isManagingStudents;

const extraHeaders = extraColumns.map((column) => column.columnName);

return [
translate('campaign-export.common.organization-name'),
translate('campaign-export.common.campaign-id'),
Expand All @@ -177,6 +227,7 @@ function _createHeaderOfCSV(targetProfile, idPixLabel, organization, translate,
translate('campaign-export.assessment.target-profile-name'),
translate('campaign-export.common.participant-lastname'),
translate('campaign-export.common.participant-firstname'),
...extraHeaders,
...(displayDivision ? [translate('campaign-export.common.participant-division')] : []),
...(forSupStudents ? [translate('campaign-export.common.participant-group')] : []),
...(forSupStudents ? [translate('campaign-export.common.participant-student-number')] : []),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import stream from 'node:stream';
const { PassThrough } = stream;

import { usecases } from '../../../../../../src/prescription/campaign/domain/usecases/index.js';
import { ORGANIZATION_FEATURE } from '../../../../../../src/shared/domain/constants.js';
import { Assessment } from '../../../../../../src/shared/domain/models/Assessment.js';
import { CampaignParticipationStatuses, KnowledgeElement } from '../../../../../../src/shared/domain/models/index.js';
import { databaseBuilder, expect, mockLearningContent, streamToPromise } from '../../../../../test-helper.js';
Expand Down Expand Up @@ -72,6 +73,148 @@ describe('Integration | Domain | Use Cases | start-writing-campaign-assessment-r
csvPromise = streamToPromise(writableStream);
});

context('extra rows', function () {
beforeEach(async function () {
// Import Configuration
const importConfig = {
name: 'MY_TEST_EXPORT',
fileType: 'csv',
config: {
acceptedEncoding: ['utf-8'],
unicityColumns: ['my_column1'],
validationRules: {
formats: [
{ name: 'my_column1', type: 'string' },
{ name: 'my_column2', type: 'string' },
],
},
headers: [
{ name: 'my_column1', required: true, property: 'lastName' },
{ name: 'my_column2', required: true, property: 'firstName' },
{ name: 'hobby', required: true, config: { exportable: true } },
],
},
};
const feature = databaseBuilder.factory.buildFeature({
key: ORGANIZATION_FEATURE.LEARNER_IMPORT.key,
});
const organizationLearnerImportFormatId =
databaseBuilder.factory.buildOrganizationLearnerImportFormat(importConfig).id;

databaseBuilder.factory.buildOrganizationFeature({
featureId: feature.id,
organizationId: organization.id,
params: { organizationLearnerImportFormatId },
});
participant = databaseBuilder.factory.buildUser();
organizationLearner = databaseBuilder.factory.prescription.organizationLearners.buildOrganizationLearner({
firstName: '@Jean',
lastName: '=Bono',
organizationId: organization.id,
userId: participant.id,
attributes: { hobby: 'genky', sleep: '8h' },
});

campaignParticipation = databaseBuilder.factory.buildCampaignParticipation({
campaignId: campaign.id,
organizationLearnerId: organizationLearner.id,
userId: participant.id,
participantExternalId: 'toto',
masteryRate: 0.67,
createdAt,
sharedAt,
});

databaseBuilder.factory.buildAssessment({
campaignParticipationId: campaignParticipation.id,
userId: participant.id,
state: Assessment.states.COMPLETED,
type: Assessment.types.CAMPAIGN,
});

const ke1 = databaseBuilder.factory.buildKnowledgeElement({
status: 'validated',
skillId: 'recSkillWeb1',
competenceId: 'recCompetence1',
userId: participant.id,
createdAt,
});
const ke2 = databaseBuilder.factory.buildKnowledgeElement({
status: 'validated',
skillId: 'recSkillWeb2',
competenceId: 'recCompetence1',
userId: participant.id,
createdAt,
});
const ke3 = databaseBuilder.factory.buildKnowledgeElement({
status: 'invalidated',
skillId: 'recSkillWeb3',
competenceId: 'recCompetence1',
userId: participant.id,
createdAt,
});
databaseBuilder.factory.buildKnowledgeElementSnapshot({
userId: participant.id,
snappedAt: sharedAt,
snapshot: JSON.stringify([ke1, ke2, ke3]),
});

['recSkillWeb1', 'recSkillWeb2', 'recSkillWeb3'].forEach((skillId) => {
databaseBuilder.factory.buildCampaignSkill({
campaignId: campaign.id,
skillId: skillId,
});
});

await databaseBuilder.commit();
});

it('should return the complete line', async function () {
// given
const csvSecondLine =
`"${organization.name}";` +
`${campaign.id};` +
`"${campaign.code}";` +
`"'${campaign.name}";` +
`"'${targetProfile.name}";` +
`"'${organizationLearner.lastName}";` +
`"'${organizationLearner.firstName}";` +
`"${organizationLearner.attributes.hobby}";` +
`"${campaignParticipation.participantExternalId}";` +
'1;' +
'2019-02-25;' +
'"Oui";' +
'2019-03-01;' +
'1;' +
'"Non";' +
'0,67;' +
'0,67;' +
'3;' +
'2;' +
'0,67;' +
'3;' +
'2;' +
'"OK";' +
'"OK";' +
'"KO"';

// when
await usecases.startWritingCampaignAssessmentResultsToStream({
campaignId: campaign.id,
writableStream,
i18n,
});
const csv = await csvPromise;

const csvLines = csv.split('\n');
const csvFirstLineCells = csvLines[0].split(';');

// then
expect(csvFirstLineCells[7]).to.equal('"hobby"');
expect(csvLines[1]).to.equal(csvSecondLine);
});
});

context('participation shared', function () {
beforeEach(async function () {
// learner
Expand Down

0 comments on commit 7422e09

Please sign in to comment.