diff --git a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/OrcidRecordRepository.java b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/OrcidRecordRepository.java index 25a7c3df1..5c4b73123 100644 --- a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/OrcidRecordRepository.java +++ b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/OrcidRecordRepository.java @@ -11,7 +11,7 @@ import org.springframework.stereotype.Repository; @Repository -public interface OrcidRecordRepository extends MongoRepository { +public interface OrcidRecordRepository extends MongoRepository, OrcidRecordRepositoryCustom { Optional findOneByEmail(String email); @@ -20,4 +20,5 @@ public interface OrcidRecordRepository extends MongoRepository findBySalesforceId(String salesforceId, Pageable pageable); + } diff --git a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/OrcidRecordRepositoryCustom.java b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/OrcidRecordRepositoryCustom.java new file mode 100644 index 000000000..b7a8b6c56 --- /dev/null +++ b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/OrcidRecordRepositoryCustom.java @@ -0,0 +1,14 @@ +package org.orcid.memberportal.service.assertion.repository; + +import org.orcid.memberportal.service.assertion.domain.Assertion; +import org.orcid.memberportal.service.assertion.domain.MemberAssertionStatusCount; +import org.springframework.data.domain.Pageable; + +import java.util.Iterator; +import java.util.List; + +public interface OrcidRecordRepositoryCustom { + + void updateTokenSalesforceIds(String oldSalesforceId, String newSalesforceId); + +} diff --git a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/impl/OrcidRecordRepositoryCustomImpl.java b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/impl/OrcidRecordRepositoryCustomImpl.java new file mode 100644 index 000000000..035575d13 --- /dev/null +++ b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/repository/impl/OrcidRecordRepositoryCustomImpl.java @@ -0,0 +1,40 @@ +package org.orcid.memberportal.service.assertion.repository.impl; + +import com.mongodb.MongoClient; +import com.mongodb.client.DistinctIterable; +import com.mongodb.client.model.Filters; +import org.orcid.memberportal.service.assertion.domain.Assertion; +import org.orcid.memberportal.service.assertion.domain.MemberAssertionStatusCount; +import org.orcid.memberportal.service.assertion.domain.OrcidRecord; +import org.orcid.memberportal.service.assertion.domain.enumeration.AssertionStatus; +import org.orcid.memberportal.service.assertion.repository.AssertionRepositoryCustom; +import org.orcid.memberportal.service.assertion.repository.OrcidRecordRepositoryCustom; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.*; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Repository; + +import java.util.Iterator; +import java.util.List; + +@Repository +public class OrcidRecordRepositoryCustomImpl implements OrcidRecordRepositoryCustom { + + @Autowired + private MongoTemplate mongoTemplate; + + public OrcidRecordRepositoryCustomImpl(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + + @Override + public void updateTokenSalesforceIds(String oldSalesforceId, String newSalesforceId) { + mongoTemplate.updateMulti(Query.query(Criteria.where("tokens.salesforce_id").is(oldSalesforceId)), + new Update().set("tokens.$.salesforce_id", newSalesforceId), OrcidRecord.class); + } +} diff --git a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/AssertionService.java b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/AssertionService.java index c13ecf713..0e8d05e00 100644 --- a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/AssertionService.java +++ b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/AssertionService.java @@ -235,7 +235,9 @@ private String getAssertionStatus(Assertion assertion) { } public boolean updateAssertionsSalesforceId(String from, String to) { - return updateAssertionsSalesforceId(from, to, true); + boolean updated = updateAssertionsSalesforceId(from, to, true); + updated = updated && orcidRecordService.updateTokenSalesforceIds(from, to); + return updated; } private boolean updateAssertionsSalesforceId(String from, String to, boolean rollback) { diff --git a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/OrcidRecordService.java b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/OrcidRecordService.java index e98fa9bda..32150f396 100644 --- a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/OrcidRecordService.java +++ b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/services/OrcidRecordService.java @@ -17,6 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; @Service @@ -117,7 +118,7 @@ public String generateLinkForEmail(String email) { String salesforceId = assertionsUserService.getLoggedInUserSalesforceId(); return generateLinkForEmailAndSalesforceId(email, salesforceId); } - + public String generateLinkForEmailAndSalesforceId(String email, String salesforceId) { String landingPageUrl = applicationProperties.getLandingPageUrl(); Optional record = orcidRecordRepository.findOneByEmail(email); @@ -178,14 +179,18 @@ public void deleteOrcidRecordTokenByEmailAndSalesforceId(String email, String sa } } } - + public boolean userHasGrantedOrDeniedPermission(String email, String salesforceId) { Optional orcidRecordOptional = findOneByEmail(email); if (orcidRecordOptional.isEmpty()) { return false; } - + return !StringUtils.isBlank(orcidRecordOptional.get().getToken(salesforceId, true)); } + public boolean updateTokenSalesforceIds(String salesforceId, String newSalesforceId) { + orcidRecordRepository.updateTokenSalesforceIds(salesforceId, newSalesforceId); + return true; + } } diff --git a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResource.java b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResource.java index 3a28cae7b..d2fd0ce44 100644 --- a/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResource.java +++ b/assertion-service/src/main/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResource.java @@ -105,7 +105,7 @@ public class AssertionResource { @Autowired private NotificationService notificationService; - + @Autowired private MemberService memberService; @@ -452,6 +452,7 @@ private String encodeUrl(String urlString) throws MalformedURLException, URISynt public ResponseEntity updateSalesforceId(@PathVariable String salesforceId, @PathVariable String newSalesforceId) { LOG.debug("REST request to update Assertions by salesforce : {}", salesforceId); boolean success = assertionService.updateAssertionsSalesforceId(salesforceId, newSalesforceId); + success = success && orcidRecordService.updateTokenSalesforceIds(salesforceId, newSalesforceId); if (success) { return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, "assertion", salesforceId)).build(); } else { diff --git a/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/services/AssertionServiceTest.java b/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/services/AssertionServiceTest.java index 1d336b123..769c2217a 100644 --- a/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/services/AssertionServiceTest.java +++ b/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/services/AssertionServiceTest.java @@ -1835,10 +1835,13 @@ void testUpdateAssertionsSalesforceId() { ; Mockito.when(assertionRepository.findBySalesforceId(Mockito.eq("salesforce-id"), Mockito.any(Pageable.class))).thenReturn(new PageImpl(firstPage)) .thenReturn(new PageImpl(secondPage)).thenReturn(new PageImpl(thirdPage)).thenReturn(new PageImpl(new ArrayList<>())); + Mockito.when(orcidRecordService.updateTokenSalesforceIds(Mockito.anyString(), Mockito.anyString())).thenReturn(true); + boolean success = assertionService.updateAssertionsSalesforceId("salesforce-id", "new-salesforce-id"); assertThat(success).isTrue(); Mockito.verify(assertionRepository, Mockito.times((AssertionService.REGISTRY_SYNC_BATCH_SIZE * 3) - 10)).save(assertionCaptor.capture()); + Mockito.verify(orcidRecordService).updateTokenSalesforceIds(Mockito.anyString(), Mockito.anyString()); List saved = assertionCaptor.getAllValues(); saved.forEach(a -> assertThat(a.getSalesforceId()).isEqualTo("new-salesforce-id")); } diff --git a/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResourceTest.java b/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResourceTest.java index 18f553251..56bfd1bd4 100644 --- a/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResourceTest.java +++ b/assertion-service/src/test/java/org/orcid/memberportal/service/assertion/web/rest/AssertionResourceTest.java @@ -86,10 +86,10 @@ class AssertionResourceTest { @Mock private RorOrgValidator rorOrgValidator; - + @Mock private MemberService memberService; - + @Mock private NotificationService notificationService; @@ -101,7 +101,7 @@ class AssertionResourceTest { @Mock private GridOrgValidator gridOrgValidator; - + @InjectMocks private AssertionResource assertionResource; @@ -115,7 +115,7 @@ public void setUp() { Mockito.when(assertionsUserService.getLoggedInUser()).thenReturn(getUser()); Mockito.when(assertionsUserService.getLoggedInUserSalesforceId()).thenReturn(DEFAULT_SALESFORCE_ID); } - + @Test void testGetAssertionOfPendingStatus() { Assertion pendingAssertion = new Assertion(); @@ -126,7 +126,7 @@ void testGetAssertionOfPendingStatus() { Mockito.verify(assertionService).findById(Mockito.eq("test")); Mockito.verify(assertionService).populatePermissionLink(Mockito.any(Assertion.class)); } - + @Test void testGetAssertionOfNotificationSentStatus() { Assertion pendingAssertion = new Assertion(); @@ -137,7 +137,7 @@ void testGetAssertionOfNotificationSentStatus() { Mockito.verify(assertionService).findById(Mockito.eq("test")); Mockito.verify(assertionService).populatePermissionLink(Mockito.any(Assertion.class)); } - + @Test void testGetAssertionOfDeniedAccessStatus() { Assertion pendingAssertion = new Assertion(); @@ -148,7 +148,7 @@ void testGetAssertionOfDeniedAccessStatus() { Mockito.verify(assertionService).findById(Mockito.eq("test")); Mockito.verify(assertionService).populatePermissionLink(Mockito.any(Assertion.class)); } - + @Test void testGetAssertionOfRevokedAccessStatus() { Assertion pendingAssertion = new Assertion(); @@ -159,7 +159,7 @@ void testGetAssertionOfRevokedAccessStatus() { Mockito.verify(assertionService).findById(Mockito.eq("test")); Mockito.verify(assertionService).populatePermissionLink(Mockito.any(Assertion.class)); } - + @Test void testGetAssertionOfInOrcidStatus() { Assertion pendingAssertion = new Assertion(); @@ -169,7 +169,7 @@ void testGetAssertionOfInOrcidStatus() { Mockito.verify(assertionService).findById(Mockito.eq("test")); Mockito.verify(assertionService, Mockito.never()).populatePermissionLink(Mockito.any(Assertion.class)); } - + @Test void testSendNotifications() { Mockito.when(assertionsUserService.getLoggedInUser()).thenReturn(getUser()); @@ -180,23 +180,23 @@ void testSendNotifications() { Mockito.verify(assertionService).markPendingAssertionsAsNotificationRequested(Mockito.eq(DEFAULT_SALESFORCE_ID)); Mockito.verify(memberService).updateMemberDefaultLanguage(Mockito.eq(DEFAULT_SALESFORCE_ID), Mockito.eq("en")); } - + @Test void testGetNotificationRequestInProgress_inProgressIsTrue() { Mockito.when(assertionsUserService.getLoggedInUserSalesforceId()).thenReturn(DEFAULT_SALESFORCE_ID); Mockito.when(notificationService.requestInProgress(Mockito.eq(DEFAULT_SALESFORCE_ID))).thenReturn(true); - + ResponseEntity response = assertionResource.getNotificationRequestInProgress(); assertTrue(response.getStatusCode().is2xxSuccessful()); assertNotNull(response.getBody()); assertTrue(response.getBody().getInProgress()); } - + @Test void testGetNotificationRequestInProgress_inProgressIsFalse() { Mockito.when(assertionsUserService.getLoggedInUserSalesforceId()).thenReturn(DEFAULT_SALESFORCE_ID); Mockito.when(notificationService.requestInProgress(Mockito.eq(DEFAULT_SALESFORCE_ID))).thenReturn(false); - + ResponseEntity response = assertionResource.getNotificationRequestInProgress(); assertTrue(response.getStatusCode().is2xxSuccessful()); assertNotNull(response.getBody()); @@ -390,14 +390,15 @@ void testGetAssertions() throws BadRequestAlertException, org.codehaus.jettison. ResponseEntity> page = assertionResource.getAssertions(Mockito.mock(Pageable.class), new HttpHeaders(), UriComponentsBuilder.newInstance(), ""); assertNotNull(page.getBody()); } - + @Test void testUpdateSalesforceId() { Mockito.when(assertionService.updateAssertionsSalesforceId(Mockito.eq("salesforce-id"), Mockito.eq("new-salesforce-id"))).thenReturn(true); + Mockito.when(orcidRecordService.updateTokenSalesforceIds(Mockito.eq("salesforce-id"), Mockito.eq("new-salesforce-id"))).thenReturn(true); ResponseEntity response = assertionResource.updateSalesforceId("salesforce-id", "new-salesforce-id"); assertTrue(response.getStatusCode().is2xxSuccessful()); } - + @Test void testUpdateSalesforceIdWithError() { Mockito.when(assertionService.updateAssertionsSalesforceId(Mockito.eq("salesforce-id"), Mockito.eq("new-salesforce-id"))).thenReturn(false); @@ -477,7 +478,7 @@ private AssertionServiceUser getUser() { user.setLangKey("en"); return user; } - + private NotificationRequest getNotificationRequest() { NotificationRequest request = new NotificationRequest(); request.setLanguage("en"); diff --git a/member-service/src/main/java/org/orcid/memberportal/service/member/client/UserServiceClient.java b/member-service/src/main/java/org/orcid/memberportal/service/member/client/UserServiceClient.java index 5f410710d..69466f997 100644 --- a/member-service/src/main/java/org/orcid/memberportal/service/member/client/UserServiceClient.java +++ b/member-service/src/main/java/org/orcid/memberportal/service/member/client/UserServiceClient.java @@ -42,4 +42,7 @@ public interface UserServiceClient { ResponseEntity deleteUser(@PathVariable("loginOrId") String loginOrId, @RequestParam(value = "noMainContactCheck", required = false) boolean noMainContactCheck); + @RequestMapping(method = RequestMethod.PUT, value = "/api/users/memberName/{salesforceId}/{newMemberName}", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + @HystrixProperty(name = "hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds", value = "50000") + ResponseEntity updateUsersMemberNames(@PathVariable("salesforceId") String salesforceId, @PathVariable("newMemberName") String newMemberName); } diff --git a/member-service/src/main/java/org/orcid/memberportal/service/member/services/MemberService.java b/member-service/src/main/java/org/orcid/memberportal/service/member/services/MemberService.java index f61cb203c..7675406a0 100644 --- a/member-service/src/main/java/org/orcid/memberportal/service/member/services/MemberService.java +++ b/member-service/src/main/java/org/orcid/memberportal/service/member/services/MemberService.java @@ -122,79 +122,84 @@ public Member createMember(Member member) { } public Member updateMember(Member member) { - MemberValidation validation = memberValidator.validate(member, userService.getLoggedInUser()); - if (!validation.isValid()) { - throw new BadRequestAlertException("Member invalid", "member", "validation.string"); - } - Optional optional = memberRepository.findById(member.getId()); - if (!optional.isPresent()) { - throw new BadRequestAlertException("Invalid id", "member", "idunavailable.string"); - } + validateMemberUpdate(member, optional); Member existingMember = optional.get(); existingMember.setClientId(member.getClientId()); - existingMember.setClientName(member.getClientName()); existingMember.setParentSalesforceId(member.getParentSalesforceId()); existingMember.setLastModifiedBy(SecurityUtils.getCurrentUserLogin().get()); existingMember.setLastModifiedDate(Instant.now()); existingMember.setAssertionServiceEnabled(member.getAssertionServiceEnabled()); existingMember.setIsConsortiumLead(member.getIsConsortiumLead()); + propagateUpdatesAndSave(member, existingMember); + + return memberRepository.save(existingMember); + } + + private void propagateUpdatesAndSave(Member member, Member existingMember) { + if (!existingMember.getSalesforceId().equals(member.getSalesforceId())) { + updateAssertionSalesforceIds(existingMember.getSalesforceId(), member.getSalesforceId()); + updateUserSalesforceIds(existingMember.getSalesforceId(), member.getSalesforceId()); + existingMember.setSalesforceId(member.getSalesforceId()); + } + + if (!member.getClientName().equals(existingMember.getClientName())) { + updateUserMemberNames(existingMember.getSalesforceId(), member.getClientName()); + existingMember.setClientName(member.getClientName()); + } + } + + private void updateUserMemberNames(String salesforceId, String newClientName) { + userService.updateUsersMemberNames(salesforceId, newClientName); + } + + private void updateAssertionSalesforceIds(String oldSalesforceId, String newSalesforceId) { + try { + // update affiliations and users associated with the member + assertionService.updateAssertionsSalesforceId(oldSalesforceId, newSalesforceId); + } catch (Exception e) { + LOG.error("Error updating assertion salesforce ids", e); + throw new RuntimeException(e); + } + + } + + private void updateUserSalesforceIds(String oldSalesforceId, String newSalesforceId) { + try { + userService.updateUsersSalesforceId(oldSalesforceId, newSalesforceId); + } catch (Exception e) { + LOG.error("Error updating users' salesforce id from {} to {}. Rolling back assertion changes", oldSalesforceId, newSalesforceId); + assertionService.updateAssertionsSalesforceId(newSalesforceId, oldSalesforceId); + throw new RuntimeException(e); + } + } + + private void validateMemberUpdate(Member member, Optional existingMember) { + MemberValidation validation = memberValidator.validate(member, userService.getLoggedInUser()); + if (!validation.isValid()) { + throw new BadRequestAlertException("Member invalid", "member", "validation.string"); + } + + if (existingMember.isEmpty()) { + throw new BadRequestAlertException("Invalid id", "member", "idunavailable.string"); + } + // Check if name changed - if (!existingMember.getClientName().equals(member.getClientName())) { + if (!existingMember.get().getClientName().equals(member.getClientName())) { Optional optionalMember = memberRepository.findByClientName(member.getClientName()); if (optionalMember.isPresent()) { throw new BadRequestAlertException("Invalid member name", "member", "memberNameUsed.string"); } } - // Check if salesforceId changed - if (!existingMember.getSalesforceId().equals(member.getSalesforceId())) { + if (!existingMember.get().getSalesforceId().equals(member.getSalesforceId())) { Optional optionalSalesforceId = memberRepository.findBySalesforceId(member.getSalesforceId()); if (optionalSalesforceId.isPresent()) { throw new BadRequestAlertException("Invalid salesForceId", "member", "salesForceIdUsed.string"); } - - String oldSalesforceId = existingMember.getSalesforceId(); - String newSalesforceId = member.getSalesforceId(); - - try { - // update affiliations and users associated with the member - assertionService.updateAssertionsSalesforceId(oldSalesforceId, newSalesforceId); - } catch (Exception e) { - LOG.error("Error updating assertion salesforce ids", e); - throw new RuntimeException(e); - } - - try { - userService.updateUsersSalesforceId(oldSalesforceId, newSalesforceId); - } catch (Exception e) { - LOG.error("Error updating users's salesforce id", e); - LOG.error("Error updating users' salesforce id from {} to {}", oldSalesforceId, newSalesforceId); - LOG.info("Attempting to perform salesforce id rollback on affiliations"); - assertionService.updateAssertionsSalesforceId(newSalesforceId, oldSalesforceId); - LOG.info("Affiliation salesforce id rollback successfull"); - throw new RuntimeException(e); - } - existingMember.setSalesforceId(member.getSalesforceId()); - - try { - return memberRepository.save(existingMember); - } catch (Exception e) { - LOG.error("Error updating member", e); - LOG.error("Error updating member's salesforce id from {} to {}", oldSalesforceId, newSalesforceId); - LOG.info("Attempting to perform salesforce id rollback on affiliations"); - assertionService.updateAssertionsSalesforceId(newSalesforceId, oldSalesforceId); - LOG.info("Affiliation salesforce id rollback successfull"); - - LOG.info("Attempting to perform salesforce id rollback on users"); - userService.updateUsersSalesforceId(newSalesforceId, oldSalesforceId); - LOG.info("User salesforce id rollback successfull"); - throw new RuntimeException(e); - } } - return memberRepository.save(existingMember); } public MemberValidation validateMember(Member member) { diff --git a/member-service/src/main/java/org/orcid/memberportal/service/member/services/UserService.java b/member-service/src/main/java/org/orcid/memberportal/service/member/services/UserService.java index 50137c1eb..b7bf31360 100644 --- a/member-service/src/main/java/org/orcid/memberportal/service/member/services/UserService.java +++ b/member-service/src/main/java/org/orcid/memberportal/service/member/services/UserService.java @@ -88,4 +88,11 @@ public void deleteUserById(String loginOrId, boolean noMainContactCheck) { } } + public void updateUsersMemberNames(String salesforceId, String newClientName) { + ResponseEntity response = userServiceClient.updateUsersMemberNames(salesforceId, newClientName); + if (!response.getStatusCode().is2xxSuccessful()) { + LOG.warn("Error updating user member names to {} for sf id {}, response code {}", newClientName, salesforceId, response.getStatusCodeValue()); + throw new RuntimeException("Failed to update users' member names"); + } + } } diff --git a/member-service/src/test/java/org/orcid/memberportal/service/member/services/MemberServiceTest.java b/member-service/src/test/java/org/orcid/memberportal/service/member/services/MemberServiceTest.java index 91be02f26..b17d947fc 100644 --- a/member-service/src/test/java/org/orcid/memberportal/service/member/services/MemberServiceTest.java +++ b/member-service/src/test/java/org/orcid/memberportal/service/member/services/MemberServiceTest.java @@ -180,6 +180,29 @@ public Member answer(InvocationOnMock invocation) throws Throwable { Mockito.verify(userService, Mockito.never()).updateUsersSalesforceId(Mockito.anyString(), Mockito.anyString()); } + @Test + void testUpdateMemberWithDuplicateName() { + Mockito.when(memberValidator.validate(Mockito.any(Member.class), Mockito.any(MemberServiceUser.class))).thenReturn(getValidValidation()); + Mockito.when(memberRepository.findById(Mockito.anyString())).thenReturn(Optional.of(getMember())); + + // return a record when name is checked against db + Mockito.when(memberRepository.findByClientName(Mockito.anyString())).thenReturn(Optional.of(getMember())); + + Member member = getMember(); + member.setId("id"); + member.setSalesforceId("three"); + member.setClientName("new client name"); + + Exception e = Assertions.assertThrows(BadRequestAlertException.class, () -> { + memberService.updateMember(member); + }); + + assertThat(e.getMessage()).isEqualTo("Invalid member name"); + + Mockito.verify(memberRepository, Mockito.never()).save(Mockito.any(Member.class)); + Mockito.verify(userService, Mockito.never()).updateUsersSalesforceId(Mockito.anyString(), Mockito.anyString()); + } + @Test void testUpdateMemberWithSalesforceIdUpdateFailure_userFailure() { Mockito.when(memberValidator.validate(Mockito.any(Member.class), Mockito.any(MemberServiceUser.class))).thenReturn(getValidValidation()); @@ -210,7 +233,7 @@ public Member answer(InvocationOnMock invocation) throws Throwable { } @Test - void testUpdateMemberWithSalesforceIdUpdateWithMemberFailure() { + void testUpdateMemberWithSalesforceIdUpdate() { Mockito.when(memberValidator.validate(Mockito.any(Member.class), Mockito.any(MemberServiceUser.class))).thenReturn(getValidValidation()); Mockito.when(memberRepository.findById(Mockito.anyString())).thenReturn(Optional.of(getMember())); Mockito.when(memberRepository.save(Mockito.any(Member.class))).thenAnswer(new Answer() { @@ -219,26 +242,22 @@ public Member answer(InvocationOnMock invocation) throws Throwable { return (Member) invocation.getArgument(0); } }); - - Mockito.doThrow(new RuntimeException()).when(memberRepository).save(Mockito.any(Member.class)); - Member member = getMember(); member.setId("id"); member.setSalesforceId("three"); - - Assertions.assertThrows(RuntimeException.class, () -> { - memberService.updateMember(member); - }); + memberService.updateMember(member); // check assertion and user changes rolled back Mockito.verify(assertionService, Mockito.times(1)).updateAssertionsSalesforceId(Mockito.eq("two"), Mockito.eq("three")); - Mockito.verify(assertionService, Mockito.times(1)).updateAssertionsSalesforceId(Mockito.eq("three"), Mockito.eq("two")); Mockito.verify(userService, Mockito.times(1)).updateUsersSalesforceId(Mockito.eq("two"), Mockito.eq("three")); - Mockito.verify(userService, Mockito.times(1)).updateUsersSalesforceId(Mockito.eq("three"), Mockito.eq("two")); + Mockito.verify(memberRepository, Mockito.times(1)).save(memberCaptor.capture()); + + Member saved = memberCaptor.getValue(); + assertThat(saved.getSalesforceId()).isEqualTo("three"); } @Test - void testUpdateMemberWithSalesforceIdUpdate() { + void testUpdateMemberWithMemberName() { Mockito.when(memberValidator.validate(Mockito.any(Member.class), Mockito.any(MemberServiceUser.class))).thenReturn(getValidValidation()); Mockito.when(memberRepository.findById(Mockito.anyString())).thenReturn(Optional.of(getMember())); Mockito.when(memberRepository.save(Mockito.any(Member.class))).thenAnswer(new Answer() { @@ -249,16 +268,15 @@ public Member answer(InvocationOnMock invocation) throws Throwable { }); Member member = getMember(); member.setId("id"); - member.setSalesforceId("three"); + member.setClientName("a new member name"); memberService.updateMember(member); // check assertion and user changes rolled back - Mockito.verify(assertionService, Mockito.times(1)).updateAssertionsSalesforceId(Mockito.eq("two"), Mockito.eq("three")); - Mockito.verify(userService, Mockito.times(1)).updateUsersSalesforceId(Mockito.eq("two"), Mockito.eq("three")); + Mockito.verify(userService, Mockito.times(1)).updateUsersMemberNames(Mockito.eq("two"), Mockito.eq("a new member name")); Mockito.verify(memberRepository, Mockito.times(1)).save(memberCaptor.capture()); Member saved = memberCaptor.getValue(); - assertThat(saved.getSalesforceId()).isEqualTo("three"); + assertThat(saved.getClientName()).isEqualTo("a new member name"); } @Test diff --git a/ui/src/app/member/member-update.component.ts b/ui/src/app/member/member-update.component.ts index 30c16e12f..b43dd7b76 100644 --- a/ui/src/app/member/member-update.component.ts +++ b/ui/src/app/member/member-update.component.ts @@ -155,7 +155,7 @@ export class MemberUpdateComponent implements OnInit { } if (sfId) { - this.editForm.get('salesforceId')?.disable() + // this.editForm.get('salesforceId')?.disable() } } diff --git a/user-service/src/main/java/org/orcid/memberportal/service/user/repository/CustomUserRepository.java b/user-service/src/main/java/org/orcid/memberportal/service/user/repository/CustomUserRepository.java new file mode 100644 index 000000000..a0247b56d --- /dev/null +++ b/user-service/src/main/java/org/orcid/memberportal/service/user/repository/CustomUserRepository.java @@ -0,0 +1,20 @@ +package org.orcid.memberportal.service.user.repository; + +import org.orcid.memberportal.service.user.domain.User; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +/** + * Spring Data MongoDB repository for the {@link User} entity. + */ +@Repository +public interface CustomUserRepository { + + boolean updateMemberNames(String salesforceId, String newMemberName); +} diff --git a/user-service/src/main/java/org/orcid/memberportal/service/user/repository/UserRepository.java b/user-service/src/main/java/org/orcid/memberportal/service/user/repository/UserRepository.java index ea043b843..a589fc378 100644 --- a/user-service/src/main/java/org/orcid/memberportal/service/user/repository/UserRepository.java +++ b/user-service/src/main/java/org/orcid/memberportal/service/user/repository/UserRepository.java @@ -14,7 +14,7 @@ * Spring Data MongoDB repository for the {@link User} entity. */ @Repository -public interface UserRepository extends MongoRepository { +public interface UserRepository extends MongoRepository, CustomUserRepository { Optional findOneByActivationKey(String activationKey); diff --git a/user-service/src/main/java/org/orcid/memberportal/service/user/repository/impl/CustomUserRepositoryImpl.java b/user-service/src/main/java/org/orcid/memberportal/service/user/repository/impl/CustomUserRepositoryImpl.java new file mode 100644 index 000000000..5f981c4b8 --- /dev/null +++ b/user-service/src/main/java/org/orcid/memberportal/service/user/repository/impl/CustomUserRepositoryImpl.java @@ -0,0 +1,28 @@ +package org.orcid.memberportal.service.user.repository.impl; + +import org.orcid.memberportal.service.user.domain.User; +import org.orcid.memberportal.service.user.repository.CustomUserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Repository; + +@Repository +public class CustomUserRepositoryImpl implements CustomUserRepository { + + + @Autowired + private MongoTemplate mongoTemplate; + + public CustomUserRepositoryImpl(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + @Override + public boolean updateMemberNames(String salesforceId, String newMemberName) { + mongoTemplate.updateMulti(Query.query(Criteria.where("salesforceId").is(salesforceId)), new Update().set("memberName", newMemberName), User.class); + return true; + } +} diff --git a/user-service/src/main/java/org/orcid/memberportal/service/user/services/UserService.java b/user-service/src/main/java/org/orcid/memberportal/service/user/services/UserService.java index 0ef743074..a935d285d 100644 --- a/user-service/src/main/java/org/orcid/memberportal/service/user/services/UserService.java +++ b/user-service/src/main/java/org/orcid/memberportal/service/user/services/UserService.java @@ -9,9 +9,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; @@ -638,4 +636,7 @@ private boolean validLong(String code) { } } + public boolean updateUsersMemberName(String salesforceId, String newMemberName) { + return userRepository.updateMemberNames(salesforceId, newMemberName); + } } diff --git a/user-service/src/main/java/org/orcid/memberportal/service/user/web/rest/UserResource.java b/user-service/src/main/java/org/orcid/memberportal/service/user/web/rest/UserResource.java index 23c96cb7f..5648d20c5 100644 --- a/user-service/src/main/java/org/orcid/memberportal/service/user/web/rest/UserResource.java +++ b/user-service/src/main/java/org/orcid/memberportal/service/user/web/rest/UserResource.java @@ -424,6 +424,26 @@ public ResponseEntity updateUsersSalesforceId(@PathVariable String salesfo } } + /** + * {@code PUT /users/memberName/:oldMemberName/:newMemberName} : Updates memberName + * for existing Users. + * + * @param salesforceId the salesforceId for finding users to update + * @param newMemberName the new Value of the memberName to update + * @return the {@link ResponseEntity} with status {@code 200 (OK)}. + */ + @PutMapping("/users/memberName/{salesforceId}/{newMemberName}") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + public ResponseEntity updateUsersMemberName(@PathVariable String salesforceId, @PathVariable String newMemberName) { + LOG.debug("REST request to update users' member names id to {}", newMemberName); + boolean success = userService.updateUsersMemberName(salesforceId, newMemberName); + if (success) { + return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, "user", salesforceId)).build(); + } else { + return ResponseEntity.status(500).build(); + } + } + /** * {@code GET /users/:saleforceId}/owner : get the "login" user. * diff --git a/user-service/src/test/java/org/orcid/memberportal/service/user/services/UserServiceTest.java b/user-service/src/test/java/org/orcid/memberportal/service/user/services/UserServiceTest.java index f9273fc88..7bf811a18 100644 --- a/user-service/src/test/java/org/orcid/memberportal/service/user/services/UserServiceTest.java +++ b/user-service/src/test/java/org/orcid/memberportal/service/user/services/UserServiceTest.java @@ -620,6 +620,16 @@ public String answer(InvocationOnMock invocation) throws Throwable { }); } + @Test + void testUpdateUsersMemberName() { + Mockito.when(userRepository.updateMemberNames(Mockito.eq("salesforce-id"), Mockito.eq("newName"))).thenReturn(true); + + boolean success = userService.updateUsersMemberName("salesforce-id", "newName"); + assertThat(success).isTrue(); + + Mockito.verify(userRepository).updateMemberNames(Mockito.eq("salesforce-id"), Mockito.eq("newName")); + } + @Test void testUpdateUsersSalesforceId() { List firstPage = getUsersForSalesforceId("salesforce-id", 0, UserService.BATCH_SIZE); diff --git a/user-service/src/test/java/org/orcid/memberportal/service/user/web/rest/UserResourceTest.java b/user-service/src/test/java/org/orcid/memberportal/service/user/web/rest/UserResourceTest.java index ef3ed6927..db42ba417 100644 --- a/user-service/src/test/java/org/orcid/memberportal/service/user/web/rest/UserResourceTest.java +++ b/user-service/src/test/java/org/orcid/memberportal/service/user/web/rest/UserResourceTest.java @@ -80,6 +80,13 @@ void testUpdateSalesforceId() { assertTrue(response.getStatusCode().is2xxSuccessful()); } + @Test + void testUpdateUsersMemberName() { + Mockito.when(userService.updateUsersMemberName(Mockito.eq("salesforce-id"), Mockito.eq("newName"))).thenReturn(true); + ResponseEntity response = userResource.updateUsersMemberName("salesforce-id", "newName"); + assertTrue(response.getStatusCode().is2xxSuccessful()); + } + @Test void testUpdateSalesforceIdWithError() { Mockito.when(userService.updateUsersSalesforceId(Mockito.eq("salesforce-id"), Mockito.eq("new-salesforce-id"))).thenReturn(false);