Skip to content

Commit 7609c92

Browse files
authored
Add tenantRoleIds and tenantRoleNames to UserSearchRequest (#213)
* Add tenantRoleIds and tenantRoleNames to UserSearchRequest and update UserServiceImpl to handle them * Fix user search test to work with Java 8 * Fix formatting for user search test * Fix mapToValuesObject with imports and map types * Update UserServiceImpl.java * Update UserServiceImpl.java * test: enhance UserServiceImplTest with new tenant role parameter search functionality * Update UserServiceImplTest.java
1 parent d495bef commit 7609c92

File tree

4 files changed

+112
-2
lines changed

4 files changed

+112
-2
lines changed

src/main/java/com/descope/model/user/request/UserSearchRequest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,6 @@ public class UserSearchRequest {
4343
/** Retrieve only users updated before the given time. */
4444
@JsonSerialize(using = InstantToMillisSerializer.class)
4545
Instant toModifiedTime;
46+
Map<String, List<String>> tenantRoleIds;
47+
Map<String, List<String>> tenantRoleNames;
4648
}

src/main/java/com/descope/sdk/mgmt/impl/UserServiceImpl.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@
6262
import com.descope.proxy.ApiProxy;
6363
import com.descope.sdk.mgmt.UserService;
6464
import com.fasterxml.jackson.core.type.TypeReference;
65+
import com.fasterxml.jackson.databind.ObjectMapper;
6566
import java.net.URI;
67+
import java.util.HashMap;
6668
import java.util.List;
6769
import java.util.Map;
6870
import org.apache.commons.collections4.CollectionUtils;
@@ -255,9 +257,18 @@ public AllUsersResponseDetails searchAll(UserSearchRequest request) throws Desco
255257
throw ServerCommonException.invalidArgument("page");
256258
}
257259

260+
Map<String, Object> payload = new ObjectMapper().convertValue(request, new TypeReference<Map<String, Object>>() {});
261+
262+
if (request.getTenantRoleIds() != null) {
263+
payload.put("tenantRoleIds", mapToValuesObject(request.getTenantRoleIds()));
264+
}
265+
if (request.getTenantRoleNames() != null) {
266+
payload.put("tenantRoleNames", mapToValuesObject(request.getTenantRoleNames()));
267+
}
268+
258269
URI composeSearchAllUri = composeSearchAllUri();
259270
ApiProxy apiProxy = getApiProxy();
260-
return apiProxy.post(composeSearchAllUri, request, AllUsersResponseDetails.class);
271+
return apiProxy.post(composeSearchAllUri, payload, AllUsersResponseDetails.class);
261272
}
262273

263274
@Override
@@ -741,4 +752,17 @@ private URI composeExpirePasswordUri() {
741752
private URI composeGenerateEmbeddedLink() {
742753
return getUri(USER_CREATE_EMBEDDED_LINK);
743754
}
755+
756+
private static Map<String, Map<String, List<String>>> mapToValuesObject(Map<String, List<String>> inputMap) {
757+
if (inputMap == null) {
758+
return null;
759+
}
760+
Map<String, Map<String, List<String>>> result = new HashMap<>();
761+
for (Map.Entry<String, List<String>> entry : inputMap.entrySet()) {
762+
if (entry.getValue() != null) {
763+
result.put(entry.getKey(), mapOf("values", entry.getValue()));
764+
}
765+
}
766+
return result.isEmpty() ? null : result;
767+
}
744768
}

src/test/java/com/descope/model/user/request/UserSearchRequestTest.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,31 @@ public void testInstantSerialization() throws JsonProcessingException {
3131
"{\"tenantIds\":[\"tenant1\"],\"roles\":[\"role1\"],\"limit\":0,\"page\":0,\"withTestUser\":null,"
3232
+ "\"testUsersOnly\":null,\"customAttributes\":null,\"statuses\":null,\"emails\":null,\"phones\":null,"
3333
+ "\"loginIds\":null,\"userIds\":null,\"ssoAppIds\":null,\"fromCreatedTime\":%d,\"toCreatedTime\":%d,"
34-
+ "\"fromModifiedTime\":%d,\"toModifiedTime\":%d}",
34+
+ "\"fromModifiedTime\":%d,\"toModifiedTime\":%d,"
35+
+ "\"tenantRoleIds\":null,\"tenantRoleNames\":null}",
3536
expectedMillis, expectedMillis, expectedMillis, expectedMillis);
3637

3738
assertEquals(expectedJson, json);
3839
}
40+
41+
@Test
42+
public void testTenantRoleIdsAndNamesSerialization() throws JsonProcessingException {
43+
ObjectMapper mapper = new ObjectMapper();
44+
UserSearchRequest request = UserSearchRequest.builder()
45+
.tenantIds(Collections.singletonList("tenant1"))
46+
.roles(Collections.singletonList("role1"))
47+
.tenantRoleIds(Collections.singletonMap("tenant1", Collections.singletonList("roleA")))
48+
.tenantRoleNames(Collections.singletonMap("tenant2", Collections.singletonList("roleX")))
49+
.build();
50+
51+
String json = mapper.writeValueAsString(request);
52+
String expectedJson = "{\"tenantIds\":[\"tenant1\"],\"roles\":[\"role1\"],\"limit\":0,\"page\":0,"
53+
+ "\"withTestUser\":null,\"testUsersOnly\":null,\"customAttributes\":null,\"statuses\":null,\"emails\":null,"
54+
+ "\"phones\":null,\"loginIds\":null,\"userIds\":null,\"ssoAppIds\":null,\"fromCreatedTime\":null,"
55+
+ "\"toCreatedTime\":null,\"fromModifiedTime\":null,\"toModifiedTime\":null,"
56+
+ "\"tenantRoleIds\":{\"tenant1\":[\"roleA\"]},"
57+
+ "\"tenantRoleNames\":{\"tenant2\":[\"roleX\"]}}";
58+
59+
assertEquals(expectedJson, json);
60+
}
3961
}

src/test/java/com/descope/sdk/mgmt/impl/UserServiceImplTest.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.junit.jupiter.api.BeforeEach;
6767
import org.junit.jupiter.api.Test;
6868
import org.junitpioneer.jupiter.RetryingTest;
69+
import org.mockito.ArgumentCaptor;
6970
import org.mockito.MockedStatic;
7071

7172
public class UserServiceImplTest {
@@ -824,6 +825,50 @@ void testSearchAllForSuccess() {
824825
}
825826
}
826827

828+
@Test
829+
void testSearchAllWithTenantRoleParams() {
830+
Map<String, List<String>> tenantRoleIds = mapOf("tenant1", Arrays.asList("roleA", "roleB"));
831+
Map<String, List<String>> tenantRoleNames = mapOf("tenant1", Arrays.asList("roleA", "roleB"));
832+
AllUsersResponseDetails allUsersResponse = mock(AllUsersResponseDetails.class);
833+
UserSearchRequest userSearchRequest = UserSearchRequest.builder()
834+
.limit(5)
835+
.page(0)
836+
.tenantRoleIds(tenantRoleIds)
837+
.tenantRoleNames(tenantRoleNames)
838+
.build();
839+
840+
ApiProxy apiProxy = mock(ApiProxy.class);
841+
doReturn(allUsersResponse).when(apiProxy).post(any(), any(), any());
842+
843+
try (MockedStatic<ApiProxyBuilder> mockedApiProxyBuilder = mockStatic(ApiProxyBuilder.class)) {
844+
mockedApiProxyBuilder.when(() -> ApiProxyBuilder.buildProxy(any(), any())).thenReturn(apiProxy);
845+
846+
userService.searchAll(userSearchRequest);
847+
848+
@SuppressWarnings("unchecked")
849+
ArgumentCaptor<Map<String, Object>> captor = ArgumentCaptor.forClass(Map.class);
850+
verify(apiProxy).post(any(), captor.capture(), any());
851+
852+
Map<String, Object> payload = captor.getValue();
853+
854+
@SuppressWarnings("unchecked")
855+
Map<String, Object> wrappedIds = (Map<String, Object>) payload.get("tenantRoleIds");
856+
assertTrue(wrappedIds.get("tenant1") instanceof Map);
857+
858+
@SuppressWarnings("unchecked")
859+
Map<String, Object> tenantIdsMap = (Map<String, Object>) wrappedIds.get("tenant1");
860+
assertEquals(Arrays.asList("roleA", "roleB"), (tenantIdsMap.get("values")));
861+
862+
@SuppressWarnings("unchecked")
863+
Map<String, Object> wrappedNames = (Map<String, Object>) payload.get("tenantRoleNames");
864+
assertTrue(wrappedNames.get("tenant1") instanceof Map);
865+
866+
@SuppressWarnings("unchecked")
867+
Map<String, Object> tenantNamesMap = (Map<String, Object>) wrappedNames.get("tenant1");
868+
assertEquals(Arrays.asList("roleA", "roleB"), (tenantNamesMap.get("values")));
869+
}
870+
}
871+
827872
@Test
828873
void testSearchAllForInvalidLimit() {
829874
ServerCommonException thrown = assertThrows(ServerCommonException.class,
@@ -1003,6 +1048,23 @@ void testFunctionalUserWithTenantAndRole() {
10031048
user = updateResponse.getUser();
10041049
assertNotNull(user);
10051050
assertThat(user.getRoleNames()).containsExactly(roleName);
1051+
// Patch
1052+
UserResponseDetails patchResponse = userService.patch(loginId,
1053+
PatchUserRequest.builder()
1054+
.userTenants(
1055+
Arrays.asList(AssociatedTenant.builder()
1056+
.tenantId(tenantId).roleNames(Arrays.asList(roleName)).build())).build());
1057+
user = patchResponse.getUser();
1058+
assertNotNull(user);
1059+
assertThat(user.getUserTenants()).containsExactly(AssociatedTenant.builder().tenantId(tenantId)
1060+
.tenantName(tenantName).roleNames(Arrays.asList(roleName)).build());
1061+
// Search
1062+
AllUsersResponseDetails searchByTenantRoleNames = userService.searchAll(
1063+
UserSearchRequest.builder()
1064+
.tenantRoleNames(mapOf(tenantId, Arrays.asList(roleName))).build());
1065+
boolean foundByRoleName = searchByTenantRoleNames.getUsers().stream()
1066+
.anyMatch(u -> u.getUserId().equals(createResponse.getUser().getUserId()));
1067+
assertTrue(foundByRoleName);
10061068
// Delete
10071069
userService.delete(loginId);
10081070
tenantService.delete(tenantId);

0 commit comments

Comments
 (0)