/*
* Copyright (C) 2003-2007 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.services.cms.watch.impl;
import groovy.text.GStringTemplateEngine;
import groovy.text.TemplateEngine;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.portlet.PortletRequest;
import org.exoplatform.portal.application.PortalRequestContext;
import org.exoplatform.portal.mop.SiteType;
import org.exoplatform.portal.mop.user.UserNavigation;
import org.exoplatform.portal.mop.user.UserNode;
import org.exoplatform.portal.mop.user.UserPortal;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.cms.drives.DriveData;
import org.exoplatform.services.cms.drives.ManageDriveService;
import org.exoplatform.services.cms.watch.WatchDocumentService;
import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.mail.MailService;
import org.exoplatform.services.mail.Message;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.Query;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.services.security.Identity;
import org.exoplatform.services.security.IdentityRegistry;
import org.exoplatform.services.security.MembershipEntry;
import org.exoplatform.services.wcm.core.NodeLocation;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.exoplatform.web.url.navigation.NodeURL;
import org.exoplatform.webui.application.WebuiRequestContext;
import org.exoplatform.webui.application.portlet.PortletRequestContext;
/**
* Created by The eXo Platform SAS
* Author : Xuan Hoa Pham
* hoapham@exoplatform.com
* phamvuxuanhoa@gmail.com
* Dec 6, 2006
*/
public class EmailNotifyListener implements EventListener {
private NodeLocation observedNode_ ;
final public static String EMAIL_WATCHERS_PROP = "exo:emailWatcher";
private static final String SITE_EXPLORER = "siteExplorer";
private static final String PATH_PARAM = "path";
private static final String USER_ID = "${userId}";
private static final Log LOG = ExoLogger.getLogger(EmailNotifyListener.class.getName());
public EmailNotifyListener(Node oNode) {
observedNode_ = NodeLocation.getNodeLocationByNode(oNode);
}
/**
* This method is used for listening to all changes of property of a node, when there is a change,
* message is sent to list of email
*/
public void onEvent(EventIterator arg0) {
MailService mailService = WCMCoreUtils.getService(MailService.class);
WatchDocumentServiceImpl watchService = (WatchDocumentServiceImpl)WCMCoreUtils.getService(WatchDocumentService.class);
MessageConfig messageConfig = watchService.getMessageConfig();
List<String> emailList = getEmailList(NodeLocation.getNodeByLocation(observedNode_));
for (String receiver : emailList) {
try {
Message message = createMessage(receiver, messageConfig);
mailService.sendMessage(message);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("Unexpected error", e);
}
}
}
}
/**
* Create message when there is any changes of property of a node.
* @param receiver
* @param messageConfig
* @return
* @throws Exception
*/
private Message createMessage(String receiver, MessageConfig messageConfig) throws Exception {
Message message = new Message();
message.setFrom(messageConfig.getSender());
message.setTo(receiver);
message.setSubject(messageConfig.getSubject());
TemplateEngine engine = new GStringTemplateEngine();
Map<String, String> binding = new HashMap<String, String>();
Query query = new Query();
query.setEmail(receiver);
binding.put("user_name", WCMCoreUtils.getService(OrganizationService.class)
.getUserHandler()
.findUsersByQuery(query)
.load(0, 1)[0].getFullName());
Node node = NodeLocation.getNodeByLocation(observedNode_);
binding.put("doc_title", org.exoplatform.services.cms.impl.Utils.getTitle(node));
binding.put("doc_name", node.getName());
binding.put("doc_url", getViewableLink());
message.setBody(engine.createTemplate(messageConfig.getContent()).make(binding).toString());
message.setMimeType(messageConfig.getMimeType());
return message;
}
/**
*
* @return
* @throws Exception
*/
private String getViewableLink() throws Exception {
PortalRequestContext pContext = Util.getPortalRequestContext();
NodeURL nodeURL = pContext.createURL(NodeURL.TYPE);
String nodePath = NodeLocation.getNodeByLocation(observedNode_).getPath();
ManageDriveService manageDriveService = WCMCoreUtils.getService(ManageDriveService.class);
List<DriveData> driveList = manageDriveService.getDriveByUserRoles(pContext.getRemoteUser(),
getMemberships());
DriveData drive = getDrive(driveList,
WCMCoreUtils.getRepository()
.getConfiguration()
.getDefaultWorkspaceName(),
nodePath);
String driverName = drive.getName();
String nodePathInDrive = "/".equals(drive.getHomePath()) ? nodePath
: nodePath.substring(drive.getHomePath()
.length());
UserNode siteExNode = getUserNodeByURI(SITE_EXPLORER);
nodeURL.setNode(siteExNode);
nodeURL.setQueryParameterValue(PATH_PARAM, "/" + driverName + nodePathInDrive);
PortletRequestContext portletRequestContext = WebuiRequestContext.getCurrentInstance();
PortletRequest portletRequest = portletRequestContext.getRequest();
String baseURI = portletRequest.getScheme() + "://" + portletRequest.getServerName() + ":"
+ String.format("%s", portletRequest.getServerPort());
return baseURI + nodeURL.toString();
}
/**
*
* @param lstDrive
* @param workspace
* @param nodePath
* @return
* @throws RepositoryException
*/
private DriveData getDrive(List<DriveData> lstDrive, String workspace, String nodePath) throws RepositoryException {
NodeHierarchyCreator nhc = WCMCoreUtils.getService(NodeHierarchyCreator.class);
String userName = ConversationState.getCurrent().getIdentity().getUserId();
int idx;
String userNodePath = null;
try {
userNodePath = nhc.getUserNode(WCMCoreUtils.getSystemSessionProvider(), userName).getPath();
}catch (Exception e) {
//Exception while finding the user home node
userNodePath = null;
}
DriveData driveData = null;
for (DriveData drive : lstDrive) {
String driveHomePath = drive.getHomePath();
idx = driveHomePath.indexOf(USER_ID) ;
if (idx >=0 && userNodePath!=null) {
driveHomePath = userNodePath + driveHomePath.substring(idx + USER_ID.length());
}
if (workspace.equals(drive.getWorkspace()) && nodePath.startsWith(driveHomePath)) {
driveData = drive;
break;
}
}
return driveData;
}
/**
*
* @param uri
* @return
*/
private UserNode getUserNodeByURI(String uri) {
UserPortal userPortal = Util.getPortalRequestContext().getUserPortalConfig().getUserPortal();
List<UserNavigation> allNavs = userPortal.getNavigations();
for (UserNavigation nav : allNavs) {
if (nav.getKey().getType().equals(SiteType.GROUP)) {
UserNode userNode = userPortal.resolvePath(nav, null, uri);
if (userNode != null) {
return userNode;
}
}
}
return null;
}
/**
*
* @return
*/
public List<String> getMemberships() {
String userId = Util.getPortalRequestContext().getRemoteUser();
List<String> userMemberships = new ArrayList<String>();
userMemberships.add(userId);
// here we must retrieve memberships of the user using the
// IdentityRegistry Service instead of Organization Service to
// allow JAAS based authorization
Collection<MembershipEntry> memberships = getUserMembershipsFromIdentityRegistry(userId);
if (memberships != null) {
for (MembershipEntry membership : memberships) {
String role = membership.getMembershipType() + ":" + membership.getGroup();
userMemberships.add(role);
}
}
return userMemberships;
}
/**
*
* @param authenticatedUser
* @return
*/
private Collection<MembershipEntry> getUserMembershipsFromIdentityRegistry(String authenticatedUser) {
IdentityRegistry identityRegistry = WCMCoreUtils.getService(IdentityRegistry.class);
Identity currentUserIdentity = identityRegistry.getIdentity(authenticatedUser);
return currentUserIdentity.getMemberships();
}
/**
* This Method will get email of watchers when they watch a document
* @param observedNode
* @return
*/
private List<String> getEmailList(Node observedNode) {
List<String> emailList = new ArrayList<String>() ;
OrganizationService orgService = WCMCoreUtils.getService(OrganizationService.class);
try{
if(observedNode.hasProperty(EMAIL_WATCHERS_PROP)) {
Value[] watcherNames = observedNode.getProperty(EMAIL_WATCHERS_PROP).getValues() ;
for(Value value: watcherNames) {
String userName = value.getString() ;
User user = orgService.getUserHandler().findUserByName(userName) ;
if(user != null) {
emailList.add(user.getEmail()) ;
}
}
}
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("Unexpected error", e);
}
}
return emailList ;
}
}