TSK-1150: Added REST-API for task comments

This commit is contained in:
Jörg Heffner 2020-03-18 14:26:35 +01:00 committed by Holger Hagen
parent bebb60dea0
commit ce571722d5
11 changed files with 860 additions and 1 deletions

View File

@ -31,6 +31,7 @@ public interface TaskCommentMapper {
"<script> SELECT ID, TASK_ID, TEXT_FIELD, CREATOR, CREATED, MODIFIED"
+ " FROM TASK_COMMENT "
+ "WHERE TASK_ID = #{taskId} "
+ " ORDER BY CREATED ASC "
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
+ "</script>")
@Results(

View File

@ -1,3 +1,18 @@
-- TASK_COMMENT TABLE ID , TASK_ID ,TEXTFIELD ,CREATOR ,COMPLETED ,MODIFIED
-- TaskComments for GetTaskCommentAccTest + UpdateTaskCommentAccTest
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000000', 'TKI:000000000000000000000000000000000000', 'some text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000001', 'TKI:000000000000000000000000000000000000', 'some other text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000002', 'TKI:000000000000000000000000000000000000', 'some other text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000003', 'TKI:000000000000000000000000000000000025', 'some text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
-- TaskComments for DeleteTaskCommentAccTest
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000004', 'TKI:000000000000000000000000000000000001', 'some text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000005', 'TKI:000000000000000000000000000000000001', 'some other text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000006', 'TKI:000000000000000000000000000000000002', 'some text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000007', 'TKI:000000000000000000000000000000000002', 'some other text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
-- TaskComments for CreateTaskCommentAccTest
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000008', 'TKI:000000000000000000000000000000000026', 'some text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000009', 'TKI:000000000000000000000000000000000026', 'some other text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000010', 'TKI:000000000000000000000000000000000027', 'some text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000011', 'TKI:000000000000000000000000000000000027', 'some other text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');
INSERT INTO TASK_COMMENT VALUES('TCI:000000000000000000000000000000000012', 'TKI:000000000000000000000000000000000004', 'some text in textfield', 'user_1_1', '2018-01-29 15:55:00', '2018-01-30 15:55:00');

View File

@ -25,6 +25,8 @@ public final class Mapping {
public static final String URL_VERSION = PRE + "version";
public static final String URL_TASKS = PRE + "tasks";
public static final String URL_TASKS_ID = URL_TASKS + "/{taskId}";
public static final String URL_TASK_COMMENTS = URL_TASKS_ID + "/comments";
public static final String URL_TASK_COMMENT = URL_TASK_COMMENTS + "/{taskCommentId}";
public static final String URL_TASKS_ID_CLAIM = URL_TASKS_ID + "/claim";
public static final String URL_TASKS_ID_COMPLETE = URL_TASKS_ID + "/complete";
public static final String URL_TASKS_ID_TRANSFER_WORKBASKETID =

View File

@ -0,0 +1,164 @@
package pro.taskana.rest;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RestController;
import pro.taskana.common.api.exceptions.ConcurrencyException;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.rest.resource.TaskCommentListResource;
import pro.taskana.rest.resource.TaskCommentResource;
import pro.taskana.rest.resource.TaskCommentResourceAssembler;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.exceptions.TaskCommentNotFoundException;
import pro.taskana.task.api.exceptions.TaskNotFoundException;
import pro.taskana.task.api.models.TaskComment;
/** Controller for all {@link TaskComment} related endpoints. */
@RestController
@EnableHypermediaSupport(type = HypermediaType.HAL)
public class TaskCommentController {
private static final Logger LOGGER = LoggerFactory.getLogger(TaskCommentController.class);
private TaskService taskService;
private TaskCommentResourceAssembler taskCommentResourceAssembler;
TaskCommentController(
TaskService taskService, TaskCommentResourceAssembler taskCommentResourceAssembler) {
this.taskService = taskService;
this.taskCommentResourceAssembler = taskCommentResourceAssembler;
}
@GetMapping(path = Mapping.URL_TASK_COMMENT)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<TaskCommentResource> getTaskComment(@PathVariable String taskCommentId)
throws NotAuthorizedException, TaskNotFoundException, TaskCommentNotFoundException,
InvalidArgumentException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Entry to getTaskComment(taskCommentId= {})", taskCommentId);
}
TaskComment taskComment = taskService.getTaskComment(taskCommentId);
TaskCommentResource taskCommentResource = taskCommentResourceAssembler.toResource(taskComment);
ResponseEntity<TaskCommentResource> response = ResponseEntity.ok(taskCommentResource);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exit from getTaskComment(), returning {}", response);
}
return response;
}
@GetMapping(path = Mapping.URL_TASK_COMMENTS)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<TaskCommentListResource> getTaskComments(@PathVariable String taskId)
throws NotAuthorizedException, TaskNotFoundException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Entry to getTaskComments(taskId= {})", taskId);
}
List<TaskComment> taskComments = taskService.getTaskComments(taskId);
TaskCommentListResource taskCommentListResource =
taskCommentResourceAssembler.toListResource(taskComments);
ResponseEntity<TaskCommentListResource> response = ResponseEntity.ok(taskCommentListResource);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exit from getTaskComments(), returning {}", response);
}
return response;
}
@DeleteMapping(path = Mapping.URL_TASK_COMMENT)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<TaskCommentResource> deleteTaskComment(@PathVariable String taskCommentId)
throws NotAuthorizedException, TaskNotFoundException, TaskCommentNotFoundException,
InvalidArgumentException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Entry to deleteTaskComment(taskCommentId= {})", taskCommentId);
}
taskService.deleteTaskComment(taskCommentId);
ResponseEntity<TaskCommentResource> result = ResponseEntity.noContent().build();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exit from deleteTaskComment(), returning {}", result);
}
return result;
}
@PutMapping(path = Mapping.URL_TASK_COMMENT)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<TaskCommentResource> updateTaskComment(
@PathVariable String taskCommentId, @RequestBody TaskCommentResource taskCommentResource)
throws NotAuthorizedException, TaskNotFoundException, TaskCommentNotFoundException,
InvalidArgumentException, ConcurrencyException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Entry to updateTaskComment(taskCommentId= {})", taskCommentId);
}
ResponseEntity<TaskCommentResource> result;
if (taskCommentId.equals(taskCommentResource.getTaskCommentId())) {
TaskComment taskComment = taskCommentResourceAssembler.toModel(taskCommentResource);
taskComment = taskService.updateTaskComment(taskComment);
result = ResponseEntity.ok(taskCommentResourceAssembler.toResource(taskComment));
} else {
throw new InvalidArgumentException(
String.format(
"TaskCommentId ('%s') is not identical with the taskCommentId of "
+ "object in the payload which should be updated. ID=('%s')",
taskCommentId, taskCommentResource.getTaskId()));
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exit from updateTaskComment(), returning {}", result);
}
return result;
}
@PostMapping(path = Mapping.URL_TASK_COMMENTS)
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<TaskCommentResource> createTaskComment(
@RequestBody TaskCommentResource taskCommentResource)
throws NotAuthorizedException, InvalidArgumentException, TaskNotFoundException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Entry to createTaskComment(taskCommentResource= {})", taskCommentResource);
}
TaskComment taskCommentFromResource = taskCommentResourceAssembler.toModel(taskCommentResource);
TaskComment createdTaskComment = taskService.createTaskComment(taskCommentFromResource);
ResponseEntity<TaskCommentResource> result =
ResponseEntity.status(HttpStatus.CREATED)
.body(taskCommentResourceAssembler.toResource(createdTaskComment));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exit from createTaskComment(), returning {}", result);
}
return result;
}
}

View File

@ -0,0 +1,24 @@
package pro.taskana.rest.resource;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import org.springframework.hateoas.ResourceSupport;
/** Resource class for {@link TaskCommentResource} with Pagination. */
public class TaskCommentListResource extends ResourceSupport {
private List<TaskCommentResource> content;
public TaskCommentListResource() {
super();
}
public TaskCommentListResource(List<TaskCommentResource> taskCommentResources) {
this.content = taskCommentResources;
}
@JsonProperty("task comments")
public List<TaskCommentResource> getContent() {
return content;
}
}

View File

@ -0,0 +1,92 @@
package pro.taskana.rest.resource;
import org.springframework.hateoas.ResourceSupport;
import pro.taskana.task.api.models.TaskComment;
/** Resource class for {@link TaskComment}. */
public class TaskCommentResource extends ResourceSupport {
private String taskCommentId;
private String taskId;
private String textField;
private String creator;
private String created;
private String modified;
public TaskCommentResource() {}
public TaskCommentResource(TaskComment taskComment) {
this.taskCommentId = taskComment.getId();
this.taskId = taskComment.getTaskId();
this.textField = taskComment.getTextField();
this.creator = taskComment.getCreator();
this.created = taskComment.getCreated().toString();
this.modified = taskComment.getModified().toString();
}
public String getTaskCommentId() {
return taskCommentId;
}
public void setTaskCommentId(String id) {
this.taskCommentId = id;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getTextField() {
return textField;
}
public void setTextField(String textField) {
this.textField = textField;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getModified() {
return modified;
}
public void setModified(String modified) {
this.modified = modified;
}
@Override
public String toString() {
return "TaskCommentResource [taskCommentId="
+ taskCommentId
+ ", taskId="
+ taskId
+ ", textField="
+ textField
+ ", creator="
+ creator
+ ", created="
+ created
+ ", modified="
+ modified
+ "]";
}
}

View File

@ -0,0 +1,79 @@
package pro.taskana.rest.resource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.time.Instant;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.mvc.ResourceAssemblerSupport;
import org.springframework.stereotype.Component;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.api.exceptions.SystemException;
import pro.taskana.rest.Mapping;
import pro.taskana.rest.TaskCommentController;
import pro.taskana.rest.resource.links.PageLinks;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.exceptions.TaskCommentNotFoundException;
import pro.taskana.task.api.exceptions.TaskNotFoundException;
import pro.taskana.task.api.models.TaskComment;
import pro.taskana.task.internal.models.TaskCommentImpl;
/** Resource assembler for {@link TaskCommentResource}. */
@Component
public class TaskCommentResourceAssembler
extends ResourceAssemblerSupport<TaskComment, TaskCommentResource> {
private final TaskService taskService;
@Autowired
public TaskCommentResourceAssembler(TaskService taskService) {
super(TaskCommentController.class, TaskCommentResource.class);
this.taskService = taskService;
}
@Override
public TaskCommentResource toResource(TaskComment taskComment) {
TaskCommentResource taskCommentResource = new TaskCommentResource(taskComment);
try {
taskCommentResource.add(
linkTo(methodOn(TaskCommentController.class).getTaskComment(taskComment.getId()))
.withSelfRel());
} catch (TaskCommentNotFoundException
| TaskNotFoundException
| NotAuthorizedException
| InvalidArgumentException e) {
throw new SystemException("caught unexpected Exception.", e.getCause());
}
return taskCommentResource;
}
@PageLinks(Mapping.URL_TASK_COMMENTS)
public TaskCommentListResource toListResource(
List<TaskComment> taskComments) {
return new TaskCommentListResource(toResources(taskComments));
}
public TaskComment toModel(TaskCommentResource taskCommentResource) {
TaskCommentImpl taskComment =
(TaskCommentImpl) taskService.newTaskComment(taskCommentResource.getTaskId());
taskComment.setId(taskCommentResource.getTaskCommentId());
BeanUtils.copyProperties(taskCommentResource, taskComment);
if (taskCommentResource.getCreated() != null) {
taskComment.setCreated(Instant.parse(taskCommentResource.getCreated()));
}
if (taskCommentResource.getModified() != null) {
taskComment.setModified(Instant.parse(taskCommentResource.getModified()));
}
return taskComment;
}
}

View File

@ -64,6 +64,13 @@ public class RestHelper {
return headers;
}
public HttpHeaders getHeadersUser_1_1() {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic dXNlcl8xXzE6dXNlcl8xXzE=");
headers.add("Content-Type", "application/json");
return headers;
}
/**
* Return a REST template which is capable of dealing with responses in HAL format.
*

View File

@ -0,0 +1,202 @@
package pro.taskana.doc.api;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import pro.taskana.rest.Mapping;
public class TaskCommentControllerRestDocumentation extends BaseRestDocumentation {
private HashMap<String, String> taskCommentFieldDescriptionsMap = new HashMap<String, String>();
private FieldDescriptor[] allTaskCommentsFieldDescriptors;
private FieldDescriptor[] taskCommentFieldDescriptors;
private FieldDescriptor[] createTaskCommentFieldDescriptors;
@BeforeEach
void setUp() {
taskCommentFieldDescriptionsMap.put("taskCommentId", "Unique ID");
taskCommentFieldDescriptionsMap.put(
"taskId", "Task ID. Can identify the task to which the comment belongs");
taskCommentFieldDescriptionsMap.put("textField", "The content of the actual comment");
taskCommentFieldDescriptionsMap.put("creator", "The creator of the task comment");
taskCommentFieldDescriptionsMap.put(
"created", "The creation timestamp of the task comment in the system.");
taskCommentFieldDescriptionsMap.put(
"modified", "Timestamp of the last modification of the task comment");
taskCommentFieldDescriptors =
new FieldDescriptor[] {
fieldWithPath("taskCommentId")
.description(taskCommentFieldDescriptionsMap.get("taskCommentId")),
fieldWithPath("taskId").description(taskCommentFieldDescriptionsMap.get("taskId")),
fieldWithPath("textField").description(taskCommentFieldDescriptionsMap.get("textField")),
fieldWithPath("creator").description(taskCommentFieldDescriptionsMap.get("creator")),
fieldWithPath("created")
.description(taskCommentFieldDescriptionsMap.get("created"))
.type("String"),
fieldWithPath("modified")
.description(taskCommentFieldDescriptionsMap.get("modified"))
.type("String"),
fieldWithPath("_links").ignored(),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.self.href").ignored(),
fieldWithPath("_links.self.templated").ignored()
};
createTaskCommentFieldDescriptors =
new FieldDescriptor[] {
fieldWithPath("taskId").description(taskCommentFieldDescriptionsMap.get("taskId")),
fieldWithPath("textField").description(taskCommentFieldDescriptionsMap.get("textField")),
fieldWithPath("creator")
.description(taskCommentFieldDescriptionsMap.get("creator"))
.type("String")
.optional(),
fieldWithPath("created")
.description(taskCommentFieldDescriptionsMap.get("created"))
.type("String")
.optional(),
fieldWithPath("modified")
.description(taskCommentFieldDescriptionsMap.get("modified"))
.type("String")
.optional(),
};
allTaskCommentsFieldDescriptors =
new FieldDescriptor[] {
subsectionWithPath("task comments")
.description("An Array of task comments")
};
}
@Test
void getAllTaskCommentsForSpecificTaskDocTest() throws Exception {
this.mockMvc
.perform(
RestDocumentationRequestBuilders.get(
restHelper.toUrl(
Mapping.URL_TASK_COMMENTS, "TKI:000000000000000000000000000000000000"))
.accept("application/hal+json")
.header("Authorization", "Basic YWRtaW46YWRtaW4="))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(
MockMvcRestDocumentation.document(
"GetAllTaskCommentsForSpecificTaskDocTest",
responseFields(allTaskCommentsFieldDescriptors)));
}
@Test
void getSpecificTaskCommentDocTest() throws Exception {
this.mockMvc
.perform(
RestDocumentationRequestBuilders.get(
restHelper.toUrl(
Mapping.URL_TASK_COMMENT,
"TKI:100000000000000000000000000000000000",
"TCI:000000000000000000000000000000000000"))
.accept("application/hal+json")
.header("Authorization", "Basic YWRtaW46YWRtaW4="))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(
MockMvcRestDocumentation.document(
"GetSpecificTaskCommentDocTest", responseFields(taskCommentFieldDescriptors)));
}
@Test
void updateTaskCommentDocTest() throws Exception {
URL url =
new URL(
restHelper.toUrl(
Mapping.URL_TASK_COMMENT,
"TKI:000000000000000000000000000000000000",
"TCI:000000000000000000000000000000000000"));
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Authorization", "Basic YWRtaW46YWRtaW4=");
assertEquals(200, con.getResponseCode());
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), UTF_8));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
con.disconnect();
String originalTaskComment = content.toString();
String modifiedTaskComment =
originalTaskComment.replace("some text in textfield", "updated text in textfield");
this.mockMvc
.perform(
RestDocumentationRequestBuilders.put(
restHelper.toUrl(
Mapping.URL_TASK_COMMENT,
"TKI:000000000000000000000000000000000000",
"TCI:000000000000000000000000000000000000"))
.header("Authorization", "Basic YWRtaW46YWRtaW4=")
.contentType("application/json")
.content(modifiedTaskComment))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(
MockMvcRestDocumentation.document(
"UpdateTaskCommentDocTest",
requestFields(taskCommentFieldDescriptors),
responseFields(taskCommentFieldDescriptors)));
}
@Test
void createAndDeleteTaskCommentDocTest() throws Exception {
MvcResult result =
this.mockMvc
.perform(
RestDocumentationRequestBuilders.post(
restHelper.toUrl(
Mapping.URL_TASK_COMMENTS, "TKI:000000000000000000000000000000000000"))
.contentType("application/hal+json")
.content(
"{ \"taskId\" : \"TKI:000000000000000000000000000000000000\",\n"
+ " \"textField\" : \"some text in textfield\"} ")
.header("Authorization", "Basic YWRtaW46YWRtaW4="))
.andExpect(MockMvcResultMatchers.status().isCreated())
.andDo(
MockMvcRestDocumentation.document(
"CreateTaskCommentDocTest",
requestFields(createTaskCommentFieldDescriptors),
responseFields(taskCommentFieldDescriptors)))
.andReturn();
String content = result.getResponse().getContentAsString();
String newId = content.substring(content.indexOf("TCI:"), content.indexOf("TCI:") + 40);
this.mockMvc
.perform(
RestDocumentationRequestBuilders.delete(
restHelper.toUrl(
Mapping.URL_TASK_COMMENT,
"TKI:000000000000000000000000000000000000",
newId))
.header("Authorization", "Basic YWRtaW46YWRtaW4=")) // admin
.andExpect(MockMvcResultMatchers.status().isNoContent())
.andDo(MockMvcRestDocumentation.document("DeleteTaskCommentDocTest"));
}
}

View File

@ -0,0 +1,182 @@
package pro.taskana.rest;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import pro.taskana.RestHelper;
import pro.taskana.TaskanaSpringBootTest;
import pro.taskana.rest.resource.TaskCommentListResource;
import pro.taskana.rest.resource.TaskCommentResource;
/** Test TaskCommentController. */
@TaskanaSpringBootTest
class TaskCommentControllerIntTest {
private static RestTemplate template;
@Value("${taskana.schemaName:TASKANA}")
public String schemaName;
@Autowired RestHelper restHelper;
@BeforeAll
static void init() {
template = RestHelper.TEMPLATE;
}
@Test
void testGetNonExistentCommentShouldFail() {
String urlToNonExistingTaskComment =
restHelper.toUrl(
Mapping.URL_TASK_COMMENT,
"TKI:000000000000000000000000000000000000",
"Non existing task comment Id");
assertThatThrownBy(
() ->
template.exchange(
urlToNonExistingTaskComment,
HttpMethod.GET,
new HttpEntity<String>(restHelper.getHeadersAdmin()),
ParameterizedTypeReference.forType(TaskCommentResource.class)))
.extracting(ex -> ((HttpClientErrorException) ex).getStatusCode())
.isEqualTo(HttpStatus.BAD_REQUEST);
}
@Test
void testGetCommentsForNonExistingTaskShouldFail() {
String urlToNonExistingTask = restHelper.toUrl(Mapping.URL_TASK_COMMENTS, "nonExistingTaskId");
assertThatThrownBy(
() ->
template.exchange(
urlToNonExistingTask,
HttpMethod.GET,
new HttpEntity<String>(restHelper.getHeadersAdmin()),
ParameterizedTypeReference.forType(TaskCommentListResource.class)))
.extracting(ex -> ((HttpClientErrorException) ex).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
}
@Disabled("Disabled until Authorization check is up!")
@Test
void testGetTaskCommentsOfNotVisibleTaskShouldFail() {
String urlToNotVisibleTask =
restHelper.toUrl(Mapping.URL_TASK_COMMENTS, "TKI:000000000000000000000000000000000004");
ResponseEntity<TaskCommentListResource> response =
template.exchange(
urlToNotVisibleTask,
HttpMethod.GET,
new HttpEntity<String>(restHelper.getHeadersUser_1_1()),
ParameterizedTypeReference.forType(TaskCommentListResource.class));
}
@Disabled("Disabled until Authorization check is up!")
@Test
void testGetTaskCommentOfNotVisibleTaskShouldFail() {
String urlToNotVisibleTask =
restHelper.toUrl(
Mapping.URL_TASK_COMMENT,
"TKI:000000000000000000000000000000000004",
"TCI:000000000000000000000000000000000013");
ResponseEntity<TaskCommentResource> response =
template.exchange(
urlToNotVisibleTask,
HttpMethod.GET,
new HttpEntity<String>(restHelper.getHeadersUser_1_1()),
ParameterizedTypeReference.forType(TaskCommentResource.class));
}
@Disabled("Disabled until Authorization check is up!")
@Test
void testCreateTaskCommentForNotVisibleTaskShouldFail() {
TaskCommentResource taskCommentResourceToCreate = new TaskCommentResource();
taskCommentResourceToCreate.setTaskId("TKI:000000000000000000000000000000000004");
taskCommentResourceToCreate.setTextField("newly created task comment");
assertThatThrownBy(
() ->
template.exchange(
restHelper.toUrl(
Mapping.URL_TASK_COMMENTS, "TKI:000000000000000000000000000000000004"),
HttpMethod.POST,
new HttpEntity<>(taskCommentResourceToCreate, restHelper.getHeadersUser_1_1()),
ParameterizedTypeReference.forType(TaskCommentResource.class)))
.extracting(ex -> ((HttpClientErrorException) ex).getStatusCode())
.isEqualTo(HttpStatus.FORBIDDEN);
}
@Test
void testCreateTaskCommentForNotExistingTaskShouldFail() {
TaskCommentResource taskCommentResourceToCreate = new TaskCommentResource();
taskCommentResourceToCreate.setTaskId("DefinatelyNotExistingId");
taskCommentResourceToCreate.setTextField("newly created task comment");
assertThatThrownBy(
() ->
template.exchange(
restHelper.toUrl(Mapping.URL_TASK_COMMENTS, "NotExistingTaskId"),
HttpMethod.POST,
new HttpEntity<>(taskCommentResourceToCreate, restHelper.getHeadersUser_1_1()),
ParameterizedTypeReference.forType(TaskCommentResource.class)))
.extracting(ex -> ((HttpClientErrorException) ex).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
TaskCommentResource taskCommentResourceToCreate2 = new TaskCommentResource();
taskCommentResourceToCreate.setTaskId(null);
taskCommentResourceToCreate.setTextField("newly created task comment");
assertThatThrownBy(
() ->
template.exchange(
restHelper.toUrl(Mapping.URL_TASK_COMMENTS, "NotExistingTaskId"),
HttpMethod.POST,
new HttpEntity<>(taskCommentResourceToCreate2, restHelper.getHeadersUser_1_1()),
ParameterizedTypeReference.forType(TaskCommentResource.class)))
.extracting(ex -> ((HttpClientErrorException) ex).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
TaskCommentResource taskCommentResourceToCreate3 = new TaskCommentResource();
taskCommentResourceToCreate.setTaskId("");
taskCommentResourceToCreate.setTextField("newly created task comment");
assertThatThrownBy(
() ->
template.exchange(
restHelper.toUrl(Mapping.URL_TASK_COMMENTS, "NotExistingTaskId"),
HttpMethod.POST,
new HttpEntity<>(taskCommentResourceToCreate3, restHelper.getHeadersUser_1_1()),
ParameterizedTypeReference.forType(TaskCommentResource.class)))
.extracting(ex -> ((HttpClientErrorException) ex).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
}
@Test
void testUpdateTaskCommentWithConcurrentModificationShouldFail() {}
@Test
void testUpdateTaskCommentWithNoAuthorizationShouldFail() {}
@Test
void testUpdateTaskCommentOfNotExistingTaskShouldFail() {}
}

View File

@ -293,6 +293,97 @@ include::{snippets}/TransferTaskDocTest/http-response.adoc[]
The response-body is essentially the same as for getting a single task. +
Therefore for the response fields you can refer to the <<task, single task>>.
== TaskComment-Resource
=== Get a list of all task comments for a specific task
A `GET` request is used to retrieve the task comments.
==== Example Request
include::{snippets}/GetAllTaskCommentsForSpecificTaskDocTest/http-request.adoc[]
==== Example Response
include::{snippets}/GetAllTaskCommentsForSpecificTaskDocTest/http-response.adoc[]
==== Response Structure
include::{snippets}/GetAllTaskCommentsForSpecificTaskDocTest/response-fields.adoc[]
=== Get a specific task comment
A `GET` request is used to retrieve a task comment.
==== Example Request
include::{snippets}/GetSpecificTaskCommentDocTest/http-request.adoc[]
==== Example Response
include::{snippets}/GetSpecificTaskCommentDocTest/http-response.adoc[]
==== Response Structure
include::{snippets}/GetSpecificTaskCommentDocTest/response-fields.adoc[]
=== Update a task comment
A `PUT` request is used to update a task comment.
==== Example Request
include::{snippets}/UpdateTaskCommentDocTest/http-request.adoc[]
==== Request Structure
include::{snippets}/UpdateTaskCommentDocTest/request-fields.adoc[]
==== Example Response
include::{snippets}/UpdateTaskCommentDocTest/http-response.adoc[]
==== Response Structure
include::{snippets}/UpdateTaskCommentDocTest/response-fields.adoc[]
=== Create a new task comment
A `POST` request is used to create a new task comment.
==== Example Request
This minimal example shows only the required fields to create a new task comment. The <<create-task-comment-request-structure, request structure>> shows all possible fields for creating a task comment.
include::{snippets}/CreateTaskCommentDocTest/http-request.adoc[]
[[create-taskcomment--request-structure, request structure]]
==== Request Structure
include::{snippets}/CreateTaskCommentDocTest/request-fields.adoc[]
==== Example Response
include::{snippets}/CreateTaskCommentDocTest/http-response.adoc[]
==== Response Structure
The response-body is essentially the same as for getting a specific task comment. +
Therefore for the response fields you can refer to the <<task comment, specific task comment>>.
=== Delete a task comment
A `DELETE` request is used to delete a task comment.
==== Example request
include::{snippets}/DeleteTaskCommentDocTest/http-request.adoc[]
==== Example response
include::{snippets}/DeleteTaskCommentDocTest/http-response.adoc[]
== Classifications-Resource
This resource provides the entry point with classifications.