TSK-415 TaskQuery.count() does not filter out tasks in hidden workbaskets

This commit is contained in:
BerndBreier 2018-03-27 12:52:59 +02:00 committed by Holger Hagen
parent ead7b9a3a0
commit a321d275ed
7 changed files with 95 additions and 19 deletions

View File

@ -8,7 +8,7 @@ import pro.taskana.TaskState;
public class MinimalTaskSummary { public class MinimalTaskSummary {
private String taskId; private String taskId;
private String workbasketKey; private String workbasketId;
private TaskState taskState; private TaskState taskState;
MinimalTaskSummary() { MinimalTaskSummary() {
@ -23,12 +23,12 @@ public class MinimalTaskSummary {
this.taskId = taskId; this.taskId = taskId;
} }
public String getWorkbasketKey() { public String getWorkbasketId() {
return workbasketKey; return workbasketId;
} }
public void setWorkbasketKey(String workbasketKey) { public void setWorkbasketId(String workbasketKey) {
this.workbasketKey = workbasketKey; this.workbasketId = workbasketKey;
} }
public TaskState getTaskState() { public TaskState getTaskState() {
@ -44,8 +44,8 @@ public class MinimalTaskSummary {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("MinimalTaskSummary [taskId="); builder.append("MinimalTaskSummary [taskId=");
builder.append(taskId); builder.append(taskId);
builder.append(", workbasketKey="); builder.append(", workbasketId=");
builder.append(workbasketKey); builder.append(workbasketId);
builder.append(", taskState="); builder.append(", taskState=");
builder.append(taskState); builder.append(taskState);
builder.append("]"); builder.append("]");

View File

@ -0,0 +1,29 @@
package pro.taskana.impl;
/**
* This class keeps a count of tasks that are contained in a workbasket.
*
* @author bbr
*/
public class TaskCountPerWorkbasket {
Integer taskCount;
String workbasketId;
public Integer getTaskCount() {
return taskCount;
}
public void setTaskCount(Integer taskCount) {
this.taskCount = taskCount;
}
public String getWorkbasketId() {
return workbasketId;
}
public void setWorkbasketId(String workbasketId) {
this.workbasketId = workbasketId;
}
}

View File

@ -3,6 +3,8 @@ package pro.taskana.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.ibatis.exceptions.PersistenceException; import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.RowBounds;
@ -18,6 +20,7 @@ import pro.taskana.TaskanaEngine;
import pro.taskana.TaskanaRole; import pro.taskana.TaskanaRole;
import pro.taskana.TimeInterval; import pro.taskana.TimeInterval;
import pro.taskana.WorkbasketPermission; import pro.taskana.WorkbasketPermission;
import pro.taskana.WorkbasketSummary;
import pro.taskana.exceptions.InvalidArgumentException; import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.NotAuthorizedToQueryWorkbasketException; import pro.taskana.exceptions.NotAuthorizedToQueryWorkbasketException;
@ -31,7 +34,7 @@ import pro.taskana.impl.util.LoggerUtils;
public class TaskQueryImpl implements TaskQuery { public class TaskQueryImpl implements TaskQuery {
private static final String LINK_TO_MAPPER = "pro.taskana.mappings.QueryMapper.queryTaskSummaries"; private static final String LINK_TO_MAPPER = "pro.taskana.mappings.QueryMapper.queryTaskSummaries";
private static final String LINK_TO_COUNTER = "pro.taskana.mappings.QueryMapper.countQueryTasks"; private static final String LINK_TO_TASK_COUNT_PER_WORKBASKET = "pro.taskana.mappings.QueryMapper.queryTaskCountPerWorkbasket";
private static final String LINK_TO_VALUEMAPPER = "pro.taskana.mappings.QueryMapper.queryTaskColumnValues"; private static final String LINK_TO_VALUEMAPPER = "pro.taskana.mappings.QueryMapper.queryTaskColumnValues";
private static final String TIME_INTERVAL = "TimeInterval "; private static final String TIME_INTERVAL = "TimeInterval ";
private static final String IS_INVALID = " is invalid."; private static final String IS_INVALID = " is invalid.";
@ -804,14 +807,36 @@ public class TaskQueryImpl implements TaskQuery {
try { try {
taskanaEngine.openConnection(); taskanaEngine.openConnection();
checkOpenPermissionForSpecifiedWorkbaskets(); checkOpenPermissionForSpecifiedWorkbaskets();
rowCount = taskanaEngine.getSqlSession().selectOne(LINK_TO_COUNTER, this); List<TaskCountPerWorkbasket> taskCounts = taskanaEngine.getSqlSession()
return (rowCount == null) ? 0L : rowCount; .selectList(LINK_TO_TASK_COUNT_PER_WORKBASKET, this);
return countTasksInAuthorizedWorkbaskets(taskCounts);
} finally { } finally {
taskanaEngine.returnConnection(); taskanaEngine.returnConnection();
LOGGER.debug("exit from count(). Returning result {} ", rowCount); LOGGER.debug("exit from count(). Returning result {} ", rowCount);
} }
} }
private long countTasksInAuthorizedWorkbaskets(List<TaskCountPerWorkbasket> taskCounts) {
Set<String> retrievedWorkbasketIds = taskCounts.stream().map(TaskCountPerWorkbasket::getWorkbasketId).collect(
Collectors.toSet());
// use WorkbasketQuery to filter for authorized WorkBaskets
WorkbasketQueryImpl query = (WorkbasketQueryImpl) taskanaEngine.getWorkbasketService().createWorkbasketQuery();
query.setUsedToAugmentTasks(true);
List<WorkbasketSummary> allowedWorkbaskets = query
.idIn(retrievedWorkbasketIds.toArray(new String[0]))
.list();
Set<String> authorizedWorkbasketIds = allowedWorkbaskets.stream().map(WorkbasketSummary::getId).collect(
Collectors.toSet());
long count = 0;
for (TaskCountPerWorkbasket taskCount : taskCounts) {
if (authorizedWorkbasketIds.contains(taskCount.getWorkbasketId())) {
count += taskCount.getTaskCount().intValue();
}
}
return count;
}
private void checkOpenPermissionForSpecifiedWorkbaskets() { private void checkOpenPermissionForSpecifiedWorkbaskets() {
if (taskanaEngine.isUserInRole(TaskanaRole.ADMIN)) { if (taskanaEngine.isUserInRole(TaskanaRole.ADMIN)) {
LOGGER.debug("Skipping permissions check since user is in role ADMIN."); LOGGER.debug("Skipping permissions check since user is in role ADMIN.");

View File

@ -538,13 +538,13 @@ public class TaskServiceImpl implements TaskService {
List<MinimalTaskSummary> taskSummaries = taskMapper.findExistingTasks(taskIds); List<MinimalTaskSummary> taskSummaries = taskMapper.findExistingTasks(taskIds);
// check source WB (read)+transfer // check source WB (read)+transfer
Set<String> workbasketKeys = new HashSet<>(); Set<String> workbasketIds = new HashSet<>();
taskSummaries.stream().forEach(t -> workbasketKeys.add(t.getWorkbasketKey())); taskSummaries.stream().forEach(t -> workbasketIds.add(t.getWorkbasketId()));
WorkbasketQueryImpl query = (WorkbasketQueryImpl) workbasketService.createWorkbasketQuery(); WorkbasketQueryImpl query = (WorkbasketQueryImpl) workbasketService.createWorkbasketQuery();
query.setUsedToAugmentTasks(true); query.setUsedToAugmentTasks(true);
List<WorkbasketSummary> sourceWorkbaskets = query List<WorkbasketSummary> sourceWorkbaskets = query
.callerHasPermission(WorkbasketPermission.TRANSFER) .callerHasPermission(WorkbasketPermission.TRANSFER)
.keyIn(workbasketKeys.toArray(new String[0])) .idIn(workbasketIds.toArray(new String[0]))
.list(); .list();
taskIdIterator = taskIds.iterator(); taskIdIterator = taskIds.iterator();
while (taskIdIterator.hasNext()) { while (taskIdIterator.hasNext()) {
@ -558,7 +558,7 @@ public class TaskServiceImpl implements TaskService {
new TaskNotFoundException(currentTaskId, "Task with id " + currentTaskId + " was not found.")); new TaskNotFoundException(currentTaskId, "Task with id " + currentTaskId + " was not found."));
taskIdIterator.remove(); taskIdIterator.remove();
} else if (!sourceWorkbaskets.stream() } else if (!sourceWorkbaskets.stream()
.anyMatch(wb -> taskSummary.getWorkbasketKey().equals(wb.getKey()))) { .anyMatch(wb -> taskSummary.getWorkbasketId().equals(wb.getId()))) {
bulkLog.addError(currentTaskId, bulkLog.addError(currentTaskId,
new NotAuthorizedException( new NotAuthorizedException(
"The workbasket of this task got not TRANSFER permissions. TaskId=" + currentTaskId)); "The workbasket of this task got not TRANSFER permissions. TaskId=" + currentTaskId));

View File

@ -10,6 +10,7 @@ import pro.taskana.impl.ClassificationQueryImpl;
import pro.taskana.impl.ClassificationSummaryImpl; import pro.taskana.impl.ClassificationSummaryImpl;
import pro.taskana.impl.ObjectReference; import pro.taskana.impl.ObjectReference;
import pro.taskana.impl.ObjectReferenceQueryImpl; import pro.taskana.impl.ObjectReferenceQueryImpl;
import pro.taskana.impl.TaskCountPerWorkbasket;
import pro.taskana.impl.TaskQueryImpl; import pro.taskana.impl.TaskQueryImpl;
import pro.taskana.impl.TaskSummaryImpl; import pro.taskana.impl.TaskSummaryImpl;
import pro.taskana.impl.WorkbasketAccessItemImpl; import pro.taskana.impl.WorkbasketAccessItemImpl;
@ -347,7 +348,7 @@ public interface QueryMapper {
@Result(property = "permCustom12", column = "PERM_CUSTOM_12")}) @Result(property = "permCustom12", column = "PERM_CUSTOM_12")})
List<WorkbasketAccessItemImpl> queryWorkbasketAccessItems(WorkbasketAccessItemQueryImpl accessItemQuery); List<WorkbasketAccessItemImpl> queryWorkbasketAccessItems(WorkbasketAccessItemQueryImpl accessItemQuery);
@Select("<script>SELECT COUNT(ID) FROM TASK t " @Select("<script> SELECT COUNT(t.ID) as TASK_COUNT , t.WORKBASKET_ID FROM TASK t "
+ "<where>" + "<where>"
+ "<if test='taskIds != null'>AND t.ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)</if> " + "<if test='taskIds != null'>AND t.ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)</if> "
+ "<if test='createdIn !=null'> AND ( <foreach item='item' collection='createdIn' separator=' OR ' > ( <if test='item.begin!=null'> t.CREATED &gt;= #{item.begin} </if> <if test='item.begin!=null and item.end!=null'> AND </if><if test='item.end!=null'> t.CREATED &lt;=#{item.end} </if>)</foreach>)</if> " + "<if test='createdIn !=null'> AND ( <foreach item='item' collection='createdIn' separator=' OR ' > ( <if test='item.begin!=null'> t.CREATED &gt;= #{item.begin} </if> <if test='item.begin!=null and item.end!=null'> AND </if><if test='item.end!=null'> t.CREATED &lt;=#{item.end} </if>)</foreach>)</if> "
@ -422,10 +423,13 @@ public interface QueryMapper {
+ "<if test='custom16In != null'>AND t.CUSTOM_10 IN(<foreach item='item' collection='custom16In' separator=',' >#{item}</foreach>)</if> " + "<if test='custom16In != null'>AND t.CUSTOM_10 IN(<foreach item='item' collection='custom16In' separator=',' >#{item}</foreach>)</if> "
+ "<if test='custom16Like != null'>AND (<foreach item='item' collection='custom16Like' separator=' OR '>UPPER(t.CUSTOM_10) LIKE #{item}</foreach>)</if> " + "<if test='custom16Like != null'>AND (<foreach item='item' collection='custom16Like' separator=' OR '>UPPER(t.CUSTOM_10) LIKE #{item}</foreach>)</if> "
+ "</where>" + "</where>"
+ "<if test='!orderBy.isEmpty()'>ORDER BY <foreach item='item' collection='orderBy' separator=',' >${item}</foreach></if> " + "GROUP BY WORKBASKET_ID "
+ "<if test=\"_databaseId == 'db2'\">with UR </if> " + "<if test=\"_databaseId == 'db2'\">with UR </if> "
+ "</script>") + "</script>")
Long countQueryTasks(TaskQueryImpl taskQuery); @Results(value = {
@Result(property = "taskCount", column = "TASK_COUNT"),
@Result(property = "workbasketId", column = "WORKBASKET_ID")})
List<TaskCountPerWorkbasket> queryTaskCountPerWorkbasket(TaskQueryImpl taskQuery);
@Select("<script>SELECT COUNT(ID) FROM CLASSIFICATION " @Select("<script>SELECT COUNT(ID) FROM CLASSIFICATION "
+ "<where>" + "<where>"

View File

@ -236,13 +236,13 @@ public interface TaskMapper {
void updateCompleted(@Param("taskIds") List<String> taskIds, void updateCompleted(@Param("taskIds") List<String> taskIds,
@Param("referencetask") TaskSummaryImpl referencetask); @Param("referencetask") TaskSummaryImpl referencetask);
@Select("<script>SELECT ID, STATE, WORKBASKET_KEY FROM TASK " @Select("<script>SELECT ID, STATE, WORKBASKET_ID FROM TASK "
+ "WHERE ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>) " + "WHERE ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>) "
+ "<if test=\"_databaseId == 'db2'\">with UR </if> " + "<if test=\"_databaseId == 'db2'\">with UR </if> "
+ "</script>") + "</script>")
@Results(value = { @Results(value = {
@Result(property = "taskId", column = "ID"), @Result(property = "taskId", column = "ID"),
@Result(property = "workbasketKey", column = "WORKBASKET_KEY"), @Result(property = "workbasketId", column = "WORKBASKET_ID"),
@Result(property = "taskState", column = "STATE")}) @Result(property = "taskState", column = "STATE")})
List<MinimalTaskSummary> findExistingTasks(@Param("taskIds") List<String> taskIds); List<MinimalTaskSummary> findExistingTasks(@Param("taskIds") List<String> taskIds);

View File

@ -24,6 +24,7 @@ import pro.taskana.AttachmentSummary;
import pro.taskana.BaseQuery.SortDirection; import pro.taskana.BaseQuery.SortDirection;
import pro.taskana.KeyDomain; import pro.taskana.KeyDomain;
import pro.taskana.Task; import pro.taskana.Task;
import pro.taskana.TaskQuery;
import pro.taskana.TaskService; import pro.taskana.TaskService;
import pro.taskana.TaskSummary; import pro.taskana.TaskSummary;
import pro.taskana.exceptions.AttachmentPersistenceException; import pro.taskana.exceptions.AttachmentPersistenceException;
@ -604,4 +605,21 @@ public class QueryTasksAccTest extends AbstractAccTest {
} }
} }
@WithAccessId(
userName = "user_1_1",
groupNames = {"group_1"})
@Test
public void testQueryAndCountMatch() {
TaskService taskService = taskanaEngine.getTaskService();
TaskQuery taskQuery = taskService.createTaskQuery();
List<TaskSummary> tasks = taskQuery
.nameIn("Task99", "Task01", "Widerruf")
.list();
long numberOfTasks = taskQuery
.nameIn("Task99", "Task01", "Widerruf")
.count();
Assert.assertEquals(numberOfTasks, tasks.size());
}
} }