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,23 +12,113 @@ 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());
}); });
List<AccessIdResource> result = usersAndGroups.subList(0, List<AccessIdResource> result = usersAndGroups.subList(0,
Math.min(usersAndGroups.size(), maxNumerOfReturnedAccessIds)); Math.min(usersAndGroups.size(), maxNumerOfReturnedAccessIds));
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);
} }
@ -131,12 +134,9 @@ public class LdapClient {
LOGGER.debug("entry to searchUsersAndGroups(name = {})", name); LOGGER.debug("entry to searchUsersAndGroups(name = {})", name);
if (!active) { if (!active) {
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) {
throw new InvalidArgumentException("searchFor string " + name + " is too short. Minimum Length = "
+ getMinSearchForLength());
} }
testMinSearchForLength(name);
List<AccessIdResource> users = searchUsersByName(name); List<AccessIdResource> users = searchUsersByName(name);
users.addAll(searchGroupsByName(name)); users.addAll(searchGroupsByName(name));
@ -146,7 +146,7 @@ public class LdapClient {
List<AccessIdResource> result = users.subList(0, Math.min(users.size(), maxNumberOfReturnedAccessIds)); List<AccessIdResource> result = users.subList(0, Math.min(users.size(), maxNumberOfReturnedAccessIds));
LOGGER.debug("exit from searchUsersAndGroups(name = {}). Returning {} users and groups: {}", name, users.size(), LOGGER.debug("exit from searchUsersAndGroups(name = {}). Returning {} users and groups: {}", name, users.size(),
LoggerUtils.listToString(result)); LoggerUtils.listToString(result));
return result; return result;
} }
@ -155,12 +155,9 @@ public class LdapClient {
LOGGER.debug("entry to searchUsersByName(name = {}).", name); LOGGER.debug("entry to searchUsersByName(name = {}).", name);
if (!active) { if (!active) {
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) {
throw new InvalidArgumentException("searchFor string " + name + " is too short. Minimum Length = "
+ getMinSearchForLength());
} }
testMinSearchForLength(name);
final AndFilter andFilter = new AndFilter(); final AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(getUserSearchFilterName(), getUserSearchFilterValue())); andFilter.and(new EqualsFilter(getUserSearchFilterName(), getUserSearchFilterValue()));
@ -172,12 +169,12 @@ public class LdapClient {
andFilter.and(orFilter); andFilter.and(orFilter);
String[] userAttributesToReturn = {getUserFirstnameAttribute(), getUserLastnameAttribute(), String[] userAttributesToReturn = {getUserFirstnameAttribute(), getUserLastnameAttribute(),
getUserIdAttribute()}; getUserIdAttribute()};
final List<AccessIdResource> accessIds = ldapTemplate.search(getUserSearchBase(), andFilter.encode(), final List<AccessIdResource> accessIds = ldapTemplate.search(getUserSearchBase(), andFilter.encode(),
SearchControls.SUBTREE_SCOPE, userAttributesToReturn, new UserContextMapper()); SearchControls.SUBTREE_SCOPE, userAttributesToReturn, new UserContextMapper());
LOGGER.debug("exit from searchUsersByName. Retrieved the following users: {}.", LOGGER.debug("exit from searchUsersByName. Retrieved the following users: {}.",
LoggerUtils.listToString(accessIds)); LoggerUtils.listToString(accessIds));
return accessIds; return accessIds;
} }
@ -186,12 +183,9 @@ public class LdapClient {
LOGGER.debug("entry to searchGroupsByName(name = {}).", name); LOGGER.debug("entry to searchGroupsByName(name = {}).", name);
if (!active) { if (!active) {
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) {
throw new InvalidArgumentException("searchFor string " + name + " is too short. Minimum Length = "
+ getMinSearchForLength());
} }
testMinSearchForLength(name);
final AndFilter andFilter = new AndFilter(); final AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(getGroupSearchFilterName(), getGroupSearchFilterValue())); andFilter.and(new EqualsFilter(getGroupSearchFilterName(), getGroupSearchFilterValue()));
@ -210,13 +204,42 @@ public class LdapClient {
} }
final List<AccessIdResource> accessIds = ldapTemplate.search(getGroupSearchBase(), andFilter.encode(), final List<AccessIdResource> accessIds = ldapTemplate.search(getGroupSearchBase(), andFilter.encode(),
SearchControls.SUBTREE_SCOPE, groupAttributesToReturn, new GroupContextMapper()); SearchControls.SUBTREE_SCOPE, groupAttributesToReturn, new GroupContextMapper());
LOGGER.debug("Exit from searchGroupsByName. Retrieved the following groups: {}", LOGGER.debug("Exit from searchGroupsByName. Retrieved the following groups: {}",
LoggerUtils.listToString(accessIds)); LoggerUtils.listToString(accessIds));
return accessIds; return accessIds;
} }
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) {
return new ResponseEntity<>( if (searchInGroups) {
ldapCache.findMatchingAccessId(searchFor, ldapClient.getMaxNumberOfReturnedAccessIds()), return new ResponseEntity<>(
HttpStatus.OK); ldapCache.findGroupsOfUser(searchFor, ldapClient.getMaxNumberOfReturnedAccessIds()),
HttpStatus.OK);
} else {
return new ResponseEntity<>(
ldapCache.findMatchingAccessId(searchFor, ldapClient.getMaxNumberOfReturnedAccessIds()),
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.
@ -94,7 +69,7 @@ public class WorkbasketController extends AbstractPagingController {
@GetMapping @GetMapping
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<PagedResources<WorkbasketSummaryResource>> getWorkbaskets( public ResponseEntity<PagedResources<WorkbasketSummaryResource>> getWorkbaskets(
@RequestParam MultiValueMap<String, String> params) throws InvalidArgumentException { @RequestParam MultiValueMap<String, String> params) throws InvalidArgumentException {
WorkbasketQuery query = workbasketService.createWorkbasketQuery(); WorkbasketQuery query = workbasketService.createWorkbasketQuery();
query = applySortingParams(query, params); query = applySortingParams(query, params);
@ -112,7 +87,7 @@ public class WorkbasketController extends AbstractPagingController {
long totalElements = query.count(); long totalElements = query.count();
pageMetadata = initPageMetadata(pageSize, page, totalElements); pageMetadata = initPageMetadata(pageSize, page, totalElements);
workbasketSummaries = query.listPage((int) pageMetadata.getNumber(), workbasketSummaries = query.listPage((int) pageMetadata.getNumber(),
(int) pageMetadata.getSize()); (int) pageMetadata.getSize());
} else if (page == null && pageSize == null) { } else if (page == null && pageSize == null) {
// not paging // not paging
workbasketSummaries = query.list(); workbasketSummaries = query.list();
@ -122,7 +97,7 @@ public class WorkbasketController extends AbstractPagingController {
WorkbasketSummaryResourcesAssembler assembler = new WorkbasketSummaryResourcesAssembler(); WorkbasketSummaryResourcesAssembler assembler = new WorkbasketSummaryResourcesAssembler();
PagedResources<WorkbasketSummaryResource> pagedResources = assembler.toResources(workbasketSummaries, PagedResources<WorkbasketSummaryResource> pagedResources = assembler.toResources(workbasketSummaries,
pageMetadata); pageMetadata);
return new ResponseEntity<>(pagedResources, HttpStatus.OK); return new ResponseEntity<>(pagedResources, HttpStatus.OK);
} }
@ -130,7 +105,7 @@ public class WorkbasketController extends AbstractPagingController {
@GetMapping(path = "/{workbasketId}") @GetMapping(path = "/{workbasketId}")
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<WorkbasketResource> getWorkbasket(@PathVariable(value = "workbasketId") String workbasketId) public ResponseEntity<WorkbasketResource> getWorkbasket(@PathVariable(value = "workbasketId") String workbasketId)
throws WorkbasketNotFoundException, NotAuthorizedException { throws WorkbasketNotFoundException, NotAuthorizedException {
ResponseEntity<WorkbasketResource> result; ResponseEntity<WorkbasketResource> result;
Workbasket workbasket = workbasketService.getWorkbasket(workbasketId); Workbasket workbasket = workbasketService.getWorkbasket(workbasketId);
result = new ResponseEntity<>(workbasketAssembler.toResource(workbasket), HttpStatus.OK); result = new ResponseEntity<>(workbasketAssembler.toResource(workbasket), HttpStatus.OK);
@ -140,7 +115,7 @@ public class WorkbasketController extends AbstractPagingController {
@DeleteMapping(path = "/{workbasketId}") @DeleteMapping(path = "/{workbasketId}")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<?> deleteWorkbasket(@PathVariable(value = "workbasketId") String workbasketId) public ResponseEntity<?> deleteWorkbasket(@PathVariable(value = "workbasketId") String workbasketId)
throws WorkbasketNotFoundException, NotAuthorizedException, WorkbasketInUseException, InvalidArgumentException { throws WorkbasketNotFoundException, NotAuthorizedException, WorkbasketInUseException, InvalidArgumentException {
ResponseEntity<?> result = ResponseEntity.status(HttpStatus.NO_CONTENT).build(); ResponseEntity<?> result = ResponseEntity.status(HttpStatus.NO_CONTENT).build();
workbasketService.deleteWorkbasket(workbasketId); workbasketService.deleteWorkbasket(workbasketId);
return result; return result;
@ -149,8 +124,8 @@ public class WorkbasketController extends AbstractPagingController {
@PostMapping @PostMapping
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<WorkbasketResource> createWorkbasket(@RequestBody WorkbasketResource workbasketResource) public ResponseEntity<WorkbasketResource> createWorkbasket(@RequestBody WorkbasketResource workbasketResource)
throws InvalidWorkbasketException, NotAuthorizedException, WorkbasketAlreadyExistException, throws InvalidWorkbasketException, NotAuthorizedException, WorkbasketAlreadyExistException,
WorkbasketNotFoundException, DomainNotFoundException { WorkbasketNotFoundException, DomainNotFoundException {
Workbasket workbasket = workbasketAssembler.toModel(workbasketResource); Workbasket workbasket = workbasketAssembler.toModel(workbasketResource);
workbasket = workbasketService.createWorkbasket(workbasket); workbasket = workbasketService.createWorkbasket(workbasket);
return new ResponseEntity<>(workbasketAssembler.toResource(workbasket), HttpStatus.CREATED); return new ResponseEntity<>(workbasketAssembler.toResource(workbasket), HttpStatus.CREATED);
@ -159,9 +134,9 @@ public class WorkbasketController extends AbstractPagingController {
@PutMapping(path = "/{workbasketId}") @PutMapping(path = "/{workbasketId}")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<WorkbasketResource> updateWorkbasket( public ResponseEntity<WorkbasketResource> updateWorkbasket(
@PathVariable(value = "workbasketId") String workbasketId, @PathVariable(value = "workbasketId") String workbasketId,
@RequestBody WorkbasketResource workbasketResource) @RequestBody WorkbasketResource workbasketResource)
throws InvalidWorkbasketException, WorkbasketNotFoundException, NotAuthorizedException { throws InvalidWorkbasketException, WorkbasketNotFoundException, NotAuthorizedException {
ResponseEntity<WorkbasketResource> result; ResponseEntity<WorkbasketResource> result;
if (workbasketId.equals(workbasketResource.workbasketId)) { if (workbasketId.equals(workbasketResource.workbasketId)) {
Workbasket workbasket = workbasketAssembler.toModel(workbasketResource); Workbasket workbasket = workbasketAssembler.toModel(workbasketResource);
@ -169,9 +144,9 @@ public class WorkbasketController extends AbstractPagingController {
result = ResponseEntity.ok(workbasketAssembler.toResource(workbasket)); result = ResponseEntity.ok(workbasketAssembler.toResource(workbasket));
} else { } else {
throw new InvalidWorkbasketException( throw new InvalidWorkbasketException(
"Target-WB-ID('" + workbasketId "Target-WB-ID('" + workbasketId
+ "') is not identical with the WB-ID of to object which should be updated. ID=('" + "') is not identical with the WB-ID of to object which should be updated. ID=('"
+ workbasketResource.getId() + "')"); + workbasketResource.getId() + "')");
} }
return result; return result;
@ -180,14 +155,14 @@ public class WorkbasketController extends AbstractPagingController {
@GetMapping(path = "/{workbasketId}/workbasketAccessItems") @GetMapping(path = "/{workbasketId}/workbasketAccessItems")
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<Resources<WorkbasketAccessItemResource>> getWorkbasketAccessItems( public ResponseEntity<Resources<WorkbasketAccessItemResource>> getWorkbasketAccessItems(
@PathVariable(value = "workbasketId") String workbasketId) @PathVariable(value = "workbasketId") String workbasketId)
throws NotAuthorizedException, WorkbasketNotFoundException { throws NotAuthorizedException, WorkbasketNotFoundException {
ResponseEntity<Resources<WorkbasketAccessItemResource>> result; ResponseEntity<Resources<WorkbasketAccessItemResource>> result;
List<WorkbasketAccessItem> accessItems = workbasketService.getWorkbasketAccessItems(workbasketId); List<WorkbasketAccessItem> accessItems = workbasketService.getWorkbasketAccessItems(workbasketId);
Resources<WorkbasketAccessItemResource> accessItemListResource = accessItemListAssembler Resources<WorkbasketAccessItemResource> accessItemListResource = accessItemListAssembler
.toResource(workbasketId, accessItems); .toResource(workbasketId, accessItems);
result = new ResponseEntity<>(accessItemListResource, HttpStatus.OK); result = new ResponseEntity<>(accessItemListResource, HttpStatus.OK);
return result; return result;
} }
@ -195,9 +170,9 @@ public class WorkbasketController extends AbstractPagingController {
@PutMapping(value = "/{workbasketId}/workbasketAccessItems") @PutMapping(value = "/{workbasketId}/workbasketAccessItems")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<Resources<WorkbasketAccessItemResource>> setWorkbasketAccessItems( public ResponseEntity<Resources<WorkbasketAccessItemResource>> setWorkbasketAccessItems(
@PathVariable(value = "workbasketId") String workbasketId, @PathVariable(value = "workbasketId") String workbasketId,
@RequestBody List<WorkbasketAccessItemResource> workbasketAccessResourceItems) @RequestBody List<WorkbasketAccessItemResource> workbasketAccessResourceItems)
throws NotAuthorizedException, InvalidArgumentException, WorkbasketNotFoundException { throws NotAuthorizedException, InvalidArgumentException, WorkbasketNotFoundException {
if (workbasketAccessResourceItems == null) { if (workbasketAccessResourceItems == null) {
throw new InvalidArgumentException("Can´t create something with NULL body-value."); throw new InvalidArgumentException("Can´t create something with NULL body-value.");
} }
@ -208,7 +183,7 @@ public class WorkbasketController extends AbstractPagingController {
List<WorkbasketAccessItem> updatedWbAccessItems = workbasketService.getWorkbasketAccessItems(workbasketId); List<WorkbasketAccessItem> updatedWbAccessItems = workbasketService.getWorkbasketAccessItems(workbasketId);
Resources<WorkbasketAccessItemResource> accessItemListResource = accessItemListAssembler Resources<WorkbasketAccessItemResource> accessItemListResource = accessItemListAssembler
.toResource(workbasketId, updatedWbAccessItems); .toResource(workbasketId, updatedWbAccessItems);
return new ResponseEntity<>(accessItemListResource, HttpStatus.OK); return new ResponseEntity<>(accessItemListResource, HttpStatus.OK);
} }
@ -216,13 +191,13 @@ public class WorkbasketController extends AbstractPagingController {
@GetMapping(path = "/{workbasketId}/distribution-targets") @GetMapping(path = "/{workbasketId}/distribution-targets")
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<Resources<DistributionTargetResource>> getDistributionTargets( public ResponseEntity<Resources<DistributionTargetResource>> getDistributionTargets(
@PathVariable(value = "workbasketId") String workbasketId) @PathVariable(value = "workbasketId") String workbasketId)
throws WorkbasketNotFoundException, NotAuthorizedException { throws WorkbasketNotFoundException, NotAuthorizedException {
ResponseEntity<Resources<DistributionTargetResource>> result; ResponseEntity<Resources<DistributionTargetResource>> result;
List<WorkbasketSummary> distributionTargets = workbasketService.getDistributionTargets(workbasketId); List<WorkbasketSummary> distributionTargets = workbasketService.getDistributionTargets(workbasketId);
Resources<DistributionTargetResource> distributionTargetListResource = distributionTargetListAssembler Resources<DistributionTargetResource> distributionTargetListResource = distributionTargetListAssembler
.toResource(workbasketId, distributionTargets); .toResource(workbasketId, distributionTargets);
result = new ResponseEntity<>(distributionTargetListResource, HttpStatus.OK); result = new ResponseEntity<>(distributionTargetListResource, HttpStatus.OK);
return result; return result;
} }
@ -230,13 +205,13 @@ public class WorkbasketController extends AbstractPagingController {
@PutMapping(path = "/{workbasketId}/distribution-targets") @PutMapping(path = "/{workbasketId}/distribution-targets")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<Resources<DistributionTargetResource>> setDistributionTargetsForWorkbasketId( public ResponseEntity<Resources<DistributionTargetResource>> setDistributionTargetsForWorkbasketId(
@PathVariable(value = "workbasketId") String sourceWorkbasketId, @PathVariable(value = "workbasketId") String sourceWorkbasketId,
@RequestBody List<String> targetWorkbasketIds) throws WorkbasketNotFoundException, NotAuthorizedException { @RequestBody List<String> targetWorkbasketIds) throws WorkbasketNotFoundException, NotAuthorizedException {
workbasketService.setDistributionTargets(sourceWorkbasketId, targetWorkbasketIds); workbasketService.setDistributionTargets(sourceWorkbasketId, targetWorkbasketIds);
List<WorkbasketSummary> distributionTargets = workbasketService.getDistributionTargets(sourceWorkbasketId); List<WorkbasketSummary> distributionTargets = workbasketService.getDistributionTargets(sourceWorkbasketId);
Resources<DistributionTargetResource> distributionTargetListResource = distributionTargetListAssembler Resources<DistributionTargetResource> distributionTargetListResource = distributionTargetListAssembler
.toResource(sourceWorkbasketId, distributionTargets); .toResource(sourceWorkbasketId, distributionTargets);
return new ResponseEntity<>(distributionTargetListResource, HttpStatus.OK); return new ResponseEntity<>(distributionTargetListResource, HttpStatus.OK);
} }
@ -244,8 +219,8 @@ public class WorkbasketController extends AbstractPagingController {
@DeleteMapping(path = "/distribution-targets/{workbasketId}") @DeleteMapping(path = "/distribution-targets/{workbasketId}")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<Resources<DistributionTargetResource>> removeDistributionTargetForWorkbasketId( public ResponseEntity<Resources<DistributionTargetResource>> removeDistributionTargetForWorkbasketId(
@PathVariable(value = "workbasketId") String targetWorkbasketId) @PathVariable(value = "workbasketId") String targetWorkbasketId)
throws WorkbasketNotFoundException, NotAuthorizedException { throws WorkbasketNotFoundException, NotAuthorizedException {
List<WorkbasketSummary> sourceWorkbaskets = workbasketService.getDistributionSources(targetWorkbasketId); List<WorkbasketSummary> sourceWorkbaskets = workbasketService.getDistributionSources(targetWorkbasketId);
for (WorkbasketSummary source : sourceWorkbaskets) { for (WorkbasketSummary source : sourceWorkbaskets) {
workbasketService.removeDistributionTarget(source.getId(), targetWorkbasketId); workbasketService.removeDistributionTarget(source.getId(), targetWorkbasketId);
@ -255,7 +230,7 @@ public class WorkbasketController extends AbstractPagingController {
} }
private WorkbasketQuery applySortingParams(WorkbasketQuery query, MultiValueMap<String, String> params) private WorkbasketQuery applySortingParams(WorkbasketQuery query, MultiValueMap<String, String> params)
throws IllegalArgumentException { throws IllegalArgumentException {
// sorting // sorting
String sortBy = params.getFirst(SORT_BY); String sortBy = params.getFirst(SORT_BY);
if (sortBy != null) { if (sortBy != null) {
@ -291,7 +266,7 @@ public class WorkbasketController extends AbstractPagingController {
} }
private WorkbasketQuery applyFilterParams(WorkbasketQuery query, private WorkbasketQuery applyFilterParams(WorkbasketQuery query,
MultiValueMap<String, String> params) throws InvalidArgumentException { MultiValueMap<String, String> params) throws InvalidArgumentException {
if (params.containsKey(NAME)) { if (params.containsKey(NAME)) {
String[] names = extractCommaSeparatedFields(params.get(NAME)); String[] names = extractCommaSeparatedFields(params.get(NAME));
query.nameIn(names); query.nameIn(names);

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.
@ -26,7 +25,7 @@ public class WorkbasketAccessItemAssembler {
private WorkbasketService workbasketService; private WorkbasketService workbasketService;
public WorkbasketAccessItemResource toResource(WorkbasketAccessItem wbAccItem) public WorkbasketAccessItemResource toResource(WorkbasketAccessItem wbAccItem)
throws NotAuthorizedException, WorkbasketNotFoundException { throws NotAuthorizedException, WorkbasketNotFoundException {
WorkbasketAccessItemResource resource = new WorkbasketAccessItemResource(); WorkbasketAccessItemResource resource = new WorkbasketAccessItemResource();
BeanUtils.copyProperties(wbAccItem, resource); BeanUtils.copyProperties(wbAccItem, resource);
// property is named different, so it needs to be set by hand // property is named different, so it needs to be set by hand
@ -37,7 +36,7 @@ public class WorkbasketAccessItemAssembler {
public WorkbasketAccessItem toModel(WorkbasketAccessItemResource wbAccItemRecource) { public WorkbasketAccessItem toModel(WorkbasketAccessItemResource wbAccItemRecource) {
WorkbasketAccessItemImpl wbAccItemModel = (WorkbasketAccessItemImpl) workbasketService.newWorkbasketAccessItem( WorkbasketAccessItemImpl wbAccItemModel = (WorkbasketAccessItemImpl) workbasketService.newWorkbasketAccessItem(
wbAccItemRecource.workbasketId, wbAccItemRecource.accessId); wbAccItemRecource.workbasketId, wbAccItemRecource.accessId);
BeanUtils.copyProperties(wbAccItemRecource, wbAccItemModel); BeanUtils.copyProperties(wbAccItemRecource, wbAccItemModel);
wbAccItemModel.setId(wbAccItemRecource.accessItemId); wbAccItemModel.setId(wbAccItemRecource.accessItemId);
@ -45,11 +44,11 @@ public class WorkbasketAccessItemAssembler {
} }
private WorkbasketAccessItemResource addLinks(WorkbasketAccessItemResource resource, WorkbasketAccessItem wbAccItem) private WorkbasketAccessItemResource addLinks(WorkbasketAccessItemResource resource, WorkbasketAccessItem wbAccItem)
throws NotAuthorizedException, WorkbasketNotFoundException { throws NotAuthorizedException, WorkbasketNotFoundException {
resource.add( resource.add(
linkTo(methodOn(WorkbasketController.class).getWorkbasket(wbAccItem.getWorkbasketId())) linkTo(methodOn(WorkbasketController.class).getWorkbasket(wbAccItem.getWorkbasketId()))
.withRel("workbasket")); .withRel("workbasket"));
return resource; return resource;
} }
} }

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.
*/ */
@ -27,7 +26,7 @@ public class WorkbasketAccessItemListAssembler {
private WorkbasketAccessItemAssembler workbasketAccessItemAssembler; private WorkbasketAccessItemAssembler workbasketAccessItemAssembler;
public Resources<WorkbasketAccessItemResource> toResource(String workbasketId, public Resources<WorkbasketAccessItemResource> toResource(String workbasketId,
Collection<WorkbasketAccessItem> accessItems) throws NotAuthorizedException, WorkbasketNotFoundException { Collection<WorkbasketAccessItem> accessItems) throws NotAuthorizedException, WorkbasketNotFoundException {
List<WorkbasketAccessItemResource> resourceList = new ArrayList<>(); List<WorkbasketAccessItemResource> resourceList = new ArrayList<>();
for (WorkbasketAccessItem accessItem : accessItems) { for (WorkbasketAccessItem accessItem : accessItems) {
resourceList.add(workbasketAccessItemAssembler.toResource(accessItem)); resourceList.add(workbasketAccessItemAssembler.toResource(accessItem));
@ -36,11 +35,11 @@ public class WorkbasketAccessItemListAssembler {
Resources<WorkbasketAccessItemResource> accessItemListResource = new Resources<>(resourceList); Resources<WorkbasketAccessItemResource> accessItemListResource = new Resources<>(resourceList);
accessItemListResource accessItemListResource
.add(linkTo(methodOn(WorkbasketController.class).getWorkbasketAccessItems(workbasketId)) .add(linkTo(methodOn(WorkbasketController.class).getWorkbasketAccessItems(workbasketId))
.withSelfRel()); .withSelfRel());
accessItemListResource accessItemListResource
.add(linkTo(methodOn(WorkbasketController.class).getWorkbasket(workbasketId)) .add(linkTo(methodOn(WorkbasketController.class).getWorkbasket(workbasketId))
.withRel("workbasket")); .withRel("workbasket"));
return accessItemListResource; return accessItemListResource;
} }

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.
*/ */
@ -48,15 +47,15 @@ public class WorkbasketAssembler {
} }
private WorkbasketResource addLinks(WorkbasketResource resource, Workbasket wb) private WorkbasketResource addLinks(WorkbasketResource resource, Workbasket wb)
throws NotAuthorizedException, WorkbasketNotFoundException { throws NotAuthorizedException, WorkbasketNotFoundException {
resource.add(linkTo(methodOn(WorkbasketController.class).getWorkbasket(wb.getId())).withSelfRel()); resource.add(linkTo(methodOn(WorkbasketController.class).getWorkbasket(wb.getId())).withSelfRel());
resource.add(linkTo(methodOn(WorkbasketController.class).getDistributionTargets(wb.getId())) resource.add(linkTo(methodOn(WorkbasketController.class).getDistributionTargets(wb.getId()))
.withRel("distributionTargets")); .withRel("distributionTargets"));
resource.add(linkTo(methodOn(WorkbasketController.class).getWorkbasketAccessItems(wb.getId())) resource.add(linkTo(methodOn(WorkbasketController.class).getWorkbasketAccessItems(wb.getId()))
.withRel("accessItems")); .withRel("accessItems"));
resource.add(linkTo(WorkbasketController.class).withRel("allWorkbaskets")); resource.add(linkTo(WorkbasketController.class).withRel("allWorkbaskets"));
resource.add(linkTo(methodOn(WorkbasketController.class).removeDistributionTargetForWorkbasketId(wb.getId())) resource.add(linkTo(methodOn(WorkbasketController.class).removeDistributionTargetForWorkbasketId(wb.getId()))
.withRel("removeDistributionTargets")); .withRel("removeDistributionTargets"));
return resource; return resource;
} }
} }

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);
}
}