diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java index e53d436208..cf4d8c5503 100644 --- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java +++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java @@ -108,12 +108,27 @@ public SetDataEventOutcome setData(String taskId, Map searchCases(String processIdentifier, Predicate predicate, Pageable pageable) { + return searchCases(processIdentifier, predicate, pageable, new HashMap<>()); + } + + @Override + public Page searchCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) { + return searchCases(elasticStringQueries, authPrincipalDto, pageable, isIntersection, new HashMap<>()); + } + + @Override + public Long countCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection) { + return countCases(elasticStringQueries, authPrincipalDto, isIntersection, new HashMap<>()); + } + + @Override + public Page searchCases(String processIdentifier, Predicate predicate, Pageable pageable, Map params) { log.debug("Searching cases for process identifier [{}] with predicate [{}], pageable [{}]", processIdentifier, predicate, pageable); return workflowService.search(predicate, pageable); } @Override - public Page searchCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) { + public Page searchCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection, Map params) { log.debug("Searching cases for elastic queries [{}] with auth principal [{}], pageable [{}], intersect [{}]", elasticStringQueries, authPrincipalDto, pageable, isIntersection); boolean intersect = Boolean.TRUE.equals(isIntersection); List caseSearchRequests = elasticStringQueries.stream().map(query -> CaseSearchRequest.builder().query(query).build()).toList(); @@ -124,7 +139,7 @@ public Page searchCases(List elasticStringQueries, AuthPrincipalDt } @Override - public Long countCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection) { + public Long countCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection, Map params) { log.debug("Counting cases for elastic queries [{}] with auth principal [{}], intersect [{}]", elasticStringQueries, authPrincipalDto, isIntersection); boolean intersect = Boolean.TRUE.equals(isIntersection); List caseSearchRequests = elasticStringQueries.stream().map(query -> CaseSearchRequest.builder().query(query).build()).toList(); @@ -159,12 +174,22 @@ public DeleteCaseEventOutcome deleteCase(String caseId, Map para @Override public Page searchTasks(String processIdentifier, Predicate predicate, Pageable pageable) { + return searchTasks(processIdentifier, predicate, pageable, new HashMap<>()); + } + + @Override + public Page searchTasks(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) { + return searchTasks(elasticStringQueries, authPrincipalDto, pageable, isIntersection, new HashMap<>()); + } + + @Override + public Page searchTasks(String processIdentifier, Predicate predicate, Pageable pageable, Map params) { log.debug("Searching tasks for process identifier [{}] with predicate [{}], pageable [{}]", processIdentifier, predicate, pageable); return taskService.search(predicate, pageable); } @Override - public Page searchTasks(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) { + public Page searchTasks(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection, Map params) { log.debug("Searching tasks for elastic queries [{}] with auth principal [{}], pageable [{}], intersect [{}]", elasticStringQueries, authPrincipalDto, pageable, isIntersection); boolean intersect = Boolean.TRUE.equals(isIntersection); List taskSearchRequests = elasticStringQueries.stream().map(query -> ElasticTaskSearchRequest.builder().query(query).build()).toList(); @@ -174,6 +199,17 @@ public Page searchTasks(List elasticStringQueries, AuthPrincipalDt return elasticTaskService.search(taskSearchRequests, loggedUser, pageable, locale, intersect); } + @Override + public Long countTasks(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection, Map params) { + log.debug("Counting tasks for elastic queries [{}] with auth principal [{}], intersect [{}]", elasticStringQueries, authPrincipalDto, isIntersection); + boolean intersect = Boolean.TRUE.equals(isIntersection); + List taskSearchRequests = elasticStringQueries.stream().map(query -> ElasticTaskSearchRequest.builder().query(query).build()).toList(); + LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto)); + Locale locale = LocaleContextHolder.getLocale(); + log.trace("Counting tasks for elastic queries [{}] with auth principal [{}], intersect [{}], locale [{}]", elasticStringQueries, authPrincipalDto, isIntersection, locale); + return elasticTaskService.count(taskSearchRequests, loggedUser, locale, intersect); + } + @Override public AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, Map params) throws TransitionNotExecutableException { log.debug("Assigning task [{}] with auth principal [{}] and params [{}]", taskId, authPrincipalDto, params); @@ -293,7 +329,7 @@ private AbstractUser resolveAbstractUser(AuthPrincipalDto authPrincipalDto) { if (authPrincipalDto == null) { throw new IllegalArgumentException("AuthPrincipalDto cannot be null."); } - Optional userOptional = userService.findUserByUsername(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId()); - return userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId()))); + Optional userOptional = userService.findUserByUsername(authPrincipalDto.username(), authPrincipalDto.realmId()); + return userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(authPrincipalDto.username(), authPrincipalDto.realmId()))); } } diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/elastic/DataSearchRequestTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/elastic/DataSearchRequestTest.groovy index 9fcd5a7353..2c6fa62c6d 100644 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/elastic/DataSearchRequestTest.groovy +++ b/application-engine/src/test/groovy/com/netgrif/application/engine/elastic/DataSearchRequestTest.groovy @@ -196,8 +196,8 @@ class DataSearchRequestTest { new AbstractMap.SimpleEntry("fileList.fileNameValue.keyword" as String, "multifile2" as String), new AbstractMap.SimpleEntry("fileList.fileExtensionValue.keyword" as String, "txt" as String), new AbstractMap.SimpleEntry("fileList.fileExtensionValue.keyword" as String, "pdf" as String), - new AbstractMap.SimpleEntry("userList" as String, "${testUser1.name} ${testUser1.email}" as String), - new AbstractMap.SimpleEntry("userList" as String, "${testUser2.name} ${testUser2.email}" as String), + new AbstractMap.SimpleEntry("userList" as String, "${testUser1.name} ${testUser1.username}" as String), + new AbstractMap.SimpleEntry("userList" as String, "${testUser2.name} ${testUser2.username}" as String), new AbstractMap.SimpleEntry("userList" as String, "${groupService.getDefaultSystemGroup().getFullName()}" as String), new AbstractMap.SimpleEntry("userList.usernameValue.keyword" as String, "${testUser1.username}" as String), new AbstractMap.SimpleEntry("userList.usernameValue.keyword" as String, "${testUser2.username}" as String), diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/event/GroovyShellFactoryTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/event/GroovyShellFactoryTest.groovy index 97216ff8bf..5011988f2e 100644 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/event/GroovyShellFactoryTest.groovy +++ b/application-engine/src/test/groovy/com/netgrif/application/engine/event/GroovyShellFactoryTest.groovy @@ -72,7 +72,7 @@ class GroovyShellFactoryTest { void roleActionsTest() { roleService.metaClass.groovyShellTestMethod = { String string, I18nString i18nString -> println("groovyShellTestMethod") } - def user = userService.findUserByUsername(userService.getSystem().getEmail(), null) + def user = userService.findUserByUsername(userService.getSystem().getUsername(), null) def processRoleCount = user.get().processRoles.size() def roles = roleService.findAllByNetStringId(net.getStringId()) assert roles.size() == 1 @@ -81,7 +81,7 @@ class GroovyShellFactoryTest { new HashSet(roles.collect { it._id } + user.get().processRoles.collect { it._id }), new LoggedUserImpl(new ObjectId(), null, "a", "a", "", "b", "test@mail.com", "", null, null, null, null) ) - user = userService.findUserByUsername(userService.getSystem().getEmail(), null) + user = userService.findUserByUsername(userService.getSystem().getUsername(), null) assert user.get().processRoles.size() == processRoleCount + 1 } diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/orgstructure/groups/GroupServiceTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/orgstructure/groups/GroupServiceTest.groovy index 9af198986e..f4a09862f7 100644 --- a/application-engine/src/test/groovy/com/netgrif/application/engine/orgstructure/groups/GroupServiceTest.groovy +++ b/application-engine/src/test/groovy/com/netgrif/application/engine/orgstructure/groups/GroupServiceTest.groovy @@ -3,6 +3,7 @@ package com.netgrif.application.engine.orgstructure.groups import com.netgrif.application.engine.TestHelper import com.netgrif.application.engine.auth.service.GroupService import com.netgrif.application.engine.auth.service.UserService +import com.netgrif.application.engine.objects.auth.constants.UserConstants import com.netgrif.application.engine.objects.auth.domain.Authority import com.netgrif.application.engine.objects.auth.domain.Group import com.netgrif.application.engine.objects.auth.domain.QGroup @@ -88,7 +89,7 @@ class GroupServiceTest { QGroup qGroup = new QGroup("group") Group group = groupService.findByPredicate(qGroup.identifier.eq("CUSTOM_GROUP_1"), new FullPageRequest()).getContent().get(0) groupService.addUser(userService.findUserByUsername(CUSTOMER_USER_MAIL, null).get(), group) - groupService.addUser(userService.findUserByUsername("engine@netgrif.com", null).get(), group) + groupService.addUser(userService.findUserByUsername(UserConstants.SYSTEM_USER_USERNAME, null).get(), group) return group } diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/constants/UserConstants.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/constants/UserConstants.java index 75c7769fde..584dc83bfb 100644 --- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/constants/UserConstants.java +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/constants/UserConstants.java @@ -1,6 +1,7 @@ package com.netgrif.application.engine.objects.auth.constants; public final class UserConstants { + public static final String SYSTEM_USER_USERNAME = "system"; public static final String SYSTEM_USER_EMAIL = "engine@netgrif.com"; public static final String SYSTEM_USER_NAME = "application"; public static final String SYSTEM_USER_SURNAME = "engine"; diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java index 3333122aae..2632ce05b8 100644 --- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java +++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java @@ -7,19 +7,33 @@ import java.io.Serial; import java.io.Serializable; +import java.util.Objects; -@Data -public class AuthPrincipalDto implements Serializable { - +public record AuthPrincipalDto(String username, + String realmId, + @JsonIgnore + String sessionId) implements Serializable { @Serial private static final long serialVersionUID = 6725518942728316525L; - private String username; + @Override + public String toString() { + return "AuthPrincipalDto{" + + "username='" + username + '\'' + + ", realmId='" + realmId + '\'' + + '}'; + } - private String realmId; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AuthPrincipalDto that = (AuthPrincipalDto) o; + return Objects.equals(username, that.username) && Objects.equals(realmId, that.realmId); + } - @ToString.Exclude - @EqualsAndHashCode.Exclude - @JsonIgnore - private String sessionId; + @Override + public int hashCode() { + return java.util.Objects.hash(username, realmId); + } } diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java index 09db189894..cd4084fb16 100644 --- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java @@ -18,7 +18,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import java.util.List; @@ -94,6 +93,44 @@ public interface ActionApi { */ Long countCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection); + /** + * Searches for cases matching the given predicate. + * + * @param processIdentifier reserved for interface compatibility; this implementation + * does not filter by process identifier and returns cases + * from all processes. Use the predicate parameter to filter + * by specific process(es) if needed. + * @param predicate the criteria for filtering cases + * @param pageable the pagination information + * @param params additional parameters for the operation + * @return a page of cases matching the criteria + */ + Page searchCases(String processIdentifier, Predicate predicate, Pageable pageable, Map params); + + /** + * Searches for cases using elastic search queries. + * + * @param elasticStringQueries a list of queries for filtering cases + * @param authPrincipalDto the authorization principal used for the search + * @param pageable the pagination information + * @param isIntersection true to intersect results of all queries; false for union + * @param params additional parameters for the operation + * @return a page of cases matching the criteria + */ + Page searchCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection, Map params); + + + /** + * Counts the number of cases that match the provided elastic search queries. + * + * @param elasticStringQueries a list of elastic search queries used for filtering cases + * @param authPrincipalDto the authorization principal for the operation + * @param isIntersection true to intersect the results of all queries; false for union + * @param params additional parameters for the operation + * @return the total number of cases matching the criteria + */ + Long countCases(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection, Map params); + /** * Creates a new case identified by the given process identifier. * @@ -148,6 +185,43 @@ public interface ActionApi { */ Page searchTasks(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection); + /** + * Searches for tasks matching the given predicate. + * + * @param processIdentifier reserved for interface compatibility; this implementation + * does not filter by process identifier and returns tasks + * from all processes. Use the predicate parameter to filter + * by specific process(es) if needed. + * @param predicate the criteria for filtering tasks + * @param pageable the pagination information + * @param params additional params for the operation + * @return a page of tasks matching the criteria + */ + Page searchTasks(String processIdentifier, Predicate predicate, Pageable pageable, Map params); + + /** + * Searches for tasks using elastic search queries. + * + * @param elasticStringQueries a list of queries for filtering tasks + * @param authPrincipalDto the authorization principal used for the search + * @param pageable the pagination information + * @param isIntersection true to intersect results of all queries; false for union + * @param params additional params for the operation + * @return a page of tasks matching the criteria + */ + Page searchTasks(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection, Map params); + + /** + * Counts tasks using elastic search queries. + * + * @param elasticStringQueries a list of queries for filtering tasks + * @param authPrincipalDto the authorization principal used for the search + * @param isIntersection true to intersect results of all queries; false for union + * @param params additional params for the operation + * @return number of tasks matching the query + */ + Long countTasks(List elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection, Map params); + /** * Assigns a specific task to a user. * diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiDefaultParamNames.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiDefaultParamNames.java new file mode 100644 index 0000000000..fe7358e7bd --- /dev/null +++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiDefaultParamNames.java @@ -0,0 +1,8 @@ +package com.netgrif.application.engine.adapter.spring.actions; + +public final class ActionApiDefaultParamNames { + public static final String PROCESS_IDENTIFIER = "processIdentifier"; + public static final String PROCESS_ID = "processId"; + public static final String PROCESS_VERSION = "processVersion"; + public static final String PROCESS_RESOURCE_ID = "processResourceId"; +}