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
This commit is contained in:
parent
1728e6dfc3
commit
1e6587f314
|
@ -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<String> mentionedUsers, String feedOwnerId, boolean isAppFeed);
|
||||
|
||||
Comment editComment(Comment toEdit);
|
||||
|
||||
|
|
|
@ -32,8 +32,9 @@ public interface NewsServiceAsync {
|
|||
|
||||
void getUserSettings(AsyncCallback<UserSettings> callback);
|
||||
|
||||
void comment(String feedid, String text, String feedOwnerId,
|
||||
boolean isAppFeed, AsyncCallback<Comment> callback);
|
||||
void comment(String feedid, String text, ArrayList<String> mentionedUsers,
|
||||
String feedOwnerId, boolean isAppFeed,
|
||||
AsyncCallback<Comment> callback);
|
||||
|
||||
void getAllCommentsByFeed(String feedid,
|
||||
AsyncCallback<ArrayList<Comment>> callback);
|
||||
|
|
|
@ -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<AddCommentEventHandler> {
|
|||
|
||||
private TweetTemplate owner;
|
||||
private String text;
|
||||
private ArrayList<String> mentionedUsers;
|
||||
|
||||
public AddCommentEvent(TweetTemplate owner, String text, ArrayList<String> 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<String> getMentionedUsers() {
|
||||
return mentionedUsers;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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<Comment>() {
|
||||
private void doAddComment(final TweetTemplate owner, String text, ArrayList<String> mentionedUsers) {
|
||||
newsService.comment(owner.getFeedKey(), text, mentionedUsers, owner.getMyFeedUserId(), owner.isAppFeed(), new AsyncCallback<Comment>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
Window.alert("Could not deliver this comment: " + caught.getMessage());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||
xmlns:g="urn:import:com.google.gwt.user.client.ui"
|
||||
xmlns:w="urn:import:org.gcube.portlets.user.gcubewidgets.client.elements"
|
||||
xmlns:m="urn:import:org.gcube.portlets.user.newsfeed.client.templates">
|
||||
<ui:style>
|
||||
.important {
|
||||
|
@ -19,16 +20,14 @@
|
|||
<td>
|
||||
<div id="comment-supercontainer">
|
||||
<div id="comment-highlighterContainer">
|
||||
<div id="comment-highlighter">
|
||||
</div>
|
||||
<!-- <div id="comment-highlighter"> -->
|
||||
<!-- </div> -->
|
||||
<w:Div styleName="comment-highlighter" ui:field="highlighterDIV"></w:Div>
|
||||
</div>
|
||||
<div id="comment-inputContainer">
|
||||
<m:SuperPosedTextArea styleName="post-comment" ui:field="commentTextArea" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="commentContainer"> -->
|
||||
<!-- <g:TextArea styleName="post-comment" ui:field="commentTextArea" /> -->
|
||||
<!-- </div> -->
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -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("<a class=\"seemore\"> See More </a>");
|
||||
|
@ -114,4 +119,6 @@ public class SingleComment extends Composite {
|
|||
editImage.removeStyleName("uiEditButton");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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<String> mentionedUsers = new ArrayList<String>();
|
||||
|
||||
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<ArrayList<PickingUser>>() {
|
||||
|
||||
@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,"<span class=\"highlightedUser\">"+mentionedUser+"</span>");
|
||||
}
|
||||
// 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 = "<span class=\"highlightedUser\">"+toAdd+"</span>";
|
||||
|
@ -177,20 +195,26 @@ public class SuperPosedTextArea extends TextArea {
|
|||
return mentionedUsers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* <script>
|
||||
$(document).ready(function(){
|
||||
setTimeout(function(){
|
||||
$('.postTextArea').autosize();
|
||||
}, 3000);
|
||||
});
|
||||
</script>
|
||||
*
|
||||
*
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}-*/;
|
||||
}
|
||||
|
|
|
@ -149,7 +149,11 @@ public class TweetTemplate extends Composite {
|
|||
feedText = feedText.substring(0, MAX_SHOWTEXT_LENGTH) + "...";
|
||||
seeMore.setHTML("<a class=\"seemore\"> See More </a>");
|
||||
}
|
||||
|
||||
|
||||
//replace the < & and >
|
||||
feedText = feedText.replaceAll("<","<").replaceAll(">",">");
|
||||
feedText = feedText.replaceAll("&","&");
|
||||
|
||||
if (! isAppFeed) {
|
||||
messageArea.setHTML("<a>" + NewsFeedPanel.MESSAGE_LABEL + "</a>");
|
||||
contentArea.setHTML("<a class=\"link\" href=\""+GCubeSocialNetworking.USER_PROFILE_LINK
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package org.gcube.portlets.user.newsfeed.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.gcube.applicationsupportlayer.social.NotificationsManager;
|
||||
import org.gcube.portlets.widgets.pickuser.shared.PickingUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Massimiliano Assante ISTI-CNR
|
||||
*
|
||||
*/
|
||||
public class MentionNotificationsThread implements Runnable {
|
||||
private static Logger _log = LoggerFactory.getLogger(MentionNotificationsThread.class);
|
||||
|
||||
private String postText;
|
||||
private String postId;
|
||||
private NotificationsManager nm;
|
||||
private ArrayList<PickingUser> users;
|
||||
|
||||
|
||||
public MentionNotificationsThread(String postId, String postText, NotificationsManager nm, ArrayList<PickingUser> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<String> 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<PickingUser> 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<PickingUser> getOrganizationUsers(String currentScope) {
|
||||
ArrayList<PickingUser> toReturn = UsersUtil.getOrganizationUsers(currentScope, getASLSession().getUsername(), withinPortal);
|
||||
ArrayList<PickingUser> 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<PickingUser> getSelectedUserIds(ArrayList<String> fullNames) {
|
||||
if (fullNames == null)
|
||||
return new ArrayList<PickingUser>();
|
||||
else {
|
||||
ArrayList<PickingUser> allUsers = Utils.getOrganizationUsers("/"+OrganizationsUtil.getRootOrganizationName(), getASLSession().getUsername(), withinPortal);
|
||||
ArrayList<PickingUser> toReturn = new ArrayList<PickingUser>();
|
||||
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
|
||||
|
|
|
@ -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<PickingUser> getOrganizationUsers(String scope, String currUser, boolean withinPortal) {
|
||||
ArrayList<PickingUser> portalUsers = new ArrayList<PickingUser>();
|
||||
try {
|
||||
if (withinPortal) {
|
||||
UserManager um = new LiferayUserManager();
|
||||
GroupManager gm = new LiferayGroupManager();
|
||||
ScopeBean sb = new ScopeBean(scope);
|
||||
List<UserModel> 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;
|
||||
}
|
||||
}
|
|
@ -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<PickingUser> getOrganizationUsers(String scope, String currUser, boolean withinPortal) {
|
||||
ArrayList<PickingUser> portalUsers = new ArrayList<PickingUser>();
|
||||
try {
|
||||
if (withinPortal) {
|
||||
UserManager um = new LiferayUserManager();
|
||||
GroupManager gm = new LiferayGroupManager();
|
||||
ScopeBean sb = new ScopeBean(scope);
|
||||
List<UserModel> 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 <br/>
|
||||
toReturn = toReturn.replaceAll("(\r\n|\n)"," <br/> ");
|
||||
//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("<span style=\"color:gray; font-size:12px;\">shared </span><a class=\"link\" href=\"").append(url).append("\" target=\"_blank\">").append("a link.").append("</a> ").toString();
|
||||
// If possible then replace with anchor...
|
||||
sb.append("<a class=\"link\" href=\"").append(url).append("\" target=\"_blank\">").append(url).append("</a> ");
|
||||
} 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<PickingUser> taggedPeople) {
|
||||
for (PickingUser tagged : taggedPeople) {
|
||||
String taggedHTML = "<a class=\"link\" href=\""+GCubeSocialNetworking.USER_PROFILE_LINK
|
||||
+"?"+
|
||||
new String(Base64.encodeBase64(GCubeSocialNetworking.USER_PROFILE_OID.getBytes()))+"="+
|
||||
new String(Base64.encodeBase64(tagged.getUsername().getBytes()))+"\">"+tagged.getFullName()+"</a> ";
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue