TSK-1131 updateOwner on multiple tasks

This commit is contained in:
BerndBreier 2020-02-19 16:28:26 +01:00
parent 21a4110f2a
commit 20bd0922db
9 changed files with 511 additions and 74 deletions

View File

@ -249,7 +249,9 @@ public interface TaskService {
* cannot be found * cannot be found
* @throws NotAuthorizedException if the current user is not authorized to update the task * @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 * @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) Task updateTask(Task task)
throws InvalidArgumentException, TaskNotFoundException, ConcurrencyException, throws InvalidArgumentException, TaskNotFoundException, ConcurrencyException,
@ -373,4 +375,14 @@ public interface TaskService {
*/ */
BulkOperationResults<String, TaskanaException> setCallbackStateForTasks( BulkOperationResults<String, TaskanaException> setCallbackStateForTasks(
List<String> externalIds, CallbackState state); List<String> 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<String, TaskanaException> setOwnerOfTasks(
String owner, List<String> taskIds);
} }

View File

@ -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);
}
}

View File

@ -1,5 +1,6 @@
package pro.taskana.task.internal; package pro.taskana.task.internal;
import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Delete;
@ -132,6 +133,16 @@ public interface TaskMapper {
void setCallbackStateMultiple( void setCallbackStateMultiple(
@Param("externalIds") List<String> externalIds, @Param("state") CallbackState state); @Param("externalIds") List<String> externalIds, @Param("state") CallbackState state);
@Update(
"<script>UPDATE TASK SET OWNER = #{owner}, MODIFIED = #{modified} "
+ "WHERE STATE = 'READY' "
+ "AND ID IN <foreach item='taskId' index='index' separator=',' open='(' close=')' collection='taskIds'>#{taskId}</foreach> "
+ "</script>")
int setOwnerOfTasks(
@Param("owner") String owner,
@Param("taskIds") List<String> taskIds,
@Param("modified") Instant modified);
@Select( @Select(
"<script>SELECT ID, EXTERNAL_ID, CREATED, CLAIMED, COMPLETED, MODIFIED, PLANNED, DUE, NAME, CREATOR, DESCRIPTION, PRIORITY, STATE, CLASSIFICATION_CATEGORY, CLASSIFICATION_KEY, CLASSIFICATION_ID, WORKBASKET_ID, WORKBASKET_KEY, DOMAIN, BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, OWNER, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, IS_READ, IS_TRANSFERRED, CUSTOM_ATTRIBUTES, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, CUSTOM_5, CUSTOM_6, CUSTOM_7, " "<script>SELECT ID, EXTERNAL_ID, CREATED, CLAIMED, COMPLETED, MODIFIED, PLANNED, DUE, NAME, CREATOR, DESCRIPTION, PRIORITY, STATE, CLASSIFICATION_CATEGORY, CLASSIFICATION_KEY, CLASSIFICATION_ID, WORKBASKET_ID, WORKBASKET_KEY, DOMAIN, BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, OWNER, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, IS_READ, IS_TRANSFERRED, CUSTOM_ATTRIBUTES, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, CUSTOM_5, CUSTOM_6, CUSTOM_7, "
+ "CUSTOM_8, CUSTOM_9, CUSTOM_10, CUSTOM_11, CUSTOM_12, CUSTOM_13, CUSTOM_14, CUSTOM_15, CUSTOM_16 " + "CUSTOM_8, CUSTOM_9, CUSTOM_10, CUSTOM_11, CUSTOM_12, CUSTOM_13, CUSTOM_14, CUSTOM_15, CUSTOM_16 "
@ -214,7 +225,7 @@ public interface TaskMapper {
@Param("referencetask") TaskSummaryImpl referencetask); @Param("referencetask") TaskSummaryImpl referencetask);
@Select( @Select(
"<script>SELECT ID, EXTERNAL_ID, STATE, WORKBASKET_ID, CALLBACK_STATE FROM TASK " "<script>SELECT ID, EXTERNAL_ID, STATE, WORKBASKET_ID, OWNER, CALLBACK_STATE FROM TASK "
+ "<where> " + "<where> "
+ "<if test='taskIds != null'>ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)</if> " + "<if test='taskIds != null'>ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)</if> "
+ "<if test='externalIds != null'>EXTERNAL_ID IN(<foreach item='item' collection='externalIds' separator=',' >#{item}</foreach>)</if> " + "<if test='externalIds != null'>EXTERNAL_ID IN(<foreach item='item' collection='externalIds' separator=',' >#{item}</foreach>)</if> "
@ -226,6 +237,7 @@ public interface TaskMapper {
@Result(property = "taskId", column = "ID"), @Result(property = "taskId", column = "ID"),
@Result(property = "externalId", column = "EXTERNAL_ID"), @Result(property = "externalId", column = "EXTERNAL_ID"),
@Result(property = "workbasketId", column = "WORKBASKET_ID"), @Result(property = "workbasketId", column = "WORKBASKET_ID"),
@Result(property = "owner", column = "OWNER"),
@Result(property = "taskState", column = "STATE"), @Result(property = "taskState", column = "STATE"),
@Result(property = "callbackState", column = "CALLBACK_STATE") @Result(property = "callbackState", column = "CALLBACK_STATE")
}) })
@ -274,4 +286,25 @@ public interface TaskMapper {
+ "</script>") + "</script>")
@Results(value = {@Result(property = "taskId", column = "ID")}) @Results(value = {@Result(property = "taskId", column = "ID")})
List<String> filterTaskIdsForNotCompleted(@Param("taskIds") List<String> taskIds); List<String> filterTaskIdsForNotCompleted(@Param("taskIds") List<String> taskIds);
@Select(
"<script> "
+ "SELECT t.ID FROM TASK t WHERE t.ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)"
+ "<if test='accessIds != null'> "
+ "AND NOT (t.WORKBASKET_ID IN ( "
+ "<choose>"
+ "<when test=\"_databaseId == 'db2'\">"
+ "SELECT WID from (SELECT WORKBASKET_ID as WID, MAX(PERM_READ) as MAX_READ FROM WORKBASKET_ACCESS_LIST AS s where "
+ "</when>"
+ "<otherwise>"
+ "SELECT WID from (SELECT WORKBASKET_ID as WID, MAX(PERM_READ::int) as MAX_READ FROM WORKBASKET_ACCESS_LIST AS s where "
+ "</otherwise>"
+ "</choose>"
+ "ACCESS_ID IN (<foreach item='item' collection='accessIds' separator=',' >#{item}</foreach>) "
+ "group by WORKBASKET_ID ) AS f where max_read = 1 ))"
+ "</if> "
+ "</script>")
@Results(value = {@Result(property = "id", column = "ID")})
List<String> filterTaskIdsNotAuthorizedFor(
@Param("taskIds") List<String> taskIds, @Param("accessIds") List<String> accessIds);
} }

View File

@ -16,6 +16,7 @@ import org.apache.ibatis.exceptions.PersistenceException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; import pro.taskana.classification.api.exceptions.ClassificationNotFoundException;
import pro.taskana.classification.api.models.Classification; 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.InvalidStateException;
import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException;
import pro.taskana.task.api.exceptions.TaskNotFoundException; 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.Attachment;
import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.ObjectReference;
import pro.taskana.task.api.models.Task; import pro.taskana.task.api.models.Task;
@ -617,6 +619,55 @@ public class TaskServiceImpl implements TaskService {
} }
} }
@Override
public BulkOperationResults<String, TaskanaException> setOwnerOfTasks(
String owner, List<String> argTaskIds) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(
"entry to setOwnerOfTasks(owner = {}, tasks = {})",
owner,
LoggerUtils.listToString(argTaskIds));
}
try {
taskanaEngine.openConnection();
BulkOperationResults<String, TaskanaException> bulkLog = new BulkOperationResults<>();
if (argTaskIds == null || argTaskIds.isEmpty()) {
return bulkLog;
}
// remove duplicates
List<String> 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<MinimalTaskSummary> 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<String> findTasksIdsAffectedByClassificationChange(String classificationId) { public Set<String> findTasksIdsAffectedByClassificationChange(String classificationId) {
LOGGER.debug( LOGGER.debug(
"entry to findTasksIdsAffectedByClassificationChange(classificationId = {})", "entry to findTasksIdsAffectedByClassificationChange(classificationId = {})",
@ -757,6 +808,77 @@ public class TaskServiceImpl implements TaskService {
return result; return result;
} }
private void addErrorsToResultObject(
String owner,
BulkOperationResults<String, TaskanaException> bulkLog,
List<MinimalTaskSummary> 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<String> taskIds,
List<MinimalTaskSummary> existingMinimalTaskSummaries,
BulkOperationResults<String, TaskanaException> bulkLog) {
List<String> nonExistingTaskIds = new ArrayList<>(taskIds);
List<String> 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<String> filterForAuthorized(
List<String> taskIds, BulkOperationResults<String, TaskanaException> bulkLog) {
List<String> accessIds = getAccessIds();
List<String> tasksAuthorizedFor = new ArrayList<>(taskIds);
if (accessIds != null) {
List<String> 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<String> getAccessIds() {
List<String> 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) private Task claim(String taskId, boolean forceClaim)
throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, throws TaskNotFoundException, InvalidStateException, InvalidOwnerException,
NotAuthorizedException { NotAuthorizedException {

View File

@ -9,6 +9,7 @@ public class MinimalTaskSummary {
private String taskId; private String taskId;
private String externalId; private String externalId;
private String workbasketId; private String workbasketId;
private String owner;
private TaskState taskState; private TaskState taskState;
private CallbackState callbackState; private CallbackState callbackState;
@ -38,6 +39,14 @@ public class MinimalTaskSummary {
this.workbasketId = workbasketKey; this.workbasketId = workbasketKey;
} }
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public TaskState getTaskState() { public TaskState getTaskState() {
return taskState; return taskState;
} }
@ -58,10 +67,16 @@ public class MinimalTaskSummary {
public String toString() { public String toString() {
return "MinimalTaskSummary [taskId=" return "MinimalTaskSummary [taskId="
+ taskId + taskId
+ ", externalId="
+ externalId
+ ", workbasketId=" + ", workbasketId="
+ workbasketId + workbasketId
+ ", owner="
+ owner
+ ", taskState=" + ", taskState="
+ taskState + taskState
+ ", callbackState="
+ callbackState
+ "]"; + "]";
} }
} }

View File

@ -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
+ "]";
}
}

View File

@ -66,6 +66,9 @@ public interface WorkbasketService {
* @param workbasket The Workbasket to update * @param workbasket The Workbasket to update
* @return the updated Workbasket * @return the updated Workbasket
* @throws NotAuthorizedException if the current user is not authorized to update the work basket * @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) Workbasket updateWorkbasket(Workbasket workbasket)
throws NotAuthorizedException, WorkbasketNotFoundException, ConcurrencyException; throws NotAuthorizedException, WorkbasketNotFoundException, ConcurrencyException;

View File

@ -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<String, TaskanaException> 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<String> taskIds =
Arrays.asList(
"TKI:000000000000000000000000000000000058",
"TKI:000000000000000000000000000000000059",
"TKI:000000000000000000000000000000000058",
"TKI:000000000000000000000000000000000060");
BulkOperationResults<String, TaskanaException> results =
taskanaEngine.getTaskService().setOwnerOfTasks("someUser", taskIds);
assertThat(results.containsErrors()).isFalse();
}
@WithAccessId(
userName = "user_3_2",
groupNames = {"group_2"})
@Test
void testSetOwnerOfTasksWithDuplicatesAndNotExistingSucceeds() {
List<String> taskIds =
Arrays.asList(
"TKI:000000000000000000000000000000000058",
"TKI:000000000000000000000000000047110059",
"TKI:000000000000000000000000000000000059",
"TKI:000000000000000000000000000000000058",
"TKI:000000000000000000000000000000000060");
BulkOperationResults<String, TaskanaException> 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<String> taskIds =
Arrays.asList(
"TKI:000000000000000000000000000000000008",
"TKI:000000000000000000000000000000000009",
"TKI:000000000000000000000000000000000008",
"TKI:000000000000000000000000000000000010");
BulkOperationResults<String, TaskanaException> 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<String> taskIds = new ArrayList<>();
BulkOperationResults<String, TaskanaException> 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<TaskSummary> allTaskSummaries =
new TaskanaEngineProxyForTest(taskanaEngine)
.getEngine()
.runAsAdmin(
() -> {
return taskanaEngine.getTaskService().createTaskQuery().list();
});
List<String> allTaskIds =
allTaskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList());
BulkOperationResults<String, TaskanaException> 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<TaskSummary> allTaskSummaries = taskanaEngine.getTaskService().createTaskQuery().list();
List<String> allTaskIds =
allTaskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList());
BulkOperationResults<String, TaskanaException> 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;
}
}

View File

@ -22,7 +22,6 @@ import pro.taskana.security.WithAccessId;
import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.TaskState; import pro.taskana.task.api.TaskState;
import pro.taskana.task.api.exceptions.AttachmentPersistenceException; 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.InvalidStateException;
import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException;
import pro.taskana.task.api.exceptions.TaskNotFoundException; import pro.taskana.task.api.exceptions.TaskNotFoundException;
@ -337,75 +336,4 @@ class UpdateTaskAccTest extends AbstractAccTest {
assertThat(retrievedUpdatedTask.getCallbackInfo()).isEqualTo(callbackInfo); 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;
}
} }