Added support for messages reply via email
git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portal/social-mail-servlet@119771 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
3ff1494620
commit
9b28893195
|
@ -1,4 +1,8 @@
|
||||||
<ReleaseNotes>
|
<ReleaseNotes>
|
||||||
|
<Changeset component="org.gcube.portal.social-mail-servlet.1-2-0"
|
||||||
|
date="2015-10-14">
|
||||||
|
<Change>Added support for teply via email in Messages</Change>
|
||||||
|
</Changeset>
|
||||||
<Changeset component="org.gcube.portal.social-mail-servlet.1-1-0"
|
<Changeset component="org.gcube.portal.social-mail-servlet.1-1-0"
|
||||||
date="2015-09-22">
|
date="2015-09-22">
|
||||||
<Change>Fix for #577</Change>
|
<Change>Fix for #577</Change>
|
||||||
|
|
18
pom.xml
18
pom.xml
|
@ -11,8 +11,8 @@
|
||||||
<groupId>org.gcube.portal</groupId>
|
<groupId>org.gcube.portal</groupId>
|
||||||
<artifactId>social-mail-servlet</artifactId>
|
<artifactId>social-mail-servlet</artifactId>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
<version>1.1.0-SNAPSHOT</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
|
|
||||||
<name>social-mail-servlet Webapp</name>
|
<name>social-mail-servlet Webapp</name>
|
||||||
<description>This component read periodically email replies from user wanting to reply to a post via email and exports users in LDAP</description>
|
<description>This component read periodically email replies from user wanting to reply to a post via email and exports users in LDAP</description>
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -66,10 +66,20 @@
|
||||||
<artifactId>social-networking-library</artifactId>
|
<artifactId>social-networking-library</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.portal</groupId>
|
<groupId>org.gcube.portal</groupId>
|
||||||
<artifactId>notifications-common-library</artifactId>
|
<artifactId>notifications-common-library</artifactId>
|
||||||
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.common</groupId>
|
||||||
|
<artifactId>home-library</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.common</groupId>
|
||||||
|
<artifactId>home-library-jcr</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google</groupId>
|
<groupId>com.google</groupId>
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.gcube.portal.socialmail;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -24,7 +25,16 @@ import org.gcube.application.framework.core.session.SessionManager;
|
||||||
import org.gcube.application.framework.core.util.GenderType;
|
import org.gcube.application.framework.core.util.GenderType;
|
||||||
import org.gcube.applicationsupportlayer.social.ApplicationNotificationsManager;
|
import org.gcube.applicationsupportlayer.social.ApplicationNotificationsManager;
|
||||||
import org.gcube.applicationsupportlayer.social.NotificationsManager;
|
import org.gcube.applicationsupportlayer.social.NotificationsManager;
|
||||||
|
import org.gcube.applicationsupportlayer.social.mailing.AppType;
|
||||||
import org.gcube.applicationsupportlayer.social.mailing.EmailPlugin;
|
import org.gcube.applicationsupportlayer.social.mailing.EmailPlugin;
|
||||||
|
import org.gcube.common.homelibrary.home.HomeLibrary;
|
||||||
|
import org.gcube.common.homelibrary.home.exceptions.HomeNotFoundException;
|
||||||
|
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
|
||||||
|
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||||
|
import org.gcube.common.homelibrary.home.workspace.exceptions.ItemNotFoundException;
|
||||||
|
import org.gcube.common.homelibrary.home.workspace.exceptions.WorkspaceFolderNotFoundException;
|
||||||
|
import org.gcube.common.homelibrary.home.workspace.sharing.WorkspaceMessage;
|
||||||
|
import org.gcube.common.homelibrary.home.workspace.sharing.WorkspaceMessageManager;
|
||||||
import org.gcube.common.portal.PortalContext;
|
import org.gcube.common.portal.PortalContext;
|
||||||
import org.gcube.portal.custom.communitymanager.OrganizationsUtil;
|
import org.gcube.portal.custom.communitymanager.OrganizationsUtil;
|
||||||
import org.gcube.portal.databook.server.DatabookStore;
|
import org.gcube.portal.databook.server.DatabookStore;
|
||||||
|
@ -35,8 +45,10 @@ import org.gcube.portal.databook.shared.ex.ColumnNameNotFoundException;
|
||||||
import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException;
|
import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException;
|
||||||
import org.gcube.portal.databook.shared.ex.FeedTypeNotFoundException;
|
import org.gcube.portal.databook.shared.ex.FeedTypeNotFoundException;
|
||||||
import org.gcube.portal.databook.shared.ex.PrivacyLevelTypeNotFoundException;
|
import org.gcube.portal.databook.shared.ex.PrivacyLevelTypeNotFoundException;
|
||||||
|
import org.gcube.portal.notifications.bean.GenericItemBean;
|
||||||
import org.gcube.portal.notifications.thread.CommentNotificationsThread;
|
import org.gcube.portal.notifications.thread.CommentNotificationsThread;
|
||||||
import org.gcube.portal.notifications.thread.LikeNotificationsThread;
|
import org.gcube.portal.notifications.thread.LikeNotificationsThread;
|
||||||
|
import org.gcube.portal.notifications.thread.MessageNotificationsThread;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -154,38 +166,26 @@ public class PeriodicTask implements Runnable {
|
||||||
String subject = message.getSubject();
|
String subject = message.getSubject();
|
||||||
_log.info("Parsing email of " + message.getFrom()[0] + " with subject: " + subject);
|
_log.info("Parsing email of " + message.getFrom()[0] + " with subject: " + subject);
|
||||||
if (isValidReply(message)) {
|
if (isValidReply(message)) {
|
||||||
String feedId = extractFeedId(message);
|
String subAddressField = extractSubaddress(message);
|
||||||
String commentText = extractText(portalName, feedId, message);
|
|
||||||
_log.info("Extracted id: " + feedId + " text=" + commentText);
|
|
||||||
String escapedCommentText = Utils.escapeHtmlAndTransformUrl(commentText);
|
|
||||||
|
|
||||||
Address[] froms = message.getFrom();
|
Address[] froms = message.getFrom();
|
||||||
String emailAddress = froms == null ? null : ((InternetAddress) froms[0]).getAddress();
|
String emailAddress = froms == null ? null : ((InternetAddress) froms[0]).getAddress();
|
||||||
|
|
||||||
ASLSession fakeSession = getFakeASLSession(emailAddress);
|
ASLSession fakeSession = getFakeASLSession(emailAddress);
|
||||||
if (fakeSession != null) {
|
|
||||||
if (escapedCommentText.trim().compareTo("") == 0) {//it is a favorite/subscription
|
|
||||||
_log.debug("Found favorite/subscription for feed with subject: " + subject);
|
|
||||||
favoriteFeed(feedId, fakeSession);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Comment comment = new Comment(UUID.randomUUID().toString(), fakeSession.getUsername(),
|
|
||||||
new Date(), feedId, escapedCommentText, fakeSession.getUserFullName(), fakeSession.getUserAvatarId());
|
|
||||||
|
|
||||||
_log.debug("The EscapedCommentText =>" + escapedCommentText);
|
if (fakeSession != null) {
|
||||||
boolean commentCommitResult = false;
|
if (subAddressField.endsWith(AppType.POST.toString()) || subAddressField.endsWith(AppType.POST.toString().toLowerCase())) { //it is a post, a comment on a post or a mention
|
||||||
try {
|
_log.debug("Looks like a post, a comment on a post or a mention to me");
|
||||||
if (socialStore.addComment(comment))
|
String feedId = extractIdentifier(subAddressField);
|
||||||
commentCommitResult = true;
|
handlePostReply(portalName, feedId, message, fakeSession);
|
||||||
} catch (FeedIDNotFoundException e) {
|
}
|
||||||
_log.error("Related post not found for this comment " + e.getMessage());
|
else if (subAddressField.endsWith(AppType.MSG.toString()) || subAddressField.endsWith(AppType.MSG.toString().toLowerCase())) { //it is a message
|
||||||
e.printStackTrace();
|
_log.debug("Looks like a message reply to me");
|
||||||
}
|
String messageId = extractIdentifier(subAddressField);
|
||||||
if (commentCommitResult) { //the notifications should start
|
handleMessageReply(portalName, messageId, message, fakeSession);
|
||||||
notifyUsersInvolved(comment, escapedCommentText, feedId, fakeSession);
|
} else {
|
||||||
}
|
_log.warn("cannot identify the type of this email reply from " + message.getFrom()[0] + " with subject: " + subject);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
_log.warn("User Not Recognized, going to discard Message from emailAddress = " + emailAddress);
|
_log.warn("User Not Recognized, going to discard Message from emailAddress = " + emailAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,6 +209,125 @@ public class PeriodicTask implements Runnable {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this method manages the replies coming from message notifications
|
||||||
|
* @param portalName
|
||||||
|
* @param messageId the message identifier in the System managing the messages (currently in the Home Library)
|
||||||
|
* @param message the javax mail Message instance
|
||||||
|
* @param fakeSession
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private void handleMessageReply(String portalName, String messageId, Message message, ASLSession fakeSession) {
|
||||||
|
String subject = "";
|
||||||
|
String messageText = "";
|
||||||
|
String escapedMessageText = "";
|
||||||
|
try {
|
||||||
|
subject = message.getSubject();
|
||||||
|
messageText = extractText(portalName, messageId, message);
|
||||||
|
escapedMessageText = Utils.escapeHtmlAndTransformUrl(messageText);
|
||||||
|
} catch (Exception e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.debug("Found message reply, subject: " + subject, " body: " + messageText);
|
||||||
|
String newMessageId = null;
|
||||||
|
Workspace workspace;
|
||||||
|
List<String> recipientIds = null;
|
||||||
|
try {
|
||||||
|
workspace = getWorkspace(fakeSession);
|
||||||
|
|
||||||
|
WorkspaceMessageManager messageManager = workspace.getWorkspaceMessageManager();
|
||||||
|
WorkspaceMessage theMessage = messageManager.getReceivedMessage(messageId);
|
||||||
|
recipientIds = theMessage.getAddresses();
|
||||||
|
//add the sender and remove the person who is replying from the recipients
|
||||||
|
String sender = theMessage.getSender().getPortalLogin();
|
||||||
|
recipientIds.add(sender);
|
||||||
|
recipientIds.remove(fakeSession.getUsername());
|
||||||
|
|
||||||
|
_log.debug("Message Recipients:");
|
||||||
|
for (String rec : recipientIds) {
|
||||||
|
_log.debug(rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.debug("Trying to send message with subject: " + subject, " to: " + recipientIds.toString());
|
||||||
|
newMessageId = messageManager.sendMessageToPortalLogins(subject, messageText, new ArrayList<String>(), recipientIds);
|
||||||
|
|
||||||
|
} catch (WorkspaceFolderNotFoundException | InternalErrorException | HomeNotFoundException | ItemNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.debug("Message with subject: " + subject, " hase been sent, returned id: " + newMessageId);
|
||||||
|
|
||||||
|
if (newMessageId != null) {
|
||||||
|
_log.debug("Sending message notifications ... ");
|
||||||
|
List<GenericItemBean> recipients = getUsersbyUserId(recipientIds);
|
||||||
|
NotificationsManager nm = new ApplicationNotificationsManager(fakeSession);
|
||||||
|
Thread thread = new Thread(new MessageNotificationsThread(recipients, messageId, subject, escapedMessageText, nm));
|
||||||
|
thread.start();
|
||||||
|
} else {
|
||||||
|
_log.debug("Could not send message reply");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* return the User instance given his id
|
||||||
|
* @param recipientIds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<GenericItemBean> getUsersbyUserId(List<String> recipientIds) {
|
||||||
|
List<GenericItemBean> recipients = new ArrayList<GenericItemBean>();
|
||||||
|
for (String userid : recipientIds) {
|
||||||
|
com.liferay.portal.model.User user;
|
||||||
|
try {
|
||||||
|
user = UserLocalServiceUtil.getUserByScreenName(OrganizationsUtil.getCompany().getCompanyId(), userid);
|
||||||
|
recipients.add(new GenericItemBean(""+user.getUserId(), user.getScreenName(), user.getFullName(), ""));
|
||||||
|
} catch (PortalException | SystemException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recipients;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this method manages the replies coming from post notifications
|
||||||
|
* @param portalName
|
||||||
|
* @param feedId the identifier in the System managing the feeds
|
||||||
|
* @param message the javax mail Message instance
|
||||||
|
* @param fakeSession
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private void handlePostReply(String portalName, String feedId, Message message, ASLSession fakeSession) throws Exception {
|
||||||
|
String commentText = extractText(portalName, feedId, message);
|
||||||
|
_log.info("Extracted id: " + feedId + " text=" + commentText);
|
||||||
|
String escapedCommentText = Utils.escapeHtmlAndTransformUrl(commentText);
|
||||||
|
String subject = message.getSubject();
|
||||||
|
|
||||||
|
if (escapedCommentText.trim().compareTo("") == 0) {//it is a favorite/subscription
|
||||||
|
_log.debug("Found favorite/subscription for feed with subject: " + subject);
|
||||||
|
favoriteFeed(feedId, fakeSession);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Comment comment = new Comment(UUID.randomUUID().toString(), fakeSession.getUsername(),
|
||||||
|
new Date(), feedId, escapedCommentText, fakeSession.getUserFullName(), fakeSession.getUserAvatarId());
|
||||||
|
|
||||||
|
_log.debug("The EscapedCommentText =>" + escapedCommentText);
|
||||||
|
boolean commentCommitResult = false;
|
||||||
|
try {
|
||||||
|
if (socialStore.addComment(comment))
|
||||||
|
commentCommitResult = true;
|
||||||
|
} catch (FeedIDNotFoundException e) {
|
||||||
|
_log.error("Related post not found for this comment " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (commentCommitResult) { //the notifications should start
|
||||||
|
notifyUsersInvolved(comment, escapedCommentText, feedId, fakeSession);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* favorite the feed to subscribe to further comments
|
* favorite the feed to subscribe to further comments
|
||||||
* @param feedId
|
* @param feedId
|
||||||
|
@ -291,12 +410,12 @@ public class PeriodicTask implements Runnable {
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
* extracts the sub-address (the part after the + and before the @) from the email addressee
|
||||||
* @param message
|
* @param message
|
||||||
* @return
|
* @return the sub-address without + and @
|
||||||
* @throws MessagingException
|
* @throws MessagingException
|
||||||
*/
|
*/
|
||||||
private static String extractFeedId(Message message) throws MessagingException {
|
private static String extractSubaddress(Message message) throws MessagingException {
|
||||||
Address[] emails = message.getRecipients(RecipientType.TO);
|
Address[] emails = message.getRecipients(RecipientType.TO);
|
||||||
String toParse = emails[0].toString();
|
String toParse = emails[0].toString();
|
||||||
int plus = toParse.indexOf('+');
|
int plus = toParse.indexOf('+');
|
||||||
|
@ -305,6 +424,20 @@ public class PeriodicTask implements Runnable {
|
||||||
return null;
|
return null;
|
||||||
return toParse.substring(plus+1, at);
|
return toParse.substring(plus+1, at);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* extracts the identifier (the part before the $) from the Subaddress
|
||||||
|
* @param message
|
||||||
|
* @return the identifier
|
||||||
|
* @throws MessagingException
|
||||||
|
*/
|
||||||
|
private static String extractIdentifier(String subAddress) {
|
||||||
|
String id = subAddress; //for backward compatibility
|
||||||
|
int at = subAddress.indexOf('$');
|
||||||
|
if (at > -1)
|
||||||
|
id = subAddress.substring(0, at);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the email is considered a valid reply if and only of it contains the EmailPlugin.WRITE_ABOVE_TO_REPLY text in the body
|
* the email is considered a valid reply if and only of it contains the EmailPlugin.WRITE_ABOVE_TO_REPLY text in the body
|
||||||
* @param message the message to check
|
* @param message the message to check
|
||||||
|
@ -330,12 +463,16 @@ public class PeriodicTask implements Runnable {
|
||||||
}
|
}
|
||||||
String[] lines = toParse.split(System.getProperty("line.separator"));
|
String[] lines = toParse.split(System.getProperty("line.separator"));
|
||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
if (lines[i].contains(SEPARATOR))
|
if (lines[i].contains(SEPARATOR)) {
|
||||||
|
_log.debug("Yes, it is a valid Reply");
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_log.debug("NOT a valid Reply");
|
||||||
return false;
|
return false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
_log.error("Exceptiom returning NOT a valid Reply");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,9 +497,11 @@ public class PeriodicTask implements Runnable {
|
||||||
toParse = part.getContent().toString();
|
toParse = part.getContent().toString();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_log.debug("Found g text/plain Message, getting text");
|
_log.debug("Found text/plain Message, getting text");
|
||||||
toParse = messageContent.toString();
|
toParse = messageContent.toString();
|
||||||
}
|
}
|
||||||
|
_log.debug("Got Message content = " + toParse);
|
||||||
|
|
||||||
//cut the text below the WRITE_ABOVE_TO_REPLY text
|
//cut the text below the WRITE_ABOVE_TO_REPLY text
|
||||||
String[] lines = toParse.split(System.getProperty("line.separator"));
|
String[] lines = toParse.split(System.getProperty("line.separator"));
|
||||||
int until = -1;
|
int until = -1;
|
||||||
|
@ -385,6 +524,22 @@ public class PeriodicTask implements Runnable {
|
||||||
if (! (i == until -1) )
|
if (! (i == until -1) )
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
return sb.toString().trim();
|
|
||||||
|
String toReturn = sb.toString().trim();
|
||||||
|
_log.debug("Returning text extracted = " + toReturn);
|
||||||
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the workspace instance
|
||||||
|
* @throws InternalErrorException
|
||||||
|
* @throws HomeNotFoundException
|
||||||
|
* @throws WorkspaceFolderNotFoundException
|
||||||
|
*/
|
||||||
|
private Workspace getWorkspace(ASLSession session) throws InternalErrorException, HomeNotFoundException, WorkspaceFolderNotFoundException {
|
||||||
|
Workspace workspace = HomeLibrary.getUserWorkspace(session.getUsername());
|
||||||
|
return workspace;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue