diff --git a/.classpath b/.classpath index 1151b0d..91f2707 100644 --- a/.classpath +++ b/.classpath @@ -25,7 +25,7 @@ - + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index db32697..839d647 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -1,3 +1,5 @@ eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 encoding/=UTF-8 diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 7bedda1..bf18a98 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -4,7 +4,9 @@ - + + uses + diff --git a/pom.xml b/pom.xml index 756fde0..058631f 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,11 @@ org.gcube.portal social-networking-library provided + + + org.gcube.portal + notifications-common-library + [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) com.google diff --git a/src/main/java/org/gcube/portal/socialmail/MailReader.java b/src/main/java/org/gcube/portal/socialmail/MailReader.java index 6d27a5f..880ebc8 100644 --- a/src/main/java/org/gcube/portal/socialmail/MailReader.java +++ b/src/main/java/org/gcube/portal/socialmail/MailReader.java @@ -90,13 +90,4 @@ public class MailReader extends HttpServlet { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {} - - public static void main(String[] args) { - new MailReader().init(); - System.out.println("Scheduling periodic task ... "); - //System.out.println(host + user + password); - scheduler.scheduleAtFixedRate(new PeriodicTask(store, portalName, host, user, password), 0, MINUTES_DELAY, TimeUnit.MINUTES); - } - - } \ No newline at end of file diff --git a/src/main/java/org/gcube/portal/socialmail/PeriodicTask.java b/src/main/java/org/gcube/portal/socialmail/PeriodicTask.java index b044a22..1963b83 100644 --- a/src/main/java/org/gcube/portal/socialmail/PeriodicTask.java +++ b/src/main/java/org/gcube/portal/socialmail/PeriodicTask.java @@ -1,6 +1,7 @@ package org.gcube.portal.socialmail; import java.security.GeneralSecurityException; +import java.util.ArrayList; import java.util.Date; import java.util.Properties; import java.util.UUID; @@ -21,12 +22,21 @@ import javax.mail.internet.MimeMessage.RecipientType; import org.gcube.application.framework.core.session.ASLSession; import org.gcube.application.framework.core.session.SessionManager; import org.gcube.application.framework.core.util.GenderType; +import org.gcube.applicationsupportlayer.social.ApplicationNotificationsManager; +import org.gcube.applicationsupportlayer.social.NotificationsManager; import org.gcube.applicationsupportlayer.social.mailing.EmailPlugin; import org.gcube.common.portal.PortalContext; import org.gcube.portal.custom.communitymanager.OrganizationsUtil; import org.gcube.portal.databook.server.DatabookStore; import org.gcube.portal.databook.shared.Comment; +import org.gcube.portal.databook.shared.Feed; +import org.gcube.portal.databook.shared.Like; +import org.gcube.portal.databook.shared.ex.ColumnNameNotFoundException; import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException; +import org.gcube.portal.databook.shared.ex.FeedTypeNotFoundException; +import org.gcube.portal.databook.shared.ex.PrivacyLevelTypeNotFoundException; +import org.gcube.portal.notifications.thread.CommentNotificationsThread; +import org.gcube.portal.notifications.thread.LikeNotificationsThread; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +53,7 @@ import com.sun.mail.util.MailSSLSocketFactory; */ public class PeriodicTask implements Runnable { private static final Logger _log = LoggerFactory.getLogger(PeriodicTask.class); - + private DatabookStore socialStore; private String host; private String mailserver_username; @@ -81,7 +91,7 @@ public class PeriodicTask implements Runnable { User user = UserLocalServiceUtil.getUserByEmailAddress(companyId, emailAddress); username = user.getScreenName(); SessionManager.getInstance().getASLSession(sessionID, username).setScope(scope); - + //add the social information needed by apps String fullName = user.getFirstName() + " " + user.getLastName(); String email = user.getEmailAddress(); @@ -92,11 +102,13 @@ public class PeriodicTask implements Runnable { SessionManager.getInstance().getASLSession(sessionID, username).setUserEmailAddress(email); SessionManager.getInstance().getASLSession(sessionID, username).setUserAvatarId(thumbnailURL); SessionManager.getInstance().getASLSession(sessionID, username).setUserGender(isMale? GenderType.MALE : GenderType.FEMALE); - + + _log.debug("Created fakesession for user " + username + " email="+emailAddress); + } catch (PortalException | SystemException e) { e.printStackTrace(); } - + return SessionManager.getInstance().getASLSession(sessionID, username); } @@ -120,7 +132,7 @@ public class PeriodicTask implements Runnable { Session emailSession = Session.getDefaultInstance(pop3Props); - //emailSession.setDebug(true); + emailSession.setDebug(false); //create the POP3 socialStore object and connect with the pop server Store store = emailSession.getStore("pop3s"); @@ -143,19 +155,19 @@ public class PeriodicTask implements Runnable { String feedId = extractFeedId(message); String commentText = extractText(portalName, feedId, message); - + String escapedCommentText = Utils.escapeHtmlAndTransformUrl(commentText); - + Address[] froms = message.getFrom(); String emailAddress = froms == null ? null : ((InternetAddress) froms[0]).getAddress(); - + ASLSession fakeSession = getFakeASLSession(emailAddress); - + Comment comment = new Comment(UUID.randomUUID().toString(), fakeSession.getUsername(), new Date(), feedId, escapedCommentText, fakeSession.getUserFullName(), fakeSession.getUserAvatarId()); - - _log.debug("Parsed and escapedCommentText =>" + escapedCommentText); + + _log.debug("The EscapedCommentText =>" + escapedCommentText); boolean commentCommitResult = false; try { if (socialStore.addComment(comment)) @@ -164,11 +176,11 @@ public class PeriodicTask implements Runnable { _log.error("Related post not found for this comment " + e.getMessage()); e.printStackTrace(); } - if (commentCommitResult) { //the notify - _log.info("Now the NOTIFICATION SHOULD START!!!!!"); + if (commentCommitResult) { //the notifications should start + notifyUsersInvolved(comment, escapedCommentText, feedId, fakeSession); } - + //delete this message message.setFlag(Flags.Flag.DELETED, true); System.out.println("Marked DELETE for message: " + subject); } @@ -185,7 +197,53 @@ public class PeriodicTask implements Runnable { e.printStackTrace(); } } + /** + * this method take care of notify all the users that need to be notified when someone comment + * @param comment + * @param feedId + * @param fakeSession + * @throws PrivacyLevelTypeNotFoundException + * @throws FeedTypeNotFoundException + * @throws FeedIDNotFoundException + * @throws ColumnNameNotFoundException + */ + private void notifyUsersInvolved(Comment comment, String commentText, String feedId, ASLSession fakeSession) throws PrivacyLevelTypeNotFoundException, FeedTypeNotFoundException, FeedIDNotFoundException, ColumnNameNotFoundException { + Feed feed = socialStore.readFeed(feedId); + String feedOwnerId = feed.getEntityId(); + boolean isAppFeed = feed.isApplicationFeed(); + //if the user who commented this post is not the user who posted it notifies the poster user (Feed owner) + NotificationsManager nm = new ApplicationNotificationsManager(fakeSession); + if (! fakeSession.getUsername().equals(feedOwnerId) && (!isAppFeed)) { + boolean result = nm.notifyOwnCommentReply(feedOwnerId, feedId, commentText); + _log.trace("Comment Notification to post owner added? " + result); + } + + //if there are users who liked this post they get notified, asynchronously with this thread + ArrayList favorites = getAllLikesByFeed(feedId); + Thread likesThread = new Thread(new LikeNotificationsThread(commentText, nm, favorites, feedOwnerId)); + likesThread.start(); + + //notify the other users who commented this post (excluding the ones above) + Thread commentsNotificationthread = new Thread(new CommentNotificationsThread(socialStore, fakeSession.getUsername(), comment.getFeedid(), commentText, nm, feedOwnerId, favorites)); + commentsNotificationthread.start(); + } + /** + * + * @param feedid + * @return + */ + public ArrayList getAllLikesByFeed(String feedid) { + _log.trace("Asking likes for " + feedid); + ArrayList toReturn = (ArrayList) socialStore.getAllLikesByFeed(feedid); + return toReturn; + } + /** + * + * @param message + * @return + * @throws MessagingException + */ private String extractFeedId(Message message) throws MessagingException { Address[] emails = message.getRecipients(RecipientType.TO); String toParse = emails[0].toString(); @@ -195,9 +253,15 @@ public class PeriodicTask implements Runnable { return null; return toParse.substring(plus+1, at); } - + /** + * + * @param portalName + * @param subjectId + * @param message + * @return + * @throws Exception + */ private String extractText(String portalName, String subjectId, Message message) throws Exception { - Address[] emails = message.getRecipients(RecipientType.TO); Object messageContent = message.getContent(); String toParse = null; // Check if content is pure text/html or in parts @@ -212,7 +276,7 @@ public class PeriodicTask implements Runnable { _log.debug("Found g text/plain Message, getting text"); toParse = messageContent.toString(); } - + //cut the text below the WRITE_ABOVE_TO_REPLY text String[] lines = toParse.split(System.getProperty("line.separator")); int until = -1; for (int i = 0; i < lines.length; i++) { @@ -221,13 +285,18 @@ public class PeriodicTask implements Runnable { break; } } - String toReturn = ""; + StringBuilder sb = new StringBuilder(); + /* + * this is needed to remove the text added by the email client like when you reply, e.g. On wrote ... + * it also handles the case where the user writes between that and the WRITE_ABOVE_TO_REPLY text + */ for (int i = 0; i < until; i++) { if (! ( lines[i].contains(portalName) || lines[i].contains(subjectId) || (lines[i].startsWith("> ") && lines[i].trim().length() < 2)) ) { - toReturn += lines[i]; + sb.append(lines[i]); } + if (! (i == until -1) ) + sb.append("\n"); } - return toReturn; - + return sb.toString().trim(); } } diff --git a/src/main/java/org/gcube/portal/socialmail/Utils.java b/src/main/java/org/gcube/portal/socialmail/Utils.java index 36dee71..35200b6 100644 --- a/src/main/java/org/gcube/portal/socialmail/Utils.java +++ b/src/main/java/org/gcube/portal/socialmail/Utils.java @@ -80,4 +80,18 @@ public class Utils { } return null; } + /** + * Escape an html string. Escaping data received from the client helps to + * prevent cross-site script vulnerabilities. + * + * @param html the html string to escape + * @return the escaped string + */ + protected static String escapeHtml(String html) { + if (html == null) { + return null; + } + return html.replaceAll("&", "&").replaceAll("<", "<") + .replaceAll(">", ">"); + } }