Skip to content

Commit c0db06a

Browse files
committed
feat(rest) : Adding pagination for listing users endpoint.
Signed-off-by: rudra-superrr <rudra.chopra@siemens.com>
1 parent 598226e commit c0db06a

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,13 +26,15 @@
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

3233
public class ResourceComparatorGenerator<T> {
3334

3435
private static final Map<Component._Fields, Comparator<Component>> componentMap = generateComponentMap();
3536
private static final Map<Project._Fields, Comparator<Project>> projectMap = generateProjectMap();
37+
private static final Map<User._Fields, Comparator<User>> userMap = generateUserMap();
3638
private static final Map<Release._Fields, Comparator<Release>> releaseMap = generateReleaseMap();
3739
private static final Map<Package._Fields, Comparator<Package>> packageMap = generatePackageMap();
3840
private static final Map<SearchResult._Fields, Comparator<SearchResult>> searchResultMap = generateSearchResultMap();
@@ -59,6 +61,13 @@ private static Map<Project._Fields, Comparator<Project>> generateProjectMap() {
5961
return Collections.unmodifiableMap(projectMap);
6062
}
6163

64+
private static Map<User._Fields, Comparator<User>> generateUserMap() {
65+
Map<User._Fields, Comparator<User>> userMap = new HashMap<>();
66+
userMap.put(User._Fields.FULLNAME, Comparator.comparing(User::getFullname, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
67+
userMap.put(User._Fields.EMAIL, Comparator.comparing(User::getEmail, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
68+
return Collections.unmodifiableMap(userMap);
69+
}
70+
6271
private static Map<Release._Fields, Comparator<Release>> generateReleaseMap() {
6372
Map<Release._Fields, Comparator<Release>> releaseMap = new HashMap<>();
6473
releaseMap.put(Release._Fields.NAME, Comparator.comparing(Release::getName, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
@@ -114,6 +123,8 @@ public Comparator<T> generateComparator(String type) throws ResourceClassNotFoun
114123
return (Comparator<T>)defaultComponentComparator();
115124
case SW360Constants.TYPE_PROJECT:
116125
return (Comparator<T>)defaultProjectComparator();
126+
case SW360Constants.TYPE_USER:
127+
return (Comparator<T>)defaultUserComparator();
117128
case SW360Constants.TYPE_RELEASE:
118129
return (Comparator<T>)defaultReleaseComparator();
119130
case SW360Constants.TYPE_SEARCHRESULT:
@@ -155,6 +166,15 @@ public Comparator<T> generateComparator(String type, List<String> properties) th
155166
}
156167
}
157168
return generateProjectComparatorWithFields(type, projectFields);
169+
case SW360Constants.TYPE_USER:
170+
List<User._Fields> userFields = new ArrayList<>();
171+
for(String property:properties) {
172+
User._Fields field = User._Fields.findByName(property);
173+
if (field != null) {
174+
userFields.add(field);
175+
}
176+
}
177+
return generateUserComparatorWithFields(type, userFields);
158178
case SW360Constants.TYPE_RELEASE:
159179
List<Release._Fields> releaeFields = new ArrayList<>();
160180
for(String property:properties) {
@@ -223,6 +243,15 @@ public Comparator<T> generateProjectComparatorWithFields(String type, List<Proje
223243
}
224244
}
225245

246+
public Comparator<T> generateUserComparatorWithFields(String type, List<User._Fields> fields) throws ResourceClassNotFoundException {
247+
switch (type) {
248+
case SW360Constants.TYPE_USER:
249+
return (Comparator<T>)userComparator(fields);
250+
default:
251+
throw new ResourceClassNotFoundException("No comparator for resource class with name " + type);
252+
}
253+
}
254+
226255
public Comparator<T> generateReleaseComparatorWithFields(String type, List<Release._Fields> fields) throws ResourceClassNotFoundException {
227256
switch (type) {
228257
case SW360Constants.TYPE_RELEASE:
@@ -292,6 +321,18 @@ private Comparator<Project> projectComparator(List<Project._Fields> fields) {
292321
return comparator;
293322
}
294323

324+
private Comparator<User> userComparator(List<User._Fields> fields) {
325+
Comparator<User> comparator = Comparator.comparing(x -> true);
326+
for (User._Fields field:fields) {
327+
Comparator<User> fieldComparator = userMap.get(field);
328+
if(fieldComparator != null) {
329+
comparator = comparator.thenComparing(fieldComparator);
330+
}
331+
}
332+
comparator = comparator.thenComparing(defaultUserComparator());
333+
return comparator;
334+
}
335+
295336
private Comparator<Release> releaseComparator(List<Release._Fields> fields) {
296337
Comparator<Release> comparator = Comparator.comparing(x -> true);
297338
for (Release._Fields field:fields) {
@@ -360,6 +401,10 @@ private Comparator<Project> defaultProjectComparator() {
360401
return projectMap.get(Project._Fields.NAME);
361402
}
362403

404+
private Comparator<User> defaultUserComparator() {
405+
return userMap.get(User._Fields.EMAIL);
406+
}
407+
363408
private Comparator<Release> defaultReleaseComparator() {
364409
return releaseMap.get(Release._Fields.NAME);
365410
}

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)