Closes #2389 Possibility to keep the Owner and OwnerLongName of a task when cancelClaiming

This commit is contained in:
Jörg Heffner 2023-09-12 15:28:03 +02:00 committed by Jörg Heffner
parent 67502025a5
commit 422fd4aa19
6 changed files with 295 additions and 56 deletions

View File

@ -43,7 +43,7 @@ import pro.taskana.workbasket.api.exceptions.NotAuthorizedOnWorkbasketException;
import pro.taskana.workbasket.api.models.WorkbasketSummary; import pro.taskana.workbasket.api.models.WorkbasketSummary;
@TaskanaIntegrationTest @TaskanaIntegrationTest
class ClaimTaskAccTest { class ClaimTaskAccTest implements TaskanaConfigurationModifier {
@TaskanaInject TaskService taskService; @TaskanaInject TaskService taskService;
@TaskanaInject ClassificationService classificationService; @TaskanaInject ClassificationService classificationService;
@TaskanaInject WorkbasketService workbasketService; @TaskanaInject WorkbasketService workbasketService;
@ -56,6 +56,11 @@ class ClaimTaskAccTest {
WorkbasketSummary wbWithoutReadTasks; WorkbasketSummary wbWithoutReadTasks;
WorkbasketSummary wbWithoutRead; WorkbasketSummary wbWithoutRead;
@Override
public TaskanaConfiguration.Builder modify(TaskanaConfiguration.Builder builder) {
return builder.addAdditionalUserInfo(true);
}
@WithAccessId(user = "businessadmin") @WithAccessId(user = "businessadmin")
@BeforeAll @BeforeAll
void setup() throws Exception { void setup() throws Exception {
@ -371,6 +376,52 @@ class ClaimTaskAccTest {
assertThat(unclaimedTask.getOwnerLongName()).isNull(); assertThat(unclaimedTask.getOwnerLongName()).isNull();
} }
@WithAccessId(user = "user-1-2")
@Test
void should_KeepOwnerAndOwnerLongName_When_CancelClaimWithKeepOwner() throws Exception {
Task claimedTask =
TaskBuilder.newTask()
.state(TaskState.CLAIMED)
.claimed(Instant.now())
.owner("user-1-2")
.classificationSummary(defaultClassificationSummary)
.workbasketSummary(defaultWorkbasketSummary)
.primaryObjRef(defaultObjectReference)
.buildAndStore(taskService);
Task unclaimedTask = taskService.cancelClaim(claimedTask.getId(), true);
assertThat(unclaimedTask).isNotNull();
assertThat(unclaimedTask.getState()).isEqualTo(TaskState.READY);
assertThat(unclaimedTask.getClaimed()).isNull();
assertThat(unclaimedTask.isRead()).isTrue();
assertThat(unclaimedTask.getOwner()).isEqualTo("user-1-2");
assertThat(unclaimedTask.getOwnerLongName()).isEqualTo("Long name of user-1-2");
}
@WithAccessId(user = "user-1-2")
@Test
void should_KeepOwnerAndOwnerLongName_When_ForceCancelClaimWithKeepOwner() throws Exception {
Task claimedTask =
TaskBuilder.newTask()
.state(TaskState.CLAIMED)
.claimed(Instant.now())
.owner("user-1-2")
.classificationSummary(defaultClassificationSummary)
.workbasketSummary(defaultWorkbasketSummary)
.primaryObjRef(defaultObjectReference)
.buildAndStore(taskService);
Task unclaimedTask = taskService.forceCancelClaim(claimedTask.getId(), true);
assertThat(unclaimedTask).isNotNull();
assertThat(unclaimedTask.getState()).isEqualTo(TaskState.READY);
assertThat(unclaimedTask.getClaimed()).isNull();
assertThat(unclaimedTask.isRead()).isTrue();
assertThat(unclaimedTask.getOwner()).isEqualTo("user-1-2");
assertThat(unclaimedTask.getOwnerLongName()).isEqualTo("Long name of user-1-2");
}
@WithAccessId(user = "user-1-2") @WithAccessId(user = "user-1-2")
@Test @Test
void should_CancelClaimTask_When_TaskIsInReview() throws Exception { void should_CancelClaimTask_When_TaskIsInReview() throws Exception {

View File

@ -220,6 +220,44 @@ public interface TaskService {
NotAuthorizedOnWorkbasketException, NotAuthorizedOnWorkbasketException,
InvalidTaskStateException; InvalidTaskStateException;
/**
* Cancel the claim of an existing {@linkplain Task} if it was claimed by the current user before.
*
* @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} which should be
* unclaimed
* @param keepOwner If set to true, will keep the {@linkplain Task#getOwner()} and {@linkplain
* Task#getOwnerLongName()}
* @return the unclaimed {@linkplain Task}
* @throws TaskNotFoundException if the {@linkplain Task} with taskId was not found
* @throws InvalidTaskStateException if the {@linkplain Task} is already in one of the {@linkplain
* TaskState#END_STATES}
* @throws InvalidOwnerException if the {@linkplain Task} is claimed by another user
* @throws NotAuthorizedOnWorkbasketException if the current user has no {@linkplain
* WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in
*/
Task cancelClaim(String taskId, boolean keepOwner)
throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException;
/**
* Cancel the claim of an existing {@linkplain Task} even if it was claimed by another user.
*
* @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} which should be
* unclaimed
* @param keepOwner If set to true, will keep the {@linkplain Task#getOwner()} and {@linkplain
* Task#getOwnerLongName()}
* @return the unclaimed {@linkplain Task}
* @throws TaskNotFoundException if the {@linkplain Task} with taskId was not found
* @throws InvalidTaskStateException if the {@linkplain Task} is already in one of the {@linkplain
* TaskState#END_STATES}
* @throws NotAuthorizedOnWorkbasketException if the current user has no {@linkplain
* WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in
*/
Task forceCancelClaim(String taskId, boolean keepOwner)
throws TaskNotFoundException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException;
/** /**
* Cancel the claim of an existing {@linkplain Task} even if it was claimed by another user. * Cancel the claim of an existing {@linkplain Task} even if it was claimed by another user.
* *

View File

@ -160,30 +160,55 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public Task claim(String taskId) public Task claim(String taskId)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
return claim(taskId, false); return claim(taskId, false);
} }
@Override @Override
public Task forceClaim(String taskId) public Task forceClaim(String taskId)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
return claim(taskId, true); return claim(taskId, true);
} }
@Override @Override
public Task cancelClaim(String taskId) public Task cancelClaim(String taskId)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
return this.cancelClaim(taskId, false); return this.cancelClaim(taskId, false, false);
} }
@Override @Override
public Task forceCancelClaim(String taskId) public Task forceCancelClaim(String taskId)
throws TaskNotFoundException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException { throws TaskNotFoundException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException {
try { try {
return this.cancelClaim(taskId, true); return this.cancelClaim(taskId, true, false);
} catch (InvalidOwnerException e) {
throw new SystemException("this should not have happened. You've discovered a new bug!", e);
}
}
@Override
public Task cancelClaim(String taskId, boolean keepOwner)
throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException {
return this.cancelClaim(taskId, false, keepOwner);
}
@Override
public Task forceCancelClaim(String taskId, boolean keepOwner)
throws TaskNotFoundException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException {
try {
return this.cancelClaim(taskId, true, keepOwner);
} catch (InvalidOwnerException e) { } catch (InvalidOwnerException e) {
throw new SystemException("this should not have happened. You've discovered a new bug!", e); throw new SystemException("this should not have happened. You've discovered a new bug!", e);
} }
@ -191,51 +216,67 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public Task requestReview(String taskId) public Task requestReview(String taskId)
throws InvalidTaskStateException, TaskNotFoundException, InvalidOwnerException, throws InvalidTaskStateException,
TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return requestReview(taskId, false); return requestReview(taskId, false);
} }
@Override @Override
public Task forceRequestReview(String taskId) public Task forceRequestReview(String taskId)
throws InvalidTaskStateException, TaskNotFoundException, InvalidOwnerException, throws InvalidTaskStateException,
TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return requestReview(taskId, true); return requestReview(taskId, true);
} }
@Override @Override
public Task requestChanges(String taskId) public Task requestChanges(String taskId)
throws InvalidTaskStateException, TaskNotFoundException, InvalidOwnerException, throws InvalidTaskStateException,
TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return requestChanges(taskId, false); return requestChanges(taskId, false);
} }
@Override @Override
public Task forceRequestChanges(String taskId) public Task forceRequestChanges(String taskId)
throws InvalidTaskStateException, TaskNotFoundException, InvalidOwnerException, throws InvalidTaskStateException,
TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return requestChanges(taskId, true); return requestChanges(taskId, true);
} }
@Override @Override
public Task completeTask(String taskId) public Task completeTask(String taskId)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
return completeTask(taskId, false); return completeTask(taskId, false);
} }
@Override @Override
public Task forceCompleteTask(String taskId) public Task forceCompleteTask(String taskId)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
return completeTask(taskId, true); return completeTask(taskId, true);
} }
@Override @Override
public Task createTask(Task taskToCreate) public Task createTask(Task taskToCreate)
throws WorkbasketNotFoundException, ClassificationNotFoundException, throws WorkbasketNotFoundException,
TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, ClassificationNotFoundException,
ObjectReferencePersistenceException, NotAuthorizedOnWorkbasketException { TaskAlreadyExistException,
InvalidArgumentException,
AttachmentPersistenceException,
ObjectReferencePersistenceException,
NotAuthorizedOnWorkbasketException {
if (createTaskPreprocessorManager.isEnabled()) { if (createTaskPreprocessorManager.isEnabled()) {
taskToCreate = createTaskPreprocessorManager.processTaskBeforeCreation(taskToCreate); taskToCreate = createTaskPreprocessorManager.processTaskBeforeCreation(taskToCreate);
@ -417,14 +458,18 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public Task transfer(String taskId, String destinationWorkbasketId, boolean setTransferFlag) public Task transfer(String taskId, String destinationWorkbasketId, boolean setTransferFlag)
throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
WorkbasketNotFoundException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
return taskTransferrer.transfer(taskId, destinationWorkbasketId, setTransferFlag); return taskTransferrer.transfer(taskId, destinationWorkbasketId, setTransferFlag);
} }
@Override @Override
public Task transfer(String taskId, String workbasketKey, String domain, boolean setTransferFlag) public Task transfer(String taskId, String workbasketKey, String domain, boolean setTransferFlag)
throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
WorkbasketNotFoundException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
return taskTransferrer.transfer(taskId, workbasketKey, domain, setTransferFlag); return taskTransferrer.transfer(taskId, workbasketKey, domain, setTransferFlag);
} }
@ -506,9 +551,13 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public Task updateTask(Task task) public Task updateTask(Task task)
throws InvalidArgumentException, TaskNotFoundException, ConcurrencyException, throws InvalidArgumentException,
AttachmentPersistenceException, ObjectReferencePersistenceException, TaskNotFoundException,
ClassificationNotFoundException, NotAuthorizedOnWorkbasketException, ConcurrencyException,
AttachmentPersistenceException,
ObjectReferencePersistenceException,
ClassificationNotFoundException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid(); String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid();
TaskImpl newTaskImpl = (TaskImpl) task; TaskImpl newTaskImpl = (TaskImpl) task;
@ -563,7 +612,8 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public BulkOperationResults<String, TaskanaException> transferTasks( public BulkOperationResults<String, TaskanaException> transferTasks(
String destinationWorkbasketId, List<String> taskIds, boolean setTransferFlag) String destinationWorkbasketId, List<String> taskIds, boolean setTransferFlag)
throws InvalidArgumentException, WorkbasketNotFoundException, throws InvalidArgumentException,
WorkbasketNotFoundException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return taskTransferrer.transfer(taskIds, destinationWorkbasketId, setTransferFlag); return taskTransferrer.transfer(taskIds, destinationWorkbasketId, setTransferFlag);
} }
@ -574,7 +624,8 @@ public class TaskServiceImpl implements TaskService {
String destinationWorkbasketDomain, String destinationWorkbasketDomain,
List<String> taskIds, List<String> taskIds,
boolean setTransferFlag) boolean setTransferFlag)
throws InvalidArgumentException, WorkbasketNotFoundException, throws InvalidArgumentException,
WorkbasketNotFoundException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return taskTransferrer.transfer( return taskTransferrer.transfer(
taskIds, destinationWorkbasketKey, destinationWorkbasketDomain, setTransferFlag); taskIds, destinationWorkbasketKey, destinationWorkbasketDomain, setTransferFlag);
@ -582,15 +633,21 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public void deleteTask(String taskId) public void deleteTask(String taskId)
throws TaskNotFoundException, NotAuthorizedException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidTaskStateException, InvalidCallbackStateException { NotAuthorizedException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException,
InvalidCallbackStateException {
deleteTask(taskId, false); deleteTask(taskId, false);
} }
@Override @Override
public void forceDeleteTask(String taskId) public void forceDeleteTask(String taskId)
throws TaskNotFoundException, NotAuthorizedException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidTaskStateException, InvalidCallbackStateException { NotAuthorizedException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException,
InvalidCallbackStateException {
deleteTask(taskId, true); deleteTask(taskId, true);
} }
@ -759,22 +816,30 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public TaskComment updateTaskComment(TaskComment taskComment) public TaskComment updateTaskComment(TaskComment taskComment)
throws ConcurrencyException, TaskCommentNotFoundException, TaskNotFoundException, throws ConcurrencyException,
InvalidArgumentException, NotAuthorizedOnTaskCommentException, TaskCommentNotFoundException,
TaskNotFoundException,
InvalidArgumentException,
NotAuthorizedOnTaskCommentException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return taskCommentService.updateTaskComment(taskComment); return taskCommentService.updateTaskComment(taskComment);
} }
@Override @Override
public void deleteTaskComment(String taskCommentId) public void deleteTaskComment(String taskCommentId)
throws TaskCommentNotFoundException, TaskNotFoundException, InvalidArgumentException, throws TaskCommentNotFoundException,
NotAuthorizedOnTaskCommentException, NotAuthorizedOnWorkbasketException { TaskNotFoundException,
InvalidArgumentException,
NotAuthorizedOnTaskCommentException,
NotAuthorizedOnWorkbasketException {
taskCommentService.deleteTaskComment(taskCommentId); taskCommentService.deleteTaskComment(taskCommentId);
} }
@Override @Override
public TaskComment getTaskComment(String taskCommentid) public TaskComment getTaskComment(String taskCommentid)
throws TaskCommentNotFoundException, TaskNotFoundException, InvalidArgumentException, throws TaskCommentNotFoundException,
TaskNotFoundException,
InvalidArgumentException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
return taskCommentService.getTaskComment(taskCommentid); return taskCommentService.getTaskComment(taskCommentid);
} }
@ -922,7 +987,9 @@ public class TaskServiceImpl implements TaskService {
@Override @Override
public Task terminateTask(String taskId) public Task terminateTask(String taskId)
throws TaskNotFoundException, NotAuthorizedException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
NotAuthorizedException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
taskanaEngine.getEngine().checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.TASK_ADMIN); taskanaEngine.getEngine().checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.TASK_ADMIN);
@ -1265,7 +1332,9 @@ public class TaskServiceImpl implements TaskService {
} }
private Task claim(String taskId, boolean forceClaim) private Task claim(String taskId, boolean forceClaim)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
TaskImpl task; TaskImpl task;
try { try {
@ -1309,7 +1378,9 @@ public class TaskServiceImpl implements TaskService {
} }
private Task requestReview(String taskId, boolean force) private Task requestReview(String taskId, boolean force)
throws TaskNotFoundException, InvalidTaskStateException, InvalidOwnerException, throws TaskNotFoundException,
InvalidTaskStateException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid(); String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid();
TaskImpl task; TaskImpl task;
@ -1360,7 +1431,9 @@ public class TaskServiceImpl implements TaskService {
} }
private Task requestChanges(String taskId, boolean force) private Task requestChanges(String taskId, boolean force)
throws InvalidTaskStateException, TaskNotFoundException, InvalidOwnerException, throws InvalidTaskStateException,
TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid(); String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid();
TaskImpl task; TaskImpl task;
@ -1422,9 +1495,12 @@ public class TaskServiceImpl implements TaskService {
} }
} }
private static void cancelClaimActionsOnTask(TaskSummaryImpl task, Instant now) { private static void cancelClaimActionsOnTask(
TaskSummaryImpl task, Instant now, boolean keepOwner) {
if (!keepOwner) {
task.setOwner(null); task.setOwner(null);
task.setOwnerLongName(null); task.setOwnerLongName(null);
}
task.setModified(now); task.setModified(now);
task.setClaimed(null); task.setClaimed(null);
task.setRead(true); task.setRead(true);
@ -1501,15 +1577,16 @@ public class TaskServiceImpl implements TaskService {
} }
} }
private Task cancelClaim(String taskId, boolean forceUnclaim) private Task cancelClaim(String taskId, boolean forceUnclaim, boolean keepOwner)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid(); String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid();
TaskImpl task; TaskImpl task;
try { try {
taskanaEngine.openConnection(); taskanaEngine.openConnection();
task = (TaskImpl) getTask(taskId); task = (TaskImpl) getTask(taskId);
TaskImpl oldTask = duplicateTaskExactly(task); TaskImpl oldTask = duplicateTaskExactly(task);
TaskState state = task.getState(); TaskState state = task.getState();
@ -1529,7 +1606,7 @@ public class TaskServiceImpl implements TaskService {
throw new InvalidOwnerException(userId, taskId); throw new InvalidOwnerException(userId, taskId);
} }
Instant now = Instant.now(); Instant now = Instant.now();
cancelClaimActionsOnTask(task, now); cancelClaimActionsOnTask(task, now, keepOwner);
taskMapper.update(task); taskMapper.update(task);
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Task '{}' unclaimed by user '{}'.", taskId, userId); LOGGER.debug("Task '{}' unclaimed by user '{}'.", taskId, userId);
@ -1552,7 +1629,9 @@ public class TaskServiceImpl implements TaskService {
} }
private Task completeTask(String taskId, boolean isForced) private Task completeTask(String taskId, boolean isForced)
throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidOwnerException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException { InvalidTaskStateException {
String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid(); String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid();
TaskImpl task; TaskImpl task;
@ -1596,8 +1675,11 @@ public class TaskServiceImpl implements TaskService {
} }
private void deleteTask(String taskId, boolean forceDelete) private void deleteTask(String taskId, boolean forceDelete)
throws TaskNotFoundException, NotAuthorizedException, NotAuthorizedOnWorkbasketException, throws TaskNotFoundException,
InvalidTaskStateException, InvalidCallbackStateException { NotAuthorizedException,
NotAuthorizedOnWorkbasketException,
InvalidTaskStateException,
InvalidCallbackStateException {
taskanaEngine.getEngine().checkRoleMembership(TaskanaRole.ADMIN); taskanaEngine.getEngine().checkRoleMembership(TaskanaRole.ADMIN);
TaskImpl task; TaskImpl task;
try { try {
@ -1751,8 +1833,10 @@ public class TaskServiceImpl implements TaskService {
} }
private void standardSettingsOnTaskCreation(TaskImpl task, Classification classification) private void standardSettingsOnTaskCreation(TaskImpl task, Classification classification)
throws InvalidArgumentException, ClassificationNotFoundException, throws InvalidArgumentException,
AttachmentPersistenceException, ObjectReferencePersistenceException { ClassificationNotFoundException,
AttachmentPersistenceException,
ObjectReferencePersistenceException {
final Instant now = Instant.now(); final Instant now = Instant.now();
task.setId(IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK)); task.setId(IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK));
if (task.getExternalId() == null) { if (task.getExternalId() == null) {

View File

@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; import pro.taskana.classification.api.exceptions.ClassificationNotFoundException;
import pro.taskana.common.api.BaseQuery.SortDirection; import pro.taskana.common.api.BaseQuery.SortDirection;
@ -288,6 +289,7 @@ public class TaskController {
* before. * before.
* *
* @param taskId the Id of the requested Task. * @param taskId the Id of the requested Task.
* @param keepOwner flag whether or not to keep the owner despite the cancel claim
* @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 InvalidTaskStateException if the Task is already in an end state. * @throws InvalidTaskStateException if the Task is already in an end state.
@ -298,12 +300,13 @@ public class TaskController {
*/ */
@DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM) @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<TaskRepresentationModel> cancelClaimTask(@PathVariable String taskId) public ResponseEntity<TaskRepresentationModel> cancelClaimTask(
@PathVariable String taskId, @RequestParam(defaultValue = "false") boolean keepOwner)
throws TaskNotFoundException, throws TaskNotFoundException,
InvalidTaskStateException, InvalidTaskStateException,
InvalidOwnerException, InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
Task updatedTask = taskService.cancelClaim(taskId); Task updatedTask = taskService.cancelClaim(taskId, keepOwner);
return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask));
} }
@ -312,6 +315,7 @@ public class TaskController {
* This endpoint force cancels the claim of an existing Task. * This endpoint force cancels the claim of an existing Task.
* *
* @param taskId the Id of the requested Task. * @param taskId the Id of the requested Task.
* @param keepOwner flag whether or not to keep the owner despite the cancel claim
* @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 InvalidTaskStateException if the Task is already in an end state. * @throws InvalidTaskStateException if the Task is already in an end state.
@ -322,12 +326,13 @@ public class TaskController {
*/ */
@DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM_FORCE) @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM_FORCE)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseEntity<TaskRepresentationModel> forceCancelClaimTask(@PathVariable String taskId) public ResponseEntity<TaskRepresentationModel> forceCancelClaimTask(
@PathVariable String taskId, @RequestParam(defaultValue = "false") boolean keepOwner)
throws TaskNotFoundException, throws TaskNotFoundException,
InvalidTaskStateException, InvalidTaskStateException,
InvalidOwnerException, InvalidOwnerException,
NotAuthorizedOnWorkbasketException { NotAuthorizedOnWorkbasketException {
Task updatedTask = taskService.forceCancelClaim(taskId); Task updatedTask = taskService.forceCancelClaim(taskId, keepOwner);
return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask));
} }

View File

@ -64,16 +64,12 @@ class TaskControllerIntTest {
@Autowired TaskanaConfiguration taskanaConfiguration; @Autowired TaskanaConfiguration taskanaConfiguration;
private static final ParameterizedTypeReference<TaskSummaryPagedRepresentationModel> private static final ParameterizedTypeReference<TaskSummaryPagedRepresentationModel>
TASK_SUMMARY_PAGE_MODEL_TYPE = new ParameterizedTypeReference<>() {}; TASK_SUMMARY_PAGE_MODEL_TYPE = new ParameterizedTypeReference<>() {};
private static final ParameterizedTypeReference<TaskSummaryCollectionRepresentationModel> private static final ParameterizedTypeReference<TaskSummaryCollectionRepresentationModel>
TASK_SUMMARY_COLLECTION_MODEL_TYPE = new ParameterizedTypeReference<>() {}; TASK_SUMMARY_COLLECTION_MODEL_TYPE = new ParameterizedTypeReference<>() {};
private static final ParameterizedTypeReference<TaskRepresentationModel> TASK_MODEL_TYPE = private static final ParameterizedTypeReference<TaskRepresentationModel> TASK_MODEL_TYPE =
ParameterizedTypeReference.forType(TaskRepresentationModel.class); ParameterizedTypeReference.forType(TaskRepresentationModel.class);
private final RestHelper restHelper; private final RestHelper restHelper;
private final DataSource dataSource; private final DataSource dataSource;
private final String schemaName; private final String schemaName;
@Autowired @Autowired
@ -2350,6 +2346,70 @@ class TaskControllerIntTest {
assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY); assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY);
} }
@Test
void should_KeepOwnerAndOwnerLongName_When_CancelClaimWithKeepOwner() {
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000000");
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
// retrieve task from Rest Api
ResponseEntity<TaskRepresentationModel> getTaskResponse =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE);
assertThat(getTaskResponse.getBody()).isNotNull();
TaskRepresentationModel taskRepresentationModel = getTaskResponse.getBody();
assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED);
assertThat(taskRepresentationModel.getOwner()).isEqualTo("user-1-1");
// cancel claim
String url2 =
restHelper.toUrl(
RestEndpoints.URL_TASKS_ID_CLAIM + "?keepOwner=true",
"TKI:000000000000000000000000000000000000");
ResponseEntity<TaskRepresentationModel> cancelClaimResponse =
TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE);
assertThat(cancelClaimResponse.getBody()).isNotNull();
assertThat(cancelClaimResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
TaskRepresentationModel cancelClaimedtaskRepresentationModel = cancelClaimResponse.getBody();
assertThat(cancelClaimedtaskRepresentationModel.getClaimed()).isNull();
assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY);
assertThat(cancelClaimedtaskRepresentationModel.getOwner()).isEqualTo("user-1-1");
assertThat(cancelClaimedtaskRepresentationModel.getOwnerLongName())
.isEqualTo("Mustermann, Max - (user-1-1)");
}
@Test
void should_KeepOwnerAndOwnerLongName_When_ForceCancelClaimWithKeepOwner() {
String url =
restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000001");
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
// retrieve task from Rest Api
ResponseEntity<TaskRepresentationModel> getTaskResponse =
TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE);
assertThat(getTaskResponse.getBody()).isNotNull();
TaskRepresentationModel taskRepresentationModel = getTaskResponse.getBody();
assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED);
assertThat(taskRepresentationModel.getOwner()).isEqualTo("user-1-1");
// cancel claim
String url2 =
restHelper.toUrl(
RestEndpoints.URL_TASKS_ID_CLAIM_FORCE + "?keepOwner=true",
"TKI:000000000000000000000000000000000001");
ResponseEntity<TaskRepresentationModel> cancelClaimResponse =
TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE);
assertThat(cancelClaimResponse.getBody()).isNotNull();
assertThat(cancelClaimResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
TaskRepresentationModel cancelClaimedtaskRepresentationModel = cancelClaimResponse.getBody();
assertThat(cancelClaimedtaskRepresentationModel.getClaimed()).isNull();
assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY);
assertThat(cancelClaimedtaskRepresentationModel.getOwner()).isEqualTo("user-1-1");
assertThat(cancelClaimedtaskRepresentationModel.getOwnerLongName())
.isEqualTo("Mustermann, Max - (user-1-1)");
}
@Test @Test
void should_ForceCancelClaim_When_TaskIsClaimedByDifferentOwner() { void should_ForceCancelClaim_When_TaskIsClaimedByDifferentOwner() {
String url = String url =

View File

@ -30,4 +30,5 @@ taskana.jobs.priority.task.enable=true
taskana.jobs.cleanup.workbasket.enable=true taskana.jobs.cleanup.workbasket.enable=true
taskana.jobs.refresh.user.enable=true taskana.jobs.refresh.user.enable=true
taskana.jobs.cleanup.history.simple.enable=false taskana.jobs.cleanup.history.simple.enable=false
taskana.user.addAdditionalUserInfo=true