diff --git a/cypress/integration/09_admin_links.spec.js b/cypress/integration/09_admin_links.spec.js
index 5c1e5fb146..0341da81a6 100755
--- a/cypress/integration/09_admin_links.spec.js
+++ b/cypress/integration/09_admin_links.spec.js
@@ -9,7 +9,7 @@ context('Administration pages', () => {
it('I should see a link for the dataset properties configuration', () => {
cy.get('.toolbar-icon-system-admin-dkan').contains('DKAN').next('.toolbar-menu').then($el=>{
cy.wrap($el).invoke('show')
- cy.wrap($el).contains('Metastore referencer')
+ cy.wrap($el).contains('Metastore configuration')
})
cy.visit(baseurl + "/admin/dkan/properties")
cy.get('.option').should('contain.text', 'Distribution (distribution)')
diff --git a/modules/metastore/config/install/metastore.settings.yml b/modules/metastore/config/install/metastore.settings.yml
index 214b8a869b..b88d28cb42 100644
--- a/modules/metastore/config/install/metastore.settings.yml
+++ b/modules/metastore/config/install/metastore.settings.yml
@@ -19,4 +19,5 @@ property_list:
'spatial': '0'
'temporal': '0'
'isPartOf': '0'
+html_allowed_properties: []
resource_perspective_display: source
diff --git a/modules/metastore/config/schema/metastore.schema.yml b/modules/metastore/config/schema/metastore.schema.yml
index fbb22a1080..30f80aef44 100644
--- a/modules/metastore/config/schema/metastore.schema.yml
+++ b/modules/metastore/config/schema/metastore.schema.yml
@@ -14,6 +14,12 @@ metastore.settings:
sequence:
type: string
label: 'Property'
+ html_allowed_properties:
+ type: sequence
+ label: 'HTML Allowed Properties'
+ sequence:
+ type: string
+ label: 'Property'
resource_perspective_display:
type: string
- label: 'Resource download url display'
\ No newline at end of file
+ label: 'Resource download url display'
diff --git a/modules/metastore/metastore.links.menu.yml b/modules/metastore/metastore.links.menu.yml
index 753cdaa252..79df4f37ef 100644
--- a/modules/metastore/metastore.links.menu.yml
+++ b/modules/metastore/metastore.links.menu.yml
@@ -1,7 +1,7 @@
dkan.metastore.config_properties:
- title: Metastore referencer
+ title: Metastore configuration
route_name: dkan.metastore.config_properties
- description: Configure dataset properties for referencing an API endpoint.
+ description: Configure dataset properties for referencing sub-schemas and for HTML sanitization.
parent: system.admin_dkan
weight: 14
diff --git a/modules/metastore/metastore.post_update.php b/modules/metastore/metastore.post_update.php
new file mode 100644
index 0000000000..664577c9f5
--- /dev/null
+++ b/modules/metastore/metastore.post_update.php
@@ -0,0 +1,12 @@
+config('metastore.settings');
- $options = $this->schemaHelper->retrieveSchemaProperties('dataset');
- $default_values = $config->get('property_list');
+
$form['description'] = [
'#markup' => $this->t(
- 'Select properties from the dataset schema to be available as individual objects.
- Each property will be assigned a unique identifier in addition to its original schema value.'
+ 'Configure the metastore settings.'
),
];
+
+ $form['html_allowed_properties'] = [
+ '#type' => 'checkboxes',
+ '#title' => $this->t('Properties that allow HTML'),
+ '#description' => $this->t('Metadata properties that may contain HTML elements.'),
+ '#options' => $this->schemaHelper->retrieveStringSchemaProperties(),
+ '#default_value' => $config->get('html_allowed_properties') ?:
+ ['dataset_description', 'distribution_description'],
+ ];
+
$form['property_list'] = [
'#type' => 'checkboxes',
- '#title' => $this->t('Dataset properties'),
- '#options' => $options,
- '#default_value' => $default_values,
+ '#title' => $this->t('Dataset properties to be stored as separate entities; use caution'),
+ '#description' => $this->t('Select properties from the dataset schema to be available as individual objects.
+ Each property will be assigned a unique identifier in addition to its original schema value.'),
+ '#options' => $this->schemaHelper->retrieveSchemaProperties(),
+ '#default_value' => $config->get('property_list'),
];
+
return parent::buildForm($form, $form_state);
}
@@ -107,6 +118,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('metastore.settings')
->set('property_list', $form_state->getValue('property_list'))
+ ->set('html_allowed_properties', $form_state->getValue('html_allowed_properties'))
->save();
// Rebuild routes, without clearing all caches.
diff --git a/modules/metastore/src/SchemaPropertiesHelper.php b/modules/metastore/src/SchemaPropertiesHelper.php
index e1b19d76a3..0ddd326371 100644
--- a/modules/metastore/src/SchemaPropertiesHelper.php
+++ b/modules/metastore/src/SchemaPropertiesHelper.php
@@ -38,7 +38,7 @@ public function __construct(SchemaRetriever $schemaRetriever) {
}
/**
- * Retrieve schema properties.
+ * Retrieve dataset schema properties.
*
* @return array
* List of schema properties' title and description.
@@ -62,4 +62,88 @@ public function retrieveSchemaProperties(): array {
return $property_list;
}
+ /**
+ * Retrieve all string schema properties.
+ *
+ * @return array
+ * List of schema properties' title and description.
+ */
+ public function retrieveStringSchemaProperties(): array {
+ // Create a json object from our schema.
+ $schema = $this->schemaRetriever->retrieve('dataset');
+ $schema_object = json_decode($schema);
+
+ return $this->buildPropertyList($schema_object->properties);
+ }
+
+ /**
+ * Build a list of JSON schema properties.
+ *
+ * @param object $input
+ * JSON Schema object we're parsing.
+ * @param string $parent
+ * Parent object.
+ * @param array $property_list
+ * Array we're building of schema properties.
+ *
+ * @return array
+ * List of schema properties' title and description.
+ *
+ * @see https://json-schema.org/understanding-json-schema/reference/object.html#properties
+ */
+ private function buildPropertyList($input, string $parent = 'dataset', array &$property_list = []): array {
+ foreach ($input as $name => $property) {
+ $this->parseProperty($name, $property, $parent, $property_list);
+ }
+ return $property_list;
+ }
+
+ /**
+ * Parse a single property from a JSON schema.
+ *
+ * @param string $name
+ * Property name.
+ * @param mixed $property
+ * JSON schema "property" object.
+ * @param string $parent
+ * The parent JSON Schema propety of the current property.
+ * @param array $property_list
+ * Array we're building of schema properties.
+ */
+ private function parseProperty(string $name, $property, string $parent, array &$property_list) {
+ // Exclude properties starting with @ or that are not proper objects.
+ if (substr($name, 0, 1) == '@' || gettype($property) != 'object' || !isset($property->type)) {
+ return;
+ }
+
+ // Strings can be added directly to the list.
+ if ($property->type == 'string') {
+ $title = isset($property->title) ? $property->title . ' (' . $name . ')' : ucfirst($name);
+ $property_list[$parent . '_' . $name] = ucfirst($parent) . ': ' . $title;
+ }
+ // Non-strings (arrays and objects) can be parsed for nested properties.
+ else {
+ $this->parseNestedProperties($name, $property, $property_list);
+ }
+ }
+
+ /**
+ * Parse nested schema properties.
+ *
+ * @param string $name
+ * Property ID.
+ * @param object $property
+ * JSON Schema "property" object we're parsing.
+ * @param array $property_list
+ * Array we're building of schema properties.
+ */
+ private function parseNestedProperties(string $name, $property, array &$property_list = []) {
+ if (isset($property->properties) && gettype($property->properties == 'object')) {
+ $property_list = $this->buildPropertyList($property->properties, $name, $property_list);
+ }
+ elseif (isset($property->items) && gettype($property->items) == 'object' && isset($property->items->properties)) {
+ $property_list = $this->buildPropertyList($property->items->properties, $name, $property_list);
+ }
+ }
+
}
diff --git a/modules/metastore/src/Storage/Data.php b/modules/metastore/src/Storage/Data.php
index 86697688e9..d2a2f81c37 100644
--- a/modules/metastore/src/Storage/Data.php
+++ b/modules/metastore/src/Storage/Data.php
@@ -3,6 +3,7 @@
namespace Drupal\metastore\Storage;
use Drupal\common\LoggerTrait;
+use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -84,13 +85,21 @@ abstract class Data implements MetastoreEntityStorageInterface {
*/
protected $schemaIdField;
+ /**
+ * The config factory.
+ *
+ * @var \Drupal\Core\Config\ConfigFactoryInterface
+ */
+ protected $configFactory;
+
/**
* Constructor.
*/
- public function __construct(string $schemaId, EntityTypeManagerInterface $entityTypeManager) {
+ public function __construct(string $schemaId, EntityTypeManagerInterface $entityTypeManager, ConfigFactoryInterface $config_factory) {
$this->entityTypeManager = $entityTypeManager;
$this->entityStorage = $this->entityTypeManager->getStorage($this->entityType);
$this->schemaId = $schemaId;
+ $this->configFactory = $config_factory;
}
/**
@@ -303,7 +312,7 @@ public function remove(string $uuid) {
public function store($data, string $uuid = NULL): string {
$data = json_decode($data);
- $data = $this->filterHtml($data);
+ $data = $this->filterHtml($data, $this->schemaId);
$uuid = (!$uuid && isset($data->identifier)) ? $data->identifier : $uuid;
@@ -365,7 +374,7 @@ private function updateExistingEntity(ContentEntityInterface $entity, $data): ?s
private function createNewEntity(string $uuid, $data) {
$title = '';
if ($this->schemaId === 'dataset') {
- $title = isset($data->title) ? $data->title : $data->name;
+ $title = $data->title ?? $data->name;
}
else {
$title = MetastoreService::metadataHash($data->data);
@@ -393,20 +402,30 @@ private function createNewEntity(string $uuid, $data) {
*
* @param mixed $input
* Unfiltered input.
+ * @param string $parent
+ * The parent schema of a given property.
*
* @return mixed
* Filtered output.
*/
- private function filterHtml($input) {
- // @todo find out if we still need it.
+ private function filterHtml($input, string $parent = 'dataset') {
+ $html_allowed = $this->configFactory->get('metastore.settings')->get('html_allowed_properties')
+ ?: ['dataset_description', 'distribution_description'];
switch (gettype($input)) {
case "string":
return $this->htmlPurifier($input);
case "array":
case "object":
- foreach ($input as &$value) {
- $value = $this->filterHtml($value);
+ foreach ($input as $name => &$value) {
+ // Only apply filtering to properties that allow HTML.
+ if (in_array($parent . '_' . $name, $html_allowed)) {
+ $value = $this->filterHtml($value, $name);
+ }
+ // Nested properties; check using parent.
+ elseif ($name == 'data' && gettype($value) == 'object') {
+ $value = $this->filterHtml($value, $parent);
+ }
}
return $input;
diff --git a/modules/metastore/src/Storage/DataFactory.php b/modules/metastore/src/Storage/DataFactory.php
index 4841ae34d6..cd712adc3c 100644
--- a/modules/metastore/src/Storage/DataFactory.php
+++ b/modules/metastore/src/Storage/DataFactory.php
@@ -3,6 +3,7 @@
namespace Drupal\metastore\Storage;
use Contracts\FactoryInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManager;
/**
@@ -24,11 +25,19 @@ class DataFactory implements FactoryInterface {
*/
private $entityTypeManager;
+ /**
+ * The config factory.
+ *
+ * @var \Drupal\Core\Config\ConfigFactoryInterface
+ */
+ protected $configFactory;
+
/**
* Constructor.
*/
- public function __construct(EntityTypeManager $entityTypeManager) {
+ public function __construct(EntityTypeManager $entityTypeManager, ConfigFactoryInterface $config_factory) {
$this->entityTypeManager = $entityTypeManager;
+ $this->configFactory = $config_factory;
}
/**
@@ -79,7 +88,7 @@ private function getEntityTypeBySchema(string $schema_id) : string {
* Storage object.
*/
protected function createNodeInstance(string $identifier) {
- return new NodeData($identifier, $this->entityTypeManager);
+ return new NodeData($identifier, $this->entityTypeManager, $this->configFactory);
}
/**
diff --git a/modules/metastore/src/Storage/NodeData.php b/modules/metastore/src/Storage/NodeData.php
index d223346bc1..72c8c49afc 100644
--- a/modules/metastore/src/Storage/NodeData.php
+++ b/modules/metastore/src/Storage/NodeData.php
@@ -2,6 +2,7 @@
namespace Drupal\metastore\Storage;
+use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
@@ -12,14 +13,14 @@ class NodeData extends Data {
/**
* NodeData constructor.
*/
- public function __construct(string $schemaId, EntityTypeManagerInterface $entityTypeManager) {
+ public function __construct(string $schemaId, EntityTypeManagerInterface $entityTypeManager, ConfigFactoryInterface $config_factory) {
$this->entityType = 'node';
$this->bundle = 'data';
$this->bundleKey = "type";
$this->labelKey = "title";
$this->schemaIdField = "field_data_type";
$this->metadataField = "field_json_metadata";
- parent::__construct($schemaId, $entityTypeManager);
+ parent::__construct($schemaId, $entityTypeManager, $config_factory);
}
/**
diff --git a/modules/metastore/tests/src/Unit/MetastoreControllerTest.php b/modules/metastore/tests/src/Unit/MetastoreControllerTest.php
index d294098165..21a0f1e1d2 100644
--- a/modules/metastore/tests/src/Unit/MetastoreControllerTest.php
+++ b/modules/metastore/tests/src/Unit/MetastoreControllerTest.php
@@ -3,6 +3,8 @@
namespace Drupal\Tests\metastore\Unit;
use Drupal\Core\Cache\Context\CacheContextsManager;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ImmutableConfig;
use Drupal\metastore\DatasetApiDocs;
use Drupal\metastore\Exception\ExistingObjectException;
use Drupal\metastore\Exception\MissingObjectException;
@@ -39,6 +41,18 @@ class MetastoreControllerTest extends TestCase {
*/
protected $validMetadataFactory;
+ /**
+ * List html allowed schema properties properties.
+ *
+ * @var string[]
+ */
+ public const HTML_ALLOWED_PROPERTIES = [
+ 'dataset_description' => 'dataset_description',
+ 'distribution_description' => 'distribution_description',
+ 'dataset_title' => 0,
+ 'dataset_identifier' => 0,
+ ];
+
protected function setUp(): void {
parent::setUp();
$this->validMetadataFactory = MetastoreServiceTest::getValidMetadataFactory($this);
@@ -111,7 +125,13 @@ public function testGet() {
->add(QueryInterface::class, 'condition', QueryInterface::class)
->add(QueryInterface::class, 'execute', NULL)
->getMock();
- $nodeDataMock = new NodeData($schema_id, $entityTypeManagerMock);
+ $immutableConfig = (new Chain($this))
+ ->add(ImmutableConfig::class, 'get', self::HTML_ALLOWED_PROPERTIES)
+ ->getMock();
+ $configFactoryMock = (new Chain($this))
+ ->add(ConfigFactoryInterface::class, 'get', $immutableConfig)
+ ->getMock();
+ $nodeDataMock = new NodeData($schema_id, $entityTypeManagerMock, $configFactoryMock);
$container = $this->getCommonMockChain()
->add(MetastoreService::class, 'getStorage', $nodeDataMock)
->getMock();
diff --git a/modules/metastore/tests/src/Unit/SchemaPropertiesHelperTest.php b/modules/metastore/tests/src/Unit/SchemaPropertiesHelperTest.php
index 2da7485556..5853671346 100644
--- a/modules/metastore/tests/src/Unit/SchemaPropertiesHelperTest.php
+++ b/modules/metastore/tests/src/Unit/SchemaPropertiesHelperTest.php
@@ -14,7 +14,7 @@
class SchemaPropertiesHelperTest extends TestCase {
/**
- * Test.
+ * Test to retrieve dataset schema properties.
*/
public function test() {
$schema = '{
@@ -43,4 +43,67 @@ public function test() {
$this->assertEquals($expected, $schemaPropertiesHelper->retrieveSchemaProperties());
}
+ /**
+ * Test to retrieve string schema properties.
+ */
+ public function testRetrieveStringSchemaProperties() {
+ $schema = '{
+ "type":"object",
+ "properties":{
+ "@type":{
+ "type":"string",
+ "title":"Metadata Context"
+ },
+ "title":{
+ "type":"string",
+ "title":"Title"
+ },
+ "test":{
+ "type":"string"
+ },
+ "theme": {
+ "type":"array",
+ "items": {
+ "type": "string",
+ "title": "Category"
+ }
+ },
+ "contactPoint":{
+ "type":"object",
+ "properties": {
+ "fn":{
+ "type":"string",
+ "title":"Contact Name"
+ }
+ }
+ },
+ "distribution": {
+ "type":"array",
+ "items": {
+ "type": "object",
+ "title": "Data File",
+ "properties": {
+ "title":{
+ "type":"string",
+ "title":"Title"
+ }
+ }
+ }
+ }
+ }
+ }';
+ $expected = [
+ 'dataset_title' => 'Dataset: Title (title)',
+ 'dataset_test' => 'Dataset: Test',
+ 'contactPoint_fn' => 'ContactPoint: Contact Name (fn)',
+ 'distribution_title' => 'Distribution: Title (title)'
+ ];
+
+ $chain = (new Chain($this))
+ ->add(Container::class, 'get', SchemaRetriever::class)
+ ->add(SchemaRetriever::class, 'retrieve', $schema);
+
+ $schemaPropertiesHelper = SchemaPropertiesHelper::create($chain->getMock());
+ $this->assertEquals($expected, $schemaPropertiesHelper->retrieveStringSchemaProperties());
+ }
}
diff --git a/modules/metastore/tests/src/Unit/Storage/DataTest.php b/modules/metastore/tests/src/Unit/Storage/DataTest.php
index b37e8d2675..13d786a921 100644
--- a/modules/metastore/tests/src/Unit/Storage/DataTest.php
+++ b/modules/metastore/tests/src/Unit/Storage/DataTest.php
@@ -2,6 +2,8 @@
namespace Drupal\Tests\metastore\Unit\Storage;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Field\FieldItemListInterface;
@@ -18,9 +20,27 @@
*/
class DataTest extends TestCase {
+ /**
+ * List html allowed schema properties properties.
+ *
+ * @var string[]
+ */
+ public const HTML_ALLOWED_PROPERTIES = [
+ 'dataset_description' => 'dataset_description',
+ 'distribution_description' => 'distribution_description',
+ 'dataset_title' => 0,
+ 'dataset_identifier' => 0,
+ ];
+
public function testGetStorageNode() {
+ $immutableConfig = (new Chain($this))
+ ->add(ImmutableConfig::class, 'get', self::HTML_ALLOWED_PROPERTIES)
+ ->getMock();
+ $configFactoryMock = (new Chain($this))
+ ->add(ConfigFactoryInterface::class, 'get', $immutableConfig)
+ ->getMock();
- $data = new NodeData('dataset', $this->getEtmChain()->getMock());
+ $data = new NodeData('dataset', $this->getEtmChain()->getMock(), $configFactoryMock);
$this->assertInstanceOf(NodeStorage::class, $data->getEntityStorage());
}
@@ -29,9 +49,15 @@ public function testPublishDatasetNotFound() {
$etmMock = $this->getEtmChain()
->add(QueryInterface::class, 'execute', [])
->getMock();
+ $immutableConfig = (new Chain($this))
+ ->add(ImmutableConfig::class, 'get', self::HTML_ALLOWED_PROPERTIES)
+ ->getMock();
+ $configFactoryMock = (new Chain($this))
+ ->add(ConfigFactoryInterface::class, 'get', $immutableConfig)
+ ->getMock();
$this->expectExceptionMessage('Error: 1 not found.');
- $nodeData = new NodeData('dataset', $etmMock);
+ $nodeData = new NodeData('dataset', $etmMock, $configFactoryMock);
$nodeData->publish('1');
}
@@ -43,8 +69,14 @@ public function testPublishDraftDataset() {
->add(Node::class, 'set')
->add(Node::class, 'save')
->getMock();
+ $immutableConfig = (new Chain($this))
+ ->add(ImmutableConfig::class, 'get', self::HTML_ALLOWED_PROPERTIES)
+ ->getMock();
+ $configFactoryMock = (new Chain($this))
+ ->add(ConfigFactoryInterface::class, 'get', $immutableConfig)
+ ->getMock();
- $nodeData = new NodeData('dataset', $etmMock);
+ $nodeData = new NodeData('dataset', $etmMock, $configFactoryMock);
$result = $nodeData->publish('1');
$this->assertEquals(TRUE, $result);
}
@@ -55,8 +87,14 @@ public function testPublishDatasetAlreadyPublished() {
->add(Node::class, 'get', FieldItemListInterface::class)
->add(FieldItemListInterface::class, 'getString', 'published')
->getMock();
+ $immutableConfig = (new Chain($this))
+ ->add(ImmutableConfig::class, 'get', self::HTML_ALLOWED_PROPERTIES)
+ ->getMock();
+ $configFactoryMock = (new Chain($this))
+ ->add(ConfigFactoryInterface::class, 'get', $immutableConfig)
+ ->getMock();
- $nodeData = new NodeData('dataset', $etmMock);
+ $nodeData = new NodeData('dataset', $etmMock, $configFactoryMock);
$result = $nodeData->publish('1');
$this->assertEquals(FALSE, $result);
}
@@ -86,9 +124,15 @@ public function testCount(): void {
$etmMock = $this->getEtmChain()
->add(QueryInterface::class, 'execute', $count)
->getMock();
+ $immutableConfig = (new Chain($this))
+ ->add(ImmutableConfig::class, 'get', self::HTML_ALLOWED_PROPERTIES)
+ ->getMock();
+ $configFactoryMock = (new Chain($this))
+ ->add(ConfigFactoryInterface::class, 'get', $immutableConfig)
+ ->getMock();
// Create Data object.
- $nodeData = new NodeData('dataset', $etmMock);
+ $nodeData = new NodeData('dataset', $etmMock, $configFactoryMock);
// Ensure count matches return value.
$this->assertEquals($count, $nodeData->count());
}
@@ -115,9 +159,15 @@ public function uuid() {
$etmMock = $this->getEtmChain()
->add(NodeStorage::class, 'loadMultiple', $nodes)
->getMock();
+ $immutableConfig = (new Chain($this))
+ ->add(ImmutableConfig::class, 'get', self::HTML_ALLOWED_PROPERTIES)
+ ->getMock();
+ $configFactoryMock = (new Chain($this))
+ ->add(ConfigFactoryInterface::class, 'get', $immutableConfig)
+ ->getMock();
// Create Data object.
- $nodeData = new NodeData('dataset', $etmMock);
+ $nodeData = new NodeData('dataset', $etmMock, $configFactoryMock);
// Ensure the returned uuids match those belonging to the generated nodes.
$this->assertEquals($uuids, $nodeData->retrieveIds(1, 5));
}
diff --git a/tests/src/Functional/DatasetBTBTest.php b/tests/src/Functional/DatasetBTBTest.php
index bb5b3e1db5..dd002b84d5 100644
--- a/tests/src/Functional/DatasetBTBTest.php
+++ b/tests/src/Functional/DatasetBTBTest.php
@@ -319,6 +319,37 @@ public function testDatastoreImportDeleteLocalResource() {
$this->assertDirectoryExists('public://resources/' . $refUuid);
}
+ /**
+ * Test sanitization of dataset properties.
+ */
+ public function testSanitizeDatasetProperties() {
+ $config = $this->container->get('config.factory');
+ $metastoreSettings = $config->getEditable('metastore.settings');
+
+ // Set HTML allowed on dataset description.
+ $metastoreSettings->set('html_allowed_properties', ['dataset_description'])->save();
+
+ // Title with HTML and an ampersand.
+ $datasetRootedJsonData = $this->getData(123, 'This & That Right click me', ['1.csv']);
+
+ $uuid = $this->getMetastore()->post('dataset', $datasetRootedJsonData);
+
+ $datasetRootedJsonData = $this->getMetastore()->get('dataset', $uuid);
+ $retrievedDataset = json_decode((string) $datasetRootedJsonData);
+
+ $this->assertEquals(
+ $retrievedDataset->title,
+ 'This & That Right click me'
+ );
+ $this->assertEquals(
+ $retrievedDataset->description,
+ 'This & that description. Right click me.'
+ );
+ }
+
+ /**
+ * Test sanitization of dataset properties.
+ */
private function datasetPostAndRetrieve(): object {
$datasetRootedJsonData = $this->getData(123, 'Test #1', ['district_centerpoints_small.csv']);
$dataset = json_decode($datasetRootedJsonData);
@@ -391,7 +422,7 @@ private function getData(string $identifier, string $title, array $downloadUrls)
$data = new \stdClass();
$data->title = $title;
- $data->description = 'Some description.';
+ $data->description = 'This & that description. Right click me.';
$data->identifier = $identifier;
$data->accessLevel = 'public';
$data->modified = '06-04-2020';