diff --git a/api/lib/domain/services/mail-service.js b/api/lib/domain/services/mail-service.js index aef3aa96fee..14a799d85b6 100644 --- a/api/lib/domain/services/mail-service.js +++ b/api/lib/domain/services/mail-service.js @@ -12,89 +12,65 @@ import { config } from '../../config.js'; const { ENGLISH_SPOKEN, FRENCH_FRANCE, FRENCH_SPOKEN, DUTCH_SPOKEN, SPANISH_SPOKEN } = LOCALE; const EMAIL_ADDRESS_NO_RESPONSE = 'ne-pas-repondre@pix.fr'; -const PIX_ORGA_NAME_FR = 'Pix Orga - Ne pas répondre'; -const PIX_ORGA_NAME_EN = 'Pix Orga - Noreply'; -const PIX_CERTIF_NAME_FR = 'Pix Certif - Ne pas répondre'; -const PIX_CERTIF_NAME_EN = 'Pix Certif - Noreply'; -const HELPDESK_FRENCH_FRANCE = 'https://support.pix.fr'; -const HELPDESK_ENGLISH_SPOKEN = 'https://support.pix.org/en/support/home'; -const HELPDESK_DUTCH_SPOKEN = 'https://pix.org/nl-be/support'; -const HELPDESK_FRENCH_SPOKEN = 'https://support.pix.org'; -const PIX_HOME_NAME_INTERNATIONAL = `pix${config.domain.tldOrg}`; -const PIX_HOME_NAME_FRENCH_FRANCE = `pix${config.domain.tldFr}`; -const PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN = `${config.domain.pix + config.domain.tldOrg}/en-gb/`; -const PIX_HOME_URL_INTERNATIONAL_FRENCH_SPOKEN = `${config.domain.pix + config.domain.tldOrg}/fr/`; -const PIX_HOME_URL_INTERNATIONAL_DUTCH_SPOKEN = `${config.domain.pix + config.domain.tldOrg}/nl-be/`; -const PIX_HOME_URL_FRENCH_FRANCE = `${config.domain.pix + config.domain.tldFr}`; - const EMAIL_VERIFICATION_CODE_TAG = 'EMAIL_VERIFICATION_CODE'; const SCO_ACCOUNT_RECOVERY_TAG = 'SCO_ACCOUNT_RECOVERY'; -function sendAccountCreationEmail(email, locale, redirectionUrl) { - let pixName; - let accountCreationEmailSubject; - let variables; +// FRENCH_FRANCE +const PIX_HOME_NAME_FRENCH_FRANCE = `pix${config.domain.tldFr}`; +const PIX_HOME_URL_FRENCH_FRANCE = `${config.domain.pix + config.domain.tldFr}`; +const PIX_APP_URL_FRENCH_FRANCE = `${config.domain.pixApp + config.domain.tldFr}`; +const PIX_APP_CONNECTION_URL_FRENCH_FRANCE = `${PIX_APP_URL_FRENCH_FRANCE}/connexion`; +const PIX_ORGA_HOME_URL_FRENCH_FRANCE = `${config.domain.pixOrga + config.domain.tldFr}`; +const PIX_CERTIF_HOME_URL_FRENCH_FRANCE = `${config.domain.pixCertif + config.domain.tldFr}`; +const HELPDESK_FRENCH_FRANCE = 'https://support.pix.fr'; - if (locale === FRENCH_SPOKEN) { - variables = { - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_FRENCH_SPOKEN, - redirectionUrl: redirectionUrl || `${config.domain.pixApp + config.domain.tldOrg}/connexion/?lang=fr`, - helpdeskUrl: HELPDESK_FRENCH_SPOKEN, - displayNationalLogo: false, - ...frTranslations['pix-account-creation-email'].params, - }; - - pixName = frTranslations['email-sender-name']['pix-app']; - accountCreationEmailSubject = frTranslations['pix-account-creation-email'].subject; - } else if (locale === ENGLISH_SPOKEN) { - variables = { - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - redirectionUrl: redirectionUrl || `${config.domain.pixApp + config.domain.tldOrg}/connexion/?lang=en`, - helpdeskUrl: HELPDESK_ENGLISH_SPOKEN, - displayNationalLogo: false, - ...enTranslations['pix-account-creation-email'].params, - }; - - pixName = enTranslations['email-sender-name']['pix-app']; - accountCreationEmailSubject = enTranslations['pix-account-creation-email'].subject; - } else if (locale === DUTCH_SPOKEN) { - variables = { - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_DUTCH_SPOKEN, - redirectionUrl: redirectionUrl || `${config.domain.pixApp + config.domain.tldOrg}/connexion/?lang=nl`, - helpdeskUrl: HELPDESK_DUTCH_SPOKEN, - displayNationalLogo: false, - ...nlTranslations['pix-account-creation-email'].params, - }; - - pixName = nlTranslations['email-sender-name']['pix-app']; - accountCreationEmailSubject = nlTranslations['pix-account-creation-email'].subject; - } else if (locale === SPANISH_SPOKEN) { - variables = { - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - redirectionUrl: redirectionUrl || `${config.domain.pixApp + config.domain.tldOrg}/connexion/?lang=es`, - helpdeskUrl: HELPDESK_ENGLISH_SPOKEN, - displayNationalLogo: false, - ...esTranslations['pix-account-creation-email'].params, - }; - pixName = esTranslations['email-sender-name']['pix-app']; - accountCreationEmailSubject = esTranslations['pix-account-creation-email'].subject; - } else { - variables = { - homeName: PIX_HOME_NAME_FRENCH_FRANCE, - homeUrl: PIX_HOME_URL_FRENCH_FRANCE, - redirectionUrl: redirectionUrl || `${config.domain.pixApp + config.domain.tldFr}/connexion`, - helpdeskUrl: HELPDESK_FRENCH_FRANCE, - displayNationalLogo: true, - ...frTranslations['pix-account-creation-email'].params, - }; - - pixName = frTranslations['email-sender-name']['pix-app']; - accountCreationEmailSubject = frTranslations['pix-account-creation-email'].subject; - } +// INTERNATIONAL +const PIX_HOME_NAME_INTERNATIONAL = `pix${config.domain.tldOrg}`; +const PIX_HOME_URL_INTERNATIONAL = { + en: `${config.domain.pix + config.domain.tldOrg}/en-gb/`, + fr: `${config.domain.pix + config.domain.tldOrg}/fr/`, + nl: `${config.domain.pix + config.domain.tldOrg}/nl-be/`, +}; +const PIX_ORGA_HOME_URL_INTERNATIONAL = `${config.domain.pixOrga + config.domain.tldOrg}`; +const PIX_CERTIF_HOME_URL_INTERNATIONAL = `${config.domain.pixCertif + config.domain.tldOrg}`; +const PIX_APP_URL_INTERNATIONAL = `${config.domain.pixApp + config.domain.tldOrg}`; +const PIX_APP_CONNECTION_URL_INTERNATIONAL = { + en: `${PIX_APP_URL_INTERNATIONAL}/connexion/?lang=en`, + es: `${PIX_APP_URL_INTERNATIONAL}/connexion/?lang=es`, + fr: `${PIX_APP_URL_INTERNATIONAL}/connexion/?lang=fr`, + nl: `${PIX_APP_URL_INTERNATIONAL}/connexion/?lang=nl`, +}; +const PIX_HELPDESK_URL_INTERNATIONAL = { + en: 'https://support.pix.org/en/support/home', + fr: 'https://support.pix.org', + nl: 'https://pix.org/nl-be/support', +}; +const translations = { + en: enTranslations, + es: esTranslations, + fr: frTranslations, + nl: nlTranslations, +}; + +/** + * @param email + * @param locale + * @param redirectionUrl + * @returns {Promise} + */ +function sendAccountCreationEmail(email, locale = FRENCH_FRANCE, redirectionUrl) { + const mailerConfig = _getMailerConfig(locale); + + const templateVariables = { + homeName: mailerConfig.homeName, + homeUrl: mailerConfig.homeUrl, + redirectionUrl: redirectionUrl || mailerConfig.pixAppConnectionUrl, + helpdeskUrl: mailerConfig.helpdeskUrl, + displayNationalLogo: mailerConfig.displayNationalLogo, + ...mailerConfig.translation['pix-account-creation-email'].params, + }; + const pixName = mailerConfig.translation['email-sender-name']['pix-app']; + const accountCreationEmailSubject = mailerConfig.translation['pix-account-creation-email'].subject; return mailer.sendEmail({ from: EMAIL_ADDRESS_NO_RESPONSE, @@ -102,7 +78,7 @@ function sendAccountCreationEmail(email, locale, redirectionUrl) { to: email, subject: accountCreationEmailSubject, template: mailer.accountCreationTemplateId, - variables, + variables: templateVariables, }); } @@ -124,7 +100,7 @@ function sendCertificationResultEmail({ const formattedSessionDate = dayjs(sessionDate).locale('fr').format('DD/MM/YYYY'); - const templateParams = { + const templateVariables = { certificationCenterName, sessionId, sessionDate: formattedSessionDate, @@ -133,14 +109,14 @@ function sendCertificationResultEmail({ homeName: PIX_HOME_NAME_FRENCH_FRANCE, homeUrl: PIX_HOME_URL_FRENCH_FRANCE, homeNameInternational: PIX_HOME_NAME_INTERNATIONAL, - homeUrlInternational: PIX_HOME_URL_INTERNATIONAL_FRENCH_SPOKEN, + homeUrlInternational: PIX_HOME_URL_INTERNATIONAL.fr, title: translate({ phrase: 'certification-result-email.title', locale: 'fr' }, { sessionId }), link: `${link}?lang=fr`, }, en: { ...enTranslations['certification-result-email'].params, homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, + homeUrl: PIX_HOME_URL_INTERNATIONAL.en, title: translate({ phrase: 'certification-result-email.title', locale: 'en' }, { sessionId }), link: `${link}?lang=en`, }, @@ -151,76 +127,32 @@ function sendCertificationResultEmail({ fromName: `${frTranslations['email-sender-name']['pix-app']} / ${enTranslations['email-sender-name']['pix-app']}`, to: email, template: mailer.certificationResultTemplateId, - variables: templateParams, + variables: templateVariables, }); } -function sendResetPasswordDemandEmail({ email, locale, temporaryKey }) { - const localeParam = locale ? locale : FRENCH_FRANCE; +/** + * @param email + * @param locale + * @param temporaryKey + * @returns {Promise} + */ +function sendResetPasswordDemandEmail({ email, locale = FRENCH_FRANCE, temporaryKey }) { + const mailerConfig = _getMailerConfig(locale); - let pixName = frTranslations['email-sender-name']['pix-app']; - let resetPasswordEmailSubject = frTranslations['reset-password-demand-email'].subject; - - let templateParams = { - locale: localeParam, - ...frTranslations['reset-password-demand-email'].params, - homeName: PIX_HOME_NAME_FRENCH_FRANCE, - homeUrl: PIX_HOME_URL_FRENCH_FRANCE, - resetUrl: `${config.domain.pixApp + config.domain.tldFr}/changer-mot-de-passe/${temporaryKey}`, - helpdeskURL: HELPDESK_FRENCH_FRANCE, + const templateVariables = { + locale, + ...mailerConfig.translation['reset-password-demand-email'].params, + homeName: mailerConfig.homeName, + homeUrl: mailerConfig.homeUrl, + resetUrl: + locale === FRENCH_FRANCE + ? `${PIX_APP_URL_FRENCH_FRANCE}/changer-mot-de-passe/${temporaryKey}` + : `${PIX_APP_URL_INTERNATIONAL}/changer-mot-de-passe/${temporaryKey}/?lang=${locale}`, + helpdeskURL: mailerConfig.helpdeskUrl, }; - - if (localeParam === FRENCH_SPOKEN) { - templateParams = { - ...templateParams, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: `${config.domain.pix + config.domain.tldOrg}/fr/`, - resetUrl: `${config.domain.pixApp + config.domain.tldOrg}/changer-mot-de-passe/${temporaryKey}/?lang=fr`, - helpdeskURL: HELPDESK_FRENCH_SPOKEN, - }; - } - - if (localeParam === ENGLISH_SPOKEN) { - templateParams = { - locale: localeParam, - ...enTranslations['reset-password-demand-email'].params, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - resetUrl: `${config.domain.pixApp + config.domain.tldOrg}/changer-mot-de-passe/${temporaryKey}/?lang=en`, - helpdeskURL: HELPDESK_ENGLISH_SPOKEN, - }; - - pixName = enTranslations['email-sender-name']['pix-app']; - resetPasswordEmailSubject = enTranslations['reset-password-demand-email'].subject; - } - - if (localeParam === DUTCH_SPOKEN) { - templateParams = { - locale: localeParam, - ...nlTranslations['reset-password-demand-email'].params, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_DUTCH_SPOKEN, - resetUrl: `${config.domain.pixApp + config.domain.tldOrg}/changer-mot-de-passe/${temporaryKey}/?lang=nl`, - helpdeskURL: HELPDESK_DUTCH_SPOKEN, - }; - - pixName = nlTranslations['email-sender-name']['pix-app']; - resetPasswordEmailSubject = nlTranslations['reset-password-demand-email'].subject; - } - - if (localeParam === SPANISH_SPOKEN) { - templateParams = { - locale: localeParam, - ...esTranslations['reset-password-demand-email'].params, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - resetUrl: `${config.domain.pixApp + config.domain.tldOrg}/changer-mot-de-passe/${temporaryKey}/?lang=es`, - helpdeskURL: HELPDESK_ENGLISH_SPOKEN, - }; - - pixName = esTranslations['email-sender-name']['pix-app']; - resetPasswordEmailSubject = esTranslations['reset-password-demand-email'].subject; - } + const pixName = mailerConfig.translation['email-sender-name']['pix-app']; + const resetPasswordEmailSubject = mailerConfig.translation['reset-password-demand-email'].subject; return mailer.sendEmail({ from: EMAIL_ADDRESS_NO_RESPONSE, @@ -228,68 +160,67 @@ function sendResetPasswordDemandEmail({ email, locale, temporaryKey }) { to: email, subject: resetPasswordEmailSubject, template: mailer.passwordResetTemplateId, - variables: templateParams, + variables: templateVariables, }); } -function sendOrganizationInvitationEmail({ email, organizationName, organizationInvitationId, code, locale, tags }) { - locale = locale ? locale : FRENCH_FRANCE; - let pixOrgaName = PIX_ORGA_NAME_FR; - let sendOrganizationInvitationEmailSubject = frTranslations['organization-invitation-email'].subject; +/** + * @param email + * @param organizationName + * @param organizationInvitationId + * @param code + * @param locale + * @param tags + * @returns {Promise} + */ +function sendOrganizationInvitationEmail({ + email, + organizationName, + organizationInvitationId, + code, + locale = FRENCH_FRANCE, + tags, +}) { + const mailerConfig = _getMailerConfig(locale); + + const pixOrgaName = mailerConfig.translation['email-sender-name']['pix-orga']; + const sendOrganizationInvitationEmailSubject = mailerConfig.translation['organization-invitation-email'].subject; - let templateParams = { + const templateVariables = { organizationName, - pixHomeName: PIX_HOME_NAME_FRENCH_FRANCE, - pixHomeUrl: PIX_HOME_URL_FRENCH_FRANCE, - pixOrgaHomeUrl: `${config.domain.pixOrga + config.domain.tldFr}`, - redirectionUrl: `${ - config.domain.pixOrga + config.domain.tldFr - }/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, - supportUrl: HELPDESK_FRENCH_FRANCE, - ...frTranslations['organization-invitation-email'].params, + pixHomeName: mailerConfig.homeName, + pixHomeUrl: mailerConfig.homeUrl, + pixOrgaHomeUrl: _formatUrlWithLocale(mailerConfig.pixOrgaHomeUrl, locale), + redirectionUrl: _formatUrlWithLocale( + `${mailerConfig.pixOrgaHomeUrl}/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, + locale, + ), + supportUrl: mailerConfig.helpdeskUrl, + ...mailerConfig.translation['organization-invitation-email'].params, }; - if (locale === FRENCH_SPOKEN) { - templateParams = { - organizationName, - pixHomeName: PIX_HOME_NAME_INTERNATIONAL, - pixHomeUrl: `${config.domain.pix + config.domain.tldOrg}`, - pixOrgaHomeUrl: `${config.domain.pixOrga + config.domain.tldOrg}`, - redirectionUrl: `${ - config.domain.pixOrga + config.domain.tldOrg - }/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, - supportUrl: HELPDESK_FRENCH_SPOKEN, - ...frTranslations['organization-invitation-email'].params, - }; - } - - if (locale === ENGLISH_SPOKEN) { - templateParams = { - organizationName, - pixHomeName: PIX_HOME_NAME_INTERNATIONAL, - pixHomeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - pixOrgaHomeUrl: `${config.domain.pixOrga + config.domain.tldOrg}?lang=en`, - redirectionUrl: `${ - config.domain.pixOrga + config.domain.tldOrg - }/rejoindre?invitationId=${organizationInvitationId}&code=${code}&lang=en`, - supportUrl: HELPDESK_ENGLISH_SPOKEN, - ...enTranslations['organization-invitation-email'].params, - }; - pixOrgaName = PIX_ORGA_NAME_EN; - sendOrganizationInvitationEmailSubject = enTranslations['organization-invitation-email'].subject; - } - return mailer.sendEmail({ from: EMAIL_ADDRESS_NO_RESPONSE, fromName: pixOrgaName, to: email, subject: sendOrganizationInvitationEmailSubject, template: mailer.organizationInvitationTemplateId, - variables: templateParams, + variables: templateVariables, tags: tags || null, }); } +/** + * @param email + * @param organizationName + * @param firstName + * @param lastName + * @param organizationInvitationId + * @param code + * @param locale + * @param tags + * @returns {Promise} + */ function sendScoOrganizationInvitationEmail({ email, organizationName, @@ -297,206 +228,134 @@ function sendScoOrganizationInvitationEmail({ lastName, organizationInvitationId, code, - locale, + locale = FRENCH_FRANCE, tags, }) { - locale = locale ? locale : FRENCH_FRANCE; + const mailerConfig = _getMailerConfig(locale); - let variables = { + const templateVariables = { organizationName, firstName, lastName, - pixHomeName: PIX_HOME_NAME_FRENCH_FRANCE, - pixHomeUrl: PIX_HOME_URL_FRENCH_FRANCE, - pixOrgaHomeUrl: `${config.domain.pixOrga + config.domain.tldFr}`, - redirectionUrl: `${ - config.domain.pixOrga + config.domain.tldFr - }/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, + pixHomeName: mailerConfig.homeName, + pixHomeUrl: mailerConfig.homeUrl, + pixOrgaHomeUrl: mailerConfig.pixOrgaHomeUrl, + redirectionUrl: `${mailerConfig.pixOrgaHomeUrl}/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, locale, }; - if (locale === FRENCH_SPOKEN) { - variables = { - organizationName, - firstName, - lastName, - pixHomeName: PIX_HOME_NAME_INTERNATIONAL, - pixHomeUrl: `${config.domain.pix + config.domain.tldOrg}`, - pixOrgaHomeUrl: `${config.domain.pixOrga + config.domain.tldOrg}`, - redirectionUrl: `${ - config.domain.pixOrga + config.domain.tldOrg - }/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, - locale, - }; - } - return mailer.sendEmail({ from: EMAIL_ADDRESS_NO_RESPONSE, - fromName: PIX_ORGA_NAME_FR, + fromName: mailerConfig.translation['email-sender-name']['pix-orga'], to: email, subject: 'Accès à votre espace Pix Orga', template: mailer.organizationInvitationScoTemplateId, - variables, + variables: templateVariables, tags: tags || null, }); } +/** + * @param email + * @param certificationCenterName + * @param certificationCenterInvitationId + * @param code + * @param locale + * @returns {Promise} + */ function sendCertificationCenterInvitationEmail({ email, certificationCenterName, certificationCenterInvitationId, code, - locale, + locale = FRENCH_FRANCE, }) { - let templateParams, fromName, subject; - const frenchFranceTemplateParams = { - certificationCenterName, - pixHomeName: PIX_HOME_NAME_FRENCH_FRANCE, - pixHomeUrl: PIX_HOME_URL_FRENCH_FRANCE, - pixCertifHomeUrl: `${config.domain.pixCertif + config.domain.tldFr}`, - redirectionUrl: `${ - config.domain.pixCertif + config.domain.tldFr - }/rejoindre?invitationId=${certificationCenterInvitationId}&code=${code}`, - supportUrl: HELPDESK_FRENCH_FRANCE, - ...frTranslations['certification-center-invitation-email'].params, - }; - const frenchSpokenTemplateParams = { - certificationCenterName, - pixHomeName: PIX_HOME_NAME_INTERNATIONAL, - pixHomeUrl: `${config.domain.pix + config.domain.tldOrg}`, - pixCertifHomeUrl: `${config.domain.pixCertif + config.domain.tldOrg}`, - redirectionUrl: `${ - config.domain.pixCertif + config.domain.tldOrg - }/rejoindre?invitationId=${certificationCenterInvitationId}&code=${code}`, - supportUrl: HELPDESK_FRENCH_SPOKEN, - ...frTranslations['certification-center-invitation-email'].params, - }; - const englishSpokenTemplateParams = { + const mailerConfig = _getMailerConfig(locale); + + const subject = mailerConfig.translation['certification-center-invitation-email'].subject; + const fromName = mailerConfig.translation['email-sender-name']['pix-certif']; + const templateVariables = { certificationCenterName, - pixHomeName: PIX_HOME_NAME_INTERNATIONAL, - pixHomeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - pixCertifHomeUrl: `${config.domain.pixCertif + config.domain.tldOrg}?lang=en`, - redirectionUrl: `${ - config.domain.pixCertif + config.domain.tldOrg - }/rejoindre?invitationId=${certificationCenterInvitationId}&code=${code}&lang=en`, - supportUrl: HELPDESK_ENGLISH_SPOKEN, - ...enTranslations['certification-center-invitation-email'].params, + pixHomeName: mailerConfig.homeName, + pixHomeUrl: mailerConfig.homeUrl, + pixCertifHomeUrl: _formatUrlWithLocale(mailerConfig.pixCertifHomeUrl, locale), + redirectionUrl: _formatUrlWithLocale( + `${mailerConfig.pixCertifHomeUrl}/rejoindre?invitationId=${certificationCenterInvitationId}&code=${code}`, + locale, + ), + supportUrl: mailerConfig.helpdeskUrl, + ...mailerConfig.translation['certification-center-invitation-email'].params, }; - switch (locale) { - case FRENCH_SPOKEN: - templateParams = frenchSpokenTemplateParams; - subject = frTranslations['certification-center-invitation-email'].subject; - fromName = PIX_CERTIF_NAME_FR; - break; - - case ENGLISH_SPOKEN: - templateParams = englishSpokenTemplateParams; - fromName = PIX_CERTIF_NAME_EN; - subject = enTranslations['certification-center-invitation-email'].subject; - break; - - default: - templateParams = frenchFranceTemplateParams; - subject = frTranslations['certification-center-invitation-email'].subject; - fromName = PIX_CERTIF_NAME_FR; - break; - } - return mailer.sendEmail({ subject, from: EMAIL_ADDRESS_NO_RESPONSE, fromName, to: email, template: mailer.certificationCenterInvitationTemplateId, - variables: templateParams, + variables: templateVariables, }); } +/** + * @param email + * @param firstName + * @param temporaryKey + * @returns {Promise} + */ function sendAccountRecoveryEmail({ email, firstName, temporaryKey }) { - const pixName = frTranslations['email-sender-name']['pix-app']; - const redirectionUrl = `${config.domain.pixApp + config.domain.tldFr}/recuperer-mon-compte/${temporaryKey}`; - const variables = { + const mailerConfig = _getMailerConfig(FRENCH_FRANCE); + const fromName = mailerConfig.translation['email-sender-name']['pix-app']; + const redirectionUrl = `${PIX_APP_URL_FRENCH_FRANCE}/recuperer-mon-compte/${temporaryKey}`; + const templateVariables = { firstName, redirectionUrl, - homeName: PIX_HOME_NAME_FRENCH_FRANCE, - ...frTranslations['account-recovery-email'].params, + homeName: mailerConfig.homeName, + ...mailerConfig.translation['account-recovery-email'].params, }; return mailer.sendEmail({ from: EMAIL_ADDRESS_NO_RESPONSE, - fromName: pixName, + fromName, to: email, subject: 'Récupération de votre compte Pix', template: mailer.accountRecoveryTemplateId, tags: [SCO_ACCOUNT_RECOVERY_TAG], - variables, + variables: templateVariables, }); } -function sendVerificationCodeEmail({ code, email, locale, translate }) { +/** + * @param code + * @param email + * @param locale + * @param translate + * @returns {Promise} + */ +function sendVerificationCodeEmail({ code, email, locale = FRENCH_FRANCE, translate }) { + const mailerConfig = _getMailerConfig(locale); + const options = { from: EMAIL_ADDRESS_NO_RESPONSE, - fromName: frTranslations['email-sender-name']['pix-app'], + fromName: mailerConfig.translation['email-sender-name']['pix-app'], to: email, template: mailer.emailVerificationCodeTemplateId, tags: [EMAIL_VERIFICATION_CODE_TAG], - }; - - if (locale === FRENCH_SPOKEN) { - options.subject = translate({ phrase: 'verification-code-email.subject', locale: 'fr' }, { code }); - - options.variables = { + subject: translate( + { + phrase: 'verification-code-email.subject', + locale: locale === FRENCH_FRANCE ? 'fr' : locale, + }, + { code }, + ), + variables: { code, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: `${config.domain.pix + config.domain.tldOrg}/fr/`, - displayNationalLogo: false, - ...frTranslations['verification-code-email'].body, - }; - } else if (locale === FRENCH_FRANCE) { - options.subject = translate({ phrase: 'verification-code-email.subject', locale: 'fr' }, { code }); - - options.variables = { - code, - homeName: PIX_HOME_NAME_FRENCH_FRANCE, - homeUrl: PIX_HOME_URL_FRENCH_FRANCE, - displayNationalLogo: true, - ...frTranslations['verification-code-email'].body, - }; - } else if (locale === ENGLISH_SPOKEN) { - options.subject = translate({ phrase: 'verification-code-email.subject', locale: 'en' }, { code }); - options.fromName = enTranslations['email-sender-name']['pix-app']; - - options.variables = { - code, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - displayNationalLogo: false, - ...enTranslations['verification-code-email'].body, - }; - } else if (locale === DUTCH_SPOKEN) { - options.subject = translate({ phrase: 'verification-code-email.subject', locale: 'nl' }, { code }); - options.fromName = nlTranslations['email-sender-name']['pix-app']; - - options.variables = { - code, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_DUTCH_SPOKEN, - displayNationalLogo: false, - ...nlTranslations['verification-code-email'].body, - }; - } else if (locale === SPANISH_SPOKEN) { - options.subject = translate({ phrase: 'verification-code-email.subject', locale: 'es' }, { code }); - options.fromName = esTranslations['email-sender-name']['pix-app']; - - options.variables = { - code, - homeName: PIX_HOME_NAME_INTERNATIONAL, - homeUrl: PIX_HOME_URL_INTERNATIONAL_ENGLISH_SPOKEN, - displayNationalLogo: false, - ...esTranslations['verification-code-email'].body, - }; - } + homeName: mailerConfig.homeName, + homeUrl: mailerConfig.homeUrl, + displayNationalLogo: mailerConfig.displayNationalLogo, + ...mailerConfig.translation['verification-code-email'].body, + }, + }; return mailer.sendEmail(options); } @@ -539,6 +398,69 @@ function sendNotificationToOrganizationMembersForTargetProfileDetached({ email, return mailer.sendEmail(options); } +/** + * @typedef {Object} mailerConfig + * @property {string} homeName + * @property {string} homeUrl + * @property {string} pixOrgaHomeUrl + * @property {string} pixCertifHomeUrl + * @property {string} pixAppConnectionUrl + * @property {string} helpdeskUrl + * @property {boolean} displayNationalLogo + * @property {JSON} translation + */ + +/** + * @param locale + * @returns {mailerConfig} + * @private + */ +function _getMailerConfig(locale) { + switch (locale) { + case FRENCH_SPOKEN: + case SPANISH_SPOKEN: + case ENGLISH_SPOKEN: + case DUTCH_SPOKEN: + return { + homeName: PIX_HOME_NAME_INTERNATIONAL, + homeUrl: PIX_HOME_URL_INTERNATIONAL[locale] ?? PIX_HOME_URL_INTERNATIONAL.en, + pixOrgaHomeUrl: PIX_ORGA_HOME_URL_INTERNATIONAL, + pixCertifHomeUrl: PIX_CERTIF_HOME_URL_INTERNATIONAL, + pixAppConnectionUrl: PIX_APP_CONNECTION_URL_INTERNATIONAL[locale] ?? PIX_APP_CONNECTION_URL_INTERNATIONAL.en, + helpdeskUrl: PIX_HELPDESK_URL_INTERNATIONAL[locale] ?? PIX_HELPDESK_URL_INTERNATIONAL.en, + displayNationalLogo: false, + translation: translations[locale], + }; + default: + return { + homeName: PIX_HOME_NAME_FRENCH_FRANCE, + homeUrl: PIX_HOME_URL_FRENCH_FRANCE, + pixOrgaHomeUrl: PIX_ORGA_HOME_URL_FRENCH_FRANCE, + pixCertifHomeUrl: PIX_CERTIF_HOME_URL_FRENCH_FRANCE, + pixAppConnectionUrl: PIX_APP_CONNECTION_URL_FRENCH_FRANCE, + helpdeskUrl: HELPDESK_FRENCH_FRANCE, + displayNationalLogo: true, + translation: translations.fr, + }; + } +} + +/** + * @param url + * @param locale + * @returns {string} + * @private + */ +function _formatUrlWithLocale(url, locale) { + const formattedUrl = new URL(url); + + if (locale !== FRENCH_FRANCE) { + formattedUrl.searchParams.set('lang', locale); + } + + return formattedUrl.toString(); +} + const mailService = { sendAccountCreationEmail, sendAccountRecoveryEmail, diff --git a/api/src/shared/config.js b/api/src/shared/config.js index 09ebb8dc1d4..d8c51a73b5b 100644 --- a/api/src/shared/config.js +++ b/api/src/shared/config.js @@ -375,6 +375,8 @@ const configuration = (function () { config.mailing.brevo.templates.organizationInvitationTemplateId = 'test-organization-invitation-demand-template-id'; config.mailing.brevo.templates.organizationInvitationScoTemplateId = 'test-organization-invitation-sco-demand-template-id'; + config.mailing.brevo.templates.certificationCenterInvitationTemplateId = + 'test-certification-center-invitation-template-id'; config.mailing.brevo.templates.certificationResultTemplateId = 'test-certification-result-template-id'; config.mailing.brevo.templates.passwordResetTemplateId = 'test-password-reset-template-id'; config.mailing.brevo.templates.emailChangeTemplateId = 'test-email-change-template-id'; diff --git a/api/tests/unit/domain/services/mail-service_test.js b/api/tests/unit/domain/services/mail-service_test.js index 424f7cecf52..5fcc7234a03 100644 --- a/api/tests/unit/domain/services/mail-service_test.js +++ b/api/tests/unit/domain/services/mail-service_test.js @@ -31,13 +31,14 @@ describe('Unit | Service | MailService', function () { it('calls sendEmail with from, to, subject, template', async function () { // given const locale = undefined; + const template = 'test-account-creation-template-id'; // given const expectedOptions = { from: senderEmailAddress, to: userEmailAddress, subject: 'Votre compte Pix a bien été créé', - template: 'test-account-creation-template-id', + template, }; // when @@ -67,7 +68,7 @@ describe('Unit | Service | MailService', function () { context('according to locale', function () { context('call sendEmail with localized variable options', function () { - it(`calls sendEmail with from, to, template and locale ${FRENCH_SPOKEN} or undefined`, async function () { + it(`calls sendEmail with from, to, and locale ${FRENCH_SPOKEN} or undefined`, async function () { // given const locale = FRENCH_SPOKEN; @@ -416,9 +417,10 @@ describe('Unit | Service | MailService', function () { const organizationInvitationId = 1; const code = 'ABCDEFGH01'; - it('should call sendEmail with from, to, organizationName', async function () { + it('should call sendEmail with from, to, template, organizationName', async function () { // given const locale = undefined; + const template = 'test-organization-invitation-demand-template-id'; // when await mailService.sendOrganizationInvitationEmail({ @@ -433,15 +435,12 @@ describe('Unit | Service | MailService', function () { const expectedOptions = { from: senderEmailAddress, to: userEmailAddress, - variables: { - organizationName, - }, + template, }; const options = mailer.sendEmail.firstCall.args[0]; - expect(options.from).to.equal(expectedOptions.from); - expect(options.to).to.equal(expectedOptions.to); - expect(options.variables.organizationName).to.equal(expectedOptions.variables.organizationName); + expect(options).to.includes(expectedOptions); + expect(options.variables.organizationName).to.equal(organizationName); }); context('according to tags', function () { @@ -504,9 +503,9 @@ describe('Unit | Service | MailService', function () { expect(options.subject).to.equal(mainTranslationsMapping.fr['organization-invitation-email'].subject); expect(options.variables).to.include({ pixHomeName: 'pix.org', - pixHomeUrl: 'https://pix.org', - pixOrgaHomeUrl: 'https://orga.pix.org', - redirectionUrl: `https://orga.pix.org/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, + pixHomeUrl: 'https://pix.org/fr/', + pixOrgaHomeUrl: 'https://orga.pix.org/?lang=fr', + redirectionUrl: `https://orga.pix.org/rejoindre?invitationId=${organizationInvitationId}&code=${code}&lang=fr`, supportUrl: 'https://support.pix.org', ...mainTranslationsMapping.fr['organization-invitation-email'].params, }); @@ -528,7 +527,7 @@ describe('Unit | Service | MailService', function () { expect(options.variables).to.include({ pixHomeName: 'pix.fr', pixHomeUrl: 'https://pix.fr', - pixOrgaHomeUrl: 'https://orga.pix.fr', + pixOrgaHomeUrl: 'https://orga.pix.fr/', redirectionUrl: `https://orga.pix.fr/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, supportUrl: 'https://support.pix.fr', ...mainTranslationsMapping.fr['organization-invitation-email'].params, @@ -551,7 +550,7 @@ describe('Unit | Service | MailService', function () { expect(options.variables).to.include({ pixHomeName: 'pix.fr', pixHomeUrl: 'https://pix.fr', - pixOrgaHomeUrl: 'https://orga.pix.fr', + pixOrgaHomeUrl: 'https://orga.pix.fr/', redirectionUrl: `https://orga.pix.fr/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, supportUrl: 'https://support.pix.fr', ...mainTranslationsMapping.fr['organization-invitation-email'].params, @@ -574,7 +573,7 @@ describe('Unit | Service | MailService', function () { expect(options.variables).to.include({ pixHomeName: 'pix.org', pixHomeUrl: 'https://pix.org/en-gb/', - pixOrgaHomeUrl: 'https://orga.pix.org?lang=en', + pixOrgaHomeUrl: 'https://orga.pix.org/?lang=en', redirectionUrl: `https://orga.pix.org/rejoindre?invitationId=${organizationInvitationId}&code=${code}&lang=en`, supportUrl: 'https://support.pix.org/en/support/home', ...mainTranslationsMapping.en['organization-invitation-email'].params, @@ -585,34 +584,26 @@ describe('Unit | Service | MailService', function () { }); describe('#sendScoOrganizationInvitationEmail', function () { - const fromName = 'Pix Orga - Ne pas répondre'; - - const subject = 'Accès à votre espace Pix Orga'; - const template = 'test-organization-invitation-sco-demand-template-id'; - - const organizationName = 'Organization SCO'; - const firstName = 'FirstName'; - const lastName = 'LastName'; - const pixHomeName = 'pix.fr'; - const pixHomeUrl = 'https://pix.fr'; - const pixOrgaUrl = 'https://orga.pix.fr'; - const organizationInvitationId = 1; - const code = 'ABCDEFGH01'; - - it('should call mail provider with pix-orga url, organization-invitation id, code and null tags', async function () { + it('should call mail provider with pix-orga url, organization-invitation id, code, template and null tags', async function () { // given + const organizationName = 'Organization SCO'; + const firstName = 'FirstName'; + const lastName = 'LastName'; + const organizationInvitationId = 1; + const code = 'ABCDEFGH01'; + const pixOrgaUrl = 'https://orga.pix.fr'; const expectedOptions = { from: senderEmailAddress, - fromName, + fromName: 'Pix Orga - Ne pas répondre', to: userEmailAddress, - subject, - template, + subject: 'Accès à votre espace Pix Orga', + template: 'test-organization-invitation-sco-demand-template-id', variables: { organizationName, firstName, lastName, - pixHomeName, - pixHomeUrl, + pixHomeName: 'pix.fr', + pixHomeUrl: 'https://pix.fr', pixOrgaHomeUrl: pixOrgaUrl, locale: FRENCH_FRANCE, redirectionUrl: `${pixOrgaUrl}/rejoindre?invitationId=${organizationInvitationId}&code=${code}`, @@ -655,11 +646,12 @@ describe('Unit | Service | MailService', function () { expect(sendEmailParameters.from).to.equal(senderEmailAddress); expect(sendEmailParameters.fromName).to.equal('Pix Certif - Ne pas répondre'); expect(sendEmailParameters.to).to.equal('invited@example.net'); + expect(sendEmailParameters.template).to.equal('test-certification-center-invitation-template-id'); expect(sendEmailParameters.variables).to.include({ certificationCenterName: 'Centre Pixou', pixHomeName: 'pix.fr', pixHomeUrl: 'https://pix.fr', - pixCertifHomeUrl: 'https://certif.pix.fr', + pixCertifHomeUrl: 'https://certif.pix.fr/', redirectionUrl: `https://certif.pix.fr/rejoindre?invitationId=7&code=ABCDEFGH01`, supportUrl: 'https://support.pix.fr', ...mainTranslationsMapping.fr['certification-center-invitation-email'].params, @@ -689,9 +681,9 @@ describe('Unit | Service | MailService', function () { expect(sendEmailParameters.variables).to.include({ certificationCenterName: 'Centre Pixi', pixHomeName: 'pix.org', - pixHomeUrl: 'https://pix.org', - pixCertifHomeUrl: 'https://certif.pix.org', - redirectionUrl: `https://certif.pix.org/rejoindre?invitationId=7&code=AAABBBCCC7`, + pixHomeUrl: 'https://pix.org/fr/', + pixCertifHomeUrl: 'https://certif.pix.org/?lang=fr', + redirectionUrl: `https://certif.pix.org/rejoindre?invitationId=7&code=AAABBBCCC7&lang=fr`, supportUrl: 'https://support.pix.org', ...mainTranslationsMapping.fr['certification-center-invitation-email'].params, }); @@ -722,7 +714,7 @@ describe('Unit | Service | MailService', function () { certificationCenterName: 'Centre Pixi', pixHomeName: 'pix.org', pixHomeUrl: 'https://pix.org/en-gb/', - pixCertifHomeUrl: 'https://certif.pix.org?lang=en', + pixCertifHomeUrl: 'https://certif.pix.org/?lang=en', redirectionUrl: `https://certif.pix.org/rejoindre?invitationId=777&code=LLLJJJVVV1&lang=en`, supportUrl: 'https://support.pix.org/en/support/home', ...mainTranslationsMapping.en['certification-center-invitation-email'].params, @@ -786,6 +778,7 @@ describe('Unit | Service | MailService', function () { const options = mailer.sendEmail.firstCall.args[0]; expect(options.subject).to.equal(translate('verification-code-email.subject', { code })); expect(options.fromName).to.equal('PIX - Ne pas répondre'); + expect(options.template).to.equal('test-email-verification-code-template-id'); expect(options.variables).to.include({ homeName: 'pix.org', homeUrl: 'https://pix.org/fr/', @@ -813,6 +806,7 @@ describe('Unit | Service | MailService', function () { const options = mailer.sendEmail.firstCall.args[0]; expect(options.subject).to.equal(translate('verification-code-email.subject', { code })); expect(options.fromName).to.equal('PIX - Ne pas répondre'); + expect(options.template).to.equal('test-email-verification-code-template-id'); expect(options.variables).to.include({ homeName: 'pix.fr', homeUrl: 'https://pix.fr', @@ -842,6 +836,7 @@ describe('Unit | Service | MailService', function () { translate({ phrase: 'verification-code-email.subject', locale: 'en' }, { code }), ); expect(options.fromName).to.equal('PIX - Noreply'); + expect(options.template).to.equal('test-email-verification-code-template-id'); expect(options.variables).to.include({ homeName: 'pix.org', homeUrl: 'https://pix.org/en-gb/', @@ -871,6 +866,7 @@ describe('Unit | Service | MailService', function () { translate({ phrase: 'verification-code-email.subject', locale: 'nl' }, { code }), ); expect(options.fromName).to.equal('PIX - Niet beantwoorden'); + expect(options.template).to.equal('test-email-verification-code-template-id'); expect(options.variables).to.include({ homeName: 'pix.org', homeUrl: 'https://pix.org/nl-be/', @@ -900,6 +896,7 @@ describe('Unit | Service | MailService', function () { translate({ phrase: 'verification-code-email.subject', locale: 'es' }, { code }), ); expect(options.fromName).to.equal('PIX - No contestar'); + expect(options.template).to.equal('test-email-verification-code-template-id'); expect(options.variables).to.include({ homeName: 'pix.org', homeUrl: 'https://pix.org/en-gb/', diff --git a/api/translations/en.json b/api/translations/en.json index 3a5d8ce659a..b0f9212b057 100644 --- a/api/translations/en.json +++ b/api/translations/en.json @@ -279,7 +279,9 @@ "template-name": "import-template" }, "email-sender-name": { - "pix-app": "PIX - Noreply" + "pix-app": "PIX - Noreply", + "pix-certif": "Pix Certif - Noreply", + "pix-orga": "Pix Orga - Noreply" }, "entity-validation-errors": { "ACCEPT_CGU": "Please agree to the terms and conditions of use.", diff --git a/api/translations/es.json b/api/translations/es.json index d1493f2d1da..d7e8da97a73 100644 --- a/api/translations/es.json +++ b/api/translations/es.json @@ -293,7 +293,9 @@ "template-name": "modelo de importación" }, "email-sender-name": { - "pix-app": "PIX - No contestar" + "pix-app": "PIX - No contestar", + "pix-orga": "Pix Orga - No contestar", + "pix-certif": "Pix Certif - No contestar" }, "entity-validation-errors": { "ACCEPT_CGU": "Debes aceptar las condiciones de uso de Pix para crear una cuenta.", diff --git a/api/translations/fr.json b/api/translations/fr.json index 44ec8ff276b..c5df4254b12 100644 --- a/api/translations/fr.json +++ b/api/translations/fr.json @@ -293,7 +293,9 @@ "template-name": "modele-import" }, "email-sender-name": { - "pix-app": "PIX - Ne pas répondre" + "pix-app": "PIX - Ne pas répondre", + "pix-certif": "Pix Certif - Ne pas répondre", + "pix-orga": "Pix Orga - Ne pas répondre" }, "entity-validation-errors": { "ACCEPT_CGU": "Vous devez accepter les conditions d’utilisation de Pix pour créer un compte.", diff --git a/api/translations/nl.json b/api/translations/nl.json index 505b5892722..239be9b2776 100644 --- a/api/translations/nl.json +++ b/api/translations/nl.json @@ -293,7 +293,9 @@ "template-name": "importmodel" }, "email-sender-name": { - "pix-app": "PIX - Niet beantwoorden" + "pix-app": "PIX - Niet beantwoorden", + "pix-orga": "Pix Orga - Niet beantwoorden", + "pix-certif": "Pix Certif - Niet beantwoorden" }, "entity-validation-errors": { "ACCEPT_CGU": "Je moet de gebruiksvoorwaarden van Pix accepteren om een account aan te maken.",