diff --git a/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml new file mode 100644 index 0000000..cc81385 --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml index 3f2dd2b..fe92fc5 100644 --- a/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -4,4 +4,5 @@ + diff --git a/CHANGELOG.md b/CHANGELOG.md index 0690ed3..c678c50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v2.0.0-SNAPSHOT] - 2021-02-11 + +**Enhancements** + +[#19764] Porting ckan-metadata-publisher-widget to catalogue-util-library + + ## [v1.6.2] - 2021-02-08 **Bug Fixes** diff --git a/pom.xml b/pom.xml index 35933b7..6440917 100644 --- a/pom.xml +++ b/pom.xml @@ -146,28 +146,27 @@ provided - - - - - - - - - - - - + + + + + + + + + + + + + org.gcube.datacatalogue catalogue-util-library - 0.1.0-SNAPSHOT - system - /home/francesco/git/catalogue-util-library/target/catalogue-util-library-0.1.0-SNAPSHOT.jar + [0.1.0-SNAPSHOT, 1.0.0) + compile - org.gcube.core common-scope-maps diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/CKANPublisherServicesImpl.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/CKANPublisherServicesImpl.java index 1e3f05a..699114f 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/CKANPublisherServicesImpl.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/CKANPublisherServicesImpl.java @@ -5,7 +5,6 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -20,9 +19,9 @@ import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods import org.gcube.datacatalogue.ckanutillibrary.server.utils.SessionCatalogueAttributes; import org.gcube.datacatalogue.ckanutillibrary.shared.ResourceBean; import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg; +import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanGroup; +import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanLicense; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService; -import org.gcube.portlets.widgets.ckandatapublisherwidget.server.threads.AssociationToGroupAndNotifyThread; -import org.gcube.portlets.widgets.ckandatapublisherwidget.server.threads.WritePostCatalogueManagerThread; import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.CatalogueRoleManager; import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.DiscoverTagsList; import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.GenericUtils; @@ -48,7 +47,7 @@ import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.service.UserLocalServiceUtil; -import eu.trentorise.opendata.jackan.model.CkanLicense; + /** @@ -328,8 +327,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C logger.debug("The user wants to publish in organization with name " + organizationNameOrId); String scope = getScopeFromOrgName(organizationNameOrId); DataCatalogue utils = getCatalogue(scope); - - String datasetId = utils.createCKanDatasetMultipleCustomFields(userName, + + String datasetId = utils.createCkanDatasetMultipleCustomFields(userName, title, null, organizationNameOrId, @@ -344,6 +343,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C customFields, resources, setPublic, + true, true); /** @@ -374,41 +374,43 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C utils.patchProductCustomFields(datasetId, userApiKey, addField, false); */ + + //TODO SHOULD BE NOTIFIED by gCAT // start a thread that will associate this dataset with the group - if(/*toCreate.getChosenType() != null ||*/ toCreate.getGroups() != null){ - - AssociationToGroupAndNotifyThread threadAssociationToGroup = - new AssociationToGroupAndNotifyThread( - toCreate.getGroups(), - toCreate.getGroupsForceCreation(), - null, //toCreate.getChosenType(), TODO - datasetUrl, - datasetId, - toCreate.getTitle(), - GenericUtils.getCurrentUser(getThreadLocalRequest()).getFullname(), - userName, - utils, - organizationNameOrId, - getThreadLocalRequest() - ); - threadAssociationToGroup.start(); - - } - - // launch notification thread - WritePostCatalogueManagerThread threadWritePost = - new WritePostCatalogueManagerThread( - userName, - scope, - toCreate.getTitle(), - datasetUrl, - false, // send notification to other people - toCreate.getTags(), - GenericUtils.getCurrentUser(getThreadLocalRequest()).getFullname(), - GenericUtils.getCurrentClientUrl(getThreadLocalRequest()) - ); - threadWritePost.start(); +// if(/*toCreate.getChosenType() != null ||*/ toCreate.getGroups() != null){ +// +// AssociationToGroupAndNotifyThread threadAssociationToGroup = +// new AssociationToGroupAndNotifyThread( +// toCreate.getGroups(), +// toCreate.getGroupsForceCreation(), +// null, //toCreate.getChosenType(), TODO +// datasetUrl, +// datasetId, +// toCreate.getTitle(), +// GenericUtils.getCurrentUser(getThreadLocalRequest()).getFullname(), +// userName, +// utils, +// organizationNameOrId, +// getThreadLocalRequest() +// ); +// threadAssociationToGroup.start(); +// +// } +// +// // launch notification thread +// WritePostCatalogueManagerThread threadWritePost = +// new WritePostCatalogueManagerThread( +// userName, +// scope, +// toCreate.getTitle(), +// datasetUrl, +// false, // send notification to other people +// toCreate.getTags(), +// GenericUtils.getCurrentUser(getThreadLocalRequest()).getFullname(), +// GenericUtils.getCurrentClientUrl(getThreadLocalRequest()) +// ); +// threadWritePost.start(); return toCreate; }else{ @@ -450,7 +452,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C // get the scope in which we should discover the ckan instance given the organization name in which the dataset was created String scope = getScopeFromOrgName(resource.getOrganizationNameDatasetParent()); DataCatalogue catalogue = getCatalogue(scope); - String resourceId = catalogue.addResourceToDataset(resourceBean, catalogue.getApiKeyFromUsername(username)); + String resourceId = catalogue.addResourceToDataset(resourceBean); if(resourceId != null){ logger.debug("Resource " + resource.getName() + " is now available"); @@ -475,13 +477,11 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C return deleted; }else{ - String username = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername(); try{ // get the scope in which we should discover the ckan instance given the organization name in which the dataset was created String scope = getScopeFromOrgName(resource.getOrganizationNameDatasetParent()); DataCatalogue catalogue = getCatalogue(scope); - deleted = catalogue. - deleteResourceFromDataset(resource.getOriginalIdInWorkspace(), catalogue.getApiKeyFromUsername(username)); + deleted = catalogue.deleteResourceFromDataset(resource.getOriginalIdInWorkspace()); if(deleted){ logger.info("Resource described by " + resource + " deleted"); }else @@ -565,7 +565,10 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C List toReturn = new ArrayList(); if(isWithinPortal()){ - String username = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername(); + GCubeUser user = GenericUtils.getCurrentUser(getThreadLocalRequest()); + String username = null; + if(user!=null) + username = user.getUsername(); logger.debug("Request for user " + username + " groups. Organization name is " + orgName); @@ -584,10 +587,9 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C //Fixing Incident #12563 try{ DataCatalogue catalogue = getCatalogue(scope); - String apiKey = catalogue.getApiKeyFromUsername(username); //Fixing Incident #12563 - if(apiKey!=null && !apiKey.isEmpty()){ - Map> mapRoleGroup = catalogue.getUserRoleByGroup(username, apiKey); + if(username!=null && !username.isEmpty()){ + Map> mapRoleGroup = catalogue.getUserRoleByGroup(username); Set>> set = mapRoleGroup.entrySet(); for (Entry> entry : set) { Set> subSet = entry.getValue().entrySet(); diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/AssociationToGroupAndNotifyThread.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/AssociationToGroupAndNotifyThread.java index 3266249..c252731 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/AssociationToGroupAndNotifyThread.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/threads/AssociationToGroupAndNotifyThread.java @@ -1,160 +1,161 @@ -package org.gcube.portlets.widgets.ckandatapublisherwidget.server.threads; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; - -import org.gcube.common.portal.mailing.EmailNotification; -import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; -import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods; -import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg; -import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean; -import org.gcube.vomanagement.usermanagement.UserManager; -import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; - -import com.liferay.portal.kernel.log.Log; -import com.liferay.portal.kernel.log.LogFactoryUtil; - -import eu.trentorise.opendata.jackan.model.CkanGroup; - -/** - * Associate the dataset to a group and send notifications to group's admins. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) - */ -public class AssociationToGroupAndNotifyThread extends Thread { - - //private static final Logger logger = LoggerFactory.getLogger(AssociationToGroupAndNotifyThread.class); - private static final Log logger = LogFactoryUtil.getLog(AssociationToGroupAndNotifyThread.class); - private static final String PRODUCT_ASSOCIATED_TO_GROUP_SUBJECT = "Item $TITLE added to group $GROUP"; - private static final String PRODUCT_ASSOCIATED_TO_GROUP_BODY = "Dear user,
a new item named '$TITLE' has been " - + "just published by $USER_FULLNAME in $GROUP .
" - + "You can find it here $DATASET_URL"; - - private String groupTitle; - private String datasetId; - private String username; - private String datasetTitle; - private String userFullName; - private DataCatalogue catalogue; - // private String organization; - private List groups; - private HttpServletRequest request; - private String datasetUrl; - private List groupsForceCreation; - - /** - * @param list - * @param groupTitle - * @param datasetId - * @param username - * @param catalogue - */ - public AssociationToGroupAndNotifyThread(List groups, List groupsForceCreation, String groupTitle, String datasetUrl, String datasetId, String datasetTitle, String userFullName, - String username, DataCatalogue catalogue, String organization, HttpServletRequest request) { - this.request = request; - this.groups = groups == null ? new ArrayList() : groups; - this.groupsForceCreation = groupsForceCreation; - this.groupTitle = groupTitle; - this.datasetId = datasetId; - this.username = username; - this.catalogue = catalogue; - // this.organization = organization; - this.datasetTitle = datasetTitle; - this.userFullName = userFullName; - this.datasetUrl = datasetUrl; - } - - @Override - public void run() { - - logger.info("Association thread started to put the dataset with id = "+ datasetId + " into group with title " + groupTitle + " for user " + username); - - // force creation of groups if needed - if(groupsForceCreation != null){ - logger.info("Groups that must be created before association are " + groupsForceCreation); - for (OrganizationBean groupToForce : groupsForceCreation) { - try{ - CkanGroup group = catalogue.createGroup(groupToForce.getName(), groupToForce.getTitle(), ""); - if(group == null) - logger.error("Unable to retrieve or create group with name " + groupToForce); - else - groups.add(new OrganizationBean(group.getTitle(), group.getName(), false, groupToForce.isPropagateUp())); - }catch(Exception e){ - logger.error("Failed to check if a group with this info " + groupToForce + " already exists or can be created"); - } - } - - } - - logger.info("Other groups to which the product should be associate are " + groups); - - if(groups != null) - for (OrganizationBean groupBean : groups) { - boolean putIntoGroup = catalogue.assignDatasetToGroup(groupBean.getName(), datasetId, catalogue.getApiKeyFromUsername(username), groupBean.isPropagateUp()); - logger.info("Was product put into group" + groupBean.getTitle() + "? " + putIntoGroup); - if(putIntoGroup) - notifyGroupAdmins(catalogue, groupBean.getName() ,groupBean.getTitle(), username); - } - - } - - /** - * Send a notification to the group admin(s) about the just added product - * @param username - * @param groupTitle - * @param catalogue - */ - private void notifyGroupAdmins(DataCatalogue catalogue, String groupName, String groupTitle, String username){ - - // get the groups admin - Map> userAndRoles = catalogue.getRolesAndUsersGroup(groupName); - - if(userAndRoles.containsKey(RolesCkanGroupOrOrg.ADMIN)){ - - List admins = userAndRoles.get(RolesCkanGroupOrOrg.ADMIN); - List adminsEmails = new ArrayList(); - - for(int i = 0; i < admins.size(); i++){ - String convertedName = CatalogueUtilMethods.fromCKanUsernameToUsername(admins.get(i)); - admins.set(i, convertedName); - } - - // remove the same user who published the product if he/she is an admin of the group - int indexOfUser = admins.indexOf(username); - if(indexOfUser >= 0) - admins.remove(indexOfUser); - - // further cleaning of the list (for users that are only in ckan... sysadmin for example) - UserManager um = new LiferayUserManager(); - Iterator adminIt = admins.iterator(); - - while (adminIt.hasNext()) { - String admin = (String) adminIt.next(); - try{ - adminsEmails.add(um.getUserByUsername(admin).getEmail()); - }catch(Exception e){ - logger.error("User with username " + admin + " doesn't exist in Liferay"); - adminIt.remove(); - } - } - - logger.info("The list of admins for group " + groupTitle + " is " + admins); - - if(admins.isEmpty()) - return; - - // send the email - EmailNotification mailToSend = new EmailNotification( - adminsEmails, - PRODUCT_ASSOCIATED_TO_GROUP_SUBJECT.replace("$TITLE", datasetTitle).replace("$GROUP", groupTitle), - PRODUCT_ASSOCIATED_TO_GROUP_BODY.replace("$TITLE", datasetTitle).replace("$GROUP", groupTitle).replace("$USER_FULLNAME", userFullName).replace("$DATASET_URL", datasetUrl), - request); - mailToSend.sendEmail(); - - }else - logger.warn("It seems there is no user with role Admin in group " + groupTitle); - } -} +//package org.gcube.portlets.widgets.ckandatapublisherwidget.server.threads; +// +//import java.util.ArrayList; +//import java.util.Iterator; +//import java.util.List; +//import java.util.Map; +// +//import javax.servlet.http.HttpServletRequest; +// +//import org.gcube.common.portal.mailing.EmailNotification; +//import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; +//import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods; +//import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg; +//import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanGroup; +//import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean; +//import org.gcube.vomanagement.usermanagement.UserManager; +//import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; +// +//import com.liferay.portal.kernel.log.Log; +//import com.liferay.portal.kernel.log.LogFactoryUtil; +// +// +// +///** +// * Associate the dataset to a group and send notifications to group's admins. +// * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) +// */ +//public class AssociationToGroupAndNotifyThread extends Thread { +// +// //private static final Logger logger = LoggerFactory.getLogger(AssociationToGroupAndNotifyThread.class); +// private static final Log logger = LogFactoryUtil.getLog(AssociationToGroupAndNotifyThread.class); +// private static final String PRODUCT_ASSOCIATED_TO_GROUP_SUBJECT = "Item $TITLE added to group $GROUP"; +// private static final String PRODUCT_ASSOCIATED_TO_GROUP_BODY = "Dear user,
a new item named '$TITLE' has been " +// + "just published by $USER_FULLNAME in $GROUP .
" +// + "You can find it here $DATASET_URL"; +// +// private String groupTitle; +// private String datasetId; +// private String username; +// private String datasetTitle; +// private String userFullName; +// private DataCatalogue catalogue; +// // private String organization; +// private List groups; +// private HttpServletRequest request; +// private String datasetUrl; +// private List groupsForceCreation; +// +// /** +// * @param list +// * @param groupTitle +// * @param datasetId +// * @param username +// * @param catalogue +// */ +// public AssociationToGroupAndNotifyThread(List groups, List groupsForceCreation, String groupTitle, String datasetUrl, String datasetId, String datasetTitle, String userFullName, +// String username, DataCatalogue catalogue, String organization, HttpServletRequest request) { +// this.request = request; +// this.groups = groups == null ? new ArrayList() : groups; +// this.groupsForceCreation = groupsForceCreation; +// this.groupTitle = groupTitle; +// this.datasetId = datasetId; +// this.username = username; +// this.catalogue = catalogue; +// // this.organization = organization; +// this.datasetTitle = datasetTitle; +// this.userFullName = userFullName; +// this.datasetUrl = datasetUrl; +// } +// +// @Override +// public void run() { +// +// logger.info("Association thread started to put the dataset with id = "+ datasetId + " into group with title " + groupTitle + " for user " + username); +// +// // force creation of groups if needed +// if(groupsForceCreation != null){ +// logger.info("Groups that must be created before association are " + groupsForceCreation); +// for (OrganizationBean groupToForce : groupsForceCreation) { +// try{ +// CkanGroup group = catalogue.createGroup(groupToForce.getName(), groupToForce.getTitle(), ""); +// if(group == null) +// logger.error("Unable to retrieve or create group with name " + groupToForce); +// else +// groups.add(new OrganizationBean(group.getTitle(), group.getName(), false, groupToForce.isPropagateUp())); +// }catch(Exception e){ +// logger.error("Failed to check if a group with this info " + groupToForce + " already exists or can be created"); +// } +// } +// +// } +// +// logger.info("Other groups to which the product should be associate are " + groups); +// +// if(groups != null) +// for (OrganizationBean groupBean : groups) { +// boolean putIntoGroup = catalogue.assignDatasetToGroup(groupBean.getName(), datasetId, groupBean.isPropagateUp()); +// logger.info("Was product put into group" + groupBean.getTitle() + "? " + putIntoGroup); +// if(putIntoGroup) +// notifyGroupAdmins(catalogue, groupBean.getName() ,groupBean.getTitle(), username); +// } +// +// } +// +// /** +// * Send a notification to the group admin(s) about the just added product +// * @param username +// * @param groupTitle +// * @param catalogue +// */ +// private void notifyGroupAdmins(DataCatalogue catalogue, String groupName, String groupTitle, String username){ +// +// // get the groups admin +// Map> userAndRoles = catalogue.getRolesAndUsersGroup(groupName); +// +// if(userAndRoles.containsKey(RolesCkanGroupOrOrg.ADMIN)){ +// +// List admins = userAndRoles.get(RolesCkanGroupOrOrg.ADMIN); +// List adminsEmails = new ArrayList(); +// +// for(int i = 0; i < admins.size(); i++){ +// String convertedName = CatalogueUtilMethods.fromCKanUsernameToUsername(admins.get(i)); +// admins.set(i, convertedName); +// } +// +// // remove the same user who published the product if he/she is an admin of the group +// int indexOfUser = admins.indexOf(username); +// if(indexOfUser >= 0) +// admins.remove(indexOfUser); +// +// // further cleaning of the list (for users that are only in ckan... sysadmin for example) +// UserManager um = new LiferayUserManager(); +// Iterator adminIt = admins.iterator(); +// +// while (adminIt.hasNext()) { +// String admin = (String) adminIt.next(); +// try{ +// adminsEmails.add(um.getUserByUsername(admin).getEmail()); +// }catch(Exception e){ +// logger.error("User with username " + admin + " doesn't exist in Liferay"); +// adminIt.remove(); +// } +// } +// +// logger.info("The list of admins for group " + groupTitle + " is " + admins); +// +// if(admins.isEmpty()) +// return; +// +// // send the email +// EmailNotification mailToSend = new EmailNotification( +// adminsEmails, +// PRODUCT_ASSOCIATED_TO_GROUP_SUBJECT.replace("$TITLE", datasetTitle).replace("$GROUP", groupTitle), +// PRODUCT_ASSOCIATED_TO_GROUP_BODY.replace("$TITLE", datasetTitle).replace("$GROUP", groupTitle).replace("$USER_FULLNAME", userFullName).replace("$DATASET_URL", datasetUrl), +// request); +// mailToSend.sendEmail(); +// +// }else +// logger.warn("It seems there is no user with role Admin in group " + groupTitle); +// } +//} 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 a98593f..8ab084e 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,325 +1,322 @@ -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.GenericUtils; -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 - * @author Costantino Perciante at ISTI-CNR - * (costantino.perciante@isti.cnr.it) - */ -public class WritePostCatalogueManagerThread extends Thread { - - public static final String APPLICATION_ID_CATALOGUE_MANAGER = "org.gcube.datacatalogue.ProductCatalogue"; - private static final String NOTIFICATION_MESSAGE = "Dear members,\n$USER_FULLNAME just published the item '$PRODUCT_TITLE'.\nYou can find it at: $PRODUCT_URL\n"; - 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 String username; - private String scope; - private String productTitle; - private String productUrl; - private boolean enableNotification; - private List hashtags; - private String userFullName; - private String userCurrentUrl; - - /** - * @param token - * @param scope - * @param productTitle - * @param productUrl - * @param enableNotification - * @param hashtags - * @param userFullName - */ - public WritePostCatalogueManagerThread( - String username, String scope, - String productTitle, String productUrl, boolean enableNotification, - List hashtags, String userFullName, String userCurrentUrl) { - super(); - this.username = username; - this.scope = scope; - this.productTitle = productTitle; - this.productUrl = productUrl; - this.enableNotification = enableNotification; - this.hashtags = hashtags; - this.userFullName = userFullName; - this.userCurrentUrl = userCurrentUrl; - } - - @Override - public void run() { - - try{ - // evaluate user's token for this scope - String token = GenericUtils.tryGetElseCreateToken(username, scope); - - if(token == null){ - logger.warn("Unable to proceed, user's token is not available"); - return; - } - - logger.info("Started request to write application post " - + "for new product created. Scope is " + scope + " and " - + "token is " + token.substring(0, 10) + "****************"); - - // set token and scope - ScopeProvider.instance.set(scope); - SecurityTokenProvider.instance.set(token); - - //see Feature #17577 - /*final String profilePageURL = GCubePortalConstants.PREFIX_GROUP_URL + extractOrgFriendlyURL(userCurrentUrl) + GCubePortalConstants.USER_PROFILE_FRIENDLY_URL; - - userFullName = ""+userFullName+ - " "; - */ - - userFullName = "@"+username; - - // write - writeProductPost( - productTitle, - productUrl, - userFullName, - hashtags, - enableNotification - ); - - }catch(Exception e){ - logger.error("Failed to write the post because of the following error ", e); - }finally{ - SecurityTokenProvider.instance.reset(); - ScopeProvider.instance.reset(); - } - } - - public static String extractOrgFriendlyURL(String portalURL) { - String groupRegEx = "/group/"; - if (portalURL.contains(groupRegEx)) { - String[] splits = portalURL.split(groupRegEx); - String friendlyURL = splits[1]; - if (friendlyURL.contains("/")) { - friendlyURL = friendlyURL.split("/")[0]; - } else { - friendlyURL = friendlyURL.split("\\?")[0].split("\\#")[0]; - } - return "/"+friendlyURL; - } - return null; - } - - /** - * 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(); - - 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{ - - JSONObject request = new JSONObject(); - request.put("app_id", APPLICATION_ID_CATALOGUE_MANAGER); - HttpResponse response = performRequest(client, path, request.toJSONString()); - - 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 - } - - JSONObject request = new JSONObject(); - request.put("text", message); - request.put("enable_notification", enablePostNotification); - logger.info("The post that is going to be written is ->\n" + request.toJSONString()); - HttpResponse response = performRequest(client, path, request.toJSONString()); - 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 write the post ", 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 +//package org.gcube.portlets.widgets.ckandatapublisherwidget.server.threads; +// +//import java.io.IOException; +//import java.net.HttpURLConnection; +//import java.util.List; +// +//import org.apache.http.HttpEntity; +//import org.apache.http.HttpResponse; +//import org.apache.http.client.ClientProtocolException; +//import org.apache.http.client.methods.HttpPost; +//import org.apache.http.entity.StringEntity; +//import org.apache.http.impl.client.CloseableHttpClient; +//import org.apache.http.impl.client.HttpClientBuilder; +//import org.apache.http.util.EntityUtils; +//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.GenericUtils; +// +//import com.google.gwt.json.client.JSONParser; +//import com.liferay.portal.kernel.log.Log; +//import com.liferay.portal.kernel.log.LogFactoryUtil; +// +// +///** +// * Let the Product Catalogue Manager write a post in a VRE and alert there is a new product +// * @author Costantino Perciante at ISTI-CNR +// * (costantino.perciante@isti.cnr.it) +// */ +//public class WritePostCatalogueManagerThread extends Thread { +// +// public static final String APPLICATION_ID_CATALOGUE_MANAGER = "org.gcube.datacatalogue.ProductCatalogue"; +// private static final String NOTIFICATION_MESSAGE = "Dear members,\n$USER_FULLNAME just published the item '$PRODUCT_TITLE'.\nYou can find it at: $PRODUCT_URL\n"; +// 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 String username; +// private String scope; +// private String productTitle; +// private String productUrl; +// private boolean enableNotification; +// private List hashtags; +// private String userFullName; +// private String userCurrentUrl; +// +// /** +// * @param token +// * @param scope +// * @param productTitle +// * @param productUrl +// * @param enableNotification +// * @param hashtags +// * @param userFullName +// */ +// public WritePostCatalogueManagerThread( +// String username, String scope, +// String productTitle, String productUrl, boolean enableNotification, +// List hashtags, String userFullName, String userCurrentUrl) { +// super(); +// this.username = username; +// this.scope = scope; +// this.productTitle = productTitle; +// this.productUrl = productUrl; +// this.enableNotification = enableNotification; +// this.hashtags = hashtags; +// this.userFullName = userFullName; +// this.userCurrentUrl = userCurrentUrl; +// } +// +// @Override +// public void run() { +// +// try{ +// // evaluate user's token for this scope +// String token = GenericUtils.tryGetElseCreateToken(username, scope); +// +// if(token == null){ +// logger.warn("Unable to proceed, user's token is not available"); +// return; +// } +// +// logger.info("Started request to write application post " +// + "for new product created. Scope is " + scope + " and " +// + "token is " + token.substring(0, 10) + "****************"); +// +// // set token and scope +// ScopeProvider.instance.set(scope); +// SecurityTokenProvider.instance.set(token); +// +// //see Feature #17577 +// /*final String profilePageURL = GCubePortalConstants.PREFIX_GROUP_URL + extractOrgFriendlyURL(userCurrentUrl) + GCubePortalConstants.USER_PROFILE_FRIENDLY_URL; +// +// userFullName = ""+userFullName+ +// " "; +// */ +// +// userFullName = "@"+username; +// +// // write +// writeProductPost( +// productTitle, +// productUrl, +// userFullName, +// hashtags, +// enableNotification +// ); +// +// }catch(Exception e){ +// logger.error("Failed to write the post because of the following error ", e); +// }finally{ +// SecurityTokenProvider.instance.reset(); +// ScopeProvider.instance.reset(); +// } +// } +// +// public static String extractOrgFriendlyURL(String portalURL) { +// String groupRegEx = "/group/"; +// if (portalURL.contains(groupRegEx)) { +// String[] splits = portalURL.split(groupRegEx); +// String friendlyURL = splits[1]; +// if (friendlyURL.contains("/")) { +// friendlyURL = friendlyURL.split("/")[0]; +// } else { +// friendlyURL = friendlyURL.split("\\?")[0].split("\\#")[0]; +// } +// return "/"+friendlyURL; +// } +// return null; +// } +// +// /** +// * 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(); +// +// 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{ +// +// JSONObject request = new JSONObject(); +// request.put("app_id", APPLICATION_ID_CATALOGUE_MANAGER); +// HttpResponse response = performRequest(client, path, request.toJSONString()); +// +// 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 +// } +// +// JSONObject request = new JSONObject(); +// request.put("text", message); +// request.put("enable_notification", enablePostNotification); +// logger.info("The post that is going to be written is ->\n" + request.toJSONString()); +// HttpResponse response = performRequest(client, path, request.toJSONString()); +// 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 write the post ", 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/CatalogueRoleManager.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/CatalogueRoleManager.java index 1c1ca35..120d8b8 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/CatalogueRoleManager.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/utils/CatalogueRoleManager.java @@ -6,6 +6,7 @@ import java.util.Set; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg; +import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanOrganization; import org.gcube.portlets.widgets.ckandatapublisherwidget.server.CKANPublisherServicesImpl; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean; import org.gcube.vomanagement.usermanagement.GroupManager; @@ -23,8 +24,6 @@ import org.gcube.vomanagement.usermanagement.model.GatewayRolesNames; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; -import eu.trentorise.opendata.jackan.model.CkanOrganization; - /** * Facilities to check roles into the catalogue. */