From 43daa45e1774b737e98dbb407216ad6523dad83e Mon Sep 17 00:00:00 2001 From: Sowmiya Ravikumar Date: Tue, 29 Sep 2026 13:35:47 +0100 Subject: [PATCH 1/4] task: Add Adhoc Note to New Mentee Notification Email --- .../configuration/GlobalExceptionHandler.java | 2 + .../configuration/NotificationConfig.java | 1 + .../MentorshipNotificationService.java | 7 +++- src/main/resources/application.yml | 6 ++- .../alert_new_mentees_applications_mentor.yml | 6 ++- .../GlobalExceptionHandlerTest.java | 14 +++++++ .../MentorshipNotificationServiceTest.java | 42 +++++++++++++++++++ 7 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/wcc/platform/configuration/GlobalExceptionHandler.java b/src/main/java/com/wcc/platform/configuration/GlobalExceptionHandler.java index d841238f9..1cc887981 100644 --- a/src/main/java/com/wcc/platform/configuration/GlobalExceptionHandler.java +++ b/src/main/java/com/wcc/platform/configuration/GlobalExceptionHandler.java @@ -15,6 +15,7 @@ import com.wcc.platform.domain.exceptions.ErrorDetails; import com.wcc.platform.domain.exceptions.ForbiddenException; import com.wcc.platform.domain.exceptions.InvalidCycleStatusTransitionException; +import com.wcc.platform.domain.exceptions.InvalidMentorshipTypeException; import com.wcc.platform.domain.exceptions.InvalidProgramTypeException; import com.wcc.platform.domain.exceptions.InvalidTokenException; import com.wcc.platform.domain.exceptions.MemberNotFoundException; @@ -89,6 +90,7 @@ public ResponseEntity handleInternalError( */ @ExceptionHandler({ InvalidProgramTypeException.class, + InvalidMentorshipTypeException.class, IllegalArgumentException.class, TemplateValidationException.class }) diff --git a/src/main/java/com/wcc/platform/configuration/NotificationConfig.java b/src/main/java/com/wcc/platform/configuration/NotificationConfig.java index 259ea6e30..c00081215 100644 --- a/src/main/java/com/wcc/platform/configuration/NotificationConfig.java +++ b/src/main/java/com/wcc/platform/configuration/NotificationConfig.java @@ -21,4 +21,5 @@ public class NotificationConfig { @NotBlank private String mentorProfileUrl; @NotBlank private String volunteerUrl; @NotBlank private String mentorshipEmail; + @NotBlank private String adhocMenteeNote; } diff --git a/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java b/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java index 0a8558195..7f5ac6e43 100644 --- a/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java +++ b/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java @@ -153,13 +153,18 @@ public void sendNewMenteesNotification(final Mentor mentor, final MentorshipCycl cycle.getCycleYear() != null ? cycle.getCycleYear().getValue() : LocalDate.now(ZONE_ID).getYear(); + final String adhocNote = + cycle.getMentorshipType() == MentorshipType.AD_HOC + ? notificationConfig.getAdhocMenteeNote() + : ""; sendNotification( TemplateType.NEW_MENTEES_REVIEW, Map.of( "mentorName", mentor.getFullName(), "year", year, "cycleType", cycle.getMentorshipType().getDescription(), - "mentorshipEmail", notificationConfig.getMentorshipEmail()), + "mentorshipEmail", notificationConfig.getMentorshipEmail(), + "adhocNote", adhocNote), List.of(mentor.getEmail(), notificationConfig.getMentorshipEmail())); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a91c04930..2e1b72e0b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -44,6 +44,10 @@ notification: mentorship-email: mentorship@womencodingcommunity.com mentor-profile-url: https://mentorship.womencodingcommunity.com/mentorship/mentors?keyword= volunteer-url: https://www.womencodingcommunity.com/volunteer + adhoc-mentee-note: >- +

In an Ad-Hoc cycle, a mentee can apply to more than one mentor. Once any mentor accepts, + the application is no longer available to others. If you cannot find an application in your + dashboard, it may have already been accepted by another mentor.

logging: level: @@ -65,7 +69,7 @@ file: app: cors: - allowed-origins: http://localhost:3000,https://localhost:3000 + allowed-origins: http://localhost:4000,https://localhost:4000 email: team-signature: | Best Regards
diff --git a/src/main/resources/email-templates/alert_new_mentees_applications_mentor.yml b/src/main/resources/email-templates/alert_new_mentees_applications_mentor.yml index e28de2cc9..15a114c1f 100644 --- a/src/main/resources/email-templates/alert_new_mentees_applications_mentor.yml +++ b/src/main/resources/email-templates/alert_new_mentees_applications_mentor.yml @@ -7,10 +7,12 @@ NEW_MENTEES_REVIEW:

- You have new mentee applications currently pending your review. - Could you please log into your Mentor Dashboard today to check? + You have new mentee applications currently pending your review. + Could you please log into your Mentor Dashboard today to check?

+ {{adhocNote}} +

As an action point, please approve the mentee(s) you'd like to accept, or reject so that their application(s) can be forwarded to other mentors.

diff --git a/src/test/java/com/wcc/platform/configuration/GlobalExceptionHandlerTest.java b/src/test/java/com/wcc/platform/configuration/GlobalExceptionHandlerTest.java index f6755ee49..e1b0c3292 100644 --- a/src/test/java/com/wcc/platform/configuration/GlobalExceptionHandlerTest.java +++ b/src/test/java/com/wcc/platform/configuration/GlobalExceptionHandlerTest.java @@ -13,6 +13,7 @@ import com.wcc.platform.domain.exceptions.DuplicatedMemberException; import com.wcc.platform.domain.exceptions.ErrorDetails; import com.wcc.platform.domain.exceptions.ForbiddenException; +import com.wcc.platform.domain.exceptions.InvalidMentorshipTypeException; import com.wcc.platform.domain.platform.mentorship.TechnicalAreaProficiency; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -100,6 +101,19 @@ void shouldReturnConflictForDataAccessException() { assertEquals(expectation, response.getBody()); } + @Test + @DisplayName( + "Given InvalidMentorshipTypeException, when handling, then return BAD_REQUEST") + void shouldReturnBadRequestForInvalidMentorshipTypeException() { + var exception = new InvalidMentorshipTypeException("Cycle type mismatch"); + + var response = globalExceptionHandler.handleProgramTypeError(exception, webRequest); + + var expectation = new ErrorDetails(BAD_REQUEST.value(), "Cycle type mismatch", DETAILS); + assertEquals(BAD_REQUEST, response.getStatusCode()); + assertEquals(expectation, response.getBody()); + } + @Test @DisplayName( "Given malformed JSON with unknown field, " diff --git a/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java b/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java index 6215c5569..5a0d7fb13 100644 --- a/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java +++ b/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java @@ -16,7 +16,9 @@ import com.wcc.platform.domain.platform.mentorship.ApplicationStatus; import com.wcc.platform.domain.platform.mentorship.MatchStatus; import com.wcc.platform.domain.platform.mentorship.Mentor; +import com.wcc.platform.domain.platform.mentorship.MentorshipCycleEntity; import com.wcc.platform.domain.platform.mentorship.MentorshipMatch; +import com.wcc.platform.domain.platform.mentorship.MentorshipType; import com.wcc.platform.domain.template.RenderedTemplate; import com.wcc.platform.domain.template.TemplateType; import com.wcc.platform.repository.MemberRepository; @@ -181,6 +183,46 @@ void shouldSendNotificationByMemberId() { assertThat(emailRequest.getRecipients()).contains("team@test.com"); } + @Test + @DisplayName( + "Given an Ad-Hoc cycle, when sendNewMenteesNotification, then adhocNote is included in template params") + void shouldIncludeAdhocNoteForAdHocCycle() { + var adhocNote = "

In an Ad-Hoc cycle, a mentee can apply to more than one mentor.

"; + var cycle = + MentorshipCycleEntity.builder().mentorshipType(MentorshipType.AD_HOC).build(); + + when(notificationConfig.getMentorshipEmail()).thenReturn("team@test.com"); + when(notificationConfig.getAdhocMenteeNote()).thenReturn(adhocNote); + when(emailTemplateService.renderTemplate(any(), any())) + .thenReturn(new RenderedTemplate("Subject", "Body")); + + notificationService.sendNewMenteesNotification(mentor, cycle); + + @SuppressWarnings("unchecked") + ArgumentCaptor> paramsCaptor = ArgumentCaptor.forClass(Map.class); + verify(emailTemplateService).renderTemplate(eq(TemplateType.NEW_MENTEES_REVIEW), paramsCaptor.capture()); + assertThat(paramsCaptor.getValue()).containsEntry("adhocNote", adhocNote); + } + + @Test + @DisplayName( + "Given a Long-Term cycle, when sendNewMenteesNotification, then adhocNote is empty in template params") + void shouldExcludeAdhocNoteForLongTermCycle() { + var cycle = + MentorshipCycleEntity.builder().mentorshipType(MentorshipType.LONG_TERM).build(); + + when(notificationConfig.getMentorshipEmail()).thenReturn("team@test.com"); + when(emailTemplateService.renderTemplate(any(), any())) + .thenReturn(new RenderedTemplate("Subject", "Body")); + + notificationService.sendNewMenteesNotification(mentor, cycle); + + @SuppressWarnings("unchecked") + ArgumentCaptor> paramsCaptor = ArgumentCaptor.forClass(Map.class); + verify(emailTemplateService).renderTemplate(eq(TemplateType.NEW_MENTEES_REVIEW), paramsCaptor.capture()); + assertThat(paramsCaptor.getValue()).containsEntry("adhocNote", ""); + } + @Test @DisplayName( "Given member IDs and no team email, when sendNotificationByMemberId, then sends only to members") From 8566e4cd78587f937816559db07aaf4e8b8535ca Mon Sep 17 00:00:00 2001 From: Sowmiya Ravikumar Date: Mon, 5 Oct 2026 21:36:07 +0100 Subject: [PATCH 2/4] Revert the port changes --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2e1b72e0b..b7f62cc84 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -69,7 +69,7 @@ file: app: cors: - allowed-origins: http://localhost:4000,https://localhost:4000 + allowed-origins: http://localhost:3000,https://localhost:3000 email: team-signature: | Best Regards
From c63d9b8b69fcd16bd56aec02eca494ac430fea92 Mon Sep 17 00:00:00 2001 From: Sowmiya Ravikumar Date: Fri, 9 Oct 2026 15:05:54 +0100 Subject: [PATCH 3/4] Separates Long Term and Adhoc Review Email Templates --- .../domain/template/TemplateType.java | 3 +- .../MentorshipNotificationService.java | 16 ++++---- src/main/resources/application.yml | 4 -- ..._new_mentees_adhoc_applications_mentor.yml | 39 +++++++++++++++++++ ...mentees_long_term_applications_mentor.yml} | 6 +-- .../MentorshipNotificationServiceTest.java | 24 +++++------- 6 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 src/main/resources/email-templates/alert_new_mentees_adhoc_applications_mentor.yml rename src/main/resources/email-templates/{alert_new_mentees_applications_mentor.yml => alert_new_mentees_long_term_applications_mentor.yml} (96%) diff --git a/src/main/java/com/wcc/platform/domain/template/TemplateType.java b/src/main/java/com/wcc/platform/domain/template/TemplateType.java index df48aff80..890ce0bdc 100644 --- a/src/main/java/com/wcc/platform/domain/template/TemplateType.java +++ b/src/main/java/com/wcc/platform/domain/template/TemplateType.java @@ -22,7 +22,8 @@ public enum TemplateType { REMINDER_MENTEE_LONG("reminder_long_term_mentorship_mentee.yml"), MENTEES_MENTOR_LONG("list_potential_mentees_mentor_long.yml"), FOLLOWUP_MENTEES_LONG("list_potential_mentees_follow_up_mentor_long.yml"), - NEW_MENTEES_REVIEW("alert_new_mentees_applications_mentor.yml"), + NEW_MENTEES_REVIEW_LONG_TERM("alert_new_mentees_long_term_applications_mentor.yml"), + NEW_MENTEES_REVIEW_ADHOC("alert_new_mentees_adhoc_applications_mentor.yml"), STUDY_GROUP_AVAIL("confirm_availability_study_group_mentor.yml"), STUDY_GROUPS_MENTEE("mentor_led_study_groups_mentee.yml"), STUDY_GROUP_INTRO("study_group_introduction_email_mentee.yml"), diff --git a/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java b/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java index 7f5ac6e43..a4bcf23e9 100644 --- a/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java +++ b/src/main/java/com/wcc/platform/service/MentorshipNotificationService.java @@ -143,7 +143,8 @@ public void sendPairingConfirmation( } /** - * Sends a NEW_MENTEES_REVIEW notification email to a mentor when manually assigned a mentee. + * Sends a new mentees review notification email to a mentor when a mentee applies for the mentor, + * or manually assigned by Admin * * @param mentor the mentor to notify * @param cycle the mentorship cycle @@ -153,18 +154,17 @@ public void sendNewMenteesNotification(final Mentor mentor, final MentorshipCycl cycle.getCycleYear() != null ? cycle.getCycleYear().getValue() : LocalDate.now(ZONE_ID).getYear(); - final String adhocNote = - cycle.getMentorshipType() == MentorshipType.AD_HOC - ? notificationConfig.getAdhocMenteeNote() - : ""; + final TemplateType emailTemplateType = + cycle.getMentorshipType() == MentorshipType.LONG_TERM + ? TemplateType.NEW_MENTEES_REVIEW_LONG_TERM + : TemplateType.NEW_MENTEES_REVIEW_ADHOC; sendNotification( - TemplateType.NEW_MENTEES_REVIEW, + emailTemplateType, Map.of( "mentorName", mentor.getFullName(), "year", year, "cycleType", cycle.getMentorshipType().getDescription(), - "mentorshipEmail", notificationConfig.getMentorshipEmail(), - "adhocNote", adhocNote), + "mentorshipEmail", notificationConfig.getMentorshipEmail()), List.of(mentor.getEmail(), notificationConfig.getMentorshipEmail())); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b7f62cc84..a91c04930 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -44,10 +44,6 @@ notification: mentorship-email: mentorship@womencodingcommunity.com mentor-profile-url: https://mentorship.womencodingcommunity.com/mentorship/mentors?keyword= volunteer-url: https://www.womencodingcommunity.com/volunteer - adhoc-mentee-note: >- -

In an Ad-Hoc cycle, a mentee can apply to more than one mentor. Once any mentor accepts, - the application is no longer available to others. If you cannot find an application in your - dashboard, it may have already been accepted by another mentor.

logging: level: diff --git a/src/main/resources/email-templates/alert_new_mentees_adhoc_applications_mentor.yml b/src/main/resources/email-templates/alert_new_mentees_adhoc_applications_mentor.yml new file mode 100644 index 000000000..ae57619a1 --- /dev/null +++ b/src/main/resources/email-templates/alert_new_mentees_adhoc_applications_mentor.yml @@ -0,0 +1,39 @@ +NEW_MENTEES_REVIEW_ADHOC: + subject: "[Action Required] Pending Mentee Application(s) for {{year}} {{cycleType}} WCC Mentorship Programme" + body: | +

Dear {{mentorName}},

+

+ Thank you for being part of the Women Coding Community {{year}} {{cycleType}} Mentorship Programme! +

+ +

+ You have new mentee applications currently pending your review. + Could you please log into your Mentor Dashboard today to check? +

+ +

+ In an {{cycleType}} cycle, a mentee can apply to more than one mentor. Once any mentor accepts, the application is no longer available to others. + If you cannot find an application in your dashboard, it may have already been accepted by another mentor. +

+ +

+ As an action point, please approve the mentee(s) you'd like to accept, or reject so that their application(s) can be forwarded to other mentors. +

+ +

+ Please note: If you have not logged into the dashboard before, please reply to this email, so we can send a password reset email from {{mentorshipEmail}}. +

+ +

+ If you do not see the application(s) or have any other trouble accessing your account, please feel free to reply to this email. +

+ +

+ Thank you for your continued support of the mentorship programme, and we hope to get your response soon. +

+ +

+ {{teamEmailSignature}} +

+ +

[Automated Message]

\ No newline at end of file diff --git a/src/main/resources/email-templates/alert_new_mentees_applications_mentor.yml b/src/main/resources/email-templates/alert_new_mentees_long_term_applications_mentor.yml similarity index 96% rename from src/main/resources/email-templates/alert_new_mentees_applications_mentor.yml rename to src/main/resources/email-templates/alert_new_mentees_long_term_applications_mentor.yml index 15a114c1f..d512abaa1 100644 --- a/src/main/resources/email-templates/alert_new_mentees_applications_mentor.yml +++ b/src/main/resources/email-templates/alert_new_mentees_long_term_applications_mentor.yml @@ -1,4 +1,4 @@ -NEW_MENTEES_REVIEW: +NEW_MENTEES_REVIEW_LONG_TERM: subject: "[Action Required] Pending Mentee Application(s) for {{year}} {{cycleType}} WCC Mentorship Programme" body: |

Dear {{mentorName}},

@@ -10,9 +10,7 @@ NEW_MENTEES_REVIEW: You have new mentee applications currently pending your review. Could you please log into your Mentor Dashboard today to check?

- - {{adhocNote}} - +

As an action point, please approve the mentee(s) you'd like to accept, or reject so that their application(s) can be forwarded to other mentors.

diff --git a/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java b/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java index 5a0d7fb13..36c1749b5 100644 --- a/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java +++ b/src/test/java/com/wcc/platform/service/MentorshipNotificationServiceTest.java @@ -185,14 +185,11 @@ void shouldSendNotificationByMemberId() { @Test @DisplayName( - "Given an Ad-Hoc cycle, when sendNewMenteesNotification, then adhocNote is included in template params") - void shouldIncludeAdhocNoteForAdHocCycle() { - var adhocNote = "

In an Ad-Hoc cycle, a mentee can apply to more than one mentor.

"; - var cycle = - MentorshipCycleEntity.builder().mentorshipType(MentorshipType.AD_HOC).build(); + "Given an Ad-Hoc cycle, when sendNewMenteesNotification, then NEW_MENTEES_REVIEW_ADHOC template is used") + void shouldUseAdhocReviewTemplateForAdhocCycle() { + var cycle = MentorshipCycleEntity.builder().mentorshipType(MentorshipType.AD_HOC).build(); when(notificationConfig.getMentorshipEmail()).thenReturn("team@test.com"); - when(notificationConfig.getAdhocMenteeNote()).thenReturn(adhocNote); when(emailTemplateService.renderTemplate(any(), any())) .thenReturn(new RenderedTemplate("Subject", "Body")); @@ -200,16 +197,15 @@ void shouldIncludeAdhocNoteForAdHocCycle() { @SuppressWarnings("unchecked") ArgumentCaptor> paramsCaptor = ArgumentCaptor.forClass(Map.class); - verify(emailTemplateService).renderTemplate(eq(TemplateType.NEW_MENTEES_REVIEW), paramsCaptor.capture()); - assertThat(paramsCaptor.getValue()).containsEntry("adhocNote", adhocNote); + verify(emailTemplateService) + .renderTemplate(eq(TemplateType.NEW_MENTEES_REVIEW_ADHOC), paramsCaptor.capture()); } @Test @DisplayName( - "Given a Long-Term cycle, when sendNewMenteesNotification, then adhocNote is empty in template params") - void shouldExcludeAdhocNoteForLongTermCycle() { - var cycle = - MentorshipCycleEntity.builder().mentorshipType(MentorshipType.LONG_TERM).build(); + "Given a Long-Term cycle, when sendNewMenteesNotification, then NEW_MENTEES_REVIEW_LONG_TERM is used") + void shouldUseLongTermReviewTemplateForLongTermCycle() { + var cycle = MentorshipCycleEntity.builder().mentorshipType(MentorshipType.LONG_TERM).build(); when(notificationConfig.getMentorshipEmail()).thenReturn("team@test.com"); when(emailTemplateService.renderTemplate(any(), any())) @@ -219,8 +215,8 @@ void shouldExcludeAdhocNoteForLongTermCycle() { @SuppressWarnings("unchecked") ArgumentCaptor> paramsCaptor = ArgumentCaptor.forClass(Map.class); - verify(emailTemplateService).renderTemplate(eq(TemplateType.NEW_MENTEES_REVIEW), paramsCaptor.capture()); - assertThat(paramsCaptor.getValue()).containsEntry("adhocNote", ""); + verify(emailTemplateService) + .renderTemplate(eq(TemplateType.NEW_MENTEES_REVIEW_LONG_TERM), paramsCaptor.capture()); } @Test From 4ad8ffd0128d396a80db52dc4d12b319efe8c578 Mon Sep 17 00:00:00 2001 From: Sowmiya Ravikumar Date: Fri, 9 Oct 2026 15:07:41 +0100 Subject: [PATCH 4/4] Remove adhocMenteeNote from NotificationConfig --- .../java/com/wcc/platform/configuration/NotificationConfig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/wcc/platform/configuration/NotificationConfig.java b/src/main/java/com/wcc/platform/configuration/NotificationConfig.java index c00081215..259ea6e30 100644 --- a/src/main/java/com/wcc/platform/configuration/NotificationConfig.java +++ b/src/main/java/com/wcc/platform/configuration/NotificationConfig.java @@ -21,5 +21,4 @@ public class NotificationConfig { @NotBlank private String mentorProfileUrl; @NotBlank private String volunteerUrl; @NotBlank private String mentorshipEmail; - @NotBlank private String adhocMenteeNote; }