TSK-300 import all workbasketdefinitions

This commit is contained in:
Mustapha Zorgati 2018-02-22 14:42:41 +01:00 committed by Holger Hagen
parent f327aee7b5
commit 26c13514eb
6 changed files with 159 additions and 43 deletions

View File

@ -54,6 +54,7 @@ public class ClassificationDefinitionController {
}
return new ResponseEntity<>(export, HttpStatus.OK);
} catch (ClassificationNotFoundException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@ -64,15 +65,18 @@ public class ClassificationDefinitionController {
@RequestBody List<ClassificationResource> classificationResources) {
try {
Map<String, String> systemIds = classificationService.createClassificationQuery().list().stream()
.collect(Collectors.toMap(i -> i.getKey() + i.getDomain(), ClassificationSummary::getId));
.collect(Collectors.toMap(i -> i.getKey() + "|||" + i.getDomain(), ClassificationSummary::getId));
for (ClassificationResource classificationResource : classificationResources) {
Classification classification = classificationMapper.toModel(classificationResource);
if (systemIds.containsKey(classificationResource.key + classificationResource.domain))
if (systemIds.containsKey(classificationResource.key + "|||" + classificationResource.domain))
classificationService.updateClassification(classification);
else
classificationService.createClassification(classification);
}
return new ResponseEntity<>(HttpStatus.OK);
} catch (ClassificationNotFoundException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
@ -83,7 +87,5 @@ public class ClassificationDefinitionController {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -1,24 +1,37 @@
package pro.taskana.rest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
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.Workbasket;
import pro.taskana.WorkbasketQuery;
import pro.taskana.WorkbasketService;
import pro.taskana.WorkbasketSummary;
import pro.taskana.exceptions.InvalidWorkbasketException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.WorkbasketNotFoundException;
import pro.taskana.rest.resource.WorkbasketAccessItemResource;
import pro.taskana.rest.resource.WorkbasketDefinition;
import pro.taskana.rest.resource.WorkbasketResource;
import pro.taskana.rest.resource.mapper.WorkbasketAccessItemMapper;
import pro.taskana.rest.resource.mapper.WorkbasketDefinitionMapper;
import java.util.ArrayList;
import java.util.List;
import pro.taskana.rest.resource.mapper.WorkbasketMapper;
@RestController
@RequestMapping(path = "/v1/workbasketdefinitions", produces = {MediaType.APPLICATION_JSON_VALUE})
@ -30,7 +43,14 @@ public class WorkbasketDefinitionController {
@Autowired
private WorkbasketDefinitionMapper workbasketDefinitionMapper;
@Autowired
private WorkbasketMapper workbasketMapper;
@Autowired
private WorkbasketAccessItemMapper workbasketAccessItemMapper;
@GetMapping
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<List<WorkbasketDefinition>> exportWorkbaskets(@RequestParam(required = false) String domain) {
try {
WorkbasketQuery workbasketQuery = workbasketService.createWorkbasketQuery();
@ -44,9 +64,106 @@ public class WorkbasketDefinitionController {
}
return new ResponseEntity<>(basketExports, HttpStatus.OK);
} catch (WorkbasketNotFoundException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} catch (NotAuthorizedException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}
/**
* This method imports a <b>list of {@link WorkbasketDefinition}</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) workbasket already exists an update will be executed.
* Otherwise a new workbasket will be created.
*
* @param definitions the list of workbasket definitions which will be imported to the current system.
* @return TODO: what should we return?
*/
@PostMapping(path = "/import")
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<String> importWorkbaskets(@RequestBody List<WorkbasketDefinition> definitions) {
try {
// key: logical ID
// value: system ID (in database)
Map<String, String> systemIds = workbasketService.createWorkbasketQuery().list().stream()
.collect(Collectors.toMap(this::logicalId, WorkbasketSummary::getId));
// key: old system ID
// value: system ID
Map<String, String> idConversion = new HashMap<>();
// STEP 1: update or create workbaskets from the import
for (WorkbasketDefinition definition : definitions) {
WorkbasketResource res = definition.workbasketResource;
Workbasket workbasket;
if (systemIds.containsKey(logicalId(res))) {
String oldId = res.workbasketId;
res.workbasketId = systemIds.get(logicalId(res));
workbasket = workbasketService.updateWorkbasket(
workbasketMapper.toModel(res)
);
res.workbasketId = oldId;
} else {
workbasket = workbasketService.createWorkbasket(
workbasketMapper.toModel(res)
);
}
for (WorkbasketAccessItemResource authorization : definition.authorizations) {
workbasketService.createWorkbasketAuthorization(
workbasketAccessItemMapper.toModel(authorization)
);
}
idConversion.put(definition.workbasketResource.workbasketId, workbasket.getId());
}
// STEP 2: update distribution targets
// This can not be done in step 1 because the system IDs are only known after step 1
for (WorkbasketDefinition definition : definitions) {
List<String> distributionTargets = new ArrayList<>();
for (String oldId : definition.distributionTargets) {
if (idConversion.containsKey(oldId)) {
distributionTargets.add(idConversion.get(oldId));
} else {
throw new WorkbasketNotFoundException(
String.format(
"invalid import state: Workbasket '%s' does not exist in the given import list",
oldId)
);
}
}
workbasketService.setDistributionTargets(
// no verification necessary since the workbasket was already imported in step 1.
idConversion.get(definition.workbasketResource.workbasketId), distributionTargets
);
}
return new ResponseEntity<>(HttpStatus.OK);
} catch (WorkbasketNotFoundException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} catch (InvalidWorkbasketException e) {
// TODO: which status code?
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} catch (NotAuthorizedException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}
private String logicalId(WorkbasketSummary workbasket) {
return logicalId(workbasket.getKey(), workbasket.getDomain());
}
private String logicalId(WorkbasketResource resource) {
return logicalId(resource.key, resource.domain);
}
private String logicalId(String key, String domain) {
return key + "|||" + domain;
}
}

View File

@ -1,44 +1,30 @@
package pro.taskana.rest.resource;
import pro.taskana.Workbasket;
import pro.taskana.WorkbasketAccessItem;
import java.util.List;
import java.util.Set;
import org.springframework.hateoas.ResourceSupport;
/**
* this class represents a workbasket including its distro targets and authorisations.
*/
public class WorkbasketDefinition {
public class WorkbasketDefinition extends ResourceSupport {
private final Workbasket workbasket;
private final Set<String> distributionTargets;
private final List<WorkbasketAccessItem> authorizations;
public Set<String> distributionTargets;
public List<WorkbasketAccessItemResource> authorizations;
public WorkbasketResource workbasketResource;
public WorkbasketDefinition(Workbasket workbasket, Set<String> distributionTargets,
List<WorkbasketAccessItem> authorizations) {
this.workbasket = workbasket;
public WorkbasketDefinition() {
// necessary for de-serializing
}
public WorkbasketDefinition(WorkbasketResource workbasketResource,
Set<String> distributionTargets,
List<WorkbasketAccessItemResource> authorizations) {
super();
this.workbasketResource = workbasketResource;
this.distributionTargets = distributionTargets;
this.authorizations = authorizations;
}
public Workbasket getWorkbasket() {
return workbasket;
}
public Set<String> getDistributionTargets() {
return distributionTargets;
}
public List<WorkbasketAccessItem> getAuthorizations() {
return authorizations;
}
@Override public String toString() {
return "WorkbasketDefinition{" +
"workbasket=" + workbasket +
", distributionTargets=" + distributionTargets +
", authorizations=" + authorizations +
'}';
}
}

View File

@ -36,6 +36,7 @@ public class WorkbasketResource extends ResourceSupport {
public String orgLevel4;
public WorkbasketResource() {
//necessary for de-serializing
}
public WorkbasketResource(String workbasketId, String key, String name, String domain, WorkbasketType type,

View File

@ -59,4 +59,5 @@ public class WorkbasketAccessItemMapper {
wbAccItemModel.setPermCustom12(wbAccItemRecource.permCustom12);
return wbAccItemModel;
}
}

View File

@ -8,11 +8,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import pro.taskana.Workbasket;
import pro.taskana.WorkbasketAccessItem;
import pro.taskana.WorkbasketService;
import pro.taskana.WorkbasketSummary;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.WorkbasketNotFoundException;
import pro.taskana.rest.resource.WorkbasketAccessItemResource;
import pro.taskana.rest.resource.WorkbasketDefinition;
@Component
@ -21,6 +21,12 @@ public class WorkbasketDefinitionMapper {
@Autowired
private WorkbasketService workbasketService;
@Autowired
private WorkbasketMapper workbasketMapper;
@Autowired
private WorkbasketAccessItemMapper workbasketAccessItemMapper;
/**
* maps the distro targets to their id to remove overhead.
* @param basket {@link Workbasket} which will be converted
@ -29,12 +35,15 @@ public class WorkbasketDefinitionMapper {
* @throws NotAuthorizedException if the user is not authorized
* @throws WorkbasketNotFoundException if {@code basket} is an unknown workbasket
*/
public WorkbasketDefinition toResource(Workbasket basket) throws NotAuthorizedException, WorkbasketNotFoundException {
List<WorkbasketAccessItem> authorizations = workbasketService.getWorkbasketAuthorizations(basket.getKey());
public WorkbasketDefinition toResource(Workbasket basket)
throws NotAuthorizedException, WorkbasketNotFoundException {
List<WorkbasketAccessItemResource> authorizations = workbasketService.getWorkbasketAuthorizations(
basket.getKey()).stream()
.map(workbasketAccessItemMapper::toResource)
.collect(Collectors.toList());
Set<String> distroTargets = workbasketService.getDistributionTargets(basket.getId()).stream()
.map(WorkbasketSummary::getId)
.collect(Collectors.toSet());
return new WorkbasketDefinition(basket,distroTargets,authorizations);
.map(WorkbasketSummary::getId)
.collect(Collectors.toSet());
return new WorkbasketDefinition(workbasketMapper.toResource(basket), distroTargets, authorizations);
}
}