Skip to content

Commit

Permalink
Forbid referenced templates deletion (#2177)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmangeat authored and fgravin committed Sep 25, 2017
1 parent d4f60ac commit a342579
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 42 deletions.
32 changes: 24 additions & 8 deletions core/src/main/java/org/fao/geonet/kernel/DataManager.java
Expand Up @@ -1893,14 +1893,7 @@ public synchronized Metadata updateMetadata(final ServiceContext context, final
if (!index) {
indexMetadata(metadataId, true, null);
}
MetaSearcher searcher = context.getBean(SearchManager.class).newSearcher(SearcherType.LUCENE, Geonet.File.SEARCH_LUCENE);
Element parameters = new Element(Jeeves.Elem.REQUEST);
parameters.addContent(new Element(Geonet.IndexFieldNames.XLINK).addContent("*" + metadata.getUuid() + "*"));
parameters.addContent(new Element(Geonet.SearchResult.BUILD_SUMMARY).setText("false"));
parameters.addContent(new Element(SearchParameter.ISADMIN).addContent("true"));
parameters.addContent(new Element(SearchParameter.ISTEMPLATE).addContent("y or n"));
ServiceConfig config = new ServiceConfig();
searcher.search(context, parameters, config);
MetaSearcher searcher = searcherForReferencingMetadata(context, metadata);
Map<Integer, Metadata> result = ((LuceneSearcher) searcher).getAllMdInfo(context, 500);
for (Integer id: result.keySet()) {
IndexingList list = context.getBean(IndexingList.class);
Expand Down Expand Up @@ -2166,6 +2159,17 @@ private void saveValidationStatus(int id, List<MetadataValidation> validations)
* TODO Javadoc.
*/
private void deleteMetadataFromDB(ServiceContext context, String id) throws Exception {

Metadata metadata = getMetadataRepository().findOne(Integer.valueOf(id));
if (! getSettingManager().getValueAsBool(Settings.SYSTEM_XLINK_ALLOW_REFERENCED_DELETION) &&
metadata.getDataInfo().getType() == MetadataType.SUB_TEMPLATE) {
MetaSearcher searcher = searcherForReferencingMetadata(context, metadata);
Map<Integer, Metadata> result = ((LuceneSearcher) searcher).getAllMdInfo(context, 1);
if (result.size() > 0) {
throw new Exception("this template is referenced.");
}
}

//--- remove operations
deleteMetadataOper(context, id, false);

Expand All @@ -2191,6 +2195,18 @@ public javax.persistence.criteria.Path<String> getPath(Root<MetadataFileUpload>
getXmlSerializer().delete(id, context);
}

private MetaSearcher searcherForReferencingMetadata(ServiceContext context, Metadata metadata) throws Exception {
MetaSearcher searcher = context.getBean(SearchManager.class).newSearcher(SearcherType.LUCENE, Geonet.File.SEARCH_LUCENE);
Element parameters = new Element(Jeeves.Elem.REQUEST);
parameters.addContent(new Element(Geonet.IndexFieldNames.XLINK).addContent("*" + metadata.getUuid() + "*"));
parameters.addContent(new Element(Geonet.SearchResult.BUILD_SUMMARY).setText("false"));
parameters.addContent(new Element(SearchParameter.ISADMIN).addContent("true"));
parameters.addContent(new Element(SearchParameter.ISTEMPLATE).addContent("y or n"));
ServiceConfig config = new ServiceConfig();
searcher.search(context, parameters, config);
return searcher;
}

//--------------------------------------------------------------------------
//---
//--- Metadata thumbnail API
Expand Down
Expand Up @@ -50,6 +50,7 @@ public class Settings {
public static final String SYSTEM_REQUESTED_LANGUAGE_ONLY = "system/requestedLanguage/only";
public static final String SYSTEM_AUTODETECT_ENABLE = "system/autodetect/enable";
public static final String SYSTEM_XLINKRESOLVER_ENABLE = "system/xlinkResolver/enable";
public static final String SYSTEM_XLINK_ALLOW_REFERENCED_DELETION = "system/xlinkResolver/referencedDeletionAllowed";
public static final String SYSTEM_SERVER_LOG = "system/server/log";
public static final String SYSTEM_INSPIRE_ENABLE = "system/inspire/enable";
public static final String SYSTEM_INSPIRE_ATOM = "system/inspire/atom";
Expand Down
Expand Up @@ -27,6 +27,7 @@
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.UUID;
Expand All @@ -37,10 +38,12 @@
import static org.fao.geonet.schema.iso19139.ISO19139Namespaces.GCO;
import static org.fao.geonet.schema.iso19139.ISO19139Namespaces.GMD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;

public class LocalXLinksUpdateHaveToTriggerIndexationTest extends AbstractIntegrationTestWithMockedSingletons {
public class LocalXLinksUpdateDeleteTest extends AbstractIntegrationTestWithMockedSingletons {

private static final int TEST_OWNER = 42;

Expand All @@ -64,6 +67,7 @@ public class LocalXLinksUpdateHaveToTriggerIndexationTest extends AbstractIntegr
@Before
public void setUp() throws Exception {
this.context = createServiceContext();
settingManager.setValue(Settings.SYSTEM_XLINKRESOLVER_ENABLE, true);
}

class MyQuartzJob extends IndexingTask {
Expand All @@ -80,29 +84,13 @@ public void execute() throws JobExecutionException {
}

@Test
public void nominal() throws Exception {
settingManager.setValue(Settings.SYSTEM_XLINKRESOLVER_ENABLE, true);

public void updateHasToTriggerIndexation() throws Exception {
URL contactResource = AbstractCoreIntegrationTest.class.getResource("kernel/babarContact.xml");
Element contactElement = Xml.loadStream(contactResource.openStream());
Metadata contactMetadata = insertTemplateResourceInDb(contactElement, SUB_TEMPLATE);

SpringLocalServiceInvoker mockInvoker = resetAndGetMockInvoker();
when(mockInvoker.invoke(any(String.class))).thenReturn(contactElement);
Metadata contactMetadata = insertContact(contactElement);
Metadata vicinityMapMetadata = insertVicinityMap(contactMetadata);

URL vicinityMapResource = AbstractCoreIntegrationTest.class.getResource("kernel/vicinityMap.xml");
Element vicinityMapElement = Xml.loadStream(vicinityMapResource.openStream());
Attribute href = (Attribute) Xml.selectElement(vicinityMapElement, "gmd:identificationInfo/gmd:MD_DataIdentification/gmd:pointOfContact").getAttributes().get(0);
href.setValue(href.getValue().replace("@contact_uuid@", contactMetadata.getUuid()));
Metadata vicinityMapMetadata = insertTemplateResourceInDb(vicinityMapElement, TEMPLATE);

IndexAndTaxonomy indexReader = searchManager.getIndexReader(null, -1);
IndexSearcher searcher = new IndexSearcher(indexReader.indexReader);
BooleanQuery query = new BooleanQuery();
query.add(new TermQuery(new Term(Geonet.IndexFieldNames.ANY, "babar")), BooleanClause.Occur.MUST);
query.add(new TermQuery(new Term(Geonet.IndexFieldNames.IS_TEMPLATE, "s")), BooleanClause.Occur.MUST_NOT);
TopDocs docs = searcher.search(query, 1);
Document document = indexReader.indexReader.document(docs.scoreDocs[0].doc);
Document document = searchForMetadataTagged("babar");
assertEquals(vicinityMapMetadata.getUuid(), document.getField("_uuid").stringValue());

Xml.selectElement(contactElement, "gmd:individualName/gco:CharacterString", Arrays.asList(GMD, GCO)).setText("momo");
Expand All @@ -116,20 +104,49 @@ public void nominal() throws Exception {
null,
false);

MyQuartzJob indexingTask = new MyQuartzJob();
indexingTask.execute();

new MyQuartzJob().execute();
searchManager.forceIndexChanges();
query = new BooleanQuery();
query.add(new TermQuery(new Term(Geonet.IndexFieldNames.ANY, "momo")), BooleanClause.Occur.MUST);
query.add(new TermQuery(new Term(Geonet.IndexFieldNames.IS_TEMPLATE, "s")), BooleanClause.Occur.MUST_NOT);
indexReader = searchManager.getIndexReader(null, -1);
searcher = new IndexSearcher(indexReader.indexReader);
docs = searcher.search(query, 1);
document = indexReader.indexReader.document(docs.scoreDocs[0].doc);

document = searchForMetadataTagged("momo");
assertEquals(vicinityMapMetadata.getUuid(), document.getField("_uuid").stringValue());
}

@Test
public void deleteAllowedWhenRefNotExists() throws Exception {
settingManager.setValue(Settings.SYSTEM_XLINK_ALLOW_REFERENCED_DELETION, false);
Metadata contactMetadata = insertContact();
Metadata vicinityMapMetadata = insertVicinityMap(contactMetadata);

dataManager.deleteMetadata(context, Integer.toString(vicinityMapMetadata.getId()));
dataManager.deleteMetadata(context, Integer.toString(contactMetadata.getId()));
assertNull(dataManager.getMetadata(Integer.toString(contactMetadata.getId())));
}

@Test
public void deleteHasToBeForbiddenWhenRefExistsAndSettingsSaySo() throws Exception {
settingManager.setValue(Settings.SYSTEM_XLINK_ALLOW_REFERENCED_DELETION, false);
Metadata contactMetadata = insertContact();
insertVicinityMap(contactMetadata);

try {
dataManager.deleteMetadata(context,
Integer.toString(contactMetadata.getId()));
} catch (Exception e) {

}
assertNotNull(dataManager.getMetadata(Integer.toString(contactMetadata.getId())));
}

@Test
public void deleteHasToBeAllowedWhenRefExistsAndSettingsSaySo() throws Exception {
settingManager.setValue(Settings.SYSTEM_XLINK_ALLOW_REFERENCED_DELETION, true);
Metadata contactMetadata = insertContact();
insertVicinityMap(contactMetadata);

dataManager.deleteMetadata(context, Integer.toString(contactMetadata.getId()));
assertNull(dataManager.getMetadata(Integer.toString(contactMetadata.getId())));
}

private Metadata insertTemplateResourceInDb(Element element, MetadataType type) throws Exception {
loginAsAdmin(context);

Expand Down Expand Up @@ -160,4 +177,36 @@ private Metadata insertTemplateResourceInDb(Element element, MetadataType type)

return dbInsertedMetadata;
}

private Metadata insertVicinityMap(Metadata contactMetadata) throws Exception {
URL vicinityMapResource = AbstractCoreIntegrationTest.class.getResource("kernel/vicinityMap.xml");
Element vicinityMapElement = Xml.loadStream(vicinityMapResource.openStream());
Attribute href = (Attribute) Xml.selectElement(vicinityMapElement, "gmd:identificationInfo/gmd:MD_DataIdentification/gmd:pointOfContact").getAttributes().get(0);
href.setValue(href.getValue().replace("@contact_uuid@", contactMetadata.getUuid()));
return insertTemplateResourceInDb(vicinityMapElement, TEMPLATE);
}

private Metadata insertContact() throws Exception {
URL contactResource = AbstractCoreIntegrationTest.class.getResource("kernel/babarContact.xml");
Element contactElement = Xml.loadStream(contactResource.openStream());
return insertContact(contactElement);
}

private Metadata insertContact( Element contactElement) throws Exception {
Metadata contactMetadata = insertTemplateResourceInDb(contactElement, SUB_TEMPLATE);

SpringLocalServiceInvoker mockInvoker = resetAndGetMockInvoker();
when(mockInvoker.invoke(any(String.class))).thenReturn(contactElement);
return contactMetadata;
}

private Document searchForMetadataTagged(String contactName) throws IOException {
IndexAndTaxonomy indexReader = searchManager.getIndexReader(null, -1);
IndexSearcher searcher = new IndexSearcher(indexReader.indexReader);
BooleanQuery query = new BooleanQuery();
query.add(new TermQuery(new Term(Geonet.IndexFieldNames.ANY, contactName)), BooleanClause.Occur.MUST);
query.add(new TermQuery(new Term(Geonet.IndexFieldNames.IS_TEMPLATE, "s")), BooleanClause.Occur.MUST_NOT);
TopDocs docs = searcher.search(query, 1);
return indexReader.indexReader.document(docs.scoreDocs[0].doc);
}
}
4 changes: 3 additions & 1 deletion web-ui/src/main/resources/catalog/locales/en-admin.json
Expand Up @@ -1151,5 +1151,7 @@
"ui-map-editor-help": "This configuration is used for the editor maps (bounding box and geometry editor). Every parameter is optional. The context is applied first, then the extent and layers. Supported types are: osm, bing_aerial, stamen, wmts, wms.",
"mapConfigContext": "Path to the context file (XML)",
"mapConfigExtent": "Extent, expressed in current projection",
"mapConfigLayers": "Layer objects in JSON: {\"type\"=\"XXX\",\"arg1\":\"YYY\",...}"
"mapConfigLayers": "Layer objects in JSON: {\"type\"=\"XXX\",\"arg1\":\"YYY\",...}",
"system/xlinkResolver/referencedDeletionAllowed": "Allow deletion of subtemplates referenced through an xlink.",
"system/xlinkResolver/referencedDeletionAllowed-help": "Checked means allow."
}
4 changes: 3 additions & 1 deletion web-ui/src/main/resources/catalog/locales/fr-admin.json
Expand Up @@ -1145,5 +1145,7 @@
"ui-mapExtent": "Map Extent",
"ui-mapExtent-help": "Extent coordinates to use for maps other that viewer and search maps.",
"ui-mapBackgroundLayer": "Map Background Layer",
"ui-mapBackgroundLayer-help": "Define here the background layer to use for maps other that viewer and search maps."
"ui-mapBackgroundLayer-help": "Define here the background layer to use for maps other that viewer and search maps.",
"system/xlinkResolver/referencedDeletionAllowed": "Autorise la suppression d'un subtemplate référencé par un xlink.",
"system/xlinkResolver/referencedDeletionAllowed-help": "Coché signifie autorise."
}
Expand Up @@ -595,6 +595,7 @@ INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/xlinkResolver/enable', 'false', 2, 2310, 'n');
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/xlinkResolver/localXlinkEnable', 'true', 2, 2311, 'n');
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/xlinkResolver/ignore', 'operatesOn,featureCatalogueCitation,Anchor,source', 0, 2312, 'n');
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/xlinkResolver/referencedDeletionAllowed', 'true', 2, 2313, 'n');
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/hidewithheldelements/enableLogging', 'false', 2, 2320, 'y');
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/autofixing/enable', 'true', 2, 2410, 'y');
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/searchStats/enable', 'true', 2, 2510, 'n');
Expand Down
Expand Up @@ -51,7 +51,7 @@ INSERT INTO SelectionsDes (iddes, langid, label) VALUES (1,'vie','Watch list');

INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/userFeedback/lastNotificationDate', '', 0, 1912, 'y');
INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('metadata/import/restrict', '', 0, 11000, 'y');

INSERT INTO Settings (name, value, datatype, position, internal) VALUES ('system/xlinkResolver/referencedDeletionAllowed', 'true', 2, 2313, 'n');


UPDATE Settings SET value='3.3.0' WHERE name='system/platform/version';
Expand Down

0 comments on commit a342579

Please sign in to comment.