WikiSpaceActivityPublisher.java
package org.exoplatform.wiki.ext.impl;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.portal.config.model.PortalConfig;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.services.security.IdentityConstants;
import org.exoplatform.services.security.MembershipEntry;
import org.exoplatform.social.core.activity.model.ExoSocialActivity;
import org.exoplatform.social.core.activity.model.ExoSocialActivityImpl;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
import org.exoplatform.social.core.manager.ActivityManager;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;
import org.exoplatform.social.core.storage.SpaceStorageException;
import org.exoplatform.webui.application.WebuiRequestContext;
import org.exoplatform.wiki.WikiException;
import org.exoplatform.wiki.ext.impl.WikiUIActivity.CommentType;
import org.exoplatform.wiki.mow.api.*;
import org.exoplatform.wiki.rendering.RenderingService;
import org.exoplatform.wiki.service.BreadcrumbData;
import org.exoplatform.wiki.service.IDType;
import org.exoplatform.wiki.service.PageUpdateType;
import org.exoplatform.wiki.service.WikiService;
import org.exoplatform.wiki.service.listener.PageWikiListener;
import org.exoplatform.wiki.utils.Utils;
import org.exoplatform.wiki.utils.WikiConstants;
import org.xwiki.rendering.syntax.Syntax;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class WikiSpaceActivityPublisher extends PageWikiListener {
public static final String WIKI_APP_ID = "ks-wiki:spaces";
public static final String ACTIVITY_TYPE_KEY = "act_key";
public static final String PAGE_ID_KEY = "page_id";
public static final String PAGE_TYPE_KEY = "page_type";
public static final String PAGE_OWNER_KEY = "page_owner";
public static final String PAGE_TITLE_KEY = "page_name";
public static final String URL_KEY = "page_url";
public static final String PAGE_EXCERPT = "page_exceprt";
public static final String VIEW_CHANGE_URL_KEY = "view_change_url";
public static final String VIEW_CHANGE_ANCHOR = "#CompareRevision/changes";
public static final String WIKI_PAGE_NAME = "wiki";
public static final String WIKI_PAGE_VERSION = "version";
private static final int EXCERPT_LENGTH = 140;
private static final Log LOG = ExoLogger.getExoLogger(WikiSpaceActivityPublisher.class);
private WikiService wikiService;
private IdentityManager identityManager;
private RenderingService renderingService;
private ActivityManager activityManager;
private SpaceService spaceService;
public WikiSpaceActivityPublisher(WikiService wikiService,
IdentityManager identityManager,
RenderingService renderingService,
ActivityManager activityManager,
SpaceService spaceService) {
this.wikiService = wikiService;
this.identityManager = identityManager;
this.renderingService = renderingService;
this.activityManager = activityManager;
this.spaceService = spaceService;
}
private ExoSocialActivityImpl createNewActivity(String ownerId) {
ExoSocialActivityImpl activity = new ExoSocialActivityImpl();
activity.setUserId(ownerId);
activity.setBody("body");
activity.setType(WIKI_APP_ID);
return activity;
}
private ExoSocialActivity generateActivity(Identity ownerStream,
Identity ownerIdentity,
String wikiType,
String wikiOwner,
String pageId,
Page page,
String spaceUrl,
String spaceName,
PageUpdateType activityType) throws WikiException {
// Get activity
ExoSocialActivity activity = null;
boolean isNewActivity = true;
if (page.getActivityId() != null) {
activity = activityManager.getActivity(page.getActivityId());
isNewActivity = (activity == null);
}
if (isNewActivity) {
if (page.isMinorEdit()) {
return null;
}
activity = createNewActivity(ownerIdentity.getId());
}
activity.setTitle(page.getTitle());
// Add UI params
Map<String, String> templateParams = new HashMap<>();
templateParams.put(PAGE_ID_KEY, pageId);
templateParams.put(ACTIVITY_TYPE_KEY, activityType.toString());
templateParams.put(PAGE_OWNER_KEY, wikiOwner);
templateParams.put(PAGE_TYPE_KEY, wikiType);
templateParams.put(PAGE_TITLE_KEY, page.getTitle());
String pageURL = (page.getUrl() == null) ? (spaceUrl != null ? (spaceUrl + "/" + WIKI_PAGE_NAME) : "") : page.getUrl();
templateParams.put(URL_KEY, pageURL);
int versionsTotal = 0;
List<PageVersion> versions = wikiService.getVersionsOfPage(page);
if (versions != null && !versions.isEmpty()) {
versionsTotal = versions.size();
}
templateParams.put(WIKI_PAGE_VERSION, String.valueOf(versionsTotal));
// Create page excerpt
StringBuilder excerpt = new StringBuilder();
try {
excerpt.append(renderingService.render(page.getContent(), page.getSyntax(), Syntax.PLAIN_1_0.toIdString(), false));
} catch (Exception e) {
throw new WikiException("Cannot render page " + page.getWikiType() + ":" + page.getWikiOwner() + page.getName(), e);
}
if (excerpt.length() > EXCERPT_LENGTH) {
excerpt.replace(EXCERPT_LENGTH, excerpt.length(), "...");
}
templateParams.put(PAGE_EXCERPT, validateExcerpt(excerpt.toString()));
templateParams.put(org.exoplatform.social.core.BaseActivityProcessorPlugin.TEMPLATE_PARAM_TO_PROCESS, PAGE_EXCERPT);
if (!PageUpdateType.ADD_PAGE.equals(activityType)) {
String verName = null;
if (versions != null && !versions.isEmpty()) {
verName = String.valueOf(versions.size() + 1);
}
templateParams.put(VIEW_CHANGE_URL_KEY, Utils.getURL(page.getUrl(), verName));
}
activity.setTemplateParams(templateParams);
// Save activity
if (isNewActivity) {
activityManager.saveActivityNoReturn(ownerStream, activity);
} else {
if (PageUpdateType.MOVE_PAGE.equals(activityType)) {
activity.setStreamOwner(ownerStream.getRemoteId());
}
activityManager.updateActivity(activity);
}
// Check to add comment to activity
if (!PageUpdateType.ADD_PAGE.equals(activityType)) {
if (PageUpdateType.EDIT_PAGE_TITLE.equals(activityType) && !page.isMinorEdit()) {
createAndSaveSystemComment(activity, ownerIdentity.getId(), "WikiUIActivity.msg.update-page-title", page.getTitle());
} else if (PageUpdateType.EDIT_PAGE_CONTENT.equals(activityType) && !page.isMinorEdit()) {
String comment = page.getComment();
if (StringUtils.isEmpty(comment)) {
createAndSaveSystemComment(activity, ownerIdentity.getId(), "WikiUIActivity.msg.update-page-content");
} else {
createAndSaveUserComment(activity, ownerIdentity.getId(), comment);
}
} else if (PageUpdateType.EDIT_PAGE_CONTENT_AND_TITLE.equals(activityType) && !page.isMinorEdit()) {
String comment = page.getComment();
if (StringUtils.isEmpty(comment)) {
createAndSaveComment(activity,
CommentType.SYSTEM_GROUP,
ownerIdentity.getId(),
null,
"WikiUIActivity.msg.update-page-title",
new String[] { page.getTitle() },
"WikiUIActivity.msg.update-page-content",
null);
} else {
createAndSaveComment(activity,
CommentType.SYSTEM_GROUP,
ownerIdentity.getId(),
null,
"WikiUIActivity.msg.update-page-title",
new String[] { page.getTitle() },
comment,
null);
}
} else if (PageUpdateType.MOVE_PAGE.equals(activityType)) {
List<BreadcrumbData> breadcrumbDatas = wikiService.getBreadcumb(wikiType, wikiOwner, pageId);
StringBuilder breadcrumText = new StringBuilder();
breadcrumText.append((StringUtils.isEmpty(spaceName) ? wikiOwner : spaceName)).append(" > ");
for (int i = 0; i < breadcrumbDatas.size(); i++) {
breadcrumText.append(breadcrumbDatas.get(i).getTitle());
if (i < breadcrumbDatas.size() - 1) {
breadcrumText.append(" > ");
}
}
createAndSaveSystemComment(activity, ownerIdentity.getId(), "WikiUIActivity.msg.move-page", breadcrumText.toString());
}
}
return activity;
}
private String validateExcerpt(String excerpt) {
List<String> lines = Stream.of(excerpt.split("\n")).filter(line -> !line.trim().isEmpty()).collect(Collectors.toList());
Stream<String> sLines = lines.stream();
StringBuilder result = new StringBuilder();
//
sLines.map(new Function<String, String>() {
@Override
public String apply(String line) {
if (line.length() > EXCERPT_LENGTH) {
line = line.substring(0, EXCERPT_LENGTH) + "...";
}
return line;
}
}).limit(4).forEach(line -> {
result.append("<p>");
result.append(line);
result.append("</p>");
});
if (lines.size() > 4) {
result.append("...");
}
return result.toString();
}
/**
* Create and save System comment.
*
* @param activity
* @param userId
* @param commentMsgKey
* @param args
*/
private void createAndSaveSystemComment(ExoSocialActivity activity, String userId, String commentMsgKey, String... args) {
createAndSaveComment(activity, CommentType.SYSTEM, userId, null, commentMsgKey, args, null, null);
}
/**
* Create and save User comment.
*
* @param activity
* @param userId
* @param comment
*/
private void createAndSaveUserComment(ExoSocialActivity activity, String userId, String comment) {
createAndSaveComment(activity, CommentType.USER, userId, comment, null, null, null, null);
}
/**
* Create and save comment.
*
* @param activity
* @param commentType USER: comment by user, SYSTEM: generated by system,
* GROUP_SYSTEM: block of 2 comments
* @param userId
* @param userComment
* @param commentMsgKey1
* @param args1
* @param commentMsgKey2
* @param args2
*/
private void createAndSaveComment(ExoSocialActivity activity,
CommentType commentType,
String userId,
String userComment,
String commentMsgKey1,
String[] args1,
String commentMsgKey2,
String[] args2) {
// Activity manager
ExoSocialActivity newComment = new ExoSocialActivityImpl();
StringBuilder builder = new StringBuilder();
//
if (userComment == null) {
userComment = getValueFromResourceBundle(commentMsgKey1, args1);
}
builder.append(userComment);
//
newComment.setUserId(userId);
// Activity params
Map<String, String> activityParams = new HashMap<>();
activityParams.put(WikiUIActivity.COMMENT_TYPE, commentType.name());
switch (commentType) {
case USER:
break;
case SYSTEM:
activityParams.put(WikiUIActivity.COMMENT_MESSAGE_KEY, commentMsgKey1);
activityParams.put(WikiUIActivity.COMMENT_MESSAGE_ARGS,
StringUtils.join(args1, WikiUIActivity.COMMENT_MESSAGE_ARGS_ELEMENT_SAPERATOR));
break;
case SYSTEM_GROUP:
activityParams.put(WikiUIActivity.COMMENT_MESSAGE_KEY1, commentMsgKey1);
activityParams.put(WikiUIActivity.COMMENT_MESSAGE_ARGS1,
StringUtils.join(args1, WikiUIActivity.COMMENT_MESSAGE_ARGS_ELEMENT_SAPERATOR));
activityParams.put(WikiUIActivity.COMMENT_MESSAGE_KEY2, commentMsgKey2);
activityParams.put(WikiUIActivity.COMMENT_MESSAGE_ARGS2,
StringUtils.join(args2, WikiUIActivity.COMMENT_MESSAGE_ARGS_ELEMENT_SAPERATOR));
if (args2 != null) {
builder.append("<br/>").append(getValueFromResourceBundle(commentMsgKey2, args2));
} else {
builder.append("<br/>").append(commentMsgKey2);
}
break;
}
newComment.setTemplateParams(activityParams);
newComment.setTitle(builder.toString());
//
activityManager.saveComment(activity, newComment);
}
/**
* Get the string from resource bundle file by key and parameter
*
* @param key the key in resource bundle file
* @param params
* @return
*/
private String getValueFromResourceBundle(String key, String[] params) {
WebuiRequestContext context = WebuiRequestContext.getCurrentInstance();
ResourceBundle res = context.getApplicationResourceBundle();
if (res.getString(key) == null)
return key;
String value = res.getString(key);
if (params != null) {
for (int i = 0; i < params.length; i++) {
value = value.replace("{" + i + "}", params[i]);
}
}
return value;
}
private boolean isPublic(Page page) throws WikiException {
List<PermissionEntry> permissions = page.getPermissions();
// the page is public when it has permission: [any read]
boolean isPublic = false;
if (permissions != null) {
for (PermissionEntry permissionEntry : permissions) {
if (permissionEntry.getId().equals(IdentityConstants.ANY)) {
for (Permission permission : permissionEntry.getPermissions()) {
if (PermissionType.VIEWPAGE.equals(permission.getPermissionType())) {
isPublic = true;
break;
}
}
}
}
}
return isPublic;
}
/**
* Check If a page can be read by all users of a space
*
* @param page Page
* @param space Space
* @return true : can, false : not can;
* @throws Exception
*/
private boolean isPublicInSpace(Page page, Space space) throws WikiException {
List<PermissionEntry> pagePermissions = page.getPermissions();
String groupMemberShip = MembershipEntry.ANY_TYPE + ":" + space.getGroupId();
boolean isPublic = false;
if (pagePermissions != null) {
for (PermissionEntry permissionEntry : pagePermissions) {
if (permissionEntry.getIdType().equals(IDType.MEMBERSHIP) && permissionEntry.getId().equals(groupMemberShip)) {
isPublic = true;
break;
}
}
}
return isPublic;
}
protected void saveActivity(String wikiType,
String wikiOwner,
String pageId,
Page page,
PageUpdateType activityType) throws WikiException {
try {
Class.forName("org.exoplatform.social.core.space.spi.SpaceService");
} catch (ClassNotFoundException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("eXo Social components not found!", e);
}
return;
}
// Not raise the activity in case of user space
if (PortalConfig.USER_TYPE.equals(wikiType)) {
return;
}
String username = ConversationState.getCurrent().getIdentity().getUserId();
Identity userIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, username, false);
Identity ownerStream = null, authorActivity = userIdentity;
ExoSocialActivity activity = null;
String spaceUrl = null;
String spaceName = null;
if (PortalConfig.GROUP_TYPE.equals(wikiType)) {
/* checking whether the page is in a space */
Space space;
try {
space = spaceService.getSpaceByGroupId(wikiOwner);
if (space != null) {
if (!isPublicInSpace(page, space))
return;
ownerStream = identityManager.getOrCreateIdentity(SpaceIdentityProvider.NAME, space.getPrettyName(), false);
spaceUrl = space.getUrl();
spaceName = space.getDisplayName();
}
} catch (SpaceStorageException e) {
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Space %s not existed", wikiOwner), e);
}
}
}
if (ownerStream == null) {
// if the page is public, publishing the activity in the user stream.
ownerStream = userIdentity;
}
if (ownerStream != null) {
activity = generateActivity(ownerStream,
authorActivity,
wikiType,
wikiOwner,
pageId,
page,
spaceUrl,
spaceName,
activityType);
if (activity == null) {
return;
}
// Attach activity id to wiki page
String activityId = activity.getId();
if (!StringUtils.isEmpty(activityId)) {
page.setActivityId(activityId);
wikiService.updatePage(page, null);
}
}
}
@Override
public void postAddPage(String wikiType, String wikiOwner, String pageId, Page page) throws WikiException {
if (WikiConstants.WIKI_HOME_NAME.equals(pageId)) {
// catch the case of the Wiki Home added as it's created by the system, not by
// users.
return;
}
saveActivity(wikiType, wikiOwner, pageId, page, PageUpdateType.ADD_PAGE);
}
@Override
public void postDeletePage(String wikiType, String wikiOwner, String pageId, Page page) throws WikiException {
if (page.getActivityId() != null && StringUtils.isNotEmpty(page.getActivityId())) {
activityManager.deleteActivity(page.getActivityId());
}
}
@Override
public void postUpdatePage(String wikiType,
String wikiOwner,
String pageId,
Page page,
PageUpdateType wikiUpdateType) throws WikiException {
// Generate an activity only in the following cases
if (page != null && wikiUpdateType != null
&& (wikiUpdateType.equals(PageUpdateType.ADD_PAGE) || wikiUpdateType.equals(PageUpdateType.EDIT_PAGE_CONTENT)
|| wikiUpdateType.equals(PageUpdateType.EDIT_PAGE_TITLE)
|| wikiUpdateType.equals(PageUpdateType.EDIT_PAGE_CONTENT_AND_TITLE)
|| wikiUpdateType.equals(PageUpdateType.MOVE_PAGE))) {
saveActivity(wikiType, wikiOwner, pageId, page, wikiUpdateType);
}
}
}