diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java index 5c973e3f0..ae908e0c9 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java @@ -249,7 +249,9 @@ public interface TaskService { * cannot be found * @throws NotAuthorizedException if the current user is not authorized to update the task * @throws AttachmentPersistenceException if an Attachment with ID will be added multiple times - * without using the task-methods. + * without using the task-methods + * @throws InvalidStateException if an attempt is made to change the owner of the task and the + * task is not in state READY . */ Task updateTask(Task task) throws InvalidArgumentException, TaskNotFoundException, ConcurrencyException, @@ -373,4 +375,14 @@ public interface TaskService { */ BulkOperationResults setCallbackStateForTasks( List externalIds, CallbackState state); + + /** + * Sets the owner on a list of tasks. The owner will only be set on tasks that are in state READY. + * + * @param owner the new owner of the tasks + * @param taskIds the IDs of the tasks on which the owner is to be set. + * @return the result of the operations with Id and Exception for each failed task deletion. + */ + BulkOperationResults setOwnerOfTasks( + String owner, List taskIds); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/exceptions/UpdateFailedException.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/exceptions/UpdateFailedException.java new file mode 100644 index 000000000..e1203c20d --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/exceptions/UpdateFailedException.java @@ -0,0 +1,13 @@ +package pro.taskana.task.api.exceptions; + +import pro.taskana.common.api.exceptions.TaskanaException; + +/** This exception will be thrown if a specific task is not in the database. */ +public class UpdateFailedException extends TaskanaException { + + private static final long serialVersionUID = 1L; + + public UpdateFailedException(String msg) { + super(msg); + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java index 1fd841022..b09828314 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java @@ -1,5 +1,6 @@ package pro.taskana.task.internal; +import java.time.Instant; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Delete; @@ -132,6 +133,16 @@ public interface TaskMapper { void setCallbackStateMultiple( @Param("externalIds") List externalIds, @Param("state") CallbackState state); + @Update( + "") + int setOwnerOfTasks( + @Param("owner") String owner, + @Param("taskIds") List taskIds, + @Param("modified") Instant modified); + @Select( "") @Results(value = {@Result(property = "taskId", column = "ID")}) List filterTaskIdsForNotCompleted(@Param("taskIds") List taskIds); + + @Select( + "") + @Results(value = {@Result(property = "id", column = "ID")}) + List filterTaskIdsNotAuthorizedFor( + @Param("taskIds") List taskIds, @Param("accessIds") List accessIds); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java index f404469b5..666e38dd7 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java @@ -16,6 +16,7 @@ import org.apache.ibatis.exceptions.PersistenceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import pro.taskana.TaskanaEngineConfiguration; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; import pro.taskana.classification.api.models.Classification; @@ -48,6 +49,7 @@ import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskNotFoundException; +import pro.taskana.task.api.exceptions.UpdateFailedException; import pro.taskana.task.api.models.Attachment; import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; @@ -617,6 +619,55 @@ public class TaskServiceImpl implements TaskService { } } + @Override + public BulkOperationResults setOwnerOfTasks( + String owner, List argTaskIds) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "entry to setOwnerOfTasks(owner = {}, tasks = {})", + owner, + LoggerUtils.listToString(argTaskIds)); + } + try { + taskanaEngine.openConnection(); + BulkOperationResults bulkLog = new BulkOperationResults<>(); + if (argTaskIds == null || argTaskIds.isEmpty()) { + return bulkLog; + } + // remove duplicates + List taskIds = argTaskIds.stream().sorted().distinct().collect(Collectors.toList()); + final int requestSize = taskIds.size(); + // use only elements we are authorized for + taskIds = filterForAuthorized(taskIds, bulkLog); + // set the Owner of these tasks we are authorized for + if (taskIds.isEmpty()) { + return bulkLog; + } else { + final int numberOfAffectedTasks = taskMapper.setOwnerOfTasks(owner, taskIds, Instant.now()); + // check the outcome + List existingMinimalTaskSummaries = + taskMapper.findExistingTasks(taskIds, null); + // check for tasks that don't exist + handleNonExistingTasks(taskIds, existingMinimalTaskSummaries, bulkLog); + // add all errors that occured to bulkLog + addErrorsToResultObject(owner, bulkLog, existingMinimalTaskSummaries); + LOGGER.debug( + "Received the Request to set owner on " + + requestSize + + " tasks, " + + "actually modified tasks = " + + numberOfAffectedTasks + + ", could not set owner on " + + bulkLog.getFailedIds().size() + + " tasks."); + return bulkLog; + } + } finally { + LOGGER.debug("exit from setOwnerOfTasks()"); + taskanaEngine.returnConnection(); + } + } + public Set findTasksIdsAffectedByClassificationChange(String classificationId) { LOGGER.debug( "entry to findTasksIdsAffectedByClassificationChange(classificationId = {})", @@ -757,6 +808,77 @@ public class TaskServiceImpl implements TaskService { return result; } + private void addErrorsToResultObject( + String owner, + BulkOperationResults bulkLog, + List existingMinimalTaskSummaries) { + for (MinimalTaskSummary taskSummary : existingMinimalTaskSummaries) { + if (!owner.equals(taskSummary.getOwner())) { // owner was not set + if (!taskSummary.getTaskState().equals(TaskState.READY)) { // due to invalid state + bulkLog.addError( + taskSummary.getTaskId(), + new InvalidStateException( + "Task " + + taskSummary.getTaskId() + + " is in state " + + taskSummary.getTaskState())); + } else { // due to unknown reason + bulkLog.addError( + taskSummary.getTaskId(), + new UpdateFailedException( + "Could not set owner of Task " + taskSummary.getTaskId() + ".")); + } + } + } + } + + private void handleNonExistingTasks( + List taskIds, + List existingMinimalTaskSummaries, + BulkOperationResults bulkLog) { + List nonExistingTaskIds = new ArrayList<>(taskIds); + List existingTaskIds = + existingMinimalTaskSummaries.stream() + .map(MinimalTaskSummary::getTaskId) + .collect(Collectors.toList()); + nonExistingTaskIds.removeAll(existingTaskIds); + for (String taskId : nonExistingTaskIds) { + bulkLog.addError(taskId, new TaskNotFoundException(taskId, "Task was not found")); + } + } + + private List filterForAuthorized( + List taskIds, BulkOperationResults bulkLog) { + List accessIds = getAccessIds(); + List tasksAuthorizedFor = new ArrayList<>(taskIds); + if (accessIds != null) { + List tasksNotAuthorizedFor = + taskMapper.filterTaskIdsNotAuthorizedFor(taskIds, accessIds); + tasksAuthorizedFor.removeAll(tasksNotAuthorizedFor); + String currentUserId = CurrentUserContext.getUserid(); + for (String taskId : tasksNotAuthorizedFor) { + bulkLog.addError( + taskId, + new NotAuthorizedException( + "Current user not authorized for task " + taskId, currentUserId)); + } + } + return tasksAuthorizedFor; + } + + private List getAccessIds() { + List accessIds; + if (taskanaEngine.getEngine().isUserInRole(TaskanaRole.ADMIN)) { + accessIds = null; + } else { + accessIds = CurrentUserContext.getAccessIds(); + if (TaskanaEngineConfiguration.shouldUseLowerCaseForAccessIds()) { + accessIds = accessIds.stream().map(String::toLowerCase).collect(Collectors.toList()); + } + } + return accessIds; + } + private Task claim(String taskId, boolean forceClaim) throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, NotAuthorizedException { diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/MinimalTaskSummary.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/MinimalTaskSummary.java index b3b311f30..3ba1d71b1 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/MinimalTaskSummary.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/MinimalTaskSummary.java @@ -9,6 +9,7 @@ public class MinimalTaskSummary { private String taskId; private String externalId; private String workbasketId; + private String owner; private TaskState taskState; private CallbackState callbackState; @@ -38,6 +39,14 @@ public class MinimalTaskSummary { this.workbasketId = workbasketKey; } + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + public TaskState getTaskState() { return taskState; } @@ -58,10 +67,16 @@ public class MinimalTaskSummary { public String toString() { return "MinimalTaskSummary [taskId=" + taskId + + ", externalId=" + + externalId + ", workbasketId=" + workbasketId + + ", owner=" + + owner + ", taskState=" + taskState + + ", callbackState=" + + callbackState + "]"; } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskIdOwnerState.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskIdOwnerState.java new file mode 100644 index 000000000..21fee3ffe --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskIdOwnerState.java @@ -0,0 +1,46 @@ +package pro.taskana.task.internal.models; + +import pro.taskana.task.api.TaskState; + +public class TaskIdOwnerState { + private String taskId; + private String owner; + private TaskState taskState; + + TaskIdOwnerState() {} + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public TaskState getTaskState() { + return taskState; + } + + public void setTaskState(TaskState taskState) { + this.taskState = taskState; + } + + @Override + public String toString() { + return "TaskIdOwnerState [taskId=" + + taskId + + ", owner=" + + owner + + ", taskState=" + + taskState + + "]"; + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketService.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketService.java index 9e60bda3f..01d924be7 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketService.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketService.java @@ -66,6 +66,9 @@ public interface WorkbasketService { * @param workbasket The Workbasket to update * @return the updated Workbasket * @throws NotAuthorizedException if the current user is not authorized to update the work basket + * @throws WorkbasketNotFoundException if the workbasket cannot be found. + * @throws ConcurrencyException if an attempt is made to update the workbasket and another user + * updated it already */ Workbasket updateWorkbasket(Workbasket workbasket) throws NotAuthorizedException, WorkbasketNotFoundException, ConcurrencyException; diff --git a/lib/taskana-core/src/test/java/acceptance/task/SetOwnerAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/SetOwnerAccTest.java new file mode 100644 index 000000000..a8b519d34 --- /dev/null +++ b/lib/taskana-core/src/test/java/acceptance/task/SetOwnerAccTest.java @@ -0,0 +1,265 @@ +package acceptance.task; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import acceptance.AbstractAccTest; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; +import pro.taskana.common.api.BulkOperationResults; +import pro.taskana.common.api.exceptions.ConcurrencyException; +import pro.taskana.common.api.exceptions.InvalidArgumentException; +import pro.taskana.common.api.exceptions.NotAuthorizedException; +import pro.taskana.common.api.exceptions.TaskanaException; +import pro.taskana.common.internal.TaskanaEngineProxyForTest; +import pro.taskana.security.JaasExtension; +import pro.taskana.security.WithAccessId; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.TaskState; +import pro.taskana.task.api.exceptions.AttachmentPersistenceException; +import pro.taskana.task.api.exceptions.InvalidOwnerException; +import pro.taskana.task.api.exceptions.InvalidStateException; +import pro.taskana.task.api.exceptions.TaskNotFoundException; +import pro.taskana.task.api.models.Task; +import pro.taskana.task.api.models.TaskSummary; + +/** Acceptance test for all "update task" scenarios. */ +@ExtendWith(JaasExtension.class) +public class SetOwnerAccTest extends AbstractAccTest { + + @WithAccessId( + userName = "user_1_2", + groupNames = {"group_1"}) + @Test + void testSetOwnerAndSubsequentClaimSucceeds() + throws TaskNotFoundException, NotAuthorizedException, InvalidStateException, + InvalidOwnerException, ClassificationNotFoundException, InvalidArgumentException, + ConcurrencyException, AttachmentPersistenceException { + + TaskService taskService = taskanaEngine.getTaskService(); + String taskReadyId = "TKI:000000000000000000000000000000000025"; + Task taskReady = taskService.getTask(taskReadyId); + assertThat(taskReady.getState()).isEqualTo(TaskState.READY); + assertThat(taskReady.getOwner()).isNull(); + String anyUserName = "TestUser27"; + Task modifiedTaskReady = setOwner(taskReadyId, anyUserName); + + assertThat(modifiedTaskReady.getState()).isEqualTo(TaskState.READY); + assertThat(modifiedTaskReady.getOwner()).isEqualTo(anyUserName); + Task taskClaimed = taskService.claim(taskReadyId); + assertThat(taskClaimed.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(taskClaimed.getOwner()).isEqualTo("user_1_2"); + } + + @WithAccessId( + userName = "user_1_2", + groupNames = {"group_1"}) + @Test + void testSetOwnerViaUpdateTaskNotAuthorized() + throws TaskNotFoundException, NotAuthorizedException, InvalidStateException, + InvalidOwnerException { + + TaskService taskService = taskanaEngine.getTaskService(); + String taskReadyId = "TKI:000000000000000000000000000000000024"; + String anyUserName = "TestUser3"; + + assertThatThrownBy(() -> taskService.getTask(taskReadyId)) + .isInstanceOf(NotAuthorizedException.class); + assertThatThrownBy(() -> setOwner(taskReadyId, anyUserName)) + .isInstanceOf(NotAuthorizedException.class); + } + + @WithAccessId( + userName = "user_1_2", + groupNames = {"group_1"}) + @Test + void testSetOwnerOfClaimedTaskFails() + throws TaskNotFoundException, NotAuthorizedException, InvalidStateException, + InvalidOwnerException { + + TaskService taskService = taskanaEngine.getTaskService(); + String taskClaimedId = "TKI:000000000000000000000000000000000026"; + String anyUserName = "TestUser007"; + Task taskClaimed = taskService.getTask(taskClaimedId); + assertThat(taskClaimed.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(taskClaimed.getOwner()).isEqualTo("user_1_1"); + assertThatThrownBy(() -> setOwner(taskClaimedId, anyUserName)) + .isInstanceOf(InvalidStateException.class); + } + + @WithAccessId( + userName = "user_1_2", + groupNames = {"group_1"}) + @Test + void testSetOwnerNotAuthorized() + throws TaskNotFoundException, NotAuthorizedException, InvalidStateException, + InvalidOwnerException { + + TaskService taskService = taskanaEngine.getTaskService(); + String taskReadyId = "TKI:000000000000000000000000000000000024"; + String anyUserName = "TestUser3"; + + assertThatThrownBy(() -> taskService.getTask(taskReadyId)) + .isInstanceOf(NotAuthorizedException.class); + BulkOperationResults results = + taskService.setOwnerOfTasks(anyUserName, Arrays.asList(taskReadyId)); + assertThat(results.containsErrors()).isTrue(); + assertThat(results.getErrorForId(taskReadyId)).isInstanceOf(NotAuthorizedException.class); + } + + @WithAccessId( + userName = "user_3_2", + groupNames = {"group_2"}) + @Test + void testSetOwnerOfTasksWithDuplicatesSucceeds() { + + List taskIds = + Arrays.asList( + "TKI:000000000000000000000000000000000058", + "TKI:000000000000000000000000000000000059", + "TKI:000000000000000000000000000000000058", + "TKI:000000000000000000000000000000000060"); + BulkOperationResults results = + taskanaEngine.getTaskService().setOwnerOfTasks("someUser", taskIds); + assertThat(results.containsErrors()).isFalse(); + } + + @WithAccessId( + userName = "user_3_2", + groupNames = {"group_2"}) + @Test + void testSetOwnerOfTasksWithDuplicatesAndNotExistingSucceeds() { + List taskIds = + Arrays.asList( + "TKI:000000000000000000000000000000000058", + "TKI:000000000000000000000000000047110059", + "TKI:000000000000000000000000000000000059", + "TKI:000000000000000000000000000000000058", + "TKI:000000000000000000000000000000000060"); + BulkOperationResults results = + taskanaEngine.getTaskService().setOwnerOfTasks("someUser", taskIds); + assertThat(results.containsErrors()).isTrue(); + assertThat(results.getErrorMap().size()).isEqualTo(1); + assertThat(results.getErrorForId("TKI:000000000000000000000000000047110059")) + .isInstanceOf(TaskNotFoundException.class); + } + + @WithAccessId( + userName = "user_3_2", + groupNames = {"group_2"}) + @Test + void testSetOwnerOfTasksWithNoQualifyingTasks() { + + List taskIds = + Arrays.asList( + "TKI:000000000000000000000000000000000008", + "TKI:000000000000000000000000000000000009", + "TKI:000000000000000000000000000000000008", + "TKI:000000000000000000000000000000000010"); + BulkOperationResults results = + taskanaEngine.getTaskService().setOwnerOfTasks("someUser", taskIds); + assertThat(results.containsErrors()).isTrue(); + assertThat(results.getErrorMap().size()).isEqualTo(3); + } + + @WithAccessId( + userName = "user_3_2", + groupNames = {"group_2"}) + @Test + void testSetOwnerWithEmptyList() { + List taskIds = new ArrayList<>(); + BulkOperationResults results = + taskanaEngine.getTaskService().setOwnerOfTasks("someUser", taskIds); + assertThat(results.containsErrors()).isFalse(); + } + + @WithAccessId( + userName = "user_1_2", + groupNames = {"group_2"}) + @Test + void testSetOwnerWithAllTasksAndVariousExceptions() + throws NoSuchFieldException, IllegalAccessException, SQLException { + resetDb(false); + List allTaskSummaries = + new TaskanaEngineProxyForTest(taskanaEngine) + .getEngine() + .runAsAdmin( + () -> { + return taskanaEngine.getTaskService().createTaskQuery().list(); + }); + List allTaskIds = + allTaskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); + BulkOperationResults results = + taskanaEngine.getTaskService().setOwnerOfTasks("theWorkaholic", allTaskIds); + assertThat(allTaskSummaries.size()).isEqualTo(73); + assertThat(results.containsErrors()).isTrue(); + assertThat(results.getErrorMap().size()).isEqualTo(48); + long numberOfInvalidStateExceptions = + results.getErrorMap().entrySet().stream() + .filter( + e -> + e.getValue() + .getClass() + .getName() + .equals(InvalidStateException.class.getCanonicalName())) + .count(); + assertThat(numberOfInvalidStateExceptions).isEqualTo(25); + + long numberOfNotAuthorizedExceptions = + results.getErrorMap().entrySet().stream() + .filter( + e -> + e.getValue() + .getClass() + .getName() + .equals(NotAuthorizedException.class.getCanonicalName())) + .count(); + assertThat(numberOfNotAuthorizedExceptions).isEqualTo(23); + } + + @WithAccessId( + userName = "admin", + groupNames = {"group_2"}) + @Test + void testSetOwnerWithAllTasksAndVariousExceptionsAsAdmin() + throws NoSuchFieldException, IllegalAccessException, SQLException { + resetDb(false); + List allTaskSummaries = taskanaEngine.getTaskService().createTaskQuery().list(); + List allTaskIds = + allTaskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); + BulkOperationResults results = + taskanaEngine.getTaskService().setOwnerOfTasks("theWorkaholic", allTaskIds); + assertThat(allTaskSummaries.size()).isEqualTo(73); + assertThat(results.containsErrors()).isTrue(); + assertThat(results.getErrorMap().size()).isEqualTo(26); + long numberOfInvalidStateExceptions = + results.getErrorMap().entrySet().stream() + .filter( + e -> + e.getValue() + .getClass() + .getName() + .equals(InvalidStateException.class.getCanonicalName())) + .count(); + assertThat(numberOfInvalidStateExceptions).isEqualTo(26); + } + + + private Task setOwner(String taskReadyId, String anyUserName) + throws TaskNotFoundException, NotAuthorizedException, ClassificationNotFoundException, + InvalidArgumentException, ConcurrencyException, AttachmentPersistenceException, + InvalidStateException { + TaskService taskService = taskanaEngine.getTaskService(); + Task task = taskService.getTask(taskReadyId); + task.setOwner(anyUserName); + task = taskService.updateTask(task); + return task; + } +} diff --git a/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java index a82cb50bb..a2645b4e9 100644 --- a/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java @@ -22,7 +22,6 @@ import pro.taskana.security.WithAccessId; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; -import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskNotFoundException; @@ -337,75 +336,4 @@ class UpdateTaskAccTest extends AbstractAccTest { assertThat(retrievedUpdatedTask.getCallbackInfo()).isEqualTo(callbackInfo); } - - @WithAccessId( - userName = "user_1_2", - groupNames = {"group_1"}) - @Test - void testSetOwnerAndSubsequentClaimSucceeds() - throws TaskNotFoundException, NotAuthorizedException, InvalidStateException, - InvalidOwnerException, ClassificationNotFoundException, InvalidArgumentException, - ConcurrencyException, AttachmentPersistenceException { - - TaskService taskService = taskanaEngine.getTaskService(); - String taskReadyId = "TKI:000000000000000000000000000000000025"; - Task taskReady = taskService.getTask(taskReadyId); - assertThat(taskReady.getState()).isEqualTo(TaskState.READY); - assertThat(taskReady.getOwner()).isNull(); - String anyUserName = "Holger"; - Task modifiedTaskReady = setOwner(taskReadyId, anyUserName); - - assertThat(modifiedTaskReady.getState()).isEqualTo(TaskState.READY); - assertThat(modifiedTaskReady.getOwner()).isEqualTo(anyUserName); - Task taskClaimed = taskService.claim(taskReadyId); - assertThat(taskClaimed.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(taskClaimed.getOwner()).isEqualTo("user_1_2"); - } - - @WithAccessId( - userName = "user_1_2", - groupNames = {"group_1"}) - @Test - void testSetOwnerNotAuthorized() - throws TaskNotFoundException, NotAuthorizedException, InvalidStateException, - InvalidOwnerException { - - TaskService taskService = taskanaEngine.getTaskService(); - String taskReadyId = "TKI:000000000000000000000000000000000024"; - String anyUserName = "Benjamin"; - - assertThatThrownBy(() -> taskService.getTask(taskReadyId)) - .isInstanceOf(NotAuthorizedException.class); - assertThatThrownBy(() -> setOwner(taskReadyId, anyUserName)) - .isInstanceOf(NotAuthorizedException.class); - } - - @WithAccessId( - userName = "user_1_2", - groupNames = {"group_1"}) - @Test - void testSetOwnerOfClaimedTaskFails() - throws TaskNotFoundException, NotAuthorizedException, InvalidStateException, - InvalidOwnerException { - - TaskService taskService = taskanaEngine.getTaskService(); - String taskClaimedId = "TKI:000000000000000000000000000000000026"; - String anyUserName = "Mustapha"; - Task taskClaimed = taskService.getTask(taskClaimedId); - assertThat(taskClaimed.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(taskClaimed.getOwner()).isEqualTo("user_1_1"); - assertThatThrownBy(() -> setOwner(taskClaimedId, anyUserName)) - .isInstanceOf(InvalidStateException.class); - } - - private Task setOwner(String taskReadyId, String anyUserName) - throws TaskNotFoundException, NotAuthorizedException, ClassificationNotFoundException, - InvalidArgumentException, ConcurrencyException, AttachmentPersistenceException, - InvalidStateException { - TaskService taskService = taskanaEngine.getTaskService(); - Task task = taskService.getTask(taskReadyId); - task.setOwner(anyUserName); - task = taskService.updateTask(task); - return task; - } }