Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #2348 - adds feature to request the current user via /users?currentUser #2349

Merged
merged 1 commit into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Whenever a parameter is a complex type, the attributes of the value-object can b
For example, a complex parameter with the name "complex-query-param" and attributes "attribute1" and "attribute2" would be specified in the following way: +
complex-query-param={"attribute1":"value1","attribute2":"value2"}

Whenever a parameter is a value-less type (e.g owner-is-null and current-user) it is expected to be defined without a value,
i.e., it should be specified as ?parameter and not ?parameter= or ?parameter=someValue

=== Hypermedia Support

NOTE: HATEOAS support is still in development.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static void validateParams(HttpServletRequest request, Class<?>... filter
checkExactParam(request, "owner-is-null");
}

private static void checkExactParam(HttpServletRequest request, String queryParameter) {
public static void checkExactParam(HttpServletRequest request, String queryParameter) {
String queryString = request.getQueryString();
boolean containParam = queryString != null && queryString.contains(queryParameter);
if (containParam) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
Expand All @@ -18,7 +20,9 @@
import org.springframework.web.bind.annotation.RestController;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.api.security.CurrentUserContext;
import pro.taskana.common.rest.RestEndpoints;
import pro.taskana.common.rest.util.QueryParamsValidator;
import pro.taskana.user.api.UserService;
import pro.taskana.user.api.exceptions.UserAlreadyExistException;
import pro.taskana.user.api.exceptions.UserNotFoundException;
Expand All @@ -34,10 +38,15 @@ public class UserController {
private final UserService userService;
private final UserRepresentationModelAssembler userAssembler;

private final CurrentUserContext currentUserContext;

@Autowired
UserController(UserService userService, UserRepresentationModelAssembler userAssembler) {
UserController(UserService userService,
UserRepresentationModelAssembler userAssembler,
CurrentUserContext currentUserContext) {
this.userService = userService;
this.userAssembler = userAssembler;
this.currentUserContext = currentUserContext;
}

/**
Expand All @@ -54,24 +63,39 @@ public class UserController {
public ResponseEntity<UserRepresentationModel> getUser(@PathVariable String userId)
throws UserNotFoundException, InvalidArgumentException {
User user = userService.getUser(userId);

return ResponseEntity.ok(userAssembler.toModel(user));
}

/**
* This endpoint retrieves multiple Users. If a userId can't be found in the database it will be
* ignored. If none of the given userIds is valid, the returned list will be empty.
* If currentUser is set, the current User from the context will be retrieved as well
*
* @title Get multiple Users
* @param request the HttpServletRequest of the request itself
* @param userIds the ids of the requested Users
* @param currentUser Indicates whether to fetch the current user or not as well
* @return the requested Users
* @throws InvalidArgumentException if the userIds are null or empty
* @throws UserNotFoundException if the current User was not found
*/
@GetMapping(RestEndpoints.URL_USERS)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<UserCollectionRepresentationModel> getUsers(
@RequestParam(name = "user-id") String[] userIds) throws InvalidArgumentException {
List<User> users = userService.getUsers(new HashSet<>(List.of(userIds)));
HttpServletRequest request,
@RequestParam(name = "user-id", required = false) String[] userIds,
@RequestParam(name = "current-user", required = false) String currentUser)
throws InvalidArgumentException, UserNotFoundException {
Set<User> users = new HashSet<>();

if (userIds != null) {
users.addAll(userService.getUsers(new HashSet<>(List.of(userIds))));
}

if (currentUser != null) {
QueryParamsValidator.checkExactParam(request, "current-user");
users.add(userService.getUser(this.currentUserContext.getUserid()));
}

return ResponseEntity.ok(userAssembler.toTaskanaCollectionModel(users));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,94 @@ void should_ReturnExistingUsers() throws Exception {
.containsExactlyInAnyOrder("Max", "Elena");
}

@Test
void should_ReturnCurrentUser() {
String url = restHelper.toUrl(RestEndpoints.URL_USERS) + "?current-user";
HttpEntity<?> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));

ResponseEntity<UserCollectionRepresentationModel> response =
TEMPLATE.exchange(
url,
HttpMethod.GET,
auth,
ParameterizedTypeReference.forType(UserCollectionRepresentationModel.class));
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getContent()).hasSize(1);
assertThat(response.getBody().getContent()).extracting("userId").containsExactly("teamlead-1");
}

@Test
void should_ReturnExceptionCurrentUserWithBadValue() {
String url = restHelper.toUrl(RestEndpoints.URL_USERS) + "?current-user=asd";
HttpEntity<?> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));

ThrowingCallable httpCall =
() -> TEMPLATE.exchange(
url,
HttpMethod.GET,
auth,
ParameterizedTypeReference.forType(UserCollectionRepresentationModel.class));
assertThatThrownBy(httpCall)
.isInstanceOf(HttpStatusCodeException.class)
.extracting(HttpStatusCodeException.class::cast)
.extracting(HttpStatusCodeException::getStatusCode)
.isEqualTo(HttpStatus.BAD_REQUEST);
}

@Test
void should_ReturnExceptionCurrentUserWithEmptyValue() {
String url = restHelper.toUrl(RestEndpoints.URL_USERS) + "?current-user=";
HttpEntity<?> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));

ThrowingCallable httpCall =
() -> TEMPLATE.exchange(
url,
HttpMethod.GET,
auth,
ParameterizedTypeReference.forType(UserCollectionRepresentationModel.class));
assertThatThrownBy(httpCall)
.isInstanceOf(HttpStatusCodeException.class)
.extracting(HttpStatusCodeException.class::cast)
.extracting(HttpStatusCodeException::getStatusCode)
.isEqualTo(HttpStatus.BAD_REQUEST);
}

@Test
void should_ReturnOnlyCurrentUserWhileUsingUserIds() {
String url = restHelper.toUrl(RestEndpoints.URL_USERS) + "?current-user&user-id=teamlead-1";
HttpEntity<?> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));

ResponseEntity<UserCollectionRepresentationModel> response =
TEMPLATE.exchange(
url,
HttpMethod.GET,
auth,
ParameterizedTypeReference.forType(UserCollectionRepresentationModel.class));
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getContent()).hasSize(1);
assertThat(response.getBody().getContent()).extracting("userId").containsExactly("teamlead-1");
}

@Test
void should_ReturnExistingUsersAndCurrentUser() throws Exception {
String url = restHelper.toUrl(RestEndpoints.URL_USERS)
+ "?user-id=user-1-1&user-id=USER-1-2&current-user";
HttpEntity<?> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));

ResponseEntity<UserCollectionRepresentationModel> responseEntity =
TEMPLATE.exchange(
url,
HttpMethod.GET,
auth,
ParameterizedTypeReference.forType(UserCollectionRepresentationModel.class));
UserCollectionRepresentationModel response = responseEntity.getBody();
assertThat(response).isNotNull();
assertThat(response.getContent()).hasSize(3);
assertThat(response.getContent())
.extracting("userId")
.containsExactlyInAnyOrder("user-1-1", "user-1-2", "teamlead-1");
}

@Test
void should_ReturnExistingUsers_When_ParameterContainsDuplicateAndInvalidIds() throws Exception {
// also testing different query parameter format
Expand Down