From a5b1d81ee499da11bfc07b13d5e7b2b17c0b0a0a Mon Sep 17 00:00:00 2001 From: Yvonnick Frin Date: Wed, 29 Jan 2025 16:32:58 +0100 Subject: [PATCH] feat(api): add SHOW_SKILLS, SHOW_NPS and IS_MANAGING_STUDENTS as features in OrganizationForAdmin model --- .../domain/models/OrganizationForAdmin.js | 27 ++++++++++++++++--- .../organization-for-admin.repository.js | 18 +++++++++++-- api/src/shared/domain/constants.js | 12 +++++++++ .../organization.admin.route.test.js | 3 +++ .../models/OrganizationForAdmin_test.js | 25 ++++++++++++++++- 5 files changed, 78 insertions(+), 7 deletions(-) diff --git a/api/src/organizational-entities/domain/models/OrganizationForAdmin.js b/api/src/organizational-entities/domain/models/OrganizationForAdmin.js index af25020e54e..1f9a1106300 100644 --- a/api/src/organizational-entities/domain/models/OrganizationForAdmin.js +++ b/api/src/organizational-entities/domain/models/OrganizationForAdmin.js @@ -49,15 +49,11 @@ class OrganizationForAdmin { this.logoUrl = logoUrl; this.externalId = externalId; this.provinceCode = provinceCode; - this.isManagingStudents = isManagingStudents; this.credit = credit; this.email = email; this.documentationUrl = documentationUrl; this.createdBy = createdBy; this.createdAt = createdAt; - this.showNPS = showNPS; - this.formNPSUrl = formNPSUrl; - this.showSkills = showSkills; this.archivedAt = archivedAt; this.archivistFirstName = archivistFirstName; this.archivistLastName = archivistLastName; @@ -74,7 +70,30 @@ class OrganizationForAdmin { this.identityProviderForCampaigns = identityProviderForCampaigns; this.tags = tags; this.tagIds = tagIds; + + // @deprecated you should use value stored in features property + this.isManagingStudents = isManagingStudents; + // @deprecated you should use value stored in features property + this.showNPS = showNPS; + // @deprecated you should use value stored in features property + this.formNPSUrl = formNPSUrl; + // @deprecated you should use value stored in features property + this.showSkills = showSkills; + this.features = features; + + this.features[ORGANIZATION_FEATURE.IS_MANAGING_STUDENTS.key] = { + active: this.isManagingStudents, + params: null, + }; + this.features[ORGANIZATION_FEATURE.SHOW_SKILLS.key] = { + active: this.showSkills, + params: null, + }; + this.features[ORGANIZATION_FEATURE.SHOW_NPS.key] = { + active: this.showNPS, + params: this.showNPS ? { formNPSUrl: this.formNPSUrl } : null, + }; if (this.type === 'SCO' && this.isManagingStudents) { this.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key] = { active: true, diff --git a/api/src/organizational-entities/infrastructure/repositories/organization-for-admin.repository.js b/api/src/organizational-entities/infrastructure/repositories/organization-for-admin.repository.js index 0361eea3dd1..7810f7d0567 100644 --- a/api/src/organizational-entities/infrastructure/repositories/organization-for-admin.repository.js +++ b/api/src/organizational-entities/infrastructure/repositories/organization-for-admin.repository.js @@ -236,7 +236,14 @@ async function _disableFeatures(knexConn, features, organizationId) { .where('organization-features.organizationId', organizationId) .whereIn( 'features.key', - _.keys(features).filter((key) => features[key].active === false), + _.keys( + // These features does not exist in database for now. + _.omit(features, [ + ORGANIZATION_FEATURE.SHOW_SKILLS.key, + ORGANIZATION_FEATURE.SHOW_NPS.key, + ORGANIZATION_FEATURE.IS_MANAGING_STUDENTS.key, + ]), + ).filter((key) => features[key].active === false), ) .delete(); } @@ -247,7 +254,14 @@ async function _enableFeatures(knexConn, featuresToEnable, organizationId) { await knexConn(ORGANIZATION_FEATURES_TABLE_NAME) .insert( - _.keys(featuresToEnable) + _.keys( + // These features does not exist in database for now. + _.omit(featuresToEnable, [ + ORGANIZATION_FEATURE.SHOW_SKILLS.key, + ORGANIZATION_FEATURE.SHOW_NPS.key, + ORGANIZATION_FEATURE.IS_MANAGING_STUDENTS.key, + ]), + ) .filter((key) => featuresToEnable[key].active) .map((key) => ({ organizationId, diff --git a/api/src/shared/domain/constants.js b/api/src/shared/domain/constants.js index 1513db5d2fc..309fcd950f2 100644 --- a/api/src/shared/domain/constants.js +++ b/api/src/shared/domain/constants.js @@ -51,6 +51,18 @@ const ORGANIZATION_FEATURE = { key: 'COVER_RATE', description: "Permet l'affichage de la page statistiques sur Pix Orga", }, + SHOW_SKILLS: { + key: 'SHOW_SKILLS', + description: "Permet l'ajout des acquis dans l'export de résultats", + }, + IS_MANAGING_STUDENTS: { + key: 'IS_MANAGING_STUDENTS', + description: "Permet l'activation de l'import pour le SCO et le SUP", + }, + SHOW_NPS: { + key: 'SHOW_NPS', + description: "Permet l'affichage d'un lien vers le formulaire du Net Promoter Score", + }, }; const CAMPAIGN_FEATURES = { diff --git a/api/tests/organizational-entities/acceptance/application/organization/organization.admin.route.test.js b/api/tests/organizational-entities/acceptance/application/organization/organization.admin.route.test.js index f7980400c43..375c4d9334d 100644 --- a/api/tests/organizational-entities/acceptance/application/organization/organization.admin.route.test.js +++ b/api/tests/organizational-entities/acceptance/application/organization/organization.admin.route.test.js @@ -106,6 +106,9 @@ describe('Acceptance | Organizational Entities | Application | Route | Admin | O features: { [ORGANIZATION_FEATURE.MULTIPLE_SENDING_ASSESSMENT.key]: { active: false, params: null }, [ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key]: { active: true, params: null }, + [ORGANIZATION_FEATURE.SHOW_SKILLS.key]: { active: false, params: null }, + [ORGANIZATION_FEATURE.IS_MANAGING_STUDENTS.key]: { active: true, params: null }, + [ORGANIZATION_FEATURE.SHOW_NPS.key]: { active: false, params: null }, }, }, id: organization.id.toString(), diff --git a/api/tests/organizational-entities/unit/domain/models/OrganizationForAdmin_test.js b/api/tests/organizational-entities/unit/domain/models/OrganizationForAdmin_test.js index 173ae46fc93..a849ae28aca 100644 --- a/api/tests/organizational-entities/unit/domain/models/OrganizationForAdmin_test.js +++ b/api/tests/organizational-entities/unit/domain/models/OrganizationForAdmin_test.js @@ -11,6 +11,28 @@ describe('Unit | Organizational Entities | Domain | Model | OrganizationForAdmin }).to.throw(); }); + context('legacy features', function () { + it('put legacy features to new feature format', function () { + // given + const expectedOrganization = domainBuilder.buildOrganizationForAdmin({ + showSkills: false, + isManagingStudents: true, + showNPS: true, + formNPSUrl: 'https://some-url.com', + }); + + // when + const organization = new OrganizationForAdmin(expectedOrganization); + + // then + expect(organization.features).to.deep.includes({ + [ORGANIZATION_FEATURE.SHOW_SKILLS.key]: { active: false, params: null }, + [ORGANIZATION_FEATURE.IS_MANAGING_STUDENTS.key]: { active: true, params: null }, + [ORGANIZATION_FEATURE.SHOW_NPS.key]: { active: true, params: { formNPSUrl: 'https://some-url.com' } }, + }); + }); + }); + context('for sco organizations', function () { context('when organization isManagingStudent is true', function () { it('builds an OrganizationForAdmin with compute organization learner certificability enabled', function () { @@ -42,7 +64,8 @@ describe('Unit | Organizational Entities | Domain | Model | OrganizationForAdmin const organization = new OrganizationForAdmin(expectedOrganization); // then - expect(organization.features).to.deep.equal({}); + expect(organization.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key]).to.be + .undefined; }); }); });