diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateGroupRepository.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateGroupRepository.java index 6c783ad280..83aabc8714 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateGroupRepository.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateGroupRepository.java @@ -18,6 +18,7 @@ import static org.activiti.cloud.services.query.app.repository.QuerydslBindingsHelper.whitelist; import com.querydsl.core.types.dsl.StringPath; +import java.util.Set; import org.activiti.cloud.services.query.model.QTaskCandidateGroupEntity; import org.activiti.cloud.services.query.model.TaskCandidateGroupEntity; import org.activiti.cloud.services.query.model.TaskCandidateGroupId; @@ -33,6 +34,8 @@ public interface TaskCandidateGroupRepository QuerydslPredicateExecutor, QuerydslBinderCustomizer, CrudRepository { + Set findByTaskIdIn(Set collect); + @Override default void customize(QuerydslBindings bindings, QTaskCandidateGroupEntity root) { whitelist(root).apply(bindings); diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateUserRepository.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateUserRepository.java index 51e31b6a46..6b787ba2db 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateUserRepository.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskCandidateUserRepository.java @@ -18,6 +18,8 @@ import static org.activiti.cloud.services.query.app.repository.QuerydslBindingsHelper.whitelist; import com.querydsl.core.types.dsl.StringPath; +import java.util.Collection; +import java.util.Set; import org.activiti.cloud.services.query.model.QTaskCandidateUserEntity; import org.activiti.cloud.services.query.model.TaskCandidateUserEntity; import org.activiti.cloud.services.query.model.TaskCandidateUserId; @@ -33,6 +35,8 @@ public interface TaskCandidateUserRepository QuerydslPredicateExecutor, QuerydslBinderCustomizer, CrudRepository { + Set findByTaskIdIn(Collection taskIds); + @Override default void customize(QuerydslBindings bindings, QTaskCandidateUserEntity root) { whitelist(root).apply(bindings); diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskRepository.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskRepository.java index 547604f65d..6e1918b35a 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskRepository.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-repo/src/main/java/org/activiti/cloud/services/query/app/repository/TaskRepository.java @@ -17,10 +17,14 @@ import static org.activiti.cloud.services.query.app.repository.QuerydslBindingsHelper.whitelist; +import com.querydsl.core.Tuple; import com.querydsl.core.types.dsl.StringPath; import java.util.Arrays; import org.activiti.cloud.services.query.model.QTaskEntity; import org.activiti.cloud.services.query.model.TaskEntity; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/conf/QueryRestWebMvcAutoConfiguration.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/conf/QueryRestWebMvcAutoConfiguration.java index bf38a00dda..01a151d582 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/conf/QueryRestWebMvcAutoConfiguration.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/conf/QueryRestWebMvcAutoConfiguration.java @@ -19,6 +19,8 @@ import org.activiti.cloud.alfresco.data.domain.AlfrescoPagedModelAssembler; import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.TaskEntity; @@ -202,6 +204,8 @@ public ProcessDefinitionRestrictionService processDefinitionRestrictionService( @ConditionalOnMissingBean public TaskControllerHelper taskControllerHelper( TaskRepository taskRepository, + TaskCandidateUserRepository taskCandidateUserRepository, + TaskCandidateGroupRepository taskCandidateGroupRepository, ProcessVariableService processVariableService, AlfrescoPagedModelAssembler pagedCollectionModelAssembler, TaskRepresentationModelAssembler taskRepresentationModelAssembler, @@ -210,6 +214,8 @@ public TaskControllerHelper taskControllerHelper( ) { return new TaskControllerHelper( taskRepository, + taskCandidateUserRepository, + taskCandidateGroupRepository, processVariableService, pagedCollectionModelAssembler, new QueryDslPredicateAggregator(), diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/ProcessInstanceSearchService.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/ProcessInstanceSearchService.java index 67d278b1f7..935cc26546 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/ProcessInstanceSearchService.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/ProcessInstanceSearchService.java @@ -15,15 +15,27 @@ */ package org.activiti.cloud.services.query.rest; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Tuple; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.criteria.Selection; +import java.util.ArrayList; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.activiti.api.runtime.shared.security.SecurityManager; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; import org.activiti.cloud.services.query.model.ProcessInstanceEntity; import org.activiti.cloud.services.query.model.ProcessVariableKey; import org.activiti.cloud.services.query.rest.payload.ProcessInstanceSearchRequest; import org.activiti.cloud.services.query.rest.specification.ProcessInstanceSpecification; +import org.activiti.cloud.services.query.rest.specification.SubqueryWrappingSpecification; import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.transaction.annotation.Transactional; @@ -35,6 +47,9 @@ public class ProcessInstanceSearchService { private final SecurityManager securityManager; + @PersistenceContext + private EntityManager entityManager; + public ProcessInstanceSearchService( ProcessInstanceRepository processInstanceRepository, ProcessVariableService processVariableService, @@ -77,9 +92,10 @@ private Page search( Pageable pageable, ProcessInstanceSpecification specification ) { - Page processInstances = processInstanceRepository.findAll( - specification, - PageRequest.of(pageable.getPageNumber(), pageable.getPageSize()) + Page processInstances = new PageImpl<>( + executeTupleQueryAndExtractTasks(getTupleQuery(specification, pageable)), + pageable, + processInstanceRepository.count(new SubqueryWrappingSpecification<>(specification)) ); processVariableService.fetchProcessVariablesForProcessInstances( processInstances.getContent(), @@ -87,4 +103,27 @@ private Page search( ); return processInstances; } + + private TypedQuery getTupleQuery(ProcessInstanceSpecification taskSpecification, Pageable pageable) { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery tupleQuery = cb.createTupleQuery(); + Root root = tupleQuery.from(ProcessInstanceEntity.class); + tupleQuery.where(taskSpecification.toPredicate(root, tupleQuery, cb)); + List> selections = new ArrayList<>(); + selections.add(root); + tupleQuery.getOrderList().forEach(order -> selections.add(order.getExpression())); + tupleQuery.multiselect(selections.toArray(new Selection[0])); + TypedQuery query = entityManager.createQuery(tupleQuery); + query.setFirstResult((int) pageable.getOffset()); + query.setMaxResults(pageable.getPageSize()); + return query; + } + + private List executeTupleQueryAndExtractTasks(TypedQuery query) { + return query + .getResultList() + .stream() + .map(t -> t.get(0, ProcessInstanceEntity.class)) + .collect(Collectors.toList()); + } } diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/TaskControllerHelper.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/TaskControllerHelper.java index e1d7b5f67e..a9d58f79fc 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/TaskControllerHelper.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/TaskControllerHelper.java @@ -17,19 +17,38 @@ package org.activiti.cloud.services.query.rest; import com.querydsl.core.types.Predicate; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Tuple; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.criteria.Selection; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.activiti.api.runtime.shared.security.SecurityManager; import org.activiti.cloud.alfresco.data.domain.AlfrescoPagedModelAssembler; import org.activiti.cloud.api.task.model.QueryCloudTask; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; +import org.activiti.cloud.services.query.model.TaskCandidateGroupEntity; +import org.activiti.cloud.services.query.model.TaskCandidateUserEntity; import org.activiti.cloud.services.query.model.TaskEntity; import org.activiti.cloud.services.query.rest.assembler.TaskRepresentationModelAssembler; import org.activiti.cloud.services.query.rest.payload.TaskSearchRequest; import org.activiti.cloud.services.query.rest.predicate.QueryDslPredicateAggregator; import org.activiti.cloud.services.query.rest.predicate.QueryDslPredicateFilter; +import org.activiti.cloud.services.query.rest.specification.SubqueryWrappingSpecification; import org.activiti.cloud.services.query.rest.specification.TaskSpecification; import org.activiti.cloud.services.security.TaskLookupRestrictionService; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.PagedModel; @@ -39,6 +58,10 @@ public class TaskControllerHelper { private final TaskRepository taskRepository; + private final TaskCandidateUserRepository taskCandidateUserRepository; + + private final TaskCandidateGroupRepository taskCandidateGroupRepository; + private final ProcessVariableService processVariableService; private final AlfrescoPagedModelAssembler pagedCollectionModelAssembler; @@ -51,8 +74,13 @@ public class TaskControllerHelper { private final SecurityManager securityManager; + @PersistenceContext + private EntityManager entityManager; + public TaskControllerHelper( TaskRepository taskRepository, + TaskCandidateUserRepository taskCandidateUserRepository, + TaskCandidateGroupRepository taskCandidateGroupRepository, ProcessVariableService processVariableService, AlfrescoPagedModelAssembler pagedCollectionModelAssembler, QueryDslPredicateAggregator predicateAggregator, @@ -61,6 +89,8 @@ public TaskControllerHelper( SecurityManager securityManager ) { this.taskRepository = taskRepository; + this.taskCandidateUserRepository = taskCandidateUserRepository; + this.taskCandidateGroupRepository = taskCandidateGroupRepository; this.processVariableService = processVariableService; this.pagedCollectionModelAssembler = pagedCollectionModelAssembler; this.predicateAggregator = predicateAggregator; @@ -121,7 +151,13 @@ private PagedModel> searchTasks( Pageable pageable, TaskSpecification taskSpecification ) { - Page tasks = taskRepository.findAll(taskSpecification, pageable); + Page tasks = new PageImpl<>( + executeTupleQueryAndExtractTasks(getTupleQuery(taskSpecification, pageable)), + pageable, + taskRepository.count(new SubqueryWrappingSpecification<>(taskSpecification)) + ); + fetchTaskCandidateUsers(tasks.getContent()); + fetchTaskCandidateGroups(tasks.getContent()); processVariableService.fetchProcessVariablesForTasks( tasks.getContent(), taskSearchRequest.processVariableKeys() @@ -211,4 +247,39 @@ private Page findPageWithProcessVariables( return taskRepository.findAll(extendedPredicate, pageable); } } + + private TypedQuery getTupleQuery(TaskSpecification taskSpecification, Pageable pageable) { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery tupleQuery = cb.createTupleQuery(); + Root root = tupleQuery.from(TaskEntity.class); + tupleQuery.where(taskSpecification.toPredicate(root, tupleQuery, cb)); + List> selections = new ArrayList<>(); + selections.add(root); + tupleQuery.getOrderList().forEach(order -> selections.add(order.getExpression())); + tupleQuery.multiselect(selections.toArray(new Selection[0])); + TypedQuery query = entityManager.createQuery(tupleQuery); + query.setFirstResult((int) pageable.getOffset()); + query.setMaxResults(pageable.getPageSize()); + return query; + } + + private List executeTupleQueryAndExtractTasks(TypedQuery query) { + return query.getResultList().stream().map(t -> t.get(0, TaskEntity.class)).collect(Collectors.toList()); + } + + private void fetchTaskCandidateUsers(Collection tasks) { + Map> candidatesByTaskId = taskCandidateUserRepository + .findByTaskIdIn(tasks.stream().map(TaskEntity::getId).collect(Collectors.toSet())) + .stream() + .collect(Collectors.groupingBy(TaskCandidateUserEntity::getTaskId, Collectors.toSet())); + tasks.forEach(task -> task.setTaskCandidateUsers(candidatesByTaskId.get(task.getId()))); + } + + private void fetchTaskCandidateGroups(Collection tasks) { + Map> candidatesByTaskId = taskCandidateGroupRepository + .findByTaskIdIn(tasks.stream().map(TaskEntity::getId).collect(Collectors.toSet())) + .stream() + .collect(Collectors.groupingBy(TaskCandidateGroupEntity::getTaskId, Collectors.toSet())); + tasks.forEach(task -> task.setTaskCandidateGroups(candidatesByTaskId.get(task.getId()))); + } } diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/ProcessInstanceSpecification.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/ProcessInstanceSpecification.java index 26a676c9b5..40d9d70826 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/ProcessInstanceSpecification.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/ProcessInstanceSpecification.java @@ -59,6 +59,7 @@ public Predicate toPredicate( CriteriaBuilder criteriaBuilder ) { predicates = new ArrayList<>(); + query.distinct(distinct); applyUserRestrictionFilter(root, criteriaBuilder); applyNameFilter(root, criteriaBuilder); applyInitiatorFilter(root); @@ -72,7 +73,7 @@ public Predicate toPredicate( if (!query.getResultType().equals(Long.class)) { applySorting( root, - root.join(ProcessInstanceEntity_.variables, JoinType.LEFT), + () -> root.join(ProcessInstanceEntity_.variables, JoinType.LEFT), searchRequest.sort(), query, criteriaBuilder diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/SpecificationSupport.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/SpecificationSupport.java index aa05597aab..4889fc3df7 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/SpecificationSupport.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/SpecificationSupport.java @@ -25,6 +25,7 @@ import jakarta.persistence.metamodel.SingularAttribute; import java.util.Collection; import java.util.Set; +import java.util.function.Supplier; import org.activiti.cloud.dialect.CustomPostgreSQLDialect; import org.activiti.cloud.services.query.model.ProcessVariableEntity; import org.activiti.cloud.services.query.model.ProcessVariableEntity_; @@ -37,6 +38,12 @@ public abstract class SpecificationSupport implements Specification { + protected boolean distinct = true; + + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + protected void addLikeFilters( Collection predicates, Set valuesToFilter, @@ -165,7 +172,7 @@ protected Predicate getVariableValueCondition( protected void applySorting( Root root, - SetJoin joinedProcessVars, + Supplier> joinSupplier, CloudRuntimeEntitySort sort, CriteriaQuery query, CriteriaBuilder criteriaBuilder @@ -174,6 +181,7 @@ protected void applySorting( validateSort(sort); Expression orderByClause; if (sort.isProcessVariable()) { + SetJoin joinedProcessVars = joinSupplier.get(); Expression extractedValue = criteriaBuilder.function( CustomPostgreSQLDialect.getExtractionFunction(sort.type()), Object.class, diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/SubqueryWrappingSpecification.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/SubqueryWrappingSpecification.java new file mode 100644 index 0000000000..6d30a98042 --- /dev/null +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/SubqueryWrappingSpecification.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017-2020 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.activiti.cloud.services.query.rest.specification; + +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.criteria.Subquery; +import org.springframework.data.jpa.domain.Specification; + +public class SubqueryWrappingSpecification implements Specification { + + private final SpecificationSupport specification; + + public SubqueryWrappingSpecification(SpecificationSupport specification) { + this.specification = specification; + } + + @Override + public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) { + specification.setDistinct(false); + Subquery subquery = query.subquery(root.getModel().getJavaType()); + Root subroot = subquery.correlate(root); + subquery.select(subroot); + subquery.select(subroot).where(specification.toPredicate(subroot, query, criteriaBuilder)).distinct(true); + return root.in(subquery); + } +} diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/TaskSpecification.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/TaskSpecification.java index 1900c8f9aa..8246e8c19d 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/TaskSpecification.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/main/java/org/activiti/cloud/services/query/rest/specification/TaskSpecification.java @@ -20,7 +20,6 @@ import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; -import jakarta.persistence.criteria.SetJoin; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -39,6 +38,7 @@ public class TaskSpecification extends SpecificationSupport { private List predicates; + private List havingClauses; private final TaskSearchRequest taskSearchRequest; @@ -85,6 +85,8 @@ public static TaskSpecification restricted( @Override public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) { predicates = new ArrayList<>(); + havingClauses = new ArrayList<>(); + query.distinct(distinct); applyUserRestrictionFilter(root, criteriaBuilder); applyRootTasksFilter(root, criteriaBuilder); applyStandaloneFilter(root, criteriaBuilder); @@ -104,10 +106,13 @@ public Predicate toPredicate(Root root, CriteriaQuery query, Crit applyCandidateGroupFilter(root); applyTaskVariableFilters(root, query, criteriaBuilder); applyProcessVariableFilters(root, query, criteriaBuilder); + if (!havingClauses.isEmpty()) { + query.having(havingClauses.toArray(Predicate[]::new)); + } if (!query.getResultType().equals(Long.class)) { applySorting( root, - root.join(TaskEntity_.processVariables, JoinType.LEFT), + () -> root.join(TaskEntity_.processVariables, JoinType.LEFT), taskSearchRequest.sort(), query, criteriaBuilder @@ -285,7 +290,7 @@ private void applyProcessVariableFilters( ) ); query.groupBy(root.get(TaskEntity_.id)); - query.having(getHavingClause(pvRoot, taskSearchRequest.processVariableFilters(), criteriaBuilder)); + havingClauses.add(getHavingClause(pvRoot, taskSearchRequest.processVariableFilters(), criteriaBuilder)); } } @@ -295,21 +300,28 @@ private void applyTaskVariableFilters( CriteriaBuilder criteriaBuilder ) { if (!CollectionUtils.isEmpty(taskSearchRequest.taskVariableFilters())) { - SetJoin join = root.join(TaskEntity_.variables); + Root tvRoot = query.from(TaskVariableEntity.class); + Predicate joinCondition = criteriaBuilder.equal( + root.get(TaskEntity_.id), + tvRoot.get(TaskVariableEntity_.taskId) + ); Predicate[] variableValueFilters = taskSearchRequest .taskVariableFilters() .stream() .map(filter -> criteriaBuilder.and( - criteriaBuilder.equal(join.get(TaskVariableEntity_.name), filter.name()), - getVariableValueCondition(join.get(TaskVariableEntity_.value), filter, criteriaBuilder) + joinCondition, + criteriaBuilder.equal(tvRoot.get(TaskVariableEntity_.name), filter.name()), + getVariableValueCondition(tvRoot.get(TaskVariableEntity_.value), filter, criteriaBuilder) ) ) .toArray(Predicate[]::new); predicates.add(criteriaBuilder.or(variableValueFilters)); query.groupBy(root.get(TaskEntity_.id)); - query.having(getHavingClause(join, taskSearchRequest.taskVariableFilters(), criteriaBuilder)); + havingClauses.add( + getTaskVariablesHavingClause(tvRoot, taskSearchRequest.taskVariableFilters(), criteriaBuilder) + ); } } @@ -343,8 +355,8 @@ private void applyUserRestrictionFilter(Root root, CriteriaBuilder c } } - private Predicate getHavingClause( - SetJoin root, + private Predicate getTaskVariablesHavingClause( + Root root, Collection filters, CriteriaBuilder criteriaBuilder ) { diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractProcessInstanceEntitySearchControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractProcessInstanceEntitySearchControllerIT.java index a60661d8a2..330b0ccbc2 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractProcessInstanceEntitySearchControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractProcessInstanceEntitySearchControllerIT.java @@ -19,6 +19,7 @@ import static io.restassured.module.mockmvc.RestAssuredMockMvc.postProcessors; import static io.restassured.module.mockmvc.RestAssuredMockMvc.webAppContextSetup; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInRelativeOrder; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; @@ -31,8 +32,10 @@ import java.util.Date; import java.util.List; import java.util.UUID; +import java.util.stream.IntStream; import org.activiti.QueryRestTestApplication; import org.activiti.api.process.model.ProcessInstance; +import org.activiti.api.task.model.Task; import org.activiti.cloud.alfresco.config.AlfrescoWebAutoConfiguration; import org.activiti.cloud.services.query.model.ProcessInstanceEntity; import org.activiti.cloud.services.query.model.ProcessVariableKey; @@ -40,8 +43,12 @@ import org.activiti.cloud.services.query.rest.filter.VariableFilter; import org.activiti.cloud.services.query.rest.filter.VariableType; import org.activiti.cloud.services.query.rest.payload.CloudRuntimeEntitySort; +import org.activiti.cloud.services.query.rest.payload.ProcessInstanceSearchRequest; +import org.activiti.cloud.services.query.rest.payload.TaskSearchRequest; import org.activiti.cloud.services.query.util.ProcessInstanceSearchRequestBuilder; import org.activiti.cloud.services.query.util.QueryTestUtils; +import org.activiti.cloud.services.query.util.TaskBuilder; +import org.activiti.cloud.services.query.util.TaskSearchRequestBuilder; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -2708,4 +2715,49 @@ void should_returnFilteredPaginatedAndSortedProcessInstances() { .body("page.size", is(4)) .body("page.number", is(2)); } + + @Test + void should_returnCorrectNumberOfDistinctProcessInstances() { + for (int i = 0; i < 10; i++) { + queryTestUtils + .buildProcessInstance() + .withId(String.valueOf(i)) + .withInitiator(USER) + .withProcessDefinitionKey(PROCESS_DEFINITION_KEY) + .withTasks( + queryTestUtils + .buildTask() + .withName("task1") + .withVariables( + new QueryTestUtils.VariableInput(VAR_NAME, VariableType.STRING, "value"), + new QueryTestUtils.VariableInput("var2", VariableType.STRING, "value2") + ), + queryTestUtils + .buildTask() + .withName("task2") + .withVariables( + new QueryTestUtils.VariableInput(VAR_NAME, VariableType.STRING, "value"), + new QueryTestUtils.VariableInput("var2", VariableType.STRING, "value2") + ) + ) + .withVariables( + new QueryTestUtils.VariableInput(VAR_NAME, VariableType.STRING, "value"), + new QueryTestUtils.VariableInput("var2", VariableType.STRING, "value2"), + new QueryTestUtils.VariableInput("var3", VariableType.STRING, "value3") + ) + .buildAndSave(); + } + + ProcessInstanceSearchRequest request = new ProcessInstanceSearchRequestBuilder().withInitiators(USER).build(); + + given() + .contentType(MediaType.APPLICATION_JSON) + .body(request) + .param("maxItems", 10) + .when() + .post(getSearchEndpoint()) + .then() + .statusCode(200) + .body(PROCESS_INSTANCES_JSON_PATH, hasSize(10)); + } } diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractTaskControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractTaskControllerIT.java index fea6474127..654f216df2 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractTaskControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/AbstractTaskControllerIT.java @@ -29,14 +29,18 @@ import java.util.Date; import java.util.List; import java.util.UUID; +import java.util.stream.IntStream; import org.activiti.api.task.model.Task; +import org.activiti.cloud.services.query.model.ProcessInstanceEntity; import org.activiti.cloud.services.query.model.ProcessVariableKey; import org.activiti.cloud.services.query.model.TaskEntity; import org.activiti.cloud.services.query.rest.filter.FilterOperator; import org.activiti.cloud.services.query.rest.filter.VariableFilter; import org.activiti.cloud.services.query.rest.filter.VariableType; import org.activiti.cloud.services.query.rest.payload.CloudRuntimeEntitySort; +import org.activiti.cloud.services.query.rest.payload.TaskSearchRequest; import org.activiti.cloud.services.query.util.QueryTestUtils; +import org.activiti.cloud.services.query.util.TaskBuilder; import org.activiti.cloud.services.query.util.TaskSearchRequestBuilder; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -3938,6 +3942,8 @@ void should_returnFilteredPaginatedAndSortedTasks() { for (int i = 0; i < 10; i++) { queryTestUtils .buildTask() + .withTaskCandidateGroups("group1", "group2") + .withTaskCandidateUsers(CURRENT_USER, "other-user") .withAssignee(CURRENT_USER) .withVariables(new QueryTestUtils.VariableInput(VAR_NAME, VariableType.STRING, "value")) .withId(String.valueOf(i)) @@ -3999,4 +4005,68 @@ void should_returnFilteredPaginatedAndSortedTasks() { .body("page.size", is(4)) .body("page.number", is(2)); } + + @Test + void should_returnCorrectNumberOfDistinctTasks_whenJoiningTaskAndProcessVariables() { + ProcessInstanceEntity processInstance = queryTestUtils + .buildProcessInstance() + .withTasks( + IntStream + .range(0, 10) + .mapToObj(i -> + queryTestUtils + .buildTask() + .withId(String.valueOf(i)) + .withAssignee(CURRENT_USER) + .withTaskCandidateUsers(CURRENT_USER, "other-user") + .withTaskCandidateGroups("group1", "group2") + .withVariables(new QueryTestUtils.VariableInput("taskVar", VariableType.STRING, "value")) + ) + .toArray(TaskBuilder[]::new) + ) + .withVariables( + IntStream + .range(0, 10) + .mapToObj(i -> new QueryTestUtils.VariableInput("var" + i, VariableType.STRING, "value")) + .toArray(QueryTestUtils.VariableInput[]::new) + ) + .buildAndSave(); + + TaskSearchRequest request = new TaskSearchRequestBuilder() + .withTaskVariableFilters( + new VariableFilter( + processInstance.getProcessDefinitionKey(), + "taskVar", + VariableType.STRING, + "value", + FilterOperator.EQUALS + ) + ) + .withProcessVariableFilters( + new VariableFilter( + processInstance.getProcessDefinitionKey(), + "var1", + VariableType.STRING, + "value", + FilterOperator.EQUALS + ) + ) + .withSort(new CloudRuntimeEntitySort("createdDate", Sort.Direction.DESC, false, null, null)) + .withStatus(Task.TaskStatus.ASSIGNED) + .build(); + + given() + .contentType(MediaType.APPLICATION_JSON) + .body(request) + .param("maxItems", 10) + .when() + .post(getSearchEndpointHttpPost()) + .then() + .statusCode(200) + .body(TASKS_JSON_PATH, hasSize(10)) + .body( + TASK_IDS_JSON_PATH, + contains(IntStream.range(0, 10).mapToObj(String::valueOf).toList().reversed().toArray()) + ); + } } diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationAdminControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationAdminControllerIT.java index f7627ddbea..0706fdf0cd 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationAdminControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationAdminControllerIT.java @@ -31,6 +31,8 @@ import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ApplicationRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ApplicationEntity; @@ -70,6 +72,12 @@ public class ApplicationAdminControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationControllerIT.java index 3a7219f87e..0dde8669c1 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ApplicationControllerIT.java @@ -31,6 +31,8 @@ import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ApplicationRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ApplicationEntity; @@ -70,6 +72,12 @@ public class ApplicationControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionAdminControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionAdminControllerIT.java index 0a207c033e..91da6f5ab0 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionAdminControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionAdminControllerIT.java @@ -31,6 +31,8 @@ import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.security.TaskLookupRestrictionService; @@ -70,6 +72,12 @@ public class ProcessDefinitionAdminControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionControllerIT.java index 8a5e196bcf..d38e0e062d 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessDefinitionControllerIT.java @@ -36,6 +36,8 @@ import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.QProcessDefinitionEntity; @@ -86,6 +88,12 @@ public class ProcessDefinitionControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityPoliciesManager securityPoliciesManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityAdminControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityAdminControllerIT.java index f3c3f73d3d..2a119daca7 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityAdminControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityAdminControllerIT.java @@ -34,6 +34,8 @@ import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ProcessInstanceEntity; @@ -71,6 +73,12 @@ public class ProcessInstanceEntityAdminControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityControllerIT.java index fe9d7097ba..04a4353190 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityControllerIT.java @@ -36,6 +36,8 @@ import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ProcessInstanceEntity; @@ -90,6 +92,12 @@ public class ProcessInstanceEntityControllerIT { @MockBean private ProcessDefinitionRepository processDefinitionRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityPoliciesProperties securityPoliciesProperties; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityDeleteControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityDeleteControllerIT.java index ef7aa0b9ab..7347b96916 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityDeleteControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityDeleteControllerIT.java @@ -43,6 +43,8 @@ import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; import org.activiti.cloud.services.query.app.repository.ServiceTaskRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.BPMNActivityEntity; @@ -84,6 +86,12 @@ public class ProcessInstanceEntityDeleteControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksAdminControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksAdminControllerIT.java index 215828df70..08654c6443 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksAdminControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksAdminControllerIT.java @@ -32,6 +32,8 @@ import org.activiti.cloud.alfresco.config.AlfrescoWebAutoConfiguration; import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.TaskEntity; @@ -76,6 +78,12 @@ public class ProcessInstanceEntityTasksAdminControllerIT { @MockBean private VariableRepository processVariableRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksControllerIT.java index fac0ae1d1d..ca46285855 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityTasksControllerIT.java @@ -34,6 +34,8 @@ import org.activiti.cloud.alfresco.config.AlfrescoWebAutoConfiguration; import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.TaskEntity; @@ -79,6 +81,12 @@ public class ProcessInstanceEntityTasksControllerIT { @MockBean private VariableRepository variableRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private UserGroupManager userGroupManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityVariableEntityControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityVariableEntityControllerIT.java index cd01040f6c..8c245d9075 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityVariableEntityControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessInstanceEntityVariableEntityControllerIT.java @@ -35,6 +35,8 @@ import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ProcessVariableEntity; @@ -75,6 +77,12 @@ public class ProcessInstanceEntityVariableEntityControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelAdminControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelAdminControllerIT.java index 510892e8d4..a9d9088e8a 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelAdminControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelAdminControllerIT.java @@ -33,6 +33,8 @@ import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; import org.activiti.cloud.services.query.app.repository.ProcessModelRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ProcessDefinitionEntity; @@ -69,6 +71,12 @@ public class ProcessModelAdminControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private UserGroupManager userGroupManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelControllerIT.java index c65eb5c789..ce8297112f 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/ProcessModelControllerIT.java @@ -35,6 +35,8 @@ import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; import org.activiti.cloud.services.query.app.repository.ProcessModelRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ProcessDefinitionEntity; @@ -71,6 +73,12 @@ public class ProcessModelControllerIT { @MockBean private SecurityPoliciesManager securityPoliciesManager; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private ProcessInstanceRepository processInstanceRepository; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityAdminControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityAdminControllerIT.java index 4035872581..ad07eb6056 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityAdminControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityAdminControllerIT.java @@ -37,6 +37,8 @@ import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.TaskEntity; @@ -79,6 +81,12 @@ public class TaskEntityAdminControllerIT { @MockBean private ProcessInstanceRepository processInstanceRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private TaskRepository taskRepository; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityControllerIT.java index 21b8ad317f..c9b3c1f0fc 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityControllerIT.java @@ -43,6 +43,8 @@ import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.TaskCandidateGroupEntity; @@ -99,6 +101,12 @@ class TaskEntityControllerIT { @MockBean private VariableRepository processVariableRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private EntityFinder entityFinder; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityDeleteControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityDeleteControllerIT.java index 1fe39e59d8..c77fe08b8b 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityDeleteControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityDeleteControllerIT.java @@ -35,6 +35,8 @@ import org.activiti.cloud.services.query.app.repository.EntityFinder; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.TaskEntity; @@ -78,6 +80,12 @@ public class TaskEntityDeleteControllerIT { @MockBean private VariableRepository processVariableRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityVariableEntityControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityVariableEntityControllerIT.java index 92cc9dc307..0a6dfbfb37 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityVariableEntityControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/TaskEntityVariableEntityControllerIT.java @@ -35,6 +35,8 @@ import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ProcessDefinitionRepository; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.TaskVariableRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; @@ -79,6 +81,12 @@ public class TaskEntityVariableEntityControllerIT { @MockBean private VariableRepository processVariableRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private SecurityManager securityManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/VariableEntityAdminControllerIT.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/VariableEntityAdminControllerIT.java index 5d83af44bc..6f4b7d127b 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/VariableEntityAdminControllerIT.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/rest/VariableEntityAdminControllerIT.java @@ -35,6 +35,8 @@ import org.activiti.cloud.alfresco.config.AlfrescoWebAutoConfiguration; import org.activiti.cloud.conf.QueryRestWebMvcAutoConfiguration; import org.activiti.cloud.services.query.app.repository.ProcessInstanceRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateGroupRepository; +import org.activiti.cloud.services.query.app.repository.TaskCandidateUserRepository; import org.activiti.cloud.services.query.app.repository.TaskRepository; import org.activiti.cloud.services.query.app.repository.TaskVariableRepository; import org.activiti.cloud.services.query.app.repository.VariableRepository; @@ -77,6 +79,12 @@ public class VariableEntityAdminControllerIT { @MockBean private VariableRepository processVariableRepository; + @MockBean + private TaskCandidateUserRepository taskCandidateUserRepository; + + @MockBean + private TaskCandidateGroupRepository taskCandidateGroupRepository; + @MockBean private UserGroupManager userGroupManager; diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/ProcessInstanceBuilder.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/ProcessInstanceBuilder.java index c90148d5bf..3a3f941fd0 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/ProcessInstanceBuilder.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/ProcessInstanceBuilder.java @@ -15,9 +15,12 @@ */ package org.activiti.cloud.services.query.util; +import java.time.Instant; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -26,11 +29,12 @@ import org.activiti.cloud.services.query.app.repository.VariableRepository; import org.activiti.cloud.services.query.model.ProcessInstanceEntity; import org.activiti.cloud.services.query.model.ProcessVariableEntity; +import org.activiti.cloud.services.query.model.TaskEntity; public class ProcessInstanceBuilder { private final ProcessInstanceEntity process; - private final Set taskBuffer = new HashSet<>(); + private final List taskBuffer = new ArrayList<>(); private final VariableRepository variableRepository; private final ProcessInstanceRepository processInstanceRepository; @@ -127,13 +131,15 @@ public ProcessInstanceBuilder withStatus(ProcessInstance.ProcessInstanceStatus s public ProcessInstanceEntity buildAndSave() { variableRepository.saveAll(process.getVariables()); - process.setTasks( - taskBuffer - .stream() - .map(builder -> builder.withParentProcess(process)) - .map(TaskBuilder::buildAndSave) - .collect(Collectors.toSet()) - ); + Instant instant = Instant.now(); + + Set tasks = new HashSet<>(); + for (TaskBuilder builder : taskBuffer) { + builder.withParentProcess(process); + builder.withCreatedDate(Date.from(instant.plusSeconds(taskBuffer.indexOf(builder)))); + tasks.add(builder.buildAndSave()); + } + process.setTasks(tasks); return processInstanceRepository.save(process); } } diff --git a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/TaskBuilder.java b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/TaskBuilder.java index 8a44dae252..0d240a53f2 100644 --- a/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/TaskBuilder.java +++ b/activiti-cloud-query-service/activiti-cloud-services-query/activiti-cloud-services-query-rest/src/test/java/org/activiti/cloud/services/query/util/TaskBuilder.java @@ -85,6 +85,7 @@ public TaskBuilder withPriority(Integer priority) { public TaskBuilder withAssignee(String assignee) { task.setAssignee(assignee); + task.setStatus(Task.TaskStatus.ASSIGNED); return this; } @@ -183,6 +184,9 @@ public TaskEntity buildAndSave() { variable.setProcessInstanceId(task.getProcessInstanceId()); }); taskVariableRepository.saveAll(task.getVariables()); + if (task.getCreatedDate() == null) { + task.setCreatedDate(new Date()); + } return taskRepository.save(task); }