SocialNotificationUtils.java
/*
* Copyright (C) 2003-2013 eXo Platform SAS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.exoplatform.social.notification.plugin;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.exoplatform.commons.api.notification.NotificationContext;
import org.exoplatform.commons.api.notification.NotificationMessageUtils;
import org.exoplatform.commons.api.notification.model.ArgumentLiteral;
import org.exoplatform.commons.api.notification.model.NotificationInfo;
import org.exoplatform.commons.api.notification.model.PluginKey;
import org.exoplatform.commons.api.notification.plugin.AbstractNotificationChildPlugin;
import org.exoplatform.commons.api.notification.plugin.BaseNotificationPlugin;
import org.exoplatform.commons.api.notification.service.setting.PluginContainer;
import org.exoplatform.commons.api.notification.service.storage.WebNotificationStorage;
import org.exoplatform.commons.api.notification.service.template.TemplateContext;
import org.exoplatform.commons.notification.NotificationUtils;
import org.exoplatform.commons.notification.template.TemplateUtils;
import org.exoplatform.commons.utils.CommonsUtils;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.activity.model.ExoSocialActivity;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.model.Profile;
import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
import org.exoplatform.social.core.relationship.model.Relationship;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.notification.LinkProviderUtils;
import org.exoplatform.social.notification.Utils;
import org.exoplatform.social.notification.plugin.child.DefaultActivityChildPlugin;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SocialNotificationUtils {
private static final Log LOG = ExoLogger.getLogger(SocialNotificationUtils.class);
public final static Pattern IMG_SRC_REGEX = Pattern.compile("<img[^>]+((data-plugin-name\\s*=\\s*['\"]([^'\"]+)['\"][^>]+)|(src\\s*=\\s*['\"]([^'\"]+)['\"])){2}[^>]*>");
public final static ArgumentLiteral<String> ACTIVITY_ID = new ArgumentLiteral<String>(String.class, "activityId");
public final static ArgumentLiteral<String> COMMENT_ID = new ArgumentLiteral<String>(String.class, "commentId");
public final static ArgumentLiteral<String> COMMENT_REPLY_ID = new ArgumentLiteral<String>(String.class, "commentReplyId");
public final static ArgumentLiteral<String> PARENT_ACTIVITY_ID = new ArgumentLiteral<String>(String.class, "parentActivityId");
public final static ArgumentLiteral<String> POSTER = new ArgumentLiteral<String>(String.class, "poster");
public final static ArgumentLiteral<String> LIKER = new ArgumentLiteral<String>(String.class, "likersId");
public final static ArgumentLiteral<String> SENDER = new ArgumentLiteral<String>(String.class, "sender");
public final static ArgumentLiteral<ExoSocialActivity> ACTIVITY = new ArgumentLiteral<ExoSocialActivity>(ExoSocialActivity.class, "activity");
public final static ArgumentLiteral<Profile> PROFILE = new ArgumentLiteral<Profile>(Profile.class, "profile");
public final static ArgumentLiteral<Space> SPACE = new ArgumentLiteral<Space>(Space.class, "space");
public final static ArgumentLiteral<String> REMOTE_ID = new ArgumentLiteral<String>(String.class, "remoteId");
public final static ArgumentLiteral<String> SPACE_ID = new ArgumentLiteral<String>(String.class, "spaceId");
public final static ArgumentLiteral<String> REQUEST_FROM = new ArgumentLiteral<String>(String.class, "request_from");
public final static ArgumentLiteral<String> PRETTY_NAME = new ArgumentLiteral<String>(String.class, "prettyName");
public final static ArgumentLiteral<Relationship> RELATIONSHIP = new ArgumentLiteral<Relationship>(Relationship.class, "relationship");
public final static ArgumentLiteral<String> RELATIONSHIP_ID = new ArgumentLiteral<String>(String.class, "relationshipId");
public static final String EMPTY_STR = "";
public static final String SPACE_STR = " ";
public static final String DOT_STRING = ".";
public static final String A_HREF_TAG_REGEX = "</?a[^>]*>";
public static String getUserId(String identityId) {
return Utils.getIdentityManager().getIdentity(identityId, false).getRemoteId();
}
public static List<String> toListUserIds(String... userIds) {
List<String> ids = new ArrayList<String>();
for (String userId : userIds) {
ids.add(userId);
}
return ids;
}
public static boolean isSpaceActivity(ExoSocialActivity activity) {
Identity id = Utils.getIdentityManager().getOrCreateIdentity(SpaceIdentityProvider.NAME, activity.getStreamOwner(), false);
return (id != null);
}
/**
*
* @param receiversMap
* @param templateContext
* @return
*/
public static String getMessageInSpace(Map<String, List<String>> receiversMap, TemplateContext templateContext) {
StringBuilder sb = new StringBuilder();
Space space = null;
String typeSpaceDisplay = (templateContext.getPluginId().equals("PostActivitySpaceStreamPlugin")) ? "space" : "space_members";
for (Entry<String, List<String>> entry : receiversMap.entrySet()) {
sb.append("<li style=\"margin: 0 0 13px 14px; font-size: 13px; line-height: 18px; font-family: HelveticaNeue, Helvetica, Arial, sans-serif;\">");
String id = entry.getKey();
try {
space = Utils.getSpaceService().getSpaceById(id);
} catch (Exception e) {
continue;
}
List<String> values = entry.getValue();
int count = values.size();
templateContext.put("SPACE", SocialNotificationUtils.buildRedirecUrl(typeSpaceDisplay, space.getId(), space.getDisplayName()));
String[] keys = {"USER", "USER_LIST", "LAST3_USERS"};
String key = "";
StringBuilder value = new StringBuilder();
for (int i = 0; i < count && i < 3; i++) {
Identity identity = Utils.getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, values.get(i), true);
if (i > 1 && count == 3) {
key = keys[i - 1];
} else {
key = keys[i];
}
value.append(SocialNotificationUtils.buildRedirecUrl("user", identity.getRemoteId(), identity.getProfile().getFullName()));
if (count > (i + 1) && i < 2) {
value.append(", ");
}
}
templateContext.put(key, value.toString());
if(count > 3) {
templateContext.put("COUNT", SocialNotificationUtils.buildRedirecUrl(typeSpaceDisplay, space.getId(), String.valueOf((count - 3))));
}
String digester = TemplateUtils.processDigest(templateContext.digestType(count));
sb.append(digester);
sb.append("</li>");
}
return sb.toString();
}
public static String getMessageByIds(Map<String, List<String>> receiversMap,
TemplateContext templateContext) {
return getMessageByIds(receiversMap, new HashMap<String, List<Pair<String, String>>>(), templateContext);
}
/**
*
* @param receiversMap
* @param activityUserComments
* @param templateContext
* @return
*/
public static String getMessageByIds(Map<String, List<String>> receiversMap,
Map<String, List<Pair<String, String>>> activityUserComments,
TemplateContext templateContext) {
StringBuilder sb = new StringBuilder();
ExoSocialActivity activity = null;
Space space = null;
String typeActivityDisplay = (templateContext.getPluginId().equals("LikePlugin")) ? "view_likers_activity" : "view_full_activity";
String typeSpaceDisplay = (templateContext.getPluginId().equals("PostActivitySpaceStreamPlugin")) ? "space" : "space_members";
for (Entry<String, List<String>> entry : receiversMap.entrySet()) {
sb.append("<li style=\"margin: 0 0 13px 14px; font-size: 13px; line-height: 18px; font-family: HelveticaNeue, Helvetica, Arial, sans-serif;\">");
String id = entry.getKey();
try {
if (templateContext.getPluginId().equals("PostActivitySpaceStreamPlugin")) {
space = Utils.getSpaceService().getSpaceById(id);
} else {
activity = Utils.getActivityManager().getActivity(id);
}
} catch (Exception e) {
continue;
}
List<String> values = entry.getValue();
int count = values.size();
if (activity != null) {
String title = activity.getTitle();
String imagePlaceHolder = getImagePlaceHolder(templateContext.getLanguage());
title = processImageTitle(title, imagePlaceHolder);
// removes a href link from title. Just for digest building case.
title = title.replaceAll(A_HREF_TAG_REGEX, "");
templateContext.put("ACTIVITY", SocialNotificationUtils.buildRedirecActivityUrl(typeActivityDisplay, activity.getId(), title));
} else {
templateContext.put("SPACE", SocialNotificationUtils.buildRedirecUrl(typeSpaceDisplay, space.getId(), space.getDisplayName()));
}
String[] keys = {"USER", "USER_LIST", "LAST3_USERS"};
String key = "";
StringBuilder value = new StringBuilder();
for (int i = 0; i < count && i < 3; i++) {
Identity identity = Utils.getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, values.get(i), true);
if (i > 1 && count == 3) {
key = keys[i - 1];
} else {
key = keys[i];
}
value.append(SocialNotificationUtils.buildRedirecUrl("user", identity.getRemoteId(), identity.getProfile().getFullName()));
if (count > (i + 1) && i < 2) {
value.append(", ");
}
}
templateContext.put(key, value.toString());
if(count > 3) {
if (activity != null) {
templateContext.put("COUNT", SocialNotificationUtils.buildRedirecActivityUrl(typeActivityDisplay, activity.getId(), String.valueOf((count - 3))));
} else {
templateContext.put("COUNT", SocialNotificationUtils.buildRedirecUrl(typeSpaceDisplay, space.getId(), String.valueOf((count - 3))));
}
}
String digester = TemplateUtils.processDigest(templateContext.digestType(count));
sb.append(digester);
List<Pair<String, String>> userComments = activityUserComments.get(id);
if (userComments != null && userComments.size() > 0) {
sb.append("<div style=\"background-color:#f9f9f9;padding: 10px;border-left:5px solid #AACDED; padding-left: 15px; color:black;overflow:hidden;text-overflow:ellipsis;max-width:500px;\">");
for (Pair<String, String> pair: userComments) {
if (userComments.size() > 1) {
sb.append("<b>").append(pair.getKey()).append(" : </b>");
}
sb.append("<div style=\"color:#333333; font-family: 'verdana,arial,sans-serif';white-space: normal; font-style: italic;max-height: 11px;\">")
.append(pair.getValue());
sb.append("</div>");
if (userComments.size() > 1) {
sb.append("...");
}
sb.append("<br/>");
break;
}
sb.append("</div>");
sb.append("<br/>");
}
sb.append("</li>");
}
return sb.toString();
}
/**
*
* @param receiversMap
* @param templateContext
* @param type
* @return
*/
public static String getMessageByIds(Map<String, List<String>> receiversMap, TemplateContext templateContext, String type) {
StringBuilder sb = new StringBuilder();
for (Entry<String, List<String>> entry : receiversMap.entrySet()) {
sb.append("<li style=\"margin: 0 0 13px 14px; font-size: 13px; line-height: 18px; font-family: HelveticaNeue, Helvetica, Arial, sans-serif;\">");
String targetId = entry.getKey();
List<String> values = entry.getValue();
int count = values.size();
String[] keys = new String[]{"USER", "USER_LIST", "LAST3_USERS"};
if ("space".equals(type)) {
keys = new String[]{"SPACE", "SPACE_LIST", "LAST3_SPACES"};
}
String key = "";
StringBuilder value = new StringBuilder();
for (int i = 0; i < count && i < 3; i++) {
String name = "";
if ("new_user".equals(type) || "user".equals(type) || "connections_request".equals(type)) {
Identity identity = Utils.getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, values.get(i), true);
name = identity.getProfile().getFullName();
} else {
Space space = Utils.getSpaceService().getSpaceById(values.get(i));
name = space.getDisplayName();
}
//
if (i > 1 && count == 3) {
key = keys[i - 1];
} else {
key = keys[i];
}
value.append(SocialNotificationUtils.buildRedirecUrl("new_user".equals(type) ? "user" : type, values.get(i), name));
if (count > (i + 1) && i < 2) {
value.append(", ");
}
}
templateContext.put(key, value.toString());
if(count > 3) {
if ("user".equals(type)) {
templateContext.put("COUNT", SocialNotificationUtils.buildRedirecUrl("user_activity_stream", targetId, String.valueOf((count - 3))));
templateContext.put("ACTIVITY_STREAM", LinkProviderUtils.getRedirectUrl("user_activity_stream", targetId));
} else if ("space".equals(type)) {
templateContext.put("COUNT", SocialNotificationUtils.buildRedirecUrl("space_invitation", targetId, String.valueOf((count - 3))));
} else if ("new_user".equals(type)) {
templateContext.put("COUNT", SocialNotificationUtils.buildRedirecUrl("connections", "all", String.valueOf((count - 3))));
} else {
templateContext.put("COUNT", SocialNotificationUtils.buildRedirecUrl("connections_request", targetId, String.valueOf((count - 3))));
}
} else {
if ("user".equals(type)) {
templateContext.put("ACTIVITY_STREAM", LinkProviderUtils.getRedirectUrl("user_activity_stream", targetId));
}
}
String digester = TemplateUtils.processDigest(templateContext.digestType(count));
sb.append(digester);
sb.append("</li>");
}
return sb.toString();
}
public static void processInforSendTo(Map<String, List<String>> map, String key, String value) {
List<String> list = new LinkedList<String>();
if (map.containsKey(key)) {
list.addAll(map.get(key));
}
if (list.contains(value) == false) {
list.add(value);
}
map.put(key, new ArrayList<String>(list));
}
public static void processInforUserComments(Map<String, List<Pair<String, String>>> map, String key, Pair<String, String> value) {
List<Pair<String, String>> list = new ArrayList<Pair<String, String>>();
if (map.containsKey(key)) {
list.addAll(map.get(key));
}
list.add(value);
map.put(key, list);
}
public static String buildRedirecUrl(String type, String id, String name) {
String link = LinkProviderUtils.getRedirectUrl(type, id);
return "<a target=\"_blank\" style=\"text-decoration: none; font-weight: bold; color: #2f5e92; font-family: 'HelveticaNeue Bold', Helvetica, Arial, sans-serif; font-size: 13px; line-height: 18px;\" href=\""+ link + "\">" + StringEscapeUtils.escapeHtml(name) + "</a>";
}
public static String buildRedirecActivityUrl(String type, String id, String activityTitle) {
String link = LinkProviderUtils.getRedirectUrl(type, id);
return "<a target=\"_blank\" style=\"text-decoration: none; color: #2f5e92; font-family: 'HelveticaNeue Bold', Helvetica, Arial, sans-serif; font-size: 13px; line-height: 18px;\" href=\""+ link + "\"><b>" + activityTitle + "</b></a>";
}
public static void addFooterAndFirstName(String remoteId, TemplateContext templateContext) {
String firstName = "";
String redirectUrl = "";
Identity receiver = Utils.getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, remoteId, true);
if(receiver != null) {
firstName = (String) receiver.getProfile().getProperty(Profile.FIRST_NAME);
redirectUrl = LinkProviderUtils.getRedirectUrl("notification_settings", receiver.getRemoteId());
}
templateContext.put("FIRSTNAME", firstName);
templateContext.put("FOOTER_LINK", redirectUrl);
}
public static String processImageTitle(String body, String placeholder) {
Matcher matcher = IMG_SRC_REGEX.matcher(body);
int startIdex = 0;
while (matcher.find(startIdex)) {
String imageBody = matcher.group(0);
body = body.replace(imageBody, "<i> [" + placeholder + "] </i>");
startIdex = matcher.end(1);
}
return body;
}
public static String getImagePlaceHolder(String language) {
return TemplateUtils.getResourceBundle("Notification.label.InlineImage",
new Locale(language),
"locale.social.Webui");
}
public static String getBody(NotificationContext ctx, TemplateContext context, ExoSocialActivity activity) {
PluginKey childKey = new PluginKey(activity.getType());
PluginContainer pluginContainer = CommonsUtils.getService(PluginContainer.class);
BaseNotificationPlugin child = pluginContainer.getPlugin(childKey);
if (child == null || (child instanceof AbstractNotificationChildPlugin) == false) {
child = pluginContainer.getPlugin(new PluginKey(DefaultActivityChildPlugin.ID));
}
context.put("ACTIVITY", ((AbstractNotificationChildPlugin) child).makeContent(ctx));
String body = TemplateUtils.processGroovy(context);
body = processImageTitle(body, getImagePlaceHolder(context.getLanguage()));
return body;
}
public static NotificationInfo addUserToPreviousNotification(NotificationInfo notification,
String propertyName,
String activityId,
String userId) {
// Get comment id before changing previous notification
String commentId = notification.getValueOwnerParameter(SocialNotificationUtils.COMMENT_ID.getKey());
List<String> users = null;
WebNotificationStorage storage = CommonsUtils.getService(WebNotificationStorage.class);
NotificationInfo previousNotification = storage.getUnreadNotification(notification.getKey().getId(),
activityId,
notification.getTo());
if (previousNotification != null) {
users = NotificationUtils.stringToList(previousNotification.getValueOwnerParameter(propertyName));
Identity userIdentity = Utils.getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, userId, true);
if (users == null) {
users = new ArrayList<>();
} else if (users.contains(userIdentity.getRemoteId())) {
users.remove(userIdentity.getRemoteId());
}
users.add(userIdentity.getRemoteId());
previousNotification.with(propertyName, NotificationUtils.listToString(users));
previousNotification.with(NotificationMessageUtils.NOT_HIGHLIGHT_COMMENT_PORPERTY.getKey(), "true");
previousNotification.setUpdate(true);
previousNotification.setResetOnBadge(false);
previousNotification.setLastModifiedDate(Calendar.getInstance());
previousNotification.with(SocialNotificationUtils.COMMENT_ID.getKey(), commentId);
return previousNotification;
}
return notification;
}
public static List<String> mergeUsers(NotificationInfo notification, String propertyName, String activityId, String userId) {
return NotificationUtils.stringToList(notification.getValueOwnerParameter(propertyName));
}
}