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

com.adobe.cq.social.notifications.endpoint.AbstractNotificationOperationService 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.notifications.endpoint;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
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.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.social.notifications.api.NotificationConstants;
import com.adobe.cq.social.notifications.api.NotificationManager;
import com.adobe.cq.social.notifications.api.Status;
import com.adobe.cq.social.notifications.client.api.AbstractSocialNotificationCollection;
import com.adobe.cq.social.notifications.client.api.SocialNotification;
import com.adobe.cq.social.notifications.client.api.SocialNotificationCollection;
import com.adobe.cq.social.notifications.endpoint.NotificationOperationsExtension.NotificationOperations;
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.SocialComponentFactory;
import com.adobe.cq.social.scf.SocialComponentFactoryManager;
import com.adobe.cq.social.scf.core.operations.AbstractOperationService;
import com.adobe.cq.social.serviceusers.internal.ServiceUserWrapper;
import com.adobe.cq.social.ugc.api.UgcFilter;

/**
 * Provides abstract implementation of the Subscription operation..
 * @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 AbstractNotificationOperationService
    extends AbstractOperationService implements NotificationOperationService {
    @Reference
    private SocialComponentFactoryManager componentFactoryManager;
    @Reference
    private NotificationManager notificationManager;
    @Reference
    private ServiceUserWrapper serviceUserWrapper;
    protected static final String UGC_WRITER = "ugc-writer";
    protected static final int MAX_VALUE = 2048;

    private static Logger LOG = LoggerFactory.getLogger(AbstractNotificationOperationService.class);

    @Override
    public SocialComponent markAsRead(final SlingHttpServletRequest request, final ResourceResolverFactory rrf)
        throws OperationException {
        try {
            if (!checkPermission(request.getResource())) {
                throw new OperationException("No authorization to update", HttpServletResponse.SC_UNAUTHORIZED);
            }
        } catch (final RepositoryException e) {
            LOG.error("Failed to check acl for {} ", request.getResource().getPath(), e);
            throw new OperationException("Failed to update notification",
                HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }

        ResourceResolver resolver = null;
        try {
            final Map requestParams = Collections.emptyMap();

            final U operation = getMarkReadOperation();
            resolver = getPrivilegedResolver(rrf);
            if (resolver != null) {
                final Resource resource = resolver.getResource(request.getResource().getPath());
                final ModifiableValueMap valueMap = resource.adaptTo(ModifiableValueMap.class);
                final String currentStatus =
                    valueMap.get(NotificationConstants.NOTIFICATION_STATUS_PROP, String.class);
                if (StringUtils.equals(currentStatus, Status.READ.toString())) {
                    throw new OperationException("The target notification is already marked Read",
                        HttpServletResponse.SC_BAD_REQUEST);
                }
                final Session session = resolver.adaptTo(Session.class);
                performBeforeActions(operation, session, resource, requestParams);

                valueMap.put(NotificationConstants.NOTIFICATION_STATUS_PROP, Status.READ.toString());
                resolver.commit();
                final SocialComponentFactory factory =
                    componentFactoryManager.getSocialComponentFactory(request.getResource());
                final SocialNotification component =
                    (SocialNotification) ((factory != null) ? factory.getSocialComponent(request.getResource(),
                        request) : null);
                if (component != null) {
                    performAfterActions(operation, session, component, requestParams);
                } else {
                    LOG.warn("Failed to obtain the social component");
                }
                return component;
            } else {
                throw new OperationException("Failed to obtain resource resolver",
                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
        } catch (final PersistenceException e) {
            if (resolver != null && resolver.isLive()) {
                resolver.revert();
            }
            LOG.error("Failed to change status of {}", request.getResource().getPath());
            throw new OperationException("Failed to update notification",
                HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            if (resolver != null && resolver.isLive()) {
                resolver.close();
            }
        }
    }

    @Override
    public SocialComponent markAllRead(@Nonnull final SlingHttpServletRequest request,
        @Nonnull final ResourceResolverFactory rrf) throws OperationException {
        // We don't validate the user permission in this operation since we will only mark the notifications as READ
        // that belong to the owner of the request
        final Resource resource = request.getResource();
        // Check if the resource is a NotificationCollection resource
        if (!resource.isResourceType(SocialNotificationCollection.RESOURCE_TYPE)) {
            throw new OperationException("The target resource is not the SocialNotificationCollection resource",
                HttpServletResponse.SC_BAD_REQUEST);
        }

        final ResourceResolver resolver = getPrivilegedResolver(rrf);
        try {
            if (resolver != null) {
                final Map requestParams = Collections.emptyMap();
                final U operation = getMarkAllReadOperation();
                final Session session = resolver.adaptTo(Session.class);
                performBeforeActions(operation, session, request.getResource(), requestParams);
                final UgcFilter filters = new UgcFilter();
                filters.and(AbstractSocialNotificationCollection.getPathConstraint(request.getResource()));

                final ValueMap propMap = resource.adaptTo(ValueMap.class);
                String channelId = null;
                // Adding channel filter base on the request resource configuration
                if (propMap.containsKey(SocialNotificationCollection.PROP_CHANNEL_ID)) {
                    channelId = propMap.get(SocialNotificationCollection.PROP_CHANNEL_ID, String.class);
                    LOG.debug("channelId: {}", channelId);
                }
                try {
                    final Iterable resources =
                        notificationManager.getUnreadResource(request.getResourceResolver(), AbstractSocialNotificationCollection.getPathConstraint(resource), channelId);
                    final boolean hasChanges = resources.iterator().hasNext();
                    for (final Resource res : resources) {
                        final Resource notificationRes = resolver.getResource(res.getPath());
                        final ModifiableValueMap valueMap = notificationRes.adaptTo(ModifiableValueMap.class);
                        valueMap.put(NotificationConstants.NOTIFICATION_STATUS_PROP, Status.READ.toString());
                    }

                    if (hasChanges) {
                        resolver.commit();
                    }
                    final SocialComponentFactory factory =
                        componentFactoryManager.getSocialComponentFactory(request.getResource());
                    final SocialComponent component =
                        ((factory != null) ? factory.getSocialComponent(request.getResource(), request) : null);
                    if (component != null) {
                        performAfterActions(operation, session, component, requestParams);
                    } else {
                        LOG.warn("Failed to obtain the social component");
                    }
                    return component;
                } catch (final RepositoryException e) {
                    LOG.error("Failed to obtain list of unread resources", e);
                    throw new OperationException("Failed to obtain resource resolver",
                        HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                }
            } else {
                throw new OperationException("Failed to obtain resource resolver",
                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }

        } catch (final PersistenceException e) {
            if (resolver != null && resolver.isLive()) {
                resolver.revert();
            }
            LOG.error("Failed to change status of {}", request.getResource().getPath());
            throw new OperationException("Failed to update notification",
                HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            if (resolver != null && resolver.isLive()) {
                resolver.close();
            }
        }

    }

    protected boolean checkPermission(final Resource resource) throws RepositoryException {
        // Check if the user is the owner of the stream
        final ResourceResolver resolver = resource.getResourceResolver();
        final String userId = resolver.getUserID();
        final UserManager usrMgr = resolver.adaptTo(UserManager.class);
        if (usrMgr != null) {
            final Authorizable authorizable = usrMgr.getAuthorizable(userId);
            if (resource.getPath().contains(authorizable.getPath())) {
                return true;
            }
        }
        return false;
    }

    private ResourceResolver getPrivilegedResolver(final ResourceResolverFactory rrf) {
        final Map authenticationInfo = new HashMap();
        authenticationInfo.put(ResourceResolverFactory.SUBSERVICE, UGC_WRITER);
        try {
            return serviceUserWrapper.getServiceResourceResolver(rrf, authenticationInfo);
        } catch (final LoginException e) {
            LOG.error("Failed to obtain privilieged resolver", e);
            return null;
        }
    }

    protected String getResourceType() {
        return SocialNotification.RESOURCE_TYPE;
    }

    protected abstract U getMarkReadOperation();

    protected abstract U getMarkAllReadOperation();

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy