diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java
index da73973..174732e 100644
--- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java
+++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java
@@ -922,7 +922,7 @@ public class CreateDatasetForm extends Composite{
(datasetUrl.length() > 100 ?
datasetUrl.substring(0, 100) + "..." : datasetUrl)
);
- goToDatasetButton.setHref(datasetUrl);
+ // goToDatasetButton.setHref(datasetUrl);
goToDatasetButton.addClickHandler(new ClickHandler() {
@Override
diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/dataset/resources/AddResourceToDataset.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/dataset/resources/AddResourceToDataset.java
index de6379f..aed866e 100644
--- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/dataset/resources/AddResourceToDataset.java
+++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/dataset/resources/AddResourceToDataset.java
@@ -68,7 +68,7 @@ public class AddResourceToDataset extends Composite{
(datasetUrl.length() > 100 ?
datasetUrl.substring(0, 100) + "..." : datasetUrl)
);
- goToDatasetButton.setHref(datasetUrl);
+ // goToDatasetButton.setHref(datasetUrl);
goToDatasetButton.addClickHandler(new ClickHandler() {
@Override
diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/WritePostCatalogueManagerThread.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/WritePostCatalogueManagerThread.java
index d2a2319..393f572 100644
--- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/WritePostCatalogueManagerThread.java
+++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/WritePostCatalogueManagerThread.java
@@ -1,14 +1,30 @@
package org.gcube.portlets.widgets.ckandatapublisherwidget.server.threads;
+import java.io.IOException;
+import java.net.HttpURLConnection;
import java.util.List;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider;
+import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.GCoreEndPointReaderSocial;
+import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.ServiceEndPointReaderSocial;
import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.Utils;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
+import eu.trentorise.opendata.jackan.internal.org.apache.http.Header;
+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.ClientProtocolException;
+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.util.EntityUtils;
+
/**
* Let the Product Catalogue Manager write a post in a VRE and alert there is a new product
@@ -17,15 +33,20 @@ import com.liferay.portal.kernel.log.LogFactoryUtil;
*/
public class WritePostCatalogueManagerThread extends Thread {
- //private static final Logger logger = LoggerFactory.getLogger(WritePostCatalogueManagerThread.class);
+ private static final String APPLICATION_ID_CATALOGUE_MANAGER = "org.gcube.datacatalogue.ProductCatalogue";
+ private static final String NOTIFICATION_MESSAGE = "Dear members,
The item '$PRODUCT_TITLE' has been just published by $USER_FULLNAME.
You can find it here: $PRODUCT_URL
";
+ 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 MEDIATYPE_JSON = "application/json";
private static final Log logger = LogFactoryUtil.getLog(WritePostCatalogueManagerThread.class);
+ // private static Logger logger = LoggerFactory.getLogger(WritePostCatalogueManagerThread.class);
private String username;
private String scope;
private String productTitle;
private String productUrl;
private boolean enableNotification;
private List hashtags;
- String userFullName;
+ private String userFullName;
/**
* @param token
@@ -56,7 +77,7 @@ public class WritePostCatalogueManagerThread extends Thread {
try{
// evaluate user's token for this scope
String token = Utils.tryGetElseCreateToken(username, scope);
-
+
if(token == null){
logger.warn("Unable to proceed, user's token is not available");
return;
@@ -71,7 +92,7 @@ public class WritePostCatalogueManagerThread extends Thread {
SecurityTokenProvider.instance.set(token);
// write
- Utils.writeProductPost(
+ writeProductPost(
productTitle,
productUrl,
userFullName,
@@ -86,4 +107,193 @@ public class WritePostCatalogueManagerThread extends Thread {
ScopeProvider.instance.reset();
}
}
+
+ /**
+ * Send notification to vre members about the created product by writing a post.
+ * @param productName the title of the product
+ * @param productUrl the url of the product
+ * @param hashtags a list of product's hashtags
+ */
+ private static void writeProductPost(String productName, String productUrl, String userFullname, List hashtags, boolean enablePostNotification){
+
+ // 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 = new GCoreEndPointReaderSocial(currentScope).getBasePath();
+
+ // add fallback
+ if(basePath == null || basePath.isEmpty())
+ new ServiceEndPointReaderSocial(currentScope).getBasePath();
+
+ if(basePath == null){
+
+ logger.error("Unable to write a post because there is no social networking service available");
+
+ }else{
+
+ // check base path form
+ basePath = basePath.endsWith("/") ? basePath : basePath + "/";
+
+ try(CloseableHttpClient client = HttpClientBuilder.create().build();){
+
+ String pathTokenApp = basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser;
+ String tokenApp = requireAppToken(client, pathTokenApp);
+ if(tokenApp != null){
+ String pathWritePost = basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + tokenApp;
+ writePost(client, pathWritePost, productName, productUrl, userFullname, hashtags, enablePostNotification);
+ }
+
+ }catch(Exception e){
+ logger.error("Failed to create a post", e);
+ }
+ }
+ }
+
+ /**
+ * Require the application token
+ * @param tokenUser
+ * @param basePath
+ * @param client
+ * @return
+ */
+ private static String requireAppToken(CloseableHttpClient client, String path){
+
+ String token = null;
+ try{
+
+ HttpResponse response = performRequest(client, path, "{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}");
+
+ int statusTokenGenerate = response.getStatusLine().getStatusCode();
+
+ if(statusTokenGenerate == HttpURLConnection.HTTP_CREATED){
+
+ // extract token
+ JSONObject obj = getJSONObject(response);
+ if(((Boolean) obj.get("success")))
+ token = (String)obj.get("result");
+ else
+ return null;
+
+ }else if(statusTokenGenerate == HttpURLConnection.HTTP_MOVED_TEMP
+ || statusTokenGenerate == HttpURLConnection.HTTP_MOVED_PERM
+ || statusTokenGenerate == HttpURLConnection.HTTP_SEE_OTHER){
+
+ // re-execute
+ Header[] locations = response.getHeaders("Location");
+ Header lastLocation = locations[locations.length - 1];
+ String realLocation = lastLocation.getValue();
+ logger.debug("New location is " + realLocation);
+ token = requireAppToken(client, realLocation);
+
+ }else
+ return null;
+
+ }catch(Exception e){
+ logger.error("Failed to retrieve application token", e);
+ }
+
+ logger.info("Returning app token " + (token != null ? token.substring(0, 10) + "*************************" : null));
+ return token;
+ }
+
+ /**
+ * Write post request
+ * @param client
+ * @param applicationToken
+ * @param productName
+ * @param productUrl
+ * @param userFullname
+ * @param hashtags
+ */
+ private static void writePost(CloseableHttpClient client, String path, String productName, String productUrl, String userFullname, List hashtags,
+ boolean enablePostNotification) {
+
+ try{
+
+ // replace
+ String message = NOTIFICATION_MESSAGE.replace("$PRODUCT_TITLE", productName).replace("$PRODUCT_URL", productUrl).replace("$USER_FULLNAME", userFullname);
+
+ if(hashtags != null && !hashtags.isEmpty())
+ for (String hashtag : hashtags) {
+ String modifiedHashtag = hashtag.replaceAll(" ", "_").replace("_+", "_");
+ if(modifiedHashtag.endsWith("_"))
+ modifiedHashtag = modifiedHashtag.substring(0, modifiedHashtag.length() - 1);
+ message += " #" + modifiedHashtag; // ckan accepts tag with empty spaces, we don't
+ }
+
+ logger.info("The post that is going to be written is -> " + message);
+
+ HttpResponse response = performRequest(client, path, "{\"text\":\"" + message + "\", \"enable_notification\" : "+ enablePostNotification+ "}");
+ int statusWritePost = response.getStatusLine().getStatusCode();
+
+ if(statusWritePost == HttpURLConnection.HTTP_CREATED){
+
+ // extract token
+ JSONObject obj = getJSONObject(response);
+ if(((Boolean) obj.get("success")))
+ logger.info("Post written");
+ else
+ logger.info("Failed to write the post " + obj.get("message"));
+
+ }else if(statusWritePost == HttpURLConnection.HTTP_MOVED_TEMP
+ || statusWritePost == HttpURLConnection.HTTP_MOVED_PERM
+ || statusWritePost == HttpURLConnection.HTTP_SEE_OTHER){
+
+ // re-execute
+ Header[] locations = response.getHeaders("Location");
+ Header lastLocation = locations[locations.length - 1];
+ String realLocation = lastLocation.getValue();
+ logger.debug("New location is " + realLocation);
+ writePost(client, realLocation, productName, productUrl, userFullname, hashtags, enablePostNotification);
+
+ }else
+ throw new RuntimeException("Failed to write the post");
+
+ }catch(Exception e){
+ logger.error("Failed to retrieve application token", e);
+ }
+
+ }
+
+ /**
+ * Convert the json response to a map
+ * @param response
+ * @return
+ */
+ private static JSONObject getJSONObject(HttpResponse response){
+
+ JSONObject toReturn = null;
+ HttpEntity entity = response.getEntity();
+
+ if (entity != null) {
+ try {
+ String jsonString = EntityUtils.toString(response.getEntity());
+ JSONParser parser = new JSONParser();
+ toReturn = (JSONObject)parser.parse(jsonString);
+ }catch(Exception e){
+ logger.error("Failed to read json object", e);
+ }
+ }
+
+ logger.debug("Returning " + toReturn.toJSONString());
+ return toReturn;
+ }
+
+ /**
+ * Perform an http request post request with json entity
+ * @throws IOException
+ * @throws ClientProtocolException
+ */
+ private static HttpResponse performRequest(CloseableHttpClient client, String path, String entity) throws ClientProtocolException, IOException{
+
+ HttpPost request = new HttpPost(path);
+ StringEntity stringEntity = new StringEntity(entity);
+ stringEntity.setContentType(MEDIATYPE_JSON);
+ request.setEntity(stringEntity);
+ return client.execute(request);
+
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/Utils.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/Utils.java
index e0b0ed2..fc51266 100644
--- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/Utils.java
+++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/Utils.java
@@ -3,9 +3,7 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils;
import static org.gcube.common.authorization.client.Constants.authorizationService;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@@ -13,9 +11,6 @@ import javax.servlet.http.HttpSession;
import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.provider.UserInfo;
-import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
-import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
-import org.gcube.common.homelibrary.home.workspace.folder.items.GCubeItem;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.server.ApplicationProfileScopePerUrlReader;
@@ -48,17 +43,9 @@ import org.gcube.vomanagement.usermanagement.model.GCubeRole;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.gcube.vomanagement.usermanagement.model.GatewayRolesNames;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
-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.util.EntityUtils;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
/**
@@ -70,38 +57,8 @@ public class Utils {
// Logger
//private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Utils.class);
private static final Log logger = LogFactoryUtil.getLog(Utils.class);
- private static final String APPLICATION_ID_CATALOGUE_MANAGER = "org.gcube.datacatalogue.ProductCatalogue";
- private static final String NOTIFICATION_MESSAGE = "Dear members,
The item 'PRODUCT_TITLE' has been just published by USER_FULLNAME.
You can find it here: PRODUCT_URL
";
- 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 MEDIATYPE_JSON = "application/json";
public static final String GCUBE_REQUEST_URL = "gcube-request-url";
- /** Gets the gcube item properties.
- *
- * @param item the item
- * @return the gcube item properties
- */
- public static Map getGcubeItemProperties(WorkspaceItem item) {
-
- if(item instanceof GCubeItem){
- GCubeItem gItem = (GCubeItem) item;
- try {
- if(gItem.getProperties()!=null){
- Map map = gItem.getProperties().getProperties();
- HashMap properties = new HashMap(map.size()); //TO PREVENT GWT SERIALIZATION ERROR
- for (String key : map.keySet())
- properties.put(key, map.get(key));
-
- return properties;
- }
- } catch (InternalErrorException e) {
- logger.error("Error in server getItemProperties: ", e);
- }
- }
- return null;
- }
-
/**
* Retrieve the highest ckan role the user has and also retrieve the list of organizations (scopes) in which the user has the ckan-admin or ckan-editor role
* @param currentScope the current scope
@@ -385,121 +342,6 @@ public class Utils {
return beans;
}
- /**
- * Send notification to vre members about the created product by writing a post.
- * @param productName the title of the product
- * @param productUrl the url of the product
- * @param hashtags a list of product's hashtags
- */
- public static void writeProductPost(String productName, String productUrl, String userFullname, List hashtags, boolean enablePostNotification){
-
- // 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 = new GCoreEndPointReaderSocial(currentScope).getBasePath();
-
- // add fallback
- if(basePath == null || basePath.isEmpty())
- new ServiceEndPointReaderSocial(currentScope).getBasePath();
-
- if(basePath == null){
-
- logger.error("Unable to write a post because there is no social networking service available");
-
- }else{
-
- // check base path form
- basePath = basePath.endsWith("/") ? basePath : basePath + "/";
-
- try(CloseableHttpClient client = HttpClientBuilder.create().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);
-
- basePath = basePath.startsWith("https") ? basePath : basePath.replace("http", "https").replace(":80", "");
- 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 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 = NOTIFICATION_MESSAGE.replace("PRODUCT_TITLE", productName).replace("PRODUCT_URL", productUrl).replace("USER_FULLNAME", userFullname);
-
- if(hashtags != null && !hashtags.isEmpty())
- for (String hashtag : hashtags) {
- String modifiedHashtag = hashtag.replaceAll(" ", "_").replace("_+", "_");
- if(modifiedHashtag.endsWith("_"))
- modifiedHashtag = modifiedHashtag.substring(0, modifiedHashtag.length() - 1);
- message += " #" + modifiedHashtag; // ckan accepts tag with empty spaces, we don't
- }
-
- logger.info("The post that is going to be written is -> " + message);
- postRequest = new HttpPost(basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + applicationToken);
- input = new StringEntity("{\"text\":\"" + message + "\", \"enable_notification\" : "+ enablePostNotification+ "}");
- input.setContentType(MEDIATYPE_JSON);
- postRequest.setEntity(input);
- response = client.execute(postRequest);
-
- Map 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);
- }
- }
- }
-
- /**
- * Convert the json response to a map
- * @param response
- * @return
- */
- public static Map getResponseEntityAsJSON(HttpResponse response){
-
- Map toReturn = null;
- HttpEntity entity = response.getEntity();
-
- if (entity != null) {
- try {
- toReturn = new HashMap();
- 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;
- }
-
/**
* First check to retrieve the token, else create it
* @param username
diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/WorkspaceUtils.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/WorkspaceUtils.java
index 45f1e4e..f476f68 100644
--- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/WorkspaceUtils.java
+++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/WorkspaceUtils.java
@@ -15,6 +15,7 @@ import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
import org.gcube.common.homelibrary.home.workspace.catalogue.WorkspaceCatalogue;
import org.gcube.common.homelibrary.home.workspace.folder.FolderItem;
+import org.gcube.common.homelibrary.home.workspace.folder.items.GCubeItem;
import org.gcube.datacatalogue.ckanutillibrary.server.models.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.UtilMethods;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
@@ -145,7 +146,7 @@ public class WorkspaceUtils {
bean.setDescription(originalFolderOrFile.getDescription());
// Create the folder in the catalogue
- Map folderItems = Utils.getGcubeItemProperties(originalFolderOrFile);
+ Map folderItems = getGcubeItemProperties(originalFolderOrFile);
if(folderItems != null){
// transform this properties
@@ -165,6 +166,31 @@ public class WorkspaceUtils {
}
}
+
+ /** Gets the gcube item properties.
+ *
+ * @param item the item
+ * @return the gcube item properties
+ */
+ public static Map getGcubeItemProperties(WorkspaceItem item) {
+
+ if(item instanceof GCubeItem){
+ GCubeItem gItem = (GCubeItem) item;
+ try {
+ if(gItem.getProperties()!=null){
+ Map map = gItem.getProperties().getProperties();
+ HashMap properties = new HashMap(map.size()); //TO PREVENT GWT SERIALIZATION ERROR
+ for (String key : map.keySet())
+ properties.put(key, map.get(key));
+
+ return properties;
+ }
+ } catch (InternalErrorException e) {
+ logger.error("Error in server getItemProperties: ", e);
+ }
+ }
+ return null;
+ }
/**
* Returns a tree object