GRSF management facility has been moved into a dedicated widget. At most one organization plus a role is sent to the ckan connector. The others, if any, will be managed by the portlet/widget itself.

git-svn-id: http://svn.d4science-ii.research-infrastructures.eu/gcube/trunk/portlets/user/gcube-ckan-datacatalog@141844 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Costantino Perciante 2017-01-26 17:47:46 +00:00
parent c793a06e5b
commit 7a05901a47
18 changed files with 132 additions and 939 deletions

View File

@ -33,5 +33,6 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/grsf-manage-widget"/>
<classpathentry kind="output" path="target/gcube-ckan-datacatalog-1.2.0-SNAPSHOT/WEB-INF/classes"/>
</classpath>

View File

@ -4,9 +4,6 @@
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<dependent-module archiveName="ckan-metadata-publisher-widget-1.2.0-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/ckan-metadata-publisher-widget/ckan-metadata-publisher-widget">
<dependency-type>uses</dependency-type>
</dependent-module>
<property name="context-root" value="gcube-ckan-datacatalog"/>
<property name="java-output-path" value="/gcube-ckan-datacatalog/target/gcube-ckan-datacatalog-1.0.0-SNAPSHOT/WEB-INF/classes"/>
</wb-module>

View File

@ -90,6 +90,11 @@
<!-- END FWS -->
<!-- Metadata publisher widget -->
<dependency>
<groupId>org.gcube.portlets.widgets</groupId>
<artifactId>grsf-manage-widget</artifactId>
<version>[1.0.0-SNAPSHOT,2.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.portlets.widgets</groupId>
<artifactId>ckan-metadata-publisher-widget</artifactId>

View File

@ -21,6 +21,8 @@
<!-- Inherits widget -->
<inherits
name='org.gcube.portlets.widgets.ckandatapublisherwidget.CKanMetadataPublisher' />
<inherits
name='org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidget' />
<inherits
name='org.gcube.datacatalogue.ckanutillibrary.CkanUtilLibrary' />
<inherits name='org.gcube.portlets.user.gcubewidgets.WidgetFactory' />

View File

@ -1,6 +1,7 @@
package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client;
import org.gcube.datacatalogue.grsf_manage_widget.client.view.ManageProductWidget;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.event.EditMetadataEvent;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.event.EditMetadataEventHandler;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.event.IFrameInstanciedEvent;
@ -21,7 +22,6 @@ import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.event.ShowOrgani
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.event.ShowOrganizationsEventHandler;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.event.ShowStatisticsEvent;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.event.ShowStatisticsEventHandler;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.ui.ManageProductWidget;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.view.GCubeCkanDataCatalogPanel;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.CkanConnectorAccessPoint;
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.CloseCreationFormEvent;
@ -199,10 +199,7 @@ public class CkanEventHandlerManager {
@Override
public void onShowManageProductWidget(ShowManageProductWidgetEvent event) {
new ManageProductWidget(event.getProductIdentifier());
}
});
}

View File

@ -5,7 +5,6 @@ import java.util.List;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.BeanUserInOrgGroupRole;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.CkanConnectorAccessPoint;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ManageProductBean;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@ -80,17 +79,4 @@ public interface GcubeCkanDataCatalogService extends RemoteService {
* @return
*/
boolean isManageProductEnabled();
/**
* Notify product update
*/
String notifyProductUpdate(ManageProductBean bean);
/**
* Get the product bean from the product identifier
* @param identifier
* @return ManageProductBean
* @throws Exception
*/
ManageProductBean getProductBeanById(String identifier) throws Exception;
}

View File

@ -8,7 +8,6 @@ import java.util.List;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.BeanUserInOrgGroupRole;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.CkanConnectorAccessPoint;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ManageProductBean;
import com.google.gwt.user.client.rpc.AsyncCallback;
@ -85,13 +84,4 @@ public interface GcubeCkanDataCatalogServiceAsync {
* @return
*/
void isManageProductEnabled(AsyncCallback<Boolean> callback);
/**
* Notify product update
*/
void notifyProductUpdate(ManageProductBean bean,
AsyncCallback<String> callback);
void getProductBeanById(String identifier,
AsyncCallback<ManageProductBean> callback);
}

View File

@ -1,234 +0,0 @@
package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogServiceAsync;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.GRSFStatus;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ManageProductBean;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ex.NoGRSFRecordException;
import com.github.gwtbootstrap.client.ui.AlertBlock;
import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.ControlGroup;
import com.github.gwtbootstrap.client.ui.Form;
import com.github.gwtbootstrap.client.ui.Icon;
import com.github.gwtbootstrap.client.ui.Image;
import com.github.gwtbootstrap.client.ui.ListBox;
import com.github.gwtbootstrap.client.ui.Modal;
import com.github.gwtbootstrap.client.ui.TextArea;
import com.github.gwtbootstrap.client.ui.TextBox;
import com.github.gwtbootstrap.client.ui.constants.AlertType;
import com.github.gwtbootstrap.client.ui.constants.ControlGroupType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.SelectElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget;
public class ManageProductWidget extends Composite{
private static GcubeCkanDataCatalogServiceAsync service = GWT.create(GcubeCkanDataCatalogService.class);
private static ManageProductWidgetUiBinder uiBinder = GWT
.create(ManageProductWidgetUiBinder.class);
interface ManageProductWidgetUiBinder extends
UiBinder<Widget, ManageProductWidget> {
}
@UiField
Modal manageProductModal;
@UiField
AlertBlock infoBlock;
@UiField
TextBox nameTextBox;
@UiField
TextBox currentStatus;
@UiField
ListBox listBoxStatus;
@UiField
TextArea annotationArea;
@UiField
Button cancelButton;
@UiField
Button confirmButton;
@UiField
Icon loaderIcon;
@UiField
ControlGroup listBoxStatusGroup;
@UiField
Form formUpdate;
@UiField
TextBox productType;
@UiField
Image loadingImage;
public static final String LOADING_IMAGE_URL = GWT.getModuleBaseURL() + "../images/loader.gif";
private final static List<GRSFStatus> STATUS = new ArrayList<GRSFStatus>(Arrays.asList(GRSFStatus.values()));
private final static String STATUS_UPDATE_SUCCESS = "The product was correctly updated. Thanks for your collaboration!";
private final static String STATUS_UPDATE_ERROR = "Sorry, there was a problem while trying to update the status of this product";
protected static final String ERROR_ON_RETRIEVING_BEAN = "It seems there was a problem while contacting the service...";
protected static final String NO_GRSF_RECORD_BEAN = "This record is not a GRSF record, thus it cannot be managed";
private ManageProductBean bean;
public ManageProductWidget(String productIdentifier) {
initWidget(uiBinder.createAndBindUi(this));
if(productIdentifier == null || productIdentifier.isEmpty()){
GWT.log("The received product identifier is null..");
return;
}
GWT.log("Product identifier is " + productIdentifier);
// start loader service
loadingImage.setUrl(LOADING_IMAGE_URL);
loadingImage.setVisible(true);
// async request to fetch the product
retrieveProductBean(productIdentifier);
manageProductModal.show();
}
private void retrieveProductBean(String productIdentifier) {
service.getProductBeanById(productIdentifier, new AsyncCallback<ManageProductBean>() {
@Override
public void onSuccess(ManageProductBean result) {
if(result != null){
bean = result;
annotationArea.setText("");
infoBlock.setVisible(false);
nameTextBox.setText(bean.getProductName());
currentStatus.setText(bean.getCurrentStatus().toString());
productType.setText(bean.getProductType());
List<GRSFStatus> statusToShow = new ArrayList<GRSFStatus>(STATUS);
statusToShow.remove(bean.getCurrentStatus());
listBoxStatus.addItem("Select the new status");
listBoxStatus.getElement().<SelectElement>cast().getOptions().getItem(0).setDisabled(true);
for (GRSFStatus availableStatus : statusToShow) {
listBoxStatus.addItem(availableStatus.toString());
}
listBoxStatus.setSelectedIndex(0);
}
else{
showInfo(ERROR_ON_RETRIEVING_BEAN, AlertType.ERROR);
formUpdate.setVisible(false);
confirmButton.setEnabled(false);
}
loadingImage.setVisible(false);
}
@Override
public void onFailure(Throwable caught) {
if(caught instanceof NoGRSFRecordException)
showInfo(NO_GRSF_RECORD_BEAN, AlertType.WARNING);
else
showInfo(caught.getMessage(), AlertType.ERROR);
// hide the form and disable the send button
formUpdate.setVisible(false);
confirmButton.setEnabled(false);
loadingImage.setVisible(false);
}
});
}
@UiHandler("cancelButton")
void onCancelButton(ClickEvent ce){
manageProductModal.hide();
}
@UiHandler("confirmButton")
void onSaveButton(ClickEvent ce){
if(bean == null)
return;
listBoxStatusGroup.setType(ControlGroupType.NONE);
if(listBoxStatus.getSelectedIndex() <= 0){
listBoxStatusGroup.setType(ControlGroupType.ERROR);
return;
}
manageProductModal.setCloseVisible(false);
cancelButton.setEnabled(false);
confirmButton.setEnabled(false);
loaderIcon.setVisible(true);
// set new values
bean.setAnnotation(new HTML(annotationArea.getText().trim()).getText());
bean.setNewStatus(GRSFStatus.fromString(listBoxStatus.getSelectedItemText()));
service.notifyProductUpdate(bean, new AsyncCallback<String>() {
@Override
public void onSuccess(String result) {
if(result == null){
showInfo(STATUS_UPDATE_SUCCESS, AlertType.SUCCESS);
confirmButton.removeFromParent();
formUpdate.setVisible(false);
}else{
showInfo(STATUS_UPDATE_ERROR + "(" + result + ")", AlertType.ERROR);
confirmButton.setEnabled(true);
}
manageProductModal.setCloseVisible(true);
cancelButton.setEnabled(true);
loaderIcon.setVisible(false);
}
@Override
public void onFailure(Throwable caught) {
manageProductModal.setCloseVisible(true);
cancelButton.setEnabled(true);
confirmButton.setEnabled(true);
loaderIcon.setVisible(false);
showInfo(STATUS_UPDATE_ERROR, AlertType.ERROR);
}
});
}
/**
* Show information
* @param statusUpdateError
*/
protected void showInfo(String statusUpdateError, AlertType type) {
infoBlock.setText(statusUpdateError);
infoBlock.setType(type);
infoBlock.setVisible(true);
}
}

View File

@ -1,92 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:b="urn:import:com.github.gwtbootstrap.client.ui">
<ui:style>
.loader-image {
display: block;
margin: auto auto;
}
</ui:style>
<g:HTMLPanel>
<b:Modal ui:field="manageProductModal" title="Manage product"
backdrop="STATIC" keyboard="true" animation="true" closeVisible="true">
<g:VerticalPanel width="100%">
<!-- Loader image at the beginning -->
<b:Image ui:field="loadingImage" styleName="{style.loader-image}"
visible="true"></b:Image>
<!-- Alert blocks for info/errors -->
<b:AlertBlock type="INFO" close="false" animation="true"
visible="false" ui:field="infoBlock"></b:AlertBlock>
<b:Form type="VERTICAL" visible="true" ui:field="formUpdate" width="100%">
<b:ControlGroup ui:field="productTitleGroup">
<b:ControlLabel for="name" title="Product name">
<b>Product Name:</b>
</b:ControlLabel>
<b:Controls>
<b:TextBox alternateSize="LARGE" placeholder="Product name"
enabled="false" width="97%" b:id="name" title="Product name"
ui:field="nameTextBox" />
</b:Controls>
</b:ControlGroup>
<b:ControlGroup ui:field="currentStatusGroup">
<b:ControlLabel for="currentStatus"
title="The current status of this product">
<b>Product Current Status:</b></b:ControlLabel>
<b:Controls>
<b:TextBox b:id="currentStatus" alternateSize="LARGE"
enabled="false" width="97%" title="The current status of this product"
ui:field="currentStatus">
</b:TextBox>
</b:Controls>
</b:ControlGroup>
<b:ControlGroup ui:field="listBoxStatusGroup">
<b:ControlLabel for="listboxStatus"
title="The new status of this product">
<b>Product New Status:</b></b:ControlLabel>
<b:Controls>
<b:ListBox b:id="listboxStatus" alternateSize="LARGE"
width="97%" title="Select a new status" enabled="true"
ui:field="listBoxStatus"></b:ListBox>
</b:Controls>
</b:ControlGroup>
<b:ControlGroup ui:field="productTypeGroup">
<b:ControlLabel for="productType"
title="The product type">
<b>Product Type:</b></b:ControlLabel>
<b:Controls>
<b:TextBox b:id="productType" alternateSize="LARGE"
width="97%" title="The product type" enabled="false" ui:field="productType"></b:TextBox>
</b:Controls>
</b:ControlGroup>
<b:ControlGroup ui:field="annotationAreaGroup">
<b:ControlLabel for="annotation"
title="An annotation message to send along the update">
<b>Annotation:</b></b:ControlLabel>
<b:Controls>
<b:TextArea b:id="annotation" alternateSize="LARGE"
placeholder="Add an annotation message" enabled="true" width="97%"
title="An annotation message to send along the update" ui:field="annotationArea"></b:TextArea>
</b:Controls>
</b:ControlGroup>
</b:Form>
</g:VerticalPanel>
<b:ModalFooter>
<!-- Gear to wait while application tokens are retrieved -->
<b:Icon type="GEAR" spin="true" ui:field="loaderIcon"
visible="false" />
<b:Button ui:field="cancelButton">Cancel</b:Button>
<b:Button icon="FILE" type="PRIMARY" ui:field="confirmButton">Send</b:Button>
</b:ModalFooter>
</b:Modal>
</g:HTMLPanel>
</ui:UiBinder>

View File

@ -110,25 +110,6 @@ public class GCubeCkanDataCatalogPanel extends BaseViewTemplate {
}
else {
/**
* Just check if it is enabled.. then we need to listen for dom events coming
*/
GCubeCkanDataCatalog.service.isManageProductEnabled(new AsyncCallback<Boolean>() {
@Override
public void onSuccess(Boolean result) {
isManageProductToShow = result;
managementPanel.showManageProductButton(isManageProductToShow);
}
@Override
public void onFailure(Throwable caught) {
isManageProductToShow = false;
managementPanel.showManageProductButton(isManageProductToShow);
}
});
// MANAGE CKAN MANAGEMENT PANEL ACCORDING TO MY ROLE
GCubeCkanDataCatalog.service.getMyRole(new AsyncCallback<RolesCkanGroupOrOrg>() {
@ -186,6 +167,25 @@ public class GCubeCkanDataCatalogPanel extends BaseViewTemplate {
}
});
/**
* Just check if it is enabled.. then we need to listen for dom events coming
*/
GCubeCkanDataCatalog.service.isManageProductEnabled(new AsyncCallback<Boolean>() {
@Override
public void onSuccess(Boolean result) {
isManageProductToShow = result;
managementPanel.showManageProductButton(isManageProductToShow);
}
@Override
public void onFailure(Throwable caught) {
isManageProductToShow = false;
managementPanel.showManageProductButton(isManageProductToShow);
}
});
}
}

View File

@ -18,12 +18,8 @@ import org.gcube.datacatalogue.ckanutillibrary.server.utils.SessionCatalogueAttr
import org.gcube.datacatalogue.ckanutillibrary.server.utils.UtilMethods;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.manage.GRSFNotificationService;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.BeanUserInOrgGroupRole;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.CkanConnectorAccessPoint;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.GRSFStatus;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ManageProductBean;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ex.NoGRSFRecordException;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.GroupBean;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean;
import org.gcube.vomanagement.usermanagement.GroupManager;
@ -35,7 +31,6 @@ import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import eu.trentorise.opendata.jackan.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
/**
@ -55,7 +50,6 @@ public class GcubeCkanDataCatalogServiceImpl extends RemoteServiceServlet implem
private static final String HTTP = "http";
public static String CKANCONNECTORCONTEXT = "CkanConnectorContext";
public static String CKANCONNECTORLOGOUT = "CkanConnectorLogout";
public static final String GRSF_UPDATER_SERVICE = "GRSFUpdaterEndPoint";
private static final String GRSF_ADMIN_ROLE = "GRSF-Admin";
//private static Logger logger = LoggerFactory.getLogger(GcubeCkanDataCatalogServiceImpl.class);
private static final Log logger = LogFactoryUtil.getLog(GcubeCkanDataCatalogServiceImpl.class);
@ -167,7 +161,10 @@ public class GcubeCkanDataCatalogServiceImpl extends RemoteServiceServlet implem
}
// retrieve the list of VREs to whom the user belongs
Map<String, String> roleForVre = UserUtil.getVreRoleForUser(SessionUtil.getCurrentUser(getThreadLocalRequest()).getEmail(), scopePerCurrentUrl);
Map<String, String> roleForVre = UserUtil.getVreRoleForUser(
SessionUtil.getCurrentUser(getThreadLocalRequest()).getEmail(),
scopePerCurrentUrl,
getCatalogue(scopePerCurrentUrl));
ckan.addListOfVREs(roleForVre);
return ckan;
@ -549,68 +546,4 @@ public class GcubeCkanDataCatalogServiceImpl extends RemoteServiceServlet implem
}
}
@Override
public String notifyProductUpdate(ManageProductBean bean) {
logger.info("Creating notification for the bean " + bean + " to send to the knowledge base");
try{
String context = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest());
DataCatalogue catalogue = getCatalogue(context);
// check if the base url of the service is in session
String keyPerContext = UtilMethods.concatenateSessionKeyScope(GRSF_UPDATER_SERVICE, context);
String baseUrl = (String)getThreadLocalRequest().getSession().getAttribute(keyPerContext);
if(baseUrl == null || baseUrl.isEmpty()){
baseUrl = GRSFNotificationService.discoverEndPoint(context);
getThreadLocalRequest().getSession().setAttribute(keyPerContext, baseUrl);
}
return GRSFNotificationService.updateCatalogueRecord(baseUrl, bean, catalogue, SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername());
}catch(Exception e){
logger.error("Unable to update the product.." + e.getMessage());
return e.getMessage();
}
}
@Override
public ManageProductBean getProductBeanById(String productIdentifier) throws Exception {
ManageProductBean toReturn = null;
// retrieve scope per current portlet url
String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest());
DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl);
String username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername();
CkanDataset product = catalogue.getDataset(productIdentifier, catalogue.getApiKeyFromUsername(username));
// get extras
Map<String, String> extras = product.getExtrasAsHashMap();
String status = extras.get("Status");
String uuidKB = extras.get("UUID Knowledge Base");
String productType = extras.get("Product type");
String recordType = extras.get("Record type");
String title = product.getTitle();
// it cannot be enabled in this case ...
if(recordType == null || recordType.equals("Source"))
throw new NoGRSFRecordException("This is not a GRSF record");
if(status == null || uuidKB == null || productType == null)
throw new Exception("Some information is missing in this record: Status = " + status + ", knowledge_base_uuid = " + uuidKB +
", and product type is = " + productType);
toReturn = new ManageProductBean();
toReturn.setCatalogueIdentifier(productIdentifier);
toReturn.setCurrentStatus(GRSFStatus.fromString(status));
toReturn.setKnowledgeBaseIdentifier(uuidKB);
toReturn.setProductName(title);
toReturn.setProductType(productType);
logger.info("Returning product bean " + toReturn);
return toReturn;
}
}

View File

@ -10,6 +10,7 @@ import java.util.Map;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.thread.AddUserToOrganizationThread;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean;
import org.gcube.vomanagement.usermanagement.GroupManager;
import org.gcube.vomanagement.usermanagement.RoleManager;
@ -48,12 +49,13 @@ public class UserUtil {
* @param userEMail the user e mail
* @return the list vre for user
*/
public static Map<String, String> getVreRoleForUser(String userEMail, String context){
public static Map<String, String> getVreRoleForUser(String userEMail, String context, DataCatalogue instance){
GroupManager groupManager = new LiferayGroupManager();
UserManager userManager = new LiferayUserManager();
RoleManager roleManager = new LiferayRoleManager();
Map<String, String> mapRoleByGroup = new HashMap<String, String>();
Map<String, String> mapRoleByGroupSingleVre = new HashMap<String, String>();
Map<String, String> mapRoleByGroupExtrasVre = new HashMap<String, String>();
GCubeUser user;
try {
user = userManager.getUserByEmail(userEMail);
@ -64,47 +66,46 @@ public class UserUtil {
GCubeGroup groupContext = groupManager.getGroup(groupIdContext);
Iterator<GCubeGroup> iterator = listOfGroups.iterator();
if(groupManager.isVRE(groupIdContext)){
long parentId = groupContext.getParentGroupId();
while (iterator.hasNext()) {
GCubeGroup gCubeGroup = (GCubeGroup) iterator.next();
if(gCubeGroup.getParentGroupId() != parentId)
iterator.remove();
}
}else if(groupManager.isVO(groupIdContext)){
// get the list of vres
while (iterator.hasNext()) {
GCubeGroup gCubeGroup = (GCubeGroup) iterator.next();
if(groupIdContext != gCubeGroup.getParentGroupId())
iterator.remove();
}
}else{
// only the vres
while (iterator.hasNext()) {
GCubeGroup gCubeGroup = (GCubeGroup) iterator.next();
if(!groupManager.isVRE(gCubeGroup.getGroupId()))
iterator.remove();
}
}
// retrieve the role
for (GCubeGroup vre: listOfGroups) {
mapRoleByGroup.put(vre.getGroupName().toLowerCase(),
RolesCkanGroupOrOrg.convertToCkanCapacity(getLiferayHighestRoleInOrg(roleManager.listRolesByUserAndGroup(user.getUserId(), vre.getGroupId()))));
if(vre.getGroupId() == groupIdContext)
mapRoleByGroupSingleVre.put(vre.getGroupName().toLowerCase(),
RolesCkanGroupOrOrg.convertToCkanCapacity(getLiferayHighestRoleInOrg(roleManager.listRolesByUserAndGroup(user.getUserId(), vre.getGroupId()))));
else
mapRoleByGroupExtrasVre.put(vre.getGroupName().toLowerCase(),
RolesCkanGroupOrOrg.convertToCkanCapacity(getLiferayHighestRoleInOrg(roleManager.listRolesByUserAndGroup(user.getUserId(), vre.getGroupId()))));
}
logger.debug("Returning Map : " + mapRoleByGroup);
return mapRoleByGroup;
// schedule the thread for the groups other than the vre to be checked in the local ckan instance
new AddUserToOrganizationThread(
instance,
userManager.getUserByEmail(userEMail).getUsername(),
mapRoleByGroupExtrasVre).
start();
logger.debug("Returning Map to the ckan connector : " + mapRoleByGroupSingleVre);
return mapRoleByGroupSingleVre;
}catch (UserManagementSystemException | UserRetrievalFault | GroupRetrievalFault e) {
logger.error("An error occurred during get list of VREs for user: "+userEMail, e);
return null;
@ -150,6 +151,9 @@ public class UserUtil {
for (GCubeGroup gCubeGroup : groups) {
if(!groupManager.isVRE(gCubeGroup.getGroupId()))
continue;
// get the name of this group
String gCubeGroupName = gCubeGroup.getGroupName();
@ -209,9 +213,9 @@ public class UserUtil {
// get highest role
RolesCkanGroupOrOrg correspondentRoleToCheck = getLiferayHighestRoleInOrg(roles);
// be sure it is so
checkIfRoleIsSetInCkanInstance(username, groupName, currentGroupId,
correspondentRoleToCheck, groupManager, gcubeCkanDataCatalogServiceImpl, orgsInWhichAtLeastEditorRole);
// the ckan connector already did the job for us
// checkIfRoleIsSetInCkanInstance(username, groupName, currentGroupId,
// correspondentRoleToCheck, groupManager, gcubeCkanDataCatalogServiceImpl, orgsInWhichAtLeastEditorRole);
toReturn = correspondentRoleToCheck;
@ -253,16 +257,12 @@ public class UserUtil {
if(res && !correspondentRoleToCheck.equals(RolesCkanGroupOrOrg.MEMBER)){
// get the orgs of the user and retrieve its title and name
List<CkanOrganization> ckanOrgs = catalogue.getOrganizationsByUser(username);
for (CkanOrganization ckanOrganization : ckanOrgs) {
if(ckanOrganization.getName().equals(gCubeGroupName.toLowerCase())){
orgsInWhichAtLeastEditorRole.add(new OrganizationBean(ckanOrganization.getTitle(), ckanOrganization.getName()));
break;
}
}
CkanOrganization organization = catalogue.getOrganizationByName(gCubeGroupName.toLowerCase());
orgsInWhichAtLeastEditorRole.add(new OrganizationBean(organization.getTitle(), organization.getName()));
}
}else
logger.error("It seems there is no ckan instance into scope " + groupManager.getInfrastructureScope(groupId));
}
else
logger.warn("It seems there is no ckan instance into scope " + groupManager.getInfrastructureScope(groupId));
}

View File

@ -1,281 +0,0 @@
package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.manage;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ManageProductBean;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
import org.json.simple.JSONArray;
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.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.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanPair;
import eu.trentorise.opendata.jackan.model.CkanTag;
/**
* Endpoint for sending update records information to GRSF KB
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class GRSFNotificationService {
//private static Logger logger = LoggerFactory.getLogger(GRSFNotificationService.class);
private static final Log logger = LogFactoryUtil.getLog(GRSFNotificationService.class);
private static final String SERVICE_POST_METHOD = "/service/updater/post";
private static final String ANNOTATION_KEY = "Annotation on update";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final String STATUS_CUSTOM_FIELD_KEY = "Status";
private static final int MAX_TRIAL = 5;
// request post fields
private static final String CATALOGUE_ID = "catalog_id";
private static final String KB_ID = "record_id";
private static final String PRODUCT_TYPE = "type";
private static final String STATUS = "status";
private static final String ANNOTATION = "annotation_msg";
private static final String ERROR = "error";
// the error of the update on success
private static final int STATUS_SUCCESS = 200;
// GRSF update service information
private static final String SERVICE_NAME = "GRSF Updater";
private static final String SERVICE_CATEGORY = "Service";
/**
* Discover the service endpoint and return its url
* @param context
* @return the url of the service on success, null otherwise
*/
public static String discoverEndPoint(String context){
String oldContext = ScopeProvider.instance.get();
ScopeProvider.instance.set(context);
String toReturn = null;
try{
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Name/text() eq '"+ SERVICE_NAME +"'");
query.addCondition("$resource/Profile/Category/text() eq '"+ SERVICE_CATEGORY +"'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> resources = client.submit(query);
if (resources.size() == 0){
logger.error("There is no Runtime Resource having name " + SERVICE_NAME +" and Category " + SERVICE_CATEGORY + " in this scope.");
throw new Exception("There is no Runtime Resource having name " + SERVICE_NAME +" and Category " + SERVICE_CATEGORY + " in this scope.");
}
else {
for (ServiceEndpoint res : resources) {
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = (ServiceEndpoint.AccessPoint) accessPointIterator
.next();
// return the path
toReturn = accessPoint.address();
}
}
}
}catch(Exception e){
logger.error("Unable to retrieve such service endpoint information!", e);
}finally{
if(oldContext != null && !oldContext.equals(context))
ScopeProvider.instance.set(oldContext);
}
return toReturn;
}
/**
* Send an update for this bean
* @param baseUrl
* @param bean
* @param username
* @param catalogue
* @return true on success, false otherwise
*/
@SuppressWarnings("unchecked")
public static String updateCatalogueRecord(String serviceUrl, ManageProductBean bean, DataCatalogue catalogue, String username){
if(serviceUrl == null)
throw new IllegalArgumentException("GRSF Updater service url cannot be null");
if(bean == null)
throw new IllegalArgumentException("Product bean to manage cannot be null");
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
JSONObject obj = new JSONObject();
obj.put(CATALOGUE_ID, bean.getCatalogueIdentifier());
obj.put(KB_ID, bean.getKnowledgeBaseIdentifier());
obj.put(PRODUCT_TYPE, bean.getProductType().toLowerCase());
obj.put(STATUS, bean.getNewStatus().toString().toLowerCase());
String annotation = bean.getAnnotation();
if(annotation != null)
obj.put(ANNOTATION, annotation.replaceAll("\"", ""));
logger.debug("Update request looks like " + obj.toJSONString());
HttpPost request = new HttpPost(serviceUrl + SERVICE_POST_METHOD);
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
StringEntity params = new StringEntity(obj.toJSONString());
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
String result = EntityUtils.toString(response.getEntity());
JSONParser parser = new JSONParser();
JSONObject parsedJSON = (JSONObject)parser.parse(result);
if(response.getStatusLine().getStatusCode() != STATUS_SUCCESS)
throw new IllegalArgumentException(
"Error while performing the update request: " + response.getStatusLine().getReasonPhrase() +
"and error in the result bean is " + parsedJSON.get(ERROR));
// patch the catalogue product
return patchProduct(catalogue, bean, username);
}catch(Exception e){
logger.error("Unable to update this record" + e.getMessage());
return e.getMessage();
}
}
/**
* Patch the product
* @param catalogue
* @param bean
* @param username
*/
@SuppressWarnings("unchecked")
private static String patchProduct(DataCatalogue catalogue,
ManageProductBean bean, String username) {
logger.info("Going to patch record in the catalogue with identifier " + bean.getCatalogueIdentifier() +
" from user " + username);
String apiKey = catalogue.getApiKeyFromUsername(username);
CkanDataset dataset = catalogue.getDataset(bean.getCatalogueIdentifier(), apiKey);
String errorMessage = null;
for (int i = 0; i < MAX_TRIAL; i++) {
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
JSONObject jsonRequest = new JSONObject();
JSONArray tagsAsJson = new JSONArray();
JSONArray groupsAsJson = new JSONArray();
JSONArray customFieldsAsJson = new JSONArray();
// manage the custom fields
List<CkanPair> extras = dataset.getExtras();
for (CkanPair ckanPair : extras) {
if(ckanPair.getKey().equals(STATUS_CUSTOM_FIELD_KEY) && ckanPair.getValue().equals(bean.getCurrentStatus().toString()))
continue;
JSONObject obj = new JSONObject();
obj.put("key", ckanPair.getKey());
obj.put("value", ckanPair.getValue());
customFieldsAsJson.add(obj);
}
// add the new one and the annotation message
JSONObject newStatus = new JSONObject();
newStatus.put("key", STATUS_CUSTOM_FIELD_KEY);
newStatus.put("value", bean.getNewStatus().toString());
customFieldsAsJson.add(newStatus);
JSONObject newAnnotation = new JSONObject();
newAnnotation.put("key", ANNOTATION_KEY);
newAnnotation.put("value", "date: " + DATE_FORMAT.format(new Date())
+ ", admin: " + new LiferayUserManager().getUserByUsername(username).getFullname()
+ ", message: " + (bean.getAnnotation() != null ? bean.getAnnotation().replaceAll("\"", "") : "none")
+ ", old status: " + bean.getCurrentStatus().toString()
+ ", new status: " + bean.getNewStatus().toString()
);
customFieldsAsJson.add(newAnnotation);
// manage the tags
List<CkanTag> tags = dataset.getTags();
for(CkanTag ckanTag : tags){
if(!ckanTag.getName().equals(bean.getCurrentStatus().toString())){
JSONObject obj = new JSONObject();
obj.put("vocabulary_id", ckanTag.getVocabularyId());
obj.put("state", ckanTag.getState().toString());
obj.put("display_name", ckanTag.getDisplayName());
obj.put("id", ckanTag.getId());
obj.put("name", ckanTag.getName());
tagsAsJson.add(obj);
}
}
// add the new one
JSONObject newTag = new JSONObject();
newTag.put("name", bean.getNewStatus().toString());
newTag.put("display_name", bean.getNewStatus().toString());
tagsAsJson.add(newTag);
// manage the groups
List<CkanGroup> groups = dataset.getGroups();
for (CkanGroup ckanGroup : groups) {
if(!ckanGroup.getName().equals("grsf" + "-" + bean.getCurrentStatus().toString().toLowerCase())){
JSONObject obj = new JSONObject();
obj.put("name", ckanGroup.getName());
groupsAsJson.add(obj);
}
}
JSONObject newGroup = new JSONObject();
newGroup.put("name", "grsf" + "-" + bean.getNewStatus().toString().toLowerCase());
groupsAsJson.add(newGroup);
// perform the request
jsonRequest.put("id", bean.getCatalogueIdentifier());
jsonRequest.put("tags", tagsAsJson);
jsonRequest.put("extras", customFieldsAsJson);
jsonRequest.put("groups", groupsAsJson);
logger.debug("Request param is going to be " + jsonRequest);
if((errorMessage = catalogue.patchProductWithJSON(bean.getCatalogueIdentifier(), jsonRequest, apiKey)) == null){
logger.info("Record patched ...");
break;
}else
continue; // retry
}catch(Exception e){
logger.error("Error while trying to patch grsf record (iteration " + i + " of " + MAX_TRIAL + ")" + e.getMessage());
errorMessage = e.getMessage();
}
}
return errorMessage;
}
}

View File

@ -0,0 +1,53 @@
package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.thread;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
/**
* Add the user to the other organizations present in the local instance of ckan.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class AddUserToOrganizationThread extends Thread {
private static final Log logger = LogFactoryUtil.getLog(AddUserToOrganizationThread.class);
private DataCatalogue instance;
private String username;
private Map<String, String> orgAndCapacity;
/**
* @param instance
* @param username
* @param orgAndCapacity
*/
public AddUserToOrganizationThread(DataCatalogue instance, String username,
Map<String, String> orgAndCapacity) {
super();
this.instance = instance;
this.username = username;
this.orgAndCapacity = orgAndCapacity;
}
@Override
public void run() {
logger.debug("Thread for role association started. Organizations and roles are in the map: " + orgAndCapacity);
Set<Entry<String, String>> entrySet = orgAndCapacity.entrySet();
for (Entry<String, String> entry : entrySet) {
instance.checkRoleIntoOrganization(username, entry.getKey(), RolesCkanGroupOrOrg.convertFromCapacity(entry.getValue()));
}
logger.debug("Thread for role association ended");
}
}

View File

@ -1,36 +0,0 @@
package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared;
/**
* Status of a grsf record.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum GRSFStatus {
APPROVED("Approved"),
REJECTED("Rejected"),
PENDING("Pending"),
ARCHIVED("Archived"),
HIDDEN("Hidden");
private String asString;
private GRSFStatus(String asString) {
this.asString = asString;
}
@Override
public String toString() {
return asString;
}
public static GRSFStatus fromString(String string){
if(string == null || string.isEmpty())
return null;
for(GRSFStatus value: GRSFStatus.values())
if(value.toString().equalsIgnoreCase(string))
return value;
return null;
}
}

View File

@ -1,110 +0,0 @@
package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared;
import java.io.Serializable;
/**
* The bean to be managed by some people (e.g., GRSF).
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ManageProductBean implements Serializable{
private static final long serialVersionUID = -4882608487467259326L;
private String productName;
private String catalogueIdentifier;
private String knowledgeBaseIdentifier;
private GRSFStatus currentStatus;
private GRSFStatus newStatus;
private String annotation;
private String productType; // fishery/stock
public ManageProductBean() {
super();
}
/**
* @param productName
* @param catalogueIdentifier
* @param knowledgeBaseIdentifier
* @param statusOld
* @param newStatus
* @param annotation
*/
public ManageProductBean(String productName, String catalogueIdentifier,
String knowledgeBaseIdentifier, GRSFStatus currentStatus, GRSFStatus newStatus,
String annotation, String productType) {
super();
this.productName = productName;
this.catalogueIdentifier = catalogueIdentifier;
this.knowledgeBaseIdentifier = knowledgeBaseIdentifier;
this.currentStatus = currentStatus;
this.newStatus = newStatus;
this.annotation = annotation;
this.productType = productType;
}
public String getCatalogueIdentifier() {
return catalogueIdentifier;
}
public void setCatalogueIdentifier(String catalogueIdentifier) {
this.catalogueIdentifier = catalogueIdentifier;
}
public String getKnowledgeBaseIdentifier() {
return knowledgeBaseIdentifier;
}
public void setKnowledgeBaseIdentifier(String knowledgeBaseIdentifier) {
this.knowledgeBaseIdentifier = knowledgeBaseIdentifier;
}
public GRSFStatus getCurrentStatus() {
return currentStatus;
}
public void setCurrentStatus(GRSFStatus currentStatus) {
this.currentStatus = currentStatus;
}
public GRSFStatus getNewStatus() {
return newStatus;
}
public void setNewStatus(GRSFStatus newStatus) {
this.newStatus = newStatus;
}
public String getAnnotation() {
return annotation;
}
public void setAnnotation(String annotation) {
this.annotation = annotation;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductType() {
return productType;
}
public void setProductType(String productType) {
this.productType = productType;
}
@Override
public String toString() {
return "ManageProductBean [productName=" + productName
+ ", catalogueIdentifier=" + catalogueIdentifier
+ ", knowledgeBaseIdentifier=" + knowledgeBaseIdentifier
+ ", currentStatus=" + currentStatus + ", newStatus="
+ newStatus + ", annotation=" + annotation + ", productType="
+ productType + "]";
}
}

View File

@ -1,28 +0,0 @@
package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.ex;
/**
* This is thrown when the Manage product is pushed on a product that has
* a Record Type field of Source or none.
* @author Costantino Perciante at ISTI-CNR
* (costantino.perciante@isti.cnr.it)
*/
public class NoGRSFRecordException extends Exception {
private static final long serialVersionUID = 721315478405659218L;
private String errorMessage;
public NoGRSFRecordException() {
super();
}
public NoGRSFRecordException(String errorMessage) {
super();
this.errorMessage = errorMessage;
}
public String getErrorMessage() {
return errorMessage;
}
}

View File

@ -29,10 +29,10 @@
<servlet-class>org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.GcubeCkanDataCatalogServiceImpl</servlet-class>
</servlet>
<!-- <servlet> -->
<!-- <servlet-name>gcubeckanlogout</servlet-name> -->
<!-- <servlet-class>org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.CkanLogout</servlet-class> -->
<!-- </servlet> -->
<!-- <servlet> -->
<!-- <servlet-name>gcubeckanlogout</servlet-name> -->
<!-- <servlet-class>org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.CkanLogout</servlet-class> -->
<!-- </servlet> -->
<servlet>
<servlet-name>checkServlet</servlet-name>
@ -54,10 +54,20 @@
<url-pattern>/gCubeCkanDataCatalog/ckanservices</url-pattern>
</servlet-mapping>
<!-- <servlet-mapping> -->
<!-- <servlet-name>gcubeckanlogout</servlet-name> -->
<!-- <url-pattern>/gCubeCkanDataCatalog/gcubeckanlogout</url-pattern> -->
<!-- </servlet-mapping> -->
<servlet>
<servlet-name>grsfmanageservice</servlet-name>
<servlet-class>org.gcube.datacatalogue.grsf_manage_widget.server.manage.GRSFNotificationService</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>grsfmanageservice</servlet-name>
<url-pattern>/GRSFManageWidget/ckanservices</url-pattern>
</servlet-mapping>
<!-- <servlet-mapping> -->
<!-- <servlet-name>gcubeckanlogout</servlet-name> -->
<!-- <url-pattern>/gCubeCkanDataCatalog/gcubeckanlogout</url-pattern> -->
<!-- </servlet-mapping> -->
<servlet-mapping>
<servlet-name>checkServlet</servlet-name>