added comment method with notification, still need testing

This commit is contained in:
Massimiliano Assante 2023-02-08 14:29:57 +01:00
parent 9f696b7f54
commit cb583b0a50
4 changed files with 301 additions and 51 deletions

View File

@ -0,0 +1,73 @@
package org.gcube.portal.social.networking.ws.inputs;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webcohesion.enunciate.metadata.DocumentationExample;
/**
* Generic input bean for methods that allow to comment posts
*/
@JsonIgnoreProperties(ignoreUnknown = true) // ignore in serialization/deserialization
public class CommentInputBean implements Serializable{
private static final long serialVersionUID = 5274608088828232980L;
@JsonProperty("text")
@NotNull(message="text cannot be null")
@Size(min=1, message="text cannot be empty")
@DocumentationExample("I would like to comment that ...")
/**
* text the text of the comment
*/
private String text;
@NotNull(message="postid cannot be null")
@JsonProperty("postid")
/**
* postid the postid of the post where you attach the comment
*/
private String postid;
public CommentInputBean() {
super();
}
/**
* @param text
* @param postid
* @param params
*/
public CommentInputBean(String text, String postid) {
super();
this.text = text;
this.postid = postid;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getPostid() {
return postid;
}
public void setPostid(String postid) {
this.postid = postid;
}
@Override
public String toString() {
return "CommentInputBean [text=" + text + ", postid=" + postid + "]";
}
}

View File

@ -48,14 +48,14 @@ import com.webcohesion.enunciate.metadata.rs.StatusCodes;
*/
@Path("2/comments")
@RequestHeaders ({
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
@RequestHeader( name = "Content-Type", description = "application/json")
})
@RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
@RequestHeader( name = "Content-Type", description = "application/json")
})
public class Comments {
// Logger
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Comments.class);
/*
* Retrieve the list of comments belonging to the post id (key) of the token in the related context
* @param key the key as in the POST JSON representation
@ -167,7 +167,7 @@ public class Comments {
return Response.status(status).entity(responseBean).build();
}
/**
* Create a new comment to a post having as owner the auth token's owner
* @param post The post to be written
@ -193,37 +193,18 @@ public class Comments {
String context = ScopeProvider.instance.get();
ResponseBean responseBean = new ResponseBean();
Status status = Status.OK;
SocialMessageParser messageParser = new SocialMessageParser(comment.getText());
String escapedCommentText = messageParser.getParsedMessage();
// parse
String key = UUID.randomUUID().toString();
String postId = comment.getPostid();
String commentText = escapedCommentText;
String commentText = comment.getText();
String userid = username;
Date time = new Date();
GCubeUser user;
// retrieve group information
UserManager uManager = UserManagerWSBuilder.getInstance().getUserManager();
try {
user = uManager.getUserByUsername(userid);
} catch(Exception e){
logger.error("Unable to get user informations, comment write fails.", e);
responseBean.setMessage("Unable to get user informations, comment write fails with username " + userid + " that does not exist ");
responseBean.setSuccess(false);
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
String fullName = user.getFirstName() + " " + user.getLastName();
String thumbnailURL = user.getUserAvatarURL();
Comment theComment = new Comment(key, userid, time, postId, commentText, fullName, thumbnailURL);
boolean result = false;
Comment theComment = null;
try {
result = CassandraConnection.getInstance().getDatabookStore().addComment(theComment);
logger.info("Added comment? " + theComment.toString() + " Result is " +result);
String postOwnerId = CassandraConnection.getInstance().getDatabookStore().readPost(postId).getKey();
theComment = SocialUtils.commentPost(userid, time, postId, commentText, postOwnerId, context);
logger.info("Added comment " + theComment.toString());
} catch(Exception e){
e.printStackTrace();
responseBean.setMessage("Could not reach the DB to write the comment, something went wrong");
@ -232,20 +213,20 @@ public class Comments {
return Response.status(status).entity(responseBean).build();
}
if(result){
if(theComment != null){
logger.info("Comment correctly written by user " + username);
responseBean.setResult(result);
responseBean.setSuccess(true);
return Response.status(status).entity(responseBean).build();
} else {
logger.error("Unable to write comment.");
responseBean.setMessage("Unable to write comment");
responseBean.setSuccess(false);
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
logger.error("Unable to write comment.");
responseBean.setMessage("Unable to write comment");
responseBean.setSuccess(false);
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
}

View File

@ -28,6 +28,7 @@ import org.gcube.portal.databook.shared.Feed;
import org.gcube.portal.databook.shared.Post;
import org.gcube.portal.databook.shared.RangePosts;
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.social.networking.ws.inputs.PostInputBean;
@ -138,6 +139,53 @@ public class Posts {
return Response.status(status).entity(responseBean).build();
}
/**
* Retrieve a post by id
* @return the post if the post id belongs to a post in the context identified by the token
*/
@GET
@Path("get-post/")
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes ({
@ResponseCode ( code = 200, condition = "Successful retrieval of posts, reported in the 'result' field of the returned object"),
@ResponseCode ( code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getPost(@QueryParam("id") String id) {
String context = ScopeProvider.instance.get();
Caller caller = AuthorizationProvider.instance.get();
ResponseBean responseBean = new ResponseBean();
Status status = Status.OK;
List<Post> posts = new ArrayList<>();
try{
logger.debug("Retrieving post with id " + id);
try {
posts.add(CassandraConnection.getInstance().getDatabookStore().readPost(id));
} catch(FeedIDNotFoundException e){
responseBean.setMessage("The post with id " + id + " does not exist in context " + context);
responseBean.setSuccess(false);
return Response.status(status).entity(responseBean).build();
}
Filters.filterPostsPerContext(posts, context);
Filters.hideSensitiveInformation(posts, caller.getClient().getId());
if (posts.isEmpty()) {
responseBean.setMessage("The post with id " + id + " does not belong to this context " + context);
responseBean.setSuccess(false);
status = Status.FORBIDDEN;
return Response.status(status).entity(responseBean).build();
}
responseBean.setResult(posts.get(0));
responseBean.setMessage("");
responseBean.setSuccess(true);
}catch(Exception e){
logger.error("Unable to retrieve such post.", e);
responseBean.setMessage(e.getMessage());
responseBean.setSuccess(false);
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
/**
* Retrieve a given quantity of latest user's posts
* @param quantity the number of latest post to get
@ -367,8 +415,8 @@ public class Posts {
else
logger.debug("Disable notification for this application post.");
// write feed + notification if it is the case
Feed written = SocialUtils.shareApplicationUpdate(
// write post + notification if it is the case
Post written = SocialUtils.shareApplicationUpdate(
postText,
params,
previewTitle,

View File

@ -6,14 +6,16 @@ import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.Map.Entry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.gcube.applicationsupportlayer.social.ApplicationNotificationsManager;
import org.gcube.applicationsupportlayer.social.NotificationsManager;
import org.gcube.applicationsupportlayer.social.ex.ApplicationProfileNotFoundException;
@ -24,13 +26,15 @@ import org.gcube.common.resources.gcore.utils.XPathHelper;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.portal.databook.shared.ApplicationProfile;
import org.gcube.portal.databook.shared.Feed;
import org.gcube.portal.databook.shared.FeedType;
import org.gcube.portal.databook.shared.Comment;
import org.gcube.portal.databook.shared.Like;
import org.gcube.portal.databook.shared.Post;
import org.gcube.portal.databook.shared.PostType;
import org.gcube.portal.databook.shared.PrivacyLevel;
import org.gcube.portal.databook.shared.ex.FeedIDNotFoundException;
import org.gcube.portal.notifications.bean.GenericItemBean;
import org.gcube.portal.notifications.thread.CommentNotificationsThread;
import org.gcube.portal.notifications.thread.LikeNotificationsThread;
import org.gcube.portal.notifications.thread.MentionNotificationsThread;
import org.gcube.portal.notifications.thread.PostNotificationsThread;
import org.gcube.portal.social.networking.caches.SocialNetworkingSiteFinder;
@ -44,6 +48,10 @@ import org.gcube.social_networking.socialutillibrary.Utils;
import org.gcube.socialnetworking.socialtoken.SocialMessageParser;
import org.gcube.vomanagement.usermanagement.GroupManager;
import org.gcube.vomanagement.usermanagement.UserManager;
import org.gcube.vomanagement.usermanagement.exception.TeamRetrievalFault;
import org.gcube.vomanagement.usermanagement.exception.UserManagementSystemException;
import org.gcube.vomanagement.usermanagement.exception.UserRetrievalFault;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
@ -52,6 +60,7 @@ import org.xml.sax.InputSource;
/**
* Utility class.
*/
@SuppressWarnings("deprecation")
public class SocialUtils {
// Logger
@ -60,7 +69,7 @@ public class SocialUtils {
public final static String NO_TEXT_FILE_SHARE = "_N0_73X7_SH4R3_";
public final static int CACHING_TIME_TO_EXPIRATION = 2506000;//29 days 6 minutes 40 seconds
public final static String DISABLED_USERS_NOTIFICATIONS_NAMESPACE = "dun:";
// name of the portlet for vre notification
public static final String NEWS_FEED_PORTLET_CLASSNAME = "org.gcube.portlets.user.newsfeed.server.NewsServiceImpl";
@ -104,7 +113,7 @@ public class SocialUtils {
* @param httpImageUrl
* @return true upon success, false on failure
*/
public static Feed shareApplicationUpdate(
public static Post shareApplicationUpdate(
String postText,
String uriParams,
String previewTitle,
@ -129,7 +138,7 @@ public class SocialUtils {
String scope = ScopeProvider.instance.get();
String appId = caller.getClient().getId();
Feed toWrite =
Post toWrite =
buildPost(
escapedPostText,
uriParams == null ? "" : uriParams,
@ -140,7 +149,7 @@ public class SocialUtils {
scope);
// try to save it
boolean res = CassandraConnection.getInstance().getDatabookStore().saveAppFeed(toWrite);
boolean res = CassandraConnection.getInstance().getDatabookStore().saveAppPost(toWrite);
if(res){
logger.info("Feed correctly written by application " + appId);
@ -218,7 +227,7 @@ public class SocialUtils {
* @param previewThumbnailUrl the image url to show in the preview
* @return a feed instance ready to be written
*/
private static Feed buildPost(
private static Post buildPost(
String description,
String uriParams,
String previewTitle,
@ -233,9 +242,9 @@ public class SocialUtils {
if (uriParams != null && uriParams.compareTo("") != 0)
uri += "?"+uriParams;
Feed toReturn = new Feed(
Post toReturn = new Post(
UUID.randomUUID().toString(),
FeedType.PUBLISH,
PostType.PUBLISH,
applicationProfile.getKey(),
new Date(),
scopeApp,
@ -497,4 +506,143 @@ public class SocialUtils {
}
return toShare;
}
/**
* Allows to comment post in a certain vre.
* @param userid the username
* @param time the date and time of the comment
* @param postId the key of the post that was commented
* @param commentText the text as it is, it will be parsed
* @param postOwnerId the username of the user who created the post that was commented
* @param context the VRE context
*
* @return the Comment instance if ok, null if somwthign went KO
* @throws FeedIDNotFoundException
*/
public static Comment commentPost(String userid, Date time, String postId, String commentText, String postOwnerId, String context) throws FeedIDNotFoundException {
SocialMessageParser messageParser = new SocialMessageParser(commentText);
String escapedCommentText = messageParser.getParsedMessage();
//check if any mention exists
ArrayList<GenericItemBean> mentionedUsers = getUsersFromUsernames(Utils.getMentionedUsernames(commentText));
ArrayList<ItemBean> mentionedUsersToConvertInHTML = convertToItemBean(mentionedUsers);
SocialNetworkingSite site = SocialNetworkingSiteFinder.getSocialNetworkingSiteFromScope(ScopeProvider.instance.get());
escapedCommentText = Utils.convertMentionUsernamesAnchorHTML(escapedCommentText, mentionedUsersToConvertInHTML, site.getSiteURL(), site.getSiteLandingPagePath());
// retrieve user information
GCubeUser user;
UserManager uManager = UserManagerWSBuilder.getInstance().getUserManager();
try {
user = uManager.getUserByUsername(userid);
} catch(Exception e){
logger.error("Unable to get user informations, comment write fails.", e);
return null;
}
String commentKey = UUID.randomUUID().toString(); // a unique id that goes in the DB
String email = user.getEmail();
String fullName = user.getFirstName() + " " + user.getLastName();
String thumbnailURL = user.getUserAvatarURL();
Comment theComment = new Comment(commentKey, userid, time, postId, escapedCommentText, fullName, thumbnailURL);
logger.info("Attempting to save Comment with text: " + commentText + " postid="+postId);
boolean result = CassandraConnection.getInstance().getDatabookStore().addComment(theComment);
logger.info("Added comment? " + theComment.toString() + " Result is " +result);
if (!result)
return null;
//if the comment was correctly delivered notify users involved
SocialNetworkingUser socialUser = new SocialNetworkingUser(userid, email, fullName, thumbnailURL);
NotificationsManager nm = new ApplicationNotificationsManager(UserManagerWSBuilder.getInstance().getUserManager(), site, context, socialUser, NEWS_FEED_PORTLET_CLASSNAME);
//if the user who commented this post is not the user who posted it notify the poster user (Post owner)
if (! user.getUsername().equals(postOwnerId)) {
boolean resultNotifyOwnComment = nm.notifyOwnCommentReply(postOwnerId, postId, escapedCommentText, theComment.getKey());
logger.trace("Comment Notification to post owner added? " + resultNotifyOwnComment);
}
//if there are users who liked this post they get notified, asynchronously with this thread
ArrayList<Like> likes = getAllLikesByPost(postId);
Thread likesThread = new Thread(new LikeNotificationsThread(escapedCommentText, nm, likes, postOwnerId, theComment.getKey()));
likesThread.start();
//notify the other users who commented this post (excluding the ones above)
Thread commentsNotificationthread = new Thread(new CommentNotificationsThread(
CassandraConnection.getInstance().getDatabookStore(),
uManager, user.getUsername(), theComment.getFeedid(), escapedCommentText, nm, postOwnerId, theComment.getKey(), likes));
commentsNotificationthread.start();
//send the notification to the mentioned users, if any
if (mentionedUsers != null && mentionedUsers.size() > 0) {
ArrayList<GenericItemBean> toPass = new ArrayList<GenericItemBean>();
// among the mentionedUsers there could be groups of people
Map<String, ItemBean> uniqueUsersToNotify = new HashMap<>();
UserManager um = new LiferayUserManager();
for (ItemBean bean : mentionedUsersToConvertInHTML) {
if(bean.isItemGroup()){
// retrieve the users of this group
try {
List<GCubeUser> teamUsers = um.listUsersByTeam(Long.parseLong(bean.getId()));
for (GCubeUser userTeam : teamUsers) {
if(!uniqueUsersToNotify.containsKey(userTeam.getUsername()))
uniqueUsersToNotify.put(userTeam.getUsername(), new ItemBean(userTeam.getUserId()+"",
userTeam.getUsername(), userTeam.getFullname(), userTeam.getUserAvatarURL()));
}
} catch (NumberFormatException
| UserManagementSystemException
| TeamRetrievalFault | UserRetrievalFault e) {
logger.error("Unable to retrieve team information", e);
}
}else{
// it is a user, just add to the hashmap
if(!uniqueUsersToNotify.containsKey(bean.getName()))
uniqueUsersToNotify.put(bean.getName(), bean);
}
}
// iterate over the hashmap
Iterator<Entry<String, ItemBean>> userMapIterator = uniqueUsersToNotify.entrySet().iterator();
while (userMapIterator.hasNext()) {
Map.Entry<String, ItemBean> userEntry = (Map.Entry<String, ItemBean>) userMapIterator
.next();
ItemBean userBean = userEntry.getValue();
toPass.add(new GenericItemBean(userBean.getId(), userBean.getName(), userBean.getAlternativeName(), userBean.getThumbnailURL()));
}
Thread thread = new Thread(new MentionNotificationsThread(theComment.getFeedid(), escapedCommentText, nm, null, toPass));
thread.start();
}
return theComment;
}
private static ArrayList<Like> getAllLikesByPost(String postid) {
ArrayList<Like> toReturn = (ArrayList<Like>) CassandraConnection.getInstance().getDatabookStore().getAllLikesByPost(postid);
logger.debug("Asking likes for " + postid);
for (Like like : toReturn) {
// retrieve user information
GCubeUser user;
UserManager uManager = UserManagerWSBuilder.getInstance().getUserManager();
try {
user = uManager.getUserByUsername(like.getUserid());
} catch(Exception e){
logger.error("Unable to get user informations, comment write fails.", e);
return null;
}
String thumbnailURL = user.getUserAvatarURL();
like.setThumbnailURL(thumbnailURL == null ? "" : thumbnailURL);
}
return toReturn;
}
}