All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.cq.social.members.endpoints.AbstractCommunityMemberGroupProfileOperationService Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2015 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.adobe.cq.social.members.endpoints;

import com.adobe.cq.social.members.api.CommunityMemberGroup;
import com.adobe.cq.social.members.api.CommunityMemberGroupProfile;
import com.adobe.cq.social.members.api.CommunityMemberUser;
import com.adobe.cq.social.members.api.MembersUtils;
import com.adobe.cq.social.scf.ClientUtilities;
import com.adobe.cq.social.scf.ClientUtilityFactory;
import com.adobe.cq.social.scf.Operation;
import com.adobe.cq.social.scf.OperationException;
import com.adobe.cq.social.scf.OperationExtension;
import com.adobe.cq.social.scf.SocialComponent;
import com.adobe.cq.social.scf.SocialComponentFactoryManager;
import com.adobe.cq.social.scf.core.operations.AbstractOperationService;
import com.adobe.cq.social.ugcbase.SocialUtils;
import com.day.cq.commons.jcr.JcrUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.value.StringValue;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.request.RequestParameter;
import org.apache.sling.api.request.RequestParameterMap;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.base.util.AccessControlUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.granite.xss.XSSAPI;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Provides abstract implementation of group operations.
 * @param  is a {@link OperationExtension} that will be used as hooks by the extending class.
 * @param  is a {@link Operation} that is being provided by the extending class.
 */
@Component(metatype = false, componentAbstract = true)
public abstract class AbstractCommunityMemberGroupProfileOperationService
    extends AbstractOperationService implements CommunityMemberGroupProfileOperations {

    /**
     * Logger.
     */
    private static final Logger LOG = LoggerFactory
        .getLogger(AbstractCommunityMemberGroupProfileOperationService.class);

    /** Social Component Factory Manager. */
    @Reference
    private SocialComponentFactoryManager componentFactoryManager;

    @Reference
    private SlingRepository repository;

    @Reference
    private ResourceResolverFactory rrf;

    protected ComponentContext context;

    /** Reference to XSSAPI. */
    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY, policy = ReferencePolicy.STATIC)
    private XSSAPI xss;

    @Reference
    private SocialUtils socialUtils;

    @Reference
    private ClientUtilityFactory clientUtilFactory;

    @Reference
    private MembersUtils membersUtils;

    private final String PROFILE_PATH = "./profile/";

    /**
     * Get the SocialComponent for the specified {@link Resource} and {@link SlingHttpServletRequest}.
     * @param group the target group
     * @param request the client request
     * @return the {@link SocialComponent}
     */
    @Override
    public SocialComponent getSocialComponentForGroup(final Resource group, final SlingHttpServletRequest request) {
        return getSocialComponentForGroup(group, getClientUtils(request));
    }

    public SocialComponent getSocialComponentForGroup(final Resource group, final ClientUtilities clientUtilities) {
        return membersUtils.getCommunityGroupProfile(
            group.getName().equals("profile") ? group : group.getChild("profile"), clientUtilities,
            CommunityMemberGroupProfile.RESOURCE_TYPE);
    }

    private SocialComponent getSocialComponent(final Resource group, final ClientUtilities clientUtilities) {
        String groupId;
        try {
            groupId = group.adaptTo(Node.class).getProperty("rep:authorizableId").getString();
        } catch (final RepositoryException e) {
            LOG.debug("failed to get groupId from resource {}", group.getName(), e);
            groupId = group.getName();
        }
        return membersUtils.getCommunityGroup(groupId, group.getResourceResolver(), clientUtilities,
            CommunityMemberGroup.RESOURCE_TYPE);
    }

    protected ClientUtilities getClientUtils(final SlingHttpServletRequest request) {
        return clientUtilFactory.getClientUtilities(xss, request, socialUtils);
    }

    @Override
    public Resource update(final SlingHttpServletRequest request) throws OperationException {
        ensurePropertyExists(request, PROP_GROUP_ID);
        final RequestParameterMap requestParameterMap = request.getRequestParameterMap();
        final Session session = request.getResource().getResourceResolver().adaptTo(Session.class);
        final Map requestParams = getRequestParams(requestParameterMap);
        Resource resource = update(request.getResource(), requestParams, getClientUtils(request));
        checkMembers(resource, requestParameterMap, session);
        return resource;
    }

    private void ensurePropertyExists(final SlingHttpServletRequest request, final String property)
        throws OperationException {
        ensurePropertyExists(request.getRequestParameterMap(), property);
    }

    private void ensurePropertyExists(final RequestParameterMap map, final String property) throws OperationException {
        if (!map.containsKey(property)) {
            throw new OperationException("Undefined " + property + " from the request.",
                HttpServletResponse.SC_BAD_REQUEST);
        }
    }

    private void checkMembers(final Resource resource, final RequestParameterMap requestParameterMap,
        final Session session) throws OperationException {
        try {
            String groupId = requestParameterMap.getValue(PROP_GROUP_ID).getString();
            final UserManager userManager = resource.adaptTo(UserManager.class);
            final ResourceResolver resolver = resource.getResourceResolver();
            final Group group = (Group) userManager.getAuthorizable(groupId);
            List memberId = new ArrayList();
            if (requestParameterMap.containsKey(PROP_MEMBER_ID)) {
                memberId.addAll(Arrays.asList(toStringArray(requestParameterMap.getValues(PROP_MEMBER_ID))));
            }
            Iterator members = group.getDeclaredMembers();
            List membersList = new ArrayList();
            while (members.hasNext()) {
                final Authorizable member = members.next();
                membersList.add(member.getID());
                if (!memberId.contains(member.getID()) && isValidGroupMember(resolver, member)) {
                    performMemberOperations(group, member, getRemoveMemberOperation());
                }
            }
            for (final String member : memberId) {
                if (!membersList.contains(member)) {
                    final Authorizable authorizable = userManager.getAuthorizable(member);
                    if (authorizable != null) {
                        performMemberOperations(group, authorizable, getAddMemberOperation());
                    }
                }
            }
            session.save();
        } catch (final RepositoryException e) {
            cleanupFailure(session);
            throw new OperationException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    private boolean isValidGroupMember(final ResourceResolver resolver, final Authorizable member) {
        Resource authResource = null;

        try {
            authResource = resolver.getResource(member.getPath());
        } catch (final RepositoryException e) {
            LOG.debug("Failed to get child group resource. UserId - {}.", resolver.getUserID());
        }

        return membersUtils.isValidGroupMember(authResource);
    }

    private void performMemberOperations(final Group group, final Authorizable member, final U operation) {
        String groupId = "";
        String memberId = "";
        try {
            groupId = group.getID();
            memberId = member.getID();
            if (membersUtils.isEnablementGroup(group)) {
                LOG.warn("Failed to perform operation for enablement group, as it is one of system groups: "
                        + groupId);
                return;
            }
            if (member.isGroup() && membersUtils.isEnablementGroup(member)) {
                LOG.warn("Failed to perform operation for enablement group, as it is one of system groups: "
                        + memberId);
                return;
            }
            if (operation.equals(CommunityMemberGroupProfileOperationExtension.MemberGroupOperation.REMOVE_MEMBER)) {
                group.removeMember(member);
            } else if (operation
                .equals(CommunityMemberGroupProfileOperationExtension.MemberGroupOperation.ADD_MEMBER)) {
                group.addMember(member);
            } else {
                LOG.debug(String
                    .format("Failed to perform unknown member operation for %s and %s", groupId, memberId));
            }
        } catch (final RepositoryException e) {
            LOG.debug(String.format("Failed to perform member operation for %s and %s", groupId, memberId));
        }
    }

    @Override
    public Resource update(final Resource resource, final Map requestParams,
        final ClientUtilities clientUtils) throws OperationException {
        final String groupId = (String) requestParams.get(PROP_GROUP_ID);
        final String givenName = (String) requestParams.get(PROP_GROUP_NAME);
        final String aboutMe = (String) requestParams.get(PROP_GROUP_DESCRIPTION);
        if (StringUtils.isEmpty(groupId)) {
            throw new OperationException("Missing groupId from the request.", HttpServletResponse.SC_BAD_REQUEST);
        }

        final Session session = resource.getResourceResolver().adaptTo(Session.class);
        if (session != null) {
            try {
                final UserManager userManager = resource.adaptTo(UserManager.class);
                final Group group = (Group) userManager.getAuthorizable(groupId);
                if (!StringUtils.isEmpty(givenName)) {
                    group.setProperty(PROFILE_PATH + PROP_GROUP_NAME, new StringValue(givenName));
                }
                if (!StringUtils.isEmpty(aboutMe)) {
                    group.setProperty(PROFILE_PATH + PROP_GROUP_DESCRIPTION, new StringValue(aboutMe));
                }

                return resource.getResourceResolver().getResource(group.getPath());
            } catch (final RepositoryException e) {
                cleanupFailure(session);
                throw new OperationException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
        } else {
            throw new OperationException("Session is null", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public Resource addMember(final SlingHttpServletRequest request) throws OperationException {
        ensurePropertyExists(request, PROP_GROUP_ID);
        ensurePropertyExists(request, PROP_MEMBER_ID);
        final Map requestParams = getRequestParams(request.getRequestParameterMap());
        return addMember(request.getResource(), requestParams, getClientUtils(request));
    }

    @Override
    public Resource addMember(final Resource resource, final Map requestParams,
        final ClientUtilities clientUtils) throws OperationException {
        return addOrRemoveMember(resource, requestParams, getAddMemberOperation());
    }

    @Override
    public Resource removeMember(final SlingHttpServletRequest request) throws OperationException {
        ensurePropertyExists(request, PROP_GROUP_ID);
        ensurePropertyExists(request, PROP_MEMBER_ID);
        final Map requestParams = getRequestParams(request.getRequestParameterMap());
        return removeMember(request.getResource(), requestParams, getClientUtils(request));
    }

    @Override
    public Resource removeMember(final Resource resource, final Map requestParams,
        final ClientUtilities clientUtils) throws OperationException {
        return addOrRemoveMember(resource, requestParams, getRemoveMemberOperation());
    }

    public Resource addOrRemoveMember(final Resource resource, final Map requestParams,
        final U operation) throws OperationException {
        final String groupId = (String) requestParams.get(CommunityMemberGroupProfileOperations.PROP_GROUP_ID);
        final Session session = resource.getResourceResolver().adaptTo(Session.class);
        if (session != null) {
            try {
                final UserManager userManager = resource.adaptTo(UserManager.class);
                final Group group = (Group) userManager.getAuthorizable(groupId);
                if (group == null) {
                    String error = "Failed to get authorizable for " + groupId;
                    LOG.error(error);
                    throw new OperationException(error, HttpServletResponse.SC_NOT_FOUND);
                }
                if (!membersUtils.isValidMember(group)) {
                    String error = "No permission to modify " + groupId;
                    LOG.error(error);
                    throw new OperationException(error, HttpServletResponse.SC_NOT_ACCEPTABLE);
                }
                final String[] members =
                    requestParams.get(CommunityMemberGroupProfileOperations.PROP_MEMBER_ID) instanceof String
                        ? new String[]{(String) requestParams
                            .get(CommunityMemberGroupProfileOperations.PROP_MEMBER_ID)} : (String[]) requestParams
                            .get(CommunityMemberGroupProfileOperations.PROP_MEMBER_ID);
                for (int i = 0; i < members.length; i++) {
                    addOrRemoveMember(group, members[i], operation, session);
                }

                session.save();
                return resource.getResourceResolver().getResource(group.getPath());
            } catch (final RepositoryException e) {
                cleanupFailure(session);
                throw new OperationException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
        } else {
            throw new OperationException("Session is null", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    private void addOrRemoveMember(final Group group, final String memberId, final U operation, final Session session)
        throws OperationException {
        try {
            final UserManager userManager = AccessControlUtil.getUserManager(session);
            if (group != null && !StringUtils.isEmpty(memberId)) {
                if (membersUtils.isEnablementGroup(group)) {
                    LOG.warn("Failed to perform operation for enablement group, as it is one of system groups: "
                            + group.getID());
                    return;
                }
                Authorizable authorizable = userManager.getAuthorizable(memberId);
                if (authorizable == null) {
                    String error = "Failed to get authorizable for " + memberId;
                    LOG.debug(error);
                    throw new OperationException(error, HttpServletResponse.SC_NOT_FOUND);
                }
                if (authorizable.isGroup() && membersUtils.isEnablementGroup(authorizable)) {
                    LOG.warn("Failed to perform operation for enablement group, as it is one of system groups: "
                            + authorizable.getID());
                    return;
                }
                if (membersUtils.isValidMember(authorizable)) {
                    boolean success = false;
                    if (operation.equals(getAddMemberOperation()) && !group.isMember(authorizable)) {
                        success = group.addMember(authorizable);
                    } else if (operation.equals(getRemoveMemberOperation()) && group.isMember(authorizable)) {
                        success = group.removeMember(authorizable);
                    }
                    if (!success) {
                        String error =
                            String.format(operation.equals(getAddMemberOperation()) ? "Failed to add %s to %s"
                                : "Failed to remove %s from %s", memberId, group.getID());
                        LOG.error(error);
                        throw new OperationException(error, HttpServletResponse.SC_NOT_IMPLEMENTED);
                    }
                } else {
                    String error = "No permission to get authorizable for " + memberId;
                    LOG.error(error);
                    throw new OperationException(error, HttpServletResponse.SC_NOT_ACCEPTABLE);
                }
            }
        } catch (final RepositoryException e) {
            String error =
                operation.equals(getAddMemberOperation()) ? "Failed to add member to Group"
                    : "Failed to remove member from Group";
            LOG.error(error, e);
            throw new OperationException(error, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public Resource create(final SlingHttpServletRequest request) throws OperationException {
        ensurePropertyExists(request, PROP_GROUP_ID);
        final RequestParameterMap requestParameterMap = request.getRequestParameterMap();
        final Session session = request.getResource().getResourceResolver().adaptTo(Session.class);
        final Map requestParams = getRequestParams(requestParameterMap);
        Resource resource = createGroup(request.getResource(), requestParams, getClientUtils(request));
        checkMembers(resource, requestParameterMap, session);
        return resource;
    }

    private Map getRequestParams(final RequestParameterMap params) throws OperationException {
        final Map requestParams = new HashMap();

        for (final String key : params.keySet()) {
            RequestParameter[] values = params.getValues(key);
            requestParams.put(key, values.length > 1 ? toStringArray(params.getValues(key)) : params.getValue(key)
                .getString());
        }

        return requestParams;
    }

    @Override
    public Resource createGroup(final Resource resource, final Map requestParams,
        final ClientUtilities clientUtils) throws OperationException {
        final String groupId = (String) requestParams.get(PROP_GROUP_ID);
        final String givenName = (String) requestParams.get(PROP_GROUP_NAME);
        final String aboutMe = (String) requestParams.get(PROP_GROUP_DESCRIPTION);
        if (StringUtils.isEmpty(groupId)) {
            throw new OperationException("Missing groupId from the request.", HttpServletResponse.SC_BAD_REQUEST);
        }

        try {
            final ResourceResolver resolver = resource.getResourceResolver();
            final U createOperation = getCreateOperation();

            // use the session from the request so that we can enforce ACL for this request
            Session session = resolver.adaptTo(Session.class);
            performBeforeActions(createOperation, session, resource, requestParams);
            final UserManager userManager = AccessControlUtil.getUserManager(session);
            Group group = userManager.createGroup(new Principal() {
                @Override
                public String getName() {
                    return groupId;
                }
            }, CommunityMemberGroup.COMMUNITY_GROUPS_PATH);

            group.setProperty(PROFILE_PATH + PROP_GROUP_NAME,
                JcrUtil.createValue(StringUtils.isEmpty(givenName) ? groupId : givenName, session));
            if (!StringUtils.isEmpty(aboutMe)) {
                group.setProperty(PROFILE_PATH + PROP_GROUP_DESCRIPTION, JcrUtil.createValue(aboutMe, session));
            }

            CommunityMemberGroup memberGroup =
                (CommunityMemberGroup) getSocialComponent(resolver.getResource(group.getPath()), clientUtils);
            performAfterActions(createOperation, session, memberGroup, requestParams);
            return resolver.getResource(group.getPath());
        } catch (final RepositoryException e) {
            LOG.error("failed to create new group {}", givenName, e);
            throw new OperationException("Failed to create new Group", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    private String[] toStringArray(final RequestParameter[] values) {
        String[] stringValues = null;
        if (values != null && values.length > 0) {
            stringValues = new String[values.length];
            for (int i = 0; i < values.length; i++) {
                stringValues[i] = values[i].getString();
            }
        }
        return stringValues;
    }

    /**
     * @param session session
     */
    protected void cleanupFailure(final Session session) {
        try {
            session.refresh(false);
        } catch (final RepositoryException e) {
            LOG.error("Failed to refresh the session", e);
        }
    }

    protected abstract U getCreateOperation();

    protected abstract U getAddMemberOperation();

    protected abstract U getRemoveMemberOperation();

    protected abstract U getUpdateOperation();
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy