diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java index bc46f98..d58ef14 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java @@ -13,91 +13,141 @@ import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; /** * CKAN publisher services. - * @author Costantino Perciante at ISTI-CNR - * (costantino.perciante@isti.cnr.it) + * + * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ @RemoteServiceRelativePath("ckanservices") public interface CKanPublisherService extends RemoteService { /** * Retrieve the list of licenses to show to the user. + * * @return a LicenseBean on success, null on error. */ List getLicenses(); /** * Retrieve the list of profiles for a given organization name . + * + * @param orgName the org name * @return a List on success, null on error. + * @throws Exception the exception */ List getProfiles(String orgName) throws Exception; /** * Retrieve a partially filled bean given a folder id/file id and its owner. + * * @param folderIdOrFileId the id of the folder of file to publish * @return @return a DatasetMetadataBean on success, null on error. - * @throws Exception + * @throws Exception the exception */ DatasetBean getDatasetBean(String folderIdOrFileId) throws Exception; /** - * Try to create such dataset starting from the information contained into the toCreate bean. - * @param toCreate + * Try to create such dataset starting from the information contained into the + * toCreate bean. + * + * @param toCreate the to create * @return the sent bean filled with the needed information + * @throws Exception the exception */ DatasetBean createCKanDataset(DatasetBean toCreate) throws Exception; /** - * Add this resource to the dataset whose id is datasetId - * @param resource - * @param datasetId + * Add this resource to the dataset whose id is datasetId. + * + * @param resource the resource + * @param datasetId the dataset id + * @return the resource element bean + * @throws Exception the exception */ ResourceElementBean addResourceToDataset(ResourceElementBean resource, String datasetId) throws Exception; /** - * Delete this resource from the dataset with id datasetId - * @param resource - * @param datasetId + * Delete this resource from the dataset with id datasetId. + * + * @param resource the resource * @return true on success, false otherwise - * @throws Exception + * @throws Exception the exception */ boolean deleteResourceFromDataset(ResourceElementBean resource) throws Exception; /** - * Given the title the user wants to give to the new product to create, a check is performed - * to understand if a dataset with the proposed title (and so the id generated at server side) already exists - * @param title + * Given the title the user wants to give to the new product to create, a check + * is performed to understand if a dataset with the proposed title (and so the + * id generated at server side) already exists. + * + * @param title the title + * @param orgName the org name * @return true if it exists, false otherwise - * @throws Exception + * @throws Exception the exception */ boolean datasetIdAlreadyExists(String title, String orgName) throws Exception; /** - * Retrieve the list of groups the user can choose to associate this product with. - * @param orgName retrieve the groups in the context linked to this name. If null, returns - * the one in the current context. + * Retrieve the list of groups the user can choose to associate this product + * with. + * + * @param orgName retrieve the groups in the context linked to this name. If + * null, returns the one in the current context. * @return a list of groups' beans */ List getUserGroups(String orgName); - + /** - * The method checks if the user is a publisher or he/she doesn't have the rights to publish + * The method checks if the user is a publisher or he/she doesn't have the + * rights to publish. + * * @return true if he/she can publish, false otherwise - * @throws Exception + * @throws Exception the exception */ - boolean isPublisherUser(boolean isWorkspaceRequest) throws Exception; - + boolean isPublisherUser() throws Exception; + /** - * Get the list of vocabulary tags for this scope - * @param orgName - * @return - * @throws Exception + * Get the list of vocabulary tags for this scope. + * + * @param orgName the org name + * @return the tags for organization + * @throws Exception the exception */ List getTagsForOrganization(String orgName) throws Exception; - + /** - * Validate a geo json field - * @param json - * @return + * Validate a geo json field. + * + * @param json the json + * @return true, if is geo JSON valid + * @throws Exception the exception */ boolean isGeoJSONValid(String json) throws Exception; + + /** + * Checks if is owner or admin user. + * + * @param datasetIdOrName the dataset id or name + * @return true, if is owner or admin user + * @throws Exception the exception + */ + boolean isPublisherOwnerOrAdminUser(String datasetIdOrName) throws Exception; + + /** + * Gets the dataset bean for update. + * + * @param itemID the item ID + * @return the dataset bean for update + * @throws Exception the exception + */ + DatasetBean getDatasetBeanForUpdate(String itemID) throws Exception; + + /** + * Gets the profile for update. + * + * @param orgName the org name + * @param datasetType the dataset type + * @param datasedIdOrName the datased id or name + * @return the profile for update + * @throws Exception the exception + */ + List getProfileForUpdate(String orgName, String datasetType, String datasedIdOrName) throws Exception; } diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherServiceAsync.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherServiceAsync.java index 71440ab..b31010f 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherServiceAsync.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherServiceAsync.java @@ -12,97 +12,147 @@ import com.google.gwt.user.client.rpc.AsyncCallback; /** * CKAN publisher services RPC. + * * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public interface CKanPublisherServiceAsync { /** * Retrieve the list of licenses to show to the user. + * + * @param callback the callback * @return a LicenseBean on success, null on error. */ void getLicenses(AsyncCallback> callback); /** * Retrieve a partially filled bean given a folder id/file id and its owner. + * * @param folderIdOrFileId the id of the folder of file to publish + * @param callback the callback * @return @return a DatasetMetadataBean on success, null on error. */ - void getDatasetBean(String folderIdOrFileId, - AsyncCallback callback); + void getDatasetBean(String folderIdOrFileId, AsyncCallback callback); /** - * Try to create such dataset starting from the information contained into the toCreate bean. - * @param toCreate + * Try to create such dataset starting from the information contained into the + * toCreate bean. + * + * @param toCreate the to create + * @param callback the callback * @return the sent bean full filled with the needed information */ - void createCKanDataset(DatasetBean toCreate, - AsyncCallback callback); + void createCKanDataset(DatasetBean toCreate, AsyncCallback callback); /** - * Add this resource to the dataset whose id is datasetId - * @param resource - * @param datasetId - * @param callback + * Add this resource to the dataset whose id is datasetId. + * + * @param resource the resource + * @param datasetId the dataset id + * @param callback the callback */ void addResourceToDataset(ResourceElementBean resource, String datasetId, AsyncCallback callback); /** - * Delete this resource from the dataset with id datasetId - * @param resource + * Delete this resource from the dataset with id datasetId. + * + * @param resource the resource + * @param callback the callback * @return true on success, false otherwise */ void deleteResourceFromDataset(ResourceElementBean resource, AsyncCallback callback); /** * Retrieve the list of profiles for a given organization name . + * + * @param orgName the org name + * @param callback the callback * @return a List on success, null on error. */ void getProfiles(String orgName, AsyncCallback> callback); /** - * Given the title the user wants to give to the new product to create, a check is performed - * to understand if a dataset with the proposed title (and so the id generated at server side) already exists - * @param title + * Given the title the user wants to give to the new product to create, a check + * is performed to understand if a dataset with the proposed title (and so the + * id generated at server side) already exists. + * + * @param title the title + * @param orgName the org name + * @param callback the callback * @return true if it exists, false otherwise */ void datasetIdAlreadyExists(String title, String orgName, AsyncCallback callback); - // /** - // * Return a tree object representing the whole folder hierarchy - // * @param folderId - // * @return ResourceElementBean - // */ - // void getTreeFolder(String folderId, - // AsyncCallback callback); + // /** + // * Return a tree object representing the whole folder hierarchy + // * @param folderId + // * @return ResourceElementBean + // */ + // void getTreeFolder(String folderId, + // AsyncCallback callback); /** - * Retrieve the list of groups the user can choose to associate this product with. - * @param orgName retrieve the groups in the context linked to this name. If null, returns - * the one in the current context. + * Retrieve the list of groups the user can choose to associate this product + * with. + * + * @param orgName retrieve the groups in the context linked to this name. If + * null, returns the one in the current context. + * @param callback the callback * @return a list of groups' beans */ void getUserGroups(String orgName, AsyncCallback> callback); /** - * The method checks if the user is a publisher or he/she doesn't have the rights to publish - * @return true if he/she can publish, false otherwise + * Checks if is publisher user. + * + * @param callback the callback */ - void isPublisherUser(boolean isWorkspaceRequest, - AsyncCallback callback); + void isPublisherUser(AsyncCallback callback); /** - * Get the list of vocabulary tags for this scope - * @param orgName - * @return + * Get the list of vocabulary tags for this scope. + * + * @param orgName the org name + * @param callback the callback + * @return the tags for organization */ - void getTagsForOrganization(String orgName, - AsyncCallback> callback); + void getTagsForOrganization(String orgName, AsyncCallback> callback); /** - * Validate a geo json field - * @param json - * @return + * Validate a geo json field. + * + * @param json the json + * @param callback the callback */ void isGeoJSONValid(String json, AsyncCallback callback); + + /** + * Checks if is owner or admin user. + * + * @param datasetIdOrName the dataset id or name + * @param callback the callback + * @return true, if is owner or admin user + */ + void isPublisherOwnerOrAdminUser(String datasetIdOrName, AsyncCallback callback); + + /** + * Gets the dataset bean. + * + * @param itemID the item ID + * @return the dataset bean + * @throws Exception the exception + */ + void getDatasetBeanForUpdate(String itemID, AsyncCallback callback); + + /** + * Gets the profile for update. + * + * @param orgName the org name + * @param datasetType the dataset type + * @param datasedIdOrName the datased id or name + * @param callaback the callaback + * @return the profile for update + */ + void getProfileForUpdate(String orgName, String datasetType, String datasedIdOrName, AsyncCallback> callaback); } diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/CreateDatasetForm.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/CreateDatasetForm.java index 0fd3c3a..5f3038e 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/CreateDatasetForm.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/CreateDatasetForm.java @@ -402,7 +402,7 @@ public class CreateDatasetForm extends Composite { // check if the user has publishing rights setAlertBlock("Checking your permissions, please wait...", AlertType.INFO, true); - ckanServices.isPublisherUser(isWorkspaceRequest, new AsyncCallback() { + ckanServices.isPublisherUser(new AsyncCallback() { @Override public void onSuccess(Boolean result) { diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/UpdateDatasetForm.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/UpdateDatasetForm.java new file mode 100644 index 0000000..cb137c8 --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/UpdateDatasetForm.java @@ -0,0 +1,1797 @@ +package org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.form; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanMetadataPublisher; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherServiceAsync; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.CloseCreationFormEvent; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.CloseCreationFormEventHandler; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.DeleteCustomFieldEvent; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.DeleteCustomFieldEventHandler; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.metadata.CustomFieldEntry; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.resources.AddResourceToDataset; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.utils.InfoIconsLabels; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.utils.WizardCreator; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.workspace.SelectResourceByWEMainPanel; +import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetBean; +import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean; +import org.gcube.portlets.widgets.mpformbuilder.client.form.MetaDataField; +import org.gcube.portlets.widgets.mpformbuilder.client.form.generic.CreateMetadataForm.OPERATION; +import org.gcube.portlets.widgets.mpformbuilder.client.ui.metadata.CategoryPanel; +import org.gcube.portlets.widgets.mpformbuilder.client.ui.metadata.MetaDataFieldSkeleton; +import org.gcube.portlets.widgets.mpformbuilder.client.ui.resources.AddResourceContainer; +import org.gcube.portlets.widgets.mpformbuilder.client.ui.resources.AddedResourcesSummary; +import org.gcube.portlets.widgets.mpformbuilder.client.ui.tags.TagsPanel; +import org.gcube.portlets.widgets.mpformbuilder.shared.license.LicenseBean; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.CategoryWrapper; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetaDataProfileBean; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetadataFieldWrapper; + +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.ListBox; +import com.github.gwtbootstrap.client.ui.Paragraph; +import com.github.gwtbootstrap.client.ui.Popover; +import com.github.gwtbootstrap.client.ui.Tab; +import com.github.gwtbootstrap.client.ui.TabPanel; +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.github.gwtbootstrap.client.ui.constants.IconType; +import com.github.gwtbootstrap.client.ui.constants.ResizeType; +import com.github.gwtbootstrap.client.ui.resources.Bootstrap.Tabs; +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.SelectElement; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DomEvent; +import com.google.gwt.event.shared.HandlerManager; +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.Timer; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FocusPanel; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; + +/** + * Create metadata form for ckan product. + * + * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + */ +public class UpdateDatasetForm extends Composite { + + private static EditMetadataFormUiBinder uiBinder = GWT.create(EditMetadataFormUiBinder.class); + + /** + * The Interface EditMetadataFormUiBinder. + * + * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it + * + * Feb 6, 2024 + */ + interface EditMetadataFormUiBinder extends UiBinder { + } + + @UiField + HTMLPanel createDatasetMainPanel; + @UiField + TextBox titleTextBox; + @UiField + TextArea descriptionTextarea; + @UiField + ListBox licenseListbox; + @UiField + ListBox visibilityListbox; + @UiField + ListBox organizationsListbox; + @UiField + TextBox versionTextbox; + @UiField + TextBox authorTextbox; + @UiField + TextBox authorEmailTextbox; + @UiField + TextBox maintainerTextbox; + @UiField + TextBox maintainerEmailTextbox; + @UiField + ControlGroup customFields; + @UiField + Button addCustomFieldButton; + @UiField + Button createButton; + @UiField + Button resetButton; + @UiField + AlertBlock infoBlock; + @UiField + AlertBlock alertNoResources; + @UiField + AlertBlock onContinueAlertBlock; + @UiField + AlertBlock onCreateAlertBlock; + @UiField + VerticalPanel metadataFieldsPanel; + @UiField + ListBox metadataTypeListbox; + @UiField + Form formFirstStep; + @UiField + Form formSecondStep; + @UiField + Form formThirdStep; + @UiField + Button continueButton; + @UiField + Button goBackButtonSecondStep; + @UiField + Paragraph selectedProfile; + @UiField + Button goToDatasetButton; + @UiField + HorizontalPanel goToDatasetButtonPanel; + @UiField + Button addResourcesButton; + @UiField + SimplePanel workspaceResourcesContainer; + @UiField + Button continueThirdStep; + @UiField + Button goBackButtonFirstStep; + @UiField + Anchor licenseUrlAnchor; + @UiField + Paragraph unavailableUrl; + @UiField + TagsPanel tagsPanel; + @UiField + ListBox groupsListbox; + + // info panels + @UiField + Icon infoIconLicenses; + @UiField + FocusPanel focusPanelLicenses; + @UiField + Popover popoverLicenses; + @UiField + Icon infoIconVisibility; + @UiField + FocusPanel focusPanelVisibility; + @UiField + Popover popoverVisibility; + @UiField + Icon infoIconAuthor; + @UiField + FocusPanel focusPanelAuthor; + @UiField + Popover popoverAuthor; + @UiField + Icon infoIconMaintainerEmail; + @UiField + FocusPanel focusPanelMaintainerEmail; + @UiField + Popover popoverMaintainerEmail; + @UiField + Icon infoIconAuthorEmail; + @UiField + FocusPanel focusPanelAuthorEmail; + @UiField + Popover popoverAuthorEmail; + @UiField + Icon infoIconTypes; + @UiField + FocusPanel focusPanelTypes; + @UiField + Popover popoverTypes; + @UiField + Icon infoIconMaintainer; + @UiField + FocusPanel focusPanelMaintainer; + @UiField + Popover popoverMaintainer; + @UiField + Icon infoIconCustomFields; + @UiField + FocusPanel focusPanelCustomFields; + @UiField + Popover popoverCustomFields; + @UiField + Icon infoIconResources; + @UiField + FocusPanel focusPanelResources; + @UiField + Popover popoverResources; + @UiField + Icon infoIconTitle; + @UiField + FocusPanel focusPanelTitle; + @UiField + Popover popoverGroups; + @UiField + Icon infoIconGroups; + @UiField + FocusPanel focusPanelGroups; + @UiField + Popover popoverTitle; + @UiField + Icon infoIconDescription; + @UiField + Popover popoverDescription; + @UiField + FocusPanel focusPanelDescription; + @UiField + ControlGroup metadataTypesControlGroup; + @UiField + ControlGroup productTitleGroup; + @UiField + ControlGroup maintainerControlGroup; + @UiField + ControlGroup versionControlGroup; + @UiField + ControlGroup organizationsGroup; + @UiField + ControlGroup groupsControlGroup; + + @UiField + HTMLPanel wizardCreatorPanel; + + private Icon iconSpinner = new Icon(IconType.SPINNER); + + // Create a remote service proxy to talk to the server-side ckan service. + private final CKanPublisherServiceAsync ckanServices = GWT.create(CKanPublisherService.class); + + // private static final String REGEX_TITLE_PRODUCT_SUBWORD = "[^a-zA-Z0-9_.-]"; + private static final String REGEX_MAIL = "\\b[\\w.%-]+@[-.\\w]+\\.[A-Za-z]{2,4}\\b"; + private static final String NONE_PROFILE = "none"; + + // error/info messages + protected static final String ERROR_PRODUCT_CREATION = "There was an error while trying to publish your item."; + protected static final String PRODUCT_CREATED_OK = "Item correctly published!"; + private static final String TRYING_TO_CREATE_PRODUCT = "Trying to publish the item, please wait..."; + protected static final String MISSING_PUBLISH_RIGHTS = "It seems you are not authorized to edit this item. Either you must be the author item or Catalogue Admininistrator in the organization"; + + // tab panel + private TabPanel tabPanel; + + // add resource form + private AddResourceToDataset resourceForm; + + // the licenses + private List licenseBean; + + // event bus + private HandlerManager eventBus; + + // added custom field entries (by the user) + private List customFieldEntriesList = new ArrayList(); + + // the list of MetaDataField added + private List listOfMetadataFields = new ArrayList(); + + // dataset metadata bean + private DatasetBean receivedBean; + + // the owner + private String owner; + + // workspace request? + // private boolean isWorkspaceRequest = false; + + // resource table + // private TwinColumnSelectionMainPanel resourcesTwinPanel; + + // resource table + private SelectResourceByWEMainPanel resourcesSelectByWEMainPanel; + + // List of opened popup'ids + private List popupOpenedIds = new ArrayList(); + + // map of organization name title + private Map nameTitleOrganizationMap = new HashMap(); + + private WizardCreator wizCreator; + + private boolean isWorkspaceRequest = false; + private String datasetIdOrName; + + /** + * Instantiates a new update dataset form. + * + * @param eventBus the event bus + * @param itemId the item id + */ + public UpdateDatasetForm(HandlerManager eventBus, String itemId) { + createDatasetFormBody(eventBus, itemId, OPERATION.UPDATE); + } + + /** + * Bind on events. + */ + private void bind() { + // when a custom field is removed, remove it from the list + eventBus.addHandler(DeleteCustomFieldEvent.TYPE, new DeleteCustomFieldEventHandler() { + + @Override + public void onRemoveEntry(DeleteCustomFieldEvent event) { + customFieldEntriesList.remove(event.getRemovedEntry()); + customFields.remove(event.getRemovedEntry()); + } + }); + + // on close form + eventBus.addHandler(CloseCreationFormEvent.TYPE, new CloseCreationFormEventHandler() { + @Override + public void onClose(CloseCreationFormEvent event) { + InfoIconsLabels.closeDialogBox(popupOpenedIds); + } + }); + } + + /** + * The real constructor. + * + * @param eventBus the event bus + * @param datasetIdOrName the item id + * @param operation the operation + */ + private void createDatasetFormBody(final HandlerManager eventBus, String datasetIdOrName, + final OPERATION operation) { + + initWidget(uiBinder.createAndBindUi(this)); + this.eventBus = eventBus; + this.datasetIdOrName = datasetIdOrName; + + iconSpinner.setSpin(true); + iconSpinner.getElement().getStyle().setMarginLeft(5, Unit.PX); + + List listOfSteps = Arrays.asList("Edit Common Metadata", "Edit Item Specific Metadata & Publish"); + + this.wizCreator = new WizardCreator(listOfSteps); + wizardCreatorPanel.add(wizCreator); + + this.descriptionTextarea.setResize(ResizeType.VERTICAL); + bind(); + prepareInfoIcons(); + + // disable continue button + continueButton.setEnabled(false); + resetButton.setEnabled(false); + + // hide tags panel + tagsPanel.setVisible(false); + + // check if the user has publishing rights + setAlertBlock("Checking your permissions, please wait...", AlertType.INFO, true); + + ckanServices.isPublisherOwnerOrAdminUser(this.datasetIdOrName, new AsyncCallback() { + + @Override + public void onSuccess(Boolean result) { + GWT.log("isPublisherOwnerOrAdminUser: " + result); + if (result) { + + // set info block + setAlertBlock("Retrieving information, please wait...", AlertType.INFO, true); + + // get back the licenses and the metadata information + ckanServices.getDatasetBeanForUpdate(datasetIdOrName, new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + + setAlertBlock(caught.getMessage(), AlertType.ERROR, true); + + } + + @Override + public void onSuccess(final DatasetBean bean) { + GWT.log("getDatasetBeanForUpdate returns: " + bean); + + if (bean == null) { + + setAlertBlock("Error while retrieving information.", AlertType.ERROR, true); + } else { + + // save it + receivedBean = bean; + + // fill the form + titleTextBox.setText(bean.getTitle()); + descriptionTextarea.setText(bean.getDescription()); + versionTextbox.setText(String.valueOf(bean.getVersion())); + authorTextbox.setText(bean.getAuthorFullName()); + authorEmailTextbox.setText(bean.getAuthorEmail()); + maintainerTextbox.setText(bean.getMaintainer()); + maintainerEmailTextbox.setText(bean.getMaintainerEmail()); + + setAlertBlock("Retrieving information, please wait...", AlertType.INFO, true); + + // vocabulary list of tags has preemption + List vocabularyTags = bean.getTagsVocabulary(); + if (vocabularyTags != null) { + tagsPanel.setVocabulary(vocabularyTags); + if (bean.getTags() != null) { + for (String tag : bean.getTags()) { + tagsPanel.addTagElement(tag); + } + + } + } + + // retrieve custom fields + Map> customFieldsMap = bean.getCustomFields(); + + // TODO Check if these tags are ok for the vocabulary + if (customFieldsMap != null && vocabularyTags == null) { + + // get the keys and put them as tags + Iterator>> iteratorOverCustomField = customFieldsMap + .entrySet().iterator(); + + while (iteratorOverCustomField.hasNext()) { + Map.Entry> entry = iteratorOverCustomField + .next(); + + List values = entry.getValue(); + + for (String value : values) { + // these are fixed key, variable value custom fields + CustomFieldEntry toAdd = new CustomFieldEntry(eventBus, entry.getKey(), + value, false); + customFieldEntriesList.add(toAdd); + customFields.add(toAdd); + + // add as tag + tagsPanel.addTagElement(entry.getKey()); + } + } + } + + // set it as visible anyway + tagsPanel.setVisible(true); + +// if (isWorkspaceRequest) { +// // if there are not resources, for now just checked it ( and hide so that the +// // step will be skipped) +// if (hideManageResources()) { +// alertNoResources.setType(AlertType.WARNING); +// alertNoResources.setVisible(true); +// } else +// // resourcesSelectByWEMainPanel = new +// // TwinColumnSelectionMainPanel(bean.getResourceRoot()); +// resourcesSelectByWEMainPanel = new SelectResourceByWEMainPanel( +// bean.getResourceRoot()); +// } + + if (bean.getResourceRoot() != null) + resourcesSelectByWEMainPanel = new SelectResourceByWEMainPanel( + bean.getResourceRoot()); + + // set organizations + List organizations = bean.getOrganizationList(); + + for (OrganizationBean organization : organizations) { + organizationsListbox.addItem(organization.getTitle()); + nameTitleOrganizationMap.put(organization.getTitle(), organization.getName()); + } + + // force the selection of the first one, and retrieve the list of profiles + organizationsListbox.setSelectedIndex(0); + + // add change handler to dynamically retrieve the list of profiles + organizationsListbox.addChangeHandler(new ChangeHandler() { + + @Override + public void onChange(ChangeEvent event) { + event.preventDefault(); + organizationsListboxChangeHandlerBody(operation); + } + }); + + // get the name of the organization from the title + final String orgName = nameTitleOrganizationMap + .get(organizationsListbox.getSelectedItemText()); + + // force tags +// setAlertBlock("Checking for tags vocabulary, please wait...", AlertType.INFO, true); +// ckanServices.getTagsForOrganization(orgName, new AsyncCallback>() { +// +// @Override +// public void onSuccess(List vocabulary) { +// +// tagsPanel.setVocabulary(vocabulary); +// tagsPanel.setVisible(true); +// } +// +// @Override +// public void onFailure(Throwable arg0) { +// +// setAlertBlock( +// "Error while checking if a vocabulary of tags is defined in the selected organization.", +// AlertType.ERROR, true); +// tagsPanel.setVisible(true); +// +// } +// }); + + // try to retrieve the profiles + setAlertBlock("Retrieving types, please wait...", AlertType.INFO, true); + + // perform remote request of profiles for the selected organization + ckanServices.getProfileForUpdate(orgName, bean.getChosenType(), bean.getId(), + new AsyncCallback>() { + + @Override + public void onFailure(Throwable caught) { + setAlertBlock(caught.getMessage(), AlertType.ERROR, true); + } + + @Override + public void onSuccess(final List profiles) { + setAlertBlock("", AlertType.ERROR, false); + if (profiles == null) { + setAlertBlock( + "An unknow error occurred while retrieving types, sorry", + AlertType.ERROR, true); + } else { + + GWT.log("Profile returned are: " + profiles.size()); + if (!GWT.isProdMode()) { + for (MetaDataProfileBean profile : profiles) { + GWT.log("Profile title: " + profile.getTitle() + ", type: " + + profile.getType()); + } + } + + receivedBean.setMetadataList(profiles); + prepareMetadataList(receivedBean, operation); + organizationsListbox.setEnabled(true); + metadataTypeListbox.setEnabled(true); + + // try to retrieve the licenses + setAlertBlock("Retrieving licenses, please wait...", AlertType.INFO, + true); + ckanServices.getLicenses(new AsyncCallback>() { + + @Override + public void onFailure(Throwable caught) { + setAlertBlock(caught.getMessage(), AlertType.ERROR, true); + } + + @Override + public void onSuccess(List licenses) { + setAlertBlock("", AlertType.ERROR, false); + + if (licenses != null && !licenses.isEmpty()) { + + licenseBean = licenses; + + // fill the listbox + for (int i = 0; i < licenses.size(); i++) { + licenseListbox.addItem(licenses.get(i).getTitle()); + } + + // set the url of the license, if any + showLicenseUrl(); + + // try to retrieve the licenses + setAlertBlock("Retrieving groups, please wait...", + AlertType.INFO, true); + + // request groups + ckanServices.getUserGroups(orgName, + new AsyncCallback>() { + + @Override + public void onSuccess( + List groups) { + if (groups == null) { + setAlertBlock( + "Error while retrieving groups", + AlertType.ERROR, true); + } else { + if (groups.isEmpty()) { + groupsControlGroup + .setVisible(false); + } else { + + // add groups + for (OrganizationBean group : groups) { + groupsListbox.addItem( + group.getTitle(), + group.getName()); + } + hideGroupsAlreadyInProfile( + profiles); + } + // everything went ok + setAlertBlock("", AlertType.ERROR, + false); + continueButton.setEnabled(true); + resetButton.setEnabled(true); + } + } + + @Override + public void onFailure(Throwable caught) { + setAlertBlock(caught.getMessage(), + AlertType.ERROR, true); + } + }); + + } else { + setAlertBlock("Error while retrieving licenses", + AlertType.ERROR, true); + } + } + }); + } + } + }); + } + } + }); + + } else { + setAlertBlock(MISSING_PUBLISH_RIGHTS, AlertType.ERROR, true); + } + + } + + @Override + public void onFailure(Throwable caught) { + setAlertBlock(MISSING_PUBLISH_RIGHTS, AlertType.ERROR, true); + } + }); + + } + + /** + * When the organization name is changed we need to retrieve the list of + * profiles and groups. + * + * @param operation the operation + */ + private void organizationsListboxChangeHandlerBody(OPERATION operation) { + + // remove any other product profiles + metadataTypeListbox.clear(); + + // add "none" item again + metadataTypeListbox.addItem(NONE_PROFILE); + + // select "none" + metadataTypeListbox.setSelectedIndex(0); + + // get the name of the organization from the title + String selectedOrganizationTitle = organizationsListbox.getSelectedItemText(); + final String orgName = nameTitleOrganizationMap.get(selectedOrganizationTitle); + + // try to retrieve the profiles + setAlertBlock("Retrieving types, please wait...", AlertType.INFO, true); + + // disable the list of organizations name so that the user doesn't change it + // again + // also disable the profiles and the list of groups + organizationsListbox.setEnabled(false); + metadataTypeListbox.setEnabled(false); + groupsListbox.clear(); + groupsControlGroup.setVisible(false); + + // perform remote request of profiles for the selected organization + ckanServices.getProfiles(orgName, new AsyncCallback>() { + + @Override + public void onSuccess(final List profiles) { + + if (profiles != null) { + + receivedBean.setMetadataList(profiles); + prepareMetadataList(receivedBean, operation); + organizationsListbox.setEnabled(true); + metadataTypeListbox.setEnabled(true); + + // try to retrieve the licenses + setAlertBlock("Retrieving groups, please wait...", AlertType.INFO, true); + + // request groups + ckanServices.getUserGroups(orgName, new AsyncCallback>() { + + @Override + public void onSuccess(List groups) { + + if (groups == null) { + setAlertBlock("Error while retrieving groups, try later", AlertType.ERROR, true); + } else { + if (groups.isEmpty()) { + groupsControlGroup.setVisible(false); + } else { + + // add groups + for (OrganizationBean group : groups) { + groupsListbox.addItem(group.getTitle(), group.getName()); + } + groupsListbox.setEnabled(true); + hideGroupsAlreadyInProfile(profiles); + } + setAlertBlock("", AlertType.ERROR, false); + } + } + + @Override + public void onFailure(Throwable caught) { + setAlertBlock("Error while retrieving groups, try later", AlertType.ERROR, true); + } + }); + + // check also for tags (if for that context there is a vocabulary or not) + tagsPanel.setVisible(false); + setAlertBlock("Checking for tags vocabulary, please wait...", AlertType.INFO, true); + ckanServices.getTagsForOrganization(orgName, new AsyncCallback>() { + + @Override + public void onSuccess(List vocabulary) { + + tagsPanel.setVocabulary(vocabulary); + tagsPanel.setVisible(true); + setAlertBlock("", AlertType.ERROR, false); + } + + @Override + public void onFailure(Throwable arg0) { + + setAlertBlock( + "Error while checking if a vocabulary of tags is defined in the selected organization.", + AlertType.ERROR, true); + tagsPanel.setVocabulary(null); + tagsPanel.setVisible(true); + + } + }); + + } else + setAlertBlock("Error while retrieving types, sorry", AlertType.ERROR, true); + + } + + @Override + public void onFailure(Throwable caught) { + + setAlertBlock("Error while retrieving types, sorry", AlertType.ERROR, true); + + } + }); + + } + + /** + * Add the items to the listbox and put data into the metadataPanel. + * + * @param receivedBean the received bean + * @param operation the operation + */ + private void prepareMetadataList(final DatasetBean receivedBean, OPERATION operation) { + + // the profile should be one + List profiles = receivedBean.getMetadataList(); + + if (profiles != null && !profiles.isEmpty()) { + for (MetaDataProfileBean metadataBean : profiles) { + + metadataTypeListbox.addItem(metadataBean.getType()); + + // add handler on select + metadataTypeListbox.addChangeHandler(new ChangeHandler() { + + @Override + public void onChange(ChangeEvent event) { + + String selectedItemText = metadataTypeListbox.getSelectedItemText(); + metadataFieldsPanel.clear(); + if (selectedItemText.equals(NONE_PROFILE)) { + metadataFieldsPanel.setVisible(false); + receivedBean.setChosenType(null); + } else { + receivedBean.setChosenType(selectedItemText); + addFields(selectedItemText, operation); + } + } + }); + } + + // hide elements or show them if needed (groups in profiles cannot be present + // again in groups listbox) + if (groupsControlGroup.isVisible()) { + List groupsToHide = new ArrayList(); + for (MetaDataProfileBean profile : profiles) + groupsToHide.add(profile.getType().toString()); + + SelectElement se = groupsListbox.getElement().cast(); + + for (int i = 0; i < groupsListbox.getItemCount(); i++) { + if (groupsToHide.contains(groupsListbox.getItemText(i))) { + se.getOptions().getItem(i).getStyle().setProperty("display", "none"); + } else + se.getOptions().getItem(i).getStyle().setProperty("display", ""); + } + } + + metadataTypesControlGroup.setVisible(true); + } else { + // just hide this listbox + metadataTypesControlGroup.setVisible(false); + metadataFieldsPanel.clear(); + listOfMetadataFields.clear(); + receivedBean.setChosenType(null); + } + + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + + @Override + public void execute() { + if (profiles.size() == 1) { + // showChooseProfileForm(false); + metadataTypeListbox.setSelectedValue(profiles.get(0).getType()); + // customLegend.setText("Insert Information for: " + profiles.get(0).getType(), + // true); + DomEvent.fireNativeEvent(Document.get().createChangeEvent(), metadataTypeListbox); + } + } + }); + } + + /** + * Add fields of the selected metadata profile to the widget. + * + * @param selectedItem the selected item + * @param operation the operation + */ + protected void addFields(String selectedItem, OPERATION operation) { + + for (MetaDataProfileBean bean : receivedBean.getMetadataList()) { + if (bean.getType().equals(selectedItem)) { + + // clear old data + listOfMetadataFields.clear(); + + // prepare the data + List fields = bean.getMetadataFields(); + List categories = bean.getCategories(); + + GWT.log("There are " + categories.size() + " categories for profile " + bean.getTitle()); + + if (categories == null || categories.isEmpty()) { + for (MetadataFieldWrapper field : fields) { + /* + * MetaDataFieldSkeleton fieldWidget; try { fieldWidget = new + * MetaDataFieldSkeleton(field, eventBus); metadataFieldsPanel.add(fieldWidget); + * listOfMetadataFields.add(fieldWidget); } catch (Exception e) { + * GWT.log("Unable to build such widget", e); } + */ + + MetaDataField fieldWidget; + try { + fieldWidget = new MetaDataField(field, eventBus, operation); + metadataFieldsPanel.add(fieldWidget); + listOfMetadataFields.add(fieldWidget); + } catch (Exception e) { + GWT.log("Unable to build such widget", e); + } + } + } else { + + // create the categories, then parse the fields. Fields do not belonging to a + // category are put at the end + for (CategoryWrapper categoryWrapper : categories) { + if (categoryWrapper.getFieldsForThisCategory() != null + && categoryWrapper.getFieldsForThisCategory().size() > 0) { + CategoryPanel cp = new CategoryPanel(categoryWrapper.getTitle(), + categoryWrapper.getDescription()); + List fieldsForThisCategory = categoryWrapper + .getFieldsForThisCategory(); + fields.removeAll(fieldsForThisCategory); + + for (MetadataFieldWrapper metadataFieldWrapper : fieldsForThisCategory) { + + /* + * MetaDataFieldSkeleton fieldWidget; try { fieldWidget = new + * MetaDataFieldSkeleton(metadataFieldWrapper, eventBus); + * cp.addField(fieldWidget); listOfMetadataFields.add(fieldWidget); } catch + * (Exception e) { GWT.log("Unable to build such widget", e); } + */ + + MetaDataField fieldWidget; + try { + fieldWidget = new MetaDataField(metadataFieldWrapper, eventBus, operation); + cp.addField(fieldWidget); + listOfMetadataFields.add(fieldWidget); + } catch (Exception e) { + GWT.log("Unable to build such widget", e); + } + } + metadataFieldsPanel.add(cp); + } + } + + // add the remaining one at the end of the categories + CategoryPanel extrasCategory = new CategoryPanel("Other", null); + for (MetadataFieldWrapper field : fields) { + + /* + * MetaDataFieldSkeleton fieldWidget; try { fieldWidget = new + * MetaDataFieldSkeleton(field, eventBus); extrasCategory.addField(fieldWidget); + * listOfMetadataFields.add(fieldWidget); } catch (Exception e) { + * GWT.log("Unable to build such widget", e); } + */ + + MetaDataField fieldWidget; + try { + fieldWidget = new MetaDataField(field, eventBus, operation); + extrasCategory.addField(fieldWidget); + listOfMetadataFields.add(fieldWidget); + } catch (Exception e) { + GWT.log("Unable to build such widget", e); + } + } + metadataFieldsPanel.add(extrasCategory); + } + metadataFieldsPanel.setVisible(true); + } + } + } + + /** + * Adds the custom field event. + * + * @param e the e + */ + @UiHandler("addCustomFieldButton") + void addCustomFieldEvent(ClickEvent e) { + + CustomFieldEntry toAdd = new CustomFieldEntry(eventBus, "", "", true); + customFieldEntriesList.add(toAdd); + customFields.add(toAdd); + + } + + /** + * On continue button. + * + * @param e the e + */ + @UiHandler("continueButton") + void onContinueButton(ClickEvent e) { + + // validate data + final String errorMsg = validateDataOnContinue(); + + if (errorMsg != null) { + + alertOnContinue("Please check inserted data [" + errorMsg + "]", AlertType.ERROR); + return; + + } else { + + // better check for title (only if the dataset was not created.. if it is the + // case, fields are not frozen) + if (!titleTextBox.isEnabled()) + actionsAfterOnContinue(); + else { + actionsAfterOnContinue(); +// alertOnContinue("Checking if a item with such title already exists, please wait...", AlertType.INFO); +// final String orgName = nameTitleOrganizationMap.get(organizationsListbox.getSelectedItemText()); +// ckanServices.datasetIdAlreadyExists(titleTextBox.getText(), orgName, new AsyncCallback() { +// +// @Override +// public void onSuccess(Boolean result) { +// if (result) { +// alertOnContinue("Sorry but an item with such title already exists, try to change it", +// AlertType.WARNING); +// } else { +// actionsAfterOnContinue(); +// } +// } +// +// @Override +// public void onFailure(Throwable caught) { +// alertOnContinue("Sorry but there was a problem while checking if the inserted data are correct", +// AlertType.ERROR); +// } +// }); + } + } + } + + /** + * After onContinue ... + */ + private void actionsAfterOnContinue() { + + // check what to do + if (isWorkspaceRequest) { + + // we need to show the page to handle resources one by one from the workspace + formFirstStep.setVisible(false); + boolean hideManageRes = hideManageResources(); + int stepActive = -1; + if (hideManageRes) { + stepActive = 3; + } else { + stepActive = 2; + } + + formSecondStep.setVisible(!hideManageRes); + formThirdStep.setVisible(hideManageRes); + activeWizardStep(stepActive); + + // add the resources to the container panel + if (workspaceResourcesContainer.getWidget() == null) { + workspaceResourcesContainer.getElement().getStyle().setMarginLeft(20, Unit.PX); + workspaceResourcesContainer.add(resourcesSelectByWEMainPanel); + } + + } else { + + // this is not a workspace request + formFirstStep.setVisible(false); + formThirdStep.setVisible(true); + activeWizardStep(2); + + } + + if (metadataTypeListbox.getSelectedItemText().equals(NONE_PROFILE)) + selectedProfile.setText(""); + else + selectedProfile.setText("Selected Type is " + metadataTypeListbox.getSelectedItemText()); + + } + + /** + * Active wizard step. + * + * @param step the step + */ + private void activeWizardStep(int step) { + if (wizCreator != null) { + wizCreator.activeStep(step); + } + } + + /** + * On go back button first step. + * + * @param e the e + */ + @UiHandler("goBackButtonFirstStep") + void onGoBackButtonFirstStep(ClickEvent e) { + + // swap forms + formFirstStep.setVisible(true); + activeWizardStep(1); + formSecondStep.setVisible(false); + formThirdStep.setVisible(false); + + } + + /** + * On go back button. + * + * @param e the e + */ + @UiHandler("goBackButtonSecondStep") + void onGoBackButton(ClickEvent e) { + + // swap forms + if (isWorkspaceRequest) { + boolean hideManageRes = hideManageResources(); + int stepActive = -1; + if (hideManageRes) { + stepActive = 1; + } else { + stepActive = 2; + } + formFirstStep.setVisible(hideManageRes); + formSecondStep.setVisible(!hideManageRes); + activeWizardStep(stepActive); + } else { + + formFirstStep.setVisible(true); + formSecondStep.setVisible(false); + activeWizardStep(1); + } + formThirdStep.setVisible(false); + + } + + /** + * On continue third step. + * + * @param e the e + */ + @UiHandler("continueThirdStep") + void onContinueThirdStep(ClickEvent e) { + + // swap forms + formSecondStep.setVisible(false); + formThirdStep.setVisible(true); + activeWizardStep(3); + + } + + /** + * Creates the dataset event. + * + * @param e the e + */ + @UiHandler("createButton") + void createDatasetEvent(ClickEvent e) { + + String errorMessage = areProfileDataValid(); + + if (errorMessage != null) { + alertOnCreate("Please check the inserted values and the mandatory fields [" + errorMessage + "]", false, + AlertType.ERROR, true); + } else { + + String title = titleTextBox.getValue().trim(); + String description = descriptionTextarea.getText().trim(); + String selectedLicense = licenseListbox.getSelectedItemText(); + String visibility = visibilityListbox.getSelectedItemText(); + long version = Long.valueOf(versionTextbox.getValue().trim()); + String author = authorTextbox.getValue(); + String authorEmail = authorEmailTextbox.getValue(); + String maintainer = maintainerTextbox.getValue().trim(); + String maintainerEmail = maintainerEmailTextbox.getValue().trim(); + String chosenOrganizationTitle = organizationsListbox.getSelectedItemText(); + Set tags = new HashSet(tagsPanel.getTags()); + + // we need to retrieve the organization's name from this title + List orgs = receivedBean.getOrganizationList(); + String chosenOrganization = null; + for (OrganizationBean organizationBean : orgs) { + if (chosenOrganizationTitle.equals(organizationBean.getTitle())) { + chosenOrganization = organizationBean.getName(); + break; + } + } + + List groups = new ArrayList(); + List groupsToForceCreation = new ArrayList(); + + // get groups, if any + int items = groupsListbox.getItemCount(); + for (int i = 0; i < items; i++) { + String groupTitle = groupsListbox.getItemText(i); + String groupName = groupsListbox.getValue(i); + if (groupsListbox.isItemSelected(i)) { + groups.add(new OrganizationBean(groupTitle, groupName, false)); + } + } + + Map> customFieldsMap = new HashMap>(); + + // prepare custom fields + for (MetaDataField metaField : listOfMetadataFields) { + + for (MetaDataFieldSkeleton field : metaField.getListOfMetadataFields()) { + + List valuesForField = field.getFieldCurrentValue(); + if (!valuesForField.isEmpty()) { + String key = field.getFieldNameQualified(); + List valuesForThisField = null; + if (customFieldsMap.containsKey(key)) + valuesForThisField = customFieldsMap.get(key); + else + valuesForThisField = new ArrayList(); + + valuesForThisField.addAll(valuesForField); + customFieldsMap.put(key, valuesForThisField); + + // get also tag/group if it is the case for this field + List tagsField = field.getTagFromThisField(); + if (tagsField != null) + tags.addAll(tagsField); + + List groupsTitle = field.getGroupTitleFromThisGroup(); + if (groupsTitle != null) { + for (String groupTitle : groupsTitle) { + if (field.isGroupToForce()) + groupsToForceCreation.add( + new OrganizationBean(groupTitle, groupTitle, false, field.isPropagateUp())); + else + groups.add( + new OrganizationBean(groupTitle, groupTitle, false, field.isPropagateUp())); + } + } + } + } + } + + for (CustomFieldEntry customEntry : customFieldEntriesList) { + String key = customEntry.getKey(); + String value = customEntry.getValue(); + if (value != null && !value.isEmpty()) { + List valuesForThisField = null; + if (customFieldsMap.containsKey(key)) + valuesForThisField = customFieldsMap.get(key); + else + valuesForThisField = new ArrayList(); + valuesForThisField.add(value); + customFieldsMap.put(key, valuesForThisField); + } + + } + + // fill the bean + receivedBean.setAuthorFullName(author); + receivedBean.setAuthorEmail(authorEmail); + receivedBean.setDescription(description); + receivedBean.setLicense(selectedLicense); + receivedBean.setMaintainer(maintainer); + receivedBean.setMaintainerEmail(maintainerEmail); + receivedBean.setVersion(version); + receivedBean.setVisibile(visibility.equals("Public")); + receivedBean.setTitle(title); + receivedBean.setTags(new ArrayList(tags)); + receivedBean.setSelectedOrganization(chosenOrganization); + receivedBean.setGroups(groups); + receivedBean.setGroupsForceCreation(groupsToForceCreation); + + if (resourcesSelectByWEMainPanel != null) { + receivedBean.setResourceRoot(resourcesSelectByWEMainPanel.getResourcesToPublish()); + } + + receivedBean.setCustomFields(customFieldsMap); + + // alert + alertOnCreate(TRYING_TO_CREATE_PRODUCT, true, AlertType.INFO, false); + + // invoke the create method + createButton.setEnabled(false); + goBackButtonSecondStep.setEnabled(false); + + ckanServices.createCKanDataset(receivedBean, new AsyncCallback() { + + @Override + public void onSuccess(final DatasetBean createdDatasetBean) { + CKanMetadataPublisher.printJs("createCKanDataset returned"); + + GWT.log("Created the dataset: " + createdDatasetBean); + + if (createdDatasetBean != null) { + + CKanMetadataPublisher.printJs(createdDatasetBean.toString()); + + final String datasetUrl = createdDatasetBean.getSource(); + + alertOnCreate(PRODUCT_CREATED_OK, false, AlertType.SUCCESS, false); + + try { + // disable dataset fields + disableDatasetFields(); + } catch (Exception e) { + // TODO: handle exception + } + + // disable reset + resetButton.setEnabled(false); + + // show the go to dataset button + + goToDatasetButtonPanel.setVisible(true); + goToDatasetButton.setVisible(true); + + String title = createdDatasetBean.getTitle(); + String link = "(click here) "; + link += title.length() > 90 ? title.substring(0, 90) + "..." : title; + + goToDatasetButton.setTitle("Go to the item: " + title); + + goToDatasetButton.setText(link); + goToDatasetButton.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + Window.open(datasetUrl, "_blank", ""); + // Window.Location.assign(datasetUrl); + } + }); + + // set hidden the create button + createButton.setVisible(false); + + // if we are in the "general case" we need to show a form for adding resources + if (!isWorkspaceRequest) { + + try { + // show the add resources button + addResourcesButton.setVisible(true); + + addResourcesButton.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + + // remove content of the main panel + createDatasetMainPanel.clear(); + + // TabPanelException + tabPanel = new TabPanel(Tabs.ABOVE); + tabPanel.setWidth("100%"); + + // add the form + + resourceForm = new AddResourceToDataset(eventBus, createdDatasetBean.getId(), + createdDatasetBean.getTitle(), + createdDatasetBean.getSelectedOrganization(), owner, datasetUrl); + + // tab for the form + Tab formContainer = new Tab(); + formContainer.add(resourceForm); + formContainer.setHeading("Add New Resource"); + tabPanel.add(formContainer); + + // tab for the added resources + Tab addedResources = new Tab(); + addedResources.add(new AddedResourcesSummary(eventBus)); + addedResources.setHeading("Added Resource"); + tabPanel.add(addedResources); + + // add tabs to resources panel + tabPanel.selectTab(0); + + // form container + AddResourceContainer container = new AddResourceContainer(datasetUrl); + container.add(tabPanel); + + // add the new content of the main panel + createDatasetMainPanel.add(container); + } + }); + } catch (Exception e2) { + // silent + } + } + + } else { + + alertOnCreate(ERROR_PRODUCT_CREATION, false, AlertType.ERROR, true); + } + + } + + @Override + public void onFailure(Throwable caught) { + alertOnCreate(ERROR_PRODUCT_CREATION + " Error message is : " + caught.getMessage(), false, + AlertType.ERROR, true); + CKanMetadataPublisher.printJs(caught.toString()); + } + }); + } + } + + /** + * Prepare the info icons of all core metadata info. + */ + private void prepareInfoIcons() { + + // tags + tagsPanel.prepareIcon(popupOpenedIds); + + // licenses + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.LICENSES_INFO_ID_POPUP, + InfoIconsLabels.LICENSES_INFO_TEXT, InfoIconsLabels.LICENSES_INFO_CAPTION, infoIconLicenses, + popoverLicenses, focusPanelLicenses, popupOpenedIds); + + // visibility + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.VISIBILITY_INFO_ID_POPUP, + InfoIconsLabels.VISIBILITY_INFO_TEXT, InfoIconsLabels.VISIBILITY_INFO_CAPTION, infoIconVisibility, + popoverVisibility, focusPanelVisibility, popupOpenedIds); + + // author + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.AUTHOR_INFO_ID_POPUP, + InfoIconsLabels.AUTHOR_INFO_TEXT, InfoIconsLabels.AUTHOR_INFO_CAPTION, infoIconAuthor, popoverAuthor, + focusPanelAuthor, popupOpenedIds); + + // author's email + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.AUTHOR_EMAIL_INFO_ID_POPUP, + InfoIconsLabels.AUTHOR_EMAIL_INFO_TEXT, InfoIconsLabels.AUTHOR_EMAIL_INFO_CAPTION, infoIconAuthorEmail, + popoverAuthorEmail, focusPanelAuthorEmail, popupOpenedIds); + + // maintainer + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.MAINTAINER_INFO_ID_POPUP, + InfoIconsLabels.MAINTAINER_INFO_TEXT, InfoIconsLabels.MAINTAINER_INFO_CAPTION, infoIconMaintainer, + popoverMaintainer, focusPanelMaintainer, popupOpenedIds); + + // maintainer's email + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.MAINTAINER_EMAIL_INFO_ID_POPUP, + InfoIconsLabels.MAINTAINER_EMAIL_INFO_TEXT, InfoIconsLabels.MAINTAINER_EMAIL_INFO_CAPTION, + infoIconMaintainerEmail, popoverMaintainerEmail, focusPanelMaintainerEmail, popupOpenedIds); + + // profiles (or types) + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.PROFILES_INFO_ID_POPUP, + InfoIconsLabels.PROFILES_INFO_TEXT, InfoIconsLabels.PROFILES_INFO_CAPTION, infoIconTypes, popoverTypes, + focusPanelTypes, popupOpenedIds); + + // custom fields + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.CUSTOM_FIELDS_INFO_ID_POPUP, + InfoIconsLabels.CUSTOM_FIELDS_INFO_TEXT, InfoIconsLabels.CUSTOM_FIELDS_INFO_CAPTION, + infoIconCustomFields, popoverCustomFields, focusPanelCustomFields, popupOpenedIds); + + // resources field + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.RESOURCES_INFO_ID_POPUP, + InfoIconsLabels.RESOURCES_INFO_TEXT, InfoIconsLabels.RESOURCES_INFO_CAPTION, infoIconResources, + popoverResources, focusPanelResources, popupOpenedIds); + + // title + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.TITLE_INFO_ID_POPUP, + InfoIconsLabels.TITLE_INFO_TEXT, InfoIconsLabels.TITLE_INFO_CAPTION, infoIconTitle, popoverTitle, + focusPanelTitle, popupOpenedIds); + + // description + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.DESCRIPTION_INFO_ID_POPUP, + InfoIconsLabels.DESCRIPTION_INFO_TEXT, InfoIconsLabels.DESCRIPTION_INFO_CAPTION, infoIconDescription, + popoverDescription, focusPanelDescription, popupOpenedIds); + + // groups + InfoIconsLabels.preparePopupPanelAndPopover(InfoIconsLabels.GROUPS_INFO_ID_POPUP, + InfoIconsLabels.GROUPS_INFO_TEXT, InfoIconsLabels.GROUPS_INFO_CAPTION, infoIconGroups, popoverGroups, + focusPanelGroups, popupOpenedIds); + } + + /** + * Test if profile data are valid. + * + * @return the string + */ + private String areProfileDataValid() { + + for (MetaDataField metaField : listOfMetadataFields) { + + for (MetaDataFieldSkeleton field : metaField.getListOfMetadataFields()) { + + field.removeError(); + + String error = field.isFieldValueValid(); + if (error != null) { + field.showError(); + return field.getFieldNameOriginal() + " is not valid. Suggestion: " + error; + } + } + } + + return null; + } + + /** + * On continue show alert box and enable buttons. + * + * @param text the text + * @param type the type + */ + private void alertOnContinue(String text, AlertType type) { + + onContinueAlertBlock.setText(text); + onContinueAlertBlock.setType(type); + onContinueAlertBlock.setVisible(true); + continueButton.setEnabled(true); + resetButton.setEnabled(true); + + // hide after some seconds + Timer t = new Timer() { + + @Override + public void run() { + + onContinueAlertBlock.setVisible(false); + + } + }; + + t.schedule(4000); + } + + /** + * On continue show alert box and enable buttons. + * + * @param text the text + * @param showSpinner the show spinner + * @param type the type + * @param hideAfterAWhile the hide after A while + */ + private void alertOnCreate(String text, boolean showSpinner, AlertType type, boolean hideAfterAWhile) { + + onCreateAlertBlock.clear(); + + try { + onCreateAlertBlock.remove(iconSpinner); + } catch (Exception e) { + } + + if (showSpinner) { + onCreateAlertBlock.add(iconSpinner); + } + + onCreateAlertBlock.setText(text); + onCreateAlertBlock.setType(type); + onCreateAlertBlock.setVisible(true); + createButton.setEnabled(true); + goBackButtonSecondStep.setEnabled(true); + + if (hideAfterAWhile) { + // hide after some seconds + Timer t = new Timer() { + + @Override + public void run() { + + onCreateAlertBlock.setVisible(false); + + } + }; + t.schedule(15000); + } + } + + /** + * Validate data. + * + * @return true on success, false otherwise + */ + private String validateDataOnContinue() { + + // remove errors + productTitleGroup.setType(ControlGroupType.NONE); + maintainerControlGroup.setType(ControlGroupType.NONE); + versionControlGroup.setType(ControlGroupType.NONE); + metadataTypesControlGroup.setType(ControlGroupType.NONE); + organizationsGroup.setType(ControlGroupType.NONE); + tagsPanel.setGroupPanelType(ControlGroupType.NONE); + + String title = titleTextBox.getText().trim(); + if (title.isEmpty()) { + productTitleGroup.setType(ControlGroupType.ERROR); + return "Missing title"; + } + + if (title.length() < 2) { + productTitleGroup.setType(ControlGroupType.ERROR); + return "The field title is too short"; + } + + // better check for the title + // String[] splittedTitle = title.split(" "); + + /* + * No check, see #20828 for (String word : splittedTitle) { String replaced = + * word.replaceAll(REGEX_TITLE_PRODUCT_SUBWORD, ""); if(!replaced.equals(word)){ + * productTitleGroup.setType(ControlGroupType.ERROR); return + * "Please note not all characters are allowed for the title"; } } + */ + + // email reg expression + String maintainerMail = maintainerEmailTextbox.getText(); + if (!maintainerMail.isEmpty() && !maintainerMail.matches(REGEX_MAIL)) { + maintainerControlGroup.setType(ControlGroupType.ERROR); + return "Not valid maintainer email"; + } + + // check if version is a number + try { + int number = Integer.valueOf(versionTextbox.getText().trim()); + if (number <= 0) + throw new Exception(); + } catch (Exception e) { + versionControlGroup.setType(ControlGroupType.ERROR); + return "Version must be a natural number greater than zero"; + } + + // check if metadata profile is different from none and its mandatory fields + // have been fulfilled + if (checkSelectedMetaDataProfile()) { + metadataTypesControlGroup.setType(ControlGroupType.ERROR); + return "You must select a Type different frome none"; + } + + if (organizationsListbox.getSelectedItemText() == null) { + organizationsGroup.setType(ControlGroupType.ERROR); + return "You must select an organization in which you want to publish"; + } + + // at least one tag.. + if (tagsPanel.getTags().isEmpty()) { + tagsPanel.setGroupPanelType(ControlGroupType.ERROR); + return "Please add at least one meaningful tag for the item"; + } + + return null; + } + + /** + * Checks if a metadata profile has been chosen and its fields have been + * fulfilled. + * + * @return true, if successful + */ + private boolean checkSelectedMetaDataProfile() { + return metadataTypeListbox.getSelectedItemText().equals(NONE_PROFILE) + && metadataTypeListbox.getItemCount() != 1; + } + + /** + * Reset form event. + * + * @param e the e + */ + @UiHandler("resetButton") + void resetFormEvent(ClickEvent e) { + + // reset main fields + titleTextBox.setText(""); + descriptionTextarea.setText(""); + versionTextbox.setText(""); + maintainerTextbox.setText(""); + maintainerEmailTextbox.setText(""); + tagsPanel.removeTags(); + + // unselect all groups + for (int i = 0; i < groupsListbox.getItemCount(); i++) + groupsListbox.setItemSelected(i, false); + + // delete custom fields + for (CustomFieldEntry customField : customFieldEntriesList) { + customField.removeFromParent(); + } + customFieldEntriesList.clear(); + } + + /** + * Disable dataset editable fields once the dataset has been successfully + * created. + */ + protected void disableDatasetFields() { + + titleTextBox.setEnabled(false); + descriptionTextarea.setEnabled(false); + versionTextbox.setEnabled(false); + maintainerTextbox.setEnabled(false); + maintainerEmailTextbox.setEnabled(false); + visibilityListbox.setEnabled(false); + tagsPanel.freeze(); + licenseListbox.setEnabled(false); + organizationsListbox.setEnabled(false); + addCustomFieldButton.setEnabled(false); + metadataTypeListbox.setEnabled(false); + groupsListbox.setEnabled(false); + + for (CustomFieldEntry ce : customFieldEntriesList) + ce.freeze(); + + // disable profile fields + for (MetaDataField metaField : listOfMetadataFields) { + for (MetaDataFieldSkeleton field : metaField.getListOfMetadataFields()) { + field.freeze(true); + } + + } + + // freeze table of resources + if (resourcesSelectByWEMainPanel != null) + resourcesSelectByWEMainPanel.freeze(); + } + + /** + * change alert block behavior. + * + * @param textToShow the text to show + * @param type the type + * @param visible the visible + */ + private void setAlertBlock(String textToShow, AlertType type, boolean visible) { + + infoBlock.setText(textToShow); + infoBlock.setType(type); + infoBlock.setVisible(visible); + + } + + /** + * On selected license change. + * + * @param c the c + */ + @UiHandler("licenseListbox") + void onSelectedLicenseChange(ChangeEvent c) { + + showLicenseUrl(); + + } + + /** + * The body of the onSelectedLicenseChange. + */ + private void showLicenseUrl() { + + String selectedLicense = licenseListbox.getSelectedItemText(); + int index = -1; + if ((index = licenseBean.indexOf(new LicenseBean(selectedLicense, null))) >= 0) { + LicenseBean foundLicense = licenseBean.get(index); + licenseUrlAnchor.setText(foundLicense.getUrl()); + licenseUrlAnchor.setHref(foundLicense.getUrl()); + licenseUrlAnchor.setVisible(true); + unavailableUrl.setVisible(false); + } else { + licenseUrlAnchor.setVisible(false); + unavailableUrl.setVisible(true); + } + } + + /** + * Hide the groups that are already listed in the profiles page. + * + * @param profiles the profiles + */ + private void hideGroupsAlreadyInProfile(List profiles) { + + List groupsToHide = new ArrayList(); + for (MetaDataProfileBean profile : profiles) + groupsToHide.add(profile.getType()); + + SelectElement se = groupsListbox.getElement().cast(); + + int hiddenElements = 0; + for (int i = 0; i < groupsListbox.getItemCount(); i++) { + if (groupsToHide.contains(groupsListbox.getItemText(i))) { + se.getOptions().getItem(i).getStyle().setProperty("display", "none"); + hiddenElements++; + } + } + + if (hiddenElements == groupsListbox.getItemCount()) + groupsControlGroup.setVisible(false); + else + groupsControlGroup.setVisible(true); + + } + + /** + * Check if resource(s) are missing. + * + * @return true, if successful + */ + private boolean hideManageResources() { + + return receivedBean.getResourceRoot() == null || receivedBean.getResourceRoot().isFolder() + && (receivedBean.getResourceRoot().getChildrenSize() == null + || receivedBean.getResourceRoot().getChildrenSize() == 0); + + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/UpdateDatasetForm.ui.xml b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/UpdateDatasetForm.ui.xml new file mode 100644 index 0000000..971dca9 --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/form/UpdateDatasetForm.ui.xml @@ -0,0 +1,442 @@ + + + + .form-main-style { + margin-left: 10px; + } + + .fieldset-border-style { + border: 1px groove #444 !important; + box-shadow: 0px 0px 0px 0px #000 !important; + padding: 10px !important; + margin: 5px !important; + } + + .legend-style { + width: auto !important; + padding: 10px !important; + margin-bottom: 0 !important; + border-bottom: 0 !important; + } + + @external .form-horizontal .input-large; + .form-horizontal .input-large .input-prepend { + width: 95%; + } + + .block-alert-style { + margin-top: 10px; + padding: 10px; + margin-bottom: 10px; + } + + .tagsPanelStyle { + display: inline-block; + } + + .selected-profile { + font-weight: bold; + } + + .label-go-to-product { + display: inline-block; + vertical-align: middle; + font-weight: bold; + } + + .the-margin-gotoitem { + margin-left: 5px; + margin-top: 10px; + margin-bottom: 10px; + } + + + + + + + + Insert Item Information + + * + is required + + + + + + + + + * + Title : + + + + + + + + + + + + + + + + Description: + + + + + + + + + + + + + + + + + + License: + + + + + + + + + + + + + + + Selected + License Url: + + + Unavailable + + + + + + + Visibility: + + + Restricted + Public + + + + + + + + + + + + + Publish in: + + + + + + + + + Version: + + + + + + + + + * + Author: + + + + + + + + + + + + + + + + * + Author Email: + + + + + + + + + + + + + + + + Maintainer: + + + + + + + + + + + + + + + + Maintainer Email: + + + + + + + + + + + + + + + Types: + + + none + + + + + + + + + + + + + Item Groups: + + + + + + + + + + + + + + + + + + + + + + Continue + Reset + + + + + + + + + Select Item Resources + + + + + + + + + + + + + Continue + + Go + Back + + + + + + + + Insert Item Profile Information + + * + is required + + + + + + + + + + + Custom Field(s): + + + + + + + + + + + + + + + + + + + + + Go to the Item + + + + Add Resources + + Create + + Go + Back + + + + + \ No newline at end of file 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 f9ef26c..560de8a 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 @@ -10,6 +10,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import javax.servlet.http.HttpSession; @@ -22,8 +23,12 @@ import org.gcube.datacatalogue.utillibrary.server.utils.CatalogueUtilMethods; import org.gcube.datacatalogue.utillibrary.server.utils.SessionCatalogueAttributes; import org.gcube.datacatalogue.utillibrary.shared.ResourceBean; import org.gcube.datacatalogue.utillibrary.shared.RolesCkanGroupOrOrg; +import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset; import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanGroup; import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanLicense; +import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanOrganization; +import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanResource; +import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanTag; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService; import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.CatalogueRoleManager; import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.DiscoverTagsList; @@ -35,6 +40,7 @@ import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBea import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceElementBean; import org.gcube.portlets.widgets.mpformbuilder.shared.license.LicenseBean; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetaDataProfileBean; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetadataFieldWrapper; import org.gcube.vomanagement.usermanagement.GroupManager; import org.gcube.vomanagement.usermanagement.UserManager; import org.gcube.vomanagement.usermanagement.exception.GroupRetrievalFault; @@ -241,7 +247,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C DatasetBean bean = null; String userName = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername(); - logger.info("DatasetBean request for " + folderId + " and " + userName); + logger.info("DatasetBean request for folderId " + folderId + " and " + userName); if (isWithinPortal()) { try { @@ -320,6 +326,133 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C return bean; } + /** + * Gets the dataset bean for update. + * + * @param datasetIdOrName the dataset id or name + * @return the dataset bean for update + * @throws Exception the exception + */ + @Override + public DatasetBean getDatasetBeanForUpdate(String datasetIdOrName) throws Exception { + + DatasetBean bean = null; + String userName = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername(); + + logger.info("DatasetBeanForUpdate request for " + datasetIdOrName + " and " + userName); + + String scopePerCurrentUrl = GenericUtils.getScopeFromClientUrl(getThreadLocalRequest()); + + DataCatalogue utils = getCatalogue(scopePerCurrentUrl); + + CkanDataset dataset = utils.getDataset(datasetIdOrName, userName); + + if (dataset == null) { + // the user cannot read the item, so he/she is not the owner nor the admin + throw new Exception("Dataset with id " + datasetIdOrName + " not found for user " + userName); + } + + logger.debug("Building bean"); + bean = new DatasetBean(); + + bean.setId(datasetIdOrName); + bean.setTitle(dataset.getTitle()); + bean.setDescription(dataset.getNotes()); + bean.setLicense(dataset.getLicenseTitle()); + bean.setVisibile(dataset.isPriv()); + + long version = 1; + try { + version = Long.parseLong(dataset.getVersion()); + } catch (Exception e) { + // TODO: handle exception + } + bean.setVersion(version); + + bean.setOwnerIdentifier(dataset.getCreatorUserId()); + + bean.setAuthorFullName(dataset.getAuthor()); + bean.setAuthorEmail(dataset.getAuthorEmail()); + + bean.setMaintainer(dataset.getMaintainer()); + bean.setMaintainerEmail(dataset.getMaintainerEmail()); + + CkanOrganization ckanOrganization = dataset.getOrganization(); + + // UPDATED By Francesco +// String vreName = scope.substring(scope.lastIndexOf("/") + 1, scope.length()); +// logger.debug("In dev mode using the scope: " + scope + " and VRE name: " + vreName); + bean.setOrganizationList( + Arrays.asList(new OrganizationBean(ckanOrganization.getTitle(), ckanOrganization.getName(), true))); + + List listDatasetTags = dataset.getTags(); + + + if(logger.isDebugEnabled()) { + logger.debug("List tags from CKAN are: "); + for (CkanTag ckanTag : listDatasetTags) { + logger.debug("ckanTag: "+ckanTag.getDisplayName()); + logger.debug("ckanTag: "+ckanTag.getName()); + } + } + + // selected tags into Dataset + if (listDatasetTags != null) { + List listTags = dataset.getTags().stream().map(t -> t.getName()).collect(Collectors.toList()); + logger.info("setTags: {}",listTags); + bean.setTags(listTags); + } + + // Vocabulary Tags from Generi Resources + bean.setTagsVocabulary(discoverTagsVocabulary(scopePerCurrentUrl)); + + // By default setting the root folder ID for updating the Resources on the + // client-side + // TODO LOAD THE WORKSPACE ROOT + /* + * Workspace workspace = getWorkspaceFromStorageHub(); + * WorkspaceUtils.toWorkspaceResource(workspace.getRoot().getId(), userName, + * bean, workspace); + */ + + // Settings the CKAN resources + List resources = dataset.getResources(); + if (resources != null) { + List list = new ArrayList(resources.size()); + for (CkanResource ckanResource : resources) { + ResourceElementBean reb = toResourceBean(ckanResource); + list.add(reb); + } + bean.setResources(list); + } + + // Settings the dataset type + Map extras = dataset.getExtrasAsHashMap(); + if (extras != null) { + String theDatasetType = extras.get(SYS_TYPE); + bean.setChosenType(theDatasetType); + } + + logger.debug("Returning bean " + bean); + logger.info("Returning the bean for dataset title {} and type {}" + bean.getTitle(), bean.getChosenType()); + return bean; + } + + /** + * To resource bean. + * + * @param ckanResource the ckan resource + */ + public ResourceElementBean toResourceBean(CkanResource ckanResource) { + ResourceElementBean reb = new ResourceElementBean(); + reb.setName(ckanResource.getName()); + reb.setDescription(ckanResource.getDescription()); + reb.setEditableName(ckanResource.getName()); + reb.setUrl(ckanResource.getUrl()); + reb.setMimeType(ckanResource.getMimetype()); + return reb; + } + /** * Discover from the IS the vocabulary of tags for this scope, if present. * @@ -548,6 +681,72 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C return toReturn; } + /** + * Gets the profile for update. + * + * @param orgName the org name + * @param datasetType the dataset type + * @param datasedIdOrName the datased id or name + * @return the profile for update + * @throws Exception the exception + */ + @Override + public List getProfileForUpdate(String orgName, String datasetType, String datasedIdOrName) + throws Exception { + logger.info("Called getProfileForUpdate for orgName {} and dataset type {} ", orgName, datasetType); + logger.debug("Requested profiles for products into orgName " + orgName); + List toRead = new ArrayList(); + + List toReturn = new ArrayList(); + try { + String evaluatedScope = getScopeFromOrgName(orgName); + logger.debug("Evaluated scope is " + evaluatedScope); + toRead = MetadataDiscovery.getMetadataProfilesList(evaluatedScope, getThreadLocalRequest()); + + for (MetaDataProfileBean metaDataProfileBean : toRead) { + logger.debug("Comparing profile {} with datasetType {}", metaDataProfileBean.getType(), datasetType); + if (metaDataProfileBean.getType().compareTo(datasetType) == 0) { + logger.info("Profile found {}", metaDataProfileBean.getType()); + toReturn.add(metaDataProfileBean); + } + } + } catch (Exception e) { + logger.error("Failed to retrieve profiles for scope coming from organization name " + orgName, e); + throw e; + } + + HttpSession httpSession = this.getThreadLocalRequest().getSession(); + // retrieve scope per current portlet url + String scopePerCurrentUrl = GenericUtils.getScopeFromClientUrl(getThreadLocalRequest()); + String username = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername(); + DataCatalogue utils = getCatalogue(scopePerCurrentUrl); + CkanDataset dataset = utils.getDataset(datasedIdOrName, username); + + if (toReturn.isEmpty()) + throw new Exception("No Profile found for dataset type: " + datasetType); + + // Settings current values in the profile found + MetaDataProfileBean profileBean = toReturn.get(0); + logger.trace("The profile is {}", profileBean); + Map extras = dataset.getExtrasAsHashMap(); + logger.trace("Current extras are {}", extras); + for (MetadataFieldWrapper metadataFieldWrapper : profileBean.getMetadataFields()) { + String fieldName = metadataFieldWrapper.getFieldName(); + logger.trace("Searching field name {} in the profile", fieldName); + String currValueOfExtraField = extras.get(metadataFieldWrapper.getFieldName()); + logger.trace("Current value found is {} for field name {}", currValueOfExtraField, fieldName); + metadataFieldWrapper.setCurrentValues(currValueOfExtraField); + } + + if (logger.isDebugEnabled()) { + logger.debug("Returning filled profile {}", profileBean.getType()); + logger.debug("with MetadataFields {}", profileBean.getMetadataFields()); + } + + logger.info("returing the filled profile {}", profileBean.getType()); + return Arrays.asList(profileBean); + } + /** * Dataset id already exists. * @@ -575,7 +774,10 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C /** * The method tries to retrieve the scope related to the organization using the * map first, if no match is found, it retrieves such information by using - * liferay + * liferay. + * + * @param orgName the org name + * @return the scope from org name */ private String getScopeFromOrgName(String orgName) { @@ -679,12 +881,11 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C /** * Checks if is publisher user. * - * @param isWorkspaceRequest the is workspace request * @return true, if is publisher user * @throws Exception the exception */ @Override - public boolean isPublisherUser(boolean isWorkspaceRequest) throws Exception { + public boolean isPublisherUser() throws Exception { String username = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername(); logger.info("Checking if the user " + username + " can publish or not on the catalogue"); @@ -759,6 +960,60 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C } } + /** + * Checks if is publisher owner or admin user. + * + * @param datasetIdOrName the dataset id or name + * @return true, if is publisher owner or admin user + * @throws Exception the exception + */ + @Override + public boolean isPublisherOwnerOrAdminUser(String datasetIdOrName) throws Exception { + + String username = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername(); + logger.info("Checking if the user " + username + " can publish or not on the catalogue"); + + boolean isPublisher = isPublisherUser(); + + if (isPublisher) { + RolesCkanGroupOrOrg role = null; + String scopePerCurrentUrl = GenericUtils.getScopeFromClientUrl(getThreadLocalRequest()); + + if (!isWithinPortal()) { + role = RolesCkanGroupOrOrg.EDITOR; + logger.warn("OUT FROM PORTAL SETTING HARD-CODED ROLE " + role); + } else { + String keyPerScopeRole = CatalogueUtilMethods + .concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_HIGHEST_ROLE, scopePerCurrentUrl); + HttpSession httpSession = this.getThreadLocalRequest().getSession(); + role = (RolesCkanGroupOrOrg) httpSession.getAttribute(keyPerScopeRole); + } + + // if the user is an EDITOT he/she must be also the owner of the dataset + if (role.equals(RolesCkanGroupOrOrg.EDITOR)) { + logger.info("The user {} is an {}", username, RolesCkanGroupOrOrg.EDITOR); + String loggedUserEmail = GenericUtils.getCurrentUser(getThreadLocalRequest()).getEmail(); + logger.debug("Logged user email: {} ", loggedUserEmail); + DataCatalogue utils = getCatalogue(scopePerCurrentUrl); + CkanDataset dataset = utils.getDataset(datasetIdOrName, username); + String datasetOwnerEmail = dataset.getAuthorEmail(); + logger.debug("Dataset Owner email: {} ", datasetOwnerEmail); + + if (loggedUserEmail != null && datasetOwnerEmail != null + && datasetOwnerEmail.compareTo(loggedUserEmail) == 0) { + logger.info("The user {} is owner of the dataset id {}, returning isOwnerOrAdminUser true ", + username, dataset.getId()); + return true; + } + } else if (role.equals(RolesCkanGroupOrOrg.ADMIN)) { + logger.info("The user {} is an {}", username, RolesCkanGroupOrOrg.ADMIN); + return true; + } + } + logger.info("The user {} does not have the rights to update the dataset with id {}", username, datasetIdOrName); + return false; + } + /** * Checks if is geo JSON valid. * diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/shared/DatasetBean.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/shared/DatasetBean.java index f6c3fd1..1757325 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/shared/DatasetBean.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/shared/DatasetBean.java @@ -9,7 +9,9 @@ import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetaDataProfileB import com.google.gwt.user.client.rpc.IsSerializable; /** - * This bean will contain during ckan metadata creation information related to the future build. + * This bean will contain during ckan metadata creation information related to + * the future build. + * * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ @SuppressWarnings("serial") @@ -31,20 +33,25 @@ public class DatasetBean implements Serializable, IsSerializable { private String selectedOrganization; private long version; // version 1, 2 ... private boolean visible; // Private (false) or Public(true) - private List organizationList; // list of organization in which the user is present and could create the dataset - private ResourceElementBean resourceRoot; // in case of workspace, this is the directory root or the single file information + private List organizationList; // list of organization in which the user is present and could + // create the dataset + private ResourceElementBean resourceRoot; // in case of workspace, this is the directory root or the single file + // information private List metadataList; private List tags; // on retrieve, they are the keys of the product private List tagsVocabulary; // when available private Map> customFields; private List groups; private List groupsForceCreation; + private List resources; - public DatasetBean(){ + public DatasetBean() { super(); } - /** Create a metadata bean object. + /** + * Create a metadata bean object. + * * @param id * @param title * @param description @@ -65,13 +72,10 @@ public class DatasetBean implements Serializable, IsSerializable { * @param addResources * @param metadataList */ - public DatasetBean(String id, String title, String description, - Map> customFields, List tags, - String license, boolean visible, String source, long version, - String authorName, String authorSurname, String authorEmail, String maintainer, - String maintainerEmail, String ownerIdentifier, - List organizationList, String selectedOrganization, - ResourceElementBean resourceRoot, + public DatasetBean(String id, String title, String description, Map> customFields, + List tags, String license, boolean visible, String source, long version, String authorName, + String authorSurname, String authorEmail, String maintainer, String maintainerEmail, String ownerIdentifier, + List organizationList, String selectedOrganization, ResourceElementBean resourceRoot, List metadataList, List groups, List tagsVocabulary) { super(); this.id = id; @@ -289,6 +293,14 @@ public class DatasetBean implements Serializable, IsSerializable { this.groupsForceCreation = groupsForceCreation; } + public void setResources(List resources) { + this.resources = resources; + } + + public List getCkanResources() { + return resources; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); diff --git a/src/test/java/org/gcube/portlets/widgets/ckandatapublisherwidget/TestPublishingWidget.java b/src/test/java/org/gcube/portlets/widgets/ckandatapublisherwidget/TestPublishingWidget.java index 3244f73..2735a17 100644 --- a/src/test/java/org/gcube/portlets/widgets/ckandatapublisherwidget/TestPublishingWidget.java +++ b/src/test/java/org/gcube/portlets/widgets/ckandatapublisherwidget/TestPublishingWidget.java @@ -1,31 +1,31 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget; - import java.util.Arrays; import java.util.Calendar; +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.storagehubwrapper.server.StorageHubWrapper; import org.gcube.datacatalogue.utillibrary.server.DataCatalogueFactory; +import org.gcube.datacatalogue.utillibrary.server.DataCatalogueImpl; +import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset; import org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils.WorkspaceUtils; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetBean; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean; +import org.junit.Test; import org.slf4j.LoggerFactory; - - /** * The Class TestDataCatalogueLib. * - * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy) - * Jun 1, 2020 + * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy) Jun 1, 2020 */ public class TestPublishingWidget { private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(TestPublishingWidget.class); private String scope = "/gcube"; - //private String testUser = "costantino_perciante"; + // private String testUser = "costantino_perciante"; private String testUser = "francesco.mangiacrapa"; private String authorizationToken = ""; @@ -34,23 +34,50 @@ public class TestPublishingWidget { * * @throws Exception the exception */ - //@Before - public void before() throws Exception{ + // @Before + public void before() throws Exception { } + + @Test + public void getDataset() { + + try { + scope = "/d4science.research-infrastructures.eu/D4OS/Blue-Cloud2026Project"; + authorizationToken = "8c3ce374-5482-422d-9542-97b1b9360747-843339462"; //Blue-Cloud2026Project + + ScopeProvider.instance.set(scope); + SecurityTokenProvider.instance.set(authorizationToken); + + String datasetId = "blue-cloud_2026_-_a_federated_european_fair_and_open_research_ecosystem_for_oceans_seas_coastal_and"; + + DataCatalogueFactory factory = DataCatalogueFactory.getFactory(); + + DataCatalogueImpl utils = factory.getUtilsPerScope(scope); + + CkanDataset dataset = utils.getDataset(datasetId, testUser); + System.out.println("Dataset: "+dataset); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + } + /** * Factory test. * * @throws Exception the exception */ - //@Test - public void factoryTest() throws Exception{ + // @Test + public void factoryTest() throws Exception { DataCatalogueFactory factory = DataCatalogueFactory.getFactory(); - while(true){ + while (true) { factory.getUtilsPerScope(scope); - Thread.sleep(60* 1000 * 3); + Thread.sleep(60 * 1000 * 3); factory.getUtilsPerScope(scope); break; } @@ -61,16 +88,16 @@ public class TestPublishingWidget { } } - - //@Test - public void getDatasetBeanTest() throws Exception{ + + // @Test + public void getDatasetBeanTest() throws Exception { ScopeProvider.instance.set(scope); String userName = testUser; String token = authorizationToken; - + String folderId = "6399daa7-2173-4314-b4f7-2afa24eae8f8"; DatasetBean bean; - try{ + try { bean = new DatasetBean(); bean.setId(folderId); bean.setDescription("This is a fantastic description"); @@ -83,24 +110,23 @@ public class TestPublishingWidget { bean.setMaintainer("Francesco Mangiacrapa"); bean.setMaintainerEmail("francesco.mangiacrapa@isti.cnr.it"); - //UPDATED By Francesco - String vreName = scope.substring(scope.lastIndexOf("/")+1,scope.length()); - LOG.debug("In dev mode using the scope: "+scope+" and VRE name: "+vreName); + // UPDATED By Francesco + String vreName = scope.substring(scope.lastIndexOf("/") + 1, scope.length()); + LOG.debug("In dev mode using the scope: " + scope + " and VRE name: " + vreName); bean.setOrganizationList(Arrays.asList(new OrganizationBean(vreName, vreName.toLowerCase(), true))); bean.setOwnerIdentifier(userName); - if(folderId != null && !folderId.isEmpty()){ + if (folderId != null && !folderId.isEmpty()) { StorageHubWrapper storageHubWrapper = new StorageHubWrapper(scope, token, false, false, true); WorkspaceUtils.toWorkspaceResource(folderId, userName, bean, storageHubWrapper.getWorkspace()); } - }catch(Exception e){ + } catch (Exception e) { LOG.error("Error while building bean into dev mode", e); throw new Exception("Error while retrieving basic information " + e.getMessage()); } - - LOG.info("Got dataset: "+bean); + + LOG.info("Got dataset: " + bean); } - }