TSK-694 - Show list of all access items valid for a user (REST)

This commit is contained in:
Martin Rojas Miguel Angel 2018-08-28 14:12:50 +02:00 committed by Mustapha Zorgati
parent 131e11e7aa
commit 3f8dc3cf87
14 changed files with 702 additions and 134 deletions

View File

@ -1,8 +1,6 @@
package pro.taskana.ldap; package pro.taskana.ldap;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import pro.taskana.rest.resource.AccessIdResource; import pro.taskana.rest.resource.AccessIdResource;
@ -14,13 +12,40 @@ import pro.taskana.rest.resource.AccessIdResource;
*/ */
public class LdapCacheTestImpl implements LdapCache { public class LdapCacheTestImpl implements LdapCache {
/**
* Dictionary is a {@link Map} collection that contains {@link AccessIdResource} as key (user)
* and {@link List<AccessIdResource>} as value (groups of which the user is a member) .
*/
private static Map<AccessIdResource, List<AccessIdResource>> users;
@Override @Override
public List<AccessIdResource> findMatchingAccessId(String searchFor, int maxNumerOfReturnedAccessIds) { public List<AccessIdResource> findMatchingAccessId(String searchFor, int maxNumerOfReturnedAccessIds) {
return findAcessIdResource(searchFor, maxNumerOfReturnedAccessIds, false);
}
@Override
public List<AccessIdResource> findGroupsOfUser(String searchFor, int maxNumerOfReturnedAccessIds) {
if (users == null) {
addUsersToGroups();
}
return findAcessIdResource(searchFor, maxNumerOfReturnedAccessIds, true);
}
private List <AccessIdResource> findAcessIdResource (String searchFor, int maxNumerOfReturnedAccessIds, boolean groupMember) {
List<AccessIdResource> usersAndGroups = accessIds.stream() List<AccessIdResource> usersAndGroups = accessIds.stream()
.filter(t -> (t.getName().toLowerCase().contains(searchFor.toLowerCase()) .filter(t -> (t.getName().toLowerCase().contains(searchFor.toLowerCase())
|| t.getAccessId().toLowerCase().contains(searchFor.toLowerCase()))) || t.getAccessId().toLowerCase().contains(searchFor.toLowerCase())))
.collect(Collectors.toList()); .collect(Collectors.toList());
List<AccessIdResource> usersAndGroupsAux = new ArrayList<>(usersAndGroups);
if (groupMember) {
usersAndGroupsAux.forEach(item -> {
if (users.get(item) != null) {
usersAndGroups.addAll(users.get(item));
}
});
}
usersAndGroups.sort((AccessIdResource a, AccessIdResource b) -> { usersAndGroups.sort((AccessIdResource a, AccessIdResource b) -> {
return a.getAccessId().compareToIgnoreCase(b.getAccessId()); return a.getAccessId().compareToIgnoreCase(b.getAccessId());
}); });
@ -31,6 +56,69 @@ public class LdapCacheTestImpl implements LdapCache {
return result; return result;
} }
private void addUsersToGroups() {
List<AccessIdResource> groups = new ArrayList<>();
users = new HashMap<>();
accessIds.forEach(item -> {
if (!item.getAccessId().contains("ou=groups")) {
users.put(item, new ArrayList<>());
} else {
groups.add(item);
}
});
int groupNumber = 0;
List<AccessIdResource> group0 = new ArrayList<>(), group1 = new ArrayList<>(), group2 = new ArrayList<>(), group3 = new ArrayList<>();
for (AccessIdResource group : groups) {
switch (groupNumber) {
case 0:
group0.add(group);
break;
case 1:
group1.add(group);
break;
case 2:
group2.add(group);
break;
case 3:
group3.add(group);
break;
}
if (groupNumber != 3) {
groupNumber++;
} else {
groupNumber = 0;
}
}
int countUser = 0;
for (AccessIdResource item : accessIds) {
if (!item.getAccessId().contains("ou=groups")) {
switch (countUser) {
case 0:
users.put(item, group0);
break;
case 1:
users.put(item, group1);
break;
case 2:
users.put(item, group2);
break;
case 3:
users.put(item, group3);
break;
}
}
if (countUser != 3) {
countUser++;
} else {
countUser = 0;
}
}
}
private static List<AccessIdResource> accessIds = new ArrayList<>(Arrays.asList( private static List<AccessIdResource> accessIds = new ArrayList<>(Arrays.asList(
new AccessIdResource("Martin, Rojas Miguel Angel", "user_1_1"), new AccessIdResource("Martin, Rojas Miguel Angel", "user_1_1"),
new AccessIdResource("Lengl, Marcel", "user_1_2"), new AccessIdResource("Lengl, Marcel", "user_1_2"),

View File

@ -39,6 +39,7 @@ taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
taskana.ldap.groupNameAttribute=cn taskana.ldap.groupNameAttribute=cn
taskana.ldap.minSearchForLength=3 taskana.ldap.minSearchForLength=3
taskana.ldap.maxNumberOfReturnedAccessIds=50 taskana.ldap.maxNumberOfReturnedAccessIds=50
taskana.ldap.groupsOfUser=memberUid
####### JobScheduler cron expression that specifies when the JobSchedler runs ####### JobScheduler cron expression that specifies when the JobSchedler runs
taskana.jobscheduler.async.cron=0 * * * * * taskana.jobscheduler.async.cron=0 * * * * *
####### cache static resources properties ####### cache static resources properties

View File

@ -0,0 +1,121 @@
package pro.taskana.rest;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.http.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import pro.taskana.rest.resource.WorkbasketAccesItemExtendedResource;
import java.util.Collections;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RestConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {"devMode=true"})
public class WorkbasketAccessItemControllerIntTest {
String url = "http://127.0.0.1:";
RestTemplate template;
HttpEntity<String> request;
@LocalServerPort
int port;
@Before
public void before() {
template = getRestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x");
request = new HttpEntity<String>(headers);
}
@Test
public void testGetAllWorkbasketAccessItems() {
ResponseEntity<PagedResources<WorkbasketAccesItemExtendedResource>> response = template.exchange(
url + port + "/v1/workbasket-access", HttpMethod.GET, request,
new ParameterizedTypeReference<PagedResources<WorkbasketAccesItemExtendedResource>>() {
});
assertNotNull(response.getBody().getLink(Link.REL_SELF));
}
@Test
public void testGetWorkbasketAccessItemsKeepingFilters() {
String parameters = "/v1/workbasket-access/?sort-by=workbasket-key&order=asc&page=1&page-size=9&access-ids=user_1_1";
ResponseEntity<PagedResources<WorkbasketAccesItemExtendedResource>> response = template.exchange(
url + port + parameters, HttpMethod.GET, request,
new ParameterizedTypeReference<PagedResources<WorkbasketAccesItemExtendedResource>>() {
});
assertNotNull(response.getBody().getLink(Link.REL_SELF));
assertTrue(response.getBody()
.getLink(Link.REL_SELF)
.getHref()
.endsWith(parameters));
}
@Test
public void testThrowsExceptionIfInvalidFilterIsUsed() {
try {
template.exchange(
url + port + "/v1/workbasket-access/?sort-by=workbasket-key&order=asc&page=1&page-size=9&invalid=user_1_1", HttpMethod.GET, request,
new ParameterizedTypeReference<PagedResources<WorkbasketAccesItemExtendedResource>>() {
});
fail();
} catch (HttpClientErrorException e) {
assertEquals(HttpStatus.BAD_REQUEST, e.getStatusCode());
assertTrue(e.getResponseBodyAsString().contains("[invalid]"));
}
}
@Test
public void testGetSecondPageSortedByWorkbasketKey() {
String parameters = "/v1/workbasket-access/?sort-by=workbasket-key&order=asc&page=2&page-size=9&access-ids=user_1_1";
ResponseEntity<PagedResources<WorkbasketAccesItemExtendedResource>> response = template.exchange(
url + port + parameters, HttpMethod.GET, request,
new ParameterizedTypeReference<PagedResources<WorkbasketAccesItemExtendedResource>>() {
});
assertEquals(1, response.getBody().getContent().size());
assertEquals("user_1_1", response.getBody().getContent().iterator().next().accessId);
assertNotNull(response.getBody().getLink(Link.REL_SELF));
assertTrue(response.getBody()
.getLink(Link.REL_SELF)
.getHref()
.endsWith(parameters));
assertNotNull(response.getBody().getLink(Link.REL_FIRST));
assertNotNull(response.getBody().getLink(Link.REL_LAST));
assertEquals(9, response.getBody().getMetadata().getSize());
assertEquals(1, response.getBody().getMetadata().getTotalElements());
assertEquals(1, response.getBody().getMetadata().getTotalPages());
assertEquals(1, response.getBody().getMetadata().getNumber());
}
/**
* Return a REST template which is capable of dealing with responses in HAL format
*
* @return RestTemplate
*/
private RestTemplate getRestTemplate() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(new Jackson2HalModule());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
converter.setObjectMapper(mapper);
RestTemplate template = new RestTemplate(Collections.<HttpMessageConverter<?>>singletonList(converter));
return template;
}
}

View File

@ -21,4 +21,12 @@ public interface LdapCache {
* @return a List of access ids for users and group where the name or id contains the search string. * @return a List of access ids for users and group where the name or id contains the search string.
*/ */
List<AccessIdResource> findMatchingAccessId(String searchFor, int maxNumerOfReturnedAccessIds); List<AccessIdResource> findMatchingAccessId(String searchFor, int maxNumerOfReturnedAccessIds);
/**
*
* @param searchFor the search string. The search is performed over names and ids of group .
* @param maxNumerOfReturnedAccessIds
* @return
*/
List<AccessIdResource> findGroupsOfUser(String searchFor, int maxNumerOfReturnedAccessIds);
} }

View File

@ -1,10 +1,5 @@
package pro.taskana.ldap; package pro.taskana.ldap;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.naming.directory.SearchControls;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -17,12 +12,15 @@ import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.OrFilter; import org.springframework.ldap.filter.OrFilter;
import org.springframework.ldap.filter.WhitespaceWildcardsFilter; import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import pro.taskana.exceptions.InvalidArgumentException; import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.SystemException; import pro.taskana.exceptions.SystemException;
import pro.taskana.impl.util.LoggerUtils; import pro.taskana.impl.util.LoggerUtils;
import pro.taskana.rest.resource.AccessIdResource; import pro.taskana.rest.resource.AccessIdResource;
import javax.annotation.PostConstruct;
import javax.naming.directory.SearchControls;
import java.util.List;
/** /**
* Class for Ldap access. * Class for Ldap access.
* *
@ -51,6 +49,7 @@ public class LdapClient {
private String groupSearchFilterName; private String groupSearchFilterName;
private String groupSearchFilterValue; private String groupSearchFilterValue;
private String groupNameAttribute; private String groupNameAttribute;
private String groupsOfUser;
private int minSearchForLength; private int minSearchForLength;
private int maxNumberOfReturnedAccessIds; private int maxNumberOfReturnedAccessIds;
@ -85,6 +84,7 @@ public class LdapClient {
groupSearchFilterName = getGroupSearchFilterName(); groupSearchFilterName = getGroupSearchFilterName();
groupSearchFilterValue = getGroupSearchFilterValue(); groupSearchFilterValue = getGroupSearchFilterValue();
groupNameAttribute = getGroupNameAttribute(); groupNameAttribute = getGroupNameAttribute();
groupsOfUser = getGroupsOfUser();
ldapTemplate.setDefaultCountLimit(maxNumberOfReturnedAccessIds); ldapTemplate.setDefaultCountLimit(maxNumberOfReturnedAccessIds);
@ -120,6 +120,9 @@ public class LdapClient {
if (groupNameAttribute == null) { if (groupNameAttribute == null) {
message += " taskana.ldap.groupNameAttribute is not configured."; message += " taskana.ldap.groupNameAttribute is not configured.";
} }
if (groupsOfUser == null) {
message += " taskana.ldap.groupsOfUser is not configured.";
}
if (!message.equals(emptyMessage)) { if (!message.equals(emptyMessage)) {
throw new SystemException(message); throw new SystemException(message);
} }
@ -133,10 +136,7 @@ public class LdapClient {
throw new SystemException( throw new SystemException(
"LdapClient was called but is not active due to missing configuration: " + message); "LdapClient was called but is not active due to missing configuration: " + message);
} }
if (name == null || name.length() < minSearchForLength) { testMinSearchForLength(name);
throw new InvalidArgumentException("searchFor string " + name + " is too short. Minimum Length = "
+ getMinSearchForLength());
}
List<AccessIdResource> users = searchUsersByName(name); List<AccessIdResource> users = searchUsersByName(name);
users.addAll(searchGroupsByName(name)); users.addAll(searchGroupsByName(name));
@ -157,10 +157,7 @@ public class LdapClient {
throw new SystemException( throw new SystemException(
"LdapClient was called but is not active due to missing configuration: " + message); "LdapClient was called but is not active due to missing configuration: " + message);
} }
if (name == null || name.length() < minSearchForLength) { testMinSearchForLength(name);
throw new InvalidArgumentException("searchFor string " + name + " is too short. Minimum Length = "
+ getMinSearchForLength());
}
final AndFilter andFilter = new AndFilter(); final AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(getUserSearchFilterName(), getUserSearchFilterValue())); andFilter.and(new EqualsFilter(getUserSearchFilterName(), getUserSearchFilterValue()));
@ -188,10 +185,7 @@ public class LdapClient {
throw new SystemException( throw new SystemException(
"LdapClient was called but is not active due to missing configuration: " + message); "LdapClient was called but is not active due to missing configuration: " + message);
} }
if (name == null || name.length() < minSearchForLength) { testMinSearchForLength(name);
throw new InvalidArgumentException("searchFor string " + name + " is too short. Minimum Length = "
+ getMinSearchForLength());
}
final AndFilter andFilter = new AndFilter(); final AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(getGroupSearchFilterName(), getGroupSearchFilterValue())); andFilter.and(new EqualsFilter(getGroupSearchFilterName(), getGroupSearchFilterValue()));
@ -217,6 +211,35 @@ public class LdapClient {
} }
public List<AccessIdResource> searchGroupsofUsersIsMember(final String name) throws InvalidArgumentException {
LOGGER.debug("entry to searchGroupsofUsersIsMember(name = {}).", name);
if (!active) {
throw new SystemException(
"LdapClient was called but is not active due to missing configuration: " + message);
}
testMinSearchForLength(name);
final AndFilter andFilter = new AndFilter();
andFilter.and(new WhitespaceWildcardsFilter(getGroupNameAttribute(), ""));
andFilter.and(new EqualsFilter(getGroupsOfUser(), name));
String[] userAttributesToReturn = {getUserIdAttribute(), getGroupNameAttribute()};
final List<AccessIdResource> accessIds = ldapTemplate.search(getGroupSearchBase(), andFilter.encode(),
SearchControls.SUBTREE_SCOPE, userAttributesToReturn, new GroupContextMapper());
LOGGER.debug("exit from searchGroupsofUsersIsMember. Retrieved the following users: {}.",
LoggerUtils.listToString(accessIds));
return accessIds;
}
private void testMinSearchForLength(final String name) throws InvalidArgumentException {
if (name == null || name.length() < minSearchForLength) {
throw new InvalidArgumentException("searchFor string " + name + " is too short. Minimum Length = "
+ getMinSearchForLength());
}
}
public boolean useLdap() { public boolean useLdap() {
String useLdap = env.getProperty(TASKANA_USE_LDAP_PROP_NAME); String useLdap = env.getProperty(TASKANA_USE_LDAP_PROP_NAME);
if (useLdap == null || useLdap.isEmpty()) { if (useLdap == null || useLdap.isEmpty()) {
@ -282,6 +305,10 @@ public class LdapClient {
return maxNumberOfReturnedAccessIds; return maxNumberOfReturnedAccessIds;
} }
public String getGroupsOfUser() {
return env.getProperty("taskana.ldap.groupsOfUser");
}
/** /**
* Context Mapper for user entries. * Context Mapper for user entries.
*/ */

View File

@ -35,17 +35,28 @@ public class AccessIdController {
@GetMapping @GetMapping
public ResponseEntity<List<AccessIdResource>> validateAccessIds( public ResponseEntity<List<AccessIdResource>> validateAccessIds(
@RequestParam String searchFor) throws InvalidArgumentException { @RequestParam String searchFor, @RequestParam(required = false) boolean searchInGroups) throws InvalidArgumentException {
if (searchFor.length() < ldapClient.getMinSearchForLength()) { if (searchFor.length() < ldapClient.getMinSearchForLength()) {
throw new InvalidArgumentException("searchFor string '" + searchFor + "' is too short. Minimum searchFor length = " throw new InvalidArgumentException("searchFor string '" + searchFor + "' is too short. Minimum searchFor length = "
+ ldapClient.getMinSearchForLength()); + ldapClient.getMinSearchForLength());
} }
if (ldapClient.useLdap()) { if (ldapClient.useLdap()) {
return new ResponseEntity<>(ldapClient.searchUsersAndGroups(searchFor), HttpStatus.OK); List<AccessIdResource> accessIdUsers = ldapClient.searchUsersAndGroups(searchFor);
if (searchInGroups) {
List<AccessIdResource> accessIdGroups = ldapClient.searchGroupsofUsersIsMember(searchFor);
accessIdUsers.addAll(accessIdGroups);
}
return new ResponseEntity<>(accessIdUsers, HttpStatus.OK);
} else if (ldapCache != null) { } else if (ldapCache != null) {
if (searchInGroups) {
return new ResponseEntity<>(
ldapCache.findGroupsOfUser(searchFor, ldapClient.getMaxNumberOfReturnedAccessIds()),
HttpStatus.OK);
} else {
return new ResponseEntity<>( return new ResponseEntity<>(
ldapCache.findMatchingAccessId(searchFor, ldapClient.getMaxNumberOfReturnedAccessIds()), ldapCache.findMatchingAccessId(searchFor, ldapClient.getMaxNumberOfReturnedAccessIds()),
HttpStatus.OK); HttpStatus.OK);
}
} else { } else {
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.NOT_FOUND); return new ResponseEntity<>(new ArrayList<>(), HttpStatus.NOT_FOUND);
} }

View File

@ -0,0 +1,145 @@
package pro.taskana.rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import pro.taskana.BaseQuery;
import pro.taskana.WorkbasketAccessItemExtended;
import pro.taskana.WorkbasketAccessItemExtendedQuery;
import pro.taskana.WorkbasketService;
import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.rest.resource.WorkbasketAccesItemExtendedResource;
import pro.taskana.rest.resource.assembler.WorkbasketAccessItemExtendedAssembler;
import java.util.List;
/**
* Controller for Workbasket access.
*/
@RestController
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
@RequestMapping(path = "/v1/workbasket-access", produces = "application/hal+json")
public class WorkbasketAccessItemController extends AbstractPagingController {
private static final String LIKE = "%";
private static final String WORKBASKET_KEY = "workbasket-key";
private static final String WORKBASKET_KEY_LIKE = "workbasket-key-like";
private static final String ACCESS_ID = "access-id";
private static final String ACCESS_ID_LIKE = "access-id-like";
private static final String ACCESS_IDS = "access-ids";
private static final String SORT_BY = "sort-by";
private static final String SORT_DIRECTION = "order";
private static final String PAGING_PAGE = "page";
private static final String PAGING_PAGE_SIZE = "page-size";
@Autowired
private WorkbasketService workbasketService;
@GetMapping
public ResponseEntity<PagedResources<WorkbasketAccesItemExtendedResource>> getWorkbasketAccessItems(
@RequestParam MultiValueMap<String, String> params)
throws NotAuthorizedException, InvalidArgumentException {
WorkbasketAccessItemExtendedQuery query = workbasketService.createWorkbasketAccessItemExtendedQuery();
query = getAccessIds(query, params);
query = applyFilterParams(query, params);
query = applySortingParams(query, params);
PagedResources.PageMetadata pageMetadata = null;
List<WorkbasketAccessItemExtended> workbasketAccessItemsExtended;
String page = params.getFirst(PAGING_PAGE);
String pageSize = params.getFirst(PAGING_PAGE_SIZE);
params.remove(PAGING_PAGE);
params.remove(PAGING_PAGE_SIZE);
validateNoInvalidParameterIsLeft(params);
if (page != null && pageSize != null) {
// paging
long totalElements = query.count();
pageMetadata = initPageMetadata(pageSize, page, totalElements);
workbasketAccessItemsExtended = query.listPage((int) pageMetadata.getNumber(),
(int) pageMetadata.getSize());
} else if (page == null && pageSize == null) {
// not paging
workbasketAccessItemsExtended = query.list();
} else {
throw new InvalidArgumentException("Paging information is incomplete.");
}
WorkbasketAccessItemExtendedAssembler assembler = new WorkbasketAccessItemExtendedAssembler();
PagedResources<WorkbasketAccesItemExtendedResource> pagedResources = assembler.toResources(workbasketAccessItemsExtended,
pageMetadata);
return new ResponseEntity<>(pagedResources, HttpStatus.OK);
}
private WorkbasketAccessItemExtendedQuery getAccessIds(WorkbasketAccessItemExtendedQuery query,
MultiValueMap<String, String> params) throws InvalidArgumentException {
if (params.containsKey(ACCESS_IDS)) {
String[] accessIds = extractCommaSeparatedFields(params.get(ACCESS_IDS));
query.accessIdIn(accessIds);
params.remove(ACCESS_IDS);
}
return query;
}
private WorkbasketAccessItemExtendedQuery applyFilterParams(WorkbasketAccessItemExtendedQuery query,
MultiValueMap<String, String> params) throws InvalidArgumentException {
if (params.containsKey(WORKBASKET_KEY)) {
String[] keys = extractCommaSeparatedFields(params.get(WORKBASKET_KEY));
query.workbasketKeyIn(keys);
params.remove(WORKBASKET_KEY);
}
if (params.containsKey(WORKBASKET_KEY_LIKE)) {
query.workbasketKeyLike(LIKE + params.get(WORKBASKET_KEY_LIKE).get(0) + LIKE);
params.remove(WORKBASKET_KEY_LIKE);
}
if (params.containsKey(ACCESS_ID)) {
String[] accessId = extractCommaSeparatedFields(params.get(ACCESS_ID));
query.accessIdIn(accessId);
params.remove(ACCESS_ID);
}
if (params.containsKey(ACCESS_ID_LIKE)) {
query.accessIdLike(LIKE + params.get(ACCESS_ID_LIKE).get(0) + LIKE);
params.remove(ACCESS_ID_LIKE);
}
return query;
}
private WorkbasketAccessItemExtendedQuery applySortingParams(WorkbasketAccessItemExtendedQuery query, MultiValueMap<String, String> params)
throws IllegalArgumentException {
// sorting
String sortBy = params.getFirst(SORT_BY);
if (sortBy != null) {
BaseQuery.SortDirection sortDirection;
if (params.getFirst(SORT_DIRECTION) != null && "desc".equals(params.getFirst(SORT_DIRECTION))) {
sortDirection = BaseQuery.SortDirection.DESCENDING;
} else {
sortDirection = BaseQuery.SortDirection.ASCENDING;
}
switch (sortBy) {
case (WORKBASKET_KEY):
query = query.orderByWorkbasketKey(sortDirection);
break;
case (ACCESS_ID):
query = query.orderByAccessId(sortDirection);
break;
default:
throw new IllegalArgumentException("Unknown order '" + sortBy + "'");
}
}
params.remove(SORT_BY);
params.remove(SORT_DIRECTION);
return query;
}
}

View File

@ -1,9 +1,5 @@
package pro.taskana.rest; package pro.taskana.rest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.PagedResources; import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.PagedResources.PageMetadata; import org.springframework.hateoas.PagedResources.PageMetadata;
@ -14,40 +10,19 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import pro.taskana.BaseQuery.SortDirection; import pro.taskana.BaseQuery.SortDirection;
import pro.taskana.Workbasket; import pro.taskana.*;
import pro.taskana.WorkbasketAccessItem; import pro.taskana.exceptions.*;
import pro.taskana.WorkbasketPermission;
import pro.taskana.WorkbasketQuery;
import pro.taskana.WorkbasketService;
import pro.taskana.WorkbasketSummary;
import pro.taskana.WorkbasketType;
import pro.taskana.exceptions.DomainNotFoundException;
import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.InvalidWorkbasketException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.WorkbasketAlreadyExistException;
import pro.taskana.exceptions.WorkbasketInUseException;
import pro.taskana.exceptions.WorkbasketNotFoundException;
import pro.taskana.rest.resource.DistributionTargetResource; import pro.taskana.rest.resource.DistributionTargetResource;
import pro.taskana.rest.resource.WorkbasketAccessItemResource; import pro.taskana.rest.resource.WorkbasketAccessItemResource;
import pro.taskana.rest.resource.WorkbasketResource; import pro.taskana.rest.resource.WorkbasketResource;
import pro.taskana.rest.resource.WorkbasketSummaryResource; import pro.taskana.rest.resource.WorkbasketSummaryResource;
import pro.taskana.rest.resource.assembler.DistributionTargetListAssembler; import pro.taskana.rest.resource.assembler.*;
import pro.taskana.rest.resource.assembler.WorkbasketAccessItemListAssembler;
import pro.taskana.rest.resource.assembler.WorkbasketAccessItemAssembler; import java.util.ArrayList;
import pro.taskana.rest.resource.assembler.WorkbasketAssembler; import java.util.Arrays;
import pro.taskana.rest.resource.assembler.WorkbasketSummaryResourcesAssembler; import java.util.List;
/** /**
* Controller for all {@link Workbasket} related endpoints. * Controller for all {@link Workbasket} related endpoints.

View File

@ -0,0 +1,23 @@
package pro.taskana.rest.resource;
import org.springframework.hateoas.core.Relation;
import javax.validation.constraints.NotNull;
/**
* Resource class for {@link pro.taskana.WorkbasketAccessItem}.
*/
@Relation(collectionRelation = "accessItems")
public class WorkbasketAccesItemExtendedResource extends WorkbasketAccessItemResource {
@NotNull
public String workbasketKey;
public String getWorkbasketKey() {
return workbasketKey;
}
public void setWorkbasketKey(String workbasketKey) {
this.workbasketKey = workbasketKey;
}
}

View File

@ -1,12 +1,8 @@
package pro.taskana.rest.resource.assembler; package pro.taskana.rest.resource.assembler;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import pro.taskana.WorkbasketAccessItem; import pro.taskana.WorkbasketAccessItem;
import pro.taskana.WorkbasketService; import pro.taskana.WorkbasketService;
import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.NotAuthorizedException;
@ -15,6 +11,9 @@ import pro.taskana.impl.WorkbasketAccessItemImpl;
import pro.taskana.rest.WorkbasketController; import pro.taskana.rest.WorkbasketController;
import pro.taskana.rest.resource.WorkbasketAccessItemResource; import pro.taskana.rest.resource.WorkbasketAccessItemResource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
/** /**
* Transforms {@link WorkbasketAccessItem} to its resource counterpart {@link WorkbasketAccessItemResource} and vice * Transforms {@link WorkbasketAccessItem} to its resource counterpart {@link WorkbasketAccessItemResource} and vice
* versa. * versa.

View File

@ -0,0 +1,88 @@
package pro.taskana.rest.resource.assembler;
import org.springframework.beans.BeanUtils;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.mvc.ResourceAssemblerSupport;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import pro.taskana.WorkbasketAccessItemExtended;
import pro.taskana.rest.WorkbasketAccessItemController;
import pro.taskana.rest.resource.WorkbasketAccesItemExtendedResource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
/**
* Transforms {@link WorkbasketAccessItemExtended} to its resource counterpart {@link WorkbasketAccesItemExtendedResource} and vice versa.
*/
@Component
public class WorkbasketAccessItemExtendedAssembler extends ResourceAssemblerSupport<WorkbasketAccessItemExtended, WorkbasketAccesItemExtendedResource> {
/**
* Creates a new {@link ResourceAssemblerSupport} using the given controller class and resource type.
*/
public WorkbasketAccessItemExtendedAssembler() {
super(WorkbasketAccessItemController.class, WorkbasketAccesItemExtendedResource.class);
}
@Override
public WorkbasketAccesItemExtendedResource toResource(WorkbasketAccessItemExtended workbasketAccessItemExtended) {
WorkbasketAccesItemExtendedResource resource = createResourceWithId(workbasketAccessItemExtended.getId(), workbasketAccessItemExtended);
resource.removeLinks();
BeanUtils.copyProperties(workbasketAccessItemExtended, resource);
// named different so needs to be set by hand
resource.setAccessItemId(workbasketAccessItemExtended.getId());
return resource;
}
public PagedResources<WorkbasketAccesItemExtendedResource> toResources(List<WorkbasketAccessItemExtended> workbasketAccessItems,
PagedResources.PageMetadata pageMetadata) {
WorkbasketAccessItemExtendedAssembler assembler = new WorkbasketAccessItemExtendedAssembler();
List<WorkbasketAccesItemExtendedResource> resources = assembler.toResources(workbasketAccessItems);
PagedResources<WorkbasketAccesItemExtendedResource> pagedResources = new PagedResources<WorkbasketAccesItemExtendedResource>(
resources,
pageMetadata);
UriComponentsBuilder original = getBuilderForOriginalUri();
pagedResources.add(new Link(original.toUriString()).withSelfRel());
if (pageMetadata != null) {
pagedResources.add(new Link(original.replaceQueryParam("page", 1).toUriString()).withRel(Link.REL_FIRST));
pagedResources.add(new Link(original.replaceQueryParam("page", pageMetadata.getTotalPages()).toUriString())
.withRel(Link.REL_LAST));
if (pageMetadata.getNumber() > 1) {
pagedResources
.add(new Link(original.replaceQueryParam("page", pageMetadata.getNumber() - 1).toUriString())
.withRel(Link.REL_PREVIOUS));
}
if (pageMetadata.getNumber() < pageMetadata.getTotalPages()) {
pagedResources
.add(new Link(original.replaceQueryParam("page", pageMetadata.getNumber() + 1).toUriString())
.withRel(Link.REL_NEXT));
}
}
return pagedResources;
}
private UriComponentsBuilder getBuilderForOriginalUri() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
UriComponentsBuilder baseUri = ServletUriComponentsBuilder.fromServletMapping(request)
.path(request.getRequestURI());
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
for (String value : entry.getValue()) {
baseUri.queryParam(entry.getKey(), value);
}
}
UriComponentsBuilder original = baseUri;
return original;
}
}

View File

@ -1,22 +1,21 @@
package pro.taskana.rest.resource.assembler; package pro.taskana.rest.resource.assembler;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.Resources; import org.springframework.hateoas.Resources;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import pro.taskana.WorkbasketAccessItem; import pro.taskana.WorkbasketAccessItem;
import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.WorkbasketNotFoundException; import pro.taskana.exceptions.WorkbasketNotFoundException;
import pro.taskana.rest.WorkbasketController; import pro.taskana.rest.WorkbasketController;
import pro.taskana.rest.resource.WorkbasketAccessItemResource; import pro.taskana.rest.resource.WorkbasketAccessItemResource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
/** /**
* Mapper to convert from a list of WorkbasketAccessItem to a WorkbasketAccessItemResource. * Mapper to convert from a list of WorkbasketAccessItem to a WorkbasketAccessItemResource.
*/ */

View File

@ -1,14 +1,8 @@
package pro.taskana.rest.resource.assembler; package pro.taskana.rest.resource.assembler;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.time.Instant;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import pro.taskana.Workbasket; import pro.taskana.Workbasket;
import pro.taskana.WorkbasketService; import pro.taskana.WorkbasketService;
import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.NotAuthorizedException;
@ -17,6 +11,11 @@ import pro.taskana.impl.WorkbasketImpl;
import pro.taskana.rest.WorkbasketController; import pro.taskana.rest.WorkbasketController;
import pro.taskana.rest.resource.WorkbasketResource; import pro.taskana.rest.resource.WorkbasketResource;
import java.time.Instant;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
/** /**
* Transforms {@link Workbasket} to its resource counterpart {@link WorkbasketResource} and vice versa. * Transforms {@link Workbasket} to its resource counterpart {@link WorkbasketResource} and vice versa.
*/ */

View File

@ -0,0 +1,84 @@
package pro.taskana.rest.resource.assembler;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
<<<<<<< HEAD
import pro.taskana.WorkbasketAccessItem;
=======
>>>>>>> a89fa20c... TSK-694 - Show list of all access items valid for a user (REST)
import pro.taskana.WorkbasketAccessItemExtended;
import pro.taskana.WorkbasketService;
import pro.taskana.impl.WorkbasketAccessItemExtendedImpl;
import pro.taskana.rest.TestConfiguration;
import pro.taskana.rest.resource.WorkbasketAccesItemExtendedResource;
/**
* Test for {@link WorkbasketAccessItemExtendedAssembler}.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfiguration.class})
@WebAppConfiguration
public class WorkbasketAccessItemExtendedAssemblerTest {
@Autowired
WorkbasketAccessItemExtendedAssembler workbasketAccessItemExtendedAssembler;
@Autowired
WorkbasketService workbasketService;
@Test
public void workbasketAccessItemExtendedToResource() {
// given
WorkbasketAccessItemExtended workbasketAccessItemExtended = workbasketService.newWorkbasketAccessItemExtended("workbasketId",
"accessId");
((WorkbasketAccessItemExtendedImpl) workbasketAccessItemExtended).setWorkbasketKey("workbasketKey");
((WorkbasketAccessItemExtendedImpl) workbasketAccessItemExtended).setId("id");
workbasketAccessItemExtended.setAccessName("Name");
workbasketAccessItemExtended.setPermAppend(true);
workbasketAccessItemExtended.setPermCustom1(true);
workbasketAccessItemExtended.setPermCustom2(true);
workbasketAccessItemExtended.setPermCustom3(true);
workbasketAccessItemExtended.setPermCustom4(true);
workbasketAccessItemExtended.setPermCustom5(true);
workbasketAccessItemExtended.setPermCustom6(true);
workbasketAccessItemExtended.setPermCustom7(true);
workbasketAccessItemExtended.setPermCustom8(true);
workbasketAccessItemExtended.setPermCustom9(true);
workbasketAccessItemExtended.setPermCustom10(true);
workbasketAccessItemExtended.setPermCustom11(true);
workbasketAccessItemExtended.setPermCustom12(true);
workbasketAccessItemExtended.setPermDistribute(true);
workbasketAccessItemExtended.setPermOpen(true);
workbasketAccessItemExtended.setPermRead(true);
workbasketAccessItemExtended.setPermTransfer(true);
workbasketAccessItemExtended.setPermDistribute(true);
// when
WorkbasketAccesItemExtendedResource workbasketAccesItemExtendedResource = workbasketAccessItemExtendedAssembler.toResource(workbasketAccessItemExtended);
// then
Assert.assertEquals(workbasketAccessItemExtended.getWorkbasketId(), workbasketAccesItemExtendedResource.workbasketId);
Assert.assertEquals(workbasketAccessItemExtended.getWorkbasketKey(), workbasketAccesItemExtendedResource.workbasketKey);
Assert.assertEquals(workbasketAccessItemExtended.getId(), workbasketAccesItemExtendedResource.accessItemId);
Assert.assertEquals(workbasketAccessItemExtended.getAccessId(), workbasketAccesItemExtendedResource.accessId);
Assert.assertEquals(workbasketAccessItemExtended.getAccessName(), workbasketAccesItemExtendedResource.accessName);
Assert.assertEquals(workbasketAccessItemExtended.isPermAppend(), workbasketAccesItemExtendedResource.permAppend);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom1(), workbasketAccesItemExtendedResource.permCustom1);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom2(), workbasketAccesItemExtendedResource.permCustom2);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom3(), workbasketAccesItemExtendedResource.permCustom3);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom4(), workbasketAccesItemExtendedResource.permCustom4);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom5(), workbasketAccesItemExtendedResource.permCustom5);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom6(), workbasketAccesItemExtendedResource.permCustom6);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom7(), workbasketAccesItemExtendedResource.permCustom7);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom8(), workbasketAccesItemExtendedResource.permCustom8);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom9(), workbasketAccesItemExtendedResource.permCustom9);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom10(), workbasketAccesItemExtendedResource.permCustom10);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom11(), workbasketAccesItemExtendedResource.permCustom11);
Assert.assertEquals(workbasketAccessItemExtended.isPermCustom12(), workbasketAccesItemExtendedResource.permCustom12);
}
}