From d837a2ed0f4b60da7c695f393e5610d4c0c6d6cf Mon Sep 17 00:00:00 2001
From: ZAYTOUN abdellatif <zaytoun.abdellatif@gmail.com>
Date: Fri, 4 Apr 2025 02:13:40 +0200
Subject: [PATCH] feat(): Emails
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Internationaliser les sujets des emails.
- Arrêter l'envoi des mails : ATTENTION : un expert non-activé a été sollicité.
---
 .../selexpert/service/MessagingService.java   | 75 ++++++++----------
 src/main/resources/lang/messages.properties   | 24 +++++-
 .../resources/lang/messages_en.properties     | 24 +++++-
 .../emails/expert-not-activated.ftlh          |  8 --
 .../en/emails/expert-not-activated.ftlh       |  8 --
 .../service/MessagingServiceTest.java         | 77 ++++++++++++-------
 6 files changed, 126 insertions(+), 90 deletions(-)
 delete mode 100644 src/main/resources/templates/emails/expert-not-activated.ftlh
 delete mode 100644 src/main/resources/templates/en/emails/expert-not-activated.ftlh

diff --git a/src/main/java/fr/gouv/beta/selexpert/service/MessagingService.java b/src/main/java/fr/gouv/beta/selexpert/service/MessagingService.java
index 3adc80f..10eb462 100644
--- a/src/main/java/fr/gouv/beta/selexpert/service/MessagingService.java
+++ b/src/main/java/fr/gouv/beta/selexpert/service/MessagingService.java
@@ -410,17 +410,7 @@ public class MessagingService {
                   request.getId(),
                   "selexpertUrl",
                   selexpertUrl));
-          if (!activated) { // non activated user, warn ourselves
-            var emailModelForUs = new HashMap<String, Object>();
-            emailModelForUs.put("expert", expert.getName());
-            emailModelForUs.put("expertAppealCourt", expert.getAppealCourt().getName());
-            emailModelForUs.put("procedureId", request.getProcedureId());
-            emailModelForUs.put("requestId", request.getId());
-            emailModelForUs.put("jurisdiction", request.getJurisdiction().getName());
-            emailModelForUs.put(
-                "appealCourt", request.getJurisdiction().getAppealCourt().getName());
-            send(senderEmail, Email.EXPERT_NOT_ACTIVATED, emailModelForUs);
-          }
+
           toSend.updateStatus(RequestExpertStatus.SENT);
           toSend.setSentOn(now); // all requestExperts should have the same time
           // if urgent, possibly problematic if re1 sent at 23:59:59 and re2 at 00:00
@@ -458,7 +448,7 @@ public class MessagingService {
     try {
       mailService.send(
           to,
-          email.subject,
+          translationService.getMessage(email.subjectKey),
           FreeMarkerTemplateUtils.processTemplateIntoString(
               freeMarkerConfiguration.getTemplate(email.template + ".ftlh"), emailModel));
     } catch (Exception e) {
@@ -521,50 +511,45 @@ public class MessagingService {
   public enum Email {
 
     // AUTH
-    USER_ACTIVATION("Lien d'activation de compte", "user-activation"),
-    PASSWORD_RESET("Réinitialisation de votre mot de passe", "password-reset"),
+    USER_ACTIVATION("user-activation"),
+    PASSWORD_RESET("password-reset"),
 
     // COURT (MAGISTRATE / CLERK)
-    REQUEST_ACCEPTED("Demande acceptée", "request-accepted"),
-    REQUEST_REFUSED("Un expert a refusé", "request-refused", true),
-    REQUEST_REFUSED_ALL("Tous les experts ont refusé", "request-refused-all"),
-    REQUEST_DELIBERATION_REMINDER(
-        "La date du délibéré approche", "request-deliberation-reminder", true),
-    QUESTION_ASKED("Une question a été posée", "question-asked"),
-    QUESTION_REMINDER("Rappel : une question a été posée", "question-reminder"),
+    REQUEST_ACCEPTED("request-accepted"),
+    REQUEST_REFUSED("request-refused", true),
+    REQUEST_REFUSED_ALL("request-refused-all"),
+    REQUEST_DELIBERATION_REMINDER("request-deliberation-reminder", true),
+    QUESTION_ASKED("question-asked"),
+    QUESTION_REMINDER("question-reminder"),
     // CLERK
-    REQUEST_ASSIGNED("Rattachement à une demande d'expertise", "request-assigned", true),
+    REQUEST_ASSIGNED("request-assigned", true),
 
     // EXPERT
-    REQUEST_CREATED("Nouvelle demande d'expertise", "request-created"),
-    REQUEST_ACCEPTED_ACK("Demande acceptée", "request-accepted-ack"),
-    REQUEST_FULFILLED("Demande annulée", "request-fulfilled"),
-    REQUEST_CANCELLED("Demande annulée", "request-cancelled"),
-    REQUEST_REFUSED_AUTO("Refus automatique d'une demande", "request-refused-auto"),
-    REQUEST_REFUSED_ACK("Demande refusée", "request-refused-ack"),
-    DECISION_ADDED("Décision disponible", "decision-added"),
-    EXPERT_IS_NOW_AVAILABLE("Votre disponibilité", "expert-is-now-available"),
-    EXPERT_IS_STILL_UNAVAILABLE("Votre indisponibilité", "expert-is-still-unavailable"),
-    QUESTION_ANSWERED("Réponse à votre question", "question-answered"),
-    EXPERT_REMINDER("Rappel : demande d'expertise", "expert-reminder"),
-    DEADLINE_EXTENDED("Prolongation du délai de réponse", "request-deadline-extended"),
-
-    // ADMIN
-    EXPERT_NOT_ACTIVATED(
-        "ATTENTION : un expert non-activé a été sollicité", "expert-not-activated");
-
-    private final String subject;
+    REQUEST_CREATED("request-created"),
+    REQUEST_ACCEPTED_ACK("request-accepted-ack"),
+    REQUEST_FULFILLED("request-fulfilled"),
+    REQUEST_CANCELLED("request-cancelled"),
+    REQUEST_REFUSED_AUTO("request-refused-auto"),
+    REQUEST_REFUSED_ACK("request-refused-ack"),
+    DECISION_ADDED("decision-added"),
+    EXPERT_IS_NOW_AVAILABLE("expert-is-now-available"),
+    EXPERT_IS_STILL_UNAVAILABLE("expert-is-still-unavailable"),
+    QUESTION_ANSWERED("question-answered"),
+    EXPERT_REMINDER("expert-reminder"),
+    DEADLINE_EXTENDED("request-deadline-extended");
+
+    private final String subjectKey;
     private final String template;
     private final boolean optional;
 
-    Email(String subject, String template, boolean optional) {
-      this.subject = subject;
-      this.template = "emails/" + template;
+    Email(String subjectKey, boolean optional) {
+      this.subjectKey = subjectKey;
+      this.template = "emails/" + subjectKey;
       this.optional = optional;
     }
 
-    Email(String subject, String template) {
-      this(subject, template, false);
+    Email(String subjectKey) {
+      this(subjectKey, false);
     }
   }
 
diff --git a/src/main/resources/lang/messages.properties b/src/main/resources/lang/messages.properties
index 878d576..1f410c8 100644
--- a/src/main/resources/lang/messages.properties
+++ b/src/main/resources/lang/messages.properties
@@ -2,4 +2,26 @@ requestType.penal=p\u00E9nale
 requestType.civil=civile (autre que r\u00E9f\u00E9r\u00E9)
 requestType.summary_proceedings=en r\u00E9f\u00E9r\u00E9
 requestType.control_penal=de contr\u00F4le des expertises p\u00E9nales
-requestType.control_civil=de contr\u00F4le des expertises civiles
\ No newline at end of file
+requestType.control_civil=de contr\u00F4le des expertises civiles
+# Emails subjects
+user-activation=Lien d'activation de compte
+password-reset=R\u00E9initialisation de votre mot de passe
+request-accepted=Demande accept\u00E9e
+request-refused=Un expert a refus\u00E9
+request-refused-all=Tous les experts ont refus\u00E9
+request-deliberation-reminder=La date du d\u00E9lib\u00E9r\u00E9 approche
+question-asked=Une question a \u00E9t\u00E9 pos\u00E9e
+question-reminder=Rappel : une question a \u00E9t\u00E9 pos\u00E9e
+request-assigned=Rattachement \u00E0 une demande d'expertise
+request-created=Nouvelle demande d'expertise
+request-accepted-ack=Demande accept\u00E9e
+request-fulfilled=Demande annul\u00E9e
+request-cancelled=Demande annul\u00E9e
+request-refused-auto=Refus automatique d'une demande
+request-refused-ack=Demande refus\u00E9e
+decision-added=D\u00E9cision disponible
+expert-is-now-available=Votre disponibilit\u00E9
+expert-is-still-unavailable=Votre indisponibilit\u00E9
+question-answered=R\u00E9ponse \u00E0 votre question
+expert-reminder=Rappel : demande d'expertise
+request-deadline-extended=Prolongation du d\u00E9lai de r\u00E9ponse
\ No newline at end of file
diff --git a/src/main/resources/lang/messages_en.properties b/src/main/resources/lang/messages_en.properties
index 5633589..6af6ed4 100644
--- a/src/main/resources/lang/messages_en.properties
+++ b/src/main/resources/lang/messages_en.properties
@@ -2,4 +2,26 @@ requestType.penal=penal
 requestType.civil=civil
 requestType.summary_proceedings=summary proceedings
 requestType.control_penal=penal expert Report Review
-requestType.control_civil=civil expert Report Review
\ No newline at end of file
+requestType.control_civil=civil expert Report Review
+# Emails subjects
+user-activation=Account activation link
+password-reset=Password reset
+request-accepted=Request accepted
+request-refused=An expert has refused
+request-refused-all=All experts refused
+request-deliberation-reminder=Deliberation date approaching
+question-asked=A question has been asked
+question-reminder=Reminder: a question has been asked
+request-assigned=Assigned to an expertise request
+request-created=New expertise request
+request-accepted-ack=Request accepted
+request-fulfilled=Request cancelled
+request-cancelled=Request cancelled
+request-refused-auto=Automatic request refusal
+request-refused-ack=Request refused
+decision-added=Decision available
+expert-is-now-available=Your availability
+expert-is-still-unavailable=Your unavailability
+question-answered=Answer to your question
+expert-reminder=Reminder: expertise request
+request-deadline-extended=Response deadline extended
\ No newline at end of file
diff --git a/src/main/resources/templates/emails/expert-not-activated.ftlh b/src/main/resources/templates/emails/expert-not-activated.ftlh
deleted file mode 100644
index 3d39763..0000000
--- a/src/main/resources/templates/emails/expert-not-activated.ftlh
+++ /dev/null
@@ -1,8 +0,0 @@
-<#import "common.ftlh" as c>
-<@c.base>
-  <p>L'expert <b>${expert}</b> (${expertAppealCourt}) n'a toujours pas activé son compte.
-  </p>
-  <p>Il vient d'être sollicité pour la
-    <a href="${selexpertUrl}/demande/${requestId?c}">demande ${procedureId}</a>
-    (${appealCourt} > ${jurisdiction}).</p>
-</@c.base>
\ No newline at end of file
diff --git a/src/main/resources/templates/en/emails/expert-not-activated.ftlh b/src/main/resources/templates/en/emails/expert-not-activated.ftlh
deleted file mode 100644
index e6b0226..0000000
--- a/src/main/resources/templates/en/emails/expert-not-activated.ftlh
+++ /dev/null
@@ -1,8 +0,0 @@
-<#import "common.ftlh" as c>
-<@c.base>
-  <p>The expert <b>${expert}</b> (${expertAppealCourt}) has not yet activated their account.
-  </p>
-  <p>They have just been approached for the
-    <a href="${selexpertUrl}/demande/${requestId?c}">request ${procedureId}</a>
-    (${appealCourt} > ${jurisdiction}).</p>
-</@c.base>
\ No newline at end of file
diff --git a/src/test/java/fr/gouv/beta/selexpert/service/MessagingServiceTest.java b/src/test/java/fr/gouv/beta/selexpert/service/MessagingServiceTest.java
index 47a9bac..43e4d72 100644
--- a/src/test/java/fr/gouv/beta/selexpert/service/MessagingServiceTest.java
+++ b/src/test/java/fr/gouv/beta/selexpert/service/MessagingServiceTest.java
@@ -138,6 +138,8 @@ class MessagingServiceTest {
         .willReturn(List.of(requestExpert, requestExpert2, requestExpert3));
 
     when(translationService.format(anyString(), any(LocalDateTime.class))).thenReturn("");
+    when(translationService.getMessage(Email.REQUEST_CREATED.getSubjectKey()))
+        .thenReturn("request-created");
 
     // WHEN
     messagingService.onRequestCreated(new RequestCreatedEvent(request));
@@ -147,11 +149,9 @@ class MessagingServiceTest {
     then(requestExpert2.getStatus()).isEqualTo(RequestExpertStatus.SENT);
     then(requestExpert.getSentOn()).isNotNull();
     then(requestExpert.getSentOn()).isEqualTo(requestExpert2.getSentOn());
-    verify(mailService).send("1@expert.com", Email.REQUEST_CREATED.getSubject(), "");
-    verify(mailService).send("2@userexpert.com", Email.REQUEST_CREATED.getSubject(), "");
-    verify(mailService).send("3@userexpert.com", Email.REQUEST_CREATED.getSubject(), "");
-    verify(mailService)
-        .send("contact@selexpert.beta.gouv.fr", Email.EXPERT_NOT_ACTIVATED.getSubject(), "");
+    verify(mailService).send("1@expert.com", "request-created", "");
+    verify(mailService).send("2@userexpert.com", "request-created", "");
+    verify(mailService).send("3@userexpert.com", "request-created", "");
     verify(smsService).send("0606060603", "");
     verify(smsService, times(0)).send("0606060602", "");
   }
@@ -168,12 +168,15 @@ class MessagingServiceTest {
     given(requestExpertRepository.findByRequestAndStatus(request, RequestExpertStatus.SENDING))
         .willReturn(List.of());
 
+    when(translationService.getMessage(Email.REQUEST_ASSIGNED.getSubjectKey()))
+        .thenReturn("request-assigned");
+
     // WHEN
     messagingService.onRequestCreated(new RequestCreatedEvent(request));
 
     // THEN
-    verify(mailService, times(0)).send("1@clerk.com", Email.REQUEST_ASSIGNED.getSubject(), "");
-    verify(mailService, times(1)).send("2@clerk.com", Email.REQUEST_ASSIGNED.getSubject(), "");
+    verify(mailService, times(0)).send("1@clerk.com", "request-assigned", "");
+    verify(mailService, times(1)).send("2@clerk.com", "request-assigned", "");
   }
 
   @Test
@@ -184,15 +187,18 @@ class MessagingServiceTest {
     UserClerk clerkAllNotifsTrue = makeClerk(2, true);
     UserClerk clerkAllNotifsFalse = makeClerk(3, false);
 
+    when(translationService.getMessage(Email.REQUEST_ASSIGNED.getSubjectKey()))
+        .thenReturn("request-assigned");
+
     // WHEN
     messagingService.onClerksAdded(
         new ClerksAddedEvent(
             new Request(), List.of(clerkAllNotifsNull, clerkAllNotifsTrue, clerkAllNotifsFalse)));
 
     // THEN
-    verify(mailService, times(1)).send("1@clerk.com", Email.REQUEST_ASSIGNED.getSubject(), "");
-    verify(mailService, times(1)).send("2@clerk.com", Email.REQUEST_ASSIGNED.getSubject(), "");
-    verify(mailService, times(0)).send("3@clerk.com", Email.REQUEST_ASSIGNED.getSubject(), "");
+    verify(mailService, times(1)).send("1@clerk.com", "request-assigned", "");
+    verify(mailService, times(1)).send("2@clerk.com", "request-assigned", "");
+    verify(mailService, times(0)).send("3@clerk.com", "request-assigned", "");
   }
 
   @Test
@@ -208,16 +214,23 @@ class MessagingServiceTest {
     request.getRequestExperts().addAll(List.of(requestExpertAccepted, requestExpertFulfilled));
     request.setRequestClerks(List.of(makeClerk(1, true), makeClerk(2, false)));
 
+    when(translationService.getMessage(Email.REQUEST_ACCEPTED.getSubjectKey()))
+        .thenReturn("request-accepted");
+    when(translationService.getMessage(Email.REQUEST_ACCEPTED_ACK.getSubjectKey()))
+        .thenReturn("request-accepted-ack");
+    when(translationService.getMessage(Email.REQUEST_FULFILLED.getSubjectKey()))
+        .thenReturn("request-fulfilled");
+
     // WHEN
     messagingService.onRequestAccepted(
         new RequestAcceptedEvent(request, requestExpertAccepted.getExpert()));
 
     // THEN
-    verify(mailService).send("1@magistrate.com", Email.REQUEST_ACCEPTED.getSubject(), "");
-    verify(mailService).send("1@clerk.com", Email.REQUEST_ACCEPTED.getSubject(), "");
-    verify(mailService).send("2@clerk.com", Email.REQUEST_ACCEPTED.getSubject(), "");
-    verify(mailService).send("1@userexpert.com", Email.REQUEST_ACCEPTED_ACK.getSubject(), "");
-    verify(mailService).send("2@expert.com", Email.REQUEST_FULFILLED.getSubject(), "");
+    verify(mailService).send("1@magistrate.com", "request-accepted", "");
+    verify(mailService).send("1@clerk.com", "request-accepted", "");
+    verify(mailService).send("2@clerk.com", "request-accepted", "");
+    verify(mailService).send("1@userexpert.com", "request-accepted-ack", "");
+    verify(mailService).send("2@expert.com", "request-fulfilled", "");
   }
 
   @ParameterizedTest
@@ -241,10 +254,19 @@ class MessagingServiceTest {
           .willReturn(List.of(requestExpertSending));
 
       when(requestService.isRequestAtFinalExpert(request)).thenReturn(true);
+
+      when(translationService.getMessage(Email.REQUEST_REFUSED.getSubjectKey()))
+          .thenReturn("request-refused");
+      when(translationService.getMessage(Email.REQUEST_CREATED.getSubjectKey()))
+          .thenReturn("request-created");
+    } else {
+      when(translationService.getMessage(Email.REQUEST_REFUSED_ALL.getSubjectKey()))
+          .thenReturn("request-refused-all");
     }
 
-    when(translationService.format(anyString(), any(LocalDateTime.class)))
-        .thenReturn("");
+    when(translationService.format(anyString(), any(LocalDateTime.class))).thenReturn("");
+    when(translationService.getMessage(Email.REQUEST_REFUSED_ACK.getSubjectKey()))
+        .thenReturn("request-refused-ack");
 
     // WHEN
     messagingService.onRequestRefused(
@@ -253,13 +275,9 @@ class MessagingServiceTest {
 
     // THEN
     verify(mailService)
-        .send(
-            "1@magistrate.com",
-            open ? Email.REQUEST_REFUSED.getSubject() : Email.REQUEST_REFUSED_ALL.getSubject(),
-            "");
-    verify(mailService).send("1@userexpert.com", Email.REQUEST_REFUSED_ACK.getSubject(), "");
-    verify(mailService, times(open ? 1 : 0))
-        .send("2@userexpert.com", Email.REQUEST_CREATED.getSubject(), "");
+        .send("1@magistrate.com", open ? "request-refused" : "request-refused-all", "");
+    verify(mailService).send("1@userexpert.com", "request-refused-ack", "");
+    verify(mailService, times(open ? 1 : 0)).send("2@userexpert.com", "request-created", "");
   }
 
   @Test
@@ -275,6 +293,11 @@ class MessagingServiceTest {
         makeRequestExpert(RequestExpertStatus.REFUSED_AUTO, request, 2, true).build();
     request.getRequestExperts().add(requestExpertAuto2);
 
+    when(translationService.getMessage(Email.REQUEST_REFUSED_ALL.getSubjectKey()))
+        .thenReturn("request-refused-all");
+    when(translationService.getMessage(Email.REQUEST_REFUSED_AUTO.getSubjectKey()))
+        .thenReturn("request-refused-auto");
+
     // WHEN
     messagingService.onRequestRefusedAuto(
         new RequestRefusedAutoEvent(
@@ -283,8 +306,8 @@ class MessagingServiceTest {
             List.of(requestExpertAuto2.getExpert())));
 
     // THEN
-    verify(mailService).send("1@magistrate.com", Email.REQUEST_REFUSED_ALL.getSubject(), "");
-    verify(mailService).send("1@expert.com", Email.REQUEST_REFUSED_AUTO.getSubject(), "");
-    verify(mailService).send("2@userexpert.com", Email.REQUEST_REFUSED_AUTO.getSubject(), "");
+    verify(mailService).send("1@magistrate.com", "request-refused-all", "");
+    verify(mailService).send("1@expert.com", "request-refused-auto", "");
+    verify(mailService).send("2@userexpert.com", "request-refused-auto", "");
   }
 }
-- 
GitLab