2018-02-02 15:28:35 +01:00
package org.gcube.datacatalogue.grsf_manage_widget.server.manage ;
import static org.gcube.resources.discovery.icclient.ICFactory.client ;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
import javax.servlet.http.HttpServletRequest ;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider ;
import org.gcube.common.resources.gcore.GCoreEndpoint ;
import org.gcube.common.scope.api.ScopeProvider ;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue ;
import org.gcube.datacatalogue.common.Constants ;
import org.gcube.datacatalogue.grsf_manage_widget.server.manage.RevertOperationUrl.Operation ;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean ;
import org.gcube.resources.discovery.client.api.DiscoveryClient ;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery ;
import org.gcube.vomanagement.usermanagement.RoleManager ;
import org.gcube.vomanagement.usermanagement.UserManager ;
import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager ;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager ;
import org.gcube.vomanagement.usermanagement.model.GCubeTeam ;
import org.json.simple.JSONArray ;
import org.json.simple.JSONObject ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import com.fasterxml.jackson.databind.ObjectMapper ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpEntity ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.LaxRedirectStrategy ;
import eu.trentorise.opendata.jackan.internal.org.apache.http.util.EntityUtils ;
/ * *
* For managing the different interactions with social channels ( posts and mails )
* @author Costantino Perciante at ISTI - CNR ( costantino . perciante @isti.cnr.it )
* /
public class SocialCommunications {
private static final Logger logger = LoggerFactory . getLogger ( SocialCommunications . class ) ;
// for discovering social networking service
private static final String resource = " jersey-servlet " ;
private static final String serviceName = " SocialNetworking " ;
private static final String serviceClass = " Portal " ;
// social operations
private static final String SOCIAL_SERVICE_APPLICATION_TOKEN = " /2/tokens/generate-application-token/ " ;
private static final String SOCIAL_SERVICE_WRITE_APPLICATION_POST = " /2/posts/write-post-app/ " ;
private static final String SOCIAL_SEND_EMAIL = " /2/messages/write-message/ " ;
private static final String MEDIATYPE_JSON = " application/json " ;
// for writing a post in the GRSF admin context
private static final String APPLICATION_ID_CATALOGUE_MANAGER = " org.gcube.datacatalogue.GRSFNotifier " ;
// emails to be sent to editors and reviewers and post to be written into the grsf admin vre
private static final String POST_MESSAGE = " Dear members, "
+ " <br>The record 'PRODUCT_TITLE' has been just updated by USER_FULLNAME. "
+ " <br>You can inspect it here: PRODUCT_URL<br> " ;
private static final String EMAIL_MESSAGE_REVIEWER = " Dear GRSF Reviewer, "
+ " <br>an update on the record named 'PRODUCT_TITLE' has been requested by USER_FULLNAME. "
+ " <br>It is available here LINK_RECORD. " ;
private static final String EMAIL_MESSAGE_EDITOR = " Dear USER_FULLNAME, "
+ " <br>your request for the record 'PRODUCT_TITLE' has been accepted. "
+ " <br>It is available here LINK_RECORD. " ;
private static final String REVERT_LINK_PIECE = " <br>The request involves a merge operation. You can reject the merge by exploiting this link LINK in the following 24 hours. " ;
/ * *
*
* @param context
* @return
* /
private static String getBaseUrlSocialService ( String context ) {
if ( context = = null | | context . isEmpty ( ) )
throw new IllegalArgumentException ( " A valid context is needed to discover the service " ) ;
String oldContext = ScopeProvider . instance . get ( ) ;
ScopeProvider . instance . set ( context ) ;
String basePath = null ;
try {
SimpleQuery query = queryFor ( GCoreEndpoint . class ) ;
query . addCondition ( String . format ( " $resource/Profile/ServiceClass/text() eq '%s' " , serviceClass ) ) ;
query . addCondition ( " $resource/Profile/DeploymentData/Status/text() eq 'ready' " ) ;
query . addCondition ( String . format ( " $resource/Profile/ServiceName/text() eq '%s' " , serviceName ) ) ;
query . setResult ( " $resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \" " + resource + " \" ]/text() " ) ;
DiscoveryClient < String > client = client ( ) ;
List < String > endpoints = client . submit ( query ) ;
if ( endpoints = = null | | endpoints . isEmpty ( ) )
throw new Exception ( " Cannot retrieve the GCoreEndpoint serviceName: " + serviceName + " , serviceClass: " + serviceClass + " , in scope: " + context ) ;
basePath = endpoints . get ( 0 ) ;
if ( basePath = = null )
throw new Exception ( " Endpoint: " + resource + " , is null for serviceName: " + serviceName + " , serviceClass: " + serviceClass + " , in scope: " + context ) ;
} catch ( Exception e ) {
logger . error ( " Unable to retrieve such service endpoint information! " , e ) ;
} finally {
if ( oldContext ! = null & & ! oldContext . equals ( context ) )
ScopeProvider . instance . set ( oldContext ) ;
}
logger . info ( " Found base path " + basePath + " for the service " ) ;
return basePath ;
}
/ * *
* Notify the users about the required changes .
* @param bean
* @param url
* @param username
* @param fullName
* @param hashtags
* @param enablePostNotification
* /
@SuppressWarnings ( " unchecked " )
2018-02-03 19:17:37 +01:00
public static void writeProductPost ( ManageProductBean bean , String username , String fullName , String report , boolean enablePostNotification ) {
2018-02-02 15:28:35 +01:00
// discover service endpoint for the social networking library
String currentScope = ScopeProvider . instance . get ( ) ;
String tokenUser = SecurityTokenProvider . instance . get ( ) ;
logger . info ( " Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser . substring ( 0 , 10 ) + " *************** " ) ;
String basePath = getBaseUrlSocialService ( currentScope ) ;
if ( basePath = = null ) {
logger . error ( " Unable to write a post because there is no social networking service available " ) ;
} else {
basePath = basePath . endsWith ( " / " ) ? basePath : basePath + " / " ;
try ( CloseableHttpClient client = HttpClientBuilder . create ( ) . setRedirectStrategy ( new LaxRedirectStrategy ( ) ) . build ( ) ; ) {
// ask token application
HttpPost postRequest = new HttpPost ( basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + " ?gcube-token= " + tokenUser ) ;
StringEntity input = new StringEntity ( " { \" app_id \" : \" " + APPLICATION_ID_CATALOGUE_MANAGER + " \" } " ) ;
input . setContentType ( MEDIATYPE_JSON ) ;
postRequest . setEntity ( input ) ;
HttpResponse response = client . execute ( postRequest ) ;
logger . debug ( " Url is " + basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + " ?gcube-token= " + tokenUser ) ;
if ( response . getStatusLine ( ) . getStatusCode ( ) ! = 201 ) {
throw new RuntimeException ( " Failed to retrieve application token : HTTP error code : "
+ response . getStatusLine ( ) . getStatusCode ( ) ) ;
} else {
Map < String , Object > mapResponseGeneratedToken = getResponseEntityAsJSON ( response ) ;
boolean successGeneratedToken = ( boolean ) mapResponseGeneratedToken . get ( " success " ) ;
if ( ! successGeneratedToken ) {
throw new RuntimeException ( " Failed to generate the token for the application! "
+ " Error message is " + mapResponseGeneratedToken . get ( " message " ) ) ;
} else {
String applicationToken = ( String ) mapResponseGeneratedToken . get ( " result " ) ;
// replace
String message = POST_MESSAGE . replace ( " PRODUCT_TITLE " , bean . getGrsfName ( ) ) . replace ( " PRODUCT_URL " , bean . getRecordUrl ( ) ) . replace ( " USER_FULLNAME " , fullName ) ;
2018-02-03 19:17:37 +01:00
// evaluate hashtags from the report ... TODO
// if(hashtags != null && !hashtags.isEmpty())
// for (String hashtag : hashtags) {
// String modifiedHashtag = hashtag.replaceAll(" ", "_").replace("_+", "_"); // no empty spaces allowed
// if(modifiedHashtag.endsWith("_"))
// modifiedHashtag = modifiedHashtag.substring(0, modifiedHashtag.length() - 1);
// message += " #" + modifiedHashtag;
// }
2018-02-02 15:28:35 +01:00
logger . info ( " The post that is going to be written is -> " + message ) ;
postRequest = new HttpPost ( basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + " ?gcube-token= " + applicationToken ) ;
JSONObject object = new JSONObject ( ) ;
object . put ( " text " , message ) ;
object . put ( " enable_notification " , enablePostNotification ) ;
input = new StringEntity ( object . toJSONString ( ) ) ;
input . setContentType ( MEDIATYPE_JSON ) ;
postRequest . setEntity ( input ) ;
response = client . execute ( postRequest ) ;
Map < String , Object > mapResponseWritePost = getResponseEntityAsJSON ( response ) ;
if ( response . getStatusLine ( ) . getStatusCode ( ) ! = 201 )
throw new RuntimeException ( " Failed to write application post : HTTP error code : "
+ response . getStatusLine ( ) . getStatusCode ( ) + mapResponseWritePost . get ( " message " ) ) ;
}
}
} catch ( Exception e ) {
logger . error ( " Failed to create a post " , e ) ;
}
}
}
/ * *
* Send an email to the administrator as well as the
* @param bean
* @param catalogue
* @param username
* @param fullName
* @param isMergeInvolved
* @param httpSession
* @throws Exceptio
* /
@SuppressWarnings ( " unchecked " )
public static void sendEmailAdministrators (
ManageProductBean bean ,
DataCatalogue catalogue ,
String username ,
String fullName ,
long groupId ,
HttpServletRequest httpServletRequest ,
boolean isMergeInvolved ) throws Exception {
// get the list of GRSF Reviewers to alert them as well
RoleManager roleManager = new LiferayRoleManager ( ) ;
List < GCubeTeam > teamRoles = roleManager . listTeamsByGroup ( groupId ) ;
List < String > reviewers = new ArrayList < > ( ) ;
UserManager um = new LiferayUserManager ( ) ;
for ( GCubeTeam tr : teamRoles ) {
if ( tr . getTeamName ( ) . equals ( Constants . GRSF_CATALOGUE_REVIEWER_ROLE ) )
reviewers . add ( um . getUserById ( tr . getUserId ( ) ) . getUsername ( ) ) ;
}
// if the user is a reviewer, then send the email just once
reviewers . remove ( username ) ;
logger . info ( " List of " + Constants . GRSF_CATALOGUE_REVIEWER_ROLE + " is " + reviewers ) ;
// build the url that allows to revert the operation
Operation operation = Operation . MERGE ;
// discover service endpoint for the social networking library
String currentScope = ScopeProvider . instance . get ( ) ;
String tokenUser = SecurityTokenProvider . instance . get ( ) ;
logger . info ( " Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser . substring ( 0 , 10 ) + " *************** " ) ;
String basePath = getBaseUrlSocialService ( currentScope ) ;
if ( basePath = = null ) {
logger . error ( " Unable to write a post because there is no social networking service available " ) ;
} else {
basePath = basePath . endsWith ( " / " ) ? basePath : basePath + " / " ;
try ( CloseableHttpClient client = HttpClientBuilder . create ( ) . setRedirectStrategy ( new LaxRedirectStrategy ( ) ) . build ( ) ; ) {
// ask token application
HttpPost postRequest = new HttpPost ( basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + " ?gcube-token= " + tokenUser ) ;
StringEntity input = new StringEntity ( " { \" app_id \" : \" " + APPLICATION_ID_CATALOGUE_MANAGER + " \" } " ) ;
input . setContentType ( MEDIATYPE_JSON ) ;
postRequest . setEntity ( input ) ;
HttpResponse response = client . execute ( postRequest ) ;
logger . debug ( " Url is " + basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + " ?gcube-token= " + tokenUser ) ;
if ( response . getStatusLine ( ) . getStatusCode ( ) ! = 201 ) {
throw new RuntimeException ( " Failed to retrieve application token : HTTP error code : "
+ response . getStatusLine ( ) . getStatusCode ( ) ) ;
} else {
Map < String , Object > mapResponseGeneratedToken = getResponseEntityAsJSON ( response ) ;
boolean successGeneratedToken = ( boolean ) mapResponseGeneratedToken . get ( " success " ) ;
if ( ! successGeneratedToken ) {
throw new RuntimeException ( " Failed to generate the token for the application! "
+ " Error message is " + mapResponseGeneratedToken . get ( " message " ) ) ;
} else {
String applicationToken = ( String ) mapResponseGeneratedToken . get ( " result " ) ;
String revertUrl = getEncodedUrlManage ( operation , username , System . currentTimeMillis ( ) , bean . getKnowledgeBaseIdentifier ( ) , httpServletRequest ) ;
String messageToEditor = ( EMAIL_MESSAGE_EDITOR +
( isMergeInvolved ? REVERT_LINK_PIECE : " " ) ) . replace ( " USER_FULLNAME " , fullName ) . replace ( " PRODUCT_TITLE " , bean . getGrsfName ( ) ) . replace ( " LINK_RECORD " , bean . getRecordUrl ( ) ) . replace ( " LINK " , revertUrl ) ;
String messageToReviewer = ( EMAIL_MESSAGE_REVIEWER +
( isMergeInvolved ? REVERT_LINK_PIECE : " " ) ) . replace ( " USER_FULLNAME " , fullName ) . replace ( " PRODUCT_TITLE " , bean . getGrsfName ( ) ) . replace ( " LINK_RECORD " , bean . getRecordUrl ( ) ) . replace ( " LINK " , revertUrl ) ;
String subject = " Update request on GRSF Record " ;
// send email to the editor
logger . info ( " The message that is going to be send to the editor is \ n " + messageToEditor ) ;
postRequest = new HttpPost ( basePath + SOCIAL_SEND_EMAIL + " ?gcube-token= " + applicationToken ) ;
JSONObject reqMessage = new JSONObject ( ) ;
reqMessage . put ( " subject " , subject ) ;
reqMessage . put ( " body " , messageToEditor ) ;
JSONArray recipients = new JSONArray ( ) ;
JSONObject recipient = new JSONObject ( ) ;
recipient . put ( " id " , username ) ;
recipients . add ( recipient ) ;
reqMessage . put ( " recipients " , recipients ) ;
input = new StringEntity ( reqMessage . toJSONString ( ) ) ;
input . setContentType ( MEDIATYPE_JSON ) ;
postRequest . setEntity ( input ) ;
response = client . execute ( postRequest ) ;
Map < String , Object > mapResponseWritePost = getResponseEntityAsJSON ( response ) ;
if ( response . getStatusLine ( ) . getStatusCode ( ) ! = 201 ) {
logger . error ( " Failed to send message to editor : HTTP error code : "
+ response . getStatusLine ( ) . getStatusCode ( ) + mapResponseWritePost . get ( " message " ) ) ;
}
// send email to the reviewers
logger . info ( " The message that is going to be send to the reviewers is \ n " + messageToReviewer ) ;
postRequest = new HttpPost ( basePath + SOCIAL_SEND_EMAIL + " ?gcube-token= " + applicationToken ) ;
reqMessage = new JSONObject ( ) ;
reqMessage . put ( " subject " , subject ) ;
reqMessage . put ( " body " , messageToReviewer ) ;
recipients = new JSONArray ( ) ;
for ( String reviewer : reviewers ) {
JSONObject recip = new JSONObject ( ) ;
recip . put ( " id " , reviewer ) ;
recipients . add ( recip ) ;
}
reqMessage . put ( " recipients " , recipients ) ;
input = new StringEntity ( reqMessage . toJSONString ( ) ) ;
input . setContentType ( MEDIATYPE_JSON ) ;
postRequest . setEntity ( input ) ;
response = client . execute ( postRequest ) ;
mapResponseWritePost = getResponseEntityAsJSON ( response ) ;
if ( response . getStatusLine ( ) . getStatusCode ( ) ! = 201 ) {
logger . error ( " Failed to send message to editor : HTTP error code : "
+ response . getStatusLine ( ) . getStatusCode ( ) + mapResponseWritePost . get ( " message " ) ) ;
}
}
}
} catch ( Exception e ) {
logger . error ( " Failed to create a post " , e ) ;
}
}
}
/ * *
* Create the url to be send for reverting the operation
* @param httpSession
* @return
* @throws Exception
* /
public static String getEncodedUrlManage ( Operation operation , String administrator , long timestamp , String uuid , HttpServletRequest httpServletRequest ) throws Exception {
String clientUrl = Utils . getCurrentClientUrl ( httpServletRequest ) . split ( " \\ ? " ) [ 0 ] ; // ignore other parameters
RevertOperationUrl operationUrl = new RevertOperationUrl ( clientUrl , administrator , timestamp , uuid , operation ) ;
String shortUrl = operationUrl . getShortUrl ( ) ;
return shortUrl ;
}
/ * *
* Convert the json response to a map
* @param response
* @return
* /
@SuppressWarnings ( " unchecked " )
private static Map < String , Object > getResponseEntityAsJSON ( HttpResponse response ) {
Map < String , Object > toReturn = null ;
HttpEntity entity = response . getEntity ( ) ;
if ( entity ! = null ) {
try {
toReturn = new HashMap < String , Object > ( ) ;
String jsonString = EntityUtils . toString ( response . getEntity ( ) ) ;
logger . debug ( " Response as string is " + jsonString ) ;
ObjectMapper objectMapper = new ObjectMapper ( ) ;
toReturn = objectMapper . readValue ( jsonString , HashMap . class ) ;
logger . debug ( " Map is " + toReturn ) ;
} catch ( Exception e ) {
logger . error ( " Failed to read json object " , e ) ;
}
}
return toReturn ;
}
}