Skip to content

Commit c0548b8

Browse files
fix: filter user groups by env scope in query parameter
1 parent d72e30f commit c0548b8

File tree

5 files changed

+300
-22
lines changed

5 files changed

+300
-22
lines changed

gravitee-apim-rest-api/gravitee-apim-rest-api-management/gravitee-apim-rest-api-management-rest/src/main/java/io/gravitee/rest/api/management/rest/resource/organization/UserResource.java

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import java.util.HashMap;
4848
import java.util.List;
4949
import java.util.Set;
50+
import org.slf4j.Logger;
51+
import org.slf4j.LoggerFactory;
5052

5153
/**
5254
* Defines the REST resources to manage Users.
@@ -60,6 +62,8 @@
6062
@Tag(name = "Users")
6163
public class UserResource extends AbstractResource {
6264

65+
private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class);
66+
6367
@Context
6468
private ResourceContext resourceContext;
6569

@@ -120,31 +124,30 @@ public Response deleteUser() {
120124
@ApiResponse(responseCode = "404", description = "User not found")
121125
@ApiResponse(responseCode = "500", description = "Internal server error")
122126
@Permissions(@Permission(value = RolePermission.ORGANIZATION_USERS, acls = RolePermissionAction.READ))
123-
public List<UserGroupEntity> getUserGroups() {
127+
public List<UserGroupEntity> getUserGroups(@QueryParam("q") String query) {
124128
// Check that user belongs to current organization
125129
userService.findById(GraviteeContext.getExecutionContext(), userId);
130+
LOGGER.debug("Search groups for user: {} with query: {}", userId, query);
131+
Set<GroupEntity> groups = groupService.findByUserAndEnvironment(userId, query);
132+
List<UserGroupEntity> result = new ArrayList<>();
133+
groups.forEach(groupEntity -> {
134+
UserGroupEntity userGroupEntity = new UserGroupEntity();
135+
userGroupEntity.setId(groupEntity.getId());
136+
userGroupEntity.setName(groupEntity.getName());
137+
userGroupEntity.setRoles(new HashMap<>());
138+
Set<RoleEntity> roles = membershipService.getRoles(
139+
MembershipReferenceType.GROUP,
140+
groupEntity.getId(),
141+
MembershipMemberType.USER,
142+
userId
143+
);
144+
if (!roles.isEmpty()) {
145+
roles.forEach(role -> userGroupEntity.getRoles().put(role.getScope().name(), role.getName()));
146+
}
147+
result.add(userGroupEntity);
148+
});
126149

127-
List<UserGroupEntity> groups = new ArrayList<>();
128-
groupService
129-
.findByUser(userId)
130-
.forEach(groupEntity -> {
131-
UserGroupEntity userGroupEntity = new UserGroupEntity();
132-
userGroupEntity.setId(groupEntity.getId());
133-
userGroupEntity.setName(groupEntity.getName());
134-
userGroupEntity.setRoles(new HashMap<>());
135-
Set<RoleEntity> roles = membershipService.getRoles(
136-
MembershipReferenceType.GROUP,
137-
groupEntity.getId(),
138-
MembershipMemberType.USER,
139-
userId
140-
);
141-
if (!roles.isEmpty()) {
142-
roles.forEach(role -> userGroupEntity.getRoles().put(role.getScope().name(), role.getName()));
143-
}
144-
groups.add(userGroupEntity);
145-
});
146-
147-
return groups;
150+
return result;
148151
}
149152

150153
@GET
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright © 2015 The Gravitee team (http://gravitee.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.gravitee.rest.api.management.rest.resource;
17+
18+
import static org.junit.Assert.*;
19+
import static org.mockito.ArgumentMatchers.*;
20+
import static org.mockito.Mockito.*;
21+
22+
import io.gravitee.rest.api.management.rest.resource.organization.UserResource;
23+
import io.gravitee.rest.api.model.*;
24+
import io.gravitee.rest.api.service.GroupService;
25+
import io.gravitee.rest.api.service.MembershipService;
26+
import io.gravitee.rest.api.service.UserService;
27+
import io.gravitee.rest.api.service.common.ExecutionContext;
28+
import java.lang.reflect.Field;
29+
import java.util.*;
30+
import org.junit.Before;
31+
import org.junit.Test;
32+
import org.junit.runner.RunWith;
33+
import org.mockito.InjectMocks;
34+
import org.mockito.Mock;
35+
import org.mockito.junit.MockitoJUnitRunner;
36+
37+
/**
38+
* Test for UserResource.getUserGroups() method
39+
*/
40+
@RunWith(MockitoJUnitRunner.class)
41+
public class UserResourceTest {
42+
43+
private static final String USER_ID = "test-user";
44+
private static final String ENV_ID = "test-env";
45+
46+
@Mock
47+
private UserService userService;
48+
49+
@Mock
50+
private GroupService groupService;
51+
52+
@Mock
53+
private MembershipService membershipService;
54+
55+
@InjectMocks
56+
private UserResource userResource;
57+
58+
@Before
59+
public void setUp() throws Exception {
60+
Field userIdField = UserResource.class.getDeclaredField("userId");
61+
userIdField.setAccessible(true);
62+
userIdField.set(userResource, USER_ID);
63+
}
64+
65+
@Test
66+
public void shouldReturnAllGroupsWhenQueryIsNull() {
67+
GroupEntity group1 = new GroupEntity();
68+
group1.setId("group1");
69+
group1.setName("Group 1");
70+
71+
GroupEntity group2 = new GroupEntity();
72+
group2.setId("group2");
73+
group2.setName("Group 2");
74+
75+
when(userService.findById(any(ExecutionContext.class), eq(USER_ID))).thenReturn(new UserEntity());
76+
when(groupService.findByUserAndEnvironment(USER_ID, null)).thenReturn(Set.of(group1, group2));
77+
when(membershipService.getRoles(any(), any(), any(), any())).thenReturn(Collections.emptySet());
78+
List<UserGroupEntity> result = userResource.getUserGroups(null);
79+
assertEquals(2, result.size());
80+
verify(groupService).findByUserAndEnvironment(USER_ID, null);
81+
}
82+
83+
@Test
84+
public void shouldReturnAllGroupsWhenQueryIsEmpty() {
85+
GroupEntity group = new GroupEntity();
86+
group.setId("group1");
87+
group.setName("Group 1");
88+
89+
when(userService.findById(any(ExecutionContext.class), eq(USER_ID))).thenReturn(new UserEntity());
90+
when(groupService.findByUserAndEnvironment(USER_ID, "")).thenReturn(Set.of(group));
91+
when(membershipService.getRoles(any(), any(), any(), any())).thenReturn(Collections.emptySet());
92+
List<UserGroupEntity> result = userResource.getUserGroups("");
93+
assertEquals(1, result.size());
94+
verify(groupService).findByUserAndEnvironment(USER_ID, "");
95+
}
96+
97+
@Test
98+
public void shouldFilterGroupsByEnvironmentWhenQueryProvided() {
99+
GroupEntity envGroup = new GroupEntity();
100+
envGroup.setId("env-group");
101+
envGroup.setName("Env Group");
102+
103+
when(userService.findById(any(ExecutionContext.class), eq(USER_ID))).thenReturn(new UserEntity());
104+
when(groupService.findByUserAndEnvironment(USER_ID, ENV_ID)).thenReturn(Set.of(envGroup));
105+
when(membershipService.getRoles(any(), any(), any(), any())).thenReturn(Collections.emptySet());
106+
List<UserGroupEntity> result = userResource.getUserGroups(ENV_ID);
107+
108+
assertEquals(1, result.size());
109+
assertEquals("env-group", result.get(0).getId());
110+
assertEquals("Env Group", result.get(0).getName());
111+
verify(groupService).findByUserAndEnvironment(USER_ID, ENV_ID);
112+
verify(groupService, never()).findByUser(any());
113+
}
114+
115+
@Test
116+
public void shouldReturnEmptyListWhenUserHasNoGroups() {
117+
// Given
118+
when(userService.findById(any(ExecutionContext.class), eq(USER_ID))).thenReturn(new UserEntity());
119+
List<UserGroupEntity> result = userResource.getUserGroups(null);
120+
assertTrue(result.isEmpty());
121+
verify(membershipService, never()).getRoles(any(), any(), any(), any());
122+
}
123+
}

gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/GroupService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public interface GroupService {
4949
List<GroupEntity> findByName(final String environmentId, String name);
5050

5151
Set<GroupEntity> findByUser(String username);
52+
Set<GroupEntity> findByUserAndEnvironment(String username, String environmentId);
5253
List<ApiEntity> getApis(final String environmentId, String groupId);
5354
List<ApplicationEntity> getApplications(String groupId);
5455
int getNumberOfMembers(ExecutionContext executionContext, String groupId);

gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/GroupServiceImpl.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,34 @@ public Set<GroupEntity> findByUser(String user) {
907907
}
908908
}
909909

910+
@Override
911+
public Set<GroupEntity> findByUserAndEnvironment(String user, String environmentId) {
912+
Set<String> userGroups = membershipService
913+
.getMembershipsByMemberAndReference(MembershipMemberType.USER, user, MembershipReferenceType.GROUP)
914+
.stream()
915+
.map(MembershipEntity::getReferenceId)
916+
.collect(Collectors.toSet());
917+
918+
try {
919+
Set<Group> allGroups = groupRepository.findByIds(userGroups);
920+
Set<GroupEntity> filteredGroups = allGroups
921+
.stream()
922+
.filter(group -> environmentId == null || environmentId.equals(group.getEnvironmentId()))
923+
.map(this::map)
924+
.collect(Collectors.toSet());
925+
926+
logger.debug(
927+
"After filtering by environment '{}': {} groups remain: {}",
928+
environmentId,
929+
filteredGroups.size(),
930+
filteredGroups.stream().map(GroupEntity::getName).collect(Collectors.toList())
931+
);
932+
return filteredGroups;
933+
} catch (TechnicalException ex) {
934+
throw new TechnicalManagementException("An error occurs while trying to find user groups for environment " + environmentId, ex);
935+
}
936+
}
937+
910938
@Override
911939
public List<ApiEntity> getApis(final String environmentId, String groupId) {
912940
return apiRepository
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright © 2015 The Gravitee team (http://gravitee.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.gravitee.rest.api.service.impl;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.mockito.Mockito.when;
20+
21+
import io.gravitee.repository.exceptions.TechnicalException;
22+
import io.gravitee.repository.management.api.GroupRepository;
23+
import io.gravitee.repository.management.model.Group;
24+
import io.gravitee.rest.api.model.GroupEntity;
25+
import io.gravitee.rest.api.model.MembershipEntity;
26+
import io.gravitee.rest.api.model.MembershipMemberType;
27+
import io.gravitee.rest.api.model.MembershipReferenceType;
28+
import io.gravitee.rest.api.service.MembershipService;
29+
import java.util.Arrays;
30+
import java.util.Collections;
31+
import java.util.HashSet;
32+
import java.util.Set;
33+
import org.junit.Test;
34+
import org.junit.runner.RunWith;
35+
import org.mockito.InjectMocks;
36+
import org.mockito.Mock;
37+
import org.mockito.junit.MockitoJUnitRunner;
38+
39+
@RunWith(MockitoJUnitRunner.class)
40+
public class GroupService_FindByUserAndEnvironmentTest {
41+
42+
@InjectMocks
43+
private final GroupServiceImpl groupService = new GroupServiceImpl();
44+
45+
@Mock
46+
private GroupRepository groupRepository;
47+
48+
@Mock
49+
private MembershipService membershipService;
50+
51+
@Test
52+
public void shouldReturnGroupsForUserInEnvironment() throws TechnicalException {
53+
String userId = "user1";
54+
String envId = "env1";
55+
Group group1 = Group.builder().id("g1").environmentId(envId).name("Group1").build();
56+
Group group2 = Group.builder().id("g2").environmentId("env2").name("Group2").build();
57+
Group group3 = Group.builder().id("g3").environmentId(envId).name("Group3").build();
58+
Set<String> userGroups = new HashSet<>(Arrays.asList("g1", "g2", "g3"));
59+
when(
60+
membershipService.getMembershipsByMemberAndReference(MembershipMemberType.USER, userId, MembershipReferenceType.GROUP)
61+
).thenReturn(
62+
new HashSet<>(
63+
Arrays.asList(
64+
MembershipEntity.builder().id("m1").referenceId("g1").build(),
65+
MembershipEntity.builder().id("m2").referenceId("g2").build(),
66+
MembershipEntity.builder().id("m3").referenceId("g3").build()
67+
)
68+
)
69+
);
70+
when(groupRepository.findByIds(userGroups)).thenReturn(Set.of(group1, group2, group3));
71+
Set<GroupEntity> result = groupService.findByUserAndEnvironment(userId, envId);
72+
assertThat(result).hasSize(2);
73+
assertThat(result.stream().map(GroupEntity::getName)).containsExactlyInAnyOrder("Group1", "Group3");
74+
}
75+
76+
@Test
77+
public void shouldReturnEmptyForUserWithNoGroupsInEnv() throws TechnicalException {
78+
String userId = "user2";
79+
String envId = "env1";
80+
Group group1 = Group.builder().id("g1").environmentId("env2").name("Group2").build();
81+
Set<String> userGroups = Collections.singleton("g1");
82+
when(
83+
membershipService.getMembershipsByMemberAndReference(MembershipMemberType.USER, userId, MembershipReferenceType.GROUP)
84+
).thenReturn(new HashSet<>(Collections.singletonList(MembershipEntity.builder().id("m4").referenceId("g1").build())));
85+
when(groupRepository.findByIds(userGroups)).thenReturn(Set.of(group1));
86+
Set<GroupEntity> result = groupService.findByUserAndEnvironment(userId, envId);
87+
assertThat(result).isEmpty();
88+
}
89+
90+
@Test
91+
public void shouldReturnEmptyForNonExistentUserOrEnv() throws TechnicalException {
92+
String userId = "nouser";
93+
String envId = "noenv";
94+
when(
95+
membershipService.getMembershipsByMemberAndReference(MembershipMemberType.USER, userId, MembershipReferenceType.GROUP)
96+
).thenReturn(new HashSet<>());
97+
when(groupRepository.findByIds(Collections.emptySet())).thenReturn(Set.of());
98+
Set<GroupEntity> result = groupService.findByUserAndEnvironment(userId, envId);
99+
assertThat(result).isEmpty();
100+
}
101+
102+
@Test
103+
public void shouldReturnAllGroupsIfEnvIdIsNull() throws TechnicalException {
104+
String userId = "user3";
105+
Group group1 = Group.builder().id("g1").environmentId("env1").name("Group1").build();
106+
Group group2 = Group.builder().id("g2").environmentId("env2").name("Group2").build();
107+
Set<String> userGroups = new HashSet<>(Arrays.asList("g1", "g2"));
108+
when(
109+
membershipService.getMembershipsByMemberAndReference(MembershipMemberType.USER, userId, MembershipReferenceType.GROUP)
110+
).thenReturn(
111+
new HashSet<>(
112+
Arrays.asList(
113+
MembershipEntity.builder().id("m5").referenceId("g1").build(),
114+
MembershipEntity.builder().id("m6").referenceId("g2").build()
115+
)
116+
)
117+
);
118+
when(groupRepository.findByIds(userGroups)).thenReturn(Set.of(group1, group2));
119+
Set<GroupEntity> result = groupService.findByUserAndEnvironment(userId, null);
120+
assertThat(result).hasSize(2);
121+
assertThat(result.stream().map(GroupEntity::getName)).containsExactlyInAnyOrder("Group1", "Group2");
122+
}
123+
}

0 commit comments

Comments
 (0)