package it.inaf.ia2.gms.service; import it.inaf.ia2.gms.exception.BadRequestException; import it.inaf.ia2.gms.exception.UnauthorizedException; import it.inaf.ia2.gms.persistence.GroupsRepository; import it.inaf.ia2.gms.persistence.MembershipRepository; import it.inaf.ia2.gms.persistence.model.Group; import it.inaf.ia2.gms.persistence.model.User; import it.inaf.ia2.gms.persistence.model.UserGroupPermission; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import it.inaf.ia2.gms.persistence.PermissionsRepository; import it.inaf.ia2.gms.persistence.model.Membership; import it.inaf.ia2.gms.model.GroupNode; import it.inaf.ia2.gms.model.Permission; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.UUID; import org.springframework.transaction.annotation.Transactional; @Service public class GroupsService { public static final String ROOT = "ROOT"; private final GroupsRepository groupsRepository; private final PermissionsRepository permissionsRepository; private final MembershipRepository membershipRepository; @Autowired public GroupsService(GroupsRepository groupsRepository, PermissionsRepository permissionsRepository, MembershipRepository membershipRepository) { this.groupsRepository = groupsRepository; this.permissionsRepository = permissionsRepository; this.membershipRepository = membershipRepository; createRootIfNecessary(); } private void createRootIfNecessary() { if (groupsRepository.count() == 0) { Group root = new Group(); root.setId(ROOT); root.setName(ROOT); groupsRepository.save(root); } } @Transactional public Group addGroup(String parentId, String groupName, User user) { Group parent = getGroupById(parentId); if (parent.getChildrenGroups().stream() .anyMatch(g -> g.getName().equals(groupName))) { throw new BadRequestException("There is already a group named " + groupName); } if (!getPermissions(parent, user).contains(Permission.ADMIN)) { throw new UnauthorizedException("Missing admin privileges"); } Group group = new Group(); group.setId(UUID.randomUUID().toString()); group.setName(groupName); group.setParentGroup(parent); parent.getChildrenGroups().add(group); group = groupsRepository.save(group); groupsRepository.save(parent); return group; } @Transactional public List getSubgroups(Group parent, User user) { List permissions = getAllPermissions(user); Map nodesMap = new HashMap<>(); for (Group childGroup : parent.getChildrenGroups()) { addGroupNodeToMap(childGroup, permissions, nodesMap); } List nodes = new ArrayList<>(nodesMap.values()); // Sort by group name nodes.sort((n1, n2) -> n1.getGroupName().compareTo(n2.getGroupName())); return nodes; } public List getPermissions(Group group, User user) { List permissions = getAllPermissions(user); Map nodesMap = new HashMap<>(); addGroupNodeToMap(group, permissions, nodesMap); GroupNode groupNode = nodesMap.get(group.getId()); if (groupNode == null) { return new ArrayList<>(); } return groupNode.getPermissions(); } /** * Returns all the permissions, including also the calculated ones (the ones * derived from the memberships). */ private List getAllPermissions(User user) { // explicit permissions List permissions = permissionsRepository.findBy_user(user); List implicitPermissions = new ArrayList<>(); for (Membership membership : membershipRepository.findBy_user(user)) { UserGroupPermission userGroupPermission = new UserGroupPermission(); userGroupPermission.setUser(user); userGroupPermission.setGroup(membership.getGroup()); userGroupPermission.setPermission(Permission.TRAVERSE); implicitPermissions.add(userGroupPermission); } permissions.addAll(implicitPermissions); return permissions; } private void addGroupNodeToMap(Group group, List permissions, Map nodesMap) { for (UserGroupPermission permission : permissions) { boolean isChild = false; if (permission.getGroup().getId().equals(group.getId()) || (isChild = isChildOf(permission.getGroup(), group)) || (isParentOf(permission.getGroup(), group))) { GroupNode node = nodesMap.get(group.getId()); if (node == null) { node = getGroupNode(group); } if (isChild) { // Traversal only node.addPermission(Permission.TRAVERSE); } else { // Direct permission or permission inherited from parent node.addPermission(permission.getPermission()); } nodesMap.put(group.getId(), node); } } } private GroupNode getGroupNode(Group group) { GroupNode node = new GroupNode(); node.setGroupId(group.getId()); node.setGroupName(group.getName()); node.setHasChildren(!group.getChildrenGroups().isEmpty()); return node; } private boolean isChildOf(Group group, Group possibleParent) { Group parent = group.getParentGroup(); if (parent == null) { // ROOT has no parent return false; } if (possibleParent.getId().equals(parent.getId())) { return true; } // recursive call to parent group return isChildOf(parent, possibleParent); } private boolean isParentOf(Group group, Group possibleChild) { Group parent = possibleChild.getParentGroup(); if (parent == null) { return false; } if (parent.getId().equals(group.getId())) { return true; } // recursive call to parent group return isParentOf(group, parent); } public Group getGroupById(String groupId) { return groupsRepository.findById(groupId) .orElseThrow(() -> new BadRequestException("Group " + groupId + " not found")); } }