org.ligoj.app.plugin.id.resource.GroupResource.java Source code

Java tutorial

Introduction

Here is the source code for org.ligoj.app.plugin.id.resource.GroupResource.java

Source

/*
 * Licensed under MIT (https://github.com/ligoj/ligoj/blob/master/LICENSE)
 */
package org.ligoj.app.plugin.id.resource;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.transaction.Transactional;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.ligoj.app.api.Normalizer;
import org.ligoj.app.iam.CompanyOrg;
import org.ligoj.app.iam.GroupOrg;
import org.ligoj.app.iam.IGroupRepository;
import org.ligoj.app.iam.UserOrg;
import org.ligoj.app.iam.dao.CacheGroupRepository;
import org.ligoj.app.iam.model.CacheGroup;
import org.ligoj.app.model.ContainerType;
import org.ligoj.app.plugin.id.DnUtils;
import org.ligoj.app.plugin.id.model.ContainerScope;
import org.ligoj.bootstrap.core.json.TableItem;
import org.ligoj.bootstrap.core.json.datatable.DataTableAttributes;
import org.ligoj.bootstrap.core.resource.BusinessException;
import org.ligoj.bootstrap.core.validation.ValidationJsonException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

/**
 * Group resource.
 */
@Path(IdentityResource.SERVICE_URL + "/group")
@Service
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public class GroupResource extends AbstractContainerResource<GroupOrg, GroupEditionVo, CacheGroup> {

    /**
     * Attribute name used as filter and path.
     */
    public static final String GROUP_ATTRIBUTE = "group";

    @Autowired
    private CompanyResource organizationResource;

    @Autowired
    private CacheGroupRepository cacheGroupRepository;

    /**
     * Default constructor specifying the type as {@link ContainerType#GROUP}
     */
    public GroupResource() {
        super(ContainerType.GROUP);
    }

    @Override
    public IGroupRepository getRepository() {
        return getGroup();
    }

    @Override
    public CacheGroupRepository getCacheRepository() {
        return cacheGroupRepository;
    }

    /**
     * Return groups matching to given criteria. The visible groups, trees and companies are checked. The returned
     * groups of each user depends on the groups the user can see/write in CN form.
     * 
     * @param uriInfo
     *            filter data.
     * @return found groups.
     */
    @GET
    public TableItem<ContainerCountVo> findAll(@Context final UriInfo uriInfo) {
        final List<ContainerScope> types = containerScopeResource.findAllDescOrder(ContainerType.GROUP);
        final Map<String, CompanyOrg> companies = getCompany().findAll();
        final Collection<CompanyOrg> visibleCompanies = organizationResource.getContainers();
        final Set<GroupOrg> writeGroups = getContainersForWrite();
        final Set<GroupOrg> adminGroups = getContainersForAdmin();
        final Map<String, UserOrg> users = getUser().findAll();

        // Search the groups
        final Page<GroupOrg> findAll = getContainers(DataTableAttributes.getSearch(uriInfo),
                paginationJson.getPageRequest(uriInfo, ORDERED_COLUMNS));

        // Apply pagination and secure the users data
        return paginationJson.applyPagination(uriInfo, findAll, rawGroup -> {
            final ContainerCountVo securedUserOrg = newContainerCountVo(rawGroup, writeGroups, adminGroups, types);
            securedUserOrg.setCount(rawGroup.getMembers().size());
            // Computed the visible members
            securedUserOrg.setCountVisible((int) rawGroup.getMembers().stream().map(users::get)
                    .map(UserOrg::getCompany).map(companies::get).map(CompanyOrg::getCompanyTree)
                    .filter(c -> CollectionUtils.containsAny(visibleCompanies, c)).count());
            return securedUserOrg;
        });
    }

    /**
     * Indicates a group exists or not.
     * 
     * @param group
     *            the group name. Exact match is required, so a normalized version.
     * @return <code>true</code> if the group exists.
     */
    @GET
    @Path("{group}/exists")
    public boolean exists(@PathParam(GROUP_ATTRIBUTE) final String group) {
        return findById(group) != null;
    }

    @Override
    protected String toDn(final GroupEditionVo container, final ContainerScope scope) {
        String parentDn = scope.getDn();
        container.setParent(StringUtils.trimToNull(Normalizer.normalize(container.getParent())));
        if (container.getParent() != null) {
            // Check the parent is also inside the type, a new DN will be built
            final GroupOrg parent = findByIdExpected(container.getParent());
            if (!DnUtils.equalsOrParentOf(scope.getDn(), parent.getDn())) {
                throw new ValidationJsonException("parent", "container-parent-type-match", TYPE_ATTRIBUTE,
                        this.type, "provided", scope.getType());
            }
            parentDn = parent.getDn();
        }

        return "cn=" + container.getName() + "," + parentDn;
    }

    /**
     * Empty this group by removing all members if supported by the repository.
     * 
     * @param id
     *            The group to empty.
     */
    @POST
    @Path("empty/{id}")
    public void empty(@PathParam("id") final String id) {
        // Check the group exists
        final GroupOrg container = findByIdExpected(id);

        // Check the group can be updated by the current user
        if (!getContainersForWrite().contains(container)) {
            throw new ValidationJsonException(getTypeName(), BusinessException.KEY_UNKNOW_ID, "0", getTypeName(),
                    "1", id);
        }

        // Perform the update
        getRepository().empty(container, getUser().findAll());
    }

    @Override
    protected GroupOrg create(final GroupEditionVo container, final ContainerScope type, final String newDn) {
        // Check the related objects
        final List<String> assistants = toDn(container.getAssistants());
        final List<String> owners = toDn(container.getOwners());

        // Create the group
        final GroupOrg group = super.create(container, type, newDn);

        // Nesting management
        if (container.getParent() != null) {
            // This group will be added as "uniqueMember" of its parent
            getRepository().addGroup(group, Normalizer.normalize(container.getParent()));
        }

        // Assistant/Owner/Department management
        getRepository().addAttributes(newDn, "seeAlso", assistants);
        getRepository().addAttributes(newDn, "owner", owners);
        getRepository().addAttributes(newDn, "businessCategory",
                CollectionUtils.emptyIfNull(container.getDepartments()));

        return group;
    }

    /**
     * Convert the given user UIDs to a the corresponding DN. The users must exists.
     * 
     * @param uids
     *            The UIDs to convert.
     * @return The corresponding DN.
     */
    private List<String> toDn(final List<String> uids) {
        return CollectionUtils.emptyIfNull(uids).stream().map(getUser()::findByIdExpected).map(UserOrg::getDn)
                .collect(Collectors.toList());
    }
}