diff --git a/src/main/java/com/descope/sdk/mgmt/UserService.java b/src/main/java/com/descope/sdk/mgmt/UserService.java index e096f281..65a2edd2 100644 --- a/src/main/java/com/descope/sdk/mgmt/UserService.java +++ b/src/main/java/com/descope/sdk/mgmt/UserService.java @@ -236,6 +236,22 @@ public interface UserService { UserResponseDetails updateEmail(String loginId, String email, Boolean isVerified) throws DescopeException; + /** + * Update the email address for an existing user. + * + * @param loginId The loginID is required. + * @param email The email parameter can be empty in which case the email will be removed. + * @param isVerified The isVerified flag must be true for the user to be able to login with the + * email address. + * @param failOnConflict If true, the call will fail with an error instead of silently deleting + * and merging another user that already has this email address. + * @return {@link UserResponseDetails UserResponseDetails} + * @throws DescopeException If there occurs any exception, a subtype of this exception will be + * thrown. + */ + UserResponseDetails updateEmail(String loginId, String email, Boolean isVerified, Boolean failOnConflict) + throws DescopeException; + /** * Update the email address for an existing user. * @@ -250,6 +266,22 @@ UserResponseDetails updateEmail(String loginId, String email, Boolean isVerified UserResponseDetails updatePhone(String loginId, String phone, Boolean isVerified) throws DescopeException; + /** + * Update the email address for an existing user. + * + * @param loginId The loginID is required. + * @param phone The phone parameter can be empty in which case the phone will be removed. + * @param isVerified The isVerified flag must be true for the user to be able to login with the + * email address. + * @param failOnConflict If true, the call will fail with an error instead of silently deleting + * and merging another user that already has this phone number. + * @return {@link UserResponseDetails UserResponseDetails} + * @throws DescopeException If there occurs any exception, a subtype of this exception will be + * thrown. + */ + UserResponseDetails updatePhone(String loginId, String phone, Boolean isVerified, Boolean failOnConflict) + throws DescopeException; + /** * Update an existing user's display name (i.e., their full name). * diff --git a/src/main/java/com/descope/sdk/mgmt/impl/UserServiceImpl.java b/src/main/java/com/descope/sdk/mgmt/impl/UserServiceImpl.java index 47cc8159..a73109de 100644 --- a/src/main/java/com/descope/sdk/mgmt/impl/UserServiceImpl.java +++ b/src/main/java/com/descope/sdk/mgmt/impl/UserServiceImpl.java @@ -382,22 +382,36 @@ public UserResponseDetails deactivate(String loginId) throws DescopeException { @Override public UserResponseDetails updateEmail(String loginId, String email, Boolean isVerified) throws DescopeException { + return updateEmail(loginId, email, isVerified, null); + } + + @Override + public UserResponseDetails updateEmail(String loginId, String email, Boolean isVerified, Boolean failOnConflict) + throws DescopeException { if (StringUtils.isBlank(loginId)) { throw ServerCommonException.invalidArgument("Login ID"); } URI updateEmailUri = composeUpdateEmailUri(); Map request = mapOf("loginId", loginId, "email", email, "verified", isVerified); + addIfNotNull(request, "failOnConflict", failOnConflict); ApiProxy apiProxy = getApiProxy(); return apiProxy.post(updateEmailUri, request, UserResponseDetails.class); } @Override public UserResponseDetails updatePhone(String loginId, String phone, Boolean isVerified) throws DescopeException { + return updatePhone(loginId, phone, isVerified, null); + } + + @Override + public UserResponseDetails updatePhone(String loginId, String phone, Boolean isVerified, Boolean failOnConflict) + throws DescopeException { if (StringUtils.isBlank(loginId)) { throw ServerCommonException.invalidArgument("Login ID"); } URI updatePhoneUri = composeUpdatePhoneUri(); Map request = mapOf("loginId", loginId, "phone", phone, "verified", isVerified); + addIfNotNull(request, "failOnConflict", failOnConflict); ApiProxy apiProxy = getApiProxy(); return apiProxy.post(updatePhoneUri, request, UserResponseDetails.class); } diff --git a/src/test/java/com/descope/sdk/mgmt/impl/UserServiceImplTest.java b/src/test/java/com/descope/sdk/mgmt/impl/UserServiceImplTest.java index 6d6400d0..bbb82b4b 100644 --- a/src/test/java/com/descope/sdk/mgmt/impl/UserServiceImplTest.java +++ b/src/test/java/com/descope/sdk/mgmt/impl/UserServiceImplTest.java @@ -72,6 +72,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.RetryingTest; +import org.mockito.ArgumentCaptor; import org.mockito.MockedStatic; public class UserServiceImplTest { @@ -367,6 +368,21 @@ void testUpdateEmailForSuccess() { } } + @Test + void testUpdateEmailWithFailOnConflictForSuccess() { + UserResponseDetails userResponseDetails = mock(UserResponseDetails.class); + ApiProxy apiProxy = mock(ApiProxy.class); + doReturn(userResponseDetails).when(apiProxy).post(any(), any(), any()); + try (MockedStatic mockedApiProxyBuilder = mockStatic(ApiProxyBuilder.class)) { + mockedApiProxyBuilder.when(() -> ApiProxyBuilder.buildProxy(any(), any())).thenReturn(apiProxy); + UserResponseDetails response = userService.updateEmail("someLoginId", "someEmail", false, true); + Assertions.assertThat(response).isNotNull(); + ArgumentCaptor> captor = ArgumentCaptor.forClass(Map.class); + verify(apiProxy).post(any(), captor.capture(), any()); + assertEquals(true, captor.getValue().get("failOnConflict")); + } + } + @Test void testUpdatePhoneForEmptyLoginId() { ServerCommonException thrown = assertThrows(ServerCommonException.class, @@ -387,6 +403,21 @@ void testUpdatePhoneForSuccess() { } } + @Test + void testUpdatePhoneWithFailOnConflictForSuccess() { + UserResponseDetails userResponseDetails = mock(UserResponseDetails.class); + ApiProxy apiProxy = mock(ApiProxy.class); + doReturn(userResponseDetails).when(apiProxy).post(any(), any(), any()); + try (MockedStatic mockedApiProxyBuilder = mockStatic(ApiProxyBuilder.class)) { + mockedApiProxyBuilder.when(() -> ApiProxyBuilder.buildProxy(any(), any())).thenReturn(apiProxy); + UserResponseDetails response = userService.updatePhone("someLoginId", "1234567890", false, true); + Assertions.assertThat(response).isNotNull(); + ArgumentCaptor> captor = ArgumentCaptor.forClass(Map.class); + verify(apiProxy).post(any(), captor.capture(), any()); + assertEquals(true, captor.getValue().get("failOnConflict")); + } + } + @Test void testUpdateDisplayNameForEmptyLoginId() { ServerCommonException thrown = assertThrows(ServerCommonException.class,