TSK-1250 On demand deletion of historical data

This commit is contained in:
Joerg Heffner 2020-05-18 14:56:33 +02:00 committed by gitgoodjhe
parent eb480e4764
commit d8ad7a7fb9
69 changed files with 1526 additions and 298 deletions

View File

@ -32,6 +32,12 @@
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>pro.taskana</groupId>
<artifactId>taskana-data</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>

View File

@ -7,7 +7,7 @@ public class HistoryEventImpl extends TaskanaHistoryEvent {
public HistoryEventImpl() {}
public HistoryEventImpl(String userId, String details) {
super(userId, details);
public HistoryEventImpl(String id, String userId, String details) {
super(id, userId, details);
}
}

View File

@ -2,10 +2,14 @@ package pro.taskana.simplehistory.impl;
import java.sql.SQLException;
import java.time.Instant;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.common.api.TaskanaRole;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.simplehistory.impl.mappings.HistoryEventMapper;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.simplehistory.query.HistoryQuery;
@ -54,6 +58,32 @@ public class SimpleHistoryServiceImpl implements TaskanaHistory {
}
}
@Override
public void deleteHistoryEventsByTaskIds(List<String> taskIds)
throws InvalidArgumentException, NotAuthorizedException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("entry to deleteHistoryEventsByTaskIds(taskIds = {})", taskIds);
}
taskanaHistoryEngine.checkRoleMembership(TaskanaRole.ADMIN);
try {
taskanaHistoryEngine.openConnection();
if (taskIds == null) {
throw new InvalidArgumentException("List of taskIds must not be null.");
}
historyEventMapper.deleteMultipleByTaskIds(taskIds);
} catch (SQLException e) {
LOGGER.error("Caught exception while trying to delete history events", e);
} finally {
LOGGER.debug("exit from deleteHistoryEventsByTaskIds()");
taskanaHistoryEngine.returnConnection();
}
}
public TaskanaHistoryEvent getHistoryEvent(String historyEventId)
throws TaskanaHistoryEventNotFoundException {
LOGGER.debug("entry to getHistoryEvent (id = {})", historyEventId);

View File

@ -2,7 +2,10 @@ package pro.taskana.simplehistory.impl;
import java.sql.SQLException;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
@ -12,8 +15,13 @@ import org.apache.ibatis.session.SqlSessionManager;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.common.api.TaskanaRole;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.internal.security.CurrentUserContext;
import pro.taskana.simplehistory.TaskanaHistoryEngine;
import pro.taskana.simplehistory.impl.mappings.HistoryEventMapper;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
@ -23,7 +31,7 @@ import pro.taskana.spi.history.api.TaskanaHistory;
public class TaskanaHistoryEngineImpl implements TaskanaHistoryEngine {
protected static final ThreadLocal<Deque<SqlSessionManager>> SESSION_STACK = new ThreadLocal<>();
private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaHistoryEngineImpl.class);
private static final String DEFAULT = "default";
protected SqlSessionManager sessionManager;
protected TransactionFactory transactionFactory;
@ -52,6 +60,38 @@ public class TaskanaHistoryEngineImpl implements TaskanaHistoryEngine {
return this.taskanaHistoryService;
}
public boolean isUserInRole(TaskanaRole... roles) {
if (!getConfiguration().isSecurityEnabled()) {
return true;
}
Set<String> rolesMembers =
Arrays.stream(roles)
.map(role -> getConfiguration().getRoleMap().get(role))
.collect(HashSet::new, Set::addAll, Set::addAll);
return CurrentUserContext.getAccessIds().stream()
.anyMatch(rolesMembers::contains);
}
public void checkRoleMembership(TaskanaRole... roles) throws NotAuthorizedException {
if (!isUserInRole(roles)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Throwing NotAuthorizedException because accessIds {} are not member of roles {}",
CurrentUserContext.getAccessIds(),
Arrays.toString(roles));
}
throw new NotAuthorizedException(
"current user is not member of role(s) " + Arrays.toString(roles),
CurrentUserContext.getUserid());
}
}
public TaskanaEngineConfiguration getConfiguration() {
return this.taskanaEngineConfiguration;
}
protected SqlSessionManager createSqlSessionManager() {
Environment environment =
new Environment(

View File

@ -1,5 +1,7 @@
package pro.taskana.simplehistory.impl.mappings;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
@ -13,11 +15,11 @@ import pro.taskana.spi.history.api.events.TaskanaHistoryEvent;
public interface HistoryEventMapper {
@Insert(
"<script>INSERT INTO HISTORY_EVENTS (BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID,"
"<script>INSERT INTO HISTORY_EVENTS (ID,BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID,"
+ " EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY, POR_SYSTEM, POR_INSTANCE,"
+ " POR_TYPE, POR_VALUE, TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY, ATTACHMENT_CLASSIFICATION_KEY, "
+ " OLD_VALUE, NEW_VALUE, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, DETAILS)"
+ " VALUES ( #{historyEvent.businessProcessId}, #{historyEvent.parentBusinessProcessId}, #{historyEvent.taskId},"
+ " VALUES ( #{historyEvent.id}, #{historyEvent.businessProcessId}, #{historyEvent.parentBusinessProcessId}, #{historyEvent.taskId},"
+ " #{historyEvent.eventType}, #{historyEvent.created}, #{historyEvent.userId}, #{historyEvent.domain}, #{historyEvent.workbasketKey},"
+ " #{historyEvent.porCompany}, #{historyEvent.porSystem}, #{historyEvent.porInstance}, #{historyEvent.porType},"
+ " #{historyEvent.porValue}, #{historyEvent.taskClassificationKey}, #{historyEvent.taskClassificationCategory},"
@ -63,4 +65,9 @@ public interface HistoryEventMapper {
@Result(property = "details", column = "DETAILS")
})
TaskanaHistoryEvent findById(@Param("id") String id);
@Delete(
"<script>DELETE FROM HISTORY_EVENTS WHERE TASK_ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)</script>")
void deleteMultipleByTaskIds(@Param("taskIds") List<String> taskIds);
}

View File

@ -1,27 +1,39 @@
package acceptance;
import configuration.DbWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Objects;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.session.SqlSessionManager;
import org.junit.jupiter.api.BeforeAll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
import pro.taskana.common.internal.util.IdGenerator;
import pro.taskana.sampledata.SampleDataGenerator;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.TaskanaHistoryEngineImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
/** Set up database for tests. */
public abstract class AbstractAccTest {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAccTest.class);
private static final String ID_PREFIX_HISTORY_EVENT = "HEI";
protected static TaskanaEngineConfiguration taskanaEngineConfiguration;
protected static TaskanaHistoryEngineImpl taskanaHistoryEngine;
protected static TaskanaEngine taskanaEngine;
private static final String USER_HOME_DIRECTORY = System.getProperty("user.home");
private static final int POOL_TIME_TO_WAIT = 50;
@ -72,17 +84,20 @@ public abstract class AbstractAccTest {
protected static void resetDb(String schemaName) throws Exception {
DataSource dataSource = getDataSource();
TaskanaEngineConfiguration taskanaEngineConfiguration =
taskanaEngineConfiguration =
new TaskanaEngineConfiguration(
dataSource,
false,
schemaName != null && !schemaName.isEmpty() ? schemaName : getSchemaName());
taskanaHistoryEngine = TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngineConfiguration);
taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine();
taskanaEngine.setConnectionManagementMode(ConnectionManagementMode.AUTOCOMMIT);
historyService = new SimpleHistoryServiceImpl();
historyService.initialize(taskanaEngineConfiguration);
DbWriter writer = new DbWriter();
writer.clearDB(dataSource);
writer.generateTestData(dataSource);
SampleDataGenerator sampleDataGenerator = new SampleDataGenerator(dataSource, getSchemaName());
sampleDataGenerator.clearDb();
sampleDataGenerator.generateTestData();
}
protected static DataSource getDataSource() {
@ -117,6 +132,12 @@ public abstract class AbstractAccTest {
protected static SimpleHistoryServiceImpl getHistoryService() {
return historyService;
* @param id the id of the event
String id,
HistoryEventImpl historyEvent =
new HistoryEventImpl(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT), userid, details);
historyEvent.setId(id);
}
@BeforeAll
@ -236,4 +257,15 @@ public abstract class AbstractAccTest {
return schemaName;
}
protected HistoryQueryMapper getHistoryQueryMapper()
throws NoSuchFieldException, IllegalAccessException {
Field sessionManagerField = TaskanaHistoryEngineImpl.class.getDeclaredField("sessionManager");
sessionManagerField.setAccessible(true);
SqlSessionManager sqlSessionManager =
(SqlSessionManager) sessionManagerField.get(taskanaHistoryEngine);
return sqlSessionManager.getMapper(HistoryQueryMapper.class);
}
}

View File

@ -0,0 +1,60 @@
package acceptance.events;
import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import acceptance.security.JaasExtension;
import acceptance.security.WithAccessId;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.HistoryQueryImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.TaskState;
import pro.taskana.task.api.models.Task;
@ExtendWith(JaasExtension.class)
class CreateHistoryEventOnCancelClaimAccTest extends AbstractAccTest {
private TaskService taskService;
private SimpleHistoryServiceImpl historyService;
@BeforeEach
public void setUp() {
taskService = taskanaEngine.getTaskService();
historyService = getHistoryService();
}
@WithAccessId(user = "admin")
@Test
void should_CreateCancelClaimedHistoryEvent_When_TaskIsCancelClaimed() throws Exception {
final String taskId = "TKI:000000000000000000000000000000000043";
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(0);
assertThat(taskService.getTask(taskId).getState()).isEqualTo(TaskState.CLAIMED);
Task task = taskService.forceCancelClaim(taskId);
assertThat(task.getState()).isEqualTo(TaskState.READY);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(1);
assertThat(historyService.getHistoryEvent(listEvents.get(0).getId()).getEventType())
.isEqualTo("TASK_CLAIM_CANCELLED");
}
}

View File

@ -0,0 +1,60 @@
package acceptance.events;
import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import acceptance.security.JaasExtension;
import acceptance.security.WithAccessId;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.HistoryQueryImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.TaskState;
import pro.taskana.task.api.models.Task;
@ExtendWith(JaasExtension.class)
class CreateHistoryEventOnClaimAccTest extends AbstractAccTest {
private TaskService taskService;
private SimpleHistoryServiceImpl historyService;
@BeforeEach
public void setUp() {
taskService = taskanaEngine.getTaskService();
historyService = getHistoryService();
}
@WithAccessId(user = "admin")
@Test
void should_CreateClaimedHistoryEvent_When_TaskIsClaimed() throws Exception {
final String taskId = "TKI:000000000000000000000000000000000047";
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(0);
assertThat(taskService.getTask(taskId).getState()).isEqualTo(TaskState.READY);
Task task = taskService.claim(taskId);
assertThat(task.getState()).isEqualTo(TaskState.CLAIMED);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(1);
assertThat(historyService.getHistoryEvent(listEvents.get(0).getId()).getEventType())
.isEqualTo("TASK_CLAIMED");
}
}

View File

@ -0,0 +1,58 @@
package acceptance.events;
import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import acceptance.security.JaasExtension;
import acceptance.security.WithAccessId;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.HistoryQueryImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.TaskState;
@ExtendWith(JaasExtension.class)
class CreateHistoryEventOnCompletionAccTest extends AbstractAccTest {
private TaskService taskService;
private SimpleHistoryServiceImpl historyService;
@BeforeEach
public void setUp() {
taskService = taskanaEngine.getTaskService();
historyService = getHistoryService();
}
@WithAccessId(user = "admin")
@Test
void should_CreateCompletedHistoryEvent_When_TaskIsCompleted() throws Exception {
final String taskId = "TKI:000000000000000000000000000000000001";
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(0);
assertThat(taskService.getTask(taskId).getState()).isEqualTo(TaskState.CLAIMED);
taskService.forceCompleteTask(taskId);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(1);
assertThat(historyService.getHistoryEvent(listEvents.get(0).getId()).getEventType())
.isEqualTo("TASK_COMPLETED");
}
}

View File

@ -0,0 +1,65 @@
package acceptance.events;
import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import acceptance.security.JaasExtension;
import acceptance.security.WithAccessId;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.HistoryQueryImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.models.ObjectReference;
import pro.taskana.task.internal.models.TaskImpl;
@ExtendWith(JaasExtension.class)
class CreateHistoryEventOnTaskCreationAccTest extends AbstractAccTest {
private TaskService taskService;
private SimpleHistoryServiceImpl historyService;
@BeforeEach
public void setUp() {
taskService = taskanaEngine.getTaskService();
historyService = getHistoryService();
}
protected ObjectReference createObjectRef(
String company, String system, String systemInstance, String type, String value) {
ObjectReference objectRef = new ObjectReference();
objectRef.setCompany(company);
objectRef.setSystem(system);
objectRef.setSystemInstance(systemInstance);
objectRef.setType(type);
objectRef.setValue(value);
return objectRef;
}
@Test
@WithAccessId(user = "admin")
void should_CreateCreatedHistoryEvent_When_TaskIsCreated() throws Exception {
TaskImpl newTask = (TaskImpl) taskService.newTask("WBI:100000000000000000000000000000000006");
newTask.setClassificationKey("T2100");
ObjectReference objectReference =
createObjectRef("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567");
newTask.setPrimaryObjRef(objectReference);
taskService.createTask(newTask);
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(newTask.getId()));
assertThat(listEvents).hasSize(1);
assertThat(listEvents.get(0).getEventType()).isEqualTo("TASK_CREATED");
}
}

View File

@ -0,0 +1,60 @@
package acceptance.events;
import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import acceptance.security.JaasExtension;
import acceptance.security.WithAccessId;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.HistoryQueryImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.models.Task;
@ExtendWith(JaasExtension.class)
class CreateHistoryEventOnTaskUpdateAccTest extends AbstractAccTest {
private TaskService taskService;
private SimpleHistoryServiceImpl historyService;
@BeforeEach
public void setUp() {
taskService = taskanaEngine.getTaskService();
historyService = getHistoryService();
}
@Test
@WithAccessId(user = "admin")
void should_CreateUpdatedHistoryEvent_When_TaskIsCreated() throws Exception {
final String taskId = "TKI:000000000000000000000000000000000000";
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(2);
Task task = taskService.getTask(taskId);
task.setName("someUpdatedName");
taskService.updateTask(task);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(3);
assertThat(listEvents.get(2).getEventType()).isEqualTo("TASK_UPDATED");
assertThat(historyService.getHistoryEvent(listEvents.get(2).getId()).getDetails())
.contains("someUpdatedName");
}
}

View File

@ -0,0 +1,56 @@
package acceptance.events;
import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import acceptance.security.JaasExtension;
import acceptance.security.WithAccessId;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.HistoryQueryImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.task.api.TaskService;
@ExtendWith(JaasExtension.class)
class CreateHistoryEventOnTransferAccTest extends AbstractAccTest {
private TaskService taskService;
private SimpleHistoryServiceImpl historyService;
@BeforeEach
public void setUp() {
taskService = taskanaEngine.getTaskService();
historyService = getHistoryService();
}
@WithAccessId(user = "admin")
@Test
void should_CreateTransferredHistoryEvent_When_TaskIstransferred() throws Exception {
final String taskId = "TKI:000000000000000000000000000000000003";
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(0);
taskService.transfer(taskId, "WBI:100000000000000000000000000000000006");
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(1);
assertThat(historyService.getHistoryEvent(listEvents.get(0).getId()).getEventType())
.isEqualTo("TASK_TRANSFERRED");
}
}

View File

@ -0,0 +1,173 @@
package acceptance.events;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import acceptance.AbstractAccTest;
import acceptance.security.JaasExtension;
import acceptance.security.WithAccessId;
import java.util.Arrays;
import java.util.List;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryEventImpl;
import pro.taskana.simplehistory.impl.HistoryQueryImpl;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.exceptions.TaskNotFoundException;
@ExtendWith(JaasExtension.class)
class DeleteHistoryEventsOnTaskDeletionAccTest extends AbstractAccTest {
private TaskService taskService;
private SimpleHistoryServiceImpl historyService;
@BeforeEach
public void setUp() {
taskService = taskanaEngine.getTaskService();
historyService = getHistoryService();
}
@Test
@WithAccessId(user = "admin")
void should_deleteHistoryEvents_When_TaskIsDeleted_With_HistoryDeletionEnabled()
throws Exception {
final String taskid = "TKI:000000000000000000000000000000000036";
taskanaEngineConfiguration.setDeleteHistoryOnTaskDeletionEnabled(true);
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskid));
assertThat(listEvents).hasSize(2);
taskService.deleteTask(taskid);
// make sure the task got deleted
ThrowingCallable getDeletedTaskCall =
() -> {
taskService.getTask(taskid);
};
assertThatThrownBy(getDeletedTaskCall).isInstanceOf(TaskNotFoundException.class);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskid));
assertThat(listEvents).hasSize(0);
}
@Test
@WithAccessId(user = "admin")
void should_deleteHistoryEvents_When_TasksAreDeleted_With_HistoryDeletionEnabled()
throws Exception {
final String taskId_1 = "TKI:000000000000000000000000000000000037";
final String taskId_2 = "TKI:000000000000000000000000000000000038";
taskanaEngineConfiguration.setDeleteHistoryOnTaskDeletionEnabled(true);
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId_1, taskId_2));
assertThat(listEvents).hasSize(3);
taskService.deleteTasks(Arrays.asList(taskId_1, taskId_2));
// make sure the tasks got deleted
ThrowingCallable getDeletedTaskCall =
() -> {
taskService.getTask(taskId_1);
};
ThrowingCallable getDeletedTaskCall2 =
() -> {
taskService.getTask(taskId_2);
};
assertThatThrownBy(getDeletedTaskCall).isInstanceOf(TaskNotFoundException.class);
assertThatThrownBy(getDeletedTaskCall2).isInstanceOf(TaskNotFoundException.class);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId_1, taskId_2));
assertThat(listEvents).hasSize(0);
}
@Test
@WithAccessId(user = "admin")
void should_notDeleteHistoryEvents_When_TaskIsDeleted_With_HistoryDeletionDisabled()
throws Exception {
final String taskId = "TKI:000000000000000000000000000000000039";
taskanaEngineConfiguration.setDeleteHistoryOnTaskDeletionEnabled(false);
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(2);
taskService.deleteTask(taskId);
// make sure the task got deleted
ThrowingCallable getDeletedTaskCall =
() -> {
taskService.getTask(taskId);
};
assertThatThrownBy(getDeletedTaskCall).isInstanceOf(TaskNotFoundException.class);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId));
assertThat(listEvents).hasSize(2);
}
@Test
@WithAccessId(user = "admin")
void should_notDeleteHistoryEvents_When_TasksAreDeleted_With_HistoryDeletionDisabled()
throws Exception {
final String taskId_1 = "TKI:000000000000000000000000000000000040";
final String taskId_2 = "TKI:000000000000000000000000000000000068";
taskanaEngineConfiguration.setDeleteHistoryOnTaskDeletionEnabled(false);
HistoryQueryMapper historyQueryMapper = getHistoryQueryMapper();
List<HistoryEventImpl> listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId_1, taskId_2));
assertThat(listEvents).hasSize(2);
taskService.deleteTasks(Arrays.asList(taskId_1, taskId_2));
// make sure the tasks got deleted
ThrowingCallable getDeletedTaskCall =
() -> {
taskService.getTask(taskId_1);
};
ThrowingCallable getDeletedTaskCall2 =
() -> {
taskService.getTask(taskId_2);
};
assertThatThrownBy(getDeletedTaskCall).isInstanceOf(TaskNotFoundException.class);
assertThatThrownBy(getDeletedTaskCall2).isInstanceOf(TaskNotFoundException.class);
listEvents =
historyQueryMapper.queryHistoryEvent(
(HistoryQueryImpl) historyService.createHistoryQuery().taskIdIn(taskId_1, taskId_2));
assertThat(listEvents).hasSize(2);
}
}

View File

@ -7,10 +7,11 @@ import org.junit.jupiter.api.Test;
import pro.taskana.spi.history.api.events.TaskanaHistoryEvent;
class GetHistoryEventAccTest extends AbstractAccTest {
@Test
void should_ReturnSpecificTaskHistoryEventWithDetails_For_HistoryEventId() throws Exception {
void should_ReturnSpecificTaskHistoryEventWithDetails_For_HistoryEventId()
String detailsJson =
"{\"changes\":[{"
@ -21,7 +22,8 @@ class GetHistoryEventAccTest extends AbstractAccTest {
+ "\"fieldName\":\"owner\","
+ "\"oldValue\":\"owner1\"}]}";
TaskanaHistoryEvent taskHistoryEvent = getHistoryService().getHistoryEvent("4");
TaskanaHistoryEvent taskHistoryEvent =
getHistoryService().getHistoryEvent("HEI:000000000000000000000000000000000000");
assertThat(taskHistoryEvent.getBusinessProcessId()).isEqualTo("BPI:01");
assertThat(taskHistoryEvent.getUserId()).isEqualTo("admin");
assertThat(taskHistoryEvent.getEventType()).isEqualTo("TASK_UPDATED");

View File

@ -31,7 +31,7 @@ class QueryHistoryAccTest extends AbstractAccTest {
.createHistoryQuery()
.listValues(HistoryQueryColumnName.CREATED, SortDirection.ASCENDING);
assertThat(ascendingList).hasSize(2);
assertThat(ascendingList).hasSize(13);
assertThat(ascendingList).isEqualTo(defaultList);
List<String> descendingList =
@ -55,12 +55,12 @@ class QueryHistoryAccTest extends AbstractAccTest {
List<HistoryEventImpl> results = query.list();
assertThat(results)
.extracting(TaskanaHistoryEvent::getUserId)
.containsExactly("admin", "peter");
.containsOnly("admin", "peter");
results = query.orderByUserId(SortDirection.DESCENDING).list();
assertThat(results)
.extracting(TaskanaHistoryEvent::getUserId)
.containsExactly("admin", "peter");
assertThat(query.domainLike().count()).isEqualTo(3);
.containsOnly("admin", "peter");
assertThat(query.domainLike().count()).isEqualTo(13);
}
@Test
@ -76,7 +76,7 @@ class QueryHistoryAccTest extends AbstractAccTest {
@Test
void should_ReturnEmptyList_When_ProvidingWrongContraints() {
List<HistoryEventImpl> result = getHistoryService().createHistoryQuery().list(1, 1000);
assertThat(result).hasSize(2);
assertThat(result).hasSize(12);
result = getHistoryService().createHistoryQuery().list(100, 1000);
assertThat(result).isEmpty();
@ -94,10 +94,10 @@ class QueryHistoryAccTest extends AbstractAccTest {
@Test
void should_ReturnCountOfEvents_When_UsingCountMethod() {
long count = getHistoryService().createHistoryQuery().userIdIn("peter").count();
assertThat(count).isOne();
assertThat(count).isEqualTo(6);
count = getHistoryService().createHistoryQuery().count();
assertThat(count).isEqualTo(3);
assertThat(count).isEqualTo(13);
count = getHistoryService().createHistoryQuery().userIdIn("klaus", "arnold", "benni").count();
assertThat(count).isZero();
@ -107,11 +107,11 @@ class QueryHistoryAccTest extends AbstractAccTest {
void should_ReturnHistoryEvents_For_DifferentInAttributes() {
List<HistoryEventImpl> returnValues =
getHistoryService().createHistoryQuery().businessProcessIdIn("BPI:01", "BPI:02").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues =
getHistoryService().createHistoryQuery().parentBusinessProcessIdIn("BPI:01").list();
assertThat(returnValues).hasSize(1);
assertThat(returnValues).hasSize(6);
returnValues =
getHistoryService()
@ -121,63 +121,63 @@ class QueryHistoryAccTest extends AbstractAccTest {
assertThat(returnValues).hasSize(2);
returnValues = getHistoryService().createHistoryQuery().eventTypeIn("TASK_CREATED").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(12);
TimeInterval timeInterval = new TimeInterval(Instant.now().minusSeconds(10), Instant.now());
returnValues = getHistoryService().createHistoryQuery().createdWithin(timeInterval).list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(0);
returnValues = getHistoryService().createHistoryQuery().userIdIn("admin").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues = getHistoryService().createHistoryQuery().domainIn("DOMAIN_A").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(12);
returnValues =
getHistoryService()
.createHistoryQuery()
.workbasketKeyIn("WBI:100000000000000000000000000000000001")
.list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues = getHistoryService().createHistoryQuery().porCompanyIn("00").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues = getHistoryService().createHistoryQuery().porSystemIn("PASystem").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues = getHistoryService().createHistoryQuery().porInstanceIn("22").list();
assertThat(returnValues).hasSize(1);
assertThat(returnValues).hasSize(6);
returnValues = getHistoryService().createHistoryQuery().porTypeIn("VN").list();
assertThat(returnValues).isEmpty();
returnValues = getHistoryService().createHistoryQuery().porValueIn("11223344").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues =
getHistoryService().createHistoryQuery().taskClassificationKeyIn("L140101").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues =
getHistoryService().createHistoryQuery().taskClassificationCategoryIn("TASK").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues =
getHistoryService()
.createHistoryQuery()
.attachmentClassificationKeyIn("DOCTYPE_DEFAULT")
.list();
assertThat(returnValues).hasSize(1);
assertThat(returnValues).hasSize(6);
returnValues = getHistoryService().createHistoryQuery().custom1In("custom1").list();
assertThat(returnValues).hasSize(3);
assertThat(returnValues).hasSize(13);
returnValues = getHistoryService().createHistoryQuery().custom2In("custom2").list();
assertThat(returnValues).hasSize(1);
returnValues = getHistoryService().createHistoryQuery().custom3In("custom3").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
returnValues = getHistoryService().createHistoryQuery().custom4In("custom4").list();
assertThat(returnValues).hasSize(1);
@ -192,35 +192,35 @@ class QueryHistoryAccTest extends AbstractAccTest {
assertThat(returnValues).hasSize(1);
returnValues = getHistoryService().createHistoryQuery().newValueLike("new_%").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
}
@Test
void should_ReturnHistoryEvents_For_DifferentLikeAttributes() {
List<HistoryEventImpl> returnValues =
getHistoryService().createHistoryQuery().businessProcessIdLike("BPI:0%").list();
assertThat(returnValues).hasSize(3);
assertThat(returnValues).hasSize(13);
returnValues =
getHistoryService().createHistoryQuery().parentBusinessProcessIdLike("BPI:01", " %").list();
assertThat(returnValues).hasSize(1);
assertThat(returnValues).hasSize(6);
returnValues =
getHistoryService().createHistoryQuery().taskIdLike("TKI:000000000000000%").list();
assertThat(returnValues).hasSize(3);
assertThat(returnValues).hasSize(13);
returnValues = getHistoryService().createHistoryQuery().oldValueLike("old%").list();
assertThat(returnValues).hasSize(1);
returnValues = getHistoryService().createHistoryQuery().newValueLike("new_%").list();
assertThat(returnValues).hasSize(2);
assertThat(returnValues).hasSize(7);
}
@Test
void should_ReturnHistoryEvents_When_ProvidingListValues() {
List<String> returnedList =
getHistoryService().createHistoryQuery().listValues(HistoryQueryColumnName.ID, null);
assertThat(returnedList).hasSize(3);
assertThat(returnedList).hasSize(13);
returnedList =
getHistoryService()
@ -236,7 +236,7 @@ class QueryHistoryAccTest extends AbstractAccTest {
returnedList =
getHistoryService().createHistoryQuery().listValues(HistoryQueryColumnName.TASK_ID, null);
assertThat(returnedList).hasSize(2);
assertThat(returnedList).hasSize(7);
returnedList =
getHistoryService()
@ -246,7 +246,7 @@ class QueryHistoryAccTest extends AbstractAccTest {
returnedList =
getHistoryService().createHistoryQuery().listValues(HistoryQueryColumnName.CREATED, null);
assertThat(returnedList).hasSize(2);
assertThat(returnedList).hasSize(13);
returnedList =
getHistoryService().createHistoryQuery().listValues(HistoryQueryColumnName.USER_ID, null);

View File

@ -0,0 +1,329 @@
package acceptance.security;
import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
import static pro.taskana.common.internal.util.CheckedFunction.wrap;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.security.auth.Subject;
import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
import org.junit.platform.commons.JUnitException;
import org.junit.platform.commons.support.AnnotationSupport;
import pro.taskana.common.api.exceptions.SystemException;
import pro.taskana.common.internal.security.GroupPrincipal;
import pro.taskana.common.internal.security.UserPrincipal;
/** Runner for integration tests that enables JAAS subject. */
public class JaasExtension implements InvocationInterceptor, TestTemplateInvocationContextProvider {
private static final String ACCESS_IDS_STORE_KEY = "accessIds";
// region InvocationInterceptor
@Override
public <T> T interceptTestClassConstructor(
Invocation<T> invocation,
ReflectiveInvocationContext<Constructor<T>> invocationContext,
ExtensionContext extensionContext) {
return extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
@Override
public void interceptBeforeAllMethod(
Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
@Override
public void interceptBeforeEachMethod(
Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
@Override
public void interceptTestMethod(
Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
if (isAnnotated(invocationContext.getExecutable(), WithAccessIds.class)) {
throw new JUnitException("Please use @TestTemplate instead of @Test for multiple accessIds");
}
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
@Override
@SuppressWarnings("unchecked")
public <T> T interceptTestFactoryMethod(
Invocation<T> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
WithAccessIds annotation = invocationContext.getExecutable().getAnnotation(
WithAccessIds.class);
if (annotation != null) {
// our goal is to run each test returned from the test factory X times. X is the amount of
// WithAccessId annotations. In order to achieve this we are wrapping the result from the
// factory (the returning tests) in a dynamicContainer for each accessId. Since we don't know
// what the factory will return we have to check for every possible return type. All possible
// return types can be found here:
// https://junit.org/junit5/docs/current/user-guide/#writing-tests-dynamic-tests
// After checking each return type we abuse the return type of T and hardly change it to
// Stream<DynamicContainer> no matter what the factory returns. This return type is allowed
// per definition (See link above), but is not the type T. Hence we have an unchecked cast at
// the end to keep the compiler happy...
// we are using the first annotation to run the factory method with.
T factoryResult = performInvocationWithAccessId(invocation, annotation.value()[0]);
Iterable<DynamicNode> newChildrenForDynamicContainer;
// TestFactory must have one of the following return types. See link above for further details
if (factoryResult instanceof DynamicNode) {
newChildrenForDynamicContainer = Collections.singleton((DynamicNode) factoryResult);
} else if (factoryResult instanceof Stream) {
Stream<DynamicNode> nodes = (Stream<DynamicNode>) factoryResult;
newChildrenForDynamicContainer = nodes.collect(Collectors.toList());
} else if (factoryResult instanceof Iterable) {
newChildrenForDynamicContainer = (Iterable<DynamicNode>) factoryResult;
} else if (factoryResult instanceof Iterator) {
newChildrenForDynamicContainer = () -> (Iterator<DynamicNode>) factoryResult;
} else if (factoryResult instanceof DynamicNode[]) {
newChildrenForDynamicContainer = Arrays.asList((DynamicNode[]) factoryResult);
} else {
throw new SystemException(
String.format(
"Testfactory '%s' did not return a proper type",
invocationContext.getExecutable().getName()));
}
// Currently a DynamicContainer has children from this type: Stream<DynamicNode>
// Because of this the children can only be extracted once (Streams can only be operated
// once). This is obviously not ok since we want to execute each node X times. So we have to
// manually persist all children recursively to extract them X times...
Map<String, List<DynamicNode>> childrenMap = new HashMap<>();
persistDynamicContainerChildren(newChildrenForDynamicContainer, childrenMap);
Function<WithAccessId, DynamicContainer> wrapTestsInDynamicContainer =
accessId ->
DynamicContainer.dynamicContainer(
getDisplayNameForAccessId(accessId),
StreamSupport.stream(newChildrenForDynamicContainer.spliterator(), false)
.map(x -> duplicateDynamicNode(x, childrenMap)));
Store store = getStore(extensionContext);
return (T)
Stream.of(annotation.value())
.peek(a -> store.put(ACCESS_IDS_STORE_KEY, a))
.map(wrapTestsInDynamicContainer);
}
return extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
@Override
public void interceptTestTemplateMethod(
Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
WithAccessId accessId =
getStore(extensionContext).get(ACCESS_IDS_STORE_KEY, WithAccessId.class);
performInvocationWithAccessId(invocation, accessId);
}
@Override
public void interceptDynamicTest(Invocation<Void> invocation, ExtensionContext extensionContext) {
ExtensionContext testContext = getParentMethodExtensionContent(extensionContext);
// Check if the test factory provided an access Id for this dynamic test.
WithAccessId o = getStore(testContext).get(ACCESS_IDS_STORE_KEY, WithAccessId.class);
if (o != null) {
performInvocationWithAccessId(invocation, o);
} else {
extractAccessIdAndPerformInvocation(invocation, testContext.getRequiredTestMethod());
}
}
@Override
public void interceptAfterEachMethod(
Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
@Override
public void interceptAfterAllMethod(
Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) {
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
// endregion
// region TestTemplateInvocationContextProvider
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return isAnnotated(context.getElement(), WithAccessIds.class)
|| isAnnotated(context.getElement(), WithAccessId.class);
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(
ExtensionContext context) {
List<WithAccessId> accessIds =
AnnotationSupport.findRepeatableAnnotations(context.getElement(), WithAccessId.class);
Store store = getStore(context);
return accessIds.stream()
.peek(a -> store.put(ACCESS_IDS_STORE_KEY, a))
.map(JaasExtensionInvocationContext::new);
}
// endregion
private static void persistDynamicContainerChildren(
Iterable<DynamicNode> nodes, Map<String, List<DynamicNode>> childrenMap) {
nodes.forEach(
node -> {
if (node instanceof DynamicContainer) {
DynamicContainer container = (DynamicContainer) node;
List<DynamicNode> children = container.getChildren().collect(Collectors.toList());
childrenMap.put(container.hashCode() + container.getDisplayName(), children);
persistDynamicContainerChildren(children, childrenMap);
}
});
}
private static DynamicNode duplicateDynamicNode(
DynamicNode node, Map<String, List<DynamicNode>> lookupMap) {
if (node instanceof DynamicContainer) {
DynamicContainer container = (DynamicContainer) node;
Stream<DynamicNode> children =
lookupMap.get(node.hashCode() + node.getDisplayName()).stream()
.map(x -> duplicateDynamicNode(x, lookupMap));
return DynamicContainer.dynamicContainer(container.getDisplayName(), children);
}
return node;
}
private static <T> T extractAccessIdAndPerformInvocation(
Invocation<T> invocation, AnnotatedElement executable) {
return performInvocationWithAccessId(invocation, executable.getAnnotation(
WithAccessId.class));
}
private static <T> T performInvocationWithAccessId(
Invocation<T> invocation, WithAccessId withAccessId) {
Subject subject = new Subject();
subject.getPrincipals().addAll(getPrincipals(withAccessId));
Function<Invocation<T>, T> proceedInvocation = wrap(Invocation::proceed);
PrivilegedAction<T> performInvocation = () -> proceedInvocation.apply(invocation);
return Subject.doAs(subject, performInvocation);
}
private static List<Principal> getPrincipals(
WithAccessId withAccessId) {
if (withAccessId != null) {
return Stream.concat(
Stream.of(withAccessId.user()).map(UserPrincipal::new),
Arrays.stream(withAccessId.groups()).map(GroupPrincipal::new))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
private ExtensionContext getParentMethodExtensionContent(ExtensionContext extensionContext) {
Optional<ExtensionContext> parent = extensionContext.getParent();
// the class MethodExtensionContext is part of junit-jupiter-engine and has only a
// package-private visibility thus this workaround is needed.
while (!parent
.map(Object::getClass)
.map(Class::getName)
.filter(s -> s.endsWith("MethodExtensionContext"))
.isPresent()) {
parent = parent.flatMap(ExtensionContext::getParent);
}
return parent.orElseThrow(
() ->
new JUnitException(
String.format(
"Test '%s' does not have a parent method", extensionContext.getUniqueId())));
}
/**
* Gets the store with a <b>method-level</b> scope.
*
* @param context context for current extension
* @return The store
*/
private Store getStore(ExtensionContext context) {
return context.getStore(Namespace.create(getClass(), context.getRequiredTestMethod()));
}
private static String getDisplayNameForAccessId(
WithAccessId withAccessId) {
return String.format("for user '%s'", withAccessId.user());
}
private static class JaasExtensionInvocationContext implements TestTemplateInvocationContext {
private final WithAccessId withAccessId;
private JaasExtensionInvocationContext(
WithAccessId withAccessId) {
this.withAccessId = withAccessId;
}
@Override
public String getDisplayName(int invocationIndex) {
return getDisplayNameForAccessId(withAccessId);
}
@Override
public List<Extension> getAdditionalExtensions() {
return Collections.singletonList(new WithAccessIdParameterResolver());
}
private class WithAccessIdParameterResolver implements ParameterResolver {
@Override
public boolean supportsParameter(
ParameterContext parameterContext, ExtensionContext extensionContext) {
return parameterContext.getParameter().getType().equals(WithAccessId.class);
}
@Override
public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext) {
return withAccessId;
}
}
}
}

View File

@ -0,0 +1,17 @@
package acceptance.security;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Repeatable(WithAccessIds.class)
public @interface WithAccessId {
String user();
String[] groups() default {};
}

View File

@ -0,0 +1,12 @@
package acceptance.security;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface WithAccessIds {
WithAccessId[] value();
}

View File

@ -1,70 +0,0 @@
package configuration;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Set up the database's writer and generates data for tests. */
public class DbWriter {
private static final Logger LOGGER = LoggerFactory.getLogger(DbWriter.class);
private static final String INSERTVALUES = "/sql/history-events.sql";
private StringWriter outWriter = new StringWriter();
private PrintWriter logWriter;
private StringWriter errorWriter;
private PrintWriter errorLogWriter;
public DbWriter() {
this.logWriter = new PrintWriter(this.outWriter);
this.errorWriter = new StringWriter();
this.errorLogWriter = new PrintWriter(this.errorWriter);
}
public void generateTestData(DataSource dataSource) throws SQLException {
ScriptRunner runner = null;
try (Connection connection = dataSource.getConnection()) {
runner = configScriptRunner(connection);
runner.runScript(
new InputStreamReader(
DbWriter.class.getResourceAsStream(INSERTVALUES), StandardCharsets.UTF_8));
} finally {
LOGGER.debug(outWriter.toString());
if (!errorWriter.toString().trim().isEmpty()) {
LOGGER.error(errorWriter.toString());
}
}
}
public void clearDB(DataSource dataSource) throws SQLException {
ScriptRunner runner = null;
try (Connection connection = dataSource.getConnection()) {
runner = configScriptRunner(connection);
runner.runScript(new StringReader("DELETE FROM HISTORY_EVENTS;"));
} finally {
LOGGER.debug(outWriter.toString());
if (!errorWriter.toString().trim().isEmpty()) {
LOGGER.error(errorWriter.toString());
}
}
}
private ScriptRunner configScriptRunner(Connection connection) throws SQLException {
LOGGER.debug(connection.getMetaData().toString());
ScriptRunner runner = new ScriptRunner(connection);
runner.setStopOnError(true);
runner.setLogWriter(this.logWriter);
runner.setErrorLogWriter(this.errorLogWriter);
runner.setStopOnError(true);
runner.setLogWriter(this.logWriter);
runner.setErrorLogWriter(this.errorLogWriter);
return runner;
}
}

View File

@ -20,7 +20,7 @@ class TaskanaEngineConfigurationTest extends AbstractAccTest {
void testCreateTaskanaEngine() throws Exception {
DataSource ds = getDataSource();
TaskanaEngineConfiguration taskEngineConfiguration =
new TaskanaEngineConfiguration(ds, false, getSchemaName());
new TaskanaEngineConfiguration(ds, false, false, getSchemaName());
TaskanaEngine te = taskEngineConfiguration.buildTaskanaEngine();
@ -35,7 +35,13 @@ class TaskanaEngineConfigurationTest extends AbstractAccTest {
getHistoryService()
.create(
AbstractAccTest.createHistoryEvent(
"wbKey1", "taskId1", "type1", "Some comment", "wbKey2", "someUserId"));
"HEI:000000000000000000000000000000000000",
"wbKey1",
"taskId1",
"type1",
"Some comment",
"wbKey2",
"someUserId"));
count = getHistoryService().createHistoryQuery().workbasketKeyIn("wbKey1").count();
assertThat(count).isOne();
}

View File

@ -15,6 +15,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import pro.taskana.common.api.TimeInterval;
import pro.taskana.common.internal.util.IdGenerator;
import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
/**
@ -25,6 +26,8 @@ import pro.taskana.simplehistory.impl.mappings.HistoryQueryMapper;
@ExtendWith(MockitoExtension.class)
class HistoryQueryImplTest {
private static final String ID_PREFIX_HISTORY_EVENT = "HEI";
private HistoryQueryImpl historyQueryImpl;
@Mock private TaskanaHistoryEngineImpl taskanaHistoryEngineMock;
@ -66,7 +69,9 @@ class HistoryQueryImplTest {
String userId,
String details,
Instant created) {
HistoryEventImpl he = new HistoryEventImpl(userId, details);
HistoryEventImpl he =
new HistoryEventImpl(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT), userId, details);
he.setTaskId(taskId);
he.setWorkbasketKey(workbasketKey);
he.setEventType(type);

View File

@ -56,7 +56,13 @@ class SimpleHistoryServiceImplTest {
void testCreateEvent() throws Exception {
HistoryEventImpl expectedWb =
AbstractAccTest.createHistoryEvent(
"wbKey1", "taskId1", "type1", "wbKey2", "someUserId", "someDetails");
"HEI:000000000000000000000000000000000000",
"wbKey1",
"taskId1",
"type1",
"wbKey2",
"someUserId",
"someDetails");
cutSpy.create(expectedWb);
verify(taskanaHistoryEngineMock, times(1)).openConnection();
@ -70,7 +76,13 @@ class SimpleHistoryServiceImplTest {
List<HistoryEventImpl> returnList = new ArrayList<>();
returnList.add(
AbstractAccTest.createHistoryEvent(
"wbKey1", "taskId1", "type1", "wbKey2", "someUserId", "someDetails"));
"HEI:000000000000000000000000000000000000",
"wbKey1",
"taskId1",
"type1",
"wbKey2",
"someUserId",
"someDetails"));
when(historyQueryMapperMock.queryHistoryEvent(any())).thenReturn(returnList);
final List<HistoryEventImpl> result = cutSpy.createHistoryQuery().taskIdIn("taskId1").list();

View File

@ -1,7 +0,0 @@
INSERT INTO HISTORY_EVENTS (BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, TASK_CLASSIFICATION_KEY,
TASK_CLASSIFICATION_CATEGORY, ATTACHMENT_CLASSIFICATION_KEY, OLD_VALUE, NEW_VALUE, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, DETAILS) VALUES
-- BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY , POR_SYSTEM, POR_INSTANCE , POR_TYPE , POR_VALUE , TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY , ATTACHMENT_CLASSIFICATION_KEY , OLD_VALUE , NEW_VALUE , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4, details
('BPI:01' ,'' ,'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', CURRENT_TIMESTAMP , 'admin', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', 'L140101' , 'TASK' ,'' ,'old_val' ,'new_val' ,'custom1' ,'custom2' , 'custom3' ,'custom4', '{"changes":[{"newValue":"BPI:01","fieldName":"businessProcessId","oldValue":"BPI:02"},{"newValue":"admin","fieldName":"owner","oldValue":"owner1"}]}' ),
('BPI:02' ,'' ,'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -2, CURRENT_TIMESTAMP),'peter', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom2' ,'' ,'someDetails' ),
('BPI:03' ,'BPI:01','TKI:000000000000000000000000000000000001','TASK_CREATED', CURRENT_TIMESTAMP , 'admin', 'DOMAIN_A', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'' ,'someDetails' )
;

View File

@ -0,0 +1,19 @@
taskana.roles.user=group1 | group2|teamlead_1 | teamlead_2 |user_1_1| user_1_1| user_1_2| user_2_1| user_2_2| max|elena|simone
taskana.roles.Admin=name=konrad,Organisation=novatec|admin
taskana.roles.businessadmin=max|Moritz|businessadmin
taskana.roles.monitor=john|teamlead_2 | monitor
taskana.roles.taskadmin=peter | taskadmin
taskana.domains=Domain_A , DOMAIN_B
taskana.classification.types=TASK , document
taskana.classification.categories.task=EXTERNAL, manual, autoMAtic, Process
taskana.classification.categories.document=EXTERNAL
taskana.jobs.maxRetries=3
taskana.jobs.batchSize=50
taskana.jobs.cleanup.runEvery=P1D
taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.cleanup.minimumAge=P14D
taskana.german.holidays.enabled=true
taskana.german.holidays.corpus-christi.enabled=false
taskana.history.deletion.on.task.deletion.enabled=true

View File

@ -1,47 +1,47 @@
INSERT INTO HISTORY_EVENTS (BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY, ATTACHMENT_CLASSIFICATION_KEY, OLD_VALUE, NEW_VALUE, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, DETAILS) VALUES
INSERT INTO HISTORY_EVENTS (ID, BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY, ATTACHMENT_CLASSIFICATION_KEY, OLD_VALUE, NEW_VALUE, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, DETAILS) VALUES
-- BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, TASK_CREATEDD, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY , POR_SYSTEM, POR_INSTANCE , POR_TYPE , POR_VALUE , TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY , ATTACHMENT_CLASSIFICATION_KEY , OLD_VALUE , NEW_VALUE , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4
('BPI:01' ,'', 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER-2-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' ,' L140101' , 'TASK' ,'' ,'old_val12' ,'new_val12' ,'custom1' ,'custom2' , 'custom3' ,'custom4', 'some Details'),
('BPI:02' ,'', 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -2, CURRENT_TIMESTAMP ), 'USER-1-1', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '65464564' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:06' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:04' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:06' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:06' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER-1-2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER-2-1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details');
('HEI:000000000000000000000000000000000000','BPI:01' ,'', 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER_2_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' ,' L140101' , 'TASK' ,'' ,'old_val12' ,'new_val12' ,'custom1' ,'custom2' , 'custom3' ,'custom4', 'some Details'),
('HEI:000000000000000000000000000000000001','BPI:02' ,'', 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -2, CURRENT_TIMESTAMP ), 'USER_1_1', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '65464564' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000002','BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000003','BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000004','BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000005','BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000006','BPI:06' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000007','BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000008','BPI:04' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000009','BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000010','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000011','BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000012','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000013','BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000014','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000015','BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000016','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000017','BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000018','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000019','BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000020','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000021','BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000022','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000023','BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000024','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000025','BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000026','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000027','BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000028','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000029','BPI:03' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000030','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000031','BPI:05' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000032','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000033','BPI:06' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000034','BPI:02' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_CREATED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000035','BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000036','BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000037','BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000038','BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000039','BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000040','BPI:06' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000041','BPI:02' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000042','BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details'),
('HEI:000000000000000000000000000000000043','BPI:04' ,'' , 'TKI:000000000000000000000000000000000000', 'TASK_CREATED', DATEADD('DAY', -1, CURRENT_TIMESTAMP ), 'USER_1_2', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344' , '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom3' ,'custom4','some Details'),
('HEI:000000000000000000000000000000000044','BPI:03' ,'BPI:01', 'TKI:000000000000000000000000000000000001', 'TASK_DELETED', CURRENT_TIMESTAMP , 'USER_2_1', 'DOMAIN_B', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'','some Details');

View File

@ -104,7 +104,7 @@ class TaskHistoryEventControllerIntTest {
void should_ReturnSpecificTaskHistoryEventWithDetails_When_SingleEventIsQueried() {
ResponseEntity<TaskHistoryEventResource> response =
template.exchange(
server + port + "/api/v1/task-history-event/45",
server + port + "/api/v1/task-history-event/HEI:000000000000000000000000000000000000",
HttpMethod.GET,
request,
ParameterizedTypeReference.forType(TaskHistoryEventResource.class));

View File

@ -33,7 +33,8 @@ class TaskHistoryEventResourceAssemblerTest {
@Test
void taskHistoryEventModelToResource() {
HistoryEventImpl historyEvent = new HistoryEventImpl("user1", "someDetails");
HistoryEventImpl historyEvent =
new HistoryEventImpl("HEI:000000000000000000000000000000000000", "user1", "someDetails");
historyEvent.setEventType("TASK_CREATED");
historyEvent.setBusinessProcessId("BPI:01");

View File

@ -173,7 +173,7 @@ public class TaskHistoryEventControllerRestDocumentation {
this.mockMvc
.perform(
RestDocumentationRequestBuilders.get(
"http://127.0.0.1:" + port + "/api/v1/task-history-event/1")
"http://127.0.0.1:" + port + "/api/v1/task-history-event/HEI:000000000000000000000000000000000000")
.accept("application/hal+json")
.header("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"))
.andExpect(MockMvcResultMatchers.status().isOk())

View File

@ -68,6 +68,8 @@ public class TaskanaEngineConfiguration {
"taskana.german.holidays.corpus-christi.enabled";
private static final String TASKANA_CUSTOM_HOLIDAY = "taskana.custom.holidays";
private static final String TASKANA_CUSTOM_HOLIDAY_DAY_MONTH_SEPARATOR = ".";
private static final String TASKANA_HISTORY_DELETION_ON_TASK_DELETION_ENABLED =
"taskana.history.deletion.on.task.deletion.enabled";
// TASKANA_SCHEMA_VERSION
private static final String DEFAULT_SCHEMA_NAME = "TASKANA";
@ -92,6 +94,7 @@ public class TaskanaEngineConfiguration {
protected List<String> classificationTypes = new ArrayList<>();
protected Map<String, List<String>> classificationCategoriesByTypeMap = new HashMap<>();
// Properties for the monitor
private boolean deleteHistoryOnTaskDeletionEnabled;
private boolean germanPublicHolidaysEnabled;
private boolean corpusChristiEnabled;
// Properties for general job execution
@ -171,8 +174,9 @@ public class TaskanaEngineConfiguration {
initDomains(props);
initClassificationTypes(props);
initClassificationCategories(props);
initGermanHolidaysEnabled(props);
initCorpusChristiEnabled(props);
initBooleanFlag(props, TASKANA_GERMAN_HOLIDAYS_ENABLED);
initBooleanFlag(props, TASKANA_GERMAN_HOLIDAYS_CORPUS_CHRISTI_ENABLED);
initBooleanFlag(props, TASKANA_HISTORY_DELETION_ON_TASK_DELETION_ENABLED);
initCustomHolidays(props);
}
@ -268,6 +272,14 @@ public class TaskanaEngineConfiguration {
this.germanPublicHolidaysEnabled = germanPublicHolidaysEnabled;
}
public boolean isDeleteHistoryOnTaskDeletionEnabled() {
return deleteHistoryOnTaskDeletionEnabled;
}
public void setDeleteHistoryOnTaskDeletionEnabled(boolean deleteHistoryOnTaskDeletionEnabled) {
this.deleteHistoryOnTaskDeletionEnabled = deleteHistoryOnTaskDeletionEnabled;
}
public List<CustomHoliday> getCustomHolidays() {
return customHolidays;
}
@ -362,24 +374,21 @@ public class TaskanaEngineConfiguration {
return true;
}
private void initGermanHolidaysEnabled(Properties props) {
String enabled = props.getProperty(TASKANA_GERMAN_HOLIDAYS_ENABLED);
private void initBooleanFlag(Properties props, String propName) {
String enabled = props.getProperty(propName);
if (enabled != null && !enabled.isEmpty()) {
germanPublicHolidaysEnabled = Boolean.parseBoolean(enabled);
} else {
germanPublicHolidaysEnabled = false;
boolean isEnabled = Boolean.parseBoolean(enabled);
if (propName.equals(TASKANA_GERMAN_HOLIDAYS_ENABLED)) {
germanPublicHolidaysEnabled = isEnabled;
} else if (propName.equals(TASKANA_GERMAN_HOLIDAYS_CORPUS_CHRISTI_ENABLED)) {
corpusChristiEnabled = isEnabled;
} else if (propName.equals(TASKANA_HISTORY_DELETION_ON_TASK_DELETION_ENABLED)) {
deleteHistoryOnTaskDeletionEnabled = isEnabled;
}
}
LOGGER.debug("GermanPublicHolidaysEnabled = {}", germanPublicHolidaysEnabled);
}
private void initCorpusChristiEnabled(Properties props) {
String enabled = props.getProperty(TASKANA_GERMAN_HOLIDAYS_CORPUS_CHRISTI_ENABLED);
if (enabled != null && !enabled.isEmpty()) {
corpusChristiEnabled = Boolean.parseBoolean(enabled);
} else {
corpusChristiEnabled = false;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("%s = %b", propName, Boolean.parseBoolean(enabled)));
}
LOGGER.debug("CorpusChristiEnabled = {}", corpusChristiEnabled);
}
private void initJobParameters(Properties props) {

View File

@ -4,7 +4,7 @@ import java.util.function.Supplier;
import org.apache.ibatis.session.SqlSession;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.spi.history.internal.HistoryEventProducer;
import pro.taskana.spi.history.internal.HistoryEventManager;
import pro.taskana.task.internal.TaskRoutingManager;
/**
@ -67,7 +67,7 @@ public interface InternalTaskanaEngine {
*
* @return the HistoryEventProducer instance.
*/
HistoryEventProducer getHistoryEventProducer();
HistoryEventManager getHistoryEventManager();
/**
* Retrieve TaskRoutingProducer.

View File

@ -49,7 +49,7 @@ import pro.taskana.common.internal.security.GroupPrincipal;
import pro.taskana.monitor.api.MonitorService;
import pro.taskana.monitor.internal.MonitorMapper;
import pro.taskana.monitor.internal.MonitorServiceImpl;
import pro.taskana.spi.history.internal.HistoryEventProducer;
import pro.taskana.spi.history.internal.HistoryEventManager;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.internal.AttachmentMapper;
import pro.taskana.task.internal.ObjectReferenceMapper;
@ -80,12 +80,13 @@ public class TaskanaEngineImpl implements TaskanaEngine {
protected SqlSessionManager sessionManager;
protected ConnectionManagementMode mode = ConnectionManagementMode.PARTICIPATE;
protected Connection connection = null;
private HistoryEventManager historyEventManager;
protected TaskanaEngineImpl(TaskanaEngineConfiguration taskanaEngineConfiguration) {
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
createTransactionFactory(taskanaEngineConfiguration.getUseManagedTransactions());
this.sessionManager = createSqlSessionManager();
historyEventProducer = HistoryEventProducer.getInstance(taskanaEngineConfiguration);
historyEventManager = HistoryEventManager.getInstance(taskanaEngineConfiguration);
taskRoutingManager = TaskRoutingManager.getInstance(this);
this.internalTaskanaEngineImpl = new InternalTaskanaEngineImpl();
workingDaysToDaysConverter =
@ -154,7 +155,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
@Override
public boolean isHistoryEnabled() {
return HistoryEventProducer.isHistoryEnabled();
return HistoryEventManager.isHistoryEnabled();
}
@Override
@ -410,8 +411,8 @@ public class TaskanaEngineImpl implements TaskanaEngine {
}
@Override
public HistoryEventProducer getHistoryEventProducer() {
return historyEventProducer;
public HistoryEventManager getHistoryEventManager() {
return historyEventManager;
}
@Override

View File

@ -1,6 +1,10 @@
package pro.taskana.spi.history.api;
import java.util.List;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.spi.history.api.events.TaskanaHistoryEvent;
/** Interface for TASKANA History Service Provider. */
@ -20,4 +24,14 @@ public interface TaskanaHistory {
* @param event {@link TaskanaHistoryEvent} The event to be created.
*/
void create(TaskanaHistoryEvent event);
/**
* Delete history events by taskIds.
*
* @param taskIds the task ids for which all history events must be deleted
* @throws InvalidArgumentException If the list of taskIds is null
* @throws NotAuthorizedException If the user has no permission to delete events
*/
void deleteHistoryEventsByTaskIds(List<String> taskIds)
throws InvalidArgumentException, NotAuthorizedException;
}

View File

@ -5,7 +5,7 @@ import java.time.Instant;
/** Super class for all specific events from the TASKANA engine. */
public class TaskanaHistoryEvent {
protected long id;
protected String id;
protected String businessProcessId;
protected String parentBusinessProcessId;
protected String taskId;
@ -32,15 +32,20 @@ public class TaskanaHistoryEvent {
public TaskanaHistoryEvent() {}
public TaskanaHistoryEvent(String userId, String details) {
public TaskanaHistoryEvent(String id, String userId, String details) {
this.id = id;
this.userId = userId;
this.details = details;
}
public long getId() {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBusinessProcessId() {
return businessProcessId;
}

View File

@ -5,8 +5,8 @@ import pro.taskana.task.api.models.Task;
/** Event fired if a task is cancelled to be claimed. */
public class ClaimCancelledEvent extends TaskEvent {
public ClaimCancelledEvent(Task task, String userId) {
super(task, userId, null);
public ClaimCancelledEvent(String id, Task task, String userId) {
super(id, task, userId, null);
eventType = "TASK_CLAIM_CANCELLED";
created = task.getModified();
}

View File

@ -5,8 +5,8 @@ import pro.taskana.task.api.models.Task;
/** Event fired if a task is claimed. */
public class ClaimedEvent extends TaskEvent {
public ClaimedEvent(Task task, String userId) {
super(task, userId, null);
public ClaimedEvent(String id, Task task, String userId) {
super(id, task, userId, null);
setEventType("TASK_CLAIMED");
created = task.getClaimed();
}

View File

@ -6,14 +6,14 @@ import pro.taskana.task.api.models.TaskSummary;
/** Event fired if a task is completed. */
public class CompletedEvent extends TaskEvent {
public CompletedEvent(Task completedTask, String userId) {
super(completedTask, userId, null);
public CompletedEvent(String id, Task completedTask, String userId) {
super(id, completedTask, userId, null);
eventType = "TASK_COMPLETED";
created = completedTask.getCompleted();
}
public CompletedEvent(TaskSummary completedTask, String userId) {
super(completedTask, userId, null);
public CompletedEvent(String id, TaskSummary completedTask, String userId) {
super(id, completedTask, userId, null);
eventType = "TASK_COMPLETED";
created = completedTask.getCompleted();
}

View File

@ -5,8 +5,8 @@ import pro.taskana.task.api.models.Task;
/** Event fired if a task is created. */
public class CreatedEvent extends TaskEvent {
public CreatedEvent(Task task, String userId, String details) {
super(task, userId, details);
public CreatedEvent(String id, Task task, String userId, String details) {
super(id, task, userId, details);
eventType = "TASK_CREATED";
created = task.getCreated();
}

View File

@ -7,8 +7,8 @@ import pro.taskana.task.api.models.TaskSummary;
/** Super class for all task related events. */
public class TaskEvent extends TaskanaHistoryEvent {
public TaskEvent(Task task, String userId, String details) {
super(userId, details);
public TaskEvent(String id, Task task, String userId, String details) {
super(id, userId, details);
taskId = task.getId();
businessProcessId = task.getBusinessProcessId();
parentBusinessProcessId = task.getParentBusinessProcessId();
@ -31,8 +31,8 @@ public class TaskEvent extends TaskanaHistoryEvent {
}
}
public TaskEvent(TaskSummary task, String userId, String details) {
super(userId, details);
public TaskEvent(String id, TaskSummary task, String userId, String details) {
super(id, userId, details);
taskId = task.getId();
businessProcessId = task.getBusinessProcessId();
parentBusinessProcessId = task.getParentBusinessProcessId();

View File

@ -12,8 +12,12 @@ public class TransferredEvent extends TaskEvent {
private static final Logger LOGGER = LoggerFactory.getLogger(TransferredEvent.class);
public TransferredEvent(
Task task, WorkbasketSummary oldWorkbasket, WorkbasketSummary newWorkbasket, String userId) {
super(task, userId, null);
String id,
Task task,
WorkbasketSummary oldWorkbasket,
WorkbasketSummary newWorkbasket,
String userId) {
super(id, task, userId, null);
eventType = "TASK_TRANSFERRED";
created = task.getModified();
this.oldValue = oldWorkbasket.getId();

View File

@ -4,8 +4,8 @@ import pro.taskana.task.api.models.Task;
public class UpdatedEvent extends TaskEvent {
public UpdatedEvent(Task updatedTask, String userId, String details) {
super(updatedTask, userId, details);
public UpdatedEvent(String id, Task updatedTask, String userId, String details) {
super(id, updatedTask, userId, details);
eventType = "TASK_UPDATED";
created = updatedTask.getModified();
}

View File

@ -1,23 +1,28 @@
package pro.taskana.spi.history.internal;
import java.util.List;
import java.util.Objects;
import java.util.ServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pro.taskana.TaskanaEngineConfiguration;
import pro.taskana.common.api.exceptions.InvalidArgumentException;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.spi.history.api.TaskanaHistory;
import pro.taskana.spi.history.api.events.TaskanaHistoryEvent;
/** Creates events and emits them to the registered history service providers. */
public final class HistoryEventProducer {
/**
* Creates and deletes events and emits them to the registered history service providers.
*/
public final class HistoryEventManager {
private static final Logger LOGGER = LoggerFactory.getLogger(HistoryEventProducer.class);
private static HistoryEventProducer singleton;
private static final Logger LOGGER = LoggerFactory.getLogger(HistoryEventManager.class);
private static HistoryEventManager singleton;
private boolean enabled = false;
private ServiceLoader<TaskanaHistory> serviceLoader;
private HistoryEventProducer(TaskanaEngineConfiguration taskanaEngineConfiguration) {
private HistoryEventManager(TaskanaEngineConfiguration taskanaEngineConfiguration) {
serviceLoader = ServiceLoader.load(TaskanaHistory.class);
for (TaskanaHistory history : serviceLoader) {
history.initialize(taskanaEngineConfiguration);
@ -29,10 +34,10 @@ public final class HistoryEventProducer {
}
}
public static synchronized HistoryEventProducer getInstance(
public static synchronized HistoryEventManager getInstance(
TaskanaEngineConfiguration taskanaEngineConfiguration) {
if (singleton == null) {
singleton = new HistoryEventProducer(taskanaEngineConfiguration);
singleton = new HistoryEventManager(taskanaEngineConfiguration);
}
return singleton;
}
@ -45,4 +50,15 @@ public final class HistoryEventProducer {
LOGGER.debug("Sending event to history service providers: {}", event);
serviceLoader.forEach(historyProvider -> historyProvider.create(event));
}
public void deleteEvents(List<String> taskIds) {
LOGGER.debug("Sending taskIds to history service providers: {}", taskIds);
serviceLoader.forEach(historyProvider -> {
try {
historyProvider.deleteHistoryEventsByTaskIds(taskIds);
} catch (InvalidArgumentException | NotAuthorizedException e) {
LOGGER.warn("Caught an exception while trying to delete HistoryEvents", e);
}
});
}
}

View File

@ -177,7 +177,7 @@ public class AttachmentHandler {
oldAttachments.forEach(
a -> {
if (!newAttIds.contains(a.getId())) {
attachmentMapper.deleteAttachment(a.getId());
attachmentMapper.delete(a.getId());
LOGGER.debug(
"TaskService.updateTask() for TaskId={} DELETED an Attachment={}.",
newTaskImpl.getId(),

View File

@ -91,7 +91,11 @@ public interface AttachmentMapper {
@Param("taskIds") List<String> taskIds);
@Delete("DELETE FROM ATTACHMENT WHERE ID=#{attachmentId}")
void deleteAttachment(@Param("attachmentId") String attachmentId);
void delete(@Param("attachmentId") String attachmentId);
@Delete(
"<script>DELETE FROM ATTACHMENT WHERE TASK_ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)</script>")
void deleteMultipleByTaskIds(@Param("taskIds") List<String> taskIds);
@Update(
"UPDATE ATTACHMENT SET TASK_ID = #{taskId}, CREATED = #{created}, MODIFIED = #{modified},"

View File

@ -46,7 +46,7 @@ import pro.taskana.spi.history.api.events.task.ClaimedEvent;
import pro.taskana.spi.history.api.events.task.CompletedEvent;
import pro.taskana.spi.history.api.events.task.CreatedEvent;
import pro.taskana.spi.history.api.events.task.UpdatedEvent;
import pro.taskana.spi.history.internal.HistoryEventProducer;
import pro.taskana.spi.history.internal.HistoryEventManager;
import pro.taskana.task.api.CallbackState;
import pro.taskana.task.api.TaskQuery;
import pro.taskana.task.api.TaskService;
@ -101,18 +101,19 @@ public class TaskServiceImpl implements TaskService {
private static final String ID_PREFIX_BUSINESS_PROCESS = "BPI";
private static final Set<String> ALLOWED_CUSTOM_KEYS =
IntStream.rangeClosed(1, 16).mapToObj(String::valueOf).collect(Collectors.toSet());
private static final String ID_PREFIX_HISTORY_EVENT = "HEI";
private static final String TASK_WITH_ID_IS_ALREADY_IN_END_STATE =
"Task with Id %s is already in an end state.";
private final InternalTaskanaEngine taskanaEngine;
private final WorkbasketService workbasketService;
private final ClassificationService classificationService;
private final TaskMapper taskMapper;
private final AttachmentMapper attachmentMapper;
private final HistoryEventProducer historyEventProducer;
private final TaskTransferrer taskTransferrer;
private final TaskCommentServiceImpl taskCommentService;
private final ServiceLevelHandler serviceLevelHandler;
private final AttachmentHandler attachmentHandler;
private AttachmentMapper attachmentMapper;
private HistoryEventManager historyEventManager;
public TaskServiceImpl(
InternalTaskanaEngine taskanaEngine,
@ -124,7 +125,7 @@ public class TaskServiceImpl implements TaskService {
this.workbasketService = taskanaEngine.getEngine().getWorkbasketService();
this.attachmentMapper = attachmentMapper;
this.classificationService = taskanaEngine.getEngine().getClassificationService();
this.historyEventProducer = taskanaEngine.getHistoryEventProducer();
this.historyEventManager = taskanaEngine.getHistoryEventManager();
this.taskTransferrer = new TaskTransferrer(taskanaEngine, taskMapper, this);
this.taskCommentService = new TaskCommentServiceImpl(taskanaEngine, taskCommentMapper, this);
this.serviceLevelHandler = new ServiceLevelHandler(taskanaEngine, taskMapper, attachmentMapper);
@ -231,11 +232,15 @@ public class TaskServiceImpl implements TaskService {
try {
this.taskMapper.insert(task);
LOGGER.debug("Method createTask() created Task '{}'.", task.getId());
if (HistoryEventProducer.isHistoryEnabled()) {
if (HistoryEventManager.isHistoryEnabled()) {
String details = determineChangesInTaskAttributes(newTask(), task);
historyEventProducer.createEvent(
new CreatedEvent(task, CurrentUserContext.getUserid(), details));
historyEventManager.createEvent(
new CreatedEvent(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT),
task,
CurrentUserContext.getUserid(),
details));
}
} catch (PersistenceException e) {
// Error messages:
@ -434,13 +439,17 @@ public class TaskServiceImpl implements TaskService {
LOGGER.debug("Method updateTask() updated task '{}' for user '{}'.", task.getId(), userId);
if (HistoryEventProducer.isHistoryEnabled()) {
if (HistoryEventManager.isHistoryEnabled()) {
String changeDetails = determineChangesInTaskAttributes(oldTaskImpl, newTaskImpl);
LOGGER.warn(changeDetails);
historyEventProducer.createEvent(
new UpdatedEvent(task, CurrentUserContext.getUserid(), changeDetails));
historyEventManager.createEvent(
new UpdatedEvent(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT),
task,
CurrentUserContext.getUserid(),
changeDetails));
}
} finally {
@ -537,8 +546,18 @@ public class TaskServiceImpl implements TaskService {
while (taskIdIterator.hasNext()) {
removeSingleTaskForTaskDeletionById(bulkLog, taskSummaries, taskIdIterator);
}
if (!taskIds.isEmpty()) {
attachmentMapper.deleteMultipleByTaskIds(taskIds);
taskMapper.deleteMultiple(taskIds);
if (taskanaEngine.getEngine().isHistoryEnabled()
&& taskanaEngine
.getEngine()
.getConfiguration()
.isDeleteHistoryOnTaskDeletionEnabled()) {
historyEventManager.deleteEvents(taskIds);
}
}
return bulkLog;
} finally {
@ -1198,8 +1217,12 @@ public class TaskServiceImpl implements TaskService {
claimActionsOnTask(task, userId, now);
taskMapper.update(task);
LOGGER.debug("Task '{}' claimed by user '{}'.", taskId, userId);
if (HistoryEventProducer.isHistoryEnabled()) {
historyEventProducer.createEvent(new ClaimedEvent(task, CurrentUserContext.getUserid()));
if (HistoryEventManager.isHistoryEnabled()) {
historyEventManager.createEvent(
new ClaimedEvent(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT),
task,
CurrentUserContext.getUserid()));
}
} finally {
taskanaEngine.returnConnection();
@ -1294,9 +1317,12 @@ public class TaskServiceImpl implements TaskService {
task.setState(TaskState.READY);
taskMapper.update(task);
LOGGER.debug("Task '{}' unclaimed by user '{}'.", taskId, userId);
if (HistoryEventProducer.isHistoryEnabled()) {
historyEventProducer.createEvent(
new ClaimCancelledEvent(task, CurrentUserContext.getUserid()));
if (HistoryEventManager.isHistoryEnabled()) {
historyEventManager.createEvent(
new ClaimCancelledEvent(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT),
task,
CurrentUserContext.getUserid()));
}
} finally {
taskanaEngine.returnConnection();
@ -1332,8 +1358,12 @@ public class TaskServiceImpl implements TaskService {
completeActionsOnTask(task, userId, now);
taskMapper.update(task);
LOGGER.debug("Task '{}' completed by user '{}'.", taskId, userId);
if (HistoryEventProducer.isHistoryEnabled()) {
historyEventProducer.createEvent(new CompletedEvent(task, CurrentUserContext.getUserid()));
if (HistoryEventManager.isHistoryEnabled()) {
historyEventManager.createEvent(
new CompletedEvent(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT),
task,
CurrentUserContext.getUserid()));
}
} finally {
taskanaEngine.returnConnection();
@ -1360,7 +1390,14 @@ public class TaskServiceImpl implements TaskService {
throw new InvalidStateException(String.format(TASK_WITH_ID_CALLBACK_NOT_PROCESSED, taskId));
}
attachmentMapper.deleteMultipleByTaskIds(Arrays.asList(taskId));
taskMapper.delete(taskId);
if (taskanaEngine.getEngine().isHistoryEnabled()
&& taskanaEngine.getEngine().getConfiguration().isDeleteHistoryOnTaskDeletionEnabled()) {
historyEventManager.deleteEvents(Arrays.asList(taskId));
}
LOGGER.debug("Task {} deleted.", taskId);
} finally {
taskanaEngine.returnConnection();
@ -1560,7 +1597,7 @@ public class TaskServiceImpl implements TaskService {
if (!updateClaimedTaskIds.isEmpty()) {
taskMapper.updateClaimed(updateClaimedTaskIds, claimedReference);
}
if (HistoryEventProducer.isHistoryEnabled()) {
if (HistoryEventManager.isHistoryEnabled()) {
createTasksCompletedEvents(taskSummaryList);
}
}
@ -1906,7 +1943,10 @@ public class TaskServiceImpl implements TaskService {
private void createTasksCompletedEvents(List<? extends TaskSummary> taskSummaries) {
taskSummaries.forEach(
task ->
historyEventProducer.createEvent(
new CompletedEvent(task, CurrentUserContext.getUserid())));
historyEventManager.createEvent(
new CompletedEvent(
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT),
task,
CurrentUserContext.getUserid())));
}
}

View File

@ -16,8 +16,9 @@ import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.api.exceptions.TaskanaException;
import pro.taskana.common.internal.InternalTaskanaEngine;
import pro.taskana.common.internal.security.CurrentUserContext;
import pro.taskana.common.internal.util.IdGenerator;
import pro.taskana.spi.history.api.events.task.TransferredEvent;
import pro.taskana.spi.history.internal.HistoryEventProducer;
import pro.taskana.spi.history.internal.HistoryEventManager;
import pro.taskana.task.api.TaskState;
import pro.taskana.task.api.exceptions.InvalidStateException;
import pro.taskana.task.api.exceptions.TaskNotFoundException;
@ -41,12 +42,13 @@ public class TaskTransferrer {
private static final String TASK_WITH_ID = "Task with id ";
private static final String WAS_MARKED_FOR_DELETION = " was marked for deletion";
private static final String THE_WORKBASKET = "The workbasket ";
private static final String ID_PREFIX_HISTORY_EVENT = "HEI";
private static final Logger LOGGER = LoggerFactory.getLogger(TaskTransferrer.class);
private InternalTaskanaEngine taskanaEngine;
private WorkbasketService workbasketService;
private TaskServiceImpl taskService;
private TaskMapper taskMapper;
private HistoryEventProducer historyEventProducer;
private HistoryEventManager historyEventManager;
TaskTransferrer(
InternalTaskanaEngine taskanaEngine, TaskMapper taskMapper, TaskServiceImpl taskService) {
@ -55,7 +57,7 @@ public class TaskTransferrer {
this.taskService = taskService;
this.taskMapper = taskMapper;
this.workbasketService = taskanaEngine.getEngine().getWorkbasketService();
this.historyEventProducer = taskanaEngine.getHistoryEventProducer();
this.historyEventManager = taskanaEngine.getHistoryEventManager();
}
Task transfer(String taskId, String destinationWorkbasketKey, String domain)
@ -110,7 +112,7 @@ public class TaskTransferrer {
"Method transfer() transferred Task '{}' to destination workbasket {}",
taskId,
destinationWorkbasket.getId());
if (HistoryEventProducer.isHistoryEnabled()) {
if (HistoryEventManager.isHistoryEnabled()) {
createTaskTransferredEvent(task, oldWorkbasketSummary, destinationWorkbasket.asSummary());
}
return task;
@ -167,7 +169,7 @@ public class TaskTransferrer {
"Method transfer() transferred Task '{}' to destination workbasket {}",
taskId,
destinationWorkbasketId);
if (HistoryEventProducer.isHistoryEnabled()) {
if (HistoryEventManager.isHistoryEnabled()) {
createTaskTransferredEvent(task, oldWorkbasketSummary, destinationWorkbasket.asSummary());
}
return task;
@ -364,9 +366,13 @@ public class TaskTransferrer {
private void createTaskTransferredEvent(
Task task, WorkbasketSummary oldWorkbasketSummary, WorkbasketSummary newWorkbasketSummary) {
historyEventProducer.createEvent(
historyEventManager.createEvent(
new TransferredEvent(
task, oldWorkbasketSummary, newWorkbasketSummary, CurrentUserContext.getUserid()));
IdGenerator.generateWithPrefix(ID_PREFIX_HISTORY_EVENT),
task,
oldWorkbasketSummary,
newWorkbasketSummary,
CurrentUserContext.getUserid()));
}
private void updateTasksToBeTransferred(
@ -397,7 +403,7 @@ public class TaskTransferrer {
updateObject.setState(TaskState.READY);
updateObject.setOwner(null);
taskMapper.updateTransfered(taskIds, updateObject);
if (HistoryEventProducer.isHistoryEnabled()) {
if (HistoryEventManager.isHistoryEnabled()) {
createTasksTransferredEvents(taskSummaries, updateObject);
}
}

View File

@ -208,7 +208,7 @@ CREATE TABLE SCHEDULED_JOB(
CREATE TABLE HISTORY_EVENTS
(
ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
ID VARCHAR(40) NOT NULL,
BUSINESS_PROCESS_ID VARCHAR(128) NULL,
PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL,
TASK_ID VARCHAR(40) NULL,

View File

@ -211,7 +211,7 @@ CREATE TABLE SCHEDULED_JOB(
CREATE TABLE HISTORY_EVENTS
(
ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
ID VARCHAR(40) NOT NULL,
BUSINESS_PROCESS_ID VARCHAR(128) NULL,
PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL,
TASK_ID VARCHAR(40) NULL,

View File

@ -206,7 +206,7 @@ CREATE TABLE SCHEDULED_JOB(
CREATE TABLE HISTORY_EVENTS
(
ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
ID VARCHAR(40) NOT NULL,
BUSINESS_PROCESS_ID VARCHAR(128) NULL,
PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL,
TASK_ID VARCHAR(40) NULL,

View File

@ -5,11 +5,11 @@ import static org.assertj.core.api.Assertions.assertThat;
import acceptance.AbstractAccTest;
import org.junit.jupiter.api.Test;
/** Acceptance test for historyEventProducer class. */
class TaskEventProducerTest extends AbstractAccTest {
/** Acceptance test for HistoryEventManager class. */
class HistoryEventManagerTest extends AbstractAccTest {
@Test
void testHistoryEventProducerIsNotEnabled() {
void testHistoryEventManagerIsNotEnabled() {
assertThat(taskanaEngine.isHistoryEnabled()).isFalse();
}
}

View File

@ -36,7 +36,7 @@ class TaskCleanupJobAccTest extends AbstractAccTest {
createAndCompleteTask();
long totalTasksCount = taskService.createTaskQuery().count();
assertThat(totalTasksCount).isEqualTo(85);
assertThat(totalTasksCount).isEqualTo(88);
taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(false);
@ -51,7 +51,7 @@ class TaskCleanupJobAccTest extends AbstractAccTest {
@Test
void shouldCleanCompletedTasksUntilDateWithSameParentBussiness() throws Exception {
long totalTasksCount = taskService.createTaskQuery().count();
assertThat(totalTasksCount).isEqualTo(84);
assertThat(totalTasksCount).isEqualTo(87);
taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(true);

View File

@ -36,7 +36,7 @@ class TaskQueryAccTest extends AbstractAccTest {
List<TaskSummary> results = taskService.createTaskQuery().ownerLike("%a%", "%u%").list();
assertThat(results).hasSize(4);
assertThat(results).hasSize(7);
}
@WithAccessId(user = "user-1-1", groups = "businessadmin")
@ -46,7 +46,7 @@ class TaskQueryAccTest extends AbstractAccTest {
List<TaskSummary> results = taskService.createTaskQuery().ownerLike("%a%", "%u%").list();
assertThat(results).hasSize(4);
assertThat(results).hasSize(7);
}
@WithAccessId(user = "user-1-1", groups = "admin")
@ -56,6 +56,6 @@ class TaskQueryAccTest extends AbstractAccTest {
List<TaskSummary> results = taskService.createTaskQuery().ownerLike("%a%", "%u%").list();
assertThat(results).hasSize(36);
assertThat(results).hasSize(39);
}
}

View File

@ -89,7 +89,7 @@ class CancelTaskAccTest extends AbstractAccTest {
void testCancelCompletedTask() {
List<TaskSummary> taskSummaries =
taskService.createTaskQuery().stateIn(TaskState.COMPLETED).list();
assertThat(taskSummaries).hasSize(7);
assertThat(taskSummaries).hasSize(10);
ThrowingCallable taskanaCall = () -> taskService.cancelTask(taskSummaries.get(0).getId());

View File

@ -15,14 +15,18 @@ import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.common.api.BulkOperationResults;
import pro.taskana.common.api.exceptions.NotAuthorizedException;
import pro.taskana.common.api.exceptions.TaskanaException;
import pro.taskana.common.internal.TaskanaEngineProxyForTest;
import pro.taskana.common.internal.security.JaasExtension;
import pro.taskana.common.internal.security.WithAccessId;
import pro.taskana.task.api.TaskService;
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.internal.AttachmentMapper;
/** Acceptance test for all "delete task" scenarios. */
/**
* Acceptance test for all "delete task" scenarios.
*/
@ExtendWith(JaasExtension.class)
class DeleteTaskAccTest extends AbstractAccTest {
@ -42,6 +46,54 @@ class DeleteTaskAccTest extends AbstractAccTest {
assertThatThrownBy(call).isInstanceOf(NotAuthorizedException.class);
}
@WithAccessId(user = "admin")
@Test
void should_deleteAttachments_When_MultipleTasksAreDeleted()
throws NotAuthorizedException, InvalidArgumentException, NoSuchFieldException,
IllegalAccessException {
TaskService taskService = taskanaEngine.getTaskService();
TaskanaEngineProxyForTest engineProxy = new TaskanaEngineProxyForTest(taskanaEngine);
AttachmentMapper attachmentMapper =
engineProxy.getEngine().getSqlSession().getMapper(AttachmentMapper.class);
assertThat(attachmentMapper.findAttachmentSummariesByTaskIds(Arrays.asList(
"TKI:000000000000000000000000000000000067", "TKI:000000000000000000000000000000000068")))
.hasSize(4);
taskService.deleteTasks(Arrays.asList("TKI:000000000000000000000000000000000067",
"TKI:000000000000000000000000000000000068"));
assertThat(attachmentMapper.findAttachmentSummariesByTaskIds(Arrays.asList(
"TKI:000000000000000000000000000000000067", "TKI:000000000000000000000000000000000068")))
.hasSize(0);
}
@WithAccessId(user = "admin")
@Test
void should_deleteAttachments_When_SingleTaskIsDeleted()
throws NotAuthorizedException, NoSuchFieldException,
IllegalAccessException, InvalidStateException, TaskNotFoundException {
TaskService taskService = taskanaEngine.getTaskService();
TaskanaEngineProxyForTest engineProxy = new TaskanaEngineProxyForTest(taskanaEngine);
AttachmentMapper attachmentMapper =
engineProxy.getSqlSession().getMapper(AttachmentMapper.class);
assertThat(attachmentMapper.findAttachmentsByTaskId("TKI:000000000000000000000000000000000069"))
.hasSize(1);
taskService.deleteTask(
"TKI:000000000000000000000000000000000069");
assertThat(attachmentMapper.findAttachmentsByTaskId("TKI:000000000000000000000000000000000069"))
.hasSize(0);
}
@WithAccessId(user = "businessadmin")
@WithAccessId(user = "taskadmin")
@WithAccessId(user = "user-1-1")

View File

@ -107,14 +107,14 @@ class QueryTaskByClassificationNameAccTest extends AbstractAccTest {
.attachmentClassificationNameLike("Widerruf", "Beratungsprotokoll", "Dynamik%")
.orderByAttachmentClassificationName(SortDirection.ASCENDING)
.list();
assertThat(tasks).hasSize(7);
assertThat(tasks).hasSize(10);
// make sure that unordered query returns the same number of objects
tasks =
taskService
.createTaskQuery()
.attachmentClassificationNameLike("Widerruf", "Beratungsprotokoll", "Dynamik%")
.list();
assertThat(tasks).hasSize(7);
assertThat(tasks).hasSize(10);
}
@WithAccessId(user = "user-1-1")
@ -128,14 +128,14 @@ class QueryTaskByClassificationNameAccTest extends AbstractAccTest {
.attachmentClassificationNameIn("Widerruf", "Beratungsprotokoll", "Dynamikänderung")
.orderByAttachmentClassificationName(SortDirection.ASCENDING)
.list();
assertThat(tasks).hasSize(4);
assertThat(tasks).hasSize(7);
// make sure that unordered query returns the same number of objects
tasks =
taskService
.createTaskQuery()
.attachmentClassificationNameIn("Widerruf", "Beratungsprotokoll", "Dynamikänderung")
.list();
assertThat(tasks).hasSize(4);
assertThat(tasks).hasSize(7);
}
@WithAccessId(user = "user-1-1")
@ -162,12 +162,12 @@ class QueryTaskByClassificationNameAccTest extends AbstractAccTest {
// we expect 4 result objects in this case, because task
// TKI:000000000000000000000000000000000001 has 2 attachments with different Classifications
// therefore task TKI:000000000000000000000000000000000001 occurs twice in the result set
assertThat(tasks).hasSize(4);
assertThat(tasks).hasSize(7);
long numberOfTasks =
taskQuery
.attachmentClassificationNameIn("Widerruf", "Beratungsprotokoll", "Dynamikänderung")
.count();
assertThat(numberOfTasks).isEqualTo(3);
assertThat(numberOfTasks).isEqualTo(6);
// the count returns only the number of tasks that have an attachment with the specified
// classification name.
// therefore, task 001 is counted only once.

View File

@ -145,7 +145,7 @@ class QueryTasksAccTest extends AbstractAccTest {
List<TaskSummary> results =
taskService.createTaskQuery().ownerLike("%a%", "%u%").orderByCreated(ASCENDING).list();
assertThat(results).hasSize(36);
assertThat(results).hasSize(39);
TaskSummary previousSummary = null;
for (TaskSummary taskSummary : results) {
if (previousSummary != null) {
@ -206,7 +206,7 @@ class QueryTasksAccTest extends AbstractAccTest {
List<TaskSummary> result4 =
taskService.createTaskQuery().classificationKeyNotIn("L1050", "L1060", "T2100").list();
assertThat(result4).hasSize(7);
assertThat(result4).hasSize(10);
}
@WithAccessId(user = "admin")
@ -256,7 +256,7 @@ class QueryTasksAccTest extends AbstractAccTest {
.createTaskQuery()
.externalIdLike("ETI:000000000000000000000000000000%")
.listValues(TaskQueryColumnName.EXTERNAL_ID, DESCENDING);
assertThat(resultValues).hasSize(71);
assertThat(resultValues).hasSize(74);
long countAllExternalIds = taskService.createTaskQuery().externalIdLike("ETI:%").count();
long countAllIds = taskService.createTaskQuery().count();
@ -475,7 +475,7 @@ class QueryTasksAccTest extends AbstractAccTest {
@Test
void testQueryForReadEquals() {
List<TaskSummary> results = taskService.createTaskQuery().readEquals(true).list();
assertThat(results).hasSize(36);
assertThat(results).hasSize(39);
}
@WithAccessId(user = "admin")
@ -497,7 +497,7 @@ class QueryTasksAccTest extends AbstractAccTest {
@Test
void testQueryForBusinessProcessIdLike() {
List<TaskSummary> results = taskService.createTaskQuery().businessProcessIdLike("pI_%").list();
assertThat(results).hasSize(77);
assertThat(results).hasSize(80);
}
@WithAccessId(user = "admin")

View File

@ -42,7 +42,7 @@ class QueryTasksByTimeIntervalsAccTest extends AbstractAccTest {
.orderByCreated(asc)
.list();
assertThat(results).hasSize(50);
assertThat(results).hasSize(53);
TaskSummary previousSummary = null;
for (TaskSummary taskSummary : results) {
Instant cr = taskSummary.getCreated();
@ -88,7 +88,7 @@ class QueryTasksByTimeIntervalsAccTest extends AbstractAccTest {
List<TaskSummary> results =
taskService.createTaskQuery().createdWithin(interval1).orderByCreated(asc).list();
assertThat(results).hasSize(48);
assertThat(results).hasSize(51);
TaskSummary previousSummary = null;
for (TaskSummary taskSummary : results) {
Instant cr = taskSummary.getCreated();
@ -118,7 +118,7 @@ class QueryTasksByTimeIntervalsAccTest extends AbstractAccTest {
.orderByCreated(asc)
.list();
assertThat(results).hasSize(35);
assertThat(results).hasSize(38);
TaskSummary previousSummary = null;
for (TaskSummary taskSummary : results) {
Instant cr = taskSummary.getClaimed();
@ -141,7 +141,7 @@ class QueryTasksByTimeIntervalsAccTest extends AbstractAccTest {
List<TaskSummary> results =
taskService.createTaskQuery().completedWithin(interval).orderByCompleted(asc).list();
assertThat(results).hasSize(15);
assertThat(results).hasSize(18);
TaskSummary previousSummary = null;
for (TaskSummary taskSummary : results) {
Instant cr = taskSummary.getCompleted();
@ -187,7 +187,7 @@ class QueryTasksByTimeIntervalsAccTest extends AbstractAccTest {
List<TaskSummary> results =
taskService.createTaskQuery().plannedWithin(interval).orderByPlanned(asc).list();
assertThat(results).hasSize(82);
assertThat(results).hasSize(85);
TaskSummary previousSummary = null;
for (TaskSummary taskSummary : results) {
Instant cr = taskSummary.getPlanned();
@ -210,7 +210,7 @@ class QueryTasksByTimeIntervalsAccTest extends AbstractAccTest {
List<TaskSummary> results =
taskService.createTaskQuery().dueWithin(interval).orderByPlanned(asc).list();
assertThat(results).hasSize(82);
assertThat(results).hasSize(85);
TaskSummary previousSummary = null;
for (TaskSummary taskSummary : results) {
Instant cr = taskSummary.getDue();

View File

@ -39,7 +39,7 @@ class QueryTasksByWorkbasketAccTest extends AbstractAccTest {
.createTaskQuery()
.workbasketKeyDomainIn(workbasketIdentifiers.toArray(new KeyDomain[0]))
.list();
assertThat(results).hasSize(30);
assertThat(results).hasSize(55);
String[] ids =
results.stream()
@ -48,7 +48,7 @@ class QueryTasksByWorkbasketAccTest extends AbstractAccTest {
.toArray(new String[0]);
List<TaskSummary> result2 = taskService.createTaskQuery().workbasketIdIn(ids).list();
assertThat(result2).hasSize(30);
assertThat(result2).hasSize(59);
}
@WithAccessId(user = "user-1-1")

View File

@ -164,7 +164,7 @@ class SetOwnerAccTest extends AbstractAccTest {
allTaskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList());
BulkOperationResults<String, TaskanaException> results =
taskanaEngine.getTaskService().setOwnerOfTasks("theWorkaholic", allTaskIds);
assertThat(allTaskSummaries).hasSize(84);
assertThat(allTaskSummaries).hasSize(87);
assertThat(results.containsErrors()).isTrue();
Condition<Object> invalidStateException =
@ -173,10 +173,10 @@ class SetOwnerAccTest extends AbstractAccTest {
new Condition<>(
c -> c.getClass() == NotAuthorizedException.class, "NotAuthorizedException");
assertThat(results.getErrorMap())
.hasSize(82)
.hasSize(62)
.extractingFromEntries(Entry::getValue)
.hasOnlyElementsOfTypes(InvalidStateException.class, NotAuthorizedException.class)
.areExactly(28, invalidStateException)
.areExactly(39, invalidStateException)
.areExactly(54, notAuthorizedException);
}
@ -189,10 +189,10 @@ class SetOwnerAccTest extends AbstractAccTest {
allTaskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList());
BulkOperationResults<String, TaskanaException> results =
taskanaEngine.getTaskService().setOwnerOfTasks("theWorkaholic", allTaskIds);
assertThat(allTaskSummaries).hasSize(84);
assertThat(allTaskSummaries).hasSize(87);
assertThat(results.containsErrors()).isTrue();
assertThat(results.getErrorMap())
.hasSize(37)
.hasSize(40)
.extractingFromEntries(Entry::getValue)
.hasOnlyElementsOfType(InvalidStateException.class);
}

View File

@ -79,7 +79,7 @@ class TerminateTaskAccTest extends AbstractAccTest {
void should_ThrowException_When_TerminateTaskWithTaskStateCompleted() {
List<TaskSummary> taskSummaries =
taskService.createTaskQuery().stateIn(TaskState.COMPLETED).list();
assertThat(taskSummaries.size()).isEqualTo(7);
assertThat(taskSummaries.size()).isEqualTo(10);
ThrowingCallable taskanaCall = () -> taskService.terminateTask(taskSummaries.get(0).getId());
assertThatThrownBy(taskanaCall).isInstanceOf(InvalidStateException.class);

View File

@ -89,7 +89,7 @@ class TaskTransferrerTest {
verify(taskMapperMock, times(1)).update(any());
verify(internalTaskanaEngineMock, times(1)).returnConnection();
verify(internalTaskanaEngineMock, times(1)).getEngine();
verify(internalTaskanaEngineMock).getHistoryEventProducer();
verify(internalTaskanaEngineMock).getHistoryEventManager();
verify(taskanaEngineMock).getWorkbasketService();
verifyNoMoreInteractions(
attachmentMapperMock,

View File

@ -14,4 +14,6 @@ taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.cleanup.minimumAge=P14D
taskana.german.holidays.enabled=true
taskana.german.holidays.corpus-christi.enabled=false
taskana.history.deletion.on.task.deletion.enabled=true

View File

@ -13,11 +13,12 @@ public final class SampleDataProvider {
static final String TEST_CLASSIFICATION = "/sql/test-data/classification.sql";
static final String TEST_OBJECT_REFERENCE = "/sql/test-data/object-reference.sql";
static final String TEST_ATTACHMENT = "/sql/test-data/attachment.sql";
static final String TEST_HISTORY_EVENT = "/sql/test-data/history-event.sql";
static final String MONITOR_SAMPLE_DATA = "/sql/monitor-data/monitor-sample-data.sql";
private static final String DB_CLEAR_TABLES_SCRIPT = "/sql/clear/clear-db.sql";
private static final String DB_DROP_TABLES_SCRIPT = "/sql/clear/drop-tables.sql";
private static final String CLEAR_HISTORY_EVENTS = "/sql/clear/clear-history-events.sql";
private static final String HISTORY_EVENT = "/sql/sample-data/history-event.sql";
private static final String SAMPLE_HISTORY_EVENT = "/sql/sample-data/history-event.sql";
private static final String SAMPLE_TASK = "/sql/sample-data/task.sql";
private static final String SAMPLE_TASK_COMMENT = "/sql/sample-data/task-comment.sql";
private static final String SAMPLE_WORKBASKET = "/sql/sample-data/workbasket.sql";
@ -45,7 +46,7 @@ public final class SampleDataProvider {
static Stream<String> getScriptsWithEvents() {
return Stream.concat(
getSampleDataCreationScripts(), Stream.of(CLEAR_HISTORY_EVENTS, HISTORY_EVENT));
getSampleDataCreationScripts(), Stream.of(CLEAR_HISTORY_EVENTS, SAMPLE_HISTORY_EVENT));
}
static Stream<String> getScriptsToClearDatabase() {
@ -61,6 +62,7 @@ public final class SampleDataProvider {
TEST_CLASSIFICATION,
TEST_WORKBASKET,
TEST_TASK,
TEST_HISTORY_EVENT,
TEST_TASK_COMMENT,
TEST_WORKBASKET_ACCESS_LIST,
TEST_DISTRIBUTION_TARGETS,

View File

@ -1,5 +1,6 @@
-- the order is important!
DELETE FROM TASK_COMMENT;
DELETE FROM HISTORY_EVENTS;
DELETE FROM CONFIGURATION;
DELETE FROM ATTACHMENT;
DELETE FROM TASK;

View File

@ -17,3 +17,8 @@ INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000013','TKI:00
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000014','TKI:000000000000000000000000000000000010', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L11010' , 'CLI:100000000000000000000000000000000004', 'novatec' , 'novasys', 'nvinst', 'typ5', 'val4', 'ch8', null, null);
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000015','TKI:000000000000000000000000000000000011', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L10303' , 'CLI:100000000000000000000000000000000002', 'novatec' , 'novasys', 'nvinst', 'typ5', 'val5', 'ch8', '2018-01-30 12:00:00', null);
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000016','TKI:000000000000000000000000000000000012', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ5', 'val6', 'ch8', null, null);
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000017','TKI:000000000000000000000000000000000067', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null);
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000018','TKI:000000000000000000000000000000000067', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null);
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000019','TKI:000000000000000000000000000000000068', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null);
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000020','TKI:000000000000000000000000000000000068', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null);
INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000021','TKI:000000000000000000000000000000000069', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null);

View File

@ -0,0 +1,17 @@
INSERT INTO HISTORY_EVENTS (ID,BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, TASK_CLASSIFICATION_KEY,
TASK_CLASSIFICATION_CATEGORY, ATTACHMENT_CLASSIFICATION_KEY, OLD_VALUE, NEW_VALUE, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, DETAILS) VALUES
-- BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, TASK_ID, EVENT_TYPE, CREATED, USER_ID, DOMAIN, WORKBASKET_KEY, POR_COMPANY , POR_SYSTEM, POR_INSTANCE , POR_TYPE , POR_VALUE , TASK_CLASSIFICATION_KEY, TASK_CLASSIFICATION_CATEGORY , ATTACHMENT_CLASSIFICATION_KEY , OLD_VALUE , NEW_VALUE , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4, details
('HEI:000000000000000000000000000000000000','BPI:01' ,'' ,'TKI:000000000000000000000000000000000000', 'TASK_UPDATED', '2018-01-29 15:55:00' , 'admin', 'DOMAIN_B', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', 'L140101' , 'TASK' ,'' ,'old_val' ,'new_val' ,'custom1' ,'custom2' , 'custom3' ,'custom4', '{"changes":[{"newValue":"BPI:01","fieldName":"businessProcessId","oldValue":"BPI:02"},{"newValue":"admin","fieldName":"owner","oldValue":"owner1"}]}' ),
('HEI:000000000000000000000000000000000001','BPI:02' ,'' ,'TKI:000000000000000000000000000000000000', 'TASK_CREATED', '2018-01-29 15:55:01','peter', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom2' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000002','BPI:03' ,'BPI:01','TKI:000000000000000000000000000000000036','TASK_CREATED', '2018-01-29 15:55:02' , 'admin', 'DOMAIN_A', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000003','BPI:02' ,'' ,'TKI:000000000000000000000000000000000036', 'TASK_CREATED', '2018-01-29 15:55:03','peter', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom2' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000004','BPI:03' ,'BPI:01','TKI:000000000000000000000000000000000037','TASK_CREATED', '2018-01-29 15:55:04' , 'admin', 'DOMAIN_A', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000005','BPI:02' ,'' ,'TKI:000000000000000000000000000000000038', 'TASK_CREATED', '2018-01-29 15:55:05','peter', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom2' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000006','BPI:03' ,'BPI:01','TKI:000000000000000000000000000000000038','TASK_CREATED', '2018-01-29 15:55:06' , 'admin', 'DOMAIN_A', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000007','BPI:02' ,'' ,'TKI:000000000000000000000000000000000039', 'TASK_CREATED', '2018-01-29 15:55:07','peter', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom2' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000008','BPI:03' ,'BPI:01','TKI:000000000000000000000000000000000039','TASK_CREATED', '2018-01-29 15:55:08' , 'admin', 'DOMAIN_A', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000009','BPI:02' ,'' ,'TKI:000000000000000000000000000000000040', 'TASK_CREATED', '2018-01-29 15:55:09','peter', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom2' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000010','BPI:03' ,'BPI:01','TKI:000000000000000000000000000000000040','TASK_CREATED', '2018-01-29 15:55:10' , 'admin', 'DOMAIN_A', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000011','BPI:02' ,'' ,'TKI:000000000000000000000000000000000066', 'TASK_CREATED', '2018-01-29 15:55:11','peter', 'DOMAIN_A', 'WBI:100000000000000000000000000000000001', '00' , 'PASystem', '00' , 'VNR' , '11223344', '' , '' ,'' ,'2old_val' ,'new_val2' ,'custom1' ,'' , 'custom2' ,'' ,'someDetails' ),
('HEI:000000000000000000000000000000000012','BPI:03' ,'BPI:01','TKI:000000000000000000000000000000000066','TASK_CREATED', '2018-01-29 15:55:12' , 'admin', 'DOMAIN_A', 'WBI:100000000000000000000000000000000002', '11' , '' , '22' , '' , '' , 'L140101' , 'TASK' ,'DOCTYPE_DEFAULT' ,'' ,'' ,'custom1' ,'' , 'custom3' ,'' ,'someDetails' )
;

View File

@ -47,6 +47,9 @@ INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000037', 'ETI:0000000
INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000038', 'ETI:000000000000000000000000000000000038', '2018-01-29 15:55:24', '2018-01-30 15:55:24', '2018-01-30 16:55:24', '2018-01-30 16:55:24', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , 'COMPLETED' , 'EXTERN' , 'L1050' , 'CLI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000007' , 'USER-1-2' , 'DOMAIN_A', 'PI_0000000000038' , 'DOC_0000000000000000038' , 'user-1-2' , '00' , 'PASystem' , '00' , 'SDNR' , '00011122' , true , false , null , 'NONE' , null , null , null , null , null , 'al' , '11' , null , null , null , null , null , null , null , 'abc' , null , null );
INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000039', 'ETI:000000000000000000000000000000000039', '2018-01-29 15:55:24', '2018-01-30 15:55:24', '2018-01-30 16:55:24', '2018-01-30 16:55:24', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , 'COMPLETED' , 'EXTERN' , 'L1050' , 'CLI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000007' , 'USER-1-2' , 'DOMAIN_A', 'PI_0000000000039' , 'DOC_0000000000000000039' , 'user-1-2' , '00' , 'PASystem' , '00' , 'SDNR' , '00011122' , true , false , null , 'NONE' , null , null , null , null , null , null , null , null , null , null , null , null , null , null , 'abc' , null , null );
INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000040', 'ETI:000000000000000000000000000000000040', '2018-01-29 15:55:24', '2018-01-30 15:55:24', '2018-01-30 16:55:24', '2018-01-30 16:55:24', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , 'COMPLETED' , 'EXTERN' , 'L1050' , 'CLI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000007' , 'USER-1-2' , 'DOMAIN_A', 'PI_0000000000040' , 'DOC_0000000000000000040' , 'user-1-2' , '00' , 'PASystem' , '00' , 'SDNR' , '00011122' , true , false , null , 'NONE' , null , null , null , null , null , null , null , null , null , null , null , null , null , null , 'abc' , null , null );
INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000067', 'ETI:000000000000000000000000000000000067', '2018-01-29 15:55:24', '2018-01-30 15:55:24', '2018-01-30 16:55:24', '2018-01-30 16:55:24', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , 'COMPLETED' , 'EXTERN' , 'T2000' , 'CLI:100000000000000000000000000000000016', 'WBI:100000000000000000000000000000000006' , 'USER-1-2' , 'DOMAIN_A', 'PI_0000000000067' , 'DOC_0000000000000000067' , 'user-1-2' , '00' , 'PASystem' , '00' , 'SDNR' , '00011122' , true , false , null , 'NONE' , null , null , null , null , null , null , null , null , null , null , null , null , null , null , 'abc' , null , null );
INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000068', 'ETI:000000000000000000000000000000000068', '2018-01-29 15:55:24', '2018-01-30 15:55:24', '2018-01-30 16:55:24', '2018-01-30 16:55:24', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , 'COMPLETED' , 'EXTERN' , 'T2000' , 'CLI:100000000000000000000000000000000016', 'WBI:100000000000000000000000000000000006' , 'USER-1-2' , 'DOMAIN_A', 'PI_0000000000068' , 'DOC_0000000000000000068' , 'user-1-2' , '00' , 'PASystem' , '00' , 'SDNR' , '00011122' , true , false , null , 'NONE' , null , null , null , null , null , null , null , null , null , null , null , null , null , null , 'abc' , null , null );
INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000069', 'ETI:000000000000000000000000000000000069', '2018-01-29 15:55:24', '2018-01-30 15:55:24', '2018-01-30 16:55:24', '2018-01-30 16:55:24', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , 'COMPLETED' , 'EXTERN' , 'T2000' , 'CLI:100000000000000000000000000000000016', 'WBI:100000000000000000000000000000000006' , 'USER-1-2' , 'DOMAIN_A', 'PI_0000000000068' , 'DOC_0000000000000000068' , 'user-1-2' , '00' , 'PASystem' , '00' , 'SDNR' , '00011122' , true , false , null , 'NONE' , null , null , null , null , null , null , null , null , null , null , null , null , null , null , 'abc' , null , null );
-- Tasks for QueryTasksWithSortingTest
INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000041', 'ETI:000000000000000000000000000000000041', '2018-01-29 15:55:00', '2018-01-30 15:55:00', null , '2018-01-30 15:55:00', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Task99' , 'creator_user_id' , 'Lorem ipsum was n Quatsch dolor sit amet.', 'Some custom Note' , 1 , 'CLAIMED' , 'AUTOMATIC' , 'T6310' , 'CLI:000000000000000000000000000000000011', 'WBI:100000000000000000000000000000000015' , 'USER-B-2' , 'DOMAIN_B', 'BPI21' , 'PBPI21' , 'user-b-1' , 'MyCompany1', 'MySystem1', 'MyInstance1' , 'MyType1', 'MyValue1' , true , false , null , 'NONE' , null , null , null , null , null , null , null , null , null , null , null , null , null , null , 'abc' , null , null );

View File

@ -4,10 +4,10 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.PagedModel.PageMetadata;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
@ -26,11 +26,13 @@ import org.springframework.web.bind.annotation.RestController;
import pro.taskana.classification.api.exceptions.ClassificationNotFoundException;
import pro.taskana.common.api.BaseQuery.SortDirection;
import pro.taskana.common.api.BulkOperationResults;
import pro.taskana.common.api.KeyDomain;
import pro.taskana.common.api.TimeInterval;
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.rest.AbstractPagingController;
import pro.taskana.common.rest.Mapping;
import pro.taskana.common.rest.models.TaskanaPagedModel;
@ -69,6 +71,7 @@ public class TaskController extends AbstractPagingController {
private static final String OWNER = "owner";
private static final String OWNER_LIKE = "owner-like";
private static final String DOMAIN = "domain";
private static final String TASK_ID = "task-id";
private static final String WORKBASKET_ID = "workbasket-id";
private static final String WORKBASKET_KEY = "workbasket-key";
private static final String CLASSIFICATION_KEY = "classification.key";
@ -133,6 +136,41 @@ public class TaskController extends AbstractPagingController {
return response;
}
@DeleteMapping(path = Mapping.URL_TASKS)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<CollectionModel<TaskSummaryRepresentationModel>> deleteTasks(
@RequestParam MultiValueMap<String, String> params)
throws InvalidArgumentException, NotAuthorizedException {
LOGGER.debug("Entry to deleteTasks(params= {})", params);
TaskQuery query = taskService.createTaskQuery();
query = applyFilterParams(query, params);
validateNoInvalidParameterIsLeft(params);
List<TaskSummary> taskSummaries = getQueryList(query, null);
List<String> taskIdsToDelete =
taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList());
BulkOperationResults<String, TaskanaException> result =
taskService.deleteTasks(taskIdsToDelete);
List<TaskSummary> successfullyDeletedTaskSummaries =
taskSummaries.stream()
.filter(summary -> !result.getFailedIds().contains(summary.getId()))
.collect(Collectors.toList());
ResponseEntity<CollectionModel<TaskSummaryRepresentationModel>> response =
ResponseEntity.ok(
taskSummaryRepresentationModelAssembler.toCollectionModel(
successfullyDeletedTaskSummaries));
LOGGER.debug("Exit from deleteTasks(), returning {}", response);
return response;
}
@GetMapping(path = Mapping.URL_TASKS_ID)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<TaskRepresentationModel> getTask(@PathVariable String taskId)
@ -342,6 +380,11 @@ public class TaskController extends AbstractPagingController {
taskQuery.classificationKeyIn(classificationKeys);
params.remove(CLASSIFICATION_KEY);
}
if (params.containsKey(TASK_ID)) {
String[] taskIds = extractCommaSeparatedFields(params.get(TASK_ID));
taskQuery.idIn(taskIds);
params.remove(TASK_ID);
}
if (params.containsKey(WORKBASKET_ID)) {
String[] workbaskets = extractCommaSeparatedFields(params.get(WORKBASKET_ID));
taskQuery.workbasketIdIn(workbaskets);
@ -438,6 +481,13 @@ public class TaskController extends AbstractPagingController {
params.remove(EXTERNAL_ID);
}
for (int i = 1; i < 17; i++) {
if (params.containsKey(CUSTOM + i)) {
taskQuery.customAttributeIn(String.valueOf(i), params.get(CUSTOM + i).get(0));
params.remove(CUSTOM + i);
}
}
for (int i = 1; i <= 16; i++) {
if (params.containsKey(CUSTOM + i)) {
String[] customValues = extractCommaSeparatedFields(params.get(CUSTOM + i));

View File

@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
@ -240,6 +241,27 @@ class TaskControllerIntTest {
assertThat(response.getBody().getContent()).hasSize(4);
}
@Test
void should_DeleteAllTasks_For_ProvidedParams() {
ResponseEntity<CollectionModel<TaskSummaryRepresentationModel>> response =
template.exchange(
restHelper.toUrl(Mapping.URL_TASKS)
+ "?task-id=TKI:000000000000000000000000000000000036,"
+ "TKI:000000000000000000000000000000000037,"
+ "TKI:000000000000000000000000000000000038"
+ "&custom14=abc",
HttpMethod.DELETE,
new HttpEntity<String>(restHelper.getHeadersAdmin()),
new ParameterizedTypeReference<CollectionModel<TaskSummaryRepresentationModel>>() {
});
;
assertThat(response.getBody()).isNotNull();
assertThat((response.getBody()).getLink(IanaLinkRelations.SELF))
.isNotNull();
assertThat(response.getBody().getContent()).hasSize(3);
}
@Test
void should_ThrowException_When_ProvidingInvalidWildcardSearchParameters() {

View File

@ -15,3 +15,5 @@ taskana.jobs.cleanup.runEvery=P1D
taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.cleanup.minimumAge=P14D
taskana.german.holidays.enabled=true
taskana.history.deletion.on.task.deletion.enabled=true