TSK-789: Workbasket export does not contain authorizations

This commit is contained in:
Jose Ignacio Recuerda Cambil 2019-02-20 17:59:17 +01:00 committed by Holger Hagen
parent efc121257d
commit bcf031c22d
6 changed files with 170 additions and 83 deletions

View File

@ -2,8 +2,14 @@ package pro.taskana.rest;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -13,8 +19,10 @@ import org.junit.runner.RunWith;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort; import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.FileSystemResource;
import org.springframework.hateoas.hal.Jackson2HalModule; import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
@ -25,28 +33,27 @@ import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import pro.taskana.rest.resource.WorkbasketDefinition; import pro.taskana.rest.resource.WorkbasketDefinitionResource;
/**
* Test workbasket definitions.
*/
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = RestConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @SpringBootTest(classes = RestConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class WorkbasketDefinitionControllerIntTest { public class WorkbasketDefinitionControllerIntTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationController.class); private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationController.class);
private String server = "http://127.0.0.1:"; private String server = "http://127.0.0.1:";
RestTemplate template; private RestTemplate template;
private HttpEntity<String> request; private HttpEntity<String> request;
private HttpHeaders headers = new HttpHeaders(); private HttpHeaders headers = new HttpHeaders();
private ObjectMapper objMapper = new ObjectMapper();
@LocalServerPort @LocalServerPort
int port; private int port;
@Before @Before
public void before() { public void before() {
@ -57,27 +64,73 @@ public class WorkbasketDefinitionControllerIntTest {
} }
@Test @Test
public void exportWorkbasketFromDomain() { public void testExportWorkbasketFromDomain() {
ResponseEntity<List<WorkbasketDefinition>> response = template.exchange( ResponseEntity<List<WorkbasketDefinitionResource>> response = template.exchange(
this.server + this.port + "/v1/workbasket-definitions?domain=DOMAIN_A", server + port + "/v1/workbasket-definitions?domain=DOMAIN_A", HttpMethod.GET, request,
HttpMethod.GET, request, new ParameterizedTypeReference<List<WorkbasketDefinition>>() { new ParameterizedTypeReference<List<WorkbasketDefinitionResource>>() {
}); });
assertNotNull(response.getBody());
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertThat(response.getBody().get(0), instanceOf(WorkbasketDefinition.class)); assertThat(response.getBody().get(0), instanceOf(WorkbasketDefinitionResource.class));
assertEquals(11, response.getBody().size());
boolean allAuthorizationsAreEmpty = true, allDistributionTargetsAreEmpty = true;
for (WorkbasketDefinitionResource workbasketDefinition : response.getBody()) {
if (allAuthorizationsAreEmpty && !workbasketDefinition.getAuthorizations().isEmpty()) {
allAuthorizationsAreEmpty = false;
}
if (allDistributionTargetsAreEmpty && !workbasketDefinition.getDistributionTargets().isEmpty()) {
allDistributionTargetsAreEmpty = false;
}
if (!allAuthorizationsAreEmpty && !allDistributionTargetsAreEmpty) {
break;
}
}
assertFalse(allDistributionTargetsAreEmpty);
assertFalse(allAuthorizationsAreEmpty);
} }
@Test @Test
public void exportWorkbasketFromWrongDomain() { public void testExportWorkbasketsFromWrongDomain() {
ResponseEntity<List<WorkbasketDefinition>> response = template.exchange( ResponseEntity<List<WorkbasketDefinitionResource>> response = template.exchange(
this.server + this.port + "/v1/workbasket-definitions?domain=wrongDomain", server + port + "/v1/workbasket-definitions?domain=wrongDomain",
HttpMethod.GET, request, new ParameterizedTypeReference<List<WorkbasketDefinition>>() { HttpMethod.GET, request, new ParameterizedTypeReference<List<WorkbasketDefinitionResource>>() {
}); });
assertEquals(0, response.getBody().size()); assertEquals(0, response.getBody().size());
} }
@Test
public void testImportWorkbasket() throws IOException {
ResponseEntity<List<WorkbasketDefinitionResource>> response = template.exchange(
server + port + "/v1/workbasket-definitions?domain=DOMAIN_A",
HttpMethod.GET, request, new ParameterizedTypeReference<List<WorkbasketDefinitionResource>>() {
});
List<String> list = new ArrayList<>();
list.add(objMapper.writeValueAsString(response.getBody().get(0)));
ResponseEntity<String> responseImport = importRequest(list);
assertEquals(HttpStatus.OK, responseImport.getStatusCode());
}
private ResponseEntity<String> importRequest(List<String> clList) throws IOException {
File tmpFile = File.createTempFile("test", ".tmp");
FileWriter writer = new FileWriter(tmpFile);
writer.write(clList.toString());
writer.close();
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
body.add("file", new FileSystemResource(tmpFile));
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String serverUrl = server + port + "/v1/workbasket-definitions";
RestTemplate restTemplate = new RestTemplate();
return restTemplate.postForEntity(serverUrl, requestEntity, String.class);
}
/** /**
* Return a REST template which is capable of dealing with responses in HAL format. * Return a REST template which is capable of dealing with responses in HAL format.
* *
@ -94,5 +147,4 @@ public class WorkbasketDefinitionControllerIntTest {
return new RestTemplate(Collections.<HttpMessageConverter<?>>singletonList(converter)); return new RestTemplate(Collections.<HttpMessageConverter<?>>singletonList(converter));
} }
} }

View File

@ -37,11 +37,11 @@ import pro.taskana.exceptions.InvalidWorkbasketException;
import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.WorkbasketAlreadyExistException; import pro.taskana.exceptions.WorkbasketAlreadyExistException;
import pro.taskana.exceptions.WorkbasketNotFoundException; import pro.taskana.exceptions.WorkbasketNotFoundException;
import pro.taskana.rest.resource.WorkbasketDefinition; import pro.taskana.rest.resource.WorkbasketDefinitionResource;
import pro.taskana.rest.resource.WorkbasketDefinitionAssembler; import pro.taskana.rest.resource.WorkbasketDefinitionResourceAssembler;
/** /**
* Controller for all {@link WorkbasketDefinition} related endpoints. * Controller for all {@link WorkbasketDefinitionResource} related endpoints.
*/ */
@RestController @RestController
@RequestMapping(path = "/v1/workbasket-definitions", produces = {MediaType.APPLICATION_JSON_VALUE}) @RequestMapping(path = "/v1/workbasket-definitions", produces = {MediaType.APPLICATION_JSON_VALUE})
@ -53,21 +53,21 @@ public class WorkbasketDefinitionController {
private WorkbasketService workbasketService; private WorkbasketService workbasketService;
@Autowired @Autowired
private WorkbasketDefinitionAssembler workbasketDefinitionAssembler; private WorkbasketDefinitionResourceAssembler workbasketDefinitionAssembler;
@GetMapping @GetMapping
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<List<WorkbasketDefinition>> exportWorkbaskets(@RequestParam(required = false) String domain) public ResponseEntity<List<WorkbasketDefinitionResource>> exportWorkbaskets(@RequestParam(required = false) String domain)
throws NotAuthorizedException, WorkbasketNotFoundException { throws NotAuthorizedException, WorkbasketNotFoundException {
LOGGER.debug("Entry to exportWorkbaskets(domain= {})", domain); LOGGER.debug("Entry to exportWorkbaskets(domain= {})", domain);
WorkbasketQuery workbasketQuery = workbasketService.createWorkbasketQuery(); WorkbasketQuery workbasketQuery = workbasketService.createWorkbasketQuery();
List<WorkbasketSummary> workbasketSummaryList = domain != null List<WorkbasketSummary> workbasketSummaryList = domain != null
? workbasketQuery.domainIn(domain).list() ? workbasketQuery.domainIn(domain).list()
: workbasketQuery.list(); : workbasketQuery.list();
List<WorkbasketDefinition> basketExports = new ArrayList<>(); List<WorkbasketDefinitionResource> basketExports = new ArrayList<>();
for (WorkbasketSummary summary : workbasketSummaryList) { for (WorkbasketSummary summary : workbasketSummaryList) {
Workbasket workbasket = workbasketService.getWorkbasket(summary.getId()); Workbasket workbasket = workbasketService.getWorkbasket(summary.getId());
basketExports.add(workbasketDefinitionAssembler.toDefinition(workbasket)); basketExports.add(workbasketDefinitionAssembler.toResource(workbasket));
} }
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
@ -79,7 +79,7 @@ public class WorkbasketDefinitionController {
} }
/** /**
* This method imports a <b>list of {@link WorkbasketDefinition}</b>. This does not exactly match the REST norm, but * This method imports a <b>list of {@link WorkbasketDefinitionResource}</b>. This does not exactly match the REST norm, but
* we want to have an option to import all settings at once. When a logical equal (key and domain are equal) * we want to have an option to import all settings at once. When a logical equal (key and domain are equal)
* workbasket already exists an update will be executed. Otherwise a new workbasket will be created. * workbasket already exists an update will be executed. Otherwise a new workbasket will be created.
* *
@ -96,8 +96,8 @@ public class WorkbasketDefinitionController {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT); mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
List<WorkbasketDefinition> definitions = mapper.readValue(file.getInputStream(), List<WorkbasketDefinitionResource> definitions = mapper.readValue(file.getInputStream(),
new TypeReference<List<WorkbasketDefinition>>() { new TypeReference<List<WorkbasketDefinitionResource>>() {
}); });
@ -113,8 +113,8 @@ public class WorkbasketDefinitionController {
Map<String, String> idConversion = new HashMap<>(); Map<String, String> idConversion = new HashMap<>();
// STEP 1: update or create workbaskets from the import // STEP 1: update or create workbaskets from the import
for (WorkbasketDefinition definition : definitions) { for (WorkbasketDefinitionResource definition : definitions) {
Workbasket importedWb = workbasketDefinitionAssembler.toModel(definition.workbasket); Workbasket importedWb = workbasketDefinitionAssembler.toModel(definition.getWorkbasket());
Workbasket workbasket; Workbasket workbasket;
if (systemIds.containsKey(logicalId(importedWb))) { if (systemIds.containsKey(logicalId(importedWb))) {
workbasket = workbasketService.updateWorkbasket(importedWb); workbasket = workbasketService.updateWorkbasket(importedWb);
@ -127,7 +127,7 @@ public class WorkbasketDefinitionController {
for (WorkbasketAccessItem accessItem : workbasketService.getWorkbasketAccessItems(workbasket.getId())) { for (WorkbasketAccessItem accessItem : workbasketService.getWorkbasketAccessItems(workbasket.getId())) {
workbasketService.deleteWorkbasketAccessItem(accessItem.getId()); workbasketService.deleteWorkbasketAccessItem(accessItem.getId());
} }
for (WorkbasketAccessItem authorization : definition.authorizations) { for (WorkbasketAccessItem authorization : definition.getAuthorizations()) {
workbasketService.createWorkbasketAccessItem(authorization); workbasketService.createWorkbasketAccessItem(authorization);
} }
idConversion.put(importedWb.getId(), workbasket.getId()); idConversion.put(importedWb.getId(), workbasket.getId());
@ -135,9 +135,9 @@ public class WorkbasketDefinitionController {
// STEP 2: update distribution targets // STEP 2: update distribution targets
// This can not be done in step 1 because the system IDs are only known after step 1 // This can not be done in step 1 because the system IDs are only known after step 1
for (WorkbasketDefinition definition : definitions) { for (WorkbasketDefinitionResource definition : definitions) {
List<String> distributionTargets = new ArrayList<>(); List<String> distributionTargets = new ArrayList<>();
for (String oldId : definition.distributionTargets) { for (String oldId : definition.getDistributionTargets()) {
if (idConversion.containsKey(oldId)) { if (idConversion.containsKey(oldId)) {
distributionTargets.add(idConversion.get(oldId)); distributionTargets.add(idConversion.get(oldId));
} else { } else {
@ -150,7 +150,7 @@ public class WorkbasketDefinitionController {
workbasketService.setDistributionTargets( workbasketService.setDistributionTargets(
// no verification necessary since the workbasket was already imported in step 1. // no verification necessary since the workbasket was already imported in step 1.
idConversion.get(definition.workbasket.getWorkbasketId()), distributionTargets); idConversion.get(definition.getWorkbasket().getWorkbasketId()), distributionTargets);
} }
LOGGER.debug("Exit from importWorkbaskets(), returning {}", new ResponseEntity<>(HttpStatus.OK)); LOGGER.debug("Exit from importWorkbaskets(), returning {}", new ResponseEntity<>(HttpStatus.OK));
return new ResponseEntity<>(HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK);

View File

@ -1,39 +0,0 @@
package pro.taskana.rest.resource;
import java.util.List;
import java.util.Set;
import pro.taskana.WorkbasketAccessItem;
import pro.taskana.impl.util.LoggerUtils;
/**
* this class represents a workbasket including its distro targets and authorisations.
*/
public class WorkbasketDefinition {
public Set<String> distributionTargets;
public List<WorkbasketAccessItem> authorizations;
public WorkbasketResource workbasket;
public WorkbasketDefinition() {
// necessary for de-serializing
}
public WorkbasketDefinition(WorkbasketResource workbasket,
Set<String> distributionTargets,
List<WorkbasketAccessItem> authorizations) {
super();
this.workbasket = workbasket;
this.distributionTargets = distributionTargets;
this.authorizations = authorizations;
}
@Override
public String toString() {
return "WorkbasketDefinition ["
+ "distributionTargets= " + LoggerUtils.setToString(this.distributionTargets)
+ "authorizations= " + LoggerUtils.listToString(this.authorizations)
+ "workbasket= " + this.workbasket
+ "]";
}
}

View File

@ -0,0 +1,62 @@
package pro.taskana.rest.resource;
import java.util.List;
import java.util.Set;
import pro.taskana.impl.WorkbasketAccessItemImpl;
import pro.taskana.impl.util.LoggerUtils;
/**
* this class represents a workbasket including its distro targets and authorisations.
*/
public class WorkbasketDefinitionResource {
private Set<String> distributionTargets;
private List<WorkbasketAccessItemImpl> authorizations;
private WorkbasketResourceWithoutLinks workbasket;
public WorkbasketDefinitionResource() {
// necessary for de-serializing
}
public WorkbasketDefinitionResource(WorkbasketResourceWithoutLinks workbasket,
Set<String> distributionTargets, List<WorkbasketAccessItemImpl> authorizations) {
super();
this.workbasket = workbasket;
this.distributionTargets = distributionTargets;
this.authorizations = authorizations;
}
public Set<String> getDistributionTargets() {
return distributionTargets;
}
public void setDistributionTargets(Set<String> distributionTargets) {
this.distributionTargets = distributionTargets;
}
public List<WorkbasketAccessItemImpl> getAuthorizations() {
return authorizations;
}
public void setAuthorizations(List<WorkbasketAccessItemImpl> authorizations) {
this.authorizations = authorizations;
}
public WorkbasketResourceWithoutLinks getWorkbasket() {
return workbasket;
}
public void setWorkbasket(WorkbasketResourceWithoutLinks workbasket) {
this.workbasket = workbasket;
}
@Override
public String toString() {
return "WorkbasketDefinitionResource ["
+ "distributionTargets= " + LoggerUtils.setToString(this.distributionTargets)
+ "authorizations= " + LoggerUtils.listToString(this.authorizations)
+ "workbasket= " + this.workbasket
+ "]";
}
}

View File

@ -16,14 +16,15 @@ import pro.taskana.WorkbasketService;
import pro.taskana.WorkbasketSummary; import pro.taskana.WorkbasketSummary;
import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.WorkbasketNotFoundException; import pro.taskana.exceptions.WorkbasketNotFoundException;
import pro.taskana.impl.WorkbasketAccessItemImpl;
import pro.taskana.impl.WorkbasketImpl; import pro.taskana.impl.WorkbasketImpl;
/** /**
* Transforms {@link Workbasket} into a {@link WorkbasketDefinition} * Transforms {@link Workbasket} into a {@link WorkbasketDefinitionResource}
* containing all additional information about that workbasket. * containing all additional information about that workbasket.
*/ */
@Component @Component
public class WorkbasketDefinitionAssembler { public class WorkbasketDefinitionResourceAssembler {
@Autowired @Autowired
private WorkbasketService workbasketService; private WorkbasketService workbasketService;
@ -33,31 +34,31 @@ public class WorkbasketDefinitionAssembler {
* *
* @param workbasket * @param workbasket
* {@link Workbasket} which will be converted * {@link Workbasket} which will be converted
* @return a {@link WorkbasketDefinition}, containing the {@code basket}, its distribution targets and its * @return a {@link WorkbasketDefinitionResource}, containing the {@code basket}, its distribution targets and its
* authorizations * authorizations
* @throws NotAuthorizedException * @throws NotAuthorizedException
* if the user is not authorized * if the user is not authorized
* @throws WorkbasketNotFoundException * @throws WorkbasketNotFoundException
* if {@code basket} is an unknown workbasket * if {@code basket} is an unknown workbasket
*/ */
public WorkbasketDefinition toDefinition(Workbasket workbasket) public WorkbasketDefinitionResource toResource(Workbasket workbasket)
throws NotAuthorizedException, WorkbasketNotFoundException { throws NotAuthorizedException, WorkbasketNotFoundException {
WorkbasketResource basket = new WorkbasketResource(); WorkbasketResourceWithoutLinks basket = new WorkbasketResourceWithoutLinks();
BeanUtils.copyProperties(workbasket, basket); BeanUtils.copyProperties(workbasket, basket);
basket.setWorkbasketId(workbasket.getId()); basket.setWorkbasketId(workbasket.getId());
basket.setModified(workbasket.getModified().toString()); basket.setModified(workbasket.getModified().toString());
basket.setCreated(workbasket.getCreated().toString()); basket.setCreated(workbasket.getCreated().toString());
List<WorkbasketAccessItem> authorizations = new ArrayList<>(); List<WorkbasketAccessItemImpl> authorizations = new ArrayList<>();
for (WorkbasketAccessItem accessItem : workbasketService.getWorkbasketAccessItems(basket.getKey())) { for (WorkbasketAccessItem accessItem : workbasketService.getWorkbasketAccessItems(basket.getWorkbasketId())) {
authorizations.add(accessItem); authorizations.add((WorkbasketAccessItemImpl) accessItem);
} }
Set<String> distroTargets = workbasketService.getDistributionTargets(workbasket.getId()) Set<String> distroTargets = workbasketService.getDistributionTargets(workbasket.getId())
.stream() .stream()
.map(WorkbasketSummary::getId) .map(WorkbasketSummary::getId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return new WorkbasketDefinition(basket, distroTargets, authorizations); return new WorkbasketDefinitionResource(basket, distroTargets, authorizations);
} }
public Workbasket toModel(WorkbasketResource wbResource) { public Workbasket toModel(WorkbasketResource wbResource) {

View File

@ -0,0 +1,11 @@
package pro.taskana.rest.resource;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* Resource class for {@link pro.taskana.Workbasket} but without links property.
*/
@JsonIgnoreProperties(value = { "links" })
public class WorkbasketResourceWithoutLinks extends WorkbasketResource {
}