From 1e6587f31460f907b74f12a18b97e72dabdb715a Mon Sep 17 00:00:00 2001 From: Massimiliano Assante Date: Thu, 10 Apr 2014 15:45:50 +0000 Subject: [PATCH] user mentions in comments implemented and ready for testing, preserve new lines in comments implemented git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/user/news-feed@94731 82a268e6-3cf1-43bd-a215-b396298e98cf --- .../user/newsfeed/client/NewsService.java | 3 +- .../newsfeed/client/NewsServiceAsync.java | 5 +- .../client/event/AddCommentEvent.java | 16 +- .../newsfeed/client/panels/NewsFeedPanel.java | 6 +- .../client/templates/AddCommentTemplate.java | 34 ++-- .../templates/AddCommentTemplate.ui.xml | 9 +- .../client/templates/SingleComment.java | 7 + .../client/templates/SuperPosedTextArea.java | 90 ++++++---- .../client/templates/TweetTemplate.java | 6 +- .../server/MentionNotificationsThread.java | 39 ++++ .../user/newsfeed/server/NewsServiceImpl.java | 44 ++++- .../user/newsfeed/server/UsersUtil.java | 75 -------- .../portlets/user/newsfeed/server/Utils.java | 167 ++++++++++++++++++ src/main/webapp/NewsFeed.css | 4 +- 14 files changed, 353 insertions(+), 152 deletions(-) create mode 100644 src/main/java/org/gcube/portlets/user/newsfeed/server/MentionNotificationsThread.java delete mode 100644 src/main/java/org/gcube/portlets/user/newsfeed/server/UsersUtil.java create mode 100644 src/main/java/org/gcube/portlets/user/newsfeed/server/Utils.java diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsService.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsService.java index 68137a4..e49a5e9 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsService.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsService.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import org.gcube.portal.databook.shared.Comment; import org.gcube.portal.databook.shared.Like; -import org.gcube.portal.databook.shared.UserInfo; import org.gcube.portlets.user.newsfeed.shared.EnhancedFeed; import org.gcube.portlets.user.newsfeed.shared.MoreFeedsBean; import org.gcube.portlets.user.newsfeed.shared.UserSettings; @@ -36,7 +35,7 @@ public interface NewsService extends RemoteService { boolean deleteFeed(String feedid); - Comment comment(String feedid, String text, String feedOwnerId, boolean isAppFeed); + Comment comment(String feedid, String text, ArrayList mentionedUsers, String feedOwnerId, boolean isAppFeed); Comment editComment(Comment toEdit); diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsServiceAsync.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsServiceAsync.java index 2d2ef5d..20d82f7 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsServiceAsync.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/NewsServiceAsync.java @@ -32,8 +32,9 @@ public interface NewsServiceAsync { void getUserSettings(AsyncCallback callback); - void comment(String feedid, String text, String feedOwnerId, - boolean isAppFeed, AsyncCallback callback); + void comment(String feedid, String text, ArrayList mentionedUsers, + String feedOwnerId, boolean isAppFeed, + AsyncCallback callback); void getAllCommentsByFeed(String feedid, AsyncCallback> callback); diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/event/AddCommentEvent.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/event/AddCommentEvent.java index aac246c..555bc5d 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/event/AddCommentEvent.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/event/AddCommentEvent.java @@ -1,5 +1,7 @@ package org.gcube.portlets.user.newsfeed.client.event; +import java.util.ArrayList; + import org.gcube.portlets.user.newsfeed.client.templates.TweetTemplate; import com.google.gwt.event.shared.GwtEvent; @@ -11,16 +13,24 @@ public class AddCommentEvent extends GwtEvent { private TweetTemplate owner; private String text; + private ArrayList mentionedUsers; + + public AddCommentEvent(TweetTemplate owner, String text, ArrayList mentionedUsers) { + this.owner = owner; + this.text = text; + this.mentionedUsers = mentionedUsers; + } public TweetTemplate getOwner() { return owner; } + public String getText() { return text; } - public AddCommentEvent(TweetTemplate owner, String text) { - this.owner = owner; - this.text = text; + + public ArrayList getMentionedUsers() { + return mentionedUsers; } @Override diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java index 945c650..22c360c 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/panels/NewsFeedPanel.java @@ -169,7 +169,7 @@ public class NewsFeedPanel extends Composite { eventBus.addHandler(AddCommentEvent.TYPE, new AddCommentEventHandler() { @Override public void onAddComment(AddCommentEvent event) { - doAddComment(event.getOwner(), event.getText()); + doAddComment(event.getOwner(), event.getText(), event.getMentionedUsers()); } }); @@ -822,8 +822,8 @@ public class NewsFeedPanel extends Composite { } - private void doAddComment(final TweetTemplate owner, String text) { - newsService.comment(owner.getFeedKey(), text, owner.getMyFeedUserId(), owner.isAppFeed(), new AsyncCallback() { + private void doAddComment(final TweetTemplate owner, String text, ArrayList mentionedUsers) { + newsService.comment(owner.getFeedKey(), text, mentionedUsers, owner.getMyFeedUserId(), owner.isAppFeed(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { Window.alert("Could not deliver this comment: " + caught.getMessage()); diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.java index 3256dc5..4e8f339 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.java @@ -1,35 +1,25 @@ package org.gcube.portlets.user.newsfeed.client.templates; -import java.util.ArrayList; - import org.gcube.portal.databook.shared.Comment; import org.gcube.portal.databook.shared.UserInfo; -import org.gcube.portlets.user.newsfeed.client.NewsService; -import org.gcube.portlets.user.newsfeed.client.NewsServiceAsync; +import org.gcube.portlets.user.gcubewidgets.client.elements.Div; import org.gcube.portlets.user.newsfeed.client.event.AddCommentEvent; import org.gcube.portlets.user.newsfeed.client.event.EditCommentEvent; -import org.gcube.portlets.user.newsfeed.client.panels.NewsFeedPanel; -import org.gcube.portlets.widgets.pickuser.client.dialog.PickUsersDialog; -import org.gcube.portlets.widgets.pickuser.shared.PickingUser; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.KeyPressEvent; -import com.google.gwt.event.dom.client.KeyUpEvent; -import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiFactory; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; -import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Image; -import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.Widget; public class AddCommentTemplate extends Composite { @@ -40,13 +30,10 @@ public class AddCommentTemplate extends Composite { private static CommentTemplateUiBinder uiBinder = GWT.create(CommentTemplateUiBinder.class); - private final static String COMMENT_TEXT = "Add a comment ... use @ to mention someone"; - private final static String ERROR_UPDATE_TEXT = "Looks like empty to me!"; + public final static String COMMENT_TEXT = "Add a comment ... use @ to mention someone"; + public final static String ERROR_UPDATE_TEXT = "Looks like empty to me!"; public static final String avatar_default = GWT.getModuleBaseURL() + "../images/Avatar_default.png"; - private final static int TEXT_AREA_WIDTH = 450; - private final static int TEXT_AREA_HEIGHT = 40; - private TweetTemplate owner; private HandlerManager eventBus; private boolean isEditing = false; @@ -56,6 +43,7 @@ public class AddCommentTemplate extends Composite { @UiField HTMLPanel mainPanel; @UiField Image avatarImage; @UiField SuperPosedTextArea commentTextArea; + @UiField Div highlighterDIV; @UiField Button submitButton; @UiField Button cancelButton; @@ -72,8 +60,6 @@ public class AddCommentTemplate extends Composite { owner = caller; avatarImage.setPixelSize(30, 30); avatarImage.setUrl(myUserInfo.getAvatarId()); - //commentTextArea.setPixelSize(TEXT_AREA_WIDTH, TEXT_AREA_HEIGHT); - commentTextArea.setText(COMMENT_TEXT); } /** * called on edit comment @@ -89,13 +75,16 @@ public class AddCommentTemplate extends Composite { owner = caller; avatarImage.setPixelSize(30, 30); avatarImage.setUrl(caller.getMyUserInfo().getAvatarId()); - //commentTextArea.setPixelSize(TEXT_AREA_WIDTH, TEXT_AREA_HEIGHT); commentTextArea.setText(new HTML(toEdit.getText()).getText()); mainPanel.removeStyleName("comment-hidden"); mainPanel.setStyleName("single-comment"); commentTextArea.addStyleName("comment-dark-color"); } + /** Used by AddCommentTemplate to instantiate SuperPosedTextArea */ + @UiFactory SuperPosedTextArea build() { + return new SuperPosedTextArea(highlighterDIV); + } public void setFocus() { commentTextArea.setFocus(true); @@ -117,8 +106,9 @@ public class AddCommentTemplate extends Composite { toEdit.setText(escapeHtml(commentTextArea.getText())); eventBus.fireEvent(new EditCommentEvent(owner, toEdit)); } - else - eventBus.fireEvent(new AddCommentEvent(owner, escapeHtml(commentTextArea.getText()))); + else { //it is ok to add this comment + eventBus.fireEvent(new AddCommentEvent(owner, escapeHtml(commentTextArea.getText()), commentTextArea.getMentionedUsers())); + } this.getWidget().setVisible(false); owner.setCommentingDisabled(false); } diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.ui.xml b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.ui.xml index d70bf1f..b10bd39 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.ui.xml +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/AddCommentTemplate.ui.xml @@ -1,6 +1,7 @@ .important { @@ -19,16 +20,14 @@
-
-
+ + +
- - - diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SingleComment.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SingleComment.java index 1cdd388..8e1c4b4 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SingleComment.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SingleComment.java @@ -54,6 +54,11 @@ public class SingleComment extends Composite { avatarImage.setUrl(toShow.getThumbnailURL()); String commentToShow = toShow.getText(); + + //replace the < & and > + commentToShow = commentToShow.replaceAll("<","<").replaceAll(">",">"); + commentToShow = commentToShow.replaceAll("&","&"); + if (commentToShow.length() > MAX_SHOWTEXT_LENGTH) { commentToShow = commentToShow.substring(0, MAX_SHOWTEXT_LENGTH) + "..."; seeMore.setHTML(" See More "); @@ -114,4 +119,6 @@ public class SingleComment extends Composite { editImage.removeStyleName("uiEditButton"); } } + + } diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SuperPosedTextArea.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SuperPosedTextArea.java index 1bf0b6e..48e6afb 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SuperPosedTextArea.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/SuperPosedTextArea.java @@ -5,6 +5,7 @@ package org.gcube.portlets.user.newsfeed.client.templates; import java.util.ArrayList; +import org.gcube.portlets.user.gcubewidgets.client.elements.Div; import org.gcube.portlets.user.newsfeed.client.NewsService; import org.gcube.portlets.user.newsfeed.client.NewsServiceAsync; import org.gcube.portlets.user.newsfeed.client.panels.NewsFeedPanel; @@ -19,6 +20,7 @@ import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Random; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.TextArea; @@ -32,24 +34,29 @@ public class SuperPosedTextArea extends TextArea { private final NewsServiceAsync newsService = GWT.create(NewsService.class); private final HandlerManager eventBus = new HandlerManager(null); - private final static String COMMENT_TEXT = "Add a comment ... use @ to mention someone"; - private final static String ERROR_UPDATE_TEXT = "Looks like empty to me!"; - - PickUsersDialog pickUserDlg; + + private PickUsersDialog pickUserDlg; + private Div highlighterDIV; public final static int ARROW_UP = 38; public final static int ARROW_DOWN = 40; private ArrayList mentionedUsers = new ArrayList(); + + private String areaId; /** * */ - public SuperPosedTextArea() { + public SuperPosedTextArea(Div highlighterDIV) { sinkEvents(Event.ONPASTE); sinkEvents(Event.ONKEYUP); sinkEvents(Event.ONCONTEXTMENU); sinkEvents(Event.ONKEYDOWN); - + setText(AddCommentTemplate.COMMENT_TEXT); + this.highlighterDIV = highlighterDIV; + //needed to give unique identifiers to the Area (for the jQuery plugin) + areaId = "postTextArea"+Random.nextInt(); + newsService.getOrganizationUsers(NewsFeedPanel.getCurrentScope(), new AsyncCallback>() { @Override @@ -61,19 +68,23 @@ public class SuperPosedTextArea extends TextArea { public void onFailure(Throwable caught) { } }); - DOM.setElementAttribute(getElement(), "id", "postTextArea"); + DOM.setElementAttribute(getElement(), "id", areaId); bind(); Timer t = new Timer() { @Override public void run() { - myAutoSize(); + myAutoSize(areaId); + setCaretPositionToBegin(areaId); } }; - t.schedule(1000); + t.schedule(200); } - public static native void myAutoSize() /*-{ - function autoSizeArea() { - $wnd.jQuery('#postTextArea').autosize(); + /** + * This is the way to wrap jQuery plugins into GWT, wrap it in a function and call it. + */ + public static native void myAutoSize(String myAreaId) /*-{ + function autoSizeArea() { + $wnd.jQuery('#'+myAreaId).autosize(); } autoSizeArea(); }-*/; @@ -91,7 +102,7 @@ public class SuperPosedTextArea extends TextArea { super.onBrowserEvent(event); switch (event.getTypeInt()) { case Event.ONPASTE: { - if (getText().equals(COMMENT_TEXT) || getText().equals(ERROR_UPDATE_TEXT) ) { + if (getText().equals(AddCommentTemplate.COMMENT_TEXT) || getText().equals(AddCommentTemplate.ERROR_UPDATE_TEXT) ) { setText(""); addStyleName("dark-color"); removeStyleName("error"); @@ -100,7 +111,7 @@ public class SuperPosedTextArea extends TextArea { } case Event.ONKEYUP: { injectInDiv(getText()); - pickUserDlg.onKeyUp(event.getKeyCode(), this.getAbsoluteLeft(), this.getAbsoluteTop()+45, getText()); + pickUserDlg.onKeyUp(event.getKeyCode(), this.getAbsoluteLeft(), this.getAbsoluteTop()+this.getOffsetHeight(), getText()); break; } case Event.ONCONTEXTMENU: { @@ -121,15 +132,20 @@ public class SuperPosedTextArea extends TextArea { } } protected void removeSampleText() { - if (getText().equals(COMMENT_TEXT) || getText().equals(ERROR_UPDATE_TEXT) ) { + if (getText().equals(AddCommentTemplate.COMMENT_TEXT) || getText().equals(AddCommentTemplate.ERROR_UPDATE_TEXT) ) { setText(""); addStyleName("darker-color"); removeStyleName("error"); } } protected void cleanHighlighterDiv() { - DOM.getElementById("comment-highlighter").setInnerHTML(""); + //DOM.getElementById("comment-highlighter").setInnerHTML(""); + highlighterDIV.getElement().setInnerHTML(""); } + /** + * copy what is being written in the text area in the underneath DIV + * @param textAreaText + */ private void injectInDiv(String textAreaText) { String text; // parse the text: @@ -141,7 +157,8 @@ public class SuperPosedTextArea extends TextArea { text = text.replaceAll(mentionedUser,""+mentionedUser+""); } // re-inject the processed text into the div - DOM.getElementById("comment-highlighter").setInnerHTML(text); + //DOM.getElementById("comment-highlighter").setInnerHTML(text); + highlighterDIV.getElement().setInnerHTML(text); } /** @@ -158,7 +175,8 @@ public class SuperPosedTextArea extends TextArea { String[] toSplit = getText().split("@"); //get the preceeding part setText(toSplit[0]+toAdd); - Element highDiv = DOM.getElementById("comment-highlighter"); + //Element highDiv = DOM.getElementById("comment-highlighter"); + Element highDiv = highlighterDIV.getElement(); String[] htmlToSplit = highDiv.getInnerHTML().split("@"); //get the preceeding part String highLightedUser = ""+toAdd+""; @@ -177,20 +195,26 @@ public class SuperPosedTextArea extends TextArea { return mentionedUsers; } - - - - /* - * - * - * - * + + /** + * this position the caret at the begin */ - + public static native void setCaretPositionToBegin(String myAreaId) /*-{ + var elem = $doc.getElementById(myAreaId); + if(elem != null) { + if(elem.createTextRange) { + var range = elem.createTextRange(); + range.move('character', 0); + range.select(); + } + else { + if(elem.selectionStart) { + elem.focus(); + elem.setSelectionRange(0, 0); + } + else + elem.focus(); + } + } + }-*/; } diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/TweetTemplate.java b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/TweetTemplate.java index 5b14233..505f55d 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/TweetTemplate.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/client/templates/TweetTemplate.java @@ -149,7 +149,11 @@ public class TweetTemplate extends Composite { feedText = feedText.substring(0, MAX_SHOWTEXT_LENGTH) + "..."; seeMore.setHTML(" See More "); } - + + //replace the < & and > + feedText = feedText.replaceAll("<","<").replaceAll(">",">"); + feedText = feedText.replaceAll("&","&"); + if (! isAppFeed) { messageArea.setHTML("" + NewsFeedPanel.MESSAGE_LABEL + ""); contentArea.setHTML(" users; + + + public MentionNotificationsThread(String postId, String postText, NotificationsManager nm, ArrayList users) { + super(); + this.postId = postId; + this.postText = postText; + this.nm = nm; + this.users = users; + } + + @Override + public void run() { + for (PickingUser userToNotify : users) { + boolean result = nm.notifyUserTag(userToNotify.getUsername(), postId, postText); + _log.trace("Sending Notification for post mention to: " + userToNotify.getUsername() + " result?"+ result); + } + } +} diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java b/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java index 1aa2e0d..84fe7be 100644 --- a/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/newsfeed/server/NewsServiceImpl.java @@ -491,12 +491,22 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService * @param feedOwnerId the username of the user who created the post that was commented */ @Override - public Comment comment(String feedid, String commentText, String feedOwnerId, boolean isAppFeed) { + public Comment comment(String feedid, String commentText, ArrayList mentionedUserFullNames, String feedOwnerId, boolean isAppFeed) { boolean commentCommitResult = false; _log.trace("Trying to add this comment " + commentText); UserInfo user = getUserSettings().getUserInfo(); + + + String escapedCommentText = Utils.escapeHtmlAndTransformUrl(commentText); + + ArrayList mentionedUsers = null; + if (mentionedUserFullNames != null && ! mentionedUserFullNames.isEmpty()) { + mentionedUsers = getSelectedUserIds(mentionedUserFullNames); + escapedCommentText = Utils.convertMentionPeopleAnchorHTML(escapedCommentText, mentionedUsers); + } + Comment comment = new Comment(UUID.randomUUID().toString(), user.getUsername(), - new Date(), feedid, transformUrls(escapeHtml(commentText)), user.getFullName(), user.getAvatarId()); + new Date(), feedid, escapedCommentText, user.getFullName(), user.getAvatarId()); try { if (store.addComment(comment)) commentCommitResult = true; @@ -521,7 +531,13 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService //notify the other users who commented this post (excluding the ones above) Thread commentsNotificationthread = new Thread(new CommentNotificationsThread(store, user.getUsername(), comment.getFeedid(), commentText, nm, feedOwnerId, favorites)); - commentsNotificationthread.start(); + commentsNotificationthread.start(); + + //send the notification to the mentioned users, if any + if (mentionedUsers != null && mentionedUsers.size() > 0) { + Thread thread = new Thread(new MentionNotificationsThread(comment.getFeedid(), commentText, nm, mentionedUsers)); + thread.start(); + } } return comment; } @@ -683,7 +699,7 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService } @Override public ArrayList getOrganizationUsers(String currentScope) { - ArrayList toReturn = UsersUtil.getOrganizationUsers(currentScope, getASLSession().getUsername(), withinPortal); + ArrayList toReturn = Utils.getOrganizationUsers(currentScope, getASLSession().getUsername(), withinPortal); _log.trace("Returning " + toReturn.size() + " users for scope " + currentScope); return toReturn; } @@ -740,6 +756,26 @@ public class NewsServiceImpl extends RemoteServiceServlet implements NewsService } return (Boolean) getASLSession().getAttribute(SESSION_ADMIN_ATTR); } + /** + * + * @return the screennames of the addressee (user logins e.g. pino.pini) + */ + public ArrayList getSelectedUserIds(ArrayList fullNames) { + if (fullNames == null) + return new ArrayList(); + else { + ArrayList allUsers = Utils.getOrganizationUsers("/"+OrganizationsUtil.getRootOrganizationName(), getASLSession().getUsername(), withinPortal); + ArrayList toReturn = new ArrayList(); + for (String fullName : fullNames) + for (PickingUser puser : allUsers) { + if (puser.getFullName().compareTo(fullName) == 0) { + toReturn.add(puser); + break; + } + } + return toReturn; + } + } /** * tell if the user is a portal administrator or not * @param username diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/server/UsersUtil.java b/src/main/java/org/gcube/portlets/user/newsfeed/server/UsersUtil.java deleted file mode 100644 index 1d4783c..0000000 --- a/src/main/java/org/gcube/portlets/user/newsfeed/server/UsersUtil.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.gcube.portlets.user.newsfeed.server; - -import java.util.ArrayList; -import java.util.List; - -import org.gcube.common.scope.impl.ScopeBean; -import org.gcube.common.scope.impl.ScopeBean.Type; -import org.gcube.portal.custom.communitymanager.OrganizationsUtil; -import org.gcube.portlets.widgets.pickuser.shared.PickingUser; -import org.gcube.vomanagement.usermanagement.GroupManager; -import org.gcube.vomanagement.usermanagement.UserManager; -import org.gcube.vomanagement.usermanagement.impl.liferay.LiferayGroupManager; -import org.gcube.vomanagement.usermanagement.impl.liferay.LiferayUserManager; -import org.gcube.vomanagement.usermanagement.model.UserModel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.liferay.portal.service.UserLocalServiceUtil; - -public class UsersUtil { - private static final Logger _log = LoggerFactory.getLogger(UsersUtil.class); - /** - * - * @param session the Asl Session - * @param withinPortal true when is on Liferay portal - * @return the users belonging to the current organization (scope) - */ - public static ArrayList getOrganizationUsers(String scope, String currUser, boolean withinPortal) { - ArrayList portalUsers = new ArrayList(); - try { - if (withinPortal) { - UserManager um = new LiferayUserManager(); - GroupManager gm = new LiferayGroupManager(); - ScopeBean sb = new ScopeBean(scope); - List users = null; - - if (sb.is(Type.INFRASTRUCTURE)) - users = um.listUsersByGroup(gm.getRootVO().getGroupId()); - else if (sb.is(Type.VRE)) { //must be in VRE - //get the name from the scope - String orgName = scope.substring(scope.lastIndexOf("/")+1, scope.length()); - //ask the users - users = um.listUsersByGroup(gm.getGroupId(orgName)); - } - else { - _log.error("Error, you must be in SCOPE VRE OR INFRASTURCTURE, you are in VO SCOPE returning no users"); - return portalUsers; - } - for (UserModel user : users) { - if (user.getScreenName().compareTo("test.user") != 0 && user.getScreenName().compareTo(currUser) != 0) { //skip test.user & current user - String thumbnailURL = ""; - com.liferay.portal.model.UserModel lifeUser = UserLocalServiceUtil.getUserByScreenName(OrganizationsUtil.getCompany().getCompanyId(), user.getScreenName()); - thumbnailURL = "/image/user_male_portrait?img_id="+lifeUser.getPortraitId(); - portalUsers.add(new PickingUser(user.getUserId(), user.getScreenName(), user.getFullname(), thumbnailURL)); - } - } - } - else { //test users - portalUsers.add(new PickingUser("12111", "massimiliano.assante", "Test User #1", "")); - portalUsers.add(new PickingUser("14111", "massimiliano.assante", "Test Second User #2", "")); - portalUsers.add(new PickingUser("11511", "massimiliano.assante", "Test Third User", "")); - portalUsers.add(new PickingUser("11611", "massimiliano.assante", "Test Fourth User", "")); - portalUsers.add(new PickingUser("11711", "massimiliano.assante", "Test Fifth User", "")); - portalUsers.add(new PickingUser("11811", "massimiliano.assante", "Test Sixth User", "")); - portalUsers.add(new PickingUser("15811", "massimiliano.assante", "Ninth Testing User", "")); - portalUsers.add(new PickingUser("15811", "massimiliano.assante", "Eighth Testing User", "")); - portalUsers.add(new PickingUser("11211", "giogio.giorgi", "Seventh Test User", "")); - portalUsers.add(new PickingUser("2222", "pino.pinetti", "Tenth Testing User", "")); - } - } catch (Exception e) { - _log.error("Error in server get all contacts ", e); - } - return portalUsers; - } -} diff --git a/src/main/java/org/gcube/portlets/user/newsfeed/server/Utils.java b/src/main/java/org/gcube/portlets/user/newsfeed/server/Utils.java new file mode 100644 index 0000000..0612613 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/newsfeed/server/Utils.java @@ -0,0 +1,167 @@ +package org.gcube.portlets.user.newsfeed.server; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.codec.binary.Base64; +import org.gcube.common.scope.impl.ScopeBean; +import org.gcube.common.scope.impl.ScopeBean.Type; +import org.gcube.portal.custom.communitymanager.OrganizationsUtil; +import org.gcube.portal.databook.client.GCubeSocialNetworking; +import org.gcube.portlets.widgets.pickuser.shared.PickingUser; +import org.gcube.vomanagement.usermanagement.GroupManager; +import org.gcube.vomanagement.usermanagement.UserManager; +import org.gcube.vomanagement.usermanagement.impl.liferay.LiferayGroupManager; +import org.gcube.vomanagement.usermanagement.impl.liferay.LiferayUserManager; +import org.gcube.vomanagement.usermanagement.model.UserModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.liferay.portal.service.UserLocalServiceUtil; + +public class Utils { + private static final Logger _log = LoggerFactory.getLogger(Utils.class); + /** + * + * @param session the Asl Session + * @param withinPortal true when is on Liferay portal + * @return the users belonging to the current organization (scope) + */ + public static ArrayList getOrganizationUsers(String scope, String currUser, boolean withinPortal) { + ArrayList portalUsers = new ArrayList(); + try { + if (withinPortal) { + UserManager um = new LiferayUserManager(); + GroupManager gm = new LiferayGroupManager(); + ScopeBean sb = new ScopeBean(scope); + List users = null; + + if (sb.is(Type.INFRASTRUCTURE)) + users = um.listUsersByGroup(gm.getRootVO().getGroupId()); + else if (sb.is(Type.VRE)) { //must be in VRE + //get the name from the scope + String orgName = scope.substring(scope.lastIndexOf("/")+1, scope.length()); + //ask the users + users = um.listUsersByGroup(gm.getGroupId(orgName)); + } + else { + _log.error("Error, you must be in SCOPE VRE OR INFRASTURCTURE, you are in VO SCOPE returning no users"); + return portalUsers; + } + for (UserModel user : users) { + if (user.getScreenName().compareTo("test.user") != 0 && user.getScreenName().compareTo(currUser) != 0) { //skip test.user & current user + String thumbnailURL = ""; + com.liferay.portal.model.UserModel lifeUser = UserLocalServiceUtil.getUserByScreenName(OrganizationsUtil.getCompany().getCompanyId(), user.getScreenName()); + thumbnailURL = "/image/user_male_portrait?img_id="+lifeUser.getPortraitId(); + portalUsers.add(new PickingUser(user.getUserId(), user.getScreenName(), user.getFullname(), thumbnailURL)); + } + } + } + else { //test users + portalUsers.add(new PickingUser("12111", "massimiliano.assante", "Test User #1", "")); + portalUsers.add(new PickingUser("14111", "massimiliano.assante", "Test Second User #2", "")); + portalUsers.add(new PickingUser("11511", "massimiliano.assante", "Test Third User", "")); + portalUsers.add(new PickingUser("11611", "massimiliano.assante", "Test Fourth User", "")); + portalUsers.add(new PickingUser("11711", "massimiliano.assante", "Test Fifth User", "")); + portalUsers.add(new PickingUser("11811", "massimiliano.assante", "Test Sixth User", "")); + portalUsers.add(new PickingUser("15811", "massimiliano.assante", "Ninth Testing User", "")); + portalUsers.add(new PickingUser("15811", "massimiliano.assante", "Eighth Testing User", "")); + portalUsers.add(new PickingUser("11211", "giogio.giorgi", "Seventh Test User", "")); + portalUsers.add(new PickingUser("2222", "pino.pinetti", "Tenth Testing User", "")); + } + } catch (Exception e) { + _log.error("Error in server get all contacts ", e); + } + return portalUsers; + } + /** + * 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 escapeHtmlAndTransformUrl(String html) { + if (html == null) { + return null; + } + String toReturn = html.replaceAll("&", "&").replaceAll("<", "<") + .replaceAll(">", ">"); + + // replace all the line breaks by
+ toReturn = toReturn.replaceAll("(\r\n|\n)","
"); + //transfrom the URL in a clickable URL + toReturn = transformUrls(toReturn); + // then replace all the double spaces by the html version   + toReturn = toReturn.replaceAll("\\s\\s","  "); + return toReturn; + } + /** + * utility method that convert a url ina text in a clickable url by the browser + * and if the user has just pasted a link, converts the link in: shared a link + * @param feedText + * @return the text with the clickable url in it + */ + protected static String transformUrls(String feedText) { + StringBuilder sb = new StringBuilder(); + // separate input by spaces ( URLs have no spaces ) + String [] parts = feedText.split("\\s"); + // Attempt to convert each item into an URL. + for (int i = 0; i < parts.length; i++) { + String toCheck = getHttpToken(parts[i]); + if (toCheck != null) { + try { + URL url = new URL(toCheck); + if (i == 0 && parts.length == 1) //then he shared just a link + return sb.append("shared
").append("a link.").append(" ").toString(); + // If possible then replace with anchor... + sb.append("").append(url).append(" "); + } catch (MalformedURLException e) { + // If there was an URL then it's not valid + _log.error("MalformedURLException returning... "); + return feedText; + } + } else { + sb.append(parts[i]); + sb.append(" "); + } + } + return sb.toString(); + } + /** + * convert the mentioned people in HTML anchor and also Encode the params Base64 + * @param escapedFeedText + * @param taggedPeople + * @return + */ + protected static String convertMentionPeopleAnchorHTML(String escapedFeedText, ArrayList taggedPeople) { + for (PickingUser tagged : taggedPeople) { + String taggedHTML = ""+tagged.getFullName()+" "; + escapedFeedText = escapedFeedText.replace(tagged.getFullName(), taggedHTML); + } + return escapedFeedText; + } + /** + * check the tokens of a pasted text and see if there's any http link in it + * @param item a text token + * @return the actual http link + */ + private static String getHttpToken(String item) { + if (item.startsWith("http") || item.startsWith("www") || item.startsWith("(www") || item.startsWith("(http")) { + if (item.startsWith("(")) + item = item.substring(1, item.length()); + if (item.endsWith(".") || item.endsWith(")")) { //sometimes people write the url and close the phrase with a . + item = item.substring(0, item.length()-1); + } + item = item.startsWith("www") ? "http://"+item : item; + //System.out.println("getHttpToken returns -> " + item); + return item; + } + return null; + } +} diff --git a/src/main/webapp/NewsFeed.css b/src/main/webapp/NewsFeed.css index c8be50e..26cd67d 100644 --- a/src/main/webapp/NewsFeed.css +++ b/src/main/webapp/NewsFeed.css @@ -25,7 +25,7 @@ table { position: relative; } -#comment-highlighter { +.comment-highlighter { padding: 4px 2px; color: #ffffff; background-color: #FFF; @@ -56,7 +56,7 @@ table { letter-spacing: normal; line-height: normal; - border: 1px solid #999; + border: 1px solid #C3CDE7; width: 450px; min-height: 40px;