From 512ed6f8e01cee3ec79c294701d303859addd083 Mon Sep 17 00:00:00 2001 From: Allison Lee Date: Wed, 26 Aug 2026 19:46:29 -0400 Subject: [PATCH] Update Member: Remove email change support --- .../components/MemberProfileForm.tsx | 5 +- .../patchats/api/member/MemberService.java | 19 ++--- .../api/member/MemberControllerTest.java | 72 +++++++------------ .../api/member/MemberServiceTest.java | 55 +++++++++----- .../api/member/MemberTestFixtures.java | 2 +- 5 files changed, 77 insertions(+), 76 deletions(-) diff --git a/js/src/features/member-profile/components/MemberProfileForm.tsx b/js/src/features/member-profile/components/MemberProfileForm.tsx index 17f2dfcc..843c694b 100644 --- a/js/src/features/member-profile/components/MemberProfileForm.tsx +++ b/js/src/features/member-profile/components/MemberProfileForm.tsx @@ -162,9 +162,10 @@ export function MemberProfileForm({ id }: { id: string }) { required type="email" label="Email Address" - description="Use an email address you check regularly, as this is how we will contact you about your matches!" + description="Use an email address you check regularly, as this is how we will contact you about your matches! (Email changes are not currently supported.)" value={values.email} - disabled={!isEditing} + // Always disabled for now until we implement email change verification + disabled onChange={(event) => handleFieldChange("email", event.target.value)} onBlur={() => handleFieldBlur("email")} error={errors.email} diff --git a/src/main/java/org/patinanetwork/patchats/api/member/MemberService.java b/src/main/java/org/patinanetwork/patchats/api/member/MemberService.java index c1246dbe..4761e68b 100644 --- a/src/main/java/org/patinanetwork/patchats/api/member/MemberService.java +++ b/src/main/java/org/patinanetwork/patchats/api/member/MemberService.java @@ -15,7 +15,6 @@ import org.patinanetwork.patchats.common.web.exception.MemberDuplicateException; import org.patinanetwork.patchats.common.web.exception.MemberNotFoundException; import org.patinanetwork.patchats.common.web.exception.ValidationException; -import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; @Service @@ -73,9 +72,12 @@ public MemberDto updateMember(UpdateMemberRequest request, UUID id) { return MemberDto.from(member); } + if (request.email().isPresent() && !request.email().get().equals(member.getEmail())) { + throw new ValidationException("Email changes are not currently supported"); + } + validateAndUpdate(request.firstName(), member::setFirstName, "firstName", true); validateAndUpdate(request.lastName(), member::setLastName, "lastName", true); - validateAndUpdate(request.email(), member::setEmail, "email", true); validateAndUpdate(request.introduction(), member::setIntroduction, "introduction", true); validateAndUpdate(request.linkedInUrl(), member::setLinkedInUrl, "linkedInUrl", false); validateAndUpdate(request.matchPref(), member::setMatchPref, "matchPref", false); @@ -84,12 +86,13 @@ public MemberDto updateMember(UpdateMemberRequest request, UUID id) { validateAndUpdate(request.topics(), member::setTopics, "topics", false); validateAndUpdate(request.extraNotes(), member::setExtraNotes, "extraNotes", false); - try { - Member updatedMember = memberRepo.updateMember(member).orElseThrow(() -> new MemberNotFoundException(id)); - return MemberDto.from(updatedMember); - } catch (DuplicateKeyException e) { - throw new MemberDuplicateException(member.getEmail()); - } + // Commented out duplicate check since email changes are not currently supported + // try { + Member updatedMember = memberRepo.updateMember(member).orElseThrow(() -> new MemberNotFoundException(id)); + return MemberDto.from(updatedMember); + // } catch (DuplicateKeyException e) { + // throw new MemberDuplicateException(member.getEmail()); + // } } private void validateAndUpdate( diff --git a/src/test/java/org/patinanetwork/patchats/api/member/MemberControllerTest.java b/src/test/java/org/patinanetwork/patchats/api/member/MemberControllerTest.java index f2fa06ef..bcf5aac8 100644 --- a/src/test/java/org/patinanetwork/patchats/api/member/MemberControllerTest.java +++ b/src/test/java/org/patinanetwork/patchats/api/member/MemberControllerTest.java @@ -231,30 +231,6 @@ void updateMember_successWithPartialUpdate() throws Exception { .andExpect(jsonPath("$.payload.firstName").value("UpdatedFirstName")); } - @Test - void updateMember_badRequestWhenBlankRequiredField() throws Exception { - final UUID id = UUID.randomUUID(); - final UpdateMemberRequest request = new UpdateMemberRequest( - Optional.of(""), - Optional.of("UpdatedLastName"), - Optional.of("updated@example.com"), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty()); - - when(memberService.updateMember(any(), any())).thenThrow(new ValidationException("firstName cannot be empty")); - - mockMvc.perform(patch("/api/members/{id}", id) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.message").value("firstName cannot be empty")); - } - @Test void updateMember_notFoundWhenMemberDoesNotExist() throws Exception { final UUID id = UUID.randomUUID(); @@ -280,30 +256,30 @@ void updateMember_notFoundWhenMemberDoesNotExist() throws Exception { .andExpect(jsonPath("$.success").value(false)); } - @Test - void updateMember_conflictWhenEmailIsDuplicate() throws Exception { - final UUID id = UUID.randomUUID(); - final UpdateMemberRequest request = new UpdateMemberRequest( - Optional.empty(), - Optional.empty(), - Optional.of("existing@example.com"), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty()); - - when(memberService.updateMember(any(UpdateMemberRequest.class), eq(id))) - .thenThrow(new MemberDuplicateException("existing@example.com")); - - mockMvc.perform(patch("/api/members/{id}", id) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isConflict()) - .andExpect(jsonPath("$.success").value(false)); - } + // @Test + // void updateMember_conflictWhenEmailIsDuplicate() throws Exception { + // final UUID id = UUID.randomUUID(); + // final UpdateMemberRequest request = new UpdateMemberRequest( + // Optional.empty(), + // Optional.empty(), + // Optional.of("existing@example.com"), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty()); + + // when(memberService.updateMember(any(UpdateMemberRequest.class), eq(id))) + // .thenThrow(new MemberDuplicateException("existing@example.com")); + + // mockMvc.perform(patch("/api/members/{id}", id) + // .contentType(MediaType.APPLICATION_JSON) + // .content(objectMapper.writeValueAsString(request))) + // .andExpect(status().isConflict()) + // .andExpect(jsonPath("$.success").value(false)); + // } @Test void updateMember_badRequestWhenValidationFails() throws Exception { diff --git a/src/test/java/org/patinanetwork/patchats/api/member/MemberServiceTest.java b/src/test/java/org/patinanetwork/patchats/api/member/MemberServiceTest.java index f14a39c9..6d844935 100644 --- a/src/test/java/org/patinanetwork/patchats/api/member/MemberServiceTest.java +++ b/src/test/java/org/patinanetwork/patchats/api/member/MemberServiceTest.java @@ -23,7 +23,7 @@ import org.patinanetwork.patchats.api.member.dto.UpdateMemberRequest; import org.patinanetwork.patchats.common.web.exception.MemberDuplicateException; import org.patinanetwork.patchats.common.web.exception.MemberNotFoundException; -import org.springframework.dao.DuplicateKeyException; +import org.patinanetwork.patchats.common.web.exception.ValidationException; class MemberServiceTest { @@ -272,7 +272,6 @@ void updateMemberSuccessWithAllFields() { assertEquals("UpdatedFirstName", captured.getFirstName()); assertEquals("UpdatedLastName", captured.getLastName()); - assertEquals("updated@example.com", captured.getEmail()); assertEquals("https://linkedin.com/in/updated", captured.getLinkedInUrl()); assertEquals("Updated intro", captured.getIntroduction()); assertEquals("Mentor - I am looking for guidance from someone with more experience", captured.getMatchPref()); @@ -282,13 +281,40 @@ void updateMemberSuccessWithAllFields() { assertEquals("Notes", captured.getExtraNotes()); } + // @Test + // void updateMember_throwsExceptionWhenEmailIsDuplicate() { + // final UUID id = UUID.randomUUID(); + // final UpdateMemberRequest request = new UpdateMemberRequest( + // Optional.empty(), + // Optional.empty(), + // Optional.of("existing@example.com"), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty(), + // Optional.empty()); + + // final Member existingMember = Member.builder() + // .id(id) + // .firstName("John") + // .lastName("Doe") + // .email("john@example.com") + // .build(); + + // when(memberRepo.updateMember(any(Member.class))).thenThrow(new DuplicateKeyException("Email already + // exists")); + // when(memberRepo.getMemberById(id)).thenReturn(Optional.of(existingMember)); + // assertThrows(MemberDuplicateException.class, () -> memberService.updateMember(request, id)); + // } @Test - void updateMember_throwsExceptionWhenEmailIsDuplicate() { + void updateMember_throwsValidationExceptionWhenEmailIsChanged() { final UUID id = UUID.randomUUID(); final UpdateMemberRequest request = new UpdateMemberRequest( Optional.empty(), Optional.empty(), - Optional.of("existing@example.com"), + Optional.of("new@example.com"), Optional.empty(), Optional.empty(), Optional.empty(), @@ -304,16 +330,17 @@ void updateMember_throwsExceptionWhenEmailIsDuplicate() { .email("john@example.com") .build(); - when(memberRepo.updateMember(any(Member.class))).thenThrow(new DuplicateKeyException("Email already exists")); when(memberRepo.getMemberById(id)).thenReturn(Optional.of(existingMember)); - assertThrows(MemberDuplicateException.class, () -> memberService.updateMember(request, id)); + + assertThrows(ValidationException.class, () -> memberService.updateMember(request, id)); + verify(memberRepo, never()).updateMember(any()); } @Test - void updateMember_successWhenUpdatingWithSameEmail() { + void updateMember_successWhenUpdatingOtherFieldsWithUnchangedEmail() { final UUID id = UUID.randomUUID(); final UpdateMemberRequest request = new UpdateMemberRequest( - Optional.empty(), + Optional.of("UpdatedFirstName"), Optional.empty(), Optional.of("john@example.com"), Optional.empty(), @@ -329,25 +356,19 @@ void updateMember_successWhenUpdatingWithSameEmail() { .firstName("John") .lastName("Doe") .email("john@example.com") - .linkedInUrl("https://linkedin.com/in/john") - .introduction("intro") - .matchPref("Mentor") - .industryPref("Tech") - .rolePref("Engineer") - .topics("AI") - .extraNotes("notes") .build(); when(memberRepo.getMemberById(id)).thenReturn(Optional.of(existingMember)); - when(memberRepo.updateMember(any())).thenReturn(Optional.of(existingMember)); + when(memberRepo.updateMember(any(Member.class))).thenReturn(Optional.of(existingMember)); final ArgumentCaptor captor = ArgumentCaptor.forClass(Member.class); memberService.updateMember(request, id); + verify(memberRepo).updateMember(captor.capture()); final Member captured = captor.getValue(); + assertEquals("UpdatedFirstName", captured.getFirstName()); assertEquals("john@example.com", captured.getEmail()); - verify(memberRepo, never()).getMemberByEmail(any()); } @Test diff --git a/src/test/java/org/patinanetwork/patchats/api/member/MemberTestFixtures.java b/src/test/java/org/patinanetwork/patchats/api/member/MemberTestFixtures.java index 78d79101..524c3c56 100644 --- a/src/test/java/org/patinanetwork/patchats/api/member/MemberTestFixtures.java +++ b/src/test/java/org/patinanetwork/patchats/api/member/MemberTestFixtures.java @@ -22,7 +22,7 @@ final class MemberTestFixtures { static final UpdateMemberRequest UPDATE_REQUEST_ALL_FIELDS = new UpdateMemberRequest( Optional.of("UpdatedFirstName"), Optional.of("UpdatedLastName"), - Optional.of("updated@example.com"), + Optional.empty(), // Email changes are not currently supported Optional.of("https://linkedin.com/in/updated"), Optional.of("Updated intro"), Optional.of("Mentor - I am looking for guidance from someone with more experience"),