TSK-1436: reworked review comments.

This commit is contained in:
Mustapha Zorgati 2020-12-03 03:24:21 +01:00
parent 3967e2900e
commit de57596ba8
58 changed files with 542 additions and 441 deletions

View File

@ -21,9 +21,7 @@ import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** /** Default basic configuration for taskana web example. */
* Default basic configuration for taskana web example.
*/
@Configuration @Configuration
public class WebSecurityConfig { public class WebSecurityConfig {

View File

@ -522,6 +522,11 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery {
return this; return this;
} }
@Override
public TaskHistoryQuery orderByTaskHistoryEventId(SortDirection sortDirection) {
return addOrderCriteria("ID", sortDirection);
}
@Override @Override
public TaskHistoryQuery orderByBusinessProcessId(SortDirection sortDirection) { public TaskHistoryQuery orderByBusinessProcessId(SortDirection sortDirection) {
return addOrderCriteria("BUSINESS_PROCESS_ID", sortDirection); return addOrderCriteria("BUSINESS_PROCESS_ID", sortDirection);

View File

@ -335,6 +335,15 @@ public interface TaskHistoryQuery extends BaseQuery<TaskHistoryEvent, TaskHistor
TaskHistoryQuery customAttributeLike( TaskHistoryQuery customAttributeLike(
TaskHistoryCustomField customField, String... searchArguments); TaskHistoryCustomField customField, String... searchArguments);
/**
* Sort the query result by the id of the events.
*
* @param sortDirection Determines whether the result is sorted in ascending or descending order.
* If sortDirection is null, the result is sorted in ascending order
* @return the query
*/
TaskHistoryQuery orderByTaskHistoryEventId(SortDirection sortDirection);
/** /**
* Sort the query result by businessProcessId. * Sort the query result by businessProcessId.
* *

View File

@ -1,5 +1,6 @@
package acceptance.query; package acceptance.query;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest; import acceptance.AbstractAccTest;
@ -109,6 +110,32 @@ class QueryTaskHistoryAccTest extends AbstractAccTest {
assertThat(count).isZero(); assertThat(count).isZero();
} }
@Test
void should_SortQueryByIdAsc_When_Requested() {
List<TaskHistoryEvent> events =
getHistoryService()
.createTaskHistoryQuery()
.orderByTaskHistoryEventId(SortDirection.ASCENDING)
.list();
assertThat(events)
.extracting(TaskHistoryEvent::getId)
.isSortedAccordingTo(CASE_INSENSITIVE_ORDER);
}
@Test
void should_SortQueryByIdDesc_When_Requested() {
List<TaskHistoryEvent> events =
getHistoryService()
.createTaskHistoryQuery()
.orderByTaskHistoryEventId(SortDirection.DESCENDING)
.list();
assertThat(events)
.extracting(TaskHistoryEvent::getId)
.isSortedAccordingTo(CASE_INSENSITIVE_ORDER.reversed());
}
@Test @Test
void should_ReturnHistoryEvents_For_DifferentInAttributes() { void should_ReturnHistoryEvents_For_DifferentInAttributes() {
List<TaskHistoryEvent> returnValues = List<TaskHistoryEvent> returnValues =

View File

@ -1,7 +1,7 @@
= TASKANA History module RESTful API Documentation = TASKANA History module RESTful API Documentation
== Overview == Overview
This is the REST documentation for http://taskana.pro)[TASKANA]'s simplehistory REST Endpoints. This is the REST documentation for http://taskana.pro)[TASKANA]'s simplehistory REST endpoints.
For all Query Parameters:: whenever a parameter is an array type multiple values can be passed by declaring that parameter multiple times. For all Query Parameters:: whenever a parameter is an array type multiple values can be passed by declaring that parameter multiple times.
@ -13,9 +13,9 @@ Please have a look at example responses for each resource to determine the avail
TASKANA uses the https://restfulapi.net/hateoas/)[HATEOAS] (Hypermedia as the Engine of Application State) REST constraint. TASKANA uses the https://restfulapi.net/hateoas/)[HATEOAS] (Hypermedia as the Engine of Application State) REST constraint.
Most of our resources contain a `_links` section which contains navigation links. Most of our resources contain a `_links` section which contains navigation links.
These navigation links not only help navigate through our REST API, they encapsulate API. These navigation links not only help navigate through our REST API, they encapsulate API.
Using HATEOAS allows us to change some Endpoints without breaking any frontend. Using HATEOAS allows us to change some endpoints without breaking any frontend.
== History event == History event
include::{snippets}/TaskHistoryEventControllerRestDocumentationTest/getAllTaskHistoryEventDocTest/auto-section.adoc[] include::{snippets}/TaskHistoryEventControllerRestDocumentationTest/getAllTaskHistoryEventsDocTest/auto-section.adoc[]
include::{snippets}/TaskHistoryEventControllerRestDocumentationTest/getSpecificTaskHistoryEventDocTest/auto-section.adoc[] include::{snippets}/TaskHistoryEventControllerRestDocumentationTest/getSpecificTaskHistoryEventDocTest/auto-section.adoc[]

View File

@ -87,12 +87,13 @@ public class TaskHistoryEventController {
} }
/** /**
* This endpoints retrieves a single Task History Event. * This endpoint retrieves a single Task History Event.
* *
* @title Get a single Task History Event * @title Get a single Task History Event
* @param historyEventId the id of the requested Task History Event. * @param historyEventId the id of the requested Task History Event.
* @return the requested Task History Event * @return the requested Task History Event
* @throws TaskanaHistoryEventNotFoundException if the provided Task History Event is not found. * @throws TaskanaHistoryEventNotFoundException If a Task History Event can't be found by the
* provided historyEventId
*/ */
@GetMapping(path = HistoryRestEndpoints.URL_HISTORY_EVENTS_ID) @GetMapping(path = HistoryRestEndpoints.URL_HISTORY_EVENTS_ID)
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
@ -117,6 +118,7 @@ public class TaskHistoryEventController {
} }
public enum TaskHistoryQuerySortBy implements QuerySortBy<TaskHistoryQuery> { public enum TaskHistoryQuerySortBy implements QuerySortBy<TaskHistoryQuery> {
TASK_HISTORY_EVENT_ID(TaskHistoryQuery::orderByTaskHistoryEventId),
BUSINESS_PROCESS_ID(TaskHistoryQuery::orderByBusinessProcessId), BUSINESS_PROCESS_ID(TaskHistoryQuery::orderByBusinessProcessId),
PARENT_BUSINESS_PROCESS_ID(TaskHistoryQuery::orderByParentBusinessProcessId), PARENT_BUSINESS_PROCESS_ID(TaskHistoryQuery::orderByParentBusinessProcessId),
TASK_ID(TaskHistoryQuery::orderByTaskId), TASK_ID(TaskHistoryQuery::orderByTaskId),

View File

@ -13,30 +13,26 @@ import pro.taskana.spi.history.api.events.task.TaskHistoryCustomField;
public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHistoryQuery, Void> { public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHistoryQuery, Void> {
/** /** Filter by the event type of the Task History Event. This is an exact match. */
* Filter by the event type of the Task History Event. This is an exact match.
*/
@JsonProperty("event-type") @JsonProperty("event-type")
private final String[] eventType; private final String[] eventType;
/** /**
* Filter by the event type of the Task History Event. This results into a substring search. (% is * Filter by the event type of the Task History Event. This results in a substring search.. (% is
* appended to the front and end of the requested value). Further SQL "Like" wildcard characters * appended to the beginning and end of the requested value). Further SQL "Like" wildcard
* will be resolved correctly. * characters will be resolved correctly.
*/ */
@JsonProperty("event-type-like") @JsonProperty("event-type-like")
private final String[] eventTypeLike; private final String[] eventTypeLike;
/** /** Filter by the user id of the Task History Event. This is an exact match. */
* Filter by the user id of the Task History Event. This is an exact match.
*/
@JsonProperty("user-id") @JsonProperty("user-id")
private final String[] userId; private final String[] userId;
/** /**
* Filter by the user id of the Task History Event. This results into a substring search. (% is * Filter by the user id of the Task History Event. This results in a substring search.. (% is
* appended to the front and end of the requested value). Further SQL "Like" wildcard characters * appended to the beginning and end of the requested value). Further SQL "Like" wildcard
* will be resolved correctly. * characters will be resolved correctly.
*/ */
@JsonProperty("user-id-like") @JsonProperty("user-id-like")
private final String[] userIdLike; private final String[] userIdLike;
@ -49,62 +45,52 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
*/ */
private final Instant[] created; private final Instant[] created;
/** /** Filter by the domain of the Task History Event. This is an exact match. */
* Filter by the domain of the Task History Event. This is an exact match.
*/
private final String[] domain; private final String[] domain;
/** /** Filter by the task id of the Task History Event. This is an exact match. */
* Filter by the task id of the Task History Event. This is an exact match.
*/
@JsonProperty("task-id") @JsonProperty("task-id")
private final String[] taskId; private final String[] taskId;
/** /**
* Filter by the task id of the Task History Event. This results into a substring search. (% is * Filter by the task id of the Task History Event. This results in a substring search.. (% is
* appended to the front and end of the requested value). Further SQL "Like" wildcard characters * appended to the beginning and end of the requested value). Further SQL "Like" wildcard
* will be resolved correctly. * characters will be resolved correctly.
*/ */
@JsonProperty("task-id-like") @JsonProperty("task-id-like")
private final String[] taskIdLike; private final String[] taskIdLike;
/** /** Filter by the business process id of the Task History Event. This is an exact match. */
* Filter by the business process id of the Task History Event. This is an exact match.
*/
@JsonProperty("business-process-id") @JsonProperty("business-process-id")
private final String[] businessProcessId; private final String[] businessProcessId;
/** /**
* Filter by the business process id of the Task History Event. This results into a substring * Filter by the business process id of the Task History Event. This results into a substring
* search. (% is appended to the front and end of the requested value). Further SQL "Like" * search. (% is appended to the beginning and end of the requested value). Further SQL "Like"
* wildcard characters will be resolved correctly. * wildcard characters will be resolved correctly.
*/ */
@JsonProperty("business-process-id-like") @JsonProperty("business-process-id-like")
private final String[] businessProcessIdLike; private final String[] businessProcessIdLike;
/** /** Filter by the parent business process id of the Task History Event. This is an exact match. */
* Filter by the parent business process id of the Task History Event. This is an exact match.
*/
@JsonProperty("parent-business-process-id") @JsonProperty("parent-business-process-id")
private final String[] parentBusinessProcessId; private final String[] parentBusinessProcessId;
/** /**
* Filter by the parent business process id of the Task History Event. This results into a * Filter by the parent business process id of the Task History Event. This results into a
* substring search. (% is appended to the front and end of the requested value). Further SQL * substring search. (% is appended to the beginning and end of the requested value). Further SQL
* "Like" wildcard characters will be resolved correctly. * "Like" wildcard characters will be resolved correctly.
*/ */
@JsonProperty("parent-business-process-id-like") @JsonProperty("parent-business-process-id-like")
private final String[] parentBusinessProcessIdLike; private final String[] parentBusinessProcessIdLike;
/** /** Filter by the task classification key of the Task History Event. This is an exact match. */
* Filter by the task classification key of the Task History Event. This is an exact match.
*/
@JsonProperty("task-classification-key") @JsonProperty("task-classification-key")
private final String[] taskClassificationKey; private final String[] taskClassificationKey;
/** /**
* Filter by the task classification key of the Task History Event. This results into a substring * Filter by the task classification key of the Task History Event. This results into a substring
* search. (% is appended to the front and end of the requested value). Further SQL "Like" * search. (% is appended to the beginning and end of the requested value). Further SQL "Like"
* wildcard characters will be resolved correctly. * wildcard characters will be resolved correctly.
*/ */
@JsonProperty("task-classification-key-like") @JsonProperty("task-classification-key-like")
@ -118,7 +104,7 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
/** /**
* Filter by the task classification category of the Task History Event. This results into a * Filter by the task classification category of the Task History Event. This results into a
* substring search. (% is appended to the front and end of the requested value). Further SQL * substring search. (% is appended to the beginning and end of the requested value). Further SQL
* "Like" wildcard characters will be resolved correctly. * "Like" wildcard characters will be resolved correctly.
*/ */
@JsonProperty("task-classification-category-like") @JsonProperty("task-classification-category-like")
@ -132,21 +118,19 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
/** /**
* Filter by the attachment classification key of the Task History Event. This results into a * Filter by the attachment classification key of the Task History Event. This results into a
* substring search. (% is appended to the front and end of the requested value). Further SQL * substring search. (% is appended to the beginning and end of the requested value). Further SQL
* "Like" wildcard characters will be resolved correctly. * "Like" wildcard characters will be resolved correctly.
*/ */
@JsonProperty("attachment-classification-key-like") @JsonProperty("attachment-classification-key-like")
private final String[] attachmentClassificationKeyLike; private final String[] attachmentClassificationKeyLike;
/** /** Filter by the workbasket key of the Task History Event. This is an exact match. */
* Filter by the workbasket key of the Task History Event. This is an exact match.
*/
@JsonProperty("workbasket-key") @JsonProperty("workbasket-key")
private final String[] workbasketKey; private final String[] workbasketKey;
/** /**
* Filter by the workbasket key of the Task History Event. This results into a substring search. * Filter by the workbasket key of the Task History Event. This results in a substring search.. (%
* (% is appended to the front and end of the requested value). Further SQL "Like" wildcard * is appended to the beginning and end of the requested value). Further SQL "Like" wildcard
* characters will be resolved correctly. * characters will be resolved correctly.
*/ */
@JsonProperty("workbasket-key-like") @JsonProperty("workbasket-key-like")
@ -161,8 +145,8 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
/** /**
* Filter by the company of the primary object reference of the Task History Event. This results * Filter by the company of the primary object reference of the Task History Event. This results
* into a substring search. (% is appended to the front and end of the requested value). Further * into a substring search. (% is appended to the beginning and end of the requested value).
* SQL "Like" wildcard characters will be resolved correctly. * Further SQL "Like" wildcard characters will be resolved correctly.
*/ */
@JsonProperty("por-company-like") @JsonProperty("por-company-like")
private final String[] porCompanyLike; private final String[] porCompanyLike;
@ -176,8 +160,8 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
/** /**
* Filter by the system of the primary object reference of the Task History Event. This results * Filter by the system of the primary object reference of the Task History Event. This results
* into a substring search. (% is appended to the front and end of the requested value). Further * into a substring search. (% is appended to the beginning and end of the requested value).
* SQL "Like" wildcard characters will be resolved correctly. * Further SQL "Like" wildcard characters will be resolved correctly.
*/ */
@JsonProperty("por-system-like") @JsonProperty("por-system-like")
private final String[] porSystemLike; private final String[] porSystemLike;
@ -191,8 +175,8 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
/** /**
* Filter by the system instance of the primary object reference of the Task History Event. This * Filter by the system instance of the primary object reference of the Task History Event. This
* results into a substring search. (% is appended to the front and end of the requested value). * results into a substring search. (% is appended to the beginning and end of the requested
* Further SQL "Like" wildcard characters will be resolved correctly. * value). Further SQL "Like" wildcard characters will be resolved correctly.
*/ */
@JsonProperty("por-instance-like") @JsonProperty("por-instance-like")
private final String[] porInstanceLike; private final String[] porInstanceLike;
@ -206,63 +190,55 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
/** /**
* Filter by the value of the primary object reference of the Task History Event. This results * Filter by the value of the primary object reference of the Task History Event. This results
* into a substring search. (% is appended to the front and end of the requested value). Further * into a substring search. (% is appended to the beginning and end of the requested value).
* SQL "Like" wildcard characters will be resolved correctly. * Further SQL "Like" wildcard characters will be resolved correctly.
*/ */
@JsonProperty("por-value-like") @JsonProperty("por-value-like")
private final String[] porValueLike; private final String[] porValueLike;
/** /** Filter by the value of the field custom1. This is an exact match. */
* Filter by the value of the field custom1. This is an exact match.
*/
@JsonProperty("custom-1") @JsonProperty("custom-1")
private final String[] custom1; private final String[] custom1;
/** /**
* Filter by the value of the field custom1. This is an exact match. This results into a substring * Filter by the value of the field custom1. This is an exact match. This results into a substring
* search. (% is appended to the front and end of the requested value). Further SQL "Like" * search. (% is appended to the beginning and end of the requested value). Further SQL "Like"
* wildcard characters will be resolved correctly. * wildcard characters will be resolved correctly.
*/ */
@JsonProperty("custom-1-like") @JsonProperty("custom-1-like")
private final String[] custom1Like; private final String[] custom1Like;
/** /** Filter by the value of the field custom2. This is an exact match. */
* Filter by the value of the field custom2. This is an exact match.
*/
@JsonProperty("custom-2") @JsonProperty("custom-2")
private final String[] custom2; private final String[] custom2;
/** /**
* Filter by the value of the field custom1. This is an exact match. This results into a substring * Filter by the value of the field custom2. This is an exact match. This results into a substring
* search. (% is appended to the front and end of the requested value). Further SQL "Like" * search. (% is appended to the beginning and end of the requested value). Further SQL "Like"
* wildcard characters will be resolved correctly. * wildcard characters will be resolved correctly.
*/ */
@JsonProperty("custom-2-like") @JsonProperty("custom-2-like")
private final String[] custom2Like; private final String[] custom2Like;
/** /** Filter by the value of the field custom3. This is an exact match. */
* Filter by the value of the field custom3. This is an exact match.
*/
@JsonProperty("custom-3") @JsonProperty("custom-3")
private final String[] custom3; private final String[] custom3;
/** /**
* Filter by the value of the field custom1. This is an exact match. This results into a substring * Filter by the value of the field custom3. This is an exact match. This results into a substring
* search. (% is appended to the front and end of the requested value). Further SQL "Like" * search. (% is appended to the beginning and end of the requested value). Further SQL "Like"
* wildcard characters will be resolved correctly. * wildcard characters will be resolved correctly.
*/ */
@JsonProperty("custom-3-like") @JsonProperty("custom-3-like")
private final String[] custom3Like; private final String[] custom3Like;
/** /** Filter by the value of the field custom4. This is an exact match. */
* Filter by the value of the field custom4. This is an exact match.
*/
@JsonProperty("custom-4") @JsonProperty("custom-4")
private final String[] custom4; private final String[] custom4;
/** /**
* Filter by the value of the field custom1. This is an exact match. This results into a substring * Filter by the value of the field custom4. This is an exact match. This results into a substring
* search. (% is appended to the front and end of the requested value). Further SQL "Like" * search. (% is appended to the beginning and end of the requested value). Further SQL "Like"
* wildcard characters will be resolved correctly. * wildcard characters will be resolved correctly.
*/ */
@JsonProperty("custom-4-like") @JsonProperty("custom-4-like")

View File

@ -20,7 +20,7 @@ public class TaskHistoryEventRepresentationModel
/** The type of the event. */ /** The type of the event. */
private String eventType; private String eventType;
/** /**
* The time was created. * The time of event creation.
* *
* <p>The format is ISO-8601. * <p>The format is ISO-8601.
*/ */
@ -29,23 +29,23 @@ public class TaskHistoryEventRepresentationModel
private String userId; private String userId;
/** Domain. */ /** Domain. */
private String domain; private String domain;
/** The key of workbasket. */ /** The key of the Workbasket. */
private String workbasketKey; private String workbasketKey;
/** The company referenced primary object belongs to. */ /** The company the referenced primary object belongs to. */
private String porCompany; private String porCompany;
/** The type of the reference (contract, claim, policy, customer, ...). */ /** The type of the referenced primary object (contract, claim, policy, customer, ...). */
private String porType; private String porType;
/** The (kind of) system, the object resides in (e.g. SAP, MySystem A, ...). */ /** The (kind of) system, the referenced primary object resides in (e.g. SAP, MySystem A, ...). */
private String porSystem; private String porSystem;
/** The instance of the system, the object resides in. */ /** The instance of the system, the referenced primary object resides in. */
private String porInstance; private String porInstance;
/** The value of the primary object reference. */ /** The value of the primary object reference. */
private String porValue; private String porValue;
/** The key of classification task. */ /** The key of the task's classification. */
private String taskClassificationKey; private String taskClassificationKey;
/** The category of classification. */ /** The category of the task's classification. */
private String taskClassificationCategory; private String taskClassificationCategory;
/** The key of the task's attachment. */ /** The classification key of the task's attachment. */
private String attachmentClassificationKey; private String attachmentClassificationKey;
/** The old value. */ /** The old value. */
private String oldValue; private String oldValue;

View File

@ -1,12 +1,12 @@
package pro.taskana.simplehistory.rest; package pro.taskana.simplehistory.rest;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static pro.taskana.common.test.rest.RestHelper.TEMPLATE; import static pro.taskana.common.test.rest.RestHelper.TEMPLATE;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
@ -19,7 +19,9 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.util.UriComponentsBuilder;
import pro.taskana.common.rest.models.PageMetadata;
import pro.taskana.common.test.rest.RestHelper; import pro.taskana.common.test.rest.RestHelper;
import pro.taskana.common.test.rest.TaskanaSpringBootTest; import pro.taskana.common.test.rest.TaskanaSpringBootTest;
import pro.taskana.simplehistory.rest.models.TaskHistoryEventPagedRepresentationModel; import pro.taskana.simplehistory.rest.models.TaskHistoryEventPagedRepresentationModel;
@ -36,8 +38,10 @@ class TaskHistoryEventControllerIntTest {
this.restHelper = restHelper; this.restHelper = restHelper;
} }
// region Get Task History Events
@Test @Test
void testGetAllHistoryEvent() { void should_GetAllHistoryEvents_When_UrlIsVisited() {
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response = ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange( TEMPLATE.exchange(
restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS), restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS),
@ -45,33 +49,29 @@ class TaskHistoryEventControllerIntTest {
restHelper.defaultRequest(), restHelper.defaultRequest(),
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class)); ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
assertThat(response.getBody()).isNotNull(); assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull();
assertThat(response.getBody().getContent()).hasSize(45); assertThat(response.getBody().getContent()).hasSize(45);
} }
@Test @Test
void testGetAllHistoryEventDescendingOrder() { void should_GenerateSelfLink_When_TaskHistoryEventsAreRequested() {
String parameters = "?sort-by=BUSINESS_PROCESS_ID&order=DESCENDING&page-size=3&page=1";
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response = ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange( TEMPLATE.exchange(
restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters), restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS),
HttpMethod.GET, HttpMethod.GET,
restHelper.defaultRequest(), restHelper.defaultRequest(),
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class)); ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
assertThat(response.getBody()).isNotNull(); assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getContent()).hasSize(3);
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)) assertThat(response.getBody().getLink(IanaLinkRelations.SELF))
.isNotNull() .isPresent()
.get() .get()
.extracting(Link::getHref) .extracting(Link::getHref)
.asString() .asString()
.endsWith(parameters); .endsWith(HistoryRestEndpoints.URL_HISTORY_EVENTS);
} }
@Test @Test
void should_ReturnSpecificTaskHistoryEventWithoutDetails_When_ListIsQueried() { void should_ContainQueryParametersInComputedSelfLink_When_TaskHistoryEventsAreRequested() {
String parameters = String parameters = "?domain=DOMAIN_A&domain=DOMAIN_B";
"?business-process-id=BPI:01" + "&sort-by=BUSINESS_PROCESS_ID&page-size=6&page=1";
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response = ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange( TEMPLATE.exchange(
restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters), restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters),
@ -79,31 +79,47 @@ class TaskHistoryEventControllerIntTest {
restHelper.defaultRequest(), restHelper.defaultRequest(),
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class)); ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
assertThat(response.getBody()).isNotNull(); assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getLink(IanaLinkRelations.SELF))
assertThat(response.getBody().getPageMetadata()).isNotNull(); .isPresent()
assertThat(response.getBody().getContent()).hasSize(1); .get()
assertThat(response.getBody().getContent().iterator().next().getDetails()).isNull(); .extracting(Link::getHref)
.asString()
.endsWith(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters);
} }
@Test @Test
void should_ReturnSpecificTaskHistoryEventWithDetails_When_SingleEventIsQueried() { void should_SortEventsByBusinessProcessIdDesc_When_SortByAndOrderQueryParametersAreDeclared() {
ResponseEntity<TaskHistoryEventRepresentationModel> response = String parameters = "?sort-by=BUSINESS_PROCESS_ID&order=DESCENDING";
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange( TEMPLATE.exchange(
restHelper.toUrl( restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters),
HistoryRestEndpoints.URL_HISTORY_EVENTS_ID,
"THI:000000000000000000000000000000000000"),
HttpMethod.GET, HttpMethod.GET,
restHelper.defaultRequest(), restHelper.defaultRequest(),
ParameterizedTypeReference.forType(TaskHistoryEventRepresentationModel.class)); ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
assertThat(response.getBody()).isNotNull(); assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); assertThat(response.getBody().getContent())
assertThat(response.getBody().getDetails()).isNotNull(); .extracting(TaskHistoryEventRepresentationModel::getBusinessProcessId)
.isSortedAccordingTo(CASE_INSENSITIVE_ORDER.reversed());
}
@Test
void should_ApplyBusinessProcessIdFilter_When_QueryParameterIsProvided() {
String parameters = "?business-process-id=BPI:01";
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange(
restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters),
HttpMethod.GET,
restHelper.defaultRequest(),
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getContent())
.extracting(TaskHistoryEventRepresentationModel::getTaskHistoryId)
.containsExactly("THI:000000000000000000000000000000000000");
} }
@Test @Test
@Disabled("no solution for this") @Disabled("no solution for this")
void testThrowsExceptionIfInvalidFilterIsUsed() { void should_ReturnBadStatusErrorCode_When_InvalidQueryParameterIsUsed() {
ThrowingCallable httpCall = ThrowingCallable httpCall =
() -> () ->
TEMPLATE.exchange( TEMPLATE.exchange(
@ -120,8 +136,8 @@ class TaskHistoryEventControllerIntTest {
@Test @Test
@Disabled("Jörg pls fix this") @Disabled("Jörg pls fix this")
void testGetHistoryEventWrongCreatedFormat() { void should_ReturnBadStatusErrorCode_When_CreatedQueryParameterIsWrongFormatted() {
String currentTime = LocalDateTime.now().toString(); String currentTime = "wrong format";
ThrowingCallable httpCall = ThrowingCallable httpCall =
() -> () ->
TEMPLATE.exchange( TEMPLATE.exchange(
@ -138,7 +154,7 @@ class TaskHistoryEventControllerIntTest {
} }
@Test @Test
void testGetHistoryEventOfDate() { void should_ApplyCreatedFilter_When_QueryParametersAreProvided() {
Instant now = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant(); Instant now = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant();
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response = ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange( TEMPLATE.exchange(
@ -153,8 +169,14 @@ class TaskHistoryEventControllerIntTest {
} }
@Test @Test
void testGetSecondPageSortedByKey() { void should_ApplyPaging_When_PagingIsRequested() {
String parameters = "?sort-by=WORKBASKET_KEY&order=DESCENDING&page=2&page-size=2"; String expectedFirstPageParameters = "?sort-by=TASK_HISTORY_EVENT_ID&page-size=3&page=1";
String expectedLastPageParameters = "?sort-by=TASK_HISTORY_EVENT_ID&page-size=3&page=15";
String expectedPrevPageParameters = "?sort-by=TASK_HISTORY_EVENT_ID&page-size=3&page=2";
String expectedNextPageParameters = "?sort-by=TASK_HISTORY_EVENT_ID&page-size=3&page=4";
String parameters = "?sort-by=TASK_HISTORY_EVENT_ID&page-size=3&page=3";
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response = ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange( TEMPLATE.exchange(
restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters), restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS + parameters),
@ -163,19 +185,82 @@ class TaskHistoryEventControllerIntTest {
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class)); ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
assertThat(response.getBody()).isNotNull(); assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getContent()).hasSize(2); assertThat(response.getBody().getContent())
assertThat(response.getBody().getContent().iterator().next().getWorkbasketKey()) .extracting(TaskHistoryEventRepresentationModel::getTaskHistoryId)
.isEqualTo("WBI:100000000000000000000000000000000002"); .containsExactly(
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)) "THI:000000000000000000000000000000000006",
.isNotNull() "THI:000000000000000000000000000000000007",
"THI:000000000000000000000000000000000008");
assertThat(response.getBody().getPageMetadata()).isEqualTo(new PageMetadata(3, 45, 15, 3));
assertThat(response.getBody().getLink(IanaLinkRelations.FIRST))
.isPresent()
.get() .get()
.extracting(Link::getHref) .extracting(Link::getHref)
.asString() .asString()
.endsWith(parameters); .endsWith(HistoryRestEndpoints.URL_HISTORY_EVENTS + expectedFirstPageParameters);
assertThat(response.getBody().getLink(IanaLinkRelations.LAST))
.isPresent()
.get()
.extracting(Link::getHref)
.asString()
.endsWith(HistoryRestEndpoints.URL_HISTORY_EVENTS + expectedLastPageParameters);
assertThat(response.getBody().getLink(IanaLinkRelations.PREV))
.isPresent()
.get()
.extracting(Link::getHref)
.asString()
.endsWith(HistoryRestEndpoints.URL_HISTORY_EVENTS + expectedPrevPageParameters);
assertThat(response.getBody().getLink(IanaLinkRelations.NEXT))
.isPresent()
.get()
.extracting(Link::getHref)
.asString()
.endsWith(HistoryRestEndpoints.URL_HISTORY_EVENTS + expectedNextPageParameters);
}
assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); // endregion
assertThat(response.getBody().getLink(IanaLinkRelations.PREV)).isNotNull();
assertThat(response.getBody().getLink(IanaLinkRelations.NEXT)).isNotNull(); // region Get Specific Task History Event
assertThat(response.getBody().getLink(IanaLinkRelations.LAST)).isNotNull();
@Test
void should_GenerateSelfLink_When_SpecificTaskHistoryEventIsRequested() {
String id = "THI:000000000000000000000000000000000000";
String expectedUrl =
UriComponentsBuilder.fromPath(HistoryRestEndpoints.URL_HISTORY_EVENTS_ID)
.buildAndExpand(id)
.toUriString();
ResponseEntity<TaskHistoryEventPagedRepresentationModel> response =
TEMPLATE.exchange(
restHelper.toUrl(HistoryRestEndpoints.URL_HISTORY_EVENTS_ID, id),
HttpMethod.GET,
restHelper.defaultRequest(),
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getLink(IanaLinkRelations.SELF))
.isPresent()
.get()
.extracting(Link::getHref)
.asString()
.endsWith(expectedUrl);
} }
@Test
void should_GetSpecificTaskHistoryEventWithDetails_When_SingleEventIsQueried() {
ResponseEntity<TaskHistoryEventRepresentationModel> response =
TEMPLATE.exchange(
restHelper.toUrl(
HistoryRestEndpoints.URL_HISTORY_EVENTS_ID,
"THI:000000000000000000000000000000000000"),
HttpMethod.GET,
restHelper.defaultRequest(),
ParameterizedTypeReference.forType(TaskHistoryEventRepresentationModel.class));
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getDetails()).isNotNull();
}
// endregion
} }

View File

@ -10,17 +10,18 @@ import pro.taskana.common.test.BaseRestDocumentationTest;
class TaskHistoryEventControllerRestDocumentationTest extends BaseRestDocumentationTest { class TaskHistoryEventControllerRestDocumentationTest extends BaseRestDocumentationTest {
@Test @Test
void getAllTaskHistoryEventDocTest() throws Exception { void getAllTaskHistoryEventsDocTest() throws Exception {
mockMvc mockMvc
.perform( .perform(get(HistoryRestEndpoints.URL_HISTORY_EVENTS + "?page=1&page-size=3"))
get(HistoryRestEndpoints.URL_HISTORY_EVENTS + "?page=1&page-size=3"))
.andExpect(MockMvcResultMatchers.status().isOk()); .andExpect(MockMvcResultMatchers.status().isOk());
} }
@Test @Test
void getSpecificTaskHistoryEventDocTest() throws Exception { void getSpecificTaskHistoryEventDocTest() throws Exception {
mockMvc mockMvc
.perform(get(HistoryRestEndpoints.URL_HISTORY_EVENTS_ID, .perform(
get(
HistoryRestEndpoints.URL_HISTORY_EVENTS_ID,
"THI:000000000000000000000000000000000000")) "THI:000000000000000000000000000000000000"))
.andExpect(MockMvcResultMatchers.status().isOk()); .andExpect(MockMvcResultMatchers.status().isOk());
} }

View File

@ -90,8 +90,8 @@ public interface ClassificationService {
* @return the updated Classification. * @return the updated Classification.
* @throws ClassificationNotFoundException if the classification OR it´s parent does not exist. * @throws ClassificationNotFoundException if the classification OR it´s parent does not exist.
* @throws NotAuthorizedException if the caller got no ADMIN or BUSINESS_ADMIN permissions. * @throws NotAuthorizedException if the caller got no ADMIN or BUSINESS_ADMIN permissions.
* @throws ConcurrencyException if the Classification was modified meanwhile and is not latest * @throws ConcurrencyException If the classification was modified in the meantime and is not the
* anymore. * most up to date anymore.
* @throws InvalidArgumentException if the ServiceLevel property does not comply with the ISO 8601 * @throws InvalidArgumentException if the ServiceLevel property does not comply with the ISO 8601
* specification * specification
*/ */

View File

@ -447,7 +447,7 @@ public interface TaskQuery extends BaseQuery<TaskSummary, TaskQueryColumnName> {
* @param customField identifies which custom attribute is affected. * @param customField identifies which custom attribute is affected.
* @param searchArguments the customField values of the searched for tasks * @param searchArguments the customField values of the searched for tasks
* @return the query * @return the query
* @throws InvalidArgumentException if searchArguments is not given * @throws InvalidArgumentException if searchArguments are not given
*/ */
TaskQuery customAttributeIn(TaskCustomField customField, String... searchArguments) TaskQuery customAttributeIn(TaskCustomField customField, String... searchArguments)
throws InvalidArgumentException; throws InvalidArgumentException;

View File

@ -62,7 +62,7 @@ public interface TaskService {
* @param taskId id of the task which should be unclaimed. * @param taskId id of the task which should be unclaimed.
* @return updated unclaimed task * @return updated unclaimed task
* @throws TaskNotFoundException if the task can´t be found or does not exist * @throws TaskNotFoundException if the task can´t be found or does not exist
* @throws InvalidStateException if the task is already in a final state. * @throws InvalidStateException if the task is already in an end state.
* @throws InvalidOwnerException if the task is claimed by another user. * @throws InvalidOwnerException if the task is claimed by another user.
* @throws NotAuthorizedException if the current user has no read permission for the workbasket * @throws NotAuthorizedException if the current user has no read permission for the workbasket
* the task is in * the task is in
@ -77,9 +77,8 @@ public interface TaskService {
* @param taskId id of the task which should be unclaimed. * @param taskId id of the task which should be unclaimed.
* @return updated unclaimed task * @return updated unclaimed task
* @throws TaskNotFoundException if the task can´t be found or does not exist * @throws TaskNotFoundException if the task can´t be found or does not exist
* @throws InvalidStateException if the task is already completed. * @throws InvalidStateException if the task is already in an end state.
* @throws InvalidOwnerException if forceCancel is false and the task is claimed by another * @throws InvalidOwnerException if forceCancel is false and the task is claimed by another user.
* user.
* @throws NotAuthorizedException if the current user has no read permission for the workbasket * @throws NotAuthorizedException if the current user has no read permission for the workbasket
* the task is in * the task is in
*/ */
@ -307,7 +306,7 @@ public interface TaskService {
* *
* @param taskId The Id of the task to delete. * @param taskId The Id of the task to delete.
* @throws TaskNotFoundException If the given Id does not refer to an existing task. * @throws TaskNotFoundException If the given Id does not refer to an existing task.
* @throws InvalidStateException If the state of the referenced task is not Completed. * @throws InvalidStateException If the state of the referenced task is not an end state.
* @throws NotAuthorizedException if the current user is not member of role ADMIN * @throws NotAuthorizedException if the current user is not member of role ADMIN
*/ */
void deleteTask(String taskId) void deleteTask(String taskId)
@ -318,7 +317,7 @@ public interface TaskService {
* *
* @param taskId The Id of the task to delete. * @param taskId The Id of the task to delete.
* @throws TaskNotFoundException If the given Id does not refer to an existing task. * @throws TaskNotFoundException If the given Id does not refer to an existing task.
* @throws InvalidStateException If the state of the referenced task is not Completed and * @throws InvalidStateException If the state of the referenced task is not an end state and
* forceDelete is false. * forceDelete is false.
* @throws NotAuthorizedException if the current user is not member of role ADMIN * @throws NotAuthorizedException if the current user is not member of role ADMIN
*/ */

View File

@ -279,8 +279,8 @@ public interface WorkbasketService {
throws NotAuthorizedException, WorkbasketNotFoundException; throws NotAuthorizedException, WorkbasketNotFoundException;
/** /**
* Remove a distribution target from a workbasket. If the the specified distribution target * Remove a distribution target from a workbasket. If the specified distribution target doesn't
* doesn't exist, the method silently returns without doing anything. * exist, the method silently returns without doing anything.
* *
* @param sourceWorkbasketId The id of the source workbasket * @param sourceWorkbasketId The id of the source workbasket
* @param targetWorkbasketId The id of the target workbasket * @param targetWorkbasketId The id of the target workbasket

View File

@ -37,7 +37,7 @@ class CancelTaskAccTest extends AbstractAccTest {
@WithAccessId(user = "user-1-2") @WithAccessId(user = "user-1-2")
@Test @Test
void testQeryCancelledTasks() { void testQueryCancelledTasks() {
List<TaskSummary> taskSummaries = List<TaskSummary> taskSummaries =
taskService.createTaskQuery().stateIn(TaskState.CANCELLED).list(); taskService.createTaskQuery().stateIn(TaskState.CANCELLED).list();
assertThat(taskSummaries).hasSize(5); assertThat(taskSummaries).hasSize(5);

View File

@ -18,7 +18,7 @@ import pro.taskana.workbasket.api.WorkbasketType;
import pro.taskana.workbasket.internal.models.WorkbasketAccessItemImpl; import pro.taskana.workbasket.internal.models.WorkbasketAccessItemImpl;
import pro.taskana.workbasket.internal.models.WorkbasketImpl; import pro.taskana.workbasket.internal.models.WorkbasketImpl;
// TODO: this has to be moved to taskana-common but this is currently not possible due to the the // TODO: this has to be moved to taskana-common but this is currently not possible due to the
// workbasket and task imports // workbasket and task imports
class ObjectAttributeChangeDetectorTest { class ObjectAttributeChangeDetectorTest {

View File

@ -13,9 +13,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import pro.taskana.common.rest.SpringSecurityToJaasFilter; import pro.taskana.common.rest.SpringSecurityToJaasFilter;
/** /** Default basic configuration for taskana web example. */
* Default basic configuration for taskana web example.
*/
@EnableWebSecurity @EnableWebSecurity
public class BootWebSecurityConfigurer extends WebSecurityConfigurerAdapter { public class BootWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@ -116,5 +114,4 @@ public class BootWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
filter.setCreateEmptySubject(true); filter.setCreateEmptySubject(true);
return filter; return filter;
} }
} }

View File

@ -18,5 +18,4 @@ public class TaskanaWildFlyApplication extends SpringBootServletInitializer {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(TaskanaWildFlyApplication.class, args); SpringApplication.run(TaskanaWildFlyApplication.class, args);
} }
} }

View File

@ -25,5 +25,4 @@ public class WildflyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
filter.setCreateEmptySubject(true); filter.setCreateEmptySubject(true);
return filter; return filter;
} }
} }

View File

@ -49,19 +49,16 @@ public class AbstractAccTest {
protected ResponseEntity<TaskHistoryEventPagedRepresentationModel> protected ResponseEntity<TaskHistoryEventPagedRepresentationModel>
performGetHistoryEventsRestCall() { performGetHistoryEventsRestCall() {
return RestHelper.TEMPLATE return RestHelper.TEMPLATE.exchange(
.exchange(
restHelper.toUrl("/taskana" + HistoryRestEndpoints.URL_HISTORY_EVENTS), restHelper.toUrl("/taskana" + HistoryRestEndpoints.URL_HISTORY_EVENTS),
HttpMethod.GET, HttpMethod.GET,
restHelper.defaultRequest(), restHelper.defaultRequest(),
ParameterizedTypeReference ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
.forType(TaskHistoryEventPagedRepresentationModel.class));
} }
protected ResponseEntity<TaskRepresentationModel> performCreateTaskRestCall() { protected ResponseEntity<TaskRepresentationModel> performCreateTaskRestCall() {
TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); TaskRepresentationModel taskRepresentationModel = getTaskResourceSample();
return RestHelper.TEMPLATE return RestHelper.TEMPLATE.exchange(
.exchange(
restHelper.toUrl("/taskana" + RestEndpoints.URL_TASKS), restHelper.toUrl("/taskana" + RestEndpoints.URL_TASKS),
HttpMethod.POST, HttpMethod.POST,
new HttpEntity<>(taskRepresentationModel, restHelper.getHeadersTeamlead_1()), new HttpEntity<>(taskRepresentationModel, restHelper.getHeadersTeamlead_1()),

View File

@ -1,6 +1,7 @@
package pro.taskana; package pro.taskana;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static pro.taskana.common.test.rest.RestHelper.TEMPLATE;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
@ -23,7 +24,6 @@ import org.springframework.http.ResponseEntity;
import pro.taskana.common.rest.RestEndpoints; import pro.taskana.common.rest.RestEndpoints;
import pro.taskana.common.rest.models.AccessIdRepresentationModel; import pro.taskana.common.rest.models.AccessIdRepresentationModel;
import pro.taskana.common.rest.models.TaskanaUserInfoRepresentationModel; import pro.taskana.common.rest.models.TaskanaUserInfoRepresentationModel;
import pro.taskana.common.test.rest.RestHelper;
import pro.taskana.task.rest.models.TaskRepresentationModel; import pro.taskana.task.rest.models.TaskRepresentationModel;
/** /**
@ -69,8 +69,7 @@ public class TaskanaWildflyTest extends AbstractAccTest {
@RunAsClient @RunAsClient
public void should_ReturnUserInformationForAuthenticatedUser_IfRequested() { public void should_ReturnUserInformationForAuthenticatedUser_IfRequested() {
ResponseEntity<TaskanaUserInfoRepresentationModel> response = ResponseEntity<TaskanaUserInfoRepresentationModel> response =
RestHelper.TEMPLATE TEMPLATE.exchange(
.exchange(
restHelper.toUrl("/taskana" + RestEndpoints.URL_CURRENT_USER), restHelper.toUrl("/taskana" + RestEndpoints.URL_CURRENT_USER),
HttpMethod.GET, HttpMethod.GET,
restHelper.defaultRequest(), restHelper.defaultRequest(),
@ -87,13 +86,11 @@ public class TaskanaWildflyTest extends AbstractAccTest {
@RunAsClient @RunAsClient
public void should_ReturnUserFromLdap_WhenWildcardSearchIsConducted() { public void should_ReturnUserFromLdap_WhenWildcardSearchIsConducted() {
ResponseEntity<List<AccessIdRepresentationModel>> response = ResponseEntity<List<AccessIdRepresentationModel>> response =
RestHelper.TEMPLATE TEMPLATE.exchange(
.exchange(
restHelper.toUrl("/taskana" + RestEndpoints.URL_ACCESS_ID + "?search-for=rig"), restHelper.toUrl("/taskana" + RestEndpoints.URL_ACCESS_ID + "?search-for=rig"),
HttpMethod.GET, HttpMethod.GET,
restHelper.defaultRequest(), restHelper.defaultRequest(),
new ParameterizedTypeReference<List<AccessIdRepresentationModel>>() { new ParameterizedTypeReference<List<AccessIdRepresentationModel>>() {});
});
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).hasSize(2); assertThat(response.getBody()).hasSize(2);
} }
@ -102,8 +99,9 @@ public class TaskanaWildflyTest extends AbstractAccTest {
@RunAsClient @RunAsClient
public void should_ReturnTask_WhenRequested() { public void should_ReturnTask_WhenRequested() {
ResponseEntity<TaskRepresentationModel> response = ResponseEntity<TaskRepresentationModel> response =
RestHelper.TEMPLATE TEMPLATE.exchange(
.exchange(restHelper.toUrl("/taskana" + RestEndpoints.URL_TASKS_ID, restHelper.toUrl(
"/taskana" + RestEndpoints.URL_TASKS_ID,
"TKI:000000000000000000000000000000000001"), "TKI:000000000000000000000000000000000001"),
HttpMethod.GET, HttpMethod.GET,
restHelper.defaultRequest(), restHelper.defaultRequest(),

View File

@ -11,7 +11,7 @@ NOTE: HATEOAS support is still in development. Please have a look at example res
TASKANA uses the https://restfulapi.net/hateoas/)[HATEOAS] (Hypermedia as the Engine of Application State) REST constraint. TASKANA uses the https://restfulapi.net/hateoas/)[HATEOAS] (Hypermedia as the Engine of Application State) REST constraint.
Most of our resources contain a `_links` section which contains navigation links. Most of our resources contain a `_links` section which contains navigation links.
These navigation links not only help navigate through our REST API, they encapsulate API. These navigation links not only help navigate through our REST API, they encapsulate API.
Using HATEOAS allows us to change some Endpoints without breaking any frontend. Using HATEOAS allows us to change some endpoints without breaking any frontend.
== Task Resource == Task Resource
@ -81,6 +81,7 @@ include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getClassificati
include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getClassificationCategoriesByTypeMapDocTest/auto-section.adoc[] include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getClassificationCategoriesByTypeMapDocTest/auto-section.adoc[]
include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getCurrentUserInfoDocTest/auto-section.adoc[] include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getCurrentUserInfoDocTest/auto-section.adoc[]
include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getHistoryProviderIsEnabledDocTest/auto-section.adoc[] include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getHistoryProviderIsEnabledDocTest/auto-section.adoc[]
include::{snippets}/TaskanaEngineControllerRestDocumentationTest/getCurrentVersionDocTest/auto-section.adoc[]
== Import / Export == Import / Export

View File

@ -95,12 +95,12 @@ public class ClassificationController {
} }
/** /**
* This endpoints retrieves a single Classification. * This endpoint retrieves a single Classification.
* *
* @title Get a single Classification
* @param classificationId the id of the requested Classification. * @param classificationId the id of the requested Classification.
* @return the requested classification * @return the requested classification
* @throws ClassificationNotFoundException if the provided classification is not found. * @throws ClassificationNotFoundException if the requested classification is not found.
* @title Get a single Classification
*/ */
@GetMapping(path = RestEndpoints.URL_CLASSIFICATIONS_ID, produces = MediaTypes.HAL_JSON_VALUE) @GetMapping(path = RestEndpoints.URL_CLASSIFICATIONS_ID, produces = MediaTypes.HAL_JSON_VALUE)
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
@ -121,7 +121,7 @@ public class ClassificationController {
} }
/** /**
* This endpoints creates a new Classification. * This endpoint creates a new Classification.
* *
* @title Create a new Classification * @title Create a new Classification
* @param repModel the Classification which should be created. * @param repModel the Classification which should be created.
@ -165,8 +165,7 @@ public class ClassificationController {
* @throws ClassificationNotFoundException if the requested Classification is not found * @throws ClassificationNotFoundException if the requested Classification is not found
* @throws ConcurrencyException if the requested Classification id has been modified in the * @throws ConcurrencyException if the requested Classification id has been modified in the
* meantime by a different process. * meantime by a different process.
* @throws InvalidArgumentException if the id in the path and in the the request body does not * @throws InvalidArgumentException if the id in the path and in the request body does not match
* match
*/ */
@PutMapping(path = RestEndpoints.URL_CLASSIFICATIONS_ID) @PutMapping(path = RestEndpoints.URL_CLASSIFICATIONS_ID)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)

View File

@ -110,7 +110,7 @@ public class ClassificationDefinitionController {
* @param file the file containing the Classifications which should be imported. * @param file the file containing the Classifications which should be imported.
* @return nothing * @return nothing
* @throws InvalidArgumentException if any Classification within the import file is invalid * @throws InvalidArgumentException if any Classification within the import file is invalid
* @throws NotAuthorizedException if the current user is not authorized to import Classification * @throws NotAuthorizedException if the current user is not authorized to import Classifications
* @throws ConcurrencyException TODO: this makes no sense * @throws ConcurrencyException TODO: this makes no sense
* @throws ClassificationNotFoundException TODO: this makes no sense * @throws ClassificationNotFoundException TODO: this makes no sense
* @throws ClassificationAlreadyExistException TODO: this makes no sense * @throws ClassificationAlreadyExistException TODO: this makes no sense

View File

@ -19,8 +19,8 @@ public class ClassificationQueryFilterParameter
private final String[] name; private final String[] name;
/** /**
* Filter by the name of the classification. This results into a substring search. (% is appended * Filter by the name of the classification. This results in a substring search. (% is appended to
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * the beginning and end of the requested value). Further SQL "Like" wildcard characters will be
* resolved correctly. * resolved correctly.
*/ */
@JsonProperty("name-like") @JsonProperty("name-like")
@ -39,64 +39,64 @@ public class ClassificationQueryFilterParameter
private final String[] type; private final String[] type;
/** /**
* Filter by the value of the field custom1. This results into a substring search. (% is appended * Filter by the value of the field custom1. This results in a substring search.. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* resolved correctly. * be resolved correctly.
*/ */
@JsonProperty("custom-1-like") @JsonProperty("custom-1-like")
private final String[] custom1Like; private final String[] custom1Like;
/** /**
* Filter by the value of the field custom2. This results into a substring search. (% is appended * Filter by the value of the field custom2. This results in a substring search.. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* resolved correctly. * be resolved correctly.
*/ */
@JsonProperty("custom-2-like") @JsonProperty("custom-2-like")
private final String[] custom3Like;
/**
* Filter by the value of the field custom3. This results into a substring search. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be
* resolved correctly.
*/
@JsonProperty("custom-3-like")
private final String[] custom2Like; private final String[] custom2Like;
/** /**
* Filter by the value of the field custom4. This results into a substring search. (% is appended * Filter by the value of the field custom3. This results in a substring search.. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* resolved correctly. * be resolved correctly.
*/
@JsonProperty("custom-3-like")
private final String[] custom3Like;
/**
* Filter by the value of the field custom4. This results in a substring search.. (% is appended
* to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* be resolved correctly.
*/ */
@JsonProperty("custom-4-like") @JsonProperty("custom-4-like")
private final String[] custom4Like; private final String[] custom4Like;
/** /**
* Filter by the value of the field custom5. This results into a substring search. (% is appended * Filter by the value of the field custom5. This results in a substring search.. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* resolved correctly. * be resolved correctly.
*/ */
@JsonProperty("custom-5-like") @JsonProperty("custom-5-like")
private final String[] custom5Like; private final String[] custom5Like;
/** /**
* Filter by the value of the field custom6. This results into a substring search. (% is appended * Filter by the value of the field custom6. This results in a substring search.. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* resolved correctly. * be resolved correctly.
*/ */
@JsonProperty("custom-6-like") @JsonProperty("custom-6-like")
private final String[] custom6Like; private final String[] custom6Like;
/** /**
* Filter by the value of the field custom7. This results into a substring search. (% is appended * Filter by the value of the field custom7. This results in a substring search.. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* resolved correctly. * be resolved correctly.
*/ */
@JsonProperty("custom-7-like") @JsonProperty("custom-7-like")
private final String[] custom7Like; private final String[] custom7Like;
/** /**
* Filter by the value of the field custom8. This results into a substring search. (% is appended * Filter by the value of the field custom8. This results in a substring search.. (% is appended
* to the front and end of the requested value). Further SQL "Like" wildcard characters will be * to the beginning and end of the requested value). Further SQL "Like" wildcard characters will
* resolved correctly. * be resolved correctly.
*/ */
@JsonProperty("custom-8-like") @JsonProperty("custom-8-like")
private final String[] custom8Like; private final String[] custom8Like;

View File

@ -41,7 +41,7 @@ public class ClassificationSummaryRepresentationModel
* *
* <p>This is stated according to ISO 8601. * <p>This is stated according to ISO 8601.
*/ */
protected String serviceLevel; @NotNull protected String serviceLevel;
/** The type of classification. Types can be configured in the file 'taskana.properties'. */ /** The type of classification. Types can be configured in the file 'taskana.properties'. */
protected String type; protected String type;
/** A custom property with name "1". */ /** A custom property with name "1". */

View File

@ -40,7 +40,7 @@ public class AccessIdController {
* @title Search for Access Id (users and groups) * @title Search for Access Id (users and groups)
* @param searchFor the Access Id which should be searched for. * @param searchFor the Access Id which should be searched for.
* @return a list of all found Access Ids * @return a list of all found Access Ids
* @throws InvalidArgumentException if the provided search for access id is shorter thant the * @throws InvalidArgumentException if the provided search for access id is shorter than the
* configured one. * configured one.
* @throws NotAuthorizedException if the current user is not ADMIN or BUSINESS_ADMIN. * @throws NotAuthorizedException if the current user is not ADMIN or BUSINESS_ADMIN.
*/ */

View File

@ -59,7 +59,7 @@ public class QuerySortParameter<Q extends BaseQuery<?, ?>, S extends QuerySortBy
throws InvalidArgumentException { throws InvalidArgumentException {
if (sortBy == null && order != null) { if (sortBy == null && order != null) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
"Only 'order' were provided. Please also provide 'sort-by' parameter(s)"); "Only 'order' parameters were provided. Please also provide 'sort-by' parameter(s)");
} }
} }

View File

@ -38,7 +38,6 @@ public class TaskanaEngineController {
* *
* @return An array with the domain-names as strings * @return An array with the domain-names as strings
*/ */
// TODO: this is not proper usage of this endpoint..
@GetMapping(path = RestEndpoints.URL_DOMAIN) @GetMapping(path = RestEndpoints.URL_DOMAIN)
public ResponseEntity<List<String>> getDomains() { public ResponseEntity<List<String>> getDomains() {
ResponseEntity<List<String>> response = ResponseEntity<List<String>> response =

View File

@ -1,21 +1,19 @@
package pro.taskana.common.rest.models; package pro.taskana.common.rest.models;
/** import org.springframework.hateoas.RepresentationModel;
* resource class for access id validation. import org.springframework.lang.NonNull;
*/
public class AccessIdRepresentationModel {
/** /** EntityModel for access id validation. */
* The name of this Access Id. public class AccessIdRepresentationModel extends RepresentationModel<AccessIdRepresentationModel> {
*/
/** The name of this Access Id. */
private String name; private String name;
/** /**
* The value of the Access Id. This value will be used to determine the access to a workbasket. * The value of the Access Id. This value will be used to determine the access to a workbasket.
*/ */
private String accessId; private String accessId;
public AccessIdRepresentationModel() { public AccessIdRepresentationModel() {}
}
public AccessIdRepresentationModel(String name, String accessId) { public AccessIdRepresentationModel(String name, String accessId) {
this.accessId = accessId; this.accessId = accessId;
@ -39,7 +37,7 @@ public class AccessIdRepresentationModel {
} }
@Override @Override
public String toString() { public @NonNull String toString() {
return "AccessIdResource [" + "name=" + this.name + ", accessId=" + this.accessId + "]"; return "AccessIdResource [" + "name=" + this.name + ", accessId=" + this.accessId + "]";
} }
} }

View File

@ -1,6 +1,7 @@
package pro.taskana.common.rest.models; package pro.taskana.common.rest.models;
import java.beans.ConstructorProperties; import java.beans.ConstructorProperties;
import java.util.Objects;
/** /**
* This is copied from {@link org.springframework.hateoas.PagedModel.PageMetadata}. Reason: The * This is copied from {@link org.springframework.hateoas.PagedModel.PageMetadata}. Reason: The
@ -41,4 +42,37 @@ public class PageMetadata {
public long getNumber() { public long getNumber() {
return number; return number;
} }
@Override
public int hashCode() {
return Objects.hash(size, totalElements, totalPages, number);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof PageMetadata)) {
return false;
}
PageMetadata other = (PageMetadata) obj;
return size == other.size
&& totalElements == other.totalElements
&& totalPages == other.totalPages
&& number == other.number;
}
@Override
public String toString() {
return "PageMetadata [size="
+ size
+ ", totalElements="
+ totalElements
+ ", totalPages="
+ totalPages
+ ", number="
+ number
+ "]";
}
} }

View File

@ -3,6 +3,7 @@ package pro.taskana.common.rest.models;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.hateoas.RepresentationModel; import org.springframework.hateoas.RepresentationModel;
import org.springframework.lang.NonNull;
import pro.taskana.common.api.TaskanaRole; import pro.taskana.common.api.TaskanaRole;
@ -14,7 +15,7 @@ public class TaskanaUserInfoRepresentationModel
private String userId; private String userId;
/** All groups the current user is a member of. */ /** All groups the current user is a member of. */
private List<String> groupIds = new ArrayList<>(); private List<String> groupIds = new ArrayList<>();
/** All taskana roles the current user is a member of. */ /** All taskana roles the current user fulfills. */
private List<TaskanaRole> roles = new ArrayList<>(); private List<TaskanaRole> roles = new ArrayList<>();
public String getUserId() { public String getUserId() {
@ -42,7 +43,7 @@ public class TaskanaUserInfoRepresentationModel
} }
@Override @Override
public String toString() { public @NonNull String toString() {
return "TaskanaUserInfoRepresentationModel [userId=" return "TaskanaUserInfoRepresentationModel [userId="
+ userId + userId
+ ", groupIds=" + ", groupIds="

View File

@ -1,11 +1,14 @@
package pro.taskana.common.rest.models; package pro.taskana.common.rest.models;
import javax.validation.constraints.NotNull;
import org.springframework.hateoas.RepresentationModel; import org.springframework.hateoas.RepresentationModel;
import org.springframework.lang.NonNull;
/** EntityModel class for version information. */ /** EntityModel class for version information. */
public class VersionRepresentationModel extends RepresentationModel<VersionRepresentationModel> { public class VersionRepresentationModel extends RepresentationModel<VersionRepresentationModel> {
private String version; /** The current TASKANA version of the REST Service. */
@NotNull private String version;
public String getVersion() { public String getVersion() {
return version; return version;
@ -16,7 +19,7 @@ public class VersionRepresentationModel extends RepresentationModel<VersionRepre
} }
@Override @Override
public String toString() { public @NonNull String toString() {
return "VersionResource [" + "version= " + this.version + "]"; return "VersionResource [" + "version= " + this.version + "]";
} }
} }

View File

@ -46,7 +46,7 @@ public class MonitorController {
} }
/** /**
* This endpoints generates a Task Status Report. * This endpoint generates a Task Status Report.
* *
* <p>A Task Status Report contains the total number of tasks, clustered in their Task States and * <p>A Task Status Report contains the total number of tasks, clustered in their Task States and
* grouped by Workbaskets. Each row represents a Workbasket while each column represents a Task * grouped by Workbaskets. Each row represents a Workbasket while each column represents a Task
@ -55,7 +55,7 @@ public class MonitorController {
* @param domains Filter the report values by domains. * @param domains Filter the report values by domains.
* @param states Filter the report values by task states. * @param states Filter the report values by task states.
* @return the computed TaskStatusReport * @return the computed TaskStatusReport
* @throws NotAuthorizedException if the current user is not authenticated to compute the report * @throws NotAuthorizedException if the current user is not authorized to compute the report
* @title Get a Task Status Report * @title Get a Task Status Report
*/ */
@GetMapping(path = RestEndpoints.URL_MONITOR_TASKS_STATUS_REPORT) @GetMapping(path = RestEndpoints.URL_MONITOR_TASKS_STATUS_REPORT)
@ -83,7 +83,7 @@ public class MonitorController {
} }
/** /**
* This endpoints generates a Workbasket Report. * This endpoint generates a Workbasket Report.
* *
* <p>A WorkbasketReport contains the total numbers of tasks, clustered by the a Task Timestamp * <p>A WorkbasketReport contains the total numbers of tasks, clustered by the a Task Timestamp
* date range and grouped by Workbaskets. Each row represents a Workbasket while each column * date range and grouped by Workbaskets. Each row represents a Workbasket while each column
@ -92,7 +92,7 @@ public class MonitorController {
* @param states Filter the report by task states * @param states Filter the report by task states
* @param taskTimestamp determine which task timestamp should be used for comparison * @param taskTimestamp determine which task timestamp should be used for comparison
* @return the computed report * @return the computed report
* @throws NotAuthorizedException if the current user is not authenticated to compute the report * @throws NotAuthorizedException if the current user is not authorized to compute the report
* @throws InvalidArgumentException TODO: this is never thrown ... * @throws InvalidArgumentException TODO: this is never thrown ...
* @title Get a Workbasket Report * @title Get a Workbasket Report
*/ */
@ -154,16 +154,16 @@ public class MonitorController {
} }
/** /**
* This endpoints generates a Classification Report. * This endpoint generates a Classification Report.
* *
* <p>A Classification Report contains the total numbers of tasks, clustered by the a Task * <p>A Classification Report contains the total numbers of tasks, clustered by the Task Timestamp
* Timestamp date range and grouped by Classifications. Each row represents a Classification while * date range and grouped by Classifications. Each row represents a Classification while each
* each column represents a date range. * column represents a date range.
* *
* @title Get a Classification Report * @title Get a Classification Report
* @return the computed report * @return the computed report
* @param taskTimestamp determine which Task Timestamp should be used for comparison * @param taskTimestamp determine which Task Timestamp should be used for comparison
* @throws NotAuthorizedException if the current user is not authenticated to compute the report * @throws NotAuthorizedException if the current user is not authorized to compute the report
* @throws InvalidArgumentException TODO: this is never thrown * @throws InvalidArgumentException TODO: this is never thrown
*/ */
@GetMapping(path = RestEndpoints.URL_MONITOR_TASKS_CLASSIFICATION_REPORT) @GetMapping(path = RestEndpoints.URL_MONITOR_TASKS_CLASSIFICATION_REPORT)
@ -192,15 +192,15 @@ public class MonitorController {
} }
/** /**
* This endpoints generates a Timestamp Report. * This endpoint generates a Timestamp Report.
* *
* <p>A Timestamp Report contains the total numbers of tasks, clustered by date range and grouped * <p>A Timestamp Report contains the total number of tasks, clustered by date range and grouped
* by its Task Status. Each row represents a Task Status while each column represents a date * by its Task Status. Each row represents a Task Status while each column represents a date
* range. Each row can be expanded to further group the tasks by their Org Level (1-4) * range. Each row can be expanded to further group the tasks by their Org Level (1-4)
* *
* @title Get a Timestamp Report * @title Get a Timestamp Report
* @return the computed report * @return the computed report
* @throws NotAuthorizedException if the current user is not authenticated to compute the report * @throws NotAuthorizedException if the current user is not authorized to compute the report
* @throws InvalidArgumentException TODO: this is never thrown * @throws InvalidArgumentException TODO: this is never thrown
*/ */
@GetMapping(path = RestEndpoints.URL_MONITOR_TIMESTAMP_REPORT) @GetMapping(path = RestEndpoints.URL_MONITOR_TIMESTAMP_REPORT)

View File

@ -109,22 +109,22 @@ public class ReportRepresentationModel extends RepresentationModel<ReportReprese
private final Instant date; private final Instant date;
/** Column-headers of the report. */ /** Column-headers of the report. */
private final String[] header; private final String[] header;
/** Descriptions for the rows the report. */ /** Descriptions for the rows of the report. */
private final String[] rowDesc; private final String[] rowDesc;
/** Description for the sum column. */ /** Description for the sum column. */
private final String totalDesc; private final String sumRowDesc;
public MetaInformation( public MetaInformation(
String name, Instant date, String[] header, String[] rowDesc, String totalDesc) { String name, Instant date, String[] header, String[] rowDesc, String sumRowDesc) {
this.name = name; this.name = name;
this.date = date; this.date = date;
this.header = header; this.header = header;
this.rowDesc = rowDesc; this.rowDesc = rowDesc;
this.totalDesc = totalDesc; this.sumRowDesc = sumRowDesc;
} }
public String getTotalDesc() { public String getSumRowDesc() {
return totalDesc; return sumRowDesc;
} }
public String getName() { public String getName() {
@ -154,7 +154,7 @@ public class ReportRepresentationModel extends RepresentationModel<ReportReprese
+ ", rowDesc=" + ", rowDesc="
+ Arrays.toString(rowDesc) + Arrays.toString(rowDesc)
+ ", totalDesc=" + ", totalDesc="
+ totalDesc + sumRowDesc
+ "]"; + "]";
} }
} }

View File

@ -178,10 +178,9 @@ public class TaskCommentController {
* @throws NotAuthorizedException if the current user does not have access to the Task Comment * @throws NotAuthorizedException if the current user does not have access to the Task Comment
* @throws TaskNotFoundException if the referenced Task within the Task Comment does not exist * @throws TaskNotFoundException if the referenced Task within the Task Comment does not exist
* @throws TaskCommentNotFoundException if the requested Task Comment does not exist * @throws TaskCommentNotFoundException if the requested Task Comment does not exist
* @throws InvalidArgumentException if the id in the path and in the the request body does not * @throws InvalidArgumentException if the id in the path and in the request body does not match
* match * @throws ConcurrencyException if the requested Task Comment has been updated in the meantime by
* @throws ConcurrencyException if the requested Task Comment has been updated in the meantime * a different process.
* by a different process.
*/ */
@PutMapping(path = RestEndpoints.URL_TASK_COMMENT) @PutMapping(path = RestEndpoints.URL_TASK_COMMENT)
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
@ -223,7 +222,7 @@ public class TaskCommentController {
* *
* @title Create a new Task Comment * @title Create a new Task Comment
* @param taskId the id of the Task where a Task Comment should be created. * @param taskId the id of the Task where a Task Comment should be created.
* @param taskCommentRepresentationModel the body of the Task Comment * @param taskCommentRepresentationModel the Task Comment to create.
* @return the created Task Comment * @return the created Task Comment
* @throws NotAuthorizedException if the current user is not authorized to create a Task Comment * @throws NotAuthorizedException if the current user is not authorized to create a Task Comment
* @throws InvalidArgumentException if the Task Comment id is null or empty * @throws InvalidArgumentException if the Task Comment id is null or empty
@ -270,18 +269,7 @@ public class TaskCommentController {
if (sortBy != null) { if (sortBy != null) {
for (int i = 0; i < sortBy.size(); i++) { for (int i = 0; i < sortBy.size(); i++) {
SortDirection sortDirection = order == null ? SortDirection.ASCENDING : order.get(i); SortDirection sortDirection = order == null ? SortDirection.ASCENDING : order.get(i);
Comparator<TaskComment> temp; Comparator<TaskComment> temp = sortBy.get(i).getComparator();
switch (sortBy.get(i)) {
case CREATED:
temp = Comparator.comparing(TaskComment::getCreated);
break;
case MODIFIED:
temp = Comparator.comparing(TaskComment::getModified);
break;
default:
throw new InvalidArgumentException(
String.format("Unknown sort-by '%s'", sortBy.get(i)));
}
if (sortDirection == SortDirection.DESCENDING) { if (sortDirection == SortDirection.DESCENDING) {
temp = temp.reversed(); temp = temp.reversed();
} }
@ -292,7 +280,17 @@ public class TaskCommentController {
} }
enum TaskCommentsSortBy { enum TaskCommentsSortBy {
CREATED, CREATED(Comparator.comparing(TaskComment::getCreated)),
MODIFIED MODIFIED(Comparator.comparing(TaskComment::getModified));
private final Comparator<TaskComment> comparator;
TaskCommentsSortBy(Comparator<TaskComment> comparing) {
comparator = comparing;
}
public Comparator<TaskComment> getComparator() {
return comparator;
}
} }
} }

View File

@ -147,12 +147,11 @@ public class TaskController {
/** /**
* This endpoint retrieves a specific Task. * This endpoint retrieves a specific Task.
* *
* @title Get a single Task
* @param taskId the id of the requested Task * @param taskId the id of the requested Task
* @return the requested Task * @return the requested Task
* @throws TaskNotFoundException if the requested Task does not exist. * @throws TaskNotFoundException if the requested Task does not exist.
* @throws NotAuthorizedException if the current user is not authorized to get the requested * @throws NotAuthorizedException if the current user is not authorized to get the requested Task.
* Task. * @title Get a single Task
*/ */
@GetMapping(path = RestEndpoints.URL_TASKS_ID) @GetMapping(path = RestEndpoints.URL_TASKS_ID)
@Transactional(readOnly = true, rollbackFor = Exception.class) @Transactional(readOnly = true, rollbackFor = Exception.class)
@ -172,15 +171,15 @@ public class TaskController {
/** /**
* This endpoint claims a Task if possible. * This endpoint claims a Task if possible.
* *
* @title Claim a Task * @param taskId the id of the Task which should be claimed
* @param taskId the requested Task which should be claimed
* @param userName TODO: this is currently not used * @param userName TODO: this is currently not used
* @return the claimed Task * @return the claimed Task
* @throws TaskNotFoundException if the requested Task does not exist. * @throws TaskNotFoundException if the requested Task does not exist.
* @throws InvalidStateException then the state of the requested Task is not READY. * @throws InvalidStateException if the state of the requested Task is not READY.
* @throws InvalidOwnerException if the Task is already claimed by someone else. * @throws InvalidOwnerException if the Task is already claimed by someone else.
* @throws NotAuthorizedException if the current user has no read permissions for the requested * @throws NotAuthorizedException if the current user has no read permissions for the requested
* Task. * Task.
* @title Claim a Task
*/ */
@PostMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM) @PostMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -202,15 +201,15 @@ public class TaskController {
} }
/** /**
* Selects the first Task returned by the Task Query and claims it. * This endpoint selects the first Task returned by the Task Query and claims it.
* *
* @title Select and claim a Task
* @param filterParameter the filter parameters * @param filterParameter the filter parameters
* @param sortParameter the sort parameters * @param sortParameter the sort parameters
* @return the claimed Task * @return the claimed Task
* @throws InvalidOwnerException If the Task is already claimed by someone else * @throws InvalidOwnerException if the Task is already claimed by someone else
* @throws NotAuthorizedException if the current user has no read permission for the Workbasket * @throws NotAuthorizedException if the current user has no read permission for the Workbasket
* the Task is in * the Task is in
* @title Select and claim a Task
*/ */
@PostMapping(path = RestEndpoints.URL_TASKS_ID_SELECT_AND_CLAIM) @PostMapping(path = RestEndpoints.URL_TASKS_ID_SELECT_AND_CLAIM)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -236,16 +235,17 @@ public class TaskController {
} }
/** /**
* Cancel the claim of an existing Task if it was claimed by the current user before. * This endpoint cancels the claim of an existing Task if it was claimed by the current user
* before.
* *
* @title Cancel a claimed Task
* @param taskId the id of the requested Task. * @param taskId the id of the requested Task.
* @return the unclaimed Task. * @return the unclaimed Task.
* @throws TaskNotFoundException if the requested Task does not exist. * @throws TaskNotFoundException if the requested Task does not exist.
* @throws InvalidStateException if the Task is already in a final state. * @throws InvalidStateException if the Task is already in an end state.
* @throws InvalidOwnerException if the Task is claimed by a different user. * @throws InvalidOwnerException if the Task is claimed by a different user.
* @throws NotAuthorizedException if the current user has no read permission for the Workbasket * @throws NotAuthorizedException if the current user has no read permission for the Workbasket
* the Task is in * the Task is in
* @title Cancel a claimed Task
*/ */
@DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM) @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -268,14 +268,14 @@ public class TaskController {
/** /**
* This endpoint completes a Task. * This endpoint completes a Task.
* *
* @title Complete a Task * @param taskId id of the requested Task to complete.
* @param taskId the requested Task.
* @return the completed Task * @return the completed Task
* @throws TaskNotFoundException if the requested Task does not exist. * @throws TaskNotFoundException if the requested Task does not exist.
* @throws InvalidOwnerException if current user is not the owner of the Task or an administrator. * @throws InvalidOwnerException if current user is not the owner of the Task or an administrator.
* @throws InvalidStateException if Task wasn't claimed before. * @throws InvalidStateException if Task wasn't claimed previously.
* @throws NotAuthorizedException if the current user has no read permission for the Workbasket * @throws NotAuthorizedException if the current user has no read permission for the Workbasket
* the Task is in * the Task is in
* @title Complete a Task
*/ */
@PostMapping(path = RestEndpoints.URL_TASKS_ID_COMPLETE) @PostMapping(path = RestEndpoints.URL_TASKS_ID_COMPLETE)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -319,15 +319,15 @@ public class TaskController {
/** /**
* This endpoint creates a persistent Task. * This endpoint creates a persistent Task.
* *
* @title Create a new Task
* @param taskRepresentationModel the Task which should be created. * @param taskRepresentationModel the Task which should be created.
* @return the created Task * @return the created Task
* @throws WorkbasketNotFoundException if the referenced Workbasket does not exist * @throws WorkbasketNotFoundException if the referenced Workbasket does not exist
* @throws ClassificationNotFoundException if the referenced Classification does not exist * @throws ClassificationNotFoundException if the referenced Classification does not exist
* @throws NotAuthorizedException if the current user is not authorized to append a Task in the * @throws NotAuthorizedException if the current user is not authorized to append a Task to the
* referenced Workbasket * referenced Workbasket
* @throws TaskAlreadyExistException if the requested Task already exists. * @throws TaskAlreadyExistException if the requested Task already exists.
* @throws InvalidArgumentException if any input is semantically wrong. * @throws InvalidArgumentException if any input is semantically wrong.
* @title Create a new Task
*/ */
@PostMapping(path = RestEndpoints.URL_TASKS) @PostMapping(path = RestEndpoints.URL_TASKS)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -384,9 +384,8 @@ public class TaskController {
/** /**
* This endpoint updates a requested Task. * This endpoint updates a requested Task.
* *
* @title Update a Task
* @param taskId the id of the Task which should be updated * @param taskId the id of the Task which should be updated
* @param taskRepresentationModel the new Task * @param taskRepresentationModel the new Task for the requested id.
* @return the updated Task * @return the updated Task
* @throws TaskNotFoundException if the requested Task does not exist. * @throws TaskNotFoundException if the requested Task does not exist.
* @throws ClassificationNotFoundException if the updated Classification does not exist. * @throws ClassificationNotFoundException if the updated Classification does not exist.
@ -394,9 +393,11 @@ public class TaskController {
* @throws ConcurrencyException if the Task has been updated by a different process in the * @throws ConcurrencyException if the Task has been updated by a different process in the
* meantime * meantime
* @throws NotAuthorizedException if the current user is not authorized. * @throws NotAuthorizedException if the current user is not authorized.
* @throws AttachmentPersistenceException if the Task contains two attachments with the same id. * @throws AttachmentPersistenceException if the modified Task contains two attachments with the
* same id.
* @throws InvalidStateException if an attempt is made to change the owner of the Task and the * @throws InvalidStateException if an attempt is made to change the owner of the Task and the
* Task is not in state READY. * Task is not in state READY.
* @title Update a Task
*/ */
@PutMapping(path = RestEndpoints.URL_TASKS_ID) @PutMapping(path = RestEndpoints.URL_TASKS_ID)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)

View File

@ -24,60 +24,54 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
/** Filter by the name of the task. This is an exact match. */ /** Filter by the name of the task. This is an exact match. */
private final String[] name; private final String[] name;
/** /**
* Filter by the name of the task. This results into a substring search. (% is appended to the * Filter by the name of the task. This results in a substring search.. (% is appended to the
* front and end of the requested value). Further SQL "Like" wildcard characters will be resolved * front and end of the requested value). Further SQL "Like" wildcard characters will be resolved
* correctly. * correctly.
*/ */
@JsonProperty("name-like") @JsonProperty("name-like")
private final String[] nameLike; private final String[] nameLike;
/** Filter by the priority of the task. */ /** Filter by the priority of the task. This is an exact match. */
private final int[] priority; private final int[] priority;
/** Filter by the task state. This is an exact match. */
/** Filter by the task state. */
private final TaskState[] state; private final TaskState[] state;
/** Filter by the classification key. */ /** Filter by the classification key. This is an exact match. */
@JsonProperty("classification.key") @JsonProperty("classification.key")
private final String[] classificationKeys; private final String[] classificationKeys;
/** Filter by task id. */ /** Filter by task id. This is an exact match. */
@JsonProperty("task-id") @JsonProperty("task-id")
private final String[] taskIds; private final String[] taskIds;
/** Filter by workbasket id. */ /** Filter by workbasket id. This is an exact match. */
@JsonProperty("workbasket-id") @JsonProperty("workbasket-id")
private final String[] workbasketIds; private final String[] workbasketIds;
/** Filter by workbasket keys. This parameter can only be used in combination with 'domain' */ /** Filter by workbasket keys. This parameter can only be used in combination with 'domain' */
@JsonProperty("workbasket-key") @JsonProperty("workbasket-key")
private final String[] workbasketKeys; private final String[] workbasketKeys;
/** Filter by domain. This is an exact match. */
/** Filter by domain. */
private final String domain; private final String domain;
/** Filter by owner. */ /** Filter by owner. This is an exact match. */
private final String[] owner; private final String[] owner;
/** /**
* Filter by the owner of the task. This results into a substring search. (% is appended to the * Filter by the owner of the task. This results in a substring search.. (% is appended to the
* front and end of the requested value). Further SQL "Like" wildcard characters will be resolved * front and end of the requested value). Further SQL "Like" wildcard characters will be resolved
* correctly. * correctly.
*/ */
@JsonProperty("owner-like") @JsonProperty("owner-like")
private final String[] ownerLike; private final String[] ownerLike;
/** Filter by the company of the primary object reference. */ /** Filter by the company of the primary object reference. This is an exact match. */
@JsonProperty("por.company") @JsonProperty("por.company")
private final String[] porCompany; private final String[] porCompany;
/** Filter by the system of the primary object reference. This is an exact match. */
/** Filter by the system of the primary object reference. */
@JsonProperty("por.system") @JsonProperty("por.system")
private final String[] porSystem; private final String[] porSystem;
/** Filter by the system instance of the primary object reference. */ /** Filter by the system instance of the primary object reference. This is an exact match. */
@JsonProperty("por.instance") @JsonProperty("por.instance")
private final String[] porInstance; private final String[] porInstance;
/** Filter by the type of the primary object reference. This is an exact match. */
/** Filter by the type of the primary object reference. */
@JsonProperty("por.type") @JsonProperty("por.type")
private final String[] porType; private final String[] porType;
/** Filter by the value of the primary object reference. This is an exact match. */
/** Filter by the value of the primary object reference. */
@JsonProperty("por.value") @JsonProperty("por.value")
private final String[] porValue; private final String[] porValue;
/** /**
* Filter by a planned time interval. The length of the provided values has to be even. To create * Filter by a planned time interval. The length of the provided values has to be even. To create
* an open interval you can either use 'null' or just leave it blank. * an open interval you can either use 'null' or just leave it blank.
@ -146,14 +140,14 @@ public class TaskQueryFilterParameter implements QueryParameter<TaskQuery, Void>
private final WildcardSearchField[] wildcardSearchFields; private final WildcardSearchField[] wildcardSearchFields;
/** /**
* Filter by wildcard search field. * Filter by wildcard search field. This is an exact match.
* *
* <p>This must be used in combination with 'wildcard-search-value' * <p>This must be used in combination with 'wildcard-search-value'
*/ */
@JsonProperty("wildcard-search-value") @JsonProperty("wildcard-search-value")
private final String wildcardSearchValue; private final String wildcardSearchValue;
/** Filter by the external id. */ /** Filter by the external id. This is an exact match. */
@JsonProperty("external-id") @JsonProperty("external-id")
private final String[] externalIds; private final String[] externalIds;

View File

@ -8,7 +8,7 @@ import pro.taskana.task.api.models.Attachment;
/** EntityModel class for {@link Attachment}. */ /** EntityModel class for {@link Attachment}. */
public class AttachmentRepresentationModel extends AttachmentSummaryRepresentationModel { public class AttachmentRepresentationModel extends AttachmentSummaryRepresentationModel {
/** All additional information on the task. */ /** All additional information of the Attachment. */
private Map<String, String> customAttributes = new HashMap<>(); private Map<String, String> customAttributes = new HashMap<>();
public Map<String, String> getCustomAttributes() { public Map<String, String> getCustomAttributes() {

View File

@ -7,13 +7,13 @@ public class ObjectReferenceRepresentationModel
/** Unique ID. */ /** Unique ID. */
private String id; private String id;
/** The company referenced primary object belongs to. */ /** The company the referenced primary object belongs to. */
private String company; private String company;
/** The (kind of) system, the object resides in (e.g. SAP, MySystem A, ...). */ /** The (kind of) system, the referenced primary object resides in (e.g. SAP, MySystem A, ...). */
private String system; private String system;
/** The instance of the system, the object resides in. */ /** The instance of the system, the referenced primary object resides in. */
private String systemInstance; private String systemInstance;
/** The type of the reference (contract, claim, policy, customer, ...). */ /** The type of the referenced primary object (contract, claim, policy, customer, ...). */
private String type; private String type;
/** The value of the primary object reference. */ /** The value of the primary object reference. */
private String value; private String value;

View File

@ -13,7 +13,7 @@ import pro.taskana.task.api.models.Task;
public class TaskRepresentationModel extends TaskSummaryRepresentationModel { public class TaskRepresentationModel extends TaskSummaryRepresentationModel {
// All objects have to be serializable // All objects have to be serializable
/** Additional information on the task. */ /** Additional information of the task. */
private List<CustomAttribute> customAttributes = Collections.emptyList(); private List<CustomAttribute> customAttributes = Collections.emptyList();
/** Callback Information of the task. */ /** Callback Information of the task. */

View File

@ -59,7 +59,7 @@ public class TaskSummaryRepresentationModel
protected String businessProcessId; protected String businessProcessId;
/** the parent business process id. */ /** the parent business process id. */
protected String parentBusinessProcessId; protected String parentBusinessProcessId;
/** The owner of the tasks. The owner is set upon claiming of the task. */ /** The owner of the task. The owner is set upon claiming of the task. */
protected String owner; protected String owner;
/** The Objects primary ObjectReference. */ /** The Objects primary ObjectReference. */
@NotNull protected ObjectReferenceRepresentationModel primaryObjRef; @NotNull protected ObjectReferenceRepresentationModel primaryObjRef;

View File

@ -88,7 +88,7 @@ public class WorkbasketAccessItemController {
* This endpoint deletes all Workbasket Access Items for a provided Access Id. * This endpoint deletes all Workbasket Access Items for a provided Access Id.
* *
* @title Delete a Workbasket Access Item * @title Delete a Workbasket Access Item
* @param accessId the Access Id which should be removed * @param accessId the Access Id whose Workbasket Access Items should be removed
* @return no content * @return no content
* @throws NotAuthorizedException if the user is not authorized. * @throws NotAuthorizedException if the user is not authorized.
* @throws InvalidArgumentException if some argument is invalid. * @throws InvalidArgumentException if some argument is invalid.

View File

@ -15,8 +15,8 @@ public class WorkbasketAccessItemQueryFilterParameter
private final String[] workbasketKey; private final String[] workbasketKey;
/** /**
* Filter by the key of the workbasket. This results into a substring search. (% is appended to * Filter by the key of the workbasket. This results in a substring search.. (% is appended to the
* the front and end of the requested value). Further SQL "Like" wildcard characters will be * beginning and end of the requested value). Further SQL "Like" wildcard characters will be
* resolved correctly. * resolved correctly.
*/ */
@JsonProperty("workbasket-key-like") @JsonProperty("workbasket-key-like")
@ -27,8 +27,8 @@ public class WorkbasketAccessItemQueryFilterParameter
private final String[] accessId; private final String[] accessId;
/** /**
* Filter by the name of the access id. This results into a substring search. (% is appended to * Filter by the name of the access id. This results in a substring search.. (% is appended to the
* the front and end of the requested value). Further SQL "Like" wildcard characters will be * beginning and end of the requested value). Further SQL "Like" wildcard characters will be
* resolved correctly. * resolved correctly.
*/ */
@JsonProperty("access-id-like") @JsonProperty("access-id-like")

View File

@ -153,8 +153,7 @@ public class WorkbasketController {
* @title Delete a Workbasket * @title Delete a Workbasket
* @param workbasketId the id of the Workbasket which should be deleted * @param workbasketId the id of the Workbasket which should be deleted
* @return the deleted Workbasket * @return the deleted Workbasket
* @throws NotAuthorizedException if the current user is not authorized to delete this * @throws NotAuthorizedException if the current user is not authorized to delete this Workbasket.
* Workbasket.
* @throws InvalidArgumentException if the requested Workbasket id is null or empty * @throws InvalidArgumentException if the requested Workbasket id is null or empty
* @throws WorkbasketNotFoundException if the requested Workbasket is not found * @throws WorkbasketNotFoundException if the requested Workbasket is not found
* @throws WorkbasketInUseException if the Workbasket contains tasks. * @throws WorkbasketInUseException if the Workbasket contains tasks.
@ -224,10 +223,10 @@ public class WorkbasketController {
* *
* @title Update a Workbasket * @title Update a Workbasket
* @param workbasketId the id of the Workbasket which should be updated. * @param workbasketId the id of the Workbasket which should be updated.
* @param workbasketRepresentationModel the new Workbasket. * @param workbasketRepresentationModel the new Workbasket for the requested id.
* @return the updated Workbasket * @return the updated Workbasket
* @throws InvalidWorkbasketException if the requested id and the id within the new Workbasket * @throws InvalidWorkbasketException if the requested id and the id within the new Workbasket do
* do not match. * not match.
* @throws WorkbasketNotFoundException if the requested workbasket does not * @throws WorkbasketNotFoundException if the requested workbasket does not
* @throws NotAuthorizedException if the current user is not authorized to update the Workbasket * @throws NotAuthorizedException if the current user is not authorized to update the Workbasket
* @throws ConcurrencyException if an attempt is made to update the Workbasket and another user * @throws ConcurrencyException if an attempt is made to update the Workbasket and another user
@ -270,7 +269,7 @@ public class WorkbasketController {
* @return the access items for the requested workbasket. * @return the access items for the requested workbasket.
* @throws NotAuthorizedException if the current user is not member of role BUSINESS_ADMIN or * @throws NotAuthorizedException if the current user is not member of role BUSINESS_ADMIN or
* ADMIN * ADMIN
* @throws WorkbasketNotFoundException the requested Workbasket does not exist. * @throws WorkbasketNotFoundException if the requested Workbasket does not exist.
*/ */
@GetMapping( @GetMapping(
path = RestEndpoints.URL_WORKBASKET_ID_ACCESS_ITEMS, path = RestEndpoints.URL_WORKBASKET_ID_ACCESS_ITEMS,
@ -300,29 +299,29 @@ public class WorkbasketController {
* *
* @title Set all Workbasket Access Items * @title Set all Workbasket Access Items
* @param workbasketId the id of the Workbasket whose Workbasket Access Items will be replaced * @param workbasketId the id of the Workbasket whose Workbasket Access Items will be replaced
* @param workbasketAccessResourceItems the new Workbasket Access Items. * @param workbasketAccessItemRepModels the new Workbasket Access Items.
* @return the new Workbasket Access Items for the requested Workbasket * @return the new Workbasket Access Items for the requested Workbasket
* @throws NotAuthorizedException if the current user is not member of role BUSINESS_ADMIN or * @throws NotAuthorizedException if the current user is not member of role BUSINESS_ADMIN or
* ADMIN * ADMIN
* @throws InvalidArgumentException if the new Workbasket Access Items are not provided. * @throws InvalidArgumentException if the new Workbasket Access Items are not provided.
* @throws WorkbasketNotFoundException TODO: this is never thrown. * @throws WorkbasketNotFoundException TODO: this is never thrown.
* @throws WorkbasketAccessItemAlreadyExistException if a duplicate Workbasket Access Item * @throws WorkbasketAccessItemAlreadyExistException if a duplicate Workbasket Access Item exists
* exists in the provided list. * in the provided list.
*/ */
@PutMapping(path = RestEndpoints.URL_WORKBASKET_ID_ACCESS_ITEMS) @PutMapping(path = RestEndpoints.URL_WORKBASKET_ID_ACCESS_ITEMS)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<WorkbasketAccessItemCollectionRepresentationModel> setWorkbasketAccessItems( public ResponseEntity<WorkbasketAccessItemCollectionRepresentationModel> setWorkbasketAccessItems(
@PathVariable(value = "workbasketId") String workbasketId, @PathVariable(value = "workbasketId") String workbasketId,
@RequestBody WorkbasketAccessItemCollectionRepresentationModel workbasketAccessResourceItems) @RequestBody WorkbasketAccessItemCollectionRepresentationModel workbasketAccessItemRepModels)
throws NotAuthorizedException, InvalidArgumentException, WorkbasketNotFoundException, throws NotAuthorizedException, InvalidArgumentException, WorkbasketNotFoundException,
WorkbasketAccessItemAlreadyExistException { WorkbasketAccessItemAlreadyExistException {
LOGGER.debug("Entry to setWorkbasketAccessItems(workbasketId= {})", workbasketId); LOGGER.debug("Entry to setWorkbasketAccessItems(workbasketId= {})", workbasketId);
if (workbasketAccessResourceItems == null) { if (workbasketAccessItemRepModels == null) {
throw new InvalidArgumentException("Can´t create something with NULL body-value."); throw new InvalidArgumentException("Can´t create something with NULL body-value.");
} }
List<WorkbasketAccessItem> wbAccessItems = new ArrayList<>(); List<WorkbasketAccessItem> wbAccessItems = new ArrayList<>();
workbasketAccessResourceItems workbasketAccessItemRepModels
.getContent() .getContent()
.forEach( .forEach(
item -> item ->
@ -364,10 +363,10 @@ public class WorkbasketController {
LOGGER.debug("Entry to getDistributionTargets(workbasketId= {})", workbasketId); LOGGER.debug("Entry to getDistributionTargets(workbasketId= {})", workbasketId);
List<WorkbasketSummary> distributionTargets = List<WorkbasketSummary> distributionTargets =
workbasketService.getDistributionTargets(workbasketId); workbasketService.getDistributionTargets(workbasketId);
DistributionTargetsCollectionRepresentationModel distributionTargetListResource = DistributionTargetsCollectionRepresentationModel distributionTargetRepModels =
workbasketSummaryRepresentationModelAssembler.toTaskanaCollectionModel(distributionTargets); workbasketSummaryRepresentationModelAssembler.toTaskanaCollectionModel(distributionTargets);
ResponseEntity<DistributionTargetsCollectionRepresentationModel> result = ResponseEntity<DistributionTargetsCollectionRepresentationModel> result =
ResponseEntity.ok(distributionTargetListResource); ResponseEntity.ok(distributionTargetRepModels);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exit from getDistributionTargets(), returning {}", result); LOGGER.debug("Exit from getDistributionTargets(), returning {}", result);
} }
@ -383,7 +382,7 @@ public class WorkbasketController {
* @param targetWorkbasketIds the destination Workbaskets. * @param targetWorkbasketIds the destination Workbaskets.
* @return the new Distribution Targets for the requested Workbasket. * @return the new Distribution Targets for the requested Workbasket.
* @throws WorkbasketNotFoundException if any Workbasket was not found (either source or target) * @throws WorkbasketNotFoundException if any Workbasket was not found (either source or target)
* @throws NotAuthorizedException if the current used doesn't have READ permission for the source * @throws NotAuthorizedException if the current user doesn't have READ permission for the source
* Workbasket * Workbasket
*/ */
@PutMapping(path = RestEndpoints.URL_WORKBASKET_ID_DISTRIBUTION) @PutMapping(path = RestEndpoints.URL_WORKBASKET_ID_DISTRIBUTION)

View File

@ -15,8 +15,8 @@ public class WorkbasketQueryFilterParameter implements QueryParameter<Workbasket
private final String[] name; private final String[] name;
/** /**
* Filter by the name of the workbasket. This results into a substring search. (% is appended to * Filter by the name of the workbasket. This results in a substring search. (% is appended to the
* the front and end of the requested value). Further SQL "Like" wildcard characters will be * beginning and end of the requested value). Further SQL "Like" wildcard characters will be
* resolved correctly. * resolved correctly.
*/ */
@JsonProperty("name-like") @JsonProperty("name-like")
@ -26,8 +26,8 @@ public class WorkbasketQueryFilterParameter implements QueryParameter<Workbasket
private final String[] key; private final String[] key;
/** /**
* Filter by the key of the workbasket. This results into a substring search. (% is appended to * Filter by the key of the workbasket. This results in a substring search.. (% is appended to the
* the front and end of the requested value). Further SQL "Like" wildcard characters will be * beginning and end of the requested value). Further SQL "Like" wildcard characters will be
* resolved correctly. * resolved correctly.
*/ */
@JsonProperty("key-like") @JsonProperty("key-like")
@ -37,22 +37,22 @@ public class WorkbasketQueryFilterParameter implements QueryParameter<Workbasket
private final String[] owner; private final String[] owner;
/** /**
* Filter by the owner of the workbasket. This results into a substring search. (% is appended to * Filter by the owner of the workbasket. This results in a substring search.. (% is appended to
* the front and end of the requested value). Further SQL "Like" wildcard characters will be * the beginning and end of the requested value). Further SQL "Like" wildcard characters will be
* resolved correctly. * resolved correctly.
*/ */
@JsonProperty("owner-like") @JsonProperty("owner-like")
private final String[] ownerLike; private final String[] ownerLike;
/** /**
* Filter by the description of the workbasket. This results into a substring search. (% is * Filter by the description of the workbasket. This results in a substring search.. (% is
* appended to the front and end of the requested value). Further SQL "Like" wildcard characters * appended to the beginning and end of the requested value). Further SQL "Like" wildcard
* will be resolved correctly. * characters will be resolved correctly.
*/ */
@JsonProperty("description-like") @JsonProperty("description-like")
private final String[] descriptionLike; private final String[] descriptionLike;
/** Filter by the name of the workbasket. This is an exact match. */ /** Filter by the domain of the workbasket. This is an exact match. */
private final String[] domain; private final String[] domain;
/** Filter by the type of the workbasket. This is an exact match. */ /** Filter by the type of the workbasket. This is an exact match. */

View File

@ -8,7 +8,7 @@ import pro.taskana.workbasket.api.models.Workbasket;
public class WorkbasketRepresentationModel extends WorkbasketSummaryRepresentationModel { public class WorkbasketRepresentationModel extends WorkbasketSummaryRepresentationModel {
/** /**
* The creation timestamp of the classification in the system. * The creation timestamp of the workbasket in the system.
* *
* <p>The format is ISO-8601. * <p>The format is ISO-8601.
*/ */

View File

@ -1,28 +1,21 @@
package pro.taskana.classification.rest; package pro.taskana.classification.rest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import java.util.List;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.models.Classification; import pro.taskana.classification.api.models.Classification;
import pro.taskana.classification.api.models.ClassificationSummary;
import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler; import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler;
import pro.taskana.classification.rest.models.ClassificationRepresentationModel; import pro.taskana.classification.rest.models.ClassificationRepresentationModel;
import pro.taskana.common.rest.RestEndpoints; import pro.taskana.common.rest.RestEndpoints;
import pro.taskana.common.test.BaseRestDocumentationTest; import pro.taskana.common.test.BaseRestDocumentationTest;
@TestMethodOrder(OrderAnnotation.class)
class ClassificationControllerRestDocumentationTest extends BaseRestDocumentationTest { class ClassificationControllerRestDocumentationTest extends BaseRestDocumentationTest {
@Autowired ClassificationRepresentationModelAssembler assembler; @Autowired ClassificationRepresentationModelAssembler assembler;
@ -44,10 +37,10 @@ class ClassificationControllerRestDocumentationTest extends BaseRestDocumentatio
} }
@Test @Test
@Order(1)
void createClassificationDocTest() throws Exception { void createClassificationDocTest() throws Exception {
Classification classification = Classification classification =
classificationService.newClassification("Key0815casdgdgh", "DOMAIN_B", "TASK"); classificationService.newClassification("Key0815casdgdgh", "DOMAIN_B", "TASK");
classification.setServiceLevel("P1D");
ClassificationRepresentationModel repModel = assembler.toModel(classification); ClassificationRepresentationModel repModel = assembler.toModel(classification);
mockMvc mockMvc
.perform( .perform(
@ -56,25 +49,12 @@ class ClassificationControllerRestDocumentationTest extends BaseRestDocumentatio
.andExpect(MockMvcResultMatchers.status().isCreated()); .andExpect(MockMvcResultMatchers.status().isCreated());
} }
/**
* this test only works with the {@link
* ClassificationControllerRestDocumentationTest#createClassificationDocTest()} test.
*
* @throws Exception if any exception is thrown.
*/
@Test @Test
@Order(2)
void deleteClassificationDocTest() throws Exception { void deleteClassificationDocTest() throws Exception {
List<ClassificationSummary> list =
classificationService
.createClassificationQuery()
.keyIn("Key0815casdgdgh")
.domainIn("DOMAIN_B")
.typeIn("TASK")
.list();
assertThat(list).hasSize(1);
mockMvc mockMvc
.perform(delete(RestEndpoints.URL_CLASSIFICATIONS_ID, list.get(0).getId())) .perform(
delete(
RestEndpoints.URL_CLASSIFICATIONS_ID, "CLI:100000000000000000000000000000000010"))
.andExpect(MockMvcResultMatchers.status().isNoContent()); .andExpect(MockMvcResultMatchers.status().isNoContent());
} }

View File

@ -15,8 +15,7 @@ import pro.taskana.classification.rest.models.ClassificationCollectionRepresenta
import pro.taskana.common.rest.RestEndpoints; import pro.taskana.common.rest.RestEndpoints;
import pro.taskana.common.test.BaseRestDocumentationTest; import pro.taskana.common.test.BaseRestDocumentationTest;
class ClassificationDefinitionControllerRestDocumentationTest class ClassificationDefinitionControllerRestDocumentationTest extends BaseRestDocumentationTest {
extends BaseRestDocumentationTest {
@Autowired ClassificationRepresentationModelAssembler assembler; @Autowired ClassificationRepresentationModelAssembler assembler;
@Autowired ClassificationService classificationService; @Autowired ClassificationService classificationService;
@ -32,6 +31,7 @@ class ClassificationDefinitionControllerRestDocumentationTest
void importClassificationDefinitionsDocTest() throws Exception { void importClassificationDefinitionsDocTest() throws Exception {
Classification classification = Classification classification =
classificationService.newClassification("Key0815", "DOMAIN_B", "TASK"); classificationService.newClassification("Key0815", "DOMAIN_B", "TASK");
classification.setServiceLevel("P1D");
ClassificationCollectionRepresentationModel importCollection = ClassificationCollectionRepresentationModel importCollection =
assembler.toTaskanaCollectionModel(List.of(classification)); assembler.toTaskanaCollectionModel(List.of(classification));

View File

@ -18,8 +18,8 @@ public class AccessIdControllerRestDocumentationTest extends BaseRestDocumentati
@Test @Test
void getGroupsForAccessIdDocTest() throws Exception { void getGroupsForAccessIdDocTest() throws Exception {
mockMvc.perform(get(RestEndpoints.URL_ACCESS_ID_GROUPS + "?access-id=teamlead-1")) mockMvc
.perform(get(RestEndpoints.URL_ACCESS_ID_GROUPS + "?access-id=teamlead-1"))
.andExpect(MockMvcResultMatchers.status().isOk()); .andExpect(MockMvcResultMatchers.status().isOk());
} }
} }

View File

@ -19,8 +19,8 @@ class QuerySortParameterTest {
MockQuery query = mock(MockQuery.class); MockQuery query = mock(MockQuery.class);
MockSortBy sortBy = mock(MockSortBy.class); MockSortBy sortBy = mock(MockSortBy.class);
QuerySortParameter<MockQuery, MockSortBy> sortByParameter = new QuerySortParameter<>( QuerySortParameter<MockQuery, MockSortBy> sortByParameter =
List.of(sortBy), List.of(SortDirection.ASCENDING)); new QuerySortParameter<>(List.of(sortBy), List.of(SortDirection.ASCENDING));
sortByParameter.applyToQuery(query); sortByParameter.applyToQuery(query);
@ -73,8 +73,8 @@ class QuerySortParameterTest {
MockSortBy sortBy2 = mock(MockSortBy.class); MockSortBy sortBy2 = mock(MockSortBy.class);
QuerySortParameter<MockQuery, MockSortBy> sortByParameter = QuerySortParameter<MockQuery, MockSortBy> sortByParameter =
new QuerySortParameter<>(List.of(sortBy1, sortBy2), new QuerySortParameter<>(
List.of(SortDirection.ASCENDING, SortDirection.ASCENDING)); List.of(sortBy1, sortBy2), List.of(SortDirection.ASCENDING, SortDirection.ASCENDING));
sortByParameter.applyToQuery(query); sortByParameter.applyToQuery(query);
@ -102,11 +102,7 @@ class QuerySortParameterTest {
private enum MockColumnNames implements QueryColumnName {} private enum MockColumnNames implements QueryColumnName {}
private abstract static class MockSortBy implements QuerySortBy<MockQuery> { private abstract static class MockSortBy implements QuerySortBy<MockQuery> {}
} private abstract static class MockQuery implements BaseQuery<Void, MockColumnNames> {}
private abstract static class MockQuery implements BaseQuery<Void, MockColumnNames> {
}
} }

View File

@ -19,7 +19,7 @@ import pro.taskana.sampledata.SampleDataGenerator;
/** Test that the schema name can be customized. */ /** Test that the schema name can be customized. */
@TaskanaSpringBootTest @TaskanaSpringBootTest
class TestSchemaNameCustomizable { class SchemaNameCustomizableTest {
String schemaName = "CUSTOMSCHEMANAME"; String schemaName = "CUSTOMSCHEMANAME";
boolean isPostgres = false; boolean isPostgres = false;

View File

@ -48,4 +48,11 @@ class TaskanaEngineControllerRestDocumentationTest extends BaseRestDocumentation
.perform(get(RestEndpoints.URL_HISTORY_ENABLED)) .perform(get(RestEndpoints.URL_HISTORY_ENABLED))
.andExpect(MockMvcResultMatchers.status().isOk()); .andExpect(MockMvcResultMatchers.status().isOk());
} }
@Test
void getCurrentVersionDocTest() throws Exception {
mockMvc
.perform(get(RestEndpoints.URL_VERSION))
.andExpect(MockMvcResultMatchers.status().isOk());
}
} }

View File

@ -10,7 +10,6 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter; import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
@EnableWebSecurity @EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

View File

@ -62,7 +62,7 @@ class ReportRepresentationModelTest {
assertThat(meta.getRowDesc()).isEqualTo(new String[] {"WORKBASKET"}); assertThat(meta.getRowDesc()).isEqualTo(new String[] {"WORKBASKET"});
assertThat(meta.getHeader()) assertThat(meta.getHeader())
.isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray()); .isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray());
assertThat(meta.getTotalDesc()).isEqualTo("Total"); assertThat(meta.getSumRowDesc()).isEqualTo("Total");
// rows // rows
assertThat(resource.getRows()).isEmpty(); assertThat(resource.getRows()).isEmpty();
@ -98,7 +98,7 @@ class ReportRepresentationModelTest {
assertThat(meta.getRowDesc()).isEqualTo(new String[] {"CLASSIFICATION"}); assertThat(meta.getRowDesc()).isEqualTo(new String[] {"CLASSIFICATION"});
assertThat(meta.getHeader()) assertThat(meta.getHeader())
.isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray()); .isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray());
assertThat(meta.getTotalDesc()).isEqualTo("Total"); assertThat(meta.getSumRowDesc()).isEqualTo("Total");
// rows // rows
List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows(); List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows();
@ -144,7 +144,7 @@ class ReportRepresentationModelTest {
assertThat(meta.getRowDesc()).isEqualTo(new String[] {"CLASSIFICATION"}); assertThat(meta.getRowDesc()).isEqualTo(new String[] {"CLASSIFICATION"});
assertThat(meta.getHeader()) assertThat(meta.getHeader())
.isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray()); .isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray());
assertThat(meta.getTotalDesc()).isEqualTo("Total"); assertThat(meta.getSumRowDesc()).isEqualTo("Total");
// rows // rows
List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows(); List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows();
@ -199,7 +199,7 @@ class ReportRepresentationModelTest {
assertThat(meta.getRowDesc()).isEqualTo(new String[] {"TASK CLASSIFICATION", "ATTACHMENT"}); assertThat(meta.getRowDesc()).isEqualTo(new String[] {"TASK CLASSIFICATION", "ATTACHMENT"});
assertThat(meta.getHeader()) assertThat(meta.getHeader())
.isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray()); .isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray());
assertThat(meta.getTotalDesc()).isEqualTo("Total"); assertThat(meta.getSumRowDesc()).isEqualTo("Total");
// rows // rows
List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows(); List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows();
@ -279,7 +279,7 @@ class ReportRepresentationModelTest {
assertThat(meta.getRowDesc()).isEqualTo(new String[] {"TASK CLASSIFICATION", "ATTACHMENT"}); assertThat(meta.getRowDesc()).isEqualTo(new String[] {"TASK CLASSIFICATION", "ATTACHMENT"});
assertThat(meta.getHeader()) assertThat(meta.getHeader())
.isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray()); .isEqualTo(headers.stream().map(TimeIntervalColumnHeader::getDisplayName).toArray());
assertThat(meta.getTotalDesc()).isEqualTo("Total"); assertThat(meta.getSumRowDesc()).isEqualTo("Total");
// rows // rows
List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows(); List<ReportRepresentationModel.RowRepresentationModel> rows = resource.getRows();