Skip to content

Commit 5187377

Browse files
[FEATURE] Permettre aux Orga de type AEFE de bénéficier du calcul de la certificabilité (Pix-9818)
#7373
2 parents d98147a + c892346 commit 5187377

File tree

11 files changed

+151
-136
lines changed

11 files changed

+151
-136
lines changed

api/lib/application/organizations/organization-controller.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import customParseFormat from 'dayjs/plugin/customParseFormat.js';
2828
dayjs.extend(customParseFormat);
2929
import { getDivisionCertificationResultsCsv } from '../../infrastructure/utils/csv/certification-results/get-division-certification-results-csv.js';
3030
import { getCertificationAttestationsPdf as certificationAttestationPdf } from '../../infrastructure/utils/pdf/certification-attestation-pdf.js';
31-
import * as organizationForAdminSerializer from '../../infrastructure/serializers/jsonapi/organization-for-admin-serializer.js';
31+
import * as organizationForAdminSerializer from '../../infrastructure/serializers/jsonapi/organizations-administration/organization-for-admin-serializer.js';
3232

3333
import { mapCertificabilityByLabel } from './helpers.js';
3434
import * as csvSerializer from '../../infrastructure/serializers/csv/csv-serializer.js';

api/lib/domain/models/organizations-administration/OrganizationForAdmin.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class OrganizationForAdmin {
3232
identityProviderForCampaigns,
3333
enableMultipleSendingAssessment,
3434
tags = [],
35+
tagIds = [],
3536
features = {},
3637
} = {}) {
3738
this.id = id;
@@ -63,6 +64,7 @@ class OrganizationForAdmin {
6364
this.identityProviderForCampaigns = identityProviderForCampaigns;
6465
this.enableMultipleSendingAssessment = enableMultipleSendingAssessment;
6566
this.tags = tags;
67+
this.tagIds = tagIds;
6668
this.features = features;
6769
if (this.type === 'SCO' && this.isManagingStudents) {
6870
this.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key] = true;
@@ -90,6 +92,8 @@ class OrganizationForAdmin {
9092
}
9193

9294
updateWithDataProtectionOfficerAndTags(organization, dataProtectionOfficer = {}, tags = []) {
95+
const isAEFE = Boolean(tags.find((tag) => tag.name === 'AEFE'));
96+
9397
if (organization.name) this.name = organization.name;
9498
if (organization.type) this.type = organization.type;
9599
if (organization.logoUrl) this.logoUrl = organization.logoUrl;
@@ -103,9 +107,8 @@ class OrganizationForAdmin {
103107
this.updateIdentityProviderForCampaigns(organization.identityProviderForCampaigns);
104108
this.dataProtectionOfficer.updateInformation(dataProtectionOfficer);
105109
this.features[ORGANIZATION_FEATURE.MULTIPLE_SENDING_ASSESSMENT.key] = organization.enableMultipleSendingAssessment;
106-
if (this.type === 'SCO') {
107-
this.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key] = this.isManagingStudents;
108-
}
110+
this.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key] =
111+
this.type === 'SCO' && (this.isManagingStudents || isAEFE);
109112
this.tagsToAdd = differenceBy(tags, this.tags, 'id').map(({ id }) => ({ tagId: id, organizationId: this.id }));
110113
this.tagsToRemove = differenceBy(this.tags, tags, 'id').map(({ id }) => ({ tagId: id, organizationId: this.id }));
111114
}

api/lib/domain/usecases/organizations-administration/update-organization-information.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
const updateOrganizationInformation = async function ({
22
organization,
33
organizationForAdminRepository,
4+
tagRepository,
45
domainTransaction,
56
}) {
67
const existingOrganization = await organizationForAdminRepository.get(organization.id, domainTransaction);
8+
const tagsToUpdate = await tagRepository.findByIds(organization.tagIds, domainTransaction);
79

810
existingOrganization.updateWithDataProtectionOfficerAndTags(
911
organization,
1012
organization.dataProtectionOfficer,
11-
organization.tags,
13+
tagsToUpdate,
1214
);
1315

1416
await organizationForAdminRepository.update(existingOrganization, domainTransaction);

api/lib/infrastructure/repositories/organization-for-admin-repository.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,9 @@ function _toDomain(rawOrganization) {
3737
identityProviderForCampaigns: rawOrganization.identityProviderForCampaigns,
3838
enableMultipleSendingAssessment: rawOrganization.enableMultipleSendingAssessment,
3939
features: rawOrganization.features,
40+
tags: rawOrganization.tags || [],
4041
});
4142

42-
organization.tags = rawOrganization.tags || [];
43-
4443
return organization;
4544
}
4645

@@ -144,7 +143,7 @@ async function _disableFeatures(knexConn, features, organizationId) {
144143
}
145144

146145
async function _addTags(knexConn, organizationTags) {
147-
await knex('organization-tags').insert(organizationTags).onConflict(['tagId', 'organizationId']).ignore();
146+
await knexConn('organization-tags').insert(organizationTags).onConflict(['tagId', 'organizationId']).ignore();
148147
}
149148

150149
async function _removeTags(knexConn, organizationTags) {

api/lib/infrastructure/repositories/tag-repository.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,10 @@ const findAll = async function () {
3333
return rows.map((row) => new Tag(row));
3434
};
3535

36-
export { create, findByName, findAll };
36+
const findByIds = async function (tagIds, domainTransaction) {
37+
const knexConn = domainTransaction.knexTransaction;
38+
const rows = await knexConn('tags').whereIn('id', tagIds);
39+
return rows.map((row) => new Tag(row));
40+
};
41+
42+
export { create, findByName, findAll, findByIds };

api/lib/infrastructure/serializers/jsonapi/organization-for-admin-serializer.js

-109
This file was deleted.

api/lib/infrastructure/serializers/jsonapi/organizations-administration/organization-for-admin-serializer.js

+9-8
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ const serialize = function (organizations, meta) {
77
transform(record) {
88
const dataProtectionOfficer = record.dataProtectionOfficer;
99

10-
record.dataProtectionOfficerFirstName = dataProtectionOfficer.firstName;
11-
record.dataProtectionOfficerLastName = dataProtectionOfficer.lastName;
12-
record.dataProtectionOfficerEmail = dataProtectionOfficer.email;
13-
10+
if (dataProtectionOfficer) {
11+
record.dataProtectionOfficerFirstName = dataProtectionOfficer.firstName;
12+
record.dataProtectionOfficerLastName = dataProtectionOfficer.lastName;
13+
record.dataProtectionOfficerEmail = dataProtectionOfficer.email;
14+
}
1415
return record;
1516
},
1617
attributes: [
@@ -73,10 +74,10 @@ const deserialize = function (json) {
7374
const attributes = json.data.attributes;
7475
const relationships = json.data.relationships;
7576

76-
let tags = [];
77+
let tagIds = [];
7778
if (relationships && relationships.tags) {
78-
tags = relationships.tags.data.map((tag) => {
79-
return { id: parseInt(tag.id) };
79+
tagIds = relationships.tags.data.map((tag) => {
80+
return parseInt(tag.id);
8081
});
8182
}
8283

@@ -98,7 +99,7 @@ const deserialize = function (json) {
9899
dataProtectionOfficerLastName: attributes['data-protection-officer-last-name'],
99100
dataProtectionOfficerEmail: attributes['data-protection-officer-email'],
100101
enableMultipleSendingAssessment: attributes['enable-multiple-sending-assessment'],
101-
tags,
102+
tagIds,
102103
});
103104

104105
return organization;

api/tests/integration/infrastructure/repositories/tag-repository_test.js

+25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { expect, knex, domainBuilder, databaseBuilder, catchErr } from '../../..
22
import { AlreadyExistingEntityError } from '../../../../lib/domain/errors.js';
33
import { Tag } from '../../../../lib/domain/models/Tag.js';
44
import * as tagRepository from '../../../../lib/infrastructure/repositories/tag-repository.js';
5+
import { DomainTransaction } from '../../../../lib/infrastructure/DomainTransaction.js';
56

67
describe('Integration | Repository | TagRepository', function () {
78
afterEach(async function () {
@@ -81,4 +82,28 @@ describe('Integration | Repository | TagRepository', function () {
8182
expect(result).to.be.deep.equal(expectedResult);
8283
});
8384
});
85+
86+
describe('#findByIds', function () {
87+
it('should return tagsByIds', async function () {
88+
// given
89+
const unknownId = 777777777;
90+
const tag1 = new Tag({ id: 100000, name: 'PUBLIC' });
91+
const tag2 = new Tag({ id: 100001, name: 'PRIVE' });
92+
93+
databaseBuilder.factory.buildTag(tag1);
94+
databaseBuilder.factory.buildTag(tag2);
95+
96+
await databaseBuilder.commit();
97+
98+
const expectedResult = [tag1];
99+
100+
// when
101+
const result = await DomainTransaction.execute(async (domainTransaction) =>
102+
tagRepository.findByIds([tag1.id, unknownId], domainTransaction),
103+
);
104+
105+
// then
106+
expect(result).to.be.deep.equal(expectedResult);
107+
});
108+
});
84109
});

api/tests/unit/domain/models/organizations-administration/OrganizationForAdmin_test.js

+78
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,84 @@ describe('Unit | Domain | Models | OrganizationForAdmin', function () {
258258
).to.equal(true);
259259
});
260260

261+
context('when updating AEFE tags', function () {
262+
it('should enable compute organization learner certificability for SCO organization', function () {
263+
// given
264+
const givenOrganization = new OrganizationForAdmin({
265+
isManagingStudents: false,
266+
type: 'SCO',
267+
features: {
268+
[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key]: false,
269+
},
270+
});
271+
272+
// when
273+
givenOrganization.updateWithDataProtectionOfficerAndTags({}, {}, [{ name: 'AEFE', id: 1 }]);
274+
275+
// then
276+
expect(
277+
givenOrganization.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key],
278+
).to.equal(true);
279+
});
280+
281+
it('should disable compute organization learner certificability on removing AEFE', function () {
282+
// given
283+
const givenOrganization = new OrganizationForAdmin({
284+
isManagingStudents: false,
285+
type: 'SCO',
286+
features: {
287+
[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key]: true,
288+
},
289+
});
290+
291+
// when
292+
givenOrganization.updateWithDataProtectionOfficerAndTags({});
293+
294+
// then
295+
expect(
296+
givenOrganization.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key],
297+
).to.equal(false);
298+
});
299+
300+
it('should not enable compute organization learner certificability for SUP organization', function () {
301+
// given
302+
const givenOrganization = new OrganizationForAdmin({
303+
isManagingStudents: false,
304+
type: 'SUP',
305+
features: {
306+
[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key]: false,
307+
},
308+
});
309+
310+
// when
311+
givenOrganization.updateWithDataProtectionOfficerAndTags({}, {}, [{ name: 'AEFE', id: 1 }]);
312+
313+
// then
314+
expect(
315+
givenOrganization.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key],
316+
).to.equal(false);
317+
});
318+
319+
it('should not enable compute organization learner certificability for PRO organization', function () {
320+
// given
321+
const givenOrganization = new OrganizationForAdmin({
322+
isManagingStudents: false,
323+
type: 'PRO',
324+
features: {
325+
[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key]: false,
326+
},
327+
});
328+
329+
// when
330+
givenOrganization.updateWithDataProtectionOfficerAndTags({}, {}, [{ name: 'AEFE', id: 1 }]);
331+
332+
// then
333+
expect(
334+
givenOrganization.features[ORGANIZATION_FEATURE.COMPUTE_ORGANIZATION_LEARNER_CERTIFICABILITY.key],
335+
).to.equal(false);
336+
});
337+
});
338+
261339
it('should disable compute organization learner certificability when updating SCO organization isManagingStudents to false', function () {
262340
// given
263341
const givenOrganization = new OrganizationForAdmin({

0 commit comments

Comments
 (0)