diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java index e4367ba15..445760f1e 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java @@ -316,6 +316,9 @@ public class TaskServiceImpl implements TaskService { workbasketService.checkAuthorization(task.getWorkbasketSummary().getId(), WorkbasketPermission.APPEND); + + // we do use the key and not the ID to make sure that we use the classification from the right domain. + // otherwise we would have to check the classification and its domain for validity. String classificationKey = task.getClassificationKey(); if (classificationKey == null || classificationKey.length() == 0) { throw new InvalidArgumentException("classificationKey of task must not be empty"); diff --git a/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/TaskControllerIntTest.java b/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/TaskControllerIntTest.java index 34b75eb22..ef446be49 100644 --- a/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/TaskControllerIntTest.java +++ b/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/TaskControllerIntTest.java @@ -268,6 +268,87 @@ public class TaskControllerIntTest { } + @Test + public void testCreateAndDeleteTask() throws IOException { + String taskToCreateJson = "{\"classificationSummaryResource\":{\"key\":\"L11010\"}," + + "\"workbasketSummaryResource\":{\"workbasketId\":\"WBI:100000000000000000000000000000000004\"}," + + "\"primaryObjRef\":{\"company\":\"MyCompany1\",\"system\":\"MySystem1\",\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\",\"value\":\"00000001\"}}"; + + URL url = new URL("http://127.0.0.1:" + port + "/v1/tasks"); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setDoOutput(true); + con.setRequestProperty("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"); + con.setRequestProperty("Content-Type", "application/json"); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream())); + out.write(taskToCreateJson); + out.flush(); + out.close(); + assertEquals(201, con.getResponseCode()); + // con.disconnect(); + + BufferedReader in = new BufferedReader( + new InputStreamReader(con.getInputStream())); + StringBuffer responsePayload = new StringBuffer(); + String inputLine; + while ((inputLine = in.readLine()) != null) { + responsePayload.append(inputLine); + } + in.close(); + con.disconnect(); + String createdTask = responsePayload.toString(); + String taskIdOfCreatedTask = createdTask.substring(11, 51); + assertNotNull(taskIdOfCreatedTask); + assertTrue(taskIdOfCreatedTask.startsWith("TKI:")); + + // delete task again to clean test data + url = new URL("http://127.0.0.1:" + port + "/v1/tasks/" + taskIdOfCreatedTask); + con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("DELETE"); + con.setRequestProperty("Authorization", "Basic YWRtaW46YWRtaW4="); // admin + assertEquals(200, con.getResponseCode()); + con.disconnect(); + } + + @Test + public void testCreateTaskWithInvalidParameter() throws IOException { + String taskToCreateJson = "{\"classificationKey\":\"L11010\"," + + "\"workbasketSummaryResource\":{\"workbasketId\":\"WBI:100000000000000000000000000000000004\"}," + + "\"primaryObjRef\":{\"company\":\"MyCompany1\",\"system\":\"MySystem1\",\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\",\"value\":\"00000001\"}}"; + + URL url = new URL("http://127.0.0.1:" + port + "/v1/tasks"); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setDoOutput(true); + con.setRequestProperty("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"); + con.setRequestProperty("Content-Type", "application/json"); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream())); + out.write(taskToCreateJson); + out.flush(); + out.close(); + assertEquals(400, con.getResponseCode()); + con.disconnect(); + + taskToCreateJson = "{\"classificationSummaryResource\":{\"classificationId\":\"CLI:100000000000000000000000000000000004\"}," + + + "\"workbasketSummaryResource\":{\"workbasketId\":\"\"}," + + "\"primaryObjRef\":{\"company\":\"MyCompany1\",\"system\":\"MySystem1\",\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\",\"value\":\"00000001\"}}"; + + url = new URL("http://127.0.0.1:" + port + "/v1/tasks"); + con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setDoOutput(true); + con.setRequestProperty("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"); + con.setRequestProperty("Content-Type", "application/json"); + out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream())); + out.write(taskToCreateJson); + out.flush(); + out.close(); + assertEquals(400, con.getResponseCode()); + con.disconnect(); + + } + /** * Return a REST template which is capable of dealing with responses in HAL format * diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java index a6cdc61ef..31c142c27 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskController.java @@ -155,12 +155,21 @@ public class TaskController extends AbstractPagingController { return result; } + @RequestMapping(method = RequestMethod.DELETE, value = "/{taskId}") + @Transactional(rollbackFor = Exception.class) + public ResponseEntity deleteTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidStateException, NotAuthorizedException { + taskService.deleteTask(taskId, true); + ResponseEntity result = new ResponseEntity<>(HttpStatus.OK); + return result; + } + @RequestMapping(method = RequestMethod.POST) @Transactional(rollbackFor = Exception.class) - public ResponseEntity createTask(@RequestBody Task task) + public ResponseEntity createTask(@RequestBody TaskResource taskResource) throws WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, TaskAlreadyExistException, InvalidWorkbasketException, InvalidArgumentException { - Task createdTask = taskService.createTask(task); + Task createdTask = taskService.createTask(taskResourceAssembler.toModel(taskResource)); ResponseEntity result = new ResponseEntity<>(taskResourceAssembler.toResource(createdTask), HttpStatus.CREATED); return result; diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskanaRestExceptionHandler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskanaRestExceptionHandler.java index 3537108dc..0dcd3a39f 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskanaRestExceptionHandler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/TaskanaRestExceptionHandler.java @@ -41,7 +41,7 @@ public class TaskanaRestExceptionHandler extends ResponseEntityExceptionHandler @ExceptionHandler(NotAuthorizedException.class) protected ResponseEntity handleNotAuthorized(NotAuthorizedException ex, WebRequest req) { - return buildResponse(ex, req, HttpStatus.UNAUTHORIZED); + return buildResponse(ex, req, HttpStatus.FORBIDDEN); } @ExceptionHandler(TaskNotFoundException.class) diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/resource/mapper/TaskResourceAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/resource/mapper/TaskResourceAssembler.java index 4fbdb0728..7d398efd2 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/resource/mapper/TaskResourceAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/rest/resource/mapper/TaskResourceAssembler.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; import pro.taskana.Task; import pro.taskana.TaskService; +import pro.taskana.exceptions.InvalidArgumentException; import pro.taskana.impl.TaskImpl; import pro.taskana.rest.TaskController; import pro.taskana.rest.resource.TaskResource; @@ -59,7 +60,8 @@ public class TaskResourceAssembler return resource; } - public Task toModel(TaskResource resource) { + public Task toModel(TaskResource resource) throws InvalidArgumentException { + validateTaskResource(resource); TaskImpl task = (TaskImpl) taskService.newTask(resource.getWorkbasketSummaryResource().getWorkbasketId()); task.setId(resource.getTaskId()); BeanUtils.copyProperties(resource, task); @@ -83,4 +85,19 @@ public class TaskResourceAssembler return task; } + private void validateTaskResource(TaskResource resource) throws InvalidArgumentException { + if (resource.getWorkbasketSummaryResource() == null + || resource.getWorkbasketSummaryResource().getWorkbasketId() == null + || resource.getWorkbasketSummaryResource().getWorkbasketId().isEmpty()) { + throw new InvalidArgumentException( + "TaskResource must have a workbasket summary with a valid workbasketId."); + } + if (resource.getClassificationSummaryResource() == null + || resource.getClassificationSummaryResource().getKey() == null + || resource.getClassificationSummaryResource().getKey().isEmpty()) { + throw new InvalidArgumentException( + "TaskResource must have a classification summary with a valid classification key."); + } + } + }