Skip to content
GroupsService.java 6.64 KiB
Newer Older
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;
Sonia Zorba's avatar
Sonia Zorba committed
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);
        }
    }

Sonia Zorba's avatar
Sonia Zorba committed
    @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;
    }

Sonia Zorba's avatar
Sonia Zorba committed
    @Transactional
    public List<GroupNode> getSubgroups(Group parent, User user) {
        List<UserGroupPermission> permissions = getAllPermissions(user);

        Map<String, GroupNode> nodesMap = new HashMap<>();

        for (Group childGroup : parent.getChildrenGroups()) {
            addGroupNodeToMap(childGroup, permissions, nodesMap);
        }

        List<GroupNode> nodes = new ArrayList<>(nodesMap.values());

        // Sort by group name
        nodes.sort((n1, n2) -> n1.getGroupName().compareTo(n2.getGroupName()));

        return nodes;
    }
    public List<Permission> getPermissions(Group group, User user) {
        List<UserGroupPermission> permissions = getAllPermissions(user);
        Map<String, GroupNode> nodesMap = new HashMap<>();
        addGroupNodeToMap(group, permissions, nodesMap);
        GroupNode groupNode = nodesMap.get(group.getId());
        if (groupNode == null) {
Sonia Zorba's avatar
Sonia Zorba committed
            return new ArrayList<>();
        }
        return groupNode.getPermissions();
    }
    /**
     * Returns all the permissions, including also the calculated ones (the ones
     * derived from the memberships).
     */
    private List<UserGroupPermission> getAllPermissions(User user) {

        // explicit permissions
        List<UserGroupPermission> permissions = permissionsRepository.findBy_user(user);

        List<UserGroupPermission> 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<UserGroupPermission> permissions, Map<String, GroupNode> 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());
    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"));
    }
}