Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2012 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.commons.comments.api;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Locale;
import java.util.Map.Entry;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import com.adobe.cq.social.commons.CommentException;
import com.adobe.cq.social.commons.comments.impl.CommentImpl;
import com.adobe.cq.social.scf.core.BaseQueryRequestInfo;
import com.adobe.cq.social.commons.comments.impl.TransientPropertyConstants;
import com.adobe.cq.social.commons.comments.impl.TransientPropertyHelper;
import com.day.cq.wcm.api.Page;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.SyntheticResource;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.cq.social.commons.Attachment;
import com.adobe.cq.social.commons.CommentSystem;
import com.adobe.cq.social.commons.CommentUtil;
import com.adobe.cq.social.commons.comments.states.internal.State;
import com.adobe.cq.social.commons.comments.states.internal.StateMachine;
import com.adobe.cq.social.commons.comments.listing.CommentSocialComponentList;
import com.adobe.cq.social.commons.comments.listing.CommentSocialComponentListProvider;
import com.adobe.cq.social.commons.comments.listing.CommentSocialComponentListProviderManager;
import com.adobe.cq.social.commons.moderation.api.FlagReason;
import com.adobe.cq.social.commons.tagging.SocialTagManager;
import com.adobe.cq.social.scf.ClientUtilities;
import com.adobe.cq.social.scf.CollectionPagination;
import com.adobe.cq.social.scf.QueryRequestInfo;
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.User;
import com.adobe.cq.social.scf.core.BaseSocialComponent;
import com.adobe.cq.social.scf.core.CollectionSortedOrder;
import com.adobe.cq.social.srp.SocialResource;
import com.adobe.cq.social.srp.SocialResourceProvider;
import com.adobe.cq.social.srp.utilities.internal.InternalSocialResourceUtilities;
import com.adobe.cq.social.tally.Voting;
import com.adobe.cq.social.tally.client.api.Response;
import com.adobe.cq.social.tally.client.api.TallyException;
import com.adobe.cq.social.tally.client.api.Vote;
import com.adobe.cq.social.translation.TranslationResults;
import com.adobe.cq.social.translation.TranslationSCFUtil;
import com.adobe.cq.social.translation.TranslationUtil;
import com.adobe.cq.social.ugcbase.CollabUser;
import com.adobe.cq.social.ugcbase.SocialUtils;
import com.adobe.cq.social.ugcbase.core.SocialResourceUtils;
import com.adobe.granite.security.user.UserProperties;
import com.day.cq.tagging.TagConstants;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
public abstract class AbstractComment extends BaseSocialComponent implements
Comment {
/** Logger for this class. */
private static final Logger LOG = LoggerFactory.getLogger(AbstractComment.class);
private static final String UNKNOWN_USER = "Unknown";
private static final String JCR_DESCRIPTION_PROP = "jcr:description";
private static final String JCR_TITLE_PROP = "jcr:title";
private static String USERS_HOME_UGC = "/home/users/";
/** local variables. */
protected final CommentSocialComponentList replies;
private final User author;
private final Map attachments;
private final Calendar created;
private final String message;
private final String parentPath;
private final String resourceType;
private final boolean isTopLevel;
private final boolean isApproved;
private boolean isDraft = false;
private final State state;
private boolean isScheduled = false;
private final Calendar publishDate;
private boolean canEdit = false;
private boolean canDelete = false;
private boolean userIsModerator = false;
private boolean currentUserFlagged = false;
private String currentUserFlagText = null;
private String translationAttribution = null;
private final QueryRequestInfo queryInfo;
private final boolean isVisible;
private final boolean isClosed;
private final boolean isPinned;
private final boolean isFeatured;
private final boolean doDisplayTranslation;
private final boolean displayReplyButton;
private T configuration;
private final ModeratorActions moderatorActions;
private final ModeratorStatus moderatorStatus;
private final String votingRoot;
private boolean useFlagReasonList = true;
private boolean useFlagReasons = false;
private boolean useReferrerUrl;
private List flagReasons;
private CommentSocialComponentListProviderManager commentListProviderManager;
private final com.adobe.cq.social.commons.Comment comment;
private SocialComponent parentComponent;
private SocialComponent sourceComponent;
private PageInfo pageInfo;
private String descriptionTranslation = null;
private String titleTranslation = null;
private String displayTranslation = null;
private int MAX_ERROR_MESSAGE_LENGTH = 1000; // max message length that we log in the case filterHTML failing.
private final String MODERATORS_ROLE = "moderators";
private final String OWNER_ROLE = "owner";
private final String EDIT_OPERATION = "Edit";
private final String DELETE_OPERATION = "Delete";
private final String PROP_STATE = "state_s";
private final String ERROR_HTML_FILTER_MESSAGE =
"There was something wrong with this post. Please contact your administrator to fix the issue.";
private final String FILTER = "filter";
private final String PAGE = "page has";
private final String RESOURCE_COMMENTS = "se_social/se_discussion/";
private final String CATALOG = "catalog.";
private final String LEARNINGPATH = "learningpath";
private final String RESOURCE = "resource";
private String filterFromRequest = null;
/**
* Construct a comment for the specified resource and client utilities.
* @param resource the specified resource
* @param clientUtils the client utilities instance
* @param commentListProviderManager list manager to use for listing content
* @throws RepositoryException if an error occurs
*/
public AbstractComment(final Resource resource, final ClientUtilities clientUtils,
final CommentSocialComponentListProviderManager commentListProviderManager) throws RepositoryException {
this(resource, clientUtils, QueryRequestInfo.DEFAULT_QUERY_INFO_FACTORY.create(), commentListProviderManager);
}
/**
* Constructor of a comment.
* @param resource the specified {@link com.adobe.cq.social.commons.Comment}
* @param clientUtils the client utilities instance
* @param queryInfo the query info.
* @param commentListProviderManager list manager to use for listing content
* @throws RepositoryException if an error occurs
*/
public AbstractComment(final Resource resource, final ClientUtilities clientUtils,
final QueryRequestInfo queryInfo, final CommentSocialComponentListProviderManager commentListProviderManager)
throws RepositoryException {
super(resource, clientUtils);
this.commentListProviderManager = commentListProviderManager;
comment = resource.adaptTo(com.adobe.cq.social.commons.Comment.class);
author = this.clientUtils.getUser(comment.getAuthor().getId(), comment.getResource().getResourceResolver());
attachments = comment.getAttachments();
created = comment.getCreated();
message = comment.getMessage();
parentPath = comment.getComponent().getPath();
isTopLevel = comment.isTopLevel();
//This is needed for deeplinking of repliess
if (queryInfo.getPredicates().containsKey(FILTER) && (queryInfo.getPredicates().get(FILTER)[0].startsWith(PAGE))) {
filterFromRequest = queryInfo.getPredicates().get(FILTER)[0].replace(PAGE, "").trim();
this.queryInfo = new BaseQueryRequestInfo(false, new HashMap(), queryInfo.getPagination(), queryInfo.getSortOrder(), queryInfo.getSortBy());
} else {
this.queryInfo = queryInfo;
}
flagReasons = new ArrayList();
final Session session = resource.getResourceResolver().adaptTo(Session.class);
final String userId = session.getUserID();
final CommentSystem cs = comment.getCommentSystem();
// Comment is approved or it doesn't need to be because it's not moderated.
isApproved = !comment.isSpam() && (comment.isApproved() || !cs.isModerated());
userIsModerator = clientUtils.getSocialUtils().hasModeratePermissions(resource);
isDraft = comment.getProperty(com.adobe.cq.social.commons.Comment.PROP_IS_DRAFT, false);
// to get the state of the comment
// TODO: adaptor factory
final String currentState = comment.getProperty(PROP_STATE, "");
final StateMachine stateMachine = resource.adaptTo(StateMachine.class);
state = stateMachine == null ? null : stateMachine.getState(currentState);
isScheduled = comment.getProperty(com.adobe.cq.social.commons.Comment.PROP_IS_SCHEDULED, false);
publishDate = comment.getProperty(com.adobe.cq.social.commons.Comment.PROP_PUBLISH_DATE, Calendar.class);
final boolean userIsLoggedIn =
clientUtils == null ? !(userId == null || userId.equalsIgnoreCase(CollabUser.ANONYMOUS)) : !clientUtils
.userIsAnonymous();
isClosed = comment.isClosed();
isPinned = comment.getProperty(com.adobe.cq.social.commons.Comment.PROP_PINNED, false);
isFeatured = comment.getProperty(com.adobe.cq.social.commons.Comment.PROP_FEATURED, false);
useReferrerUrl = cs.getProperty(PROP_USE_REFERRER_URL, Boolean.FALSE);
configuration = createConfiguration(resource, cs.getResource());
// TODO: the complete logic should be inside state machine
final boolean canModEdit = state == null ? true : state.canPerformOperation(MODERATORS_ROLE, EDIT_OPERATION);
final boolean canOwnerEdit = state == null ? true : state.canPerformOperation(OWNER_ROLE, EDIT_OPERATION);
final boolean canModDelete =
state == null ? true : state.canPerformOperation(MODERATORS_ROLE, DELETE_OPERATION);
final boolean canOwnerDelete = state == null ? true : state.canPerformOperation(OWNER_ROLE, DELETE_OPERATION);
if ((userIsModerator && canModEdit) || (userIsOwner() && userIsLoggedIn && canOwnerEdit) && !isClosed) {
canEdit = true;
}
if ((userIsModerator && canModDelete)
|| (userIsOwner() && userIsLoggedIn && canOwnerDelete && cs.allowsDelete()) && !isClosed) {
canDelete = true;
}
// A comment is visible to moderators, and to others if it's not spam, not hidden from flagging,
// and not premoderated and not yet approved.
if (userIsModerator || (!comment.isSpam() && !comment.isFlaggedHidden() && isApproved && !isDraft)) {
isVisible = true;
} else {
isVisible = false;
}
displayReplyButton = canUserReply(userIsLoggedIn, cs, session);
moderatorStatus = (userIsModerator) ? new ModeratorStatusImpl(comment, cs) : null;
if (cs.allowsFlagging()) {
useFlagReasonList = cs.useFlagReasonList();
useFlagReasons = useFlagReasonList || cs.allowCustomFlagReason();
final Response response = getFlagResponseForUser(userId);
if (response != null && response.getResponseValue() != null) { // this user DID flag this content
currentUserFlagged = true;
if (useFlagReasons) {
final Resource responseResource = response.getResource();
final ValueMap resourceProperties = responseResource.adaptTo(ValueMap.class);
// Should not be null, but ensure it's not anyways.
currentUserFlagText =
resourceProperties.get(com.adobe.cq.social.commons.Comment.PROP_FLAG_REASON, "");
}
}
if (userIsModerator && useFlagReasons) {
flagReasons = listFlagReasons(resource, clientUtils);
}
}
this.moderatorActions = new ModeratorActionsImpl(comment, cs, userIsLoggedIn);
resourceType = comment.getResource().getResourceType();
final QueryRequestInfo repliesListInfo = QueryRequestInfo.DEFAULT_QUERY_INFO_FACTORY.create(this.queryInfo);
final CollectionPagination currentPagination = repliesListInfo.getPagination();
CollectionPagination repliesPagination;
if (configuration.isDoNotGetRepliesOnListingPage() && resource != null && TransientPropertyHelper.getTransientProperty(resource,TransientPropertyConstants.TRANSIENT_PROPERTY_COLLECTION, false)) {
repliesPagination = new CollectionPagination(0, 0, 0, currentPagination.getSortIndex(), this.configuration.getPageSize());
}else if (currentPagination.getEmbedLevel() != CollectionPagination.DEFAULT_EMBED_LEVEL) {
// don't fetch nested replies
repliesPagination =
new CollectionPagination(0, 0, currentPagination.getEmbedLevel() + 1,
currentPagination.getSortIndex(), this.configuration.getPageSize());
} else {
repliesPagination =
new CollectionPagination(currentPagination.getOffset(),
queryInfo.getPagination() == CollectionPagination.DEFAULT_PAGINATION ? this.configuration
.getPageSize() : currentPagination.getSize(),
currentPagination.getEmbedLevel() + 1, currentPagination.getSortIndex(),
this.configuration.getPageSize());
}
repliesListInfo.setPagination(repliesPagination);
repliesListInfo.setSortOrder(CollectionSortedOrder.DEFAULT_ORDER);
replies = getReplies(resource, this, this.filterFromRequest, repliesListInfo);
final Resource component = cs.getResource();
if (configuration.isVotingAllowed()) // set voting root only if its allowed for a SCF component
votingRoot = CommentUtil.getVotingRoot(component);
else
votingRoot = "";
// if this is a search, prefetches are done in SearchComponent and no need to show translate button
if (!queryInfo.isQuery()
&& resource.getPath().indexOf(
clientUtils.getSocialUtils().getStorageConfig(resource).getAsiPath() + USERS_HOME_UGC) == -1) {
prefetchResources(resource.getResourceResolver(), clientUtils, cs);
// call the function from TranslationUtil to determine weather show the translation button.
doDisplayTranslation =
TranslationUtil.doDisplayTranslation(resource.getResourceResolver(), resource, clientUtils);
} else {
doDisplayTranslation = false;
}
pageInfo = new PageInfo(this, clientUtils, repliesListInfo.getPagination());
if ((this.queryInfo.isTranslationRequest() && this.queryInfo.getPagination().getEmbedLevel() == 0)
|| (clientUtils.getRequest() != null && TranslationSCFUtil.isSmartRenderingOn(resource, clientUtils))) {
final TranslationResults results = TranslationSCFUtil.getTranslationSCF(resource, clientUtils);
if (results != null) {
final Map translations = results.getTranslation();
this.displayTranslation = results.getDisplay();
this.translationAttribution = results.getAttribution();
if (!translations.isEmpty()) {
this.descriptionTranslation = translations.get(JCR_DESCRIPTION_PROP);
this.titleTranslation = translations.get(JCR_TITLE_PROP);
}
}
}
}
/* Returns the index of a reply within all replies of a given comment for given conditions */
private int getChildIndex(final String commentToCheck, final int size, final List> sortFields) throws CommentException {
int replyIndex = 0;
if (clientUtils != null) {
final String pathToCheck = clientUtils.getCommonStorePath(resource);
final SocialResourceProvider srp = SocialResourceUtils.getSocialResource(resource).getResourceProvider();
if (srp != null) {
replyIndex = srp.getCommentIndex(pathToCheck, com.adobe.cq.social.commons.Comment.RESOURCE_TYPE, resource.getResourceResolver(),
pathToCheck + "/" + commentToCheck.split("/")[0], true);
}
}
if (replyIndex < 0) {
LOG.warn("Unable to get comment index. Fail to provide direct link to comment");
replyIndex = 0; //let's open 1st page
}
return replyIndex;
}
/* This function just handles first level reply to a top level post. We will have to write separate function for nested levels */
private CommentSocialComponentList getReplies(final Resource resource, final AbstractComment abstractComment, final String filterFromRequest, final QueryRequestInfo repliesListInfo) {
CollectionPagination repliesPagination = repliesListInfo.getPagination();
if (filterFromRequest != null) {
int replyIndex = getChildIndex(filterFromRequest, this.configuration.getPageSize(), repliesListInfo.getSortFields());
int pageNo = replyIndex/this.configuration.getPageSize() ;
repliesPagination = new CollectionPagination(pageNo * this.configuration.getPageSize(), this.configuration.getPageSize(), 1,
repliesPagination.getSortIndex(), this.configuration.getPageSize());
repliesListInfo.setPagination(repliesPagination);
}
CommentSocialComponentListProvider listProvider = this.commentListProviderManager.getCommentSocialComponentListProvider(resource, repliesListInfo);
CommentSocialComponentList replies = listProvider.getCommentSocialComponentList(abstractComment, repliesListInfo, clientUtils);
return replies;
}
/**
* @param userIsLoggedIn - true id the current request is from a logged in user
* @param cs - the {@link CommentSystem} that this {@link Comment} belongs to
* @param session - the {@link Session} associated with the current resolver
* @return true if the user can reply, false otherwise
*/
protected boolean canUserReply(final boolean userIsLoggedIn, final CommentSystem cs, final Session session) {
boolean result = false;
if (userIsLoggedIn) {
final SocialUtils socialUtils = clientUtils.getSocialUtils();
if (socialUtils != null) {
final String aclPath = socialUtils.resourceToACLPath(cs.getResource());
final boolean mayPost =
clientUtils.getSocialUtils().canAddNode(session,
aclPath == null ? CommentSystem.PATH_UGC : aclPath);
result = cs.allowsReplies() && !isClosed && mayPost;
} else {
result = false;
}
} else {
result = false;
}
return result;
}
private void prefetchResources(final ResourceResolver resolver, final ClientUtilities clientUtils,
final CommentSystem cs) {
if (!SocialResourceUtils.isSocialResource(resource)) {
return;
}
final List paths = new ArrayList(3);
if (clientUtils.isTranslationServiceConfigured(resource)) {
paths.add(resource.getPath() + "/" + TranslationUtil.TRANSLATION_NODE_NAME);
if (!isTopLevel) {
final ValueMap vm = resource.adaptTo(ValueMap.class);
if (vm != null) {
final String s = vm.get(InternalSocialResourceUtilities.PN_PARENTID, String.class);
if (s != null) {
paths.add(s + "/" + TranslationUtil.TRANSLATION_NODE_NAME);
}
}
}
}
if (configuration.isVotingAllowed()) {
paths.add(resource.getPath() + "/" + votingRoot);
if (!clientUtils.userIsAnonymous()) {
paths.add(resource.getPath() + "/" + votingRoot + "/" + clientUtils.getAuthorizedUserId());
}
}
if (!paths.isEmpty()) {
final SocialResourceProvider srp = SocialResourceUtils.getSocialResource(resource).getResourceProvider();
srp.getResources(resolver, paths);
}
}
/**
* Obtain the configuration for this comment.
* @param resource The comment resource
* @param commentSystem Resource
* @return T type
*/
protected T createConfiguration(final Resource resource, final Resource commentSystem) {
if (ResourceUtil.isNonExistingResource(commentSystem) && clientUtils != null) {
final ValueMap vm = this.clientUtils.getDesignProperties(commentSystem, CommentSystem.PROP_RESOURCE_TYPE);
return (T) new AbstractCommentCollectionConfiguration(vm);
}
return (T) new AbstractCommentCollectionConfiguration(commentSystem);
}
@Override
public T getConfiguration() {
return configuration;
}
private boolean userIsOwner() {
// TODO CollabUtil.isResourceOwner(resource) is supposed to do this, but it always treats moderators as owners
final Session session = resource.getResourceResolver().adaptTo(Session.class);
final ValueMap map = resource.adaptTo(ValueMap.class);
String resourceAuthorID = map.get(CollabUser.PROP_NAME, String.class);
final String composedByID = map.get(com.adobe.cq.social.commons.Comment.PROP_AUTHORIZABLE_ID, String.class);
if (StringUtils.isEmpty(resourceAuthorID)) {
// in case the resource has no userIdentifier property, for example calendar event
resourceAuthorID = map.get(com.day.cq.commons.jcr.JcrConstants.JCR_LAST_MODIFIED_BY, String.class);
}
return StringUtils.equals(session.getUserID(), resourceAuthorID)
|| StringUtils.equals(session.getUserID(), composedByID);
}
/**
* Get the path for the current version of the flag tally. This may or may not exist.
* @return String containing the path, or null if the resource has no returnable properties.
*/
private String getFlagsPath() {
final ValueMap props = resource.adaptTo(ValueMap.class);
if (props == null) {
LOG.warn("Unable to adapt resource {} to ValueMap.");
return null;
}
final int flagAllowCount = props.get(com.adobe.cq.social.commons.Comment.PROP_FLAG_ALLOW_COUNT, -1);
if (flagAllowCount < 0) {
// No flags exist yet, so no path to return.
return null;
}
return resource.getPath() + com.adobe.cq.social.commons.Comment.FLAG_PATH_PREFIX + flagAllowCount;
}
/**
* Return response of current user to this comment. If this comment was not flagged by this user (or was last
* unflagged), return null.
* @return Response
* @throws RepositoryException
*/
private Response getFlagResponseForUser(final String currentUserId) throws RepositoryException {
// find the vote and text provided by the current user, if any.
final ResourceResolver resolver = resource.getResourceResolver();
final String flagsPath = getFlagsPath();
if (flagsPath == null) {
return null;
}
final Resource flagResource = resolver.resolve(flagsPath);
if (ResourceUtil.isNonExistingResource(flagResource)) {
return null;
}
final Voting voting = flagResource.adaptTo(Voting.class);
Response response = null;
try {
response = voting.getUserResponse(currentUserId);
} catch (final RepositoryException e) {
LOG.error("Repository Exception getting voting response for user {}.", currentUserId);
} catch (final TallyException e) {
LOG.error("Tally Exception getting voting response for user {}.", currentUserId);
}
return response;
}
/**
* Get a list of flag reasons.
* @param resource The comment resource
* @param clientUtils
* @return The list of flag reasons.
* @throws RepositoryException
*/
private List listFlagReasons(final Resource resource, final ClientUtilities clientUtils)
throws RepositoryException {
final List reasons = new ArrayList();
final ResourceResolver resolver = resource.getResourceResolver();
final String flagsPath = getFlagsPath();
if (flagsPath == null) {
return reasons;
}
final Resource flagResource = resolver.resolve(flagsPath);
if (!ResourceUtil.isNonExistingResource(flagResource)) {
final Voting voting = flagResource.adaptTo(Voting.class);
if (voting != null) {
final Iterator> responses = voting.getResponses(0L);
while (responses.hasNext()) {
final Response response = responses.next();
final Resource responseResource = response.getResource();
final ValueMap resourceProperties = responseResource.adaptTo(ValueMap.class);
// Set the flag reason text
final String flagReasonText =
(String) resourceProperties.get(com.adobe.cq.social.commons.Comment.PROP_FLAG_REASON);
final FlagReason flagReason = new FlagReason(flagReasonText);
// Set the user name
final String flagUserId = response.getUserId();
final UserProperties userProps = clientUtils.getSocialUtils().getUserProperties(resolver, flagUserId);
final String flagUser = userProps != null ? userProps.getDisplayName() : UNKNOWN_USER;
flagReason.setUser(flagUser);
// Add the reason to the list
reasons.add(flagReason);
}
}
}
return reasons;
}
@Override
protected List getIgnoredProperties() {
this.ignoredProperties.add("jcr:.*");
this.ignoredProperties.add("userIdentifier");
this.ignoredProperties.add("referer");
this.ignoredProperties.add("authorizableId");
this.ignoredProperties.add("authorizableId");
this.ignoredProperties.add(com.adobe.cq.social.commons.Comment.PROP_PINNED);
return this.ignoredProperties;
}
/**
* {@inheritDoc}
*/
@Override
public Attachment getAttachment(final String name) {
return attachments.get(name);
}
/**
* {@inheritDoc}
*/
@Override
public User getAuthor() {
return author;
}
/**
* {@inheritDoc}
*/
@Override
public String getState() {
return (state == null) ? null : state.getTitle();
}
/**
* {@inheritDoc}
*/
@Override
public Map getAttachments() {
return attachments;
}
/**
* {@inheritDoc}
*/
@Override
public Calendar getCreated() {
return created;
}
/**
* {@inheritDoc}
*/
@Override
public String getResourceType() {
return resourceType;
}
/**
* {@inheritDoc}
*/
@Override
public String getMessage() {
try {
return clientUtils.filterHTML(message);
} catch (Throwable e) {
// this operation may fail if the message length is too long.
final String msg =
(message.length() > MAX_ERROR_MESSAGE_LENGTH) ? message.substring(MAX_ERROR_MESSAGE_LENGTH) : message;
LOG.error(
"Failed to filter HTML for the message {}. Please configure max message length or change your XSS rules for the comment system to fix the issue.",
msg);
return ERROR_HTML_FILTER_MESSAGE;
}
}
/**
* Gets the parent path for the comment.
* @return a string pointing to the externalized URL to the parent.
*/
public String getParent() {
return this.externalizeURL(this.parentPath);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getUrl();
}
/**
* Set the collection list range. If this is not set, then the return list will start at offset 0 and the default
* size
* @param pagination detail information to use
*/
@Override
public void setPagination(final CollectionPagination pagination) {
replies.setPagination(pagination);
}
/**
* {@inheritDoc}
*/
@Override
public void setSortedOrder(final CollectionSortedOrder sortedOrder) {
replies.setSortedOrder(sortedOrder);
}
public void setSortFields(final List> sortFields) {
replies.setSortFields(sortFields);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isTopLevel() {
return isTopLevel;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isApproved() {
return isApproved;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getCanEdit() {
return canEdit;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getCanReply() {
return displayReplyButton;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getCanDelete() {
return canDelete;
}
/**
* {@inheritDoc}
*/
@Override
public int getTotalSize() {
return replies.getTotalSize();
}
/**
* {@inheritDoc}
*/
@Override
public List