From 42f7eea2f2d4ee89e6c499dae0e0aed006305370 Mon Sep 17 00:00:00 2001 From: Mustapha Zorgati <15628173+mustaphazorgati@users.noreply.github.com> Date: Thu, 11 Aug 2022 16:38:38 +0200 Subject: [PATCH] TSK-1943: added REST endpoint for requesting a review on a Task --- .../src/docs/asciidoc/rest-api.adoc | 1 + .../taskana/common/rest/RestEndpoints.java | 1 + .../pro/taskana/task/rest/TaskController.java | 22 ++++++++ .../task/rest/TaskControllerIntTest.java | 53 ++++++++++++++----- .../task/rest/TaskControllerRestDocTest.java | 11 ++++ 5 files changed, 74 insertions(+), 14 deletions(-) diff --git a/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc b/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc index 8462b3a3e..8d402a1af 100644 --- a/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc +++ b/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc @@ -104,6 +104,7 @@ include::{snippets}/TaskControllerRestDocTest/claimTaskDocTest/auto-section.adoc include::{snippets}/TaskControllerRestDocTest/selectAndClaimTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/cancelClaimTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/forceCancelClaimTaskDocTest/auto-section.adoc[] +include::{snippets}/TaskControllerRestDocTest/requestReviewTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/completeTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/cancelTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/transferTaskDocTest/auto-section.adoc[] diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java index 606def550..8f1cea6d8 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java @@ -46,6 +46,7 @@ public final class RestEndpoints { public static final String URL_TASKS_ID_CLAIM = API_V1 + "tasks/{taskId}/claim"; public static final String URL_TASKS_ID_CLAIM_FORCE = API_V1 + "tasks/{taskId}/claim/force"; public static final String URL_TASKS_ID_SELECT_AND_CLAIM = API_V1 + "tasks/select-and-claim"; + public static final String URL_TASKS_ID_REQUEST_REVIEW = API_V1 + "tasks/{taskId}/request-review"; public static final String URL_TASKS_ID_COMPLETE = API_V1 + "tasks/{taskId}/complete"; public static final String URL_TASKS_ID_CANCEL = API_V1 + "tasks/{taskId}/cancel"; public static final String URL_TASKS_ID_TRANSFER_WORKBASKET_ID = diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java index 35d859b3c..476bda7f0 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java @@ -41,6 +41,7 @@ import pro.taskana.task.api.TaskService; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; +import pro.taskana.task.api.exceptions.InvalidTaskStateException; import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskNotFoundException; @@ -202,6 +203,27 @@ public class TaskController { return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); } + /** + * This endpoint request a review on the specified Task. + * + * @param taskId taskId the id of the relevant Task + * @return the Task after a review has been requested + * @throws InvalidTaskStateException if the state of the Task with taskId is not CLAIMED + * @throws TaskNotFoundException if the Task with taskId wasn't found + * @throws InvalidOwnerException if the Task is claimed by another user + * @throws NotAuthorizedException if the current user has no READ permissions for the Workbasket + * the Task is in + * @title Request a review on a Task + */ + @PostMapping(path = RestEndpoints.URL_TASKS_ID_REQUEST_REVIEW) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity requestReview(@PathVariable String taskId) + throws InvalidTaskStateException, TaskNotFoundException, InvalidOwnerException, + NotAuthorizedException { + Task task = taskService.requestReview(taskId); + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(task)); + } + /** * This endpoint selects the first Task returned by the Task Query and claims it. * diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java index 01b193d99..25826c8b8 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java @@ -52,12 +52,10 @@ import pro.taskana.workbasket.rest.models.WorkbasketSummaryRepresentationModel; class TaskControllerIntTest { private static final ParameterizedTypeReference - TASK_SUMMARY_PAGE_MODEL_TYPE = - new ParameterizedTypeReference() {}; + TASK_SUMMARY_PAGE_MODEL_TYPE = new ParameterizedTypeReference<>() {}; private static final ParameterizedTypeReference - TASK_SUMMARY_COLLECTION_MODEL_TYPE = - new ParameterizedTypeReference() {}; + TASK_SUMMARY_COLLECTION_MODEL_TYPE = new ParameterizedTypeReference<>() {}; private static final ParameterizedTypeReference TASK_MODEL_TYPE = ParameterizedTypeReference.forType(TaskRepresentationModel.class); @@ -92,7 +90,7 @@ class TaskControllerIntTest { assertThat(response.getBody()).isNotNull(); assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(59); + assertThat(response.getBody().getContent()).hasSize(60); } @Test @@ -524,8 +522,7 @@ class TaskControllerIntTest { String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?por=" - + URLEncoder.encode( - "{\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\"}", "UTF-8"); + + URLEncoder.encode("{\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\"}", UTF_8); HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); ResponseEntity response = TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); @@ -540,7 +537,7 @@ class TaskControllerIntTest { String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor=" - + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Value2\"}", "UTF-8"); + + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Value2\"}", UTF_8); HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); ResponseEntity response = TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); @@ -555,7 +552,7 @@ class TaskControllerIntTest { String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor=" - + URLEncoder.encode("{\"company\":\"Company3\"}", "UTF-8"); + + URLEncoder.encode("{\"company\":\"Company3\"}", UTF_8); HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); ResponseEntity response = TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); @@ -570,7 +567,7 @@ class TaskControllerIntTest { String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor=" - + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Quatsch\"}", "UTF-8"); + + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Quatsch\"}", UTF_8); HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); ResponseEntity response = TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); @@ -750,7 +747,7 @@ class TaskControllerIntTest { assertThat(response.getBody()).isNotNull(); assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(20); + assertThat(response.getBody().getContent()).hasSize(21); } @Test @@ -794,7 +791,7 @@ class TaskControllerIntTest { assertThat(response.getBody()).isNotNull(); assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(90); + assertThat(response.getBody().getContent()).hasSize(91); } @Test @@ -870,7 +867,7 @@ class TaskControllerIntTest { TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getContent()).hasSize(59); + assertThat((response.getBody()).getContent()).hasSize(60); String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS) @@ -945,7 +942,7 @@ class TaskControllerIntTest { assertThat(response.getBody()).isNotNull(); assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(83); + assertThat(response.getBody().getContent()).hasSize(84); } @Test @@ -1395,6 +1392,34 @@ class TaskControllerIntTest { .isEqualTo(HttpStatus.BAD_REQUEST); } + @Test + void should_RequestReviewOnATask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000035"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel repModel = getTaskResponse.getBody(); + assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(repModel.getOwner()).isEqualTo("user-1-1"); + + // request review + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_REQUEST_REVIEW, "TKI:000000000000000000000000000000000035"); + ResponseEntity requestReviewResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(requestReviewResponse.getBody()).isNotNull(); + assertThat(requestReviewResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + repModel = requestReviewResponse.getBody(); + assertThat(repModel.getOwner()).isNull(); + assertThat(repModel.getState()).isEqualTo(TaskState.READY_FOR_REVIEW); + } + @Test void should_UpdateTaskOwnerOfReadyTask() { final String url = restHelper.toUrl("/api/v1/tasks/TKI:000000000000000000000000000000000025"); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java index d507e5940..0ca5a1522 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java @@ -80,6 +80,17 @@ class TaskControllerRestDocTest extends BaseRestDocTest { .andExpect(MockMvcResultMatchers.status().isOk()); } + @Test + void requestReviewTaskDocTest() throws Exception { + mockMvc + .perform( + post( + RestEndpoints.URL_TASKS_ID_REQUEST_REVIEW, + "TKI:000000000000000000000000000000000032") + .headers(RestHelper.generateHeadersForUser("user-1-2"))) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + @Test void selectAndClaimTaskDocTest() throws Exception { mockMvc