subGroupIds) implements Serializable {
+
+ public static GroupDto fromGroup(Group group, Locale locale) {
+ return new GroupDto(group.getStringId(), group.getDisplayName(), group.getIdentifier(), group.getOwnerUsername(),
+ group.getAuthoritySet().stream().map(AuthorityDto::fromAuthority).collect(Collectors.toSet()),
+ group.getProcessRoles().stream().map(processRole -> new ProcessRoleDto(processRole, locale)).collect(Collectors.toSet()),
+ group.getGroupIds(),
+ group.getSubgroupIds()
+ );
+ }
+
+}
diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/dto/response/petrinet/ProcessRoleDto.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/dto/response/petrinet/ProcessRoleDto.java
new file mode 100644
index 00000000000..5c820c76913
--- /dev/null
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/dto/response/petrinet/ProcessRoleDto.java
@@ -0,0 +1,28 @@
+package com.netgrif.application.engine.objects.dto.response.petrinet;
+
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+
+import java.io.Serializable;
+import java.util.Locale;
+
+public record ProcessRoleDto(String stringId, String name, String description, String importId, String netImportId,
+ String netVersion, String netStringId, boolean global) implements Serializable {
+
+ /**
+ * This constructor doesn't set attributes regarding the Petri net.
+ *
+ * Use the ProcessRoleFactory to create instances that have these attributes set.
+ */
+ public ProcessRoleDto(ProcessRole role, Locale locale) {
+ this(role.getStringId(), role.getLocalisedName(locale), role.getDescription(), role.getImportId(), null, null, null, role.isGlobal());
+ }
+
+ public ProcessRoleDto(ProcessRole role, Locale locale, String netImportId,
+ String netVersion, String netStringId) {
+ this(role.getStringId(), role.getLocalisedName(locale), role.getDescription(), role.getImportId(),netImportId, netVersion, netStringId, role.isGlobal());
+ }
+
+ public ProcessRoleDto(String id, String name, String description, boolean global) {
+ this(id, name, description, null, null, null, null, global);
+ }
+}
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/service/DefaultLoggedUserFactory.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/service/DefaultLoggedUserFactory.java
deleted file mode 100644
index a27c227fd02..00000000000
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/service/DefaultLoggedUserFactory.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.netgrif.application.engine.adapter.spring.auth.service;
-
-import com.netgrif.application.engine.adapter.spring.auth.domain.LoggedUserImpl;
-import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
-import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
-import org.springframework.stereotype.Component;
-
-@Component
-public class DefaultLoggedUserFactory implements ActorTransformer.LoggedUserFactory {
-
- @Override
- public LoggedUser create() {
- return new LoggedUserImpl();
- }
-}
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/configuration/LoggedUserConfiguration.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/configuration/LoggedUserConfiguration.java
deleted file mode 100644
index 0e60422b87b..00000000000
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/configuration/LoggedUserConfiguration.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.netgrif.application.engine.adapter.spring.configuration;
-
-import com.netgrif.application.engine.adapter.spring.auth.service.DefaultLoggedUserFactory;
-import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
-import jakarta.annotation.PostConstruct;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class LoggedUserConfiguration {
-
- @PostConstruct
- public void initializeLoggedUserFactory() {
- ActorTransformer.setLoggedUserFactory(new DefaultLoggedUserFactory());
- }
-}
diff --git a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/config/LoggedUserConfiguration.java b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/config/LoggedUserConfiguration.java
new file mode 100644
index 00000000000..41e24bb144b
--- /dev/null
+++ b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/config/LoggedUserConfiguration.java
@@ -0,0 +1,24 @@
+package com.netgrif.application.engine.auth.config;
+
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
+import com.netgrif.application.engine.auth.service.AuthorityService;
+import com.netgrif.application.engine.auth.service.DefaultLoggedUserFactory;
+import com.netgrif.application.engine.auth.service.GroupService;
+import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@RequiredArgsConstructor
+public class LoggedUserConfiguration {
+
+ private final GroupService groupService;
+ private final ProcessRoleService processRoleService;
+ private final AuthorityService authorityService;
+
+ @PostConstruct
+ public void initializeLoggedUserFactory() {
+ ActorTransformer.setLoggedUserFactory(new DefaultLoggedUserFactory(groupService, processRoleService, authorityService));
+ }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationServiceImpl.java
similarity index 81%
rename from application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java
rename to nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationServiceImpl.java
index 260f705d5e4..8c44f423047 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java
+++ b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationServiceImpl.java
@@ -1,12 +1,11 @@
package com.netgrif.application.engine.auth.service;
-import com.netgrif.application.engine.auth.service.interfaces.IAuthorizationService;
import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
-public class AuthorizationService implements IAuthorizationService {
+public class AuthorizationServiceImpl implements AuthorizationService {
@Autowired
private UserService userService;
diff --git a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/DefaultLoggedUserFactory.java b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/DefaultLoggedUserFactory.java
new file mode 100644
index 00000000000..c8919a1bfa5
--- /dev/null
+++ b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/DefaultLoggedUserFactory.java
@@ -0,0 +1,80 @@
+package com.netgrif.application.engine.auth.service;
+
+import com.netgrif.application.engine.adapter.spring.auth.domain.LoggedUserImpl;
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
+import com.netgrif.application.engine.objects.auth.domain.*;
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;
+
+import java.util.Set;
+
+@Component
+@RequiredArgsConstructor
+public class DefaultLoggedUserFactory implements ActorTransformer.LoggedUserFactory {
+
+ private final GroupService groupService;
+
+ private final ProcessRoleService processRoleService;
+
+ private final AuthorityService authorityService;
+
+ @Override
+ public LoggedUser create() {
+ return new LoggedUserImpl();
+ }
+
+ @Override
+ public void resolveProcessRoles(AbstractActor user) {
+ Set processRoleIds = user.getProcessRoleIds();
+ user.getGroupIds().forEach(groupId -> {
+ resolveProcessRolesRecursively(groupService.findById(groupId), processRoleIds);
+ });
+
+ user.getProcessRoleIds().forEach(processRoleId -> {
+ ProcessRole role = processRoleService.findById(processRoleId);
+ if (role != null) {
+ user.getProcessRoles().add(role);
+ }
+ });
+ }
+
+ @Override
+ public void resolveProcessRolesRecursively(AbstractActor actor, Set processRoleIds) {
+ processRoleIds.addAll(actor.getProcessRoleIds());
+ if (!actor.getGroupIds().isEmpty()) {
+ actor.getGroupIds().forEach(groupId -> {
+ Group group = groupService.findById(groupId);
+ processRoleIds.addAll(group.getProcessRoleIds());
+ resolveProcessRolesRecursively(group, processRoleIds);
+ });
+ }
+ }
+
+ @Override
+ public void resolveAuthorities(AbstractActor user) {
+ Set authorityIds = user.getAuthorityIds();
+ user.getGroupIds().forEach(groupId -> {
+ resolveAuthoritiesRecursively(groupService.findById(groupId), authorityIds);
+ });
+
+ user.getAuthorityIds().forEach(authorityId -> {
+ Authority authority = authorityService.getOne(authorityId);
+ if (authority != null) {
+ user.getAuthoritySet().add(authority);
+ }
+ });
+ }
+
+ @Override
+ public void resolveAuthoritiesRecursively(AbstractActor actor, Set authorityIds) {
+ authorityIds.addAll(actor.getAuthorityIds());
+ if (!actor.getGroupIds().isEmpty()) {
+ actor.getGroupIds().forEach(groupId -> {
+ Group group = groupService.findById(groupId);
+ authorityIds.addAll(group.getAuthorityIds());
+ resolveAuthoritiesRecursively(group, authorityIds);
+ });
+ }
+ }
+}
diff --git a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java
index 513e96090a4..2657328bb00 100644
--- a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java
+++ b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java
@@ -1,14 +1,19 @@
package com.netgrif.application.engine.auth.service;
+import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
import com.netgrif.application.engine.adapter.spring.utils.PaginationProperties;
import com.netgrif.application.engine.auth.config.GroupConfigurationProperties;
import com.netgrif.application.engine.auth.provider.CollectionNameProvider;
import com.netgrif.application.engine.auth.repository.GroupRepository;
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
+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.dto.GroupSearchDto;
import com.netgrif.application.engine.objects.common.ResourceNotFoundException;
import com.netgrif.application.engine.objects.common.ResourceNotFoundExceptionCode;
+import com.netgrif.application.engine.objects.dto.request.group.GroupSearchRequestDto;
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
+import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
@@ -21,6 +26,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.util.Pair;
+import org.springframework.util.Assert;
import java.time.LocalDateTime;
import java.util.*;
@@ -46,6 +52,8 @@ public class GroupServiceImpl implements GroupService {
private MongoTemplate mongoTemplate;
+ private ProcessRoleService processRoleService;
+
@Autowired
public void setCollectionNameProvider(CollectionNameProvider collectionNameProvider) {
this.collectionNameProvider = collectionNameProvider;
@@ -81,6 +89,12 @@ public void setPaginationProperties(PaginationProperties paginationProperties) {
this.paginationProperties = paginationProperties;
}
+ @Lazy
+ @Autowired
+ public void setProcessRoleService(ProcessRoleService processRoleService) {
+ this.processRoleService = processRoleService;
+ }
+
@Override
public void delete(Group group) {
if (!groupRepository.existsById(group.getStringId())) {
@@ -122,7 +136,11 @@ public void delete(Group group) {
@Override
public Group save(Group group) {
- log.debug("Saving group: [{}]", group.getStringId());
+ if (groupRepository.existsById(group.getStringId())) {
+ log.info("Updating group: [{}]", group.getIdentifier());
+ } else {
+ log.info("Saving new group: [{}]", group.getIdentifier());
+ }
group.setModifiedAt(LocalDateTime.now());
return groupRepository.save(group);
}
@@ -173,8 +191,10 @@ public Optional findByIdentifier(String identifier) {
@Override
public Group getDefaultSystemGroup() {
- if (defaultSystemGroup == null) {
+ if (!groupRepository.existsByIdentifier(groupConfigurationProperties.getDefaultGroupIdentifier())) {
defaultSystemGroup = create(groupConfigurationProperties.getDefaultGroupIdentifier(), groupConfigurationProperties.getDefaultGroupTitle(), userService.getSystem());
+ } else if (defaultSystemGroup == null) {
+ defaultSystemGroup = findByIdentifier(groupConfigurationProperties.getDefaultGroupIdentifier()).orElseThrow(() -> new IllegalStateException("Default system group does not exist"));
}
return defaultSystemGroup;
}
@@ -191,6 +211,12 @@ public Group create(AbstractUser groupOwner) {
@Override
public Group create(String identifier, String title, AbstractUser groupOwner) {
+ if (identifier == null || identifier.isBlank()) {
+ throw new IllegalArgumentException("Group identifier cannot be null or blank.");
+ }
+ if (groupRepository.existsByIdentifier(identifier)) {
+ throw new IllegalArgumentException("Group with identifier [%s] already exists.".formatted(identifier));
+ }
log.info("Creating default group for user: [{}]", groupOwner.getStringId());
Group group = new com.netgrif.application.engine.adapter.spring.auth.domain.Group(identifier, groupOwner.getRealmId());
group.setOwnerId(groupOwner.getStringId());
@@ -224,28 +250,48 @@ public Group getDefaultUserGroup(AbstractUser user) {
@Override
public void addUserToDefaultSystemGroup(AbstractUser user) {
log.info("Adding user [{}] to default group", user.getStringId());
- addUser(user, getDefaultSystemGroup());
+ addUser(getDefaultSystemGroup(), user);
+ }
+
+ @Override
+ public Group assignUsersToGroup(String groupId, Set userIds) {
+ userIds = userIds == null ? new HashSet<>() : userIds;
+ Group group = this.findById(groupId);
+ Set currentGroupMemberIds = group.getMemberIds();
+
+ Set removableMemberIds = new HashSet<>(currentGroupMemberIds);
+ removableMemberIds.removeAll(userIds);
+
+ Set newMemberIds = new HashSet<>(userIds);
+ newMemberIds.removeAll(currentGroupMemberIds);
+
+ removableMemberIds.forEach(toBeRemovedId -> removeUser(group, userService.findById(toBeRemovedId, group.getRealmId())));
+ newMemberIds.forEach(toBeAddedId -> addUser(group, userService.findById(toBeAddedId, group.getRealmId())));
+ return group;
}
@Override
- public Group addUser(String userId, String groupId, String realmId) {
- return addUser(userService.findById(userId, realmId), groupId);
+ public Group addUser(String groupId, String userId, String realmId) {
+ return addUser(groupId, userService.findById(userId, realmId));
}
@Override
- public Group addUser(String userId, Group group, String realmId) {
+ public Group addUser(Group group, String userId, String realmId) {
AbstractUser user = userService.findById(userId, realmId);
- return addUser(user, group);
+ return addUser(group, user);
}
@Override
- public Group addUser(AbstractUser user, String groupIdentifier) {
- Group group = findByIdentifier(groupIdentifier).orElseThrow(() -> new IllegalArgumentException("Group with identifier [%s] not found. ".formatted(groupIdentifier)));
- return addUser(user, group);
+ public Group addUser(String groupId, AbstractUser user) {
+ Group group = findById(groupId);
+ return addUser(group, user);
}
@Override
- public Group addUser(AbstractUser user, Group group) {
+ public Group addUser(Group group, AbstractUser user) {
+ Assert.notNull(user, "User cannot be null");
+ Assert.notNull(group, "Group cannot be null");
+
log.info("Adding user [{}] to group [{}]", user.getStringId(), group.getStringId());
user.addGroupId(group.getStringId());
group.addMemberId(user.getStringId());
@@ -254,13 +300,21 @@ public Group addUser(AbstractUser user, Group group) {
}
@Override
- public Group removeUser(AbstractUser user, String groupIdentifier) {
- Group group = findByIdentifier(groupIdentifier).orElseThrow(() -> new IllegalArgumentException("Group with identifier [%s] not found. ".formatted(groupIdentifier)));
- return removeUser(user, group);
+ public Group removeUser(String groupId, String userId, String realmId) {
+ return removeUser(groupId, userService.findById(userId, realmId));
+ }
+
+ @Override
+ public Group removeUser(String groupId, AbstractUser user) {
+ Group group = findById(groupId);
+ return removeUser(group, user);
}
@Override
- public Group removeUser(AbstractUser user, Group group) {
+ public Group removeUser(Group group, AbstractUser user) {
+ Assert.notNull(user, "User cannot be null");
+ Assert.notNull(group, "Group cannot be null");
+
log.info("Removing user [{}] from group [{}]", user.getStringId(), group.getStringId());
user.removeGroupId(group.getStringId());
group.removeMemberId(user.getStringId());
@@ -299,19 +353,75 @@ public Page findAllFromRealmIn(Collection realmIds, Pageable page
}
@Override
- public Group assignAuthority(String groupId, String authorityId) {
+ public Group assignAuthorities(String groupId, Set authorityIds) {
+ Group group = this.findById(groupId);
+ Set currentAuthorityIds = group.getAuthorityIds();
+
+ Set removableAuthorityIds = new HashSet<>(currentAuthorityIds);
+ removableAuthorityIds.removeAll(authorityIds);
+
+ Set newAuthorityIds = new HashSet<>(authorityIds);
+ newAuthorityIds.removeAll(currentAuthorityIds);
+
+ removableAuthorityIds.forEach(toBeRemovedId -> removeAuthority(groupId, toBeRemovedId));
+ newAuthorityIds.forEach(toBeAddedId -> addAuthority(groupId, toBeAddedId));
+ return group;
+ }
+
+ @Override
+ public Group addAuthority(String groupId, String authorityId) {
Group group = findById(groupId);
- group.addAuthority(authorityService.getOne(authorityId));
+ Authority authority = authorityService.getOne(authorityId);
+ return addAuthority(group, authority);
+ }
+
+ @Override
+ public Group addAuthority(Group group, Authority authority) {
+ Assert.notNull(group, "Group cannot be null");
+ Assert.notNull(authority, "Authority cannot be null");
+ group.addAuthority(authority);
+ return save(group);
+ }
+
+ @Override
+ public Group removeAuthority(String groupId, String authorityId) {
+ Group group = findById(groupId);
+ Authority authority = authorityService.getOne(authorityId);
+ return removeAuthority(group, authority);
+ }
+
+ @Override
+ public Group removeAuthority(Group group, Authority authority) {
+ Assert.notNull(group, "Group cannot be null");
+ Assert.notNull(authority, "Authority cannot be null");
+ group.removeAuthority(authority);
return save(group);
}
+ @Override
+ public Group assignSubgroups(String parentGroupId, Set childGroupIds) {
+ Group parentGroup = this.findById(parentGroupId);
+ Set currentSubgroupIds = parentGroup.getSubgroupIds();
+
+ Set removableGroupIds = new HashSet<>(currentSubgroupIds);
+ removableGroupIds.removeAll(childGroupIds);
+
+ Set newSubgroupIds = new HashSet<>(childGroupIds);
+ newSubgroupIds.removeAll(currentSubgroupIds);
+
+ removableGroupIds.forEach(toBeRemovedId -> removeSubgroup(parentGroupId, toBeRemovedId));
+ newSubgroupIds.forEach(toBeAddedId -> addSubgroup(parentGroupId, toBeAddedId));
+ return parentGroup;
+ }
+
@Override
public Pair addSubgroup(String parentGroupId, String childGroupId) {
if (parentGroupId.equals(childGroupId)) {
throw new IllegalArgumentException("Trying to add group to itself [%s]!".formatted(parentGroupId));
}
Group parentGroup = this.findById(parentGroupId);
- return this.addSubgroup(parentGroup, childGroupId);
+ Group childGroup = this.findById(childGroupId);
+ return this.addSubgroup(parentGroup, childGroup);
}
@Override
@@ -334,10 +444,18 @@ public Pair addSubgroup(String parentGroupId, Group childGroup) {
@Override
public Pair addSubgroup(Group parentGroup, Group childGroup) {
+ Assert.notNull(parentGroup, "Parent group cannot be null");
+ Assert.notNull(childGroup, "Child group cannot be null");
+
// TODO: maybe handle groups cycles here?
if (parentGroup.getStringId().equals(childGroup.getStringId())) {
throw new IllegalArgumentException("Trying to add group to itself [%s]!".formatted(parentGroup.getStringId()));
}
+
+ if (parentGroup.getRealmId() != null && !parentGroup.getRealmId().equals(childGroup.getRealmId())) {
+ throw new IllegalArgumentException("Trying to add group [%s] to parent group [%s] from different realm!".formatted(childGroup.getStringId(), parentGroup.getStringId()));
+ }
+
parentGroup.addSubGroupId(childGroup.getStringId());
childGroup.addGroupId(parentGroup.getStringId());
log.info("Adding group [{}] to parent group [{}]", childGroup.getStringId(), parentGroup.getStringId());
@@ -346,6 +464,50 @@ public Pair addSubgroup(Group parentGroup, Group childGroup) {
return Pair.of(parentGroup, childGroup);
}
+ @Override
+ public Pair removeSubgroup(String parentGroupId, String childGroupId) {
+ if (parentGroupId.equals(childGroupId)) {
+ throw new IllegalArgumentException("Trying to remove group from itself [%s]!".formatted(parentGroupId));
+ }
+ Group parentGroup = this.findById(parentGroupId);
+ Group childGroup = this.findById(childGroupId);
+ return this.removeSubgroup(parentGroup, childGroup);
+ }
+
+ @Override
+ public Pair removeSubgroup(Group parentGroup, String childGroupId) {
+ if (parentGroup.getStringId().equals(childGroupId)) {
+ throw new IllegalArgumentException("Trying to remove group from itself [%s]!".formatted(parentGroup.getStringId()));
+ }
+ Group childGroup = this.findById(childGroupId);
+ return this.removeSubgroup(parentGroup, childGroup);
+ }
+
+ @Override
+ public Pair removeSubgroup(String parentGroupId, Group childGroup) {
+ if (childGroup.getStringId().equals(parentGroupId)) {
+ throw new IllegalArgumentException("Trying to remove group from itself [%s]!".formatted(childGroup.getStringId()));
+ }
+ Group parentGroup = this.findById(parentGroupId);
+ return this.removeSubgroup(parentGroup, childGroup);
+ }
+
+ @Override
+ public Pair removeSubgroup(Group parentGroup, Group childGroup) {
+ Assert.notNull(parentGroup, "Parent group cannot be null");
+ Assert.notNull(childGroup, "Child group cannot be null");
+
+ if (parentGroup.getStringId().equals(childGroup.getStringId())) {
+ throw new IllegalArgumentException("Trying to remove group from itself [%s]!".formatted(parentGroup.getStringId()));
+ }
+ parentGroup.removeSubgroupId(childGroup.getStringId());
+ childGroup.removeGroupId(parentGroup.getStringId());
+ log.info("Removing group [{}] from parent group [{}]", childGroup.getStringId(), parentGroup.getStringId());
+ this.save(parentGroup);
+ this.save(childGroup);
+ return Pair.of(parentGroup, childGroup);
+ }
+
@Override
public List getGroupParentGroupsById(String groupId) {
Group group = this.findById(groupId);
@@ -388,9 +550,13 @@ public String getGroupOwnerEmail(String groupId) {
}
@Override
- public Page search(GroupSearchDto searchDto, Pageable pageable) {
+ public Page search(GroupSearchRequestDto searchDto, Pageable pageable) {
List filters = new ArrayList<>();
- if (searchDto.getFullText() != null && !searchDto.getFullText().isBlank()) {
+ if (searchDto != null && searchDto.getIds() != null) {
+ Criteria criteria = Criteria.where("_id").in(searchDto.getIds());
+ filters.add(criteria);
+ }
+ if (searchDto != null && searchDto.getFullText() != null && !searchDto.getFullText().isBlank()) {
Criteria criteria = new Criteria().orOperator(
Criteria.where("identifier").regex(searchDto.getFullText(), "i"),
Criteria.where("displayName").regex(searchDto.getFullText(), "i"),
@@ -398,7 +564,7 @@ public Page search(GroupSearchDto searchDto, Pageable pageable) {
);
filters.add(criteria);
}
- if (searchDto.getRealmId() != null && !searchDto.getRealmId().isBlank()) {
+ if (searchDto != null && searchDto.getRealmId() != null && !searchDto.getRealmId().isBlank()) {
filters.add(Criteria.where("realmId").regex(searchDto.getRealmId(), "i"));
}
Query query = Query.query(filters.isEmpty() ? new Criteria() : new Criteria().andOperator(filters.toArray(new Criteria[0])));
@@ -407,6 +573,42 @@ public Page search(GroupSearchDto searchDto, Pageable pageable) {
return new PageImpl<>(groups, pageable, count);
}
+ @Override
+ public Group addRole(String groupId, String roleId) {
+ Group group = findById(groupId);
+ ProcessRole role = processRoleService.findById(new ProcessResourceId(roleId));
+ return addRole(group, role);
+ }
+
+ @Override
+ public Group addRole(Group group, ProcessRole processRole) {
+ Assert.notNull(group, "Group cannot be null");
+ Assert.notNull(processRole, "Process role cannot be null");
+ group.addProcessRole(processRole);
+ return save(group);
+ }
+
+ @Override
+ public Group removeRole(String groupId, String roleId) {
+ Group group = findById(groupId);
+ ProcessRole role = processRoleService.findById(new ProcessResourceId(roleId));
+ return removeRole(group, role);
+ }
+
+ @Override
+ public Group removeRole(Group group, ProcessRole processRole) {
+ Assert.notNull(group, "Group cannot be null");
+ Assert.notNull(processRole, "Process role cannot be null");
+
+ group.removeProcessRole(processRole);
+ return save(group);
+ }
+
+ @Override
+ public Page findAllByProcessRoles(Collection roleIds, Pageable pageable) {
+ return groupRepository.findAllByProcessRoles__idIn(roleIds, pageable);
+ }
+
protected String getGroupOwnerEmail(Group groupCase) {
return userService.findById(groupCase.getOwnerId(), groupCase.getRealmId()).getEmail();
}
diff --git a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserFactoryImpl.java b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserFactoryImpl.java
index 2f909d90944..f57ba8c30a0 100644
--- a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserFactoryImpl.java
+++ b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserFactoryImpl.java
@@ -2,9 +2,11 @@
import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
import com.netgrif.application.engine.adapter.spring.petrinet.web.responsebodies.ProcessRole;
-import com.netgrif.application.engine.auth.web.responsebodies.User;
+import com.netgrif.application.engine.auth.web.responsebodies.UserDto;
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
+import com.netgrif.application.engine.objects.dto.response.group.GroupDto;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
import java.util.Locale;
import java.util.stream.Collectors;
@@ -17,9 +19,12 @@ public class UserFactoryImpl implements UserFactory {
@Autowired
private ProcessRoleFactory processRoleFactory;
+ @Autowired
+ private GroupService groupService;
+
@Override
- public User getUser(AbstractUser user, Locale locale) {
- User result = getUser(user);
+ public UserDto getUser(AbstractUser user, Locale locale) {
+ UserDto result = UserDto.createUser(user, groupService.findAllByIds(user.getGroupIds(), Pageable.unpaged()).stream().map(group -> GroupDto.fromGroup(group, locale)).collect(Collectors.toList()));
String defaultRoleId = processRoleService.getDefaultRole().getStringId();
String anonymousRoleId = processRoleService.getAnonymousRole().getStringId();
@@ -36,7 +41,4 @@ public User getUser(AbstractUser user, Locale locale) {
return result;
}
- protected User getUser(AbstractUser user) {
- return User.createUser(user);
- }
}
diff --git a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java
index 218f8b364ad..5da3e61ec0a 100644
--- a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java
+++ b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java
@@ -584,6 +584,7 @@ public AbstractUser createSystemUser() {
system.setLastName(UserConstants.SYSTEM_USER_SURNAME);
system.setState(UserState.ACTIVE);
saveUser(system);
+ systemUser = system;
}
return system;
}
diff --git a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/GroupRepository.java b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/GroupRepository.java
index aaa9a0749e1..ada0294fc5c 100644
--- a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/GroupRepository.java
+++ b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/GroupRepository.java
@@ -1,10 +1,13 @@
package com.netgrif.application.engine.auth.repository;
import com.netgrif.application.engine.objects.auth.domain.Group;
+import com.netgrif.application.engine.objects.auth.domain.User;
+import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
@@ -21,6 +24,15 @@
@Repository
public interface GroupRepository extends MongoRepository, QuerydslPredicateExecutor {
+
+ /**
+ * Checks if a {@link Group} entity exists with the given identifier.
+ *
+ * @param identifier the unique identifier of the group
+ * @return {@code true} if a group with the specified identifier exists, otherwise {@code false}
+ */
+ boolean existsByIdentifier(String identifier);
+
/**
* Finds paginated list of all {@link Group} entities that have the given owner ID.
*
@@ -58,6 +70,8 @@ public interface GroupRepository extends MongoRepository, Queryds
Page findAllByRealmIdIn(Collection realmIds, Pageable pageable);
+ Page findAllByProcessRoles__idIn(Collection rolesId, Pageable pageable);
+
void removeAllByRealmIdIn(Collection realmIds);
void removeAllByRealmId(String realmId);
diff --git a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java
new file mode 100644
index 00000000000..c8d5dca211f
--- /dev/null
+++ b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/AuthorizationService.java
@@ -0,0 +1,5 @@
+package com.netgrif.application.engine.auth.service;
+
+public interface AuthorizationService {
+ boolean hasAuthority(String authority);
+}
diff --git a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java
index 81f5a20714c..aae89e778f2 100644
--- a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java
+++ b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java
@@ -1,8 +1,11 @@
package com.netgrif.application.engine.auth.service;
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
+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.dto.GroupSearchDto;
+import com.netgrif.application.engine.objects.dto.request.group.GroupSearchRequestDto;
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
+import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
import org.springframework.data.mongodb.core.query.Query;
import com.querydsl.core.types.Predicate;
import org.springframework.data.domain.Page;
@@ -12,6 +15,7 @@
import java.util.Collection;
import java.util.Optional;
import java.util.List;
+import java.util.Set;
/**
* Service interface for managing user groups in the application.
@@ -83,7 +87,14 @@ public interface GroupService {
* @return the {@link Group} with the specified ID
*/
Group findById(String id);
-
+
+ /**
+ * Finds all groups matching the specified collection of IDs with pagination support.
+ *
+ * @param ids collection of group IDs to search for
+ * @param pageable pagination information
+ * @return a page of {@link Group}s that match the provided IDs
+ */
Page findAllByIds(Collection ids, Pageable pageable);
/**
@@ -139,14 +150,24 @@ public interface GroupService {
Group getDefaultSystemGroup();
/**
- * Adds a user to a group within a specific realm.
+ * Assigns a set of users to a group based on its ID.
+ *
+ * This method updates the membership of the specified group by adding the provided user IDs.
*
+ * @param groupId the ID of the group to which the users will be assigned
+ * @param userIds a set of user IDs to assign to the group
+ * @return the updated {@link Group} object including the newly assigned users
+ */
+ Group assignUsersToGroup(String groupId, Set userIds);
+
+ /**
+ * Adds a user to a group within a specific realm.
+ * @param groupId id of the group
* @param userId ID of the user to add
- * @param groupId ID of the group
* @param realmId ID of the realm
* @return the updated {@link Group}
*/
- Group addUser(String userId, String groupId, String realmId);
+ Group addUser(String groupId, String userId, String realmId);
/**
* Adds a user to a group within a specific realm.
@@ -156,16 +177,15 @@ public interface GroupService {
* @param realmId ID of the realm
* @return the updated {@link Group}
*/
- Group addUser(String userId, Group group, String realmId);
+ Group addUser(Group group, String userId, String realmId);
/**
* Adds a user to a group specified by identifier.
- *
+ * @param groupId id of the target group
* @param user the user to add
- * @param groupIdentifier identifier of the target group
* @return the updated {@link Group}
*/
- Group addUser(AbstractUser user, String groupIdentifier);
+ Group addUser(String groupId, AbstractUser user);
/**
* Adds a user to a specific group.
@@ -174,25 +194,34 @@ public interface GroupService {
* @param group the group to add the user to
* @return the updated {@link Group}
*/
- Group addUser(AbstractUser user, Group group);
+ Group addUser(Group group, AbstractUser user);
+
+ /**
+ * Removes a user from a group within a specific realm.
+ * @param groupId the unique identifier of the group
+ * @param userId the ID of the user to remove
+ * @param realmId the ID of the realm where the group exists
+ * @return the updated {@link Group}
+ */
+ Group removeUser(String groupId, String userId, String realmId);
/**
- * Removes a user from a group specified by identifier.
+ * Removes a user from a group specified by its unique identifier.
*
- * @param user the user to remove
- * @param groupIdentifier identifier of the target group
+ * @param user the user to be removed
+ * @param groupIdentifier the unique identifier of the target group
* @return the updated {@link Group}
*/
- Group removeUser(AbstractUser user, String groupIdentifier);
+ Group removeUser(String groupId, AbstractUser user);
/**
* Removes a user from a specific group.
*
- * @param user the user to remove
- * @param group the group to remove the user from
+ * @param user the user to be removed
+ * @param group the group from which the user will be removed
* @return the updated {@link Group}
*/
- Group removeUser(AbstractUser user, Group group);
+ Group removeUser(Group group, AbstractUser user);
/**
* Finds groups matching a given predicate with pagination.
@@ -203,8 +232,17 @@ public interface GroupService {
*/
Page findByPredicate(Predicate predicate, Pageable pageable);
+ /**
+ * Finds groups matching the specified MongoDB query with pagination support.
+ *
+ * @param query the MongoDB query defining the criteria for searching groups
+ * @param pageable pagination information
+ * @return a page of {@link Group}s that match the query criteria
+ */
Page findByQuery(Query query, Pageable pageable);
+ Group assignAuthorities(String groupId, Set authorityIds);
+
/**
* Assigns an authority to a group.
*
@@ -212,7 +250,52 @@ public interface GroupService {
* @param authorityId ID of the authority to assign
* @return the updated {@link Group}
*/
- Group assignAuthority(String groupId, String authorityId);
+ Group addAuthority(String groupId, String authorityId);
+
+
+ /**
+ * Assigns a specific authority to the provided group.
+ *
+ * This method updates the group by adding the specified authority to its list of associated authorities.
+ *
+ * @param group the {@link Group} object to which the authority will be added
+ * @param authority the {@link Authority} to be assigned to the group
+ * @return the updated {@link Group} object with the newly assigned authority
+ */
+ Group addAuthority(Group group, Authority authority);
+
+ /**
+ * Removes a specific authority from a group.
+ *
+ * @param groupId the ID of the group from which the authority will be removed
+ * @param authorityId the ID of the authority to remove
+ * @return the updated {@link Group} object without the specified authority
+ */
+ Group removeAuthority(String groupId, String authorityId);
+
+
+ /**
+ * Removes a specific authority from the provided group.
+ *
+ * This method updates the group by removing the specified authority.
+ *
+ * @param group the {@link Group} object from which the authority will be removed
+ * @param authority the {@link Authority} to be removed from the group
+ * @return the updated {@link Group} object without the specified authority
+ */
+ Group removeAuthority(Group group, Authority authority);
+
+ /**
+ * Assigns multiple subgroups to a parent group.
+ *
+ * This method establishes relationships between the specified child groups
+ * and the parent group identified by its ID.
+ *
+ * @param parentGroupId the ID of the parent group to which subgroups will be assigned
+ * @param childGroupIds the list of IDs of the subgroups to be assigned to the parent group
+ * @return the updated {@link Group} representing the parent group with its new subgroup assignments
+ */
+ Group assignSubgroups(String parentGroupId, Set childGroupIds);
/**
* Adds a subgroup relationship between two groups.
@@ -250,6 +333,43 @@ public interface GroupService {
*/
Pair addSubgroup(Group parentGroup, Group childGroup);
+
+ /**
+ * Removes a subgroup relationship between two groups by their IDs.
+ *
+ * @param parentGroupId the ID of the parent group
+ * @param childGroupId the ID of the child group
+ * @return a {@link Pair} containing both the updated parent and child {@link Group}s
+ */
+ Pair removeSubgroup(String parentGroupId, String childGroupId);
+
+ /**
+ * Removes a subgroup relationship between a parent group object and a child group by its ID.
+ *
+ * @param parentGroup the parent group object
+ * @param childGroupId the ID of the child group
+ * @return a {@link Pair} containing both the updated parent and child {@link Group}s
+ */
+ Pair removeSubgroup(Group parentGroup, String childGroupId);
+
+ /**
+ * Removes a subgroup relationship between a parent group by its ID and a child group object.
+ *
+ * @param parentGroupId the ID of the parent group
+ * @param childGroup the child group object
+ * @return a {@link Pair} containing both the updated parent and child {@link Group}s
+ */
+ Pair removeSubgroup(String parentGroupId, Group childGroup);
+
+ /**
+ * Removes a subgroup relationship between two group objects.
+ *
+ * @param parentGroup the parent group object
+ * @param childGroup the child group object
+ * @return a {@link Pair} containing both the updated parent and child {@link Group}s
+ */
+ Pair removeSubgroup(Group parentGroup, Group childGroup);
+
/**
* Retrieves all parent groups of a specified group.
*
@@ -302,9 +422,49 @@ public interface GroupService {
/**
* Searches for groups based on the provided search criteria and pageable details.
*
- * @param searchDto the search criteria encapsulated in a {@link GroupSearchDto}
+ * @param searchDto the search criteria encapsulated in a {@link GroupSearchRequestDto}
* @param pageable pagination information for the results
* @return a page of {@link Group} objects that match the search criteria
*/
- Page search(GroupSearchDto searchDto, Pageable pageable);
+ Page search(GroupSearchRequestDto searchDto, Pageable pageable);
+
+ /**
+ * Adds a role to a specified group.
+ *
+ * @param groupId the ID of the group to which the role will be added
+ * @param roleId the ID of the role to add to the group
+ * @return the updated {@link Group} object with the new role assigned
+ */
+ Group addRole(String groupId, String roleId);
+
+
+ /**
+ * Assigns a specific process role to a group.
+ *
+ * @param group the {@link Group} to which the role will be added
+ * @param processRole the {@link ProcessRole} to assign to the group
+ * @return the updated {@link Group} object with the assigned role
+ */
+ Group addRole(Group group, ProcessRole processRole);
+
+ /**
+ * Removes a role from a specified group.
+ *
+ * @param groupId the ID of the group from which the role will be removed
+ * @param roleId the ID of the role to remove from the group
+ * @return the updated {@link Group} object without the specified role
+ */
+ Group removeRole(String groupId, String roleId);
+
+
+ /**
+ * Removes a specified process role from a group.
+ *
+ * @param group the {@link Group} from which the role will be removed
+ * @param processRole the {@link ProcessRole} to remove from the group
+ * @return the updated {@link Group} object without the specified role
+ */
+ Group removeRole(Group group, ProcessRole processRole);
+
+ Page findAllByProcessRoles(Collection roleIds, Pageable pageable);
}
diff --git a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserFactory.java b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserFactory.java
index 8d5b3d73092..4243ee96d68 100644
--- a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserFactory.java
+++ b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserFactory.java
@@ -1,7 +1,7 @@
package com.netgrif.application.engine.auth.service;
-import com.netgrif.application.engine.auth.web.responsebodies.User;
+import com.netgrif.application.engine.auth.web.responsebodies.UserDto;
import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
import java.util.Locale;
@@ -12,5 +12,5 @@ public interface UserFactory {
* @param locale the locale for translations
* @return a full version of the user response object, that has all of its attributes set
*/
- User getUser(AbstractUser user, Locale locale);
+ UserDto getUser(AbstractUser user, Locale locale);
}
diff --git a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserDto.java
similarity index 81%
rename from nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java
rename to nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserDto.java
index 42605f8591e..30124755ec9 100644
--- a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java
+++ b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserDto.java
@@ -6,15 +6,18 @@
import com.netgrif.application.engine.objects.auth.domain.Authority;
import com.netgrif.application.engine.objects.auth.domain.Credential;
import com.netgrif.application.engine.objects.auth.domain.enums.UserState;
+import com.netgrif.application.engine.objects.dto.response.group.GroupDto;
import lombok.Data;
import java.time.LocalDateTime;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Data
-public class User {
+public class UserDto {
public static final String ATTR_ENABLED_CREDENTIALS = "enabledCredentials";
private String id;
@@ -28,15 +31,16 @@ public class User {
private Set authorities;
private Set processRoles;
private Set negativeProcessRoles;
- private Set nextGroups;
- private User impersonated;
+ private Set groupIds;
+ private Set groups;
+ private UserDto impersonated;
private LocalDateTime createdAt;
private Map> attributes;
private boolean enabled;
private boolean emailVerified;
protected UserState state;
- public User(AbstractUser user) {
+ public UserDto(AbstractUser user) {
Attribute> enabledCredentialsAttribute = new Attribute<>();
if (user instanceof com.netgrif.application.engine.objects.auth.domain.User domainUser) {
Map> credentials = domainUser.getCredentials();
@@ -73,10 +77,18 @@ public User(AbstractUser user) {
}
}
- public static User createUser(AbstractUser user) {
- User result = new User(user);
+ public static UserDto createUser(AbstractUser user) {
+ UserDto result = new UserDto(user);
result.setAuthorities(user.getAuthoritySet());
- result.setNextGroups(user.getGroupIds());
+ result.setGroupIds(user.getGroupIds());
+ return result;
+ }
+
+ public static UserDto createUser(AbstractUser user, List groups) {
+ UserDto result = createUser(user);
+ if (groups != null) {
+ result.setGroups(new HashSet<>(groups));
+ }
return result;
}
}