From 4a643d742313cbeec062e2e493bce8bf2708d7e8 Mon Sep 17 00:00:00 2001 From: "francesco.mangiacrapa" Date: Mon, 17 Apr 2023 16:03:40 +0200 Subject: [PATCH] in progress on #24166 --- .settings/org.eclipse.wst.common.component | 78 +++++- .../client/GeoPortalDataEntryApp.java | 27 +- .../client/GeoportalDataEntryService.java | 15 ++ .../GeoportalDataEntryServiceAsync.java | 4 + .../client/ui/GeonaMainTabPanel.ui.xml | 2 +- .../client/ui/edit/UpdateRecord.java | 244 +++++++++++++++++- .../client/ui/edit/UpdateRecord.ui.xml | 3 +- .../server/FormDataObjectToJSON.java | 5 +- .../server/GeoportalDataEntryServiceImpl.java | 212 ++++++++++++++- .../server/MongoServiceUtil.java | 95 +++++-- src/test/resources/.gitignore | 1 + 11 files changed, 621 insertions(+), 65 deletions(-) diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 5f01c96..b0ea40a 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,5 +1,11 @@ - + + + + + + + @@ -90,7 +96,13 @@ - + + + + + + + @@ -181,7 +193,13 @@ - + + + + + + + @@ -272,7 +290,13 @@ - + + + + + + + @@ -363,7 +387,13 @@ - + + + + + + + @@ -412,7 +442,19 @@ uses - + + uses + + + uses + + + + + + + + @@ -503,7 +545,13 @@ - + + + + + + + @@ -594,7 +642,13 @@ - + + + + + + + @@ -685,7 +739,13 @@ - + + + + + + + diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java index 0a92dee..a2aa692 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java @@ -74,7 +74,10 @@ import org.gcube.portlets.user.geoportaldataentry.shared.UserRights; import org.gcube.portlets.widgets.mpformbuilder.client.MetadataProfileFormBuilderServiceAsync; import org.gcube.portlets.widgets.mpformbuilder.client.form.generic.CreateMetadataForm; import org.gcube.portlets.widgets.mpformbuilder.client.form.generic.CreateMetadataForm.OPERATION; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.DataTypeWrapper; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetaDataProfileBean; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetadataFieldWrapper; +import org.gcube.portlets.widgets.mpformbuilder.shared.upload.FilePath; import org.gcube.portlets.widgets.mpformbuilder.shared.upload.FileUploaded; import org.gcube.portlets.widgets.mpformbuilder.shared.upload.FileUploadedRemote; @@ -1524,7 +1527,7 @@ public class GeoPortalDataEntryApp implements EntryPoint { case EDIT_PROJECT: { final Modal modal3 = new Modal(true, true); modal3.setTitle( - "Edit: " + "Update Project with id: " + resultDocumentDV.getId() + ""); // modal3.setWidth(950); // modal3.setHeight("700px"); @@ -1846,6 +1849,17 @@ public class GeoPortalDataEntryApp implements EntryPoint { } GeoNaFormCardModel geoNaFormCardModel = new GeoNaFormCardModel(metaDataProfileBean, null, cct, gcubeProfile); + + + //In case of UPDATE operation, the fields of kind File will be not mandatory. + if(operation!=null && operation.equals(OPERATION.UPDATE)) { + List fields = geoNaFormCardModel.getMetadataProfileBean().getMetadataFields(); + for (MetadataFieldWrapper metadataFieldWrapper : fields) { + if(metadataFieldWrapper.getMandatory() && metadataFieldWrapper.getType().equals(DataTypeWrapper.File)) { + metadataFieldWrapper.setMandatory(false); + } + } + } CreateMetadataForm baseForm = null; if (fileset == null) { @@ -1870,14 +1884,19 @@ public class GeoPortalDataEntryApp implements EntryPoint { return null; List fileUploaded = new ArrayList(); + + FilesetDV filesetDV = fileset.get(0); + + GWT.log("listFiles name: "+filesetDV.getGcubeProfileFieldName()); - FilesetDV listFiles = fileset.get(0); - - for (PayloadDV payload : listFiles.getListPayload()) { + for (PayloadDV payload : filesetDV.getListPayload()) { FileUploadedRemote fu = new FileUploadedRemote(); fu.setFileName(payload.getName()); fu.setUrl(payload.getLink()); fu.setMimeType(payload.getMimetype()); + //adding FilePath according to spefic file registred in the UCD + FilePath filePath = new FilePath(filesetDV.getGcubeProfileFieldName(), filesetDV.getFilesetFieldName()); + fu.setFilePath(filePath); fileUploaded.add(fu); } diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java index 09a2493..0deb7ec 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java @@ -7,6 +7,7 @@ import org.gcube.application.geoportalcommon.shared.ResultSetPaginatedData; import org.gcube.application.geoportalcommon.shared.SearchingFilter; import org.gcube.application.geoportalcommon.shared.geoportal.ResultDocumentDV; import org.gcube.application.geoportalcommon.shared.geoportal.config.ActionDefinitionDV; +import org.gcube.application.geoportalcommon.shared.geoportal.config.FilePathDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.LifecycleInformationDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.TemporalReferenceDV; @@ -219,4 +220,18 @@ public interface GeoportalDataEntryService extends RemoteService { */ ProjectEdit getProjectEdit(String profileID, String projectID) throws Exception; + /** + * Update geportal data form. + * + * @param profileID the profile ID + * @param projectID the project ID + * @param section the section + * @param sectionPath the section path + * @param listFilePaths the list file paths + * @return the commit report + * @throws Exception the exception + */ + CommitReport updateGeportalDataForm(String profileID, String projectID, GeoNaFormDataObject section, + String sectionPath, List listFilePaths) throws Exception; + } diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java index e118e3a..4ca3553 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java @@ -7,6 +7,7 @@ import org.gcube.application.geoportalcommon.shared.ResultSetPaginatedData; import org.gcube.application.geoportalcommon.shared.SearchingFilter; import org.gcube.application.geoportalcommon.shared.geoportal.ResultDocumentDV; import org.gcube.application.geoportalcommon.shared.geoportal.config.ActionDefinitionDV; +import org.gcube.application.geoportalcommon.shared.geoportal.config.FilePathDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.LifecycleInformationDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.TemporalReferenceDV; @@ -51,6 +52,9 @@ public interface GeoportalDataEntryServiceAsync { void saveGeonaDataForms(String profileID, Tree_Node tree_Node, List stepsOnPostCreation, AsyncCallback callback); + + void updateGeportalDataForm(String profileID, String projectID, GeoNaFormDataObject section, + String sectionPath, List listFilePaths, AsyncCallback callback); void getGeonaInitConfig(AsyncCallback callback); diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.ui.xml b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.ui.xml index cc6bf6d..ea2d301 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.ui.xml +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.ui.xml @@ -104,7 +104,7 @@ Publication Report Edit + icon="PENCIL">Update Delete Project diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.java index 1128f7f..182a286 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.java @@ -1,28 +1,47 @@ package org.gcube.portlets.user.geoportaldataentry.client.ui.edit; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.gcube.application.geoportalcommon.shared.geoportal.DocumentDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ResultDocumentDV; +import org.gcube.application.geoportalcommon.shared.geoportal.config.FilePathDV; import org.gcube.application.geoportalcommon.shared.geoportal.config.GcubeProfileDV; import org.gcube.application.geoportaldatamapper.shared.MetaDataProfileBeanExt; import org.gcube.application.geoportaldatamapper.shared.ProjectEdit; +import org.gcube.portlets.user.geoportaldataentry.client.ConstantsGeoPortalDataEntryApp.ACTION_PERFORMED_ON_ITEM; import org.gcube.portlets.user.geoportaldataentry.client.GeoPortalDataEntryApp; import org.gcube.portlets.user.geoportaldataentry.client.GeoportalDataEntryServiceAsync; +import org.gcube.portlets.user.geoportaldataentry.client.events.OperationPerformedOnItemEvent; import org.gcube.portlets.user.geoportaldataentry.client.ui.card.GeoNaFormCardModel; +import org.gcube.portlets.user.geoportaldataentry.client.ui.report.ReportTemplateToHTML; import org.gcube.portlets.user.geoportaldataentry.client.ui.utils.LoaderIcon; +import org.gcube.portlets.user.geoportaldataentry.shared.CommitReport; +import org.gcube.portlets.user.geoportaldataentry.shared.GeoNaFormDataObject; import org.gcube.portlets.widgets.mpformbuilder.client.form.generic.CreateMetadataForm.OPERATION; +import org.gcube.portlets.widgets.mpformbuilder.client.form.generic.GenericFormEvents.GenericFormEventsListener; +import org.gcube.portlets.widgets.mpformbuilder.shared.GenericDatasetBean; import com.github.gwtbootstrap.client.ui.Alert; import com.github.gwtbootstrap.client.ui.Button; import com.github.gwtbootstrap.client.ui.ControlGroup; import com.github.gwtbootstrap.client.ui.ListBox; +import com.github.gwtbootstrap.client.ui.Modal; import com.github.gwtbootstrap.client.ui.constants.AlertType; import com.google.gwt.core.client.GWT; 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.shared.HandlerManager; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.Widget; @@ -48,28 +67,47 @@ public class UpdateRecord extends Composite { @UiField ControlGroup controlsControlGroup; - + @UiField Button buttonUpdate; public static final String PLACEHOLDER_LIST_BOX = "Select section..."; - private LoaderIcon loaderProjectSections = new LoaderIcon("Loading Project sections..., please wait"); + private LoaderIcon loaderProjectSections = new LoaderIcon("Loading Project sections... please wait"); - public UpdateRecord(HandlerManager editorManagerBus, String profileID, String projectID) { + private GeoNaFormCardModel currentCardSelected; + + private String profileID; + + private String projectID; + + private HashMap> sectionPathFilePaths = new HashMap<>(); + + private MetadataFormCardEventHandler formCardEventHandler = new MetadataFormCardEventHandler(); + + private ProjectEdit projectEditDTO; + + private HandlerManager appManagerBus; + + public UpdateRecord(HandlerManager appManagerBus, String profileID, String projectID) { initWidget(uiBinder.createAndBindUi(this)); + this.appManagerBus = appManagerBus; + this.profileID = profileID; + this.projectID = projectID; + setUpdateButtonEnabled(false); htmlPanelContainer.setVisible(false); alertHTMLPanel.add(loaderProjectSections); - + scrollSectionContent.getElement().getStyle().setProperty("maxHeight", "500px"); - + GeoportalDataEntryServiceAsync.Util.getInstance().getProjectEdit(profileID, projectID, new AsyncCallback() { @Override public void onSuccess(ProjectEdit result) { + projectEditDTO = result; htmlPanelContainer.setVisible(true); try { @@ -80,14 +118,39 @@ public class UpdateRecord extends Composite { listBoxSections.addItem(PLACEHOLDER_LIST_BOX, PLACEHOLDER_LIST_BOX); + int sectionArray = 0; + for (final MetaDataProfileBeanExt profileBean : result.getTheProfileBeans()) { - listBoxSections.addItem(profileBean.getType(), profileBean.getType()); + + GcubeProfileDV profileDV = profileBean.getGcubeProfileDV(); + + String sectionPath = profileDV.getParentName() != null ? profileDV.getParentName() : ""; + + sectionPath += profileDV.getSectionName(); + + // increment section stored as array + if (profileDV.getMaxOccurs() == 0 || profileDV.getMaxOccurs() > 1) { + sectionPath += "[" + sectionArray + "]"; + sectionArray++; + } else { + sectionArray = 0; + } + + List filePaths = profileDV.getFilePaths(); + + if (filePaths != null) + sectionPathFilePaths.put(sectionPath, filePaths); + + GWT.log("Adding type: " + profileBean.getType() + ", in the section path: " + sectionPath); + + listBoxSections.addItem(profileBean.getType(), sectionPath); } listBoxSections.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { + setUpdateButtonEnabled(false); MetaDataProfileBeanExt selectedBean = result.getTheProfileBeans() .get(listBoxSections.getSelectedIndex() - 1); // -1 because the first element is // the PLACEHOLDER "Select @@ -98,9 +161,12 @@ public class UpdateRecord extends Composite { GcubeProfileDV gcubeProfile = selectedBean.getGcubeProfileDV(); - GeoNaFormCardModel formcard = GeoPortalDataEntryApp.buildNewFormCardModelFromProfile( - gcubeProfile, 1, selectedBean, OPERATION.UPDATE, editorManagerBus); - scrollSectionContent.add(formcard.getMetadataForm()); + currentCardSelected = GeoPortalDataEntryApp.buildNewFormCardModelFromProfile( + gcubeProfile, 1, selectedBean, OPERATION.UPDATE, appManagerBus); + + currentCardSelected.getMetadataForm().addListener(formCardEventHandler); + + scrollSectionContent.add(currentCardSelected.getMetadataForm()); } }); @@ -109,6 +175,7 @@ public class UpdateRecord extends Composite { @Override public void onFailure(Throwable caught) { + projectEditDTO = null; htmlPanelContainer.setVisible(true); alertHTMLPanel.remove(loaderProjectSections); @@ -125,10 +192,167 @@ public class UpdateRecord extends Composite { } }); + + bindEvents(); } - + + private void setUpdateButtonEnabled(boolean bool) { + buttonUpdate.setEnabled(bool); + } + + private void bindEvents() { + + buttonUpdate.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + + alertHTMLPanel.clear(); + boolean isFormValid = currentCardSelected.getMetadataForm().isFormDataValid(); + + if (!isFormValid) { + Alert alert = new Alert("Error/s detected, please check your data entry...", AlertType.WARNING); + alert.setClose(true); + alertHTMLPanel.add(alert); + return; + } + + GeoNaFormDataObject gfdo = new GeoNaFormDataObject( + Arrays.asList(currentCardSelected.getMetadataForm().getFormDataBean()), + currentCardSelected.getGcubeProfile()); + + String sectionPath = listBoxSections.getSelectedValue(); + + GWT.log("sectionPath is: " + sectionPath); + + List listFilePaths = sectionPathFilePaths.get(sectionPath); + + final Modal modal = new Modal(true, true); + DocumentDV theDocument = projectEditDTO.getTheProjectDV().getTheDocument(); + + modal.setTitle("Updating..."); + + final FlowPanel panelContainer = new FlowPanel(); + + LoaderIcon loader = new LoaderIcon("Operation in progress... please wait"); + modal.add(loader); + String htmlMsg = "Updating the section "+listBoxSections.getSelectedItemText()+" of the project with:"; + htmlMsg += "
    "; + htmlMsg += "
  • id: " + projectID + "
  • "; + htmlMsg += "
  • profile: " + profileID + "
  • "; + htmlMsg += "
"; + htmlMsg += "
"; + panelContainer.add(new HTML(htmlMsg)); + panelContainer.add(loader); + panelContainer.add(new HTML("

")); + + modal.add(panelContainer); +// modal3.setWidth(950); +// modal3.setHeight("700px"); + modal.setCloseVisible(false); + + GeoportalDataEntryServiceAsync.Util.getInstance().updateGeportalDataForm(profileID, projectID, gfdo, + sectionPath, listFilePaths, new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + modal.setCloseVisible(true); + modal.setTitle("Error :-("); + panelContainer.clear(); + String errorMsg = "Sorry, an error occurrend when updating the project with id: "+projectID+". Please, try again. If the problem persists, please contact the support"; + Alert alert = new Alert(errorMsg, AlertType.ERROR); + alert.setClose(false); + modal.add(alert); + + } + + @Override + public void onSuccess(CommitReport result) { + modal.setCloseVisible(true); + modal.setTitle("Project updated!"); + panelContainer.clear(); + Alert alert = new Alert(); + alert.setClose(false); + alert.setType(AlertType.SUCCESS); + String htmlMsg = "The project with:"; + htmlMsg += "
    "; + htmlMsg += "
  • id: " + projectID + "
  • "; + htmlMsg += "
  • profile: " + profileID + "
  • "; + htmlMsg += "
"; + htmlMsg += "
"; + htmlMsg += "has been updated correctly!"; + alert.setHTML(htmlMsg); + + ReportTemplateToHTML rtth2 = new ReportTemplateToHTML("Project", result.getProjectAsJSON(), + false, false); + rtth2.showAsJSON(false); + + panelContainer.add(alert); + panelContainer.add(rtth2); + + appManagerBus.fireEvent(new OperationPerformedOnItemEvent( + profileID, null, ACTION_PERFORMED_ON_ITEM.UPDATED_PROJECT)); + + } + }); + + modal.show(); + } + }); + + } + public void noUpdateMode() { buttonUpdate.setVisible(false); } + /** + * The Class MetadataFormCardEventHandler. + * + * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) + * + * Oct 12, 2020 + */ + private class MetadataFormCardEventHandler implements GenericFormEventsListener { + + /** + * On form data valid. + * + * @param genericDatasetBean the generic dataset bean + */ + @Override + public void onFormDataValid(GenericDatasetBean genericDatasetBean) { + setUpdateButtonEnabled(true); + + } + + /** + * On form data edit. + */ + @Override + public void onFormDataEdit() { + setUpdateButtonEnabled(false); + + } + + /** + * On form aborted. + */ + @Override + public void onFormAborted() { + + } + + /** + * On validation error. + * + * @param throwable the throwable + * @param errorMsg the error msg + */ + @Override + public void onValidationError(Throwable throwable, String errorMsg) { + + } + } + } diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.ui.xml b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.ui.xml index 91eda14..4349254 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.ui.xml +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/edit/UpdateRecord.ui.xml @@ -50,7 +50,6 @@ UPDATE + addStyleNames="{style.button-save-style}" ui:field="buttonUpdate">UPDATE \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/FormDataObjectToJSON.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/FormDataObjectToJSON.java index 54accc5..7b6201e 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/FormDataObjectToJSON.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/FormDataObjectToJSON.java @@ -55,7 +55,7 @@ public class FormDataObjectToJSON { for (Tree_Node treeNodeChild : tree_Node.getChildren()) { GeoNaFormDataObject gnaFO = treeNodeChild.getData(); - + // Reading data and profile List listGDB = gnaFO.getListGDB(); GcubeProfileDV profile = gnaFO.getGcubeProfileDV(); @@ -161,7 +161,7 @@ public class FormDataObjectToJSON { * @return the JSON object * @throws JSONException the JSON exception */ - private JSONObject genericDatasetBeanToJSON(GenericDatasetBean gdb) throws JSONException { + protected JSONObject genericDatasetBeanToJSON(GenericDatasetBean gdb) throws JSONException { JSONObject sectJSONObject = JSONObjecOrdered.instance(); @@ -237,6 +237,7 @@ public class FormDataObjectToJSON { } return target; } + /** * The Class JSONObjecOrdered. diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java index a4cbe68..6153979 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java @@ -5,7 +5,12 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; +import java.lang.reflect.Type; +import java.net.URL; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -13,6 +18,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -61,6 +67,7 @@ import org.gcube.common.portal.PortalContext; import org.gcube.contentmanagement.blobstorage.transport.backend.RemoteBackendException; import org.gcube.portlets.user.geoportaldataentry.client.GeoportalDataEntryService; import org.gcube.portlets.user.geoportaldataentry.client.ProjectFormCard; +import org.gcube.portlets.user.geoportaldataentry.server.FormDataObjectToJSON.JSONObjecOrdered; import org.gcube.portlets.user.geoportaldataentry.shared.CommitReport; import org.gcube.portlets.user.geoportaldataentry.shared.GNADataEntryExtendedConfigProfile; import org.gcube.portlets.user.geoportaldataentry.shared.GeoNaFormDataObject; @@ -69,6 +76,7 @@ import org.gcube.portlets.user.geoportaldataentry.shared.Tree_Node; import org.gcube.portlets.user.geoportaldataentry.shared.UserRights; import org.gcube.portlets.widgets.mpformbuilder.shared.GenericDatasetBean; import org.gcube.portlets.widgets.mpformbuilder.shared.upload.FileUploaded; +import org.gcube.portlets.widgets.mpformbuilder.shared.upload.FileUploadedRemote; import org.gcube.vomanagement.usermanagement.RoleManager; import org.gcube.vomanagement.usermanagement.exception.GroupRetrievalFault; import org.gcube.vomanagement.usermanagement.exception.UserRetrievalFault; @@ -79,7 +87,13 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.internal.LinkedTreeMap; +import com.google.gson.reflect.TypeToken; import com.google.gwt.user.server.rpc.RemoteServiceServlet; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.spi.json.GsonJsonProvider; +import com.jayway.jsonpath.spi.json.JsonOrgJsonProvider; /** * The server side implementation of the RPC service. @@ -217,6 +231,94 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } } + @Override + public CommitReport updateGeportalDataForm(String profileID, String projectID, GeoNaFormDataObject section, + String sectionPath, List listFilePaths) throws Exception { + LOG.info("updateGeonaDataForm called for profileID {}", profileID); + LOG.info("and sectionPath {}", sectionPath); + LOG.info("and listFilePaths {}", listFilePaths); + + try { + + if (section == null || section.getListGDB() == null || section.getListGDB().get(0) == null) + throw new Exception("Input error. The section is null"); + + GenericDatasetBean sectionBean = section.getListGDB().get(0); + + // Converter + FormDataObjectToJSON metadataConverter = new FormDataObjectToJSON(); + // JSON Section to update converted as JSONObject + JSONObject jsonSectionObject = metadataConverter.genericDatasetBeanToJSON(sectionBean); + LOG.info("Json Section Object: {}", jsonSectionObject.toString()); + + Configuration configuration = Configuration.builder().jsonProvider(new GsonJsonProvider()).build(); +// Type type = new TypeToken>>() {}.getType(); +// Set> myMap = gson.fromJson(json, type); + + // Source Project + String jsonSourceProject = getJSONDocumentInTheProject(profileID, projectID); + LOG.info("Json source Object: {}", jsonSourceProject); + + //If the section path is the Root document, passed as "$.", fixing as "$" + if(sectionPath.compareTo(FormDataObjectToJSON.JSON_$_POINTER+".")==0) + sectionPath = FormDataObjectToJSON.JSON_$_POINTER; + + ProjectsCaller client = GeoportalClientCaller.projects(); + + + JSONObject currentSectionJObject = JsonPath.parse(jsonSourceProject, configuration).read(sectionPath); + LOG.info("currentSectionJObject: {}", currentSectionJObject.toString()); + + // Merged section between updated and current + JSONObject mergedSection = JSONObjecOrdered.instance(); + mergedSection = FormDataObjectToJSON.deepMerge(jsonSectionObject, + currentSectionJObject); + + LOG.info("Merged section: {}", mergedSection.toString()); + + // Putting the merged section into Document + Object newDocument = JsonPath.parse(jsonSourceProject, configuration).set(sectionPath, mergedSection) + .json(); + + String newDocumentString = newDocument.toString(); + LOG.debug("Going to call updateProject with document: {}", newDocumentString); + + Document updatedDocument = Serialization.read(newDocumentString, Document.class); + Project project = client.updateProject(profileID, projectID, updatedDocument); + LOG.debug("Medatata Updated with document: {}", project.getTheDocument()); + + SessionUtil.getCurrentContext(getThreadLocalRequest(), true); + + //Cleaning all the fileset path of the section (defined in the UCD) + for (FilePathDV filePath: listFilePaths) { + + String filesetFieldName = filePath.getFieldName(); + String filesetPath = sectionPath+"."+filesetFieldName; + //Replacing $.abc with $..abc + filesetPath = filesetPath.replaceFirst("\\.", ".."); + LOG.info("Going to delete fileset path: {}", filesetPath); + //client.deleteFileset(profileID, projectID, filesetPath, true); + } + + List filesUploaded = sectionBean.getFilesUploaded(); + if(filesUploaded!=null && !filesUploaded.isEmpty()) { + replaceFiles(project, sectionPath, section.getGcubeProfileDV(), filesUploaded); + } + + LOG.info("Project with id " + project.getId() + " updated correclty"); + ProjectDVBuilder projectBuilder = ProjectDVBuilder.newBuilder().fullDocumentMap(true); + ProjectDV toProjectDV = ConvertToDataValueObjectModel.toProjectDV(project, projectBuilder); + newDocumentString = toProjectDV.getTheDocument().getDocumentAsJSON(); + LOG.info("Got Document: {} ", newDocumentString); + return new CommitReport(projectID, profileID, newDocumentString, null); + } catch (Exception e) { + LOG.error("Error on converting form data: ", e); + throw new Exception( + "Error occurred on converting data, try again or contact the support. Error: " + e.getMessage()); + } + + } + /** * Recursive upload fileset. * @@ -343,14 +445,16 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen + " has maxOccurs > 1 need to manage it as array, going to add the array index"); String arraySectionJSONPAth = String.format("%s[%d]", sectionJSONPath, jpcV); LOG.debug("registering the fileset in the array section: " + sectionJSONPath); - - access = ConvertToDataServiceModel.getAccessFromDocumentSection(theJSONDocument,arraySectionJSONPAth); + + access = ConvertToDataServiceModel.getAccessFromDocumentSection(theJSONDocument, + arraySectionJSONPAth); mongoService.registerFileSet(profileID, theProject, arraySectionJSONPAth, filePath.getFieldName(), filePath.getFieldDefinition(), access, fileset); } else { LOG.info("The gCube Profile with the section " + sectionJSONPath + " has maxOccurs = 1"); LOG.debug("registering the fileset in the section: " + sectionJSONPath); - access = ConvertToDataServiceModel.getAccessFromDocumentSection(theJSONDocument,sectionJSONPath); + access = ConvertToDataServiceModel.getAccessFromDocumentSection(theJSONDocument, + sectionJSONPath); mongoService.registerFileSet(profileID, theProject, sectionJSONPath, filePath.getFieldName(), filePath.getFieldDefinition(), access, fileset); } @@ -367,6 +471,94 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } + /** + * Replace files. + * + * @param theProject the the project + * @param sectionJSONPath the section JSON path + * @param gcubeProfile the gcube profile + * @param files the files + * @throws Exception the exception + */ + protected void replaceFiles(Project theProject, String sectionJSONPath, GcubeProfileDV gcubeProfile, + List files) throws Exception { + LOG.debug("replaceFiles called [projectID: " + theProject.getId() + "], [sectionJSONPath: " + sectionJSONPath + + "], [files: " + files + "]"); + + Map collectFilesetPerFieldDef = new HashMap(); + if (files.size() > 0) { + // Iterating on the files upload for the section + for (int i = 0; i < files.size(); i++) { + FileUploaded file = files.get(i); + String formFieldName = file.getFilePath().getFormFieldLabel(); + LOG.debug("Uploading file: " + file.getFileName() + ", from formFieldName: " + formFieldName); + FilePathDV filePath = retrieveFilePathForGcubeProfileFieldName(formFieldName, gcubeProfile); + LOG.info("Found {} for the form fieldName {}", filePath, formFieldName); + if (filePath == null) { + String error = "It is not possible to register the file " + formFieldName + + ", missing configuration in the filePaths config of: " + gcubeProfile; + throw new Exception(error); + } + + // Collecting Fileset per Field Definition + FileSetDataObject collFieldDef = collectFilesetPerFieldDef.get(filePath.getFieldDefinition()); + if (collFieldDef == null) { + collFieldDef = new FileSetDataObject(); + collFieldDef.setFilePathDV(filePath); + } + + try { + + File tempDir = Files.createTempDirectory("GEOPORTAL_REPLACE_FILES_").toFile(); + String tmpDirPath = tempDir.getAbsolutePath(); + File input; + File output; + if (file instanceof FileUploadedRemote) { + FileUploadedRemote remote = (FileUploadedRemote) file; + LOG.info("Uploaded file is remote: " + remote.getUrl()); + InputStream in = new URL(remote.getUrl()).openStream(); + output = new File(tmpDirPath, remote.getFileName()); + Path outputAbsolutePath = Paths.get(output.getAbsolutePath()); + Files.copy(in, outputAbsolutePath, StandardCopyOption.REPLACE_EXISTING); + LOG.info("Remote file: " + remote.getUrl() + ", copied to new file: " + output.getName()); + } else { + LOG.info("Uploaded file is local: " + file.getTempSystemPath()); + input = new File(file.getTempSystemPath()); + output = new File(tmpDirPath, file.getFileName()); + copyContent(input, output); + LOG.info("Temp file: " + file.getTempSystemPath() + ", copied to new file: " + output.getName()); + } + + collFieldDef.addFile(output); + tempDir.deleteOnExit(); + } catch (Exception e) { + LOG.warn("Skipping file: " + file.getFileName() + ". Error: " + e.getMessage()); + } + + collectFilesetPerFieldDef.put(filePath.getFieldDefinition(), collFieldDef); + + } + + } + + LOG.info("Cluster of fileset per fieldDefinition is: " + collectFilesetPerFieldDef); + String theJSONDocument = theProject.getTheDocument().toJson(); + MongoServiceUtil mongoService = new MongoServiceUtil(); + + for (String fieldDefinition : collectFilesetPerFieldDef.keySet()) { + FileSetDataObject uploadedFileset = collectFilesetPerFieldDef.get(fieldDefinition); + LOG.info("Uploading fileset: " + uploadedFileset); + File[] fileset = uploadedFileset.getFileset(); + FilePathDV filePath = uploadedFileset.getFilePathDV(); + Access access = ConvertToDataServiceModel.getAccessFromDocumentSection(theJSONDocument, sectionJSONPath); + + LOG.info("Going to registrer files: "+Arrays.asList(fileset).toString()); + mongoService.registerFileSet(theProject.getProfileID(), theProject, sectionJSONPath, + filePath.getFieldName(), filePath.getFieldDefinition(), access, fileset); + + } + } + /** * Creates the temp file on storage. * @@ -520,13 +712,13 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen ResultSetPaginatedData searchedData = new ResultSetPaginatedData(); - //If reloadFromService = true, loads the document from the service + // If reloadFromService = true, loads the document from the service Integer totalProjectForProfile = null; - - //Loading total documents from the session - if(!reloadFromService) { + + // Loading total documents from the session + if (!reloadFromService) { totalProjectForProfile = SessionUtil.getTotalDocumentForProfileID(getThreadLocalRequest(), - theProfileID); + theProfileID); } if (totalProjectForProfile == null) { @@ -1159,7 +1351,7 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen ProjectDV theProjectDV = ConvertToDataValueObjectModel.toProjectDV(theProject, projectBuilder); ProjectEdit projectEdit = Geoportal_JSON_Mapper.loadProjectEdit(theProjectDV, scope, user.getUsername()); - + if (LOG.isDebugEnabled()) { Geoportal_JSON_Mapper.prettyPrintProjectEdit(projectEdit); } @@ -1173,7 +1365,7 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen erroMsg + ". Error: " + e.getMessage() + ". Refresh and try again or contact the support"); } } - + /** * Pretty print client data entry map. * diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/MongoServiceUtil.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/MongoServiceUtil.java index 7494cf8..4036b27 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/MongoServiceUtil.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/MongoServiceUtil.java @@ -6,7 +6,9 @@ import static org.gcube.application.geoportal.client.plugins.GeoportalAbstractPl import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; +import java.net.URL; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; @@ -25,6 +27,7 @@ import org.gcube.application.geoportal.common.utils.FileSets; import org.gcube.application.geoportal.common.utils.StorageUtils; import org.gcube.contentmanagement.blobstorage.transport.backend.RemoteBackendException; import org.gcube.portlets.widgets.mpformbuilder.shared.upload.FileUploaded; +import org.gcube.portlets.widgets.mpformbuilder.shared.upload.FileUploadedRemote; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,16 +46,35 @@ public class MongoServiceUtil { UseCaseDescriptorsI client = null; + /** + * Use case descriptors client. + * + * @return the use case descriptors I + */ public UseCaseDescriptorsI useCaseDescriptorsClient() { LOG.debug("useCaseDescriptorsClient called"); return useCaseDescriptors().build(); } + /** + * Gets the projects client. + * + * @param profileID the profile ID + * @return the projects client + */ public Projects getProjectsClient(String profileID) { LOG.debug("getProjectsClient called for profileID: " + profileID); return projects(profileID).build(); } + /** + * Creates the new. + * + * @param profileID the profile ID + * @param jsonDocument the json document + * @return the project + * @throws RemoteException the remote exception + */ public Project createNew(String profileID, String jsonDocument) throws RemoteException { LOG.debug("createNew called for profileID: " + profileID); Document myDocument = Document.parse(jsonDocument); @@ -63,10 +85,29 @@ public class MongoServiceUtil { return project; } + /** + * Register file set. + * + * @param profileID the profile ID + * @param project the project + * @param parentPath the parent path + * @param fieldName the field name + * @param fieldDefinition the field definition + * @param access the access + * @param files the files + * @throws RemoteException the remote exception + * @throws FileNotFoundException the file not found exception + * @throws JsonProcessingException the json processing exception + * @throws InvalidRequestException the invalid request exception + */ public void registerFileSet(String profileID, Project project, String parentPath, String fieldName, String fieldDefinition, Access access, File... files) throws RemoteException, FileNotFoundException, JsonProcessingException, InvalidRequestException { - LOG.debug("registerFileSet called for profileID: " + profileID); + LOG.info("registerFileSet called for profileID: " + profileID); + LOG.info("and for parentPath: " + parentPath); + LOG.info("and for fieldName: " + fieldName); + LOG.info("and for fieldDefinition: " + fieldDefinition); + LOG.info("and for access: " + access); Projects client = getProjectsClient(profileID); // Prepare request @@ -75,6 +116,7 @@ public class MongoServiceUtil { fsRequest.setToSetAccess(access); project = client.registerFileSet(project.getId(), fsRequest); + LOG.trace("Resulting Project : " + project); LOG.debug("Resulting Project as JSON: " + Serialization.write(project)); } @@ -138,32 +180,31 @@ public class MongoServiceUtil { return files; } -// /** -// * To tem files from WSC. -// * -// * @param listFiles the list files -// * @return the list -// */ -// public List toTemFilesFromWSC(List listFiles) { -// LOG.debug("toTemFilesFromWSC called"); -// if (listFiles == null || listFiles.isEmpty()) -// return null; -// -// // Building TempFile -// List files = new ArrayList(listFiles.size()); -// for (WorkspaceContentDV fileUploaded : listFiles) { -// InputStream is; -// try { -// is = new URL(fileUploaded.getLink()).openStream(); -// // Creating TempFile -// TempFile storageTempFile = createTempFileOnStorage(is, fileUploaded.getName()); -// files.add(storageTempFile); -// } catch (IOException e) { -// LOG.error("Error on creating temp file from URL: " + fileUploaded.getLink(), e); -// } -// } -// return files; -// } + + /** + * To temp file from remote. + * + * @param file the file + * @return the temp file + */ + public TempFile toTempFileFromRemote(FileUploadedRemote file) { + LOG.debug("toTemFilesFromRemote called"); + if (file == null) + return null; + + // Building TempFile + TempFile storageTempFile = null; + try { + InputStream is = new URL(file.getUrl()).openStream(); + // Creating TempFile + storageTempFile = createTempFileOnStorage(is, file.getFileName()); + } catch (IOException e) { + LOG.error("Error on creating temp file from URL: " + file.getUrl(), e); + } + + return storageTempFile; + } + /** * To JSON. diff --git a/src/test/resources/.gitignore b/src/test/resources/.gitignore index bd6e80c..5509f46 100644 --- a/src/test/resources/.gitignore +++ b/src/test/resources/.gitignore @@ -13,3 +13,4 @@ /ISTI.gcubekey /d4science.research-infrastructures.eu.gcubekey /howto.txt +/gcube_config.properties