diff --git a/.classpath b/.classpath index 1e1ce66..e47c68b 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,6 @@ - + @@ -31,5 +31,5 @@ - + diff --git a/.settings/com.gwtplugins.gdt.eclipse.core.prefs b/.settings/com.gwtplugins.gdt.eclipse.core.prefs index 2e9a5c6..45cbadf 100644 --- a/.settings/com.gwtplugins.gdt.eclipse.core.prefs +++ b/.settings/com.gwtplugins.gdt.eclipse.core.prefs @@ -1,5 +1,5 @@ eclipse.preferences.version=1 jarsExcludedFromWebInfLib= -lastWarOutDir=/home/francescomangiacrapa/git/geoportal-data-entry-app/target/geoportal-data-entry-app-3.1.0-SNAPSHOT +lastWarOutDir=/home/francescomangiacrapa/git/geoportal-data-entry-app/target/geoportal-data-entry-app-3.2.0-SNAPSHOT warSrcDir=src/main/webapp warSrcDirIsOutput=false diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 38b16fb..5301ad2 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,5 +1,5 @@ - + @@ -85,8 +85,60 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -173,7 +225,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -260,7 +338,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -347,7 +451,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -386,7 +516,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -473,7 +629,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -560,7 +742,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -647,7 +855,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 406d669..06c30f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v3.2.0-SNAPSHOT] - 2022-05-11 + +- Implemented the Update facility [#24166] +- Integrated with the geoportal-data-mapper library [#24244] +- Integrated the Geoportal Data-Viewer Widget [#25015] +- Passed to Geoportal_Resolver service [#25031] +- Provided the "View Document" and "View As JSON" facilities +- DELETE relation" operation allowed only in DRAFT phase [#25104] + ## [v3.1.0] - 2023-03-06 #### Enhancements diff --git a/pom.xml b/pom.xml index 692ffc0..42bd7a4 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ org.gcube.portlets.user geoportal-data-entry-app war - 3.1.0 + 3.2.0-SNAPSHOT GeoPortal Data Entry App The GeoPortal Data Entry App is an application to build the web forms for data entries needed to create projects/documents (based on UCD) in the D4Science Geoportal service @@ -51,7 +51,7 @@ org.gcube.distribution maven-portal-bom - 3.6.4 + 3.8.0-SNAPSHOT pom import @@ -68,22 +68,6 @@ provided - - - - - - - - - - - - - - - - com.google.gwt gwt-servlet @@ -107,6 +91,21 @@ gwt-bootstrap compile + + + org.gcube.portlets.widgets + geoportal-data-viewer-widget + [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) + compile + + + + org.gcube.application + geoportal-data-mapper + [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) + compile + + org.gcube.portlets.widgets metadata-profile-form-builder-widget @@ -129,12 +128,6 @@ - - org.gcube.portlets.widgets - openlayer-basic-widgets - [1.0.0, 2.0.0-SNAPSHOT) - compile - org.gcube.common @@ -231,6 +224,8 @@ slf4j-api provided + + junit junit @@ -243,6 +238,13 @@ guava test + + + org.projectlombok + lombok + 1.18.4 + test + diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ConstantsGeoPortalDataEntryApp.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ConstantsGeoPortalDataEntryApp.java index 5fdcf17..e175e9b 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ConstantsGeoPortalDataEntryApp.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ConstantsGeoPortalDataEntryApp.java @@ -49,8 +49,10 @@ public class ConstantsGeoPortalDataEntryApp { public static final String WORKFLOW_ACTION_POST_CREATION_ACTION_ID = "post_creation_action"; public static final DateTimeFormat DATE_TIME_FORMAT = DateTimeFormat.getFormat("dd MMMM yyyy"); + + public static final String SHOW_ON_MAP_NOT_AVAILABLE_IN_DRAFT = "The 'Show on Map' facility is not available in DRAFT phase"; - public static final String ALERT_MESSAGE_PROJECT_NOT_EDITABLE = "A Project can only be edited/updated in " + public static final String ALERT_MESSAGE_PROJECT_NOT_EDITABLE = "A Project can only be updated in " + WORKFLOW_PHASE.DRAFT.name() + " phase. You need to perform the step 'Reject' or 'UnPublish' to take back the project in " + WORKFLOW_PHASE.DRAFT.name() + " phase."; @@ -59,6 +61,12 @@ public class ConstantsGeoPortalDataEntryApp { + WORKFLOW_PHASE.DRAFT.name() + " phase. You need to perform the step 'Reject' or 'UnPublish' to take back the project in " + WORKFLOW_PHASE.DRAFT.name() + " phase."; + + + public static final String ALERT_MESSAGE_DELETE_RELATION_FORBIDDEN = "The Delete Relation operation can be performed only in " + + WORKFLOW_PHASE.DRAFT.name() + + " phase. You need to perform the step 'Reject' or 'UnPublish' to take back the project in " + + WORKFLOW_PHASE.DRAFT.name() + " phase."; /** * The Enum ACTION_PERFORMED_ON_ITEM. diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java index 7d7c58a..56269d0 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java @@ -98,6 +98,12 @@ public class GeonaMainTabPanel extends Composite { @UiField Tab tabGetListOfProjects; + @UiField + NavLink navViewAsDocument; + + @UiField + NavLink navViewAsJSON; + @UiField NavLink navShowOnMap; @@ -244,6 +250,36 @@ public class GeonaMainTabPanel extends Composite { } }); + navViewAsDocument.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + List listDocuments = null; + if (grpw != null && grpw.getSelectItems() != null) { + listDocuments = grpw.getSelectItems(); + } + + appManagerBus.fireEvent(new OperationOnItemEvent(listDocuments, + OPERATION_ON_ITEM.VIEW_PROJECT_AS_DOCUMENT)); + + } + }); + + navViewAsJSON.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + List listDocuments = null; + if (grpw != null && grpw.getSelectItems() != null) { + listDocuments = grpw.getSelectItems(); + } + + appManagerBus.fireEvent( + new OperationOnItemEvent(listDocuments, OPERATION_ON_ITEM.VIEW_PROJECT_AS_JSON)); + + } + }); + navShowReport.addClickHandler(new ClickHandler() { @Override @@ -456,21 +492,7 @@ public class GeonaMainTabPanel extends Composite { GEOPORTAL_DATA_HANDLER.geoportal_data_list); if (dataListHandler != null) { - -// NavLink link = new NavLink(ucd.getName()); -// link.addClickHandler(new ClickHandler() { -// -// @Override -// public void onClick(ClickEvent event) { -// -// appManagerBus.fireEvent(new GetListOfRecordsEvent(false, ucd.getProfileID(), -// getCurrentProjectsSearchingFilter(), true)); -// } -// }); ucdProjectTypesForListingDataView.add(ucd); - -// listOfProjectTablePanel.addProjectType(link); - listOfProjectTablePanel.addProjectType(ucd); } 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 3c44517..a9b2eed 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,11 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; +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; @@ -22,7 +26,6 @@ import org.bson.Document; import org.gcube.application.geoportal.client.utils.Serialization; import org.gcube.application.geoportal.common.model.document.Project; import org.gcube.application.geoportal.common.model.document.access.Access; -import org.gcube.application.geoportal.common.model.document.access.AccessPolicy; import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation; import org.gcube.application.geoportal.common.model.rest.TempFile; import org.gcube.application.geoportal.common.model.useCaseDescriptor.RelationshipDefinition; @@ -36,7 +39,6 @@ import org.gcube.application.geoportalcommon.geoportal.GeoportalClientCaller; import org.gcube.application.geoportalcommon.geoportal.ProjectsCaller; import org.gcube.application.geoportalcommon.geoportal.UseCaseDescriptorCaller; import org.gcube.application.geoportalcommon.shared.GNADataEntryConfigProfile; -import org.gcube.application.geoportalcommon.shared.GNADataViewerConfigProfile; import org.gcube.application.geoportalcommon.shared.GeoportalItemReferences; import org.gcube.application.geoportalcommon.shared.ResultSetPaginatedData; import org.gcube.application.geoportalcommon.shared.SearchingFilter; @@ -56,10 +58,15 @@ import org.gcube.application.geoportalcommon.shared.geoportal.project.TemporalRe import org.gcube.application.geoportalcommon.shared.geoportal.ucd.GEOPORTAL_DATA_HANDLER; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.UseCaseDescriptorDV; +import org.gcube.application.geoportalcommon.shared.geoportal.view.ProjectView; +import org.gcube.application.geoportaldatamapper.Geoportal_JSON_Mapper; +import org.gcube.application.geoportaldatamapper.shared.ProjectEdit; 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.json.JsonMerge; +import org.gcube.portlets.user.geoportaldataentry.server.json.JsonMerge.MERGE_OPTION; import org.gcube.portlets.user.geoportaldataentry.shared.CommitReport; import org.gcube.portlets.user.geoportaldataentry.shared.GNADataEntryExtendedConfigProfile; import org.gcube.portlets.user.geoportaldataentry.shared.GeoNaFormDataObject; @@ -68,6 +75,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; @@ -78,9 +86,14 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gwt.user.client.Random; import com.google.gwt.user.server.rpc.RemoteServiceServlet; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.spi.json.JsonOrgJsonProvider; +import com.jayway.jsonpath.spi.json.GsonJsonProvider; /** * The server side implementation of the RPC service. @@ -218,6 +231,187 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } } + /** + * 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 + */ + @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); + + ProjectsCaller client = null; + Project currentProject = null; + JSONObject updatedSectionObject = null; + Configuration configurationGson = null; + GenericDatasetBean sectionBean = null; + try { + + if (projectID == null) + throw new Exception("projectID is null"); + + if (profileID == null) + throw new Exception("profileID is null"); + + if (section == null || section.getListGDB() == null || section.getListGDB().get(0) == null) + throw new Exception("Input error. The section is null"); + + sectionBean = section.getListGDB().get(0); + + // Converter + FormDataObjectToJSON metadataConverter = new FormDataObjectToJSON(); + // JSON Section to update converted as JSONObject + updatedSectionObject = metadataConverter.genericDatasetBeanToJSON(sectionBean); + LOG.info("Input Json Section (to update): {}", updatedSectionObject.toString()); + + configurationGson = Configuration.builder().jsonProvider(new GsonJsonProvider()).build(); +// Type type = new TypeToken>>() {}.getType(); +// Set> myMap = gson.fromJson(json, type); + + } 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()); + } + + Boolean errorOccurred = false; + + try { + + client = GeoportalClientCaller.projects(); + SessionUtil.getCurrentContext(getThreadLocalRequest(), true); + currentProject = client.getProjectByID(profileID, projectID); + Document currentDoc = currentProject.getTheDocument(); + + // Source Project + String theDocumentJson = currentDoc.toJson(); + LOG.debug("Source document: {}", theDocumentJson); + + // If the section path is the Root document, passed as "$.", fixing as "$" + if (sectionPath.compareTo(FormDataObjectToJSON.JSON_$_POINTER + ".") == 0) + sectionPath = FormDataObjectToJSON.JSON_$_POINTER; + + com.google.gson.JsonObject targetSectionJObject = JsonPath.parse(theDocumentJson, configurationGson) + .read(sectionPath); + LOG.debug("Current Section path {} in the Document is {}", sectionPath, targetSectionJObject.toString()); + String srcJ = updatedSectionObject.toString(); + String trgJ = targetSectionJObject.toString(); + LOG.debug("Merging src {} in the target: {}", srcJ, trgJ); + String mergedDoc = JsonMerge.merge(srcJ, trgJ, MERGE_OPTION.REPLACE); + LOG.debug("mergedDoc: {}", mergedDoc); + + String newDocJson; + // If Updating path is first level of the root + if (sectionPath.equals(FormDataObjectToJSON.JSON_$_POINTER)) { + // The merged DOC is the root Document, no action required + newDocJson = mergedDoc; + } else { + // If the merged DOC is a child of the root Document, setting it as child of the + // Document in the proper section + Gson gson = new Gson(); + JsonObject gsonOject = gson.fromJson(mergedDoc, JsonObject.class); + // Putting the merged section into Document + DocumentContext newContextDocJson = JsonPath.parse(theDocumentJson, configurationGson).set(sectionPath, + gsonOject); + newDocJson = newContextDocJson.json().toString(); + + } + + Document updatedDocument = Serialization.read(newDocJson.toString(), Document.class); + LOG.info("New document is: {}", updatedDocument.toJson()); + + Project updatedProject = client.updateProject(profileID, projectID, updatedDocument); + // Project project = client.getProjectByID(profileID, projectID); + LOG.debug("Medatata Updated with document: {}", updatedProject.getTheDocument()); + + SessionUtil.getCurrentContext(getThreadLocalRequest(), true); + + if (listFilePaths != null) { + + // Collecting new files + List filesUploaded = sectionBean.getFilesUploaded(); + Map mapFilesToRegistrer = null; + if (filesUploaded != null && !filesUploaded.isEmpty()) { + mapFilesToRegistrer = collectFiles(currentProject, sectionPath, section.getGcubeProfileDV(), + filesUploaded); + } + + // 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); + try { + client.deleteFileset(profileID, projectID, filesetPath, true, true); + } catch (Exception e) { + LOG.warn("Error deleting the fileset path {} for the project {}", filesetPath, projectID); + } + } + + // Registering fileset in the section according to mapFilesToRegistrer + if (mapFilesToRegistrer != null && mapFilesToRegistrer.size()>0) { + LOG.info("Cluster of fileset per fieldDefinition is: " + mapFilesToRegistrer); + String theJSONDocument = currentProject.getTheDocument().toJson(); + MongoServiceUtil mongoService = new MongoServiceUtil(); + + for (String fieldDefinition : mapFilesToRegistrer.keySet()) { + FileSetDataObject uploadedFileset = mapFilesToRegistrer.get(fieldDefinition); + LOG.info("Uploading fileset: " + uploadedFileset); + File[] fileset = uploadedFileset.getFileset(); + FilePathDV filePath = uploadedFileset.getFilePathDV(); + Access access = ConvertToDataServiceModel.getAccessFromDocumentSection(theJSONDocument, + sectionPath); + + LOG.info("Going to register fileset: " + Arrays.asList(fileset).toString()); + mongoService.registerFileSet(currentProject.getProfileID(), currentProject, sectionPath, + filePath.getFieldName(), filePath.getFieldDefinition(), access, fileset); + + } + } + + } + + LOG.info("Project with id " + currentProject.getId() + " updated correclty"); + ProjectDVBuilder projectBuilder = ProjectDVBuilder.newBuilder().fullDocumentMap(true); + // Reading again the project to be sure + updatedProject = client.getProjectByID(profileID, projectID); + ProjectDV toProjectDV = ConvertToDataValueObjectModel.toProjectDV(updatedProject, projectBuilder); + String newDocumentString = toProjectDV.getTheDocument().getDocumentAsJSON(); + LOG.info("Got Document: {} ", newDocumentString); + return new CommitReport(projectID, profileID, newDocumentString, null); + } catch (Exception e) { + errorOccurred = true; + LOG.error("Error on updating data: ", e); + throw new Exception("Error occurred on updating data, try again or contact the support. Error: " + + e.getMessage() + ". Tried to revert the project to the previous version"); + } finally { + + // If an error occurs on updating, the previous version of the document will be + // restored + if (errorOccurred && currentProject != null) { + Document currentDocument = currentProject.getTheDocument(); + try { + Project updatedProject = client.updateProject(profileID, projectID, currentDocument); + } catch (Exception e) { + // Silent + } + } + } + + } + /** * Recursive upload fileset. * @@ -344,14 +538,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); } @@ -368,44 +564,174 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } - public Access getAccessFromDocumentSection(String theJSONDocument, String sectionJSONPath) { - String accessPolicyPath = String.format("%s.%s", sectionJSONPath, ConvertToDataValueObjectModel.POLICY); - AccessPolicy accessPolicy = AccessPolicy.OPEN; - com.jayway.jsonpath.Configuration config = com.jayway.jsonpath.Configuration.builder() - .jsonProvider(new JsonOrgJsonProvider()).build(); + /** + * Collect files. + * + * @param theProject the the project + * @param sectionJSONPath the section JSON path + * @param gcubeProfile the gcube profile + * @param files the files + * @return the map of files that must be registered + * @throws Exception the exception + */ + protected Map collectFiles(Project theProject, String sectionJSONPath, + GcubeProfileDV gcubeProfile, List files) throws Exception { + LOG.debug("collectFiles 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(); + String fileName = (remote.getFileName() == null || remote.getFileName().isEmpty()) + ? "file_" + Random.nextInt() + : remote.getFileName(); + output = new File(tmpDirPath, fileName); + 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); - // Reading policy fields - try { - JsonPath theSectionPolycJsonPath = JsonPath.compile(accessPolicyPath); - String policy = theSectionPolycJsonPath.read(theJSONDocument, config).toString(); - LOG.debug("Read " + ConvertToDataValueObjectModel.POLICY + ": " + policy + ", from section: " - + accessPolicyPath); - if (policy != null) { - accessPolicy = AccessPolicy.valueOf(policy.toUpperCase()); } - } catch (Exception e) { - LOG.info("No " + ConvertToDataValueObjectModel.POLICY + "found in the path: " + accessPolicyPath); + } - // Reading policy fields - String licenseIDPath = String.format("%s.%s", sectionJSONPath, ConvertToDataValueObjectModel.LICENSE_ID); - String licenseID = null; - try { - JsonPath theSectionLicenseJsonPath = JsonPath.compile(licenseIDPath); - licenseID = theSectionLicenseJsonPath.read(theJSONDocument, config).toString(); - LOG.debug("Read " + ConvertToDataValueObjectModel.LICENSE_ID + ": " + licenseID + ", from section: " - + theSectionLicenseJsonPath); - } catch (Exception e) { - LOG.info("No " + ConvertToDataValueObjectModel.LICENSE_ID + "found in the path: " + licenseIDPath); + return collectFilesetPerFieldDef; + } + + /** + * 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(); + String fileName = (remote.getFileName() == null || remote.getFileName().isEmpty()) + ? "file_" + Random.nextInt() + : remote.getFileName(); + output = new File(tmpDirPath, fileName); + 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); + + } + } - Access access = new Access(); - access.setPolicy(accessPolicy); - if (licenseID != null) - access.setLicense(licenseID); + LOG.info("Cluster of fileset per fieldDefinition is: " + collectFilesetPerFieldDef); + String theJSONDocument = theProject.getTheDocument().toJson(); + MongoServiceUtil mongoService = new MongoServiceUtil(); - LOG.info("Access is: " + access); - return access; + 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 register files: " + Arrays.asList(fileset).toString()); + mongoService.registerFileSet(theProject.getProfileID(), theProject, sectionJSONPath, + filePath.getFieldName(), filePath.getFieldDefinition(), access, fileset); + + } } /** @@ -527,12 +853,11 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen public GeoportalItemReferences getLinksFor(String itemId, String profileID) throws Exception { LOG.info("getLinksFor called"); - SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); - GNADataViewerConfigProfile grViewerProfile = SessionUtil - .getGeportalViewerResourceProfile(getThreadLocalRequest()); - GeoportalCommon gc = new GeoportalCommon(grViewerProfile); + String scope = SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); + //GNADataViewerConfigProfile grViewerProfile = SessionUtil.getGeportalViewerResourceProfile(getThreadLocalRequest()); + GeoportalCommon gc = new GeoportalCommon(); GeoportalItemReferences item = new GeoportalItemReferences(itemId, profileID); - item = gc.getPublicLinksFor(item, true); + item = gc.getPublicLinksFor(scope, item, true); LOG.info("Returning: " + item); return item; } @@ -561,15 +886,15 @@ 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); } - + if (totalProjectForProfile == null) { totalProjectForProfile = client.getTotalDocument(theProfileID); SessionUtil.setTotalDocumentForProfileID(getThreadLocalRequest(), theProfileID, totalProjectForProfile); @@ -1185,6 +1510,84 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen return null; } + /** + * Gets the project edit. + * + * @param profileID the profile ID + * @param projectID the project ID + * @return the project edit + * @throws Exception the exception + */ + @Override + public ProjectEdit getProjectEdit(String profileID, String projectID) throws Exception { + LOG.info("getProjectEdit called for profileID: {}, and projectID: {}", profileID, projectID); + try { + PortalContext pContext = PortalContext.getConfiguration(); + GCubeUser user = pContext.getCurrentUser(this.getThreadLocalRequest()); + String scope = SessionUtil.getCurrentContext(getThreadLocalRequest(), true); + + ProjectsCaller clientProjects = GeoportalClientCaller.projects(); + Project theProject = clientProjects.getProjectByID(profileID, projectID); + ProjectDVBuilder projectBuilder = ProjectDVBuilder.newBuilder().fullDocumentMap(true); + projectBuilder.relationships(true); + ProjectDV theProjectDV = ConvertToDataValueObjectModel.toProjectDV(theProject, projectBuilder); + + ProjectEdit projectEdit = Geoportal_JSON_Mapper.loadProjectEdit(theProjectDV, scope, user.getUsername()); + + if (LOG.isDebugEnabled() || !SessionUtil.isIntoPortal()) { + Geoportal_JSON_Mapper.prettyPrintProjectEdit(projectEdit); + } + + LOG.info(ProjectEdit.class.getSimpleName() + " returing not null: " + (projectEdit != null)); + return projectEdit; + } catch (Exception e) { + String erroMsg = "Error occurred on reading " + ProjectEdit.class.getSimpleName() + " DTO for id: " + + projectID; + LOG.warn(erroMsg, e); + throw new Exception( + erroMsg + ". Error: " + e.getMessage() + ". Refresh and try again or contact the support"); + } + } + + /** + * Gets the project view. + * + * @param profileID the profile ID + * @param projectID the project ID + * @return the project view + * @throws Exception the exception + */ + @Override + public ProjectView getProjectView(String profileID, String projectID) throws Exception { + LOG.info("getProjectEdit called for profileID: {}, and projectID: {}", profileID, projectID); + try { + PortalContext pContext = PortalContext.getConfiguration(); + GCubeUser user = pContext.getCurrentUser(this.getThreadLocalRequest()); + String scope = SessionUtil.getCurrentContext(getThreadLocalRequest(), true); + + ProjectsCaller clientProjects = GeoportalClientCaller.projects(); + Project theProject = clientProjects.getProjectByID(profileID, projectID); + ProjectDVBuilder projectBuilder = ProjectDVBuilder.newBuilder().fullDocumentMap(true); + projectBuilder.relationships(true); + ProjectDV theProjectDV = ConvertToDataValueObjectModel.toProjectDV(theProject, projectBuilder); + + ProjectView projectView = Geoportal_JSON_Mapper.loadProjectView(theProjectDV, scope, user.getUsername()); + + if (LOG.isDebugEnabled()) { + Geoportal_JSON_Mapper.prettyPrintProjectView(projectView); + } + + LOG.info(ProjectView.class.getSimpleName() + " returing not null: " + (projectView != null)); + return projectView; + } catch (Exception e) { + String erroMsg = "Error occurred on reading " + ProjectView.class.getSimpleName() + " DTO for id: " + + projectID; + LOG.warn(erroMsg, e); + throw new Exception( + erroMsg + ". Error: " + e.getMessage() + ". Refresh and try again or contact the support"); + } + } + /** * Pretty print client data entry map. * @@ -1205,9 +1608,9 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen for (String keyEntry : map.keySet()) { LOG.debug("\t " + keyEntry + ": " + map.get(keyEntry)); } - for (FileUploaded fup : gbd.getFilesUploaded()) { - LOG.debug("\t " + fup); - } +// for (FileUploaded fup : gbd.getFilesUploaded()) { +// LOG.debug("\t " + fup); +// } } } } diff --git a/src/main/webapp/GeoPortalDataEntryApp.css b/src/main/webapp/GeoPortalDataEntryApp.css index 14efc07..fa035cd 100644 --- a/src/main/webapp/GeoPortalDataEntryApp.css +++ b/src/main/webapp/GeoPortalDataEntryApp.css @@ -100,6 +100,9 @@ h1 { max-height: 700px !important; } +.modal-body-edit { + max-height: none !important; +} .disable-div { pointer-events: none; } @@ -110,12 +113,16 @@ h1 { padding: 10px !important; } -.gna-dataentry-form-fieldset fieldset { - margin: 10px !important; - border: 1px groove #ddd !important; - padding: 10px !important; +.form-fieldset-edit .control-group { + margin-bottom: 15px !important; } +.form-fieldset-edit .control-group > span { + padding-top: 3px !important; + padding-bottom: 3px !important; + font-size: 14px; + margin-bottom: 10px; +} .table-current-content { width: 100%; background-color: #efefef !important; @@ -273,6 +280,25 @@ h1 { } +/** OVERRDING legend-style into 'metadata-profile-form-builder-widget' */ + +.legend-style { + width: auto !important; + padding-left: 10px !important; + padding-top: 0px !important; + padding-right: 10px !important; + margin-bottom: 0px !important; + border-bottom: 0px !important; +} + +.legend-style small { + display: block; + font-size: 12px !important; +} + +/** END OVERRDING legend-style into 'metadata-profile-form-builder-widget' */ + + /** OVERRDING legend-style into 'metadata-profile-form-builder-widget' */ .legend-style { 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