From 279e243eab9569767b85e87736a741c4ac41f4b8 Mon Sep 17 00:00:00 2001 From: AndreiaPena Date: Fri, 6 Dec 2024 12:17:42 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20api:=20return=20Invali?= =?UTF-8?q?dSessionResultTokenError=20with=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/src/shared/application/error-manager.js | 4 ++++ api/src/shared/domain/errors.js | 7 +++++-- .../integration/application/error-manager_test.js | 11 +++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/api/src/shared/application/error-manager.js b/api/src/shared/application/error-manager.js index 95ff85db445..735941e93e0 100644 --- a/api/src/shared/application/error-manager.js +++ b/api/src/shared/application/error-manager.js @@ -492,6 +492,10 @@ function _mapToHttpError(error) { return new HttpErrors.BadRequestError(error.message, 'SENDING_EMAIL_TO_INVALID_EMAIL_ADDRESS', error.meta); } + if (error instanceof DomainErrors.InvalidSessionResultTokenError) { + return new HttpErrors.BadRequestError(error.message, error.code); + } + return new HttpErrors.BaseHttpError(error.message); } diff --git a/api/src/shared/domain/errors.js b/api/src/shared/domain/errors.js index 66f6aed4bc0..857c5ee9316 100644 --- a/api/src/shared/domain/errors.js +++ b/api/src/shared/domain/errors.js @@ -394,8 +394,11 @@ class InvalidResultRecipientTokenError extends DomainError { } class InvalidSessionResultTokenError extends DomainError { - constructor(message = 'Le token de récupération des résultats de la session de certification est invalide.') { - super(message); + constructor( + message = 'The token used to retrieve the results of the certification session is invalid.', + code = 'INVALID_SESSION_RESULT_TOKEN', + ) { + super(message, code); } } diff --git a/api/tests/shared/integration/application/error-manager_test.js b/api/tests/shared/integration/application/error-manager_test.js index 9eaba31257d..641ee47e5c1 100644 --- a/api/tests/shared/integration/application/error-manager_test.js +++ b/api/tests/shared/integration/application/error-manager_test.js @@ -89,6 +89,17 @@ describe('Integration | API | Controller Error', function () { ); expect(responseCode(response)).to.equal('SESSION_WITHOUT_STARTED_CERTIFICATION'); }); + + it('responds Bad Request when a InvalidSessionResultTokenError error occurs', async function () { + routeHandler.throws(new DomainErrors.InvalidSessionResultTokenError()); + const response = await server.requestObject(request); + + expect(response.statusCode).to.equal(BAD_REQUEST_ERROR); + expect(responseDetail(response)).to.equal( + 'The token used to retrieve the results of the certification session is invalid.', + ); + expect(responseCode(response)).to.equal('INVALID_SESSION_RESULT_TOKEN'); + }); }); context('403 Forbidden', function () { From 478485f3926534be657d87c7813f9e5f574149b8 Mon Sep 17 00:00:00 2001 From: AndreiaPena Date: Fri, 6 Dec 2024 12:19:22 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20mon-pix:=20improve=20e?= =?UTF-8?q?rror=20management=20on=20session=20results=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/download-session-results.gjs | 17 ++++++++----- mon-pix/app/services/file-saver.js | 2 +- .../download-session-results-test.gjs | 6 ++--- .../tests/unit/services/file-saver-test.js | 25 +++++++++---------- mon-pix/translations/en.json | 2 +- mon-pix/translations/fr.json | 2 +- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/mon-pix/app/components/download-session-results.gjs b/mon-pix/app/components/download-session-results.gjs index 1e727722038..aa3058cf244 100644 --- a/mon-pix/app/components/download-session-results.gjs +++ b/mon-pix/app/components/download-session-results.gjs @@ -11,13 +11,14 @@ import ENV from 'mon-pix/config/environment'; import PixWindow from 'mon-pix/utils/pix-window'; export default class DownloadSessionResults extends Component { - @tracked showErrorMessage = false; + @tracked errorMessage = null; @service fileSaver; + @service intl; @action async downloadSessionResults(event) { event.preventDefault(); - this.showErrorMessage = false; + this.errorMessage = null; try { const token = decodeURIComponent(PixWindow.getLocationHash().slice(1)); @@ -28,8 +29,12 @@ export default class DownloadSessionResults extends Component { body: { token }, }, }); - } catch { - this.showErrorMessage = true; + } catch (error) { + if (error.code === 'INVALID_SESSION_RESULT_TOKEN') { + this.errorMessage = this.intl.t('pages.download-session-results.errors.invalid-token'); + } else { + this.errorMessage = this.intl.t('common.error'); + } } } @@ -46,9 +51,9 @@ export default class DownloadSessionResults extends Component { {{t "pages.download-session-results.button.label"}} - {{#if this.showErrorMessage}} + {{#if this.errorMessage}} - {{t "pages.download-session-results.errors.expiration"}} + {{this.errorMessage}} {{/if}} diff --git a/mon-pix/app/services/file-saver.js b/mon-pix/app/services/file-saver.js index 0d321b4de92..26444b033a5 100644 --- a/mon-pix/app/services/file-saver.js +++ b/mon-pix/app/services/file-saver.js @@ -45,7 +45,7 @@ export default class FileSaver extends Service { if (!response.ok) { const payload = await response.json(); - throw new Error(payload?.errors[0]?.detail); + throw payload?.errors[0]; } if (response.headers && response.headers.get('Content-Disposition')) { diff --git a/mon-pix/tests/integration/components/download-session-results-test.gjs b/mon-pix/tests/integration/components/download-session-results-test.gjs index a5d7800eb43..9e3454e2b89 100644 --- a/mon-pix/tests/integration/components/download-session-results-test.gjs +++ b/mon-pix/tests/integration/components/download-session-results-test.gjs @@ -34,9 +34,9 @@ module('Integration | Component | download-session-results', function (hooks) { assert.dom(screen.getByRole('button', { name: t('pages.download-session-results.button.label') })).exists(); }); - test('should display the expiration error message', async function (assert) { + test('should display the invalid token error message', async function (assert) { // given - fileSaver.save.rejects(); + fileSaver.save.rejects({ status: '400', code: 'INVALID_SESSION_RESULT_TOKEN' }); // when const screen = await render(hbs``); @@ -44,7 +44,7 @@ module('Integration | Component | download-session-results', function (hooks) { await click(downloadButton); // then - assert.dom(screen.getByText(t('pages.download-session-results.errors.expiration'))).exists(); + assert.dom(screen.getByText(t('pages.download-session-results.errors.invalid-token'))).exists(); }); test('should trigger the download', async function (assert) { diff --git a/mon-pix/tests/unit/services/file-saver-test.js b/mon-pix/tests/unit/services/file-saver-test.js index 5f05f3b2cdd..a29913bce84 100644 --- a/mon-pix/tests/unit/services/file-saver-test.js +++ b/mon-pix/tests/unit/services/file-saver-test.js @@ -155,25 +155,24 @@ module('Unit | Service | file-saver', function (hooks) { }); module('when the response is an error', function () { - test('should throw an error with the response error detail as message', async function (assert) { + test('should throw', async function (assert) { // given jsonStub.resolves({ errors: [{ detail: 'the error message' }] }); const response = { ok: false, json: jsonStub }; fetchStub = sinon.stub().resolves(response); // when - try { - await fileSaver.save({ - url, - fileName: defaultFileName, - token, - fetcher: fetchStub, - downloadFileForIEBrowser: downloadFileForIEBrowserStub, - downloadFileForModernBrowsers: downloadFileForModernBrowsersStub, - }); - } catch (error) { - assert.strictEqual(error.message, 'the error message'); - } + const promise = fileSaver.save({ + url, + fileName: defaultFileName, + token, + fetcher: fetchStub, + downloadFileForIEBrowser: downloadFileForIEBrowserStub, + downloadFileForModernBrowsers: downloadFileForModernBrowsersStub, + }); + + // then + assert.rejects(promise); }); }); }); diff --git a/mon-pix/translations/en.json b/mon-pix/translations/en.json index d3e05b97de4..ae403d6d289 100644 --- a/mon-pix/translations/en.json +++ b/mon-pix/translations/en.json @@ -1267,7 +1267,7 @@ "label": "Download results" }, "errors": { - "expiration": "The session results download link has expired." + "invalid-token": "The session results download link is invalid." }, "title": "Download session results" }, diff --git a/mon-pix/translations/fr.json b/mon-pix/translations/fr.json index 546e3eb885a..9446a90a8fa 100644 --- a/mon-pix/translations/fr.json +++ b/mon-pix/translations/fr.json @@ -1267,7 +1267,7 @@ "label": "Télécharger les résultats" }, "errors": { - "expiration": "Le lien de téléchargement des résultats de session a expiré." + "invalid-token": "Le lien de téléchargement des résultats de session est invalide." }, "title": "Télécharger les résultats de session" }, From 6360d6162f2a2ae9fb84a70712053382f19777be Mon Sep 17 00:00:00 2001 From: AndreiaPena Date: Fri, 6 Dec 2024 12:59:04 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20mon-pix:=20improve=20e?= =?UTF-8?q?rror=20management=20and=20design=20on=20attestation=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user-certifications-detail-header.hbs | 1 - .../user-certifications-detail-header.js | 4 +-- .../_user-certifications-detail-header.scss | 34 +++++++------------ .../user-certifications-detail-header-test.js | 4 +-- 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/mon-pix/app/components/user-certifications-detail-header.hbs b/mon-pix/app/components/user-certifications-detail-header.hbs index 75995e5a659..5c5f706ee44 100644 --- a/mon-pix/app/components/user-certifications-detail-header.hbs +++ b/mon-pix/app/components/user-certifications-detail-header.hbs @@ -49,7 +49,6 @@

{{this.attestationDownloadErrorMessage}}

{{/if}} -

{{t "pages.certificate.verification-code.title"}} diff --git a/mon-pix/app/components/user-certifications-detail-header.js b/mon-pix/app/components/user-certifications-detail-header.js index bdcf359152f..a103ee2be13 100644 --- a/mon-pix/app/components/user-certifications-detail-header.js +++ b/mon-pix/app/components/user-certifications-detail-header.js @@ -34,8 +34,8 @@ export default class UserCertificationsDetailHeader extends Component { const token = this.session.data.authenticated.access_token; try { await this.fileSaver.save({ url, token }); - } catch (error) { - this.attestationDownloadErrorMessage = error.message; + } catch (_) { + this.attestationDownloadErrorMessage = this.intl.t('common.error'); } } } diff --git a/mon-pix/app/styles/components/_user-certifications-detail-header.scss b/mon-pix/app/styles/components/_user-certifications-detail-header.scss index 383c226255e..7918fcb013a 100644 --- a/mon-pix/app/styles/components/_user-certifications-detail-header.scss +++ b/mon-pix/app/styles/components/_user-certifications-detail-header.scss @@ -72,34 +72,31 @@ } .attestation-and-verification-code { - padding: 16px 20px; + max-width: 100%; + padding: var(--pix-spacing-4x) var(--pix-spacing-6x); background-color: var(--pix-neutral-20); border-radius: 8px; + @include device-is('desktop') { + max-width: calc(var(--pix-spacing-12x) * 6); + } + .attestation { - margin: auto; - font-size: 0.875rem; + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: var(--pix-spacing-6x); text-align: center; - button { - max-width: 250px; - padding: 14px 20px; - } - &__error-message { - max-width: 250px; - margin-top: 15px; + @extend %pix-body-s; + + margin-top: var(--pix-spacing-4x); color: var(--pix-error-500); } } - hr { - margin: 24px 0; - border: 1px solid var(--pix-neutral-20); - } - .verification-code { - max-width: 250px; margin: auto; color: var(--pix-neutral-900); letter-spacing: 0; @@ -157,10 +154,5 @@ @include device-is('desktop') { flex-grow: 0; margin-left: auto; - - .verification-code, - .attestation { - margin: 0; - } } } diff --git a/mon-pix/tests/integration/components/user-certifications-detail-header-test.js b/mon-pix/tests/integration/components/user-certifications-detail-header-test.js index 0719c05444b..511c72e7331 100644 --- a/mon-pix/tests/integration/components/user-certifications-detail-header-test.js +++ b/mon-pix/tests/integration/components/user-certifications-detail-header-test.js @@ -330,7 +330,7 @@ module('Integration | Component | user certifications detail header', function ( }); module('when there is an error during the download of the attestation', function () { - test('should show the error message', async function (assert) { + test('should show the common error message', async function (assert) { // given const fileSaverSaveStub = sinon.stub(); @@ -366,7 +366,7 @@ module('Integration | Component | user certifications detail header', function ( await click(screen.getByRole('button', { name: 'Télécharger mon attestation' })); // then - assert.ok(screen.getByText('an error message')); + assert.ok(screen.getByText('Une erreur est survenue. Veuillez recommencer ou contacter le support.')); }); }); });