Skip to content

Commit 967801c

Browse files
committed
feat(api): add v3 attestation generation for session
1 parent 4fcbad9 commit 967801c

File tree

3 files changed

+143
-70
lines changed

3 files changed

+143
-70
lines changed

api/src/certification/results/application/certification-attestation-controller.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,32 @@ const getPDFAttestation = async function (
5252
const getCertificationPDFAttestationsForSession = async function (
5353
request,
5454
h,
55-
dependencies = { certificationAttestationPdf },
55+
dependencies = { certificationAttestationPdf, v3CertificationAttestationPdf },
5656
) {
57+
const { i18n } = request;
58+
5759
const sessionId = request.params.sessionId;
5860
const isFrenchDomainExtension = request.query.isFrenchDomainExtension;
5961
const attestations = await usecases.getCertificationAttestationsForSession({
6062
sessionId,
6163
});
6264

6365
if (attestations.every((attestation) => attestation instanceof V3CertificationAttestation)) {
64-
return h.response().code(200);
65-
}
66+
const translatedFileName = i18n.__('certification-confirmation.file-name', {
67+
deliveredAt: dayjs(attestations[0].deliveredAt).format('YYYYMMDD'),
68+
});
6669

67-
const i18n = request.i18n;
70+
return h
71+
.response(
72+
dependencies.v3CertificationAttestationPdf.generate({
73+
certificates: attestations,
74+
i18n,
75+
}),
76+
)
77+
.code(200)
78+
.header('Content-Disposition', `attachment; filename=session-${sessionId}-${translatedFileName}`)
79+
.header('Content-Type', 'application/pdf');
80+
}
6881

6982
const { buffer } = await dependencies.certificationAttestationPdf.getCertificationAttestationsPdfBuffer({
7083
certificates: attestations,

api/tests/certification/evaluation/acceptance/application/certification-attestation-route_test.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { readFile } from 'node:fs/promises';
22
import * as url from 'node:url';
33

4+
import dayjs from 'dayjs';
5+
46
import { generateCertificateVerificationCode } from '../../../../../src/certification/evaluation/domain/services/verify-certificate-code-service.js';
57
import { SESSIONS_VERSIONS } from '../../../../../src/certification/shared/domain/models/SessionVersion.js';
68
import { Assessment } from '../../../../../src/shared/domain/models/index.js';
@@ -224,14 +226,16 @@ describe('Certification | Results | Acceptance | Application | Routes | certific
224226
});
225227

226228
describe('when the session version is V3', function () {
227-
it('should return 200 HTTP status code', async function () {
229+
it('should return 200 HTTP status code and the certification', async function () {
228230
// given
229231
await featureToggles.set('isV3CertificationAttestationEnabled', true);
230232
const superAdmin = await insertUserWithRoleSuperAdmin();
231233

232-
await _buildDatabaseCertification({
234+
const sessionId = 4567;
235+
236+
const { session } = await _buildDatabaseCertification({
233237
userId: superAdmin.id,
234-
sessionId: 4567,
238+
sessionId,
235239
sessionVersion: SESSIONS_VERSIONS.V3,
236240
});
237241
await databaseBuilder.commit();
@@ -247,6 +251,11 @@ describe('Certification | Results | Acceptance | Application | Routes | certific
247251

248252
// then
249253
expect(response.statusCode).to.equal(200);
254+
expect(response.headers['content-type']).to.equal('application/pdf');
255+
expect(response.headers['content-disposition']).to.equal(
256+
`attachment; filename=session-${sessionId}-attestation-pix-${dayjs(session.publishedAt).format('YYYYMMDD')}.pdf`,
257+
);
258+
expect(response.file).not.to.be.null;
250259
});
251260
});
252261
});

api/tests/certification/results/unit/application/certification-attestation-controller_test.js

+114-63
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const { FRENCH } = LANGUAGES_CODE;
1010

1111
describe('Certification | Results | Unit | Application | Controller | certification-attestation-controller', function () {
1212
describe('#getPDFAttestation', function () {
13-
describe('when the certification is new v3', function () {
13+
describe('when the attestation is for v3', function () {
1414
it('should return attestation in PDF binary format', async function () {
1515
// given
1616
const v3CertificationAttestation = domainBuilder.certification.results.buildV3CertificationAttestation();
@@ -54,7 +54,7 @@ describe('Certification | Results | Unit | Application | Controller | certificat
5454
});
5555
});
5656

57-
describe('when the certification is v2 or previous v3', function () {
57+
describe('when the attestation is for v2', function () {
5858
it('should return attestation in PDF binary format', async function () {
5959
// given
6060
const certificationAttestation = domainBuilder.buildCertificationAttestation();
@@ -99,73 +99,124 @@ describe('Certification | Results | Unit | Application | Controller | certificat
9999
});
100100

101101
describe('#getCertificationPDFAttestationsForSession', function () {
102-
it('should return an attestation in PDF binary format', async function () {
103-
// given
104-
const certificationAttestationPdf = {
105-
getCertificationAttestationsPdfBuffer: sinon.stub(),
106-
};
107-
const session = domainBuilder.certification.sessionManagement.buildSession.finalized({ id: 12 });
108-
domainBuilder.buildCertificationCourse({
109-
id: 1,
110-
sessionId: 12,
111-
userId: 1,
112-
completedAt: '2020-01-01',
113-
});
114-
domainBuilder.buildCertificationCourse({
115-
id: 2,
116-
sessionId: 12,
117-
userId: 2,
118-
completedAt: '2020-01-01',
119-
});
120-
domainBuilder.buildCertificationCourse({
121-
id: 3,
122-
sessionId: 12,
123-
userId: 3,
124-
completedAt: '2020-01-01',
125-
});
126-
const certification1 = domainBuilder.buildPrivateCertificateWithCompetenceTree({ id: 1 });
127-
const certification2 = domainBuilder.buildPrivateCertificateWithCompetenceTree({ id: 2 });
128-
const certification3 = domainBuilder.buildPrivateCertificateWithCompetenceTree({ id: 3 });
129-
const attestationPDF = 'binary string';
130-
const userId = 1;
131-
const i18n = getI18n();
102+
describe('when attestations are for a v3 session', function () {
103+
it('should return attestation in PDF binary format', async function () {
104+
// given
105+
const userId = 1;
106+
const i18n = getI18n();
132107

133-
const request = {
134-
auth: { credentials: { userId } },
135-
params: { sessionId: session.id },
136-
query: { isFrenchDomainExtension: true },
137-
i18n,
138-
};
108+
const v3CertificationAttestation = domainBuilder.certification.results.buildV3CertificationAttestation();
109+
const session = domainBuilder.certification.sessionManagement.buildSession.finalized({ id: 12 });
110+
const generatedPdf = Symbol('Stream');
139111

140-
sinon
141-
.stub(usecases, 'getCertificationAttestationsForSession')
142-
.withArgs({
143-
sessionId: session.id,
144-
})
145-
.resolves([certification1, certification2, certification3]);
112+
const request = {
113+
i18n,
114+
auth: { credentials: { userId } },
115+
params: { sessionId: session.id },
116+
query: { isFrenchDomainExtension: true },
117+
};
146118

147-
certificationAttestationPdf.getCertificationAttestationsPdfBuffer
148-
.withArgs({
149-
certificates: [certification1, certification2, certification3],
150-
isFrenchDomainExtension: true,
119+
sinon
120+
.stub(usecases, 'getCertificationAttestationsForSession')
121+
.withArgs({
122+
sessionId: session.id,
123+
})
124+
.resolves([v3CertificationAttestation, v3CertificationAttestation]);
125+
126+
const generatePdfStub = {
127+
generate: sinon.stub().returns(generatedPdf),
128+
};
129+
130+
// when
131+
const response = await certificationAttestationController.getCertificationPDFAttestationsForSession(
132+
request,
133+
hFake,
134+
{
135+
v3CertificationAttestationPdf: generatePdfStub,
136+
},
137+
);
138+
139+
// then
140+
expect(generatePdfStub.generate).calledOnceWithExactly({
141+
certificates: [v3CertificationAttestation, v3CertificationAttestation],
151142
i18n,
152-
})
153-
.resolves({ buffer: attestationPDF });
143+
});
144+
expect(response.source).to.deep.equal(generatedPdf);
145+
expect(response.headers['Content-Disposition']).to.contains(
146+
`attachment; filename=session-${session.id}-attestation-pix-${dayjs(v3CertificationAttestation.deliveredAt).format('YYYYMMDD')}.pdf`,
147+
);
148+
});
149+
});
154150

155-
// when
156-
const response = await certificationAttestationController.getCertificationPDFAttestationsForSession(
157-
request,
158-
hFake,
159-
{
160-
certificationAttestationPdf,
161-
},
162-
);
151+
describe('when attestations are for a v2 session', function () {
152+
it('should return an attestation in PDF binary format', async function () {
153+
// given
154+
const certificationAttestationPdf = {
155+
getCertificationAttestationsPdfBuffer: sinon.stub(),
156+
};
157+
const session = domainBuilder.certification.sessionManagement.buildSession.finalized({ id: 12 });
158+
domainBuilder.buildCertificationCourse({
159+
id: 1,
160+
sessionId: 12,
161+
userId: 1,
162+
completedAt: '2020-01-01',
163+
});
164+
domainBuilder.buildCertificationCourse({
165+
id: 2,
166+
sessionId: 12,
167+
userId: 2,
168+
completedAt: '2020-01-01',
169+
});
170+
domainBuilder.buildCertificationCourse({
171+
id: 3,
172+
sessionId: 12,
173+
userId: 3,
174+
completedAt: '2020-01-01',
175+
});
176+
const certification1 = domainBuilder.buildPrivateCertificateWithCompetenceTree({ id: 1 });
177+
const certification2 = domainBuilder.buildPrivateCertificateWithCompetenceTree({ id: 2 });
178+
const certification3 = domainBuilder.buildPrivateCertificateWithCompetenceTree({ id: 3 });
179+
const attestationPDF = 'binary string';
180+
const userId = 1;
181+
const i18n = getI18n();
163182

164-
// then
165-
expect(response.source).to.deep.equal(attestationPDF);
166-
expect(response.headers['Content-Disposition']).to.contains(
167-
'attachment; filename=attestation-pix-session-12.pdf',
168-
);
183+
const request = {
184+
auth: { credentials: { userId } },
185+
params: { sessionId: session.id },
186+
query: { isFrenchDomainExtension: true },
187+
i18n,
188+
};
189+
190+
sinon
191+
.stub(usecases, 'getCertificationAttestationsForSession')
192+
.withArgs({
193+
sessionId: session.id,
194+
})
195+
.resolves([certification1, certification2, certification3]);
196+
197+
certificationAttestationPdf.getCertificationAttestationsPdfBuffer
198+
.withArgs({
199+
certificates: [certification1, certification2, certification3],
200+
isFrenchDomainExtension: true,
201+
i18n,
202+
})
203+
.resolves({ buffer: attestationPDF });
204+
205+
// when
206+
const response = await certificationAttestationController.getCertificationPDFAttestationsForSession(
207+
request,
208+
hFake,
209+
{
210+
certificationAttestationPdf,
211+
},
212+
);
213+
214+
// then
215+
expect(response.source).to.deep.equal(attestationPDF);
216+
expect(response.headers['Content-Disposition']).to.contains(
217+
'attachment; filename=attestation-pix-session-12.pdf',
218+
);
219+
});
169220
});
170221
});
171222

0 commit comments

Comments
 (0)