Skip to content

Commit bfed265

Browse files
authored
Merge pull request #2169 from siemens/feat/PaginationForUsers
fix(rest) : adding pagination for listing users endpoint Reviewed by: [email protected] Tested by: [email protected]
2 parents 471856d + c0db06a commit bfed265

File tree

4 files changed

+89
-6
lines changed

4 files changed

+89
-6
lines changed

libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/resourcelists/ResourceComparatorGenerator.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest;
2727
import org.eclipse.sw360.datahandler.thrift.packages.Package;
2828
import org.eclipse.sw360.datahandler.thrift.projects.Project;
29+
import org.eclipse.sw360.datahandler.thrift.users.User;
2930
import org.eclipse.sw360.datahandler.thrift.search.SearchResult;
3031
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityDTO;
3132
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.Vulnerability;
@@ -34,6 +35,7 @@ public class ResourceComparatorGenerator<T> {
3435

3536
private static final Map<Component._Fields, Comparator<Component>> componentMap = generateComponentMap();
3637
private static final Map<Project._Fields, Comparator<Project>> projectMap = generateProjectMap();
38+
private static final Map<User._Fields, Comparator<User>> userMap = generateUserMap();
3739
private static final Map<Release._Fields, Comparator<Release>> releaseMap = generateReleaseMap();
3840
private static final Map<Package._Fields, Comparator<Package>> packageMap = generatePackageMap();
3941
private static final Map<SearchResult._Fields, Comparator<SearchResult>> searchResultMap = generateSearchResultMap();
@@ -61,6 +63,13 @@ private static Map<Project._Fields, Comparator<Project>> generateProjectMap() {
6163
return Collections.unmodifiableMap(projectMap);
6264
}
6365

66+
private static Map<User._Fields, Comparator<User>> generateUserMap() {
67+
Map<User._Fields, Comparator<User>> userMap = new HashMap<>();
68+
userMap.put(User._Fields.FULLNAME, Comparator.comparing(User::getFullname, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
69+
userMap.put(User._Fields.EMAIL, Comparator.comparing(User::getEmail, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
70+
return Collections.unmodifiableMap(userMap);
71+
}
72+
6473
private static Map<Release._Fields, Comparator<Release>> generateReleaseMap() {
6574
Map<Release._Fields, Comparator<Release>> releaseMap = new HashMap<>();
6675
releaseMap.put(Release._Fields.NAME, Comparator.comparing(Release::getName, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
@@ -124,6 +133,8 @@ public Comparator<T> generateComparator(String type) throws ResourceClassNotFoun
124133
return (Comparator<T>)defaultComponentComparator();
125134
case SW360Constants.TYPE_PROJECT:
126135
return (Comparator<T>)defaultProjectComparator();
136+
case SW360Constants.TYPE_USER:
137+
return (Comparator<T>)defaultUserComparator();
127138
case SW360Constants.TYPE_RELEASE:
128139
return (Comparator<T>)defaultReleaseComparator();
129140
case SW360Constants.TYPE_SEARCHRESULT:
@@ -167,6 +178,15 @@ public Comparator<T> generateComparator(String type, List<String> properties) th
167178
}
168179
}
169180
return generateProjectComparatorWithFields(type, projectFields);
181+
case SW360Constants.TYPE_USER:
182+
List<User._Fields> userFields = new ArrayList<>();
183+
for(String property:properties) {
184+
User._Fields field = User._Fields.findByName(property);
185+
if (field != null) {
186+
userFields.add(field);
187+
}
188+
}
189+
return generateUserComparatorWithFields(type, userFields);
170190
case SW360Constants.TYPE_RELEASE:
171191
List<Release._Fields> releaeFields = new ArrayList<>();
172192
for(String property:properties) {
@@ -244,6 +264,15 @@ public Comparator<T> generateProjectComparatorWithFields(String type, List<Proje
244264
}
245265
}
246266

267+
public Comparator<T> generateUserComparatorWithFields(String type, List<User._Fields> fields) throws ResourceClassNotFoundException {
268+
switch (type) {
269+
case SW360Constants.TYPE_USER:
270+
return (Comparator<T>)userComparator(fields);
271+
default:
272+
throw new ResourceClassNotFoundException("No comparator for resource class with name " + type);
273+
}
274+
}
275+
247276
public Comparator<T> generateReleaseComparatorWithFields(String type, List<Release._Fields> fields) throws ResourceClassNotFoundException {
248277
switch (type) {
249278
case SW360Constants.TYPE_RELEASE:
@@ -323,6 +352,18 @@ private Comparator<Project> projectComparator(List<Project._Fields> fields) {
323352
return comparator;
324353
}
325354

355+
private Comparator<User> userComparator(List<User._Fields> fields) {
356+
Comparator<User> comparator = Comparator.comparing(x -> true);
357+
for (User._Fields field:fields) {
358+
Comparator<User> fieldComparator = userMap.get(field);
359+
if(fieldComparator != null) {
360+
comparator = comparator.thenComparing(fieldComparator);
361+
}
362+
}
363+
comparator = comparator.thenComparing(defaultUserComparator());
364+
return comparator;
365+
}
366+
326367
private Comparator<Release> releaseComparator(List<Release._Fields> fields) {
327368
Comparator<Release> comparator = Comparator.comparing(x -> true);
328369
for (Release._Fields field:fields) {
@@ -403,6 +444,10 @@ private Comparator<Project> defaultProjectComparator() {
403444
return projectMap.get(Project._Fields.NAME);
404445
}
405446

447+
private Comparator<User> defaultUserComparator() {
448+
return userMap.get(User._Fields.EMAIL);
449+
}
450+
406451
private Comparator<Release> defaultReleaseComparator() {
407452
return releaseMap.get(Release._Fields.NAME);
408453
}

rest/resource-server/src/docs/asciidoc/users.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ The Users resource is used to get and list users.
1919

2020
A `GET` request will list all of the service's users.
2121

22+
===== Request parameter
23+
include::{snippets}/should_document_get_users/request-parameters.adoc[]
24+
2225
===== Response structure
2326
include::{snippets}/should_document_get_users/response-fields.adoc[]
2427

rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/user/UserController.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818

1919
import org.apache.thrift.TException;
2020
import org.eclipse.sw360.datahandler.common.CommonUtils;
21+
import org.eclipse.sw360.datahandler.common.SW360Constants;
22+
import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException;
23+
import org.eclipse.sw360.datahandler.resourcelists.PaginationParameterException;
24+
import org.eclipse.sw360.datahandler.resourcelists.PaginationResult;
2125
import org.eclipse.sw360.datahandler.thrift.users.User;
2226
import org.eclipse.sw360.rest.resourceserver.core.HalResource;
2327
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
@@ -35,8 +39,11 @@
3539
import org.springframework.web.bind.annotation.*;
3640
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
3741

42+
import org.springframework.data.domain.Pageable;
43+
import javax.servlet.http.HttpServletRequest;
3844
import java.io.UnsupportedEncodingException;
3945
import java.net.URI;
46+
import java.net.URISyntaxException;
4047
import java.net.URLDecoder;
4148
import java.util.ArrayList;
4249
import java.util.List;
@@ -69,18 +76,29 @@ public class UserController implements RepresentationModelProcessor<RepositoryLi
6976
tags = {"Users"}
7077
)
7178
@RequestMapping(value = USERS_URL, method = RequestMethod.GET)
72-
public ResponseEntity<CollectionModel<EntityModel<User>>> getUsers() {
79+
public ResponseEntity<CollectionModel<EntityModel<User>>> getUsers(
80+
Pageable pageable,
81+
HttpServletRequest request
82+
) throws TException, URISyntaxException, PaginationParameterException, ResourceClassNotFoundException {
7383
List<User> sw360Users = userService.getAllUsers();
7484

85+
PaginationResult<User> paginationResult = restControllerHelper.createPaginationResult(request, pageable, sw360Users, SW360Constants.TYPE_USER);
7586
List<EntityModel<User>> userResources = new ArrayList<>();
76-
for (User sw360User : sw360Users) {
87+
for (User sw360User : paginationResult.getResources()) {
7788
User embeddedUser = restControllerHelper.convertToEmbeddedGetUsers(sw360User);
7889
EntityModel<User> userResource = EntityModel.of(embeddedUser);
7990
userResources.add(userResource);
8091
}
8192

82-
CollectionModel<EntityModel<User>> resources = CollectionModel.of(userResources);
83-
return new ResponseEntity<>(resources, HttpStatus.OK);
93+
CollectionModel<EntityModel<User>> resources;
94+
if (sw360Users.size() == 0) {
95+
resources = restControllerHelper.emptyPageResource(User.class, paginationResult);
96+
} else {
97+
resources = restControllerHelper.generatePagesResource(paginationResult, userResources);
98+
}
99+
100+
HttpStatus status = resources == null ? HttpStatus.NO_CONTENT : HttpStatus.OK;
101+
return new ResponseEntity<>(resources, status);
84102
}
85103

86104
// '/users/{xyz}' searches by email, as opposed to by id, as is customary,

rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/UserSpecTest.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
4242
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
4343
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
44+
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
45+
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
4446

4547
@RunWith(SpringJUnit4ClassRunner.class)
4648
public class UserSpecTest extends TestRestDocsSpecBase {
@@ -109,11 +111,21 @@ public void should_document_get_users() throws Exception {
109111
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);
110112
mockMvc.perform(get("/api/users")
111113
.header("Authorization", "Bearer " + accessToken)
114+
.param("page", "0")
115+
.param("page_entries", "5")
116+
.param("sort", "email,desc")
112117
.accept(MediaTypes.HAL_JSON))
113118
.andExpect(status().isOk())
114119
.andDo(this.documentationHandler.document(
120+
requestParameters(
121+
parameterWithName("page").description("Page of users"),
122+
parameterWithName("page_entries").description("Amount of users per page"),
123+
parameterWithName("sort").description("Defines order of the users")
124+
),
115125
links(
116-
linkWithRel("curies").description("Curies are used for online documentation")
126+
linkWithRel("curies").description("Curies are used for online documentation"),
127+
linkWithRel("first").description("Link to first page"),
128+
linkWithRel("last").description("Link to last page")
117129
),
118130
responseFields(
119131
subsectionWithPath("_embedded.sw360:users[]email").description("The user's email"),
@@ -123,7 +135,12 @@ public void should_document_get_users() throws Exception {
123135
subsectionWithPath("_embedded.sw360:users[]givenName").description("The user's given name"),
124136
subsectionWithPath("_embedded.sw360:users[]lastName").description("The user's last name"),
125137
subsectionWithPath("_embedded.sw360:users").description("An array of <<resources-users, User resources>>"),
126-
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
138+
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources"),
139+
fieldWithPath("page").description("Additional paging information"),
140+
fieldWithPath("page.size").description("Number of users per page"),
141+
fieldWithPath("page.totalElements").description("Total number of all existing users"),
142+
fieldWithPath("page.totalPages").description("Total number of pages"),
143+
fieldWithPath("page.number").description("Number of the current page")
127144
)));
128145
}
129146

0 commit comments

Comments
 (0)