Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -827,18 +827,6 @@ public void loadTaskById(int id) {
stopwatch.stop();
}

/**
* Retrieve and return the list of tasks that are assigned to the user that are
* currently in progress.
*
* @return list of tasks that are currently assigned to the user that are
* currently in progress.
*/
public List<Task> getTasksInProgress() {
Stopwatch stopwatch = new Stopwatch(this, "getTasksInProgress");
return stopwatch.stop(ServiceManager.getUserService().getTasksInProgress(this.user));
}

/**
* Get taskListPath.
*
Expand Down
19 changes: 17 additions & 2 deletions Kitodo/src/main/java/org/kitodo/production/forms/UserForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,22 @@ private boolean isMissingClient() {
* are "INWORK" and belong to process, not template
*/
public List<Task> getTasksInProgress(User user) {
return ServiceManager.getUserService().getTasksInProgress(user);
return ServiceManager.getTaskService().getTasksInProgress(user);
}

/**
* Check whether the user has tasks that are "INWORK" and belong to a process.
*
* @param user the user to check
* @return true if the user has at least one task in progress
*/
public boolean hasTasksInProgress(User user) {
try {
return ServiceManager.getTaskService().hasTasksInProgress(user);
} catch (DAOException e) {
Helper.setErrorMessage("Unable to check tasks in progress for user.", logger, e);
return false;
}
}

/**
Expand Down Expand Up @@ -288,7 +303,7 @@ public void resetTasksToOpen(User user) {
* user from a connected LDAP service.
*/
public void checkAndDelete() {
if (getTasksInProgress(userObject).isEmpty()) {
if (!hasTasksInProgress(userObject)) {
deleteUser(userObject);
} else {
PrimeFaces.current().ajax().update("usersTabView:confirmResetTasksDialog");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,20 +304,15 @@ private BeanQuery formBeanQuery(Map<?, String> filters, boolean onlyOwnTasks, bo
*/
public void replaceProcessingUser(Task task, User user) {
User currentProcessingUser = task.getProcessingUser();

if (Objects.isNull(user) && Objects.isNull(currentProcessingUser)) {
logger.info("do nothing - there is neither a new nor an old user");
} else if (Objects.isNull(user)) {
currentProcessingUser.getProcessingTasks().remove(task);
task.setProcessingUser(null);
} else if (Objects.isNull(currentProcessingUser)) {
user.getProcessingTasks().add(task);
task.setProcessingUser(user);
} else if (Objects.equals(currentProcessingUser.getId(), user.getId())) {
logger.info("do nothing - both are the same");
} else {
currentProcessingUser.getProcessingTasks().remove(task);
user.getProcessingTasks().add(task);
task.setProcessingUser(user);
}
}
Expand Down Expand Up @@ -805,6 +800,41 @@ public static List<Task> getTasksInWorkByOtherUsers(List<Task> tasks) {
.collect(Collectors.toList());
}

/**
* Retrieve and return all tasks assigned to the given user
* that are currently in progress and linked to a process.
*
* @param user the processing user
* @return list of tasks in progress for the given user
*/
public List<Task> getTasksInProgress(User user) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question: Would an additional restriction to the used client of the current user not even more helpful? If an user is assigned to more clients than this list here would include all the tasks over all clients and not only the tasks of the current used client in the UI.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, might be useful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have not filtered by client before, maybe this is not necessary, as this method is only called in special places.

String hql = "FROM Task t WHERE t.processingUser = :user "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Limiting / restrict the task list to tasks where the user is set as processing user is may to restrictive as not necessary the user who need this list as worked on this task. I did not even see such restriction in the former place where only assigned processes to the task (non null) and task state in progress the restrictions are.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, i have to think about that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed that this method is mostly used for emptiness checks; we can probably optimize: If only existence is checked, we do not need to retrieve all the tasks and should do an existence check.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not even see such restriction in the former place

return user.getProcessingTasks().stream()

I think establishing the stream in that way also limited the tasks down to those the user is actually assigned to before.

+ "AND t.processingStatus = :status "
+ "AND t.process IS NOT NULL";
Map<String, Object> params = Map.of(
"user", user,
"status", TaskStatus.INWORK
);
return dao.getByQuery(hql, params);
}

/**
* Returns whether the user has at least one task in progress.
* @param user the processing user
* @return true if the user has tasks in progress, otherwise false
*/
public boolean hasTasksInProgress(User user) throws DAOException {
String hql = "FROM Task t "
+ "WHERE t.processingUser = :user "
+ "AND t.processingStatus = :status "
+ "AND t.process IS NOT NULL";

return dao.has(hql, Map.of(
"user", user,
"status", TaskStatus.INWORK
));
}

/**
* Compute and return list of tasks that are eligible as 'currentTask' for a new correction comment.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,20 +459,6 @@ private void removeFilterFromUser(User user, String userFilter) throws DAOExcept
}
}

/**
* Retrieve and return the list of tasks that are assigned to the user and
* that are "INWORK" and belong to process, not template.
*
* @return list of tasks that are currently assigned to the user and that
* are "INWORK" and belong to process, not template
*/
public List<Task> getTasksInProgress(User user) {
return user.getProcessingTasks().stream()
.filter(
task -> task.getProcessingStatus().equals(TaskStatus.INWORK) && Objects.nonNull(task.getProcess()))
.collect(Collectors.toList());
}

/**
* Changes the password for given User object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@

<h:panelGroup styleClass="action"
rendered="#{SecurityAccessController.hasAuthorityToUnassignTasks()}"
title="#{empty UserForm.getTasksInProgress(item) ? msgs.userWithoutTasks : msgs.unassignTasks}">
title="#{UserForm.hasTasksInProgress(item) ? msgs.unassignTasks : msgs.userWithoutTasks}">
Copy link
Collaborator Author

@BartChris BartChris Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be that the user list also benefits from the more efficient checks.

<p:commandLink id="unassignTasks"
action="#{UserForm.resetTasksToOpen(item)}"
styleClass="#{empty UserForm.getTasksInProgress(item) ? 'ui-state-disabled' : ''}"
disabled="#{empty UserForm.getTasksInProgress(item)}"
styleClass="#{UserForm.hasTasksInProgress(item) ? '' : 'ui-state-disabled'}"
disabled="#{not UserForm.hasTasksInProgress(item)}"
update="@this">
<h:outputText><i class="fa fa-user-times"/></h:outputText>
<h:outputText><i class="fa fa-user-times"/></h:outputText>
<p:confirm message=" #{msgs.confirmUnassignTasks}" header="#{msgs.confirmRelease}"/>
</p:commandLink>
</h:panelGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@
package org.kitodo.production.services.data;

import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.kitodo.MockDatabase;
import org.kitodo.data.database.beans.Task;
import org.kitodo.data.database.beans.User;
import org.kitodo.data.database.enums.TaskStatus;
import org.kitodo.data.database.exceptions.DAOException;
import org.kitodo.production.helper.Helper;
Expand Down Expand Up @@ -272,4 +273,64 @@ public void shouldFindDistinctTitles() throws Exception {
title = taskTitlesDistinct.get(2);
assertEquals("Closed", title, "Incorrect sorting of distinct titles for tasks!");
}

@Test
public void shouldGetTasksInProgressForUser() throws Exception {
UserService userService = ServiceManager.getUserService();
ProcessService processService = ServiceManager.getProcessService();

User user = userService.getById(1);
List<Task> expected = processService.getAll().stream()
.flatMap(p -> p.getTasks().stream())
.filter(t -> user.equals(t.getProcessingUser()))
.filter(t -> t.getProcessingStatus() == TaskStatus.INWORK)
.filter(t -> Objects.nonNull(t.getProcess()))
.collect(Collectors.toList());

List<Task> actual = taskService.getTasksInProgress(user);

assertEquals(expected.size(), actual.size(), "Unexpected task count");
assertTrue(actual.containsAll(expected), "Returned tasks do not match expected INWORK tasks");
}

@Test
public void shouldDetectTasksInProgressCorrectly() throws Exception {
UserService userService = ServiceManager.getUserService();
ProcessService processService = ServiceManager.getProcessService();

List<User> allUsers = userService.getAll();
List<Task> allTasks = processService.getAll().stream()
.flatMap(p -> p.getTasks().stream())
.collect(Collectors.toList());
User userWithTasks = null;
User userWithoutTasks = null;
for (User u : allUsers) {
boolean has = allTasks.stream().anyMatch(t ->
u.equals(t.getProcessingUser()) &&
t.getProcessingStatus() == TaskStatus.INWORK &&
t.getProcess() != null
);
if (has && userWithTasks == null) {
userWithTasks = u;
} else if (!has && userWithoutTasks == null) {
userWithoutTasks = u;
}
if (userWithTasks != null && userWithoutTasks != null) {
break;
}
}
if (userWithTasks == null) {
throw new AssertionError("No user with tasks in progress found.");
}
if (userWithoutTasks == null) {
throw new AssertionError("No user without tasks in progress found.");
}

assertTrue(taskService.hasTasksInProgress(userWithTasks),
"Expected user with tasks in progress to return true");
assertFalse(taskService.hasTasksInProgress(userWithoutTasks),
"Expected user without tasks in progress to return false");
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public void shouldGetUserByLdapLogin() throws DAOException {
@Test
public void shouldGetUserTasksInProgress() throws DAOException {
User user = userService.getByLdapLoginOrLogin("nowakLDP");
List<Task> tasks = userService.getTasksInProgress(user);
List<Task> tasks = ServiceManager.getTaskService().getTasksInProgress(user);
assertEquals(1, tasks.size(), "Number of tasks in process is incorrect!");
assertEquals("Progress", tasks.get(0).getTitle(), "Title of task is incorrect!");
}
Expand Down