From 44f50ffb5dd3bc98b774d757614532e66a7318ac Mon Sep 17 00:00:00 2001 From: Francois Prunayre Date: Tue, 1 Dec 2020 06:55:02 +0100 Subject: [PATCH 1/3] INSPIRE Validation / Add support to validate using GetRecordById url Current validation mechanism always upload the record first. Default mode is unchanged. Add a mode parameter to the API (on one record or on a selection) to define the encoding of the record to use: * By default, ISO19139 are used as is and others like ISO19115-3 are converted to ISO19139 if a formatter is available. * If mode = csw, a GetRecordById request pointing to the main portal is used. * If mode = any portal id, then a GetRecordById request is used on this portal. CSW entry point which may define custom CSW post processing. See https://github.com/geonetwork/core-geonetwork/pull/4493. Add also an API operation to clear current validation status. --- .../MInspireEtfValidateProcess.java | 96 +++++++++----- .../geonet/api/processing/ValidateApi.java | 81 +++++++++++- .../api/records/InspireValidationApi.java | 123 ++++++++++++------ .../editing/InspireValidatorUtils.java | 62 +++++++-- .../metadataactions/MetadataActionService.js | 22 +++- .../partials/selection-widget.html | 13 ++ .../GnmdInspireValidationDirective.js | 11 +- .../partials/mdValidationTools.html | 7 +- .../main/resources/catalog/locales/en-v4.json | 3 +- 9 files changed, 330 insertions(+), 88 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java b/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java index b0e092d20e0..114be66e44e 100644 --- a/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java +++ b/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java @@ -4,22 +4,24 @@ import jeeves.transaction.TransactionManager; import jeeves.transaction.TransactionTask; import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpStatus; +import org.fao.geonet.NodeInfo; import org.fao.geonet.api.API; import org.fao.geonet.api.records.editing.InspireValidatorUtils; import org.fao.geonet.api.records.formatters.FormatType; import org.fao.geonet.api.records.formatters.FormatterApi; import org.fao.geonet.api.records.formatters.FormatterWidth; import org.fao.geonet.api.records.formatters.cache.Key; -import org.fao.geonet.domain.AbstractMetadata; -import org.fao.geonet.domain.MetadataValidation; -import org.fao.geonet.domain.MetadataValidationId; -import org.fao.geonet.domain.MetadataValidationStatus; +import org.fao.geonet.domain.*; import org.fao.geonet.kernel.AccessManager; import org.fao.geonet.kernel.DataManager; import org.fao.geonet.kernel.SchemaManager; import org.fao.geonet.kernel.datamanager.IMetadataSchemaUtils; import org.fao.geonet.kernel.datamanager.IMetadataUtils; +import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.repository.MetadataValidationRepository; +import org.fao.geonet.repository.SourceRepository; +import org.fao.geonet.schema.iso19139.ISO19139Namespaces; import org.fao.geonet.schema.iso19139.ISO19139SchemaPlugin; import org.fao.geonet.utils.Log; import org.fao.geonet.utils.Xml; @@ -122,7 +124,7 @@ public Object doInTransaction(TransactionStatus transaction) throws Throwable { }); } - public void processMetadata(Set uuids) throws Exception { + public void processMetadata(Set uuids, String mode) throws Exception { IMetadataUtils metadataRepository = appContext.getBean(IMetadataUtils.class); MetadataValidationRepository metadataValidationRepository = appContext.getBean(MetadataValidationRepository.class); AccessManager accessManager = appContext.getBean(AccessManager.class); @@ -177,33 +179,65 @@ public Object doInTransaction(TransactionStatus transaction) throws Throwable { } if (applyCondition) { - String testId = inspireValidatorUtils.submitFile(serviceContext, URL, - new ByteArrayInputStream(mdToValidate.getBytes()), entry.getKey(), record.getUuid()); - inspireValidatorUtils.waitUntilReady(serviceContext, URL, testId); - - String reportUrl = inspireValidatorUtils.getReportUrl(URL, testId); - String reportXmlUrl = InspireValidatorUtils.getReportUrlXML(URL, testId); - String reportXml = inspireValidatorUtils.retrieveReport(serviceContext, reportXmlUrl); - - String validationStatus = inspireValidatorUtils.isPassed(serviceContext, URL, testId); - - MetadataValidationStatus metadataValidationStatus = - inspireValidatorUtils.calculateValidationStatus(validationStatus); - - MetadataValidation metadataValidation = new MetadataValidation() - .setId(new MetadataValidationId(record.getId(), "inspire")) - .setStatus(metadataValidationStatus).setRequired(false) - .setReportUrl(reportUrl).setReportContent(reportXml); - - metadataValidationRepository.save(metadataValidation); - - //new RecordValidationTriggeredEvent(record.getId(), - // ApiUtils.getUserSession(request.getSession()).getUserIdAsInt(), - // metadataValidation.getStatus().getCode()).publish(appContext); - - reindexMetadata = true; - inspireMetadata = true; + String testId = null; + String getRecordByIdUrl = null; + if (mode == null) { + testId = inspireValidatorUtils.submitFile(serviceContext, URL, + new ByteArrayInputStream(mdToValidate.getBytes()), entry.getKey(), record.getUuid()); + } else if (StringUtils.isNotEmpty(mode)) { + String portal = null; + if (!NodeInfo.DEFAULT_NODE.equals(mode)) { + Source source = appContext.getBean(SourceRepository.class).findOneByUuid(mode); + if (source == null) { + metadataAnalysedInError++; + Log.warning(API.LOG_MODULE_NAME, String.format( + "Portal %s not found. There is no CSW endpoint at this URL " + + "that we can send to the validator.", mode)); + } + portal = mode; + } else { + portal = NodeInfo.DEFAULT_NODE; + } + + if (portal != null) { + getRecordByIdUrl = String.format( + "%s%s/eng/csw?SERVICE=CSW&REQUEST=GetRecordById&VERSION=2.0.2&" + + "OUTPUTSCHEMA=%s&ELEMENTSETNAME=full&ID=%s", + appContext.getBean(SettingManager.class).getBaseURL(), + portal, + ISO19139Namespaces.GMD.getURI(), + record.getUuid()); + testId = inspireValidatorUtils.submitUrl(serviceContext, URL, getRecordByIdUrl, entry.getKey(), record.getUuid()); + } + } + if (testId != null) { + + inspireValidatorUtils.waitUntilReady(serviceContext, URL, testId); + + String reportUrl = inspireValidatorUtils.getReportUrl(URL, testId); + String reportXmlUrl = InspireValidatorUtils.getReportUrlXML(URL, testId); + String reportXml = inspireValidatorUtils.retrieveReport(serviceContext, reportXmlUrl); + + String validationStatus = inspireValidatorUtils.isPassed(serviceContext, URL, testId); + + MetadataValidationStatus metadataValidationStatus = + inspireValidatorUtils.calculateValidationStatus(validationStatus); + + MetadataValidation metadataValidation = new MetadataValidation() + .setId(new MetadataValidationId(record.getId(), "inspire")) + .setStatus(metadataValidationStatus).setRequired(false) + .setReportUrl(reportUrl).setReportContent(reportXml); + + metadataValidationRepository.save(metadataValidation); + + //new RecordValidationTriggeredEvent(record.getId(), + // ApiUtils.getUserSession(request.getSession()).getUserIdAsInt(), + // metadataValidation.getStatus().getCode()).publish(appContext); + + reindexMetadata = true; + inspireMetadata = true; + } } } } diff --git a/services/src/main/java/org/fao/geonet/api/processing/ValidateApi.java b/services/src/main/java/org/fao/geonet/api/processing/ValidateApi.java index fab57f1b33c..2230d15f6aa 100644 --- a/services/src/main/java/org/fao/geonet/api/processing/ValidateApi.java +++ b/services/src/main/java/org/fao/geonet/api/processing/ValidateApi.java @@ -36,6 +36,7 @@ import org.fao.geonet.api.processing.report.registry.IProcessingReportRegistry; import org.fao.geonet.api.records.editing.InspireValidatorUtils; import org.fao.geonet.domain.AbstractMetadata; +import org.fao.geonet.domain.MetadataValidation; import org.fao.geonet.events.history.RecordValidationTriggeredEvent; import org.fao.geonet.kernel.AccessManager; import org.fao.geonet.kernel.DataManager; @@ -62,9 +63,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.ArrayDeque; +import java.util.List; import java.util.Set; import static org.fao.geonet.api.ApiParams.*; +import static org.fao.geonet.api.records.InspireValidationApi.API_PARAM_INSPIRE_VALIDATION_MODE; @RequestMapping(value = { "/{portal}/api/records" @@ -191,6 +194,77 @@ public SimpleMetadataProcessingReport validateRecords( } + @io.swagger.v3.oas.annotations.Operation(summary = "Clear validation status of one or more records", + description = "") + @RequestMapping( + value = "/validate", + method = RequestMethod.DELETE, + produces = { + MediaType.APPLICATION_JSON_VALUE + } + ) + @PreAuthorize("hasAuthority('Editor')") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Records validation status cleared."), + @ApiResponse(responseCode = "403", description = ApiParams.API_RESPONSE_NOT_ALLOWED_ONLY_EDITOR) + }) + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public SimpleMetadataProcessingReport cleanValidationStatus( + @Parameter(description = API_PARAM_RECORD_UUIDS_OR_SELECTION, + required = false, + example = "") + @RequestParam(required = false) + String[] uuids, + @Parameter( + description = ApiParams.API_PARAM_BUCKET_NAME, + required = false) + @RequestParam( + required = false + ) + String bucket, + @Parameter(hidden = true) + HttpSession session, + @Parameter(hidden = true) + HttpServletRequest request + ) throws Exception { + UserSession userSession = ApiUtils.getUserSession(session); + + SimpleMetadataProcessingReport report = + new SimpleMetadataProcessingReport(); + try { + ServiceContext serviceContext = ApiUtils.createServiceContext(request); + + Set records = ApiUtils.getUuidsParameterOrSelection(uuids, bucket, userSession); + + for (String uuid : records) { + if (!metadataRepository.existsMetadataUuid(uuid)) { + report.incrementNullRecords(); + } + for (AbstractMetadata record : metadataRepository.findAllByUuid(uuid)) { + if (!accessMan.canEdit(serviceContext, String.valueOf(record.getId()))) { + report.addNotEditableMetadataId(record.getId()); + } else { + List validationStatus = metadataValidationRepository.findAllById_MetadataId(record.getId()); + metadataValidationRepository.deleteAll(validationStatus); + report.addMetadataId(record.getId()); + report.incrementProcessedRecords(); + } + } + } + + // index records + BatchOpsMetadataReindexer r = new BatchOpsMetadataReindexer(dataMan, report.getMetadata()); + r.process(true); + } catch (Exception e) { + throw e; + } finally { + report.close(); + } + return report; + } + + @io.swagger.v3.oas.annotations.Operation(summary = "Validate one or more records in INSPIRE validator", description = "Update validation status for all records.") @RequestMapping( @@ -220,6 +294,11 @@ public ResponseEntity validateRecordsInspire( required = false ) String bucket, + @Parameter( + description = API_PARAM_INSPIRE_VALIDATION_MODE, + required = false) + @RequestParam(required = false) + String mode, @Parameter(hidden = true) HttpSession session, @Parameter(hidden = true) @@ -235,7 +314,7 @@ public ResponseEntity validateRecordsInspire( Set records = ApiUtils.getUuidsParameterOrSelection(uuids, bucket, userSession); - registredMAnalyseProcess.processMetadata(records); + registredMAnalyseProcess.processMetadata(records, mode); return new ResponseEntity(HttpStatus.CREATED); } diff --git a/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java b/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java index 60898efa918..82f7c10e466 100644 --- a/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java @@ -29,8 +29,10 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jeeves.server.context.ServiceContext; import jeeves.services.ReadWriteController; +import org.apache.commons.lang.StringUtils; import org.apache.http.HttpStatus; import org.fao.geonet.ApplicationContextHolder; +import org.fao.geonet.NodeInfo; import org.fao.geonet.api.API; import org.fao.geonet.api.ApiParams; import org.fao.geonet.api.ApiUtils; @@ -43,6 +45,7 @@ import org.fao.geonet.api.tools.i18n.LanguageUtils; import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.AbstractMetadata; +import org.fao.geonet.domain.Source; import org.fao.geonet.events.history.RecordValidationTriggeredEvent; import org.fao.geonet.kernel.DataManager; import org.fao.geonet.kernel.EditLib; @@ -50,6 +53,8 @@ import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.kernel.setting.Settings; import org.fao.geonet.repository.MetadataValidationRepository; +import org.fao.geonet.repository.SourceRepository; +import org.fao.geonet.schema.iso19139.ISO19139Namespaces; import org.fao.geonet.util.ThreadPool; import org.fao.geonet.utils.Log; import org.fao.geonet.utils.Xml; @@ -90,17 +95,30 @@ @ReadWriteController public class InspireValidationApi { + public static final String API_PARAM_INSPIRE_VALIDATION_MODE = "Define the encoding of the record to use. " + + "By default, ISO19139 are used as is and " + + "ISO19115-3 are converted to ISO19139." + + "If mode = csw, a GetRecordById request is used." + + "If mode = any portal id, then a GetRecordById request is used on this portal " + + "CSW entry point which may define custom CSW post processing. " + + "See https://github.com/geonetwork/core-geonetwork/pull/4493."; @Autowired SettingManager settingManager; + @Autowired InspireValidatorUtils inspireValidatorUtils; + @Autowired LanguageUtils languageUtils; + + @Autowired + SourceRepository sourceRepository; + String supportedSchemaRegex = "(iso19139|iso19115-3).*"; + @Autowired private SchemaManager schemaManager; - @Autowired - private MetadataValidationRepository metadataValidationRepository; + @Autowired private ThreadPool threadPool; @@ -160,6 +178,11 @@ String validateRecordForInspire( required = false) @RequestParam String testsuite, + @Parameter( + description = API_PARAM_INSPIRE_VALIDATION_MODE, + required = false) + @RequestParam(required = false) + String mode, HttpServletResponse response, @Parameter(hidden = true) HttpServletRequest request, @@ -188,6 +211,9 @@ String validateRecordForInspire( String id = String.valueOf(metadata.getId()); String URL = settingManager.getValue(Settings.SYSTEM_INSPIRE_REMOTE_VALIDATION_URL); + ServiceContext context = ApiUtils.createServiceContext(request); + String getRecordByIdUrl = null; + String testId = null; try { Element md = (Element) ApiUtils.getUserSession(session).getProperty(Geonet.Session.METADATA_EDITING + id); @@ -197,49 +223,68 @@ String validateRecordForInspire( // TODO: Add support for such validation from not editing session ? } - // Use formatter to convert the record - if (!schema.equals("iso19139")) { - try { - ServiceContext context = ApiUtils.createServiceContext(request); - Key key = new Key(metadata.getId(), "eng", FormatType.xml, "iso19139", true, FormatterWidth._100); - - final FormatterApi.FormatMetadata formatMetadata = - new FormatterApi().new FormatMetadata(context, key, nativeRequest); - final byte[] data = formatMetadata.call().data; - md = Xml.loadString(new String(data, StandardCharsets.UTF_8), false); - } catch (Exception e) { - response.setStatus(HttpStatus.SC_NOT_FOUND); - return String.format("Metadata with id '%s' is in schema '%s'. No iso19139 formatter found. Error is %s", id, schema, e.getMessage()); + if (mode == null) { + // Use formatter to convert the record + if (!schema.equals("iso19139")) { + try { + Key key = new Key(metadata.getId(), "eng", FormatType.xml, "iso19139", true, FormatterWidth._100); + + final FormatterApi.FormatMetadata formatMetadata = + new FormatterApi().new FormatMetadata(context, key, nativeRequest); + final byte[] data = formatMetadata.call().data; + md = Xml.loadString(new String(data, StandardCharsets.UTF_8), false); + } catch (Exception e) { + response.setStatus(HttpStatus.SC_NOT_FOUND); + return String.format("Metadata with id '%s' is in schema '%s'. No iso19139 formatter found. Error is %s", id, schema, e.getMessage()); + } + } else { + // Cleanup metadocument elements + EditLib editLib = appContext.getBean(DataManager.class).getEditLib(); + editLib.removeEditingInfo(md); + editLib.contractElements(md); } - } else { - // Cleanup metadocument elements - EditLib editLib = appContext.getBean(DataManager.class).getEditLib(); - editLib.removeEditingInfo(md); - editLib.contractElements(md); - } - md.detach(); - ServiceContext context = ApiUtils.createServiceContext(request); - Attribute schemaLocAtt = schemaManager.getSchemaLocation( - "iso19139", context); - - if (schemaLocAtt != null) { - if (md.getAttribute( - schemaLocAtt.getName(), - schemaLocAtt.getNamespace()) == null) { - md.setAttribute(schemaLocAtt); - // make sure namespace declaration for schemalocation is present - - // remove it first (does nothing if not there) then add it - md.removeNamespaceDeclaration(schemaLocAtt.getNamespace()); - md.addNamespaceDeclaration(schemaLocAtt.getNamespace()); + md.detach(); + Attribute schemaLocAtt = schemaManager.getSchemaLocation( + "iso19139", context); + + if (schemaLocAtt != null) { + if (md.getAttribute( + schemaLocAtt.getName(), + schemaLocAtt.getNamespace()) == null) { + md.setAttribute(schemaLocAtt); + // make sure namespace declaration for schemalocation is present - + // remove it first (does nothing if not there) then add it + md.removeNamespaceDeclaration(schemaLocAtt.getNamespace()); + md.addNamespaceDeclaration(schemaLocAtt.getNamespace()); + } } - } - - InputStream metadataToTest = convertElement2InputStream(md); - String testId = inspireValidatorUtils.submitFile(context, URL, metadataToTest, testsuite, metadata.getUuid()); + InputStream metadataToTest = convertElement2InputStream(md); + testId = inspireValidatorUtils.submitFile(context, URL, metadataToTest, testsuite, metadata.getUuid()); + } else if (StringUtils.isNotEmpty(mode)) { + String portal = NodeInfo.DEFAULT_NODE; + if (!NodeInfo.DEFAULT_NODE.equals(mode)) { + Source source = sourceRepository.findOneByUuid(mode); + if (source == null) { + response.setStatus(HttpStatus.SC_NOT_FOUND); + return String.format( + "Portal %s not found. There is no CSW endpoint at this URL " + + "that we can send to the validator.", mode); + } + portal = mode; + } + getRecordByIdUrl = String.format( + "%s%s/eng/csw?SERVICE=CSW&REQUEST=GetRecordById&VERSION=2.0.2&" + + "OUTPUTSCHEMA=%s&ELEMENTSETNAME=full&ID=%s", + settingManager.getBaseURL(), + portal, + ISO19139Namespaces.GMD.getURI(), + metadataUuid); + testId = inspireValidatorUtils.submitUrl(context, URL, getRecordByIdUrl, testsuite, metadata.getUuid()); + } threadPool.runTask(new InspireValidationRunnable(context, URL, testId, metadata.getId())); diff --git a/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java b/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java index 8b2950f2d97..d4c3c5e9954 100644 --- a/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java +++ b/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java @@ -66,8 +66,12 @@ import java.util.Set; import java.util.stream.Collectors; -// Utility class to access methods in Inspire Service. -// Based on ETF Web API v.2 BETA +/** + * Utility class to access methods in Inspire Service. + * + * Based on ETF Web API v.2 + * See https://docs.etf-validator.net/v2.0/Developer_manuals/WEB-API.html + */ public class InspireValidatorUtils { @Autowired @@ -333,6 +337,7 @@ private List getTests(ServiceContext context, String endPoint, String te /** * Test run. * + * * @param endPoint the end point * @param fileId the file id * @param testList the test list @@ -340,7 +345,7 @@ private List getTests(ServiceContext context, String endPoint, String te * @throws IOException Signals that an I/O exception has occurred. * @throws JSONException the JSON exception */ - private String testRun(ServiceContext context, String endPoint, String fileId, List testList, String testTitle) { + private String testRun(ServiceContext context, String endPoint, String fileId, List testList, String testTitle) { HttpPost request = new HttpPost(endPoint + TestRuns_URL); request.setHeader("Content-type", ACCEPT); @@ -351,22 +356,28 @@ private String testRun(ServiceContext context, String endPoint, String fileId, L try { JSONObject json = new JSONObject(); JSONArray tests = new JSONArray(); - JSONObject argumets = new JSONObject(); + JSONObject arguments = new JSONObject(); JSONObject testObject = new JSONObject(); json.put("label", "TEST " + testTitle + " - " + System.currentTimeMillis()); json.put("executableTestSuiteIds", tests); - json.put("argumets", argumets); + json.put("arguments", arguments); json.put("testObject", testObject); for (String test : testList) { tests.put(test); } - argumets.put("files_to_test", ".*"); - argumets.put("tests_to_execute", ".*"); + arguments.put("files_to_test", ".*"); + arguments.put("tests_to_execute", ".*"); - testObject.put("id", fileId); + if (fileId.startsWith("http")) { + JSONObject resourceObject = new JSONObject(); + resourceObject.put("data", fileId); + testObject.put("resources", resourceObject); + } else { + testObject.put("id", fileId); + } StringEntity entity = new StringEntity(json.toString()); request.setEntity(entity); @@ -574,6 +585,41 @@ public String submitFile(ServiceContext context, String serviceEndpoint, InputSt } } + /** + * Submit URL to the external ETF validator. + * + * @param record the record + * @param testsuite + * @return the string + * @throws IOException Signals that an I/O exception has occurred. + * @throws JSONException the JSON exception + */ + public String submitUrl(ServiceContext context, String serviceEndpoint, String getRecordById, String testsuite, String testTitle) + throws IOException { + + try { + if (checkServiceStatus(context, serviceEndpoint)) { + // Get the tests to execute + List tests = getTests(context, serviceEndpoint, testsuite); + if (tests == null || tests.size() == 0) { + Log.error(Log.SERVICE, + "Default test sequence not supported. Check org.fao.geonet.api.records.editing.InspireValidatorUtils.TESTS_TO_RUN_TG13.", + new Exception()); + return null; + } + // Return test id from Inspire service + return testRun(context, serviceEndpoint, getRecordById, tests, testTitle); + + } else { + ServiceNotFoundEx ex = new ServiceNotFoundEx(serviceEndpoint); + Log.error(Log.SERVICE, "Service unavailable.", ex); + throw ex; + } + } finally { + // client.close(); + } + } + public String retrieveReport(ServiceContext context, String endPoint) throws Exception { HttpGet request = new HttpGet(endPoint); diff --git a/web-ui/src/main/resources/catalog/components/metadataactions/MetadataActionService.js b/web-ui/src/main/resources/catalog/components/metadataactions/MetadataActionService.js index cce91324f8f..727523b74eb 100644 --- a/web-ui/src/main/resources/catalog/components/metadataactions/MetadataActionService.js +++ b/web-ui/src/main/resources/catalog/components/metadataactions/MetadataActionService.js @@ -477,20 +477,36 @@ * Validates the current selection of metadata records. * @param {String} bucket */ - this.validateMdInspire = function(bucket) { + this.validateMdInspire = function(bucket, mode) { $rootScope.$broadcast('operationOnSelectionStart'); $rootScope.$broadcast('inspireMdValidationStart'); - return gnHttp.callService('../api/records/validate/inspire?' + - 'bucket=' + bucket, null, { + var url = '../api/records/validate/inspire?' + + 'bucket=' + bucket; + if (angular.isDefined(mode)) { + url += '&mode=' + mode; + } + return gnHttp.callService(url, null, { method: 'PUT' }).then(function(data) { $rootScope.$broadcast('inspireMdValidationStop'); $rootScope.$broadcast('operationOnSelectionStop'); $rootScope.$broadcast('search'); }); + }; + + this.clearValidationStatus = function(bucket) { + $rootScope.$broadcast('operationOnSelectionStart'); + var url = '../api/records/validate?' + + 'bucket=' + bucket; + return gnHttp.callService(url, null, { + method: 'DELETE' + }).then(function(data) { + $rootScope.$broadcast('operationOnSelectionStop'); + $rootScope.$broadcast('search'); + }); }; /** diff --git a/web-ui/src/main/resources/catalog/components/search/resultsview/partials/selection-widget.html b/web-ui/src/main/resources/catalog/components/search/resultsview/partials/selection-widget.html index 33f239e227b..013fff3ea45 100644 --- a/web-ui/src/main/resources/catalog/components/search/resultsview/partials/selection-widget.html +++ b/web-ui/src/main/resources/catalog/components/search/resultsview/partials/selection-widget.html @@ -114,6 +114,19 @@  validateInspire + +
  • + +  clearValidationStatus + +
  • using csw + Validation using "inspire" portal CSW entry point (which may post process outputs). + using INSPIRE endpoint-->
  • diff --git a/web-ui/src/main/resources/catalog/locales/en-v4.json b/web-ui/src/main/resources/catalog/locales/en-v4.json index d6dc24fa90b..b80ebbce29d 100644 --- a/web-ui/src/main/resources/catalog/locales/en-v4.json +++ b/web-ui/src/main/resources/catalog/locales/en-v4.json @@ -123,5 +123,6 @@ "wfsHarvesterActions": "Actions", "clearCheckboxFormChanges": "Clear modified checkbox state. Checkboxes with '*' means that those values will be removed from the selection.", "addThoseCategories-help": "Add (checked) or remove (checkbox with *) selected categories.", - "replaceByThoseCategories-help": "Remove record categories and then add (checked) or remove (checkbox with *) selected categories." + "replaceByThoseCategories-help": "Remove record categories and then add (checked) or remove (checkbox with *) selected categories.", + "clearValidationStatus": "Clear validation status" } From 0aa02202d0590f947cf1e9201c589bec26fa75ac Mon Sep 17 00:00:00 2001 From: Francois Prunayre Date: Tue, 1 Dec 2020 08:48:56 +0100 Subject: [PATCH 2/3] INSPIRE validation / Fix comment. --- .../fao/geonet/api/processing/MInspireEtfValidateProcess.java | 2 +- .../java/org/fao/geonet/api/records/InspireValidationApi.java | 2 +- .../fao/geonet/api/records/editing/InspireValidatorUtils.java | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java b/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java index 114be66e44e..62b9a1ee7c0 100644 --- a/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java +++ b/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java @@ -182,7 +182,7 @@ public Object doInTransaction(TransactionStatus transaction) throws Throwable { String testId = null; String getRecordByIdUrl = null; - if (mode == null) { + if (StringUtils.isEmpty(mode)) { testId = inspireValidatorUtils.submitFile(serviceContext, URL, new ByteArrayInputStream(mdToValidate.getBytes()), entry.getKey(), record.getUuid()); } else if (StringUtils.isNotEmpty(mode)) { diff --git a/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java b/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java index 82f7c10e466..28fc5d4cfa5 100644 --- a/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java @@ -223,7 +223,7 @@ String validateRecordForInspire( // TODO: Add support for such validation from not editing session ? } - if (mode == null) { + if (StringUtils.isEmpty(mode)) { // Use formatter to convert the record if (!schema.equals("iso19139")) { try { diff --git a/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java b/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java index d4c3c5e9954..b6ff2a74121 100644 --- a/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java +++ b/services/src/main/java/org/fao/geonet/api/records/editing/InspireValidatorUtils.java @@ -580,8 +580,6 @@ public String submitFile(ServiceContext context, String serviceEndpoint, InputSt Log.error(Log.SERVICE, "Service unavailable.", ex); throw ex; } - } finally { - // client.close(); } } From 4a473728e80b408dfb465e9939b88a8a1f7f8620 Mon Sep 17 00:00:00 2001 From: Francois Prunayre Date: Tue, 1 Dec 2020 08:53:21 +0100 Subject: [PATCH 3/3] INSPIRE validation / Fix comment. --- .../fao/geonet/api/processing/MInspireEtfValidateProcess.java | 2 +- .../java/org/fao/geonet/api/records/InspireValidationApi.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java b/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java index 62b9a1ee7c0..b6b7708bc68 100644 --- a/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java +++ b/services/src/main/java/org/fao/geonet/api/processing/MInspireEtfValidateProcess.java @@ -185,7 +185,7 @@ public Object doInTransaction(TransactionStatus transaction) throws Throwable { if (StringUtils.isEmpty(mode)) { testId = inspireValidatorUtils.submitFile(serviceContext, URL, new ByteArrayInputStream(mdToValidate.getBytes()), entry.getKey(), record.getUuid()); - } else if (StringUtils.isNotEmpty(mode)) { + } else { String portal = null; if (!NodeInfo.DEFAULT_NODE.equals(mode)) { Source source = appContext.getBean(SourceRepository.class).findOneByUuid(mode); diff --git a/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java b/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java index 28fc5d4cfa5..a368a671bd5 100644 --- a/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/InspireValidationApi.java @@ -264,7 +264,7 @@ String validateRecordForInspire( InputStream metadataToTest = convertElement2InputStream(md); testId = inspireValidatorUtils.submitFile(context, URL, metadataToTest, testsuite, metadata.getUuid()); - } else if (StringUtils.isNotEmpty(mode)) { + } else { String portal = NodeInfo.DEFAULT_NODE; if (!NodeInfo.DEFAULT_NODE.equals(mode)) { Source source = sourceRepository.findOneByUuid(mode);