com.adobe.cq.social.subscriptions.client.api.AbstractSubscriptionCollection 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.subscriptions.client.api;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.jackrabbit.util.Text;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import com.adobe.cq.social.graph.client.api.Following;
import com.adobe.cq.social.scf.ClientUtilities;
import com.adobe.cq.social.scf.QueryRequestInfo;
import com.adobe.cq.social.scf.core.BaseSocialComponent;
import com.adobe.cq.social.subscriptions.api.Subscription;
import com.adobe.cq.social.subscriptions.api.SubscriptionManager;
import com.adobe.cq.social.subscriptions.api.SubscriptionType;
import com.adobe.cq.social.subscriptions.endpoint.SubscriptionCollectionOperations;
import com.adobe.cq.social.ugcbase.CollabUser;
/**
* Base class of SCF SubscriptionCollection component. A subscription collection represents a relationships between a
* user and a resource or another user. The value of the userId and the followedId is obtained in the following order:
* If the request is a Post request, then the userId and the followedId are obtained from the request parameters. If
* the request is a Get request, then:
*
* 1. The userId is obtained from the resource {@link com.adobe.cq.social.graph.client.api.Following#PROP_USERID} property; If this property does not
* exist, the userId is obtained from the request's session user id.
*
* 2. The followedId is obtained from the resource {@link Following#PROP_FOLLOWEDID} property; If this property does
* not exist, the userId is obtained from the resource name
*/
public class AbstractSubscriptionCollection extends BaseSocialComponent implements SubscriptionCollection {
private final ResourceResolver resolver;
private String userId;
private String otherId;
private static String subscriptionTypes[];
private SortedMap states;
private final SubscriptionManager subscriptionManager;
private boolean isSubscribed;
private boolean isUserLoggedIn;
private static final String PN_ALLOW_SUBSCRIPTIONS = "allowSubscriptions";
private static final boolean PV_DEFAULT_ALLOW_SUBSCRIPTIONS = false;
private static final String SUBSRCRIPTION_RELATIONSHIP_ID = SubscriptionType.SUBSCRIPTIONS.getRelationshipId();
static {
final List list = new ArrayList();
for (final SubscriptionType type : SubscriptionType.values()) {
list.add(type.getRelationshipId());
}
final String buf[] = new String[list.size()];
subscriptionTypes = list.toArray(buf);
}
public AbstractSubscriptionCollection(final Resource resource, final ClientUtilities clientUtils,
final QueryRequestInfo q, final SubscriptionManager subscriptionManager) {
super(resource, clientUtils);
initializeNodes(resource, clientUtils);
resolver = resource.getResourceResolver();
this.subscriptionManager = subscriptionManager;
}
/**
* Construct a collection from the specified subscriptions
* @param resource Resource
* @param clientUtils ClientUtilities
* @param q QueryRequestInfo
* @param subscriptions List
*/
public AbstractSubscriptionCollection(final Resource resource, final ClientUtilities clientUtils,
final QueryRequestInfo q, final List subscriptions) {
super(resource, clientUtils);
initializeNodes(resource, clientUtils);
resolver = resource.getResourceResolver();
this.subscriptionManager = null;
states = createStateList(subscriptions);
}
private void initializeNodes(final Resource resource, final ClientUtilities clientUtils) {
// 1. Get the param value from the request first. This only apply to POST request
final SlingHttpServletRequest request = clientUtils.getRequest();
if (request != null) {
this.userId = resource.getResourceResolver().getUserID();
this.otherId =
clientUtils.getUserId(request.getParameter(SubscriptionCollectionOperations.PROP_SUBSCRIBED_ID));
}
ValueMap properties = null;
// 2. If userId is not defined from the request,
// get the userId from the resource property (this only apply to GET request).
// If it is not defined, use the session user id
if (StringUtils.isBlank(this.userId)) {
this.userId = resource.getResourceResolver().getUserID();
}
// 3. if the subscribedId is not defined, get this value form the resource property.
// if this value is not defined as the resource property, check if we can obtain it from the
// resource path itself
if (StringUtils.isBlank(this.otherId)) {
properties = resource.getValueMap();
if (properties == null) {
properties = resource.getValueMap();
}
this.otherId = properties.get(SubscriptionCollectionOperations.PROP_SUBSCRIBED_ID, "");
if (StringUtils.isBlank(otherId)) {
final String resourceId = resource.getPath();
if (resourceId.startsWith(ClientUtilities.USER_ROOTPATH)) {
otherId = clientUtils.getUserId(resourceId);
} else {
otherId = Text.getRelativeParent(resourceId, 1);
}
}
}
isUserLoggedIn = !(StringUtils.isEmpty(userId) || userId.equalsIgnoreCase(CollabUser.ANONYMOUS));
if (StringUtils.isBlank(this.otherId)) {
throw new IllegalArgumentException("Invalid value of followedId.");
}
}
@Override
public String getSubscribedId() {
return otherId;
}
@Override
public String getOwner() {
return userId;
}
@Override
public String getPath() {
return resource.getPath();
}
@Override
public String[] getTypes() {
boolean allowSubscriptions = PV_DEFAULT_ALLOW_SUBSCRIPTIONS;
if (StringUtils.isNotEmpty(getSubscribedId())) {
final Resource subscribeRes = this.resolver.getResource(getSubscribedId());
allowSubscriptions = getAllowEmailSubscribing(subscribeRes, true);
}
String types[];
if (!allowSubscriptions) {
types = ArrayUtils.removeElement(subscriptionTypes, SUBSRCRIPTION_RELATIONSHIP_ID);
} else {
types = new String[subscriptionTypes.length];
System.arraycopy(subscriptionTypes, 0, types, 0, subscriptionTypes.length);
}
return types;
}
private boolean getAllowEmailSubscribing(final Resource resource, boolean lookDeep) {
boolean allowSubscriptions = PV_DEFAULT_ALLOW_SUBSCRIPTIONS;
if (resource != null) {
final ValueMap values = resource.adaptTo(ValueMap.class);
if (values != null) {
if (values.containsKey(PN_ALLOW_SUBSCRIPTIONS)) {
allowSubscriptions = values.get(PN_ALLOW_SUBSCRIPTIONS, PV_DEFAULT_ALLOW_SUBSCRIPTIONS);
} else if (lookDeep) {
// support subscription to forum-topic, blog-article, qna-question
// so look for parent component if property not found
return getAllowEmailSubscribing(resource.getParent(), false);
}
}
}
return allowSubscriptions;
}
@Override
public Map getStates() {
if (states == null) {
if (isUserLoggedIn) {
List subscriptions =
subscriptionManager.getSubscriptions(resolver, otherId, userId, getTypes());
if (subscriptions != null) {
states = createStateList(subscriptions);
}
} else {
states = createStateList(Collections.emptyList());
}
}
if (states != null) {
return Collections.unmodifiableMap(states);
} else {
return Collections.emptyMap();
}
}
private SortedMap createStateList(final List subscriptions) {
final SortedMap states =
new TreeMap(new Comparator() {
@Override
public int compare(final String k1, final String k2) {
SubscriptionType t1 = null, t2 = null;
if (StringUtils.isNotBlank(k1)) {
t1 = SubscriptionType.getByRelationshipId(k1);
}
if (StringUtils.isNotBlank(k2)) {
t2 = SubscriptionType.getByRelationshipId(k2);
}
if (t1 != null && t2 != null) {
return t1.compareTo(t2);
}
return 0;
}
});
for (final Subscription subscription : subscriptions) {
states.put(subscription.getSubscriptionType(),
new SubscriptionStatusImpl(subscription.getSubscriptionType(), true));
isSubscribed = true;
}
final String[] types = getTypes();
for (String type : types) {
if (!states.containsKey(type)) {
states.put(type, new SubscriptionStatusImpl(type, false));
}
}
return states;
}
@Override
public boolean isSubscribed() {
if (states == null) {
getStates();
}
return isSubscribed;
}
@Override
public boolean isUserLoggedIn() {
return isUserLoggedIn;
}
static class SubscriptionStatusImpl implements SubscriptionStatus {
final private String type;
final private boolean state;
public SubscriptionStatusImpl(final String type, final boolean state) {
this.type = type;
this.state = state;
}
@Override
public String getDisplayName() {
return SubscriptionType.getByRelationshipId(type).getDisplayName();
}
@Override
public boolean isSelected() {
return state;
}
}
}