Commit 05b26897 authored by Denis Laxalde's avatar Denis Laxalde
Browse files

[hooks,entities] Handle resources for CKAN dataset

Closes #4502967.
parent 183145b6bee7
......@@ -113,3 +113,25 @@ class CKANPublishableAdapter(EntityAdapter):
dataset-like entity.
"""
return None
def dataset_resources(self):
"""May return a list of entities adaptable as IDownloadable to be set
as resources of the CKAN dataset.
"""
return []
def ckan_resources(self):
"""Yield dicts of CKAN dataset resource info"""
for entity in self.dataset_resources():
adapted = entity.cw_adapt_to('IDownloadable')
if adapted is None:
self.warning(
'invalid resource %r, could not adapt to IDownloadable',
entity)
continue
yield {'url': adapted.download_url(),
'name': adapted.download_file_name(),
'mimetype': adapted.download_content_type(),
'created': str(entity.creation_date),
'last_modified': str(entity.modification_date),
}
......@@ -54,6 +54,23 @@ def delete_dataset(config, eid, datasetid):
_ckan_action(config, eid, 'package_delete', data={'id': datasetid})
def add_dataset_resource(config, eid, datasetid, resource_data):
"""Add a resource to an existing CKAN dataset"""
resource_data['package_id'] = datasetid
return _ckan_action(config, eid, 'resource_create', data=resource_data)
def delete_dataset_resources(config, eid, datasetid):
"""Delete resources of a CKAN dataset"""
res = _ckan_action(config, eid, 'package_show', data={'id': datasetid})
resources = res['resources']
deleted = set([])
for resource in resources:
_ckan_action(config, eid, 'resource_delete', {'id': resource['id']})
deleted.add(resource['id'])
return deleted
class DeleteCKANDataSetHook(hook.Hook):
"""Delete CKAN dataset upon deletion of the corresponding entity"""
__regid__ = 'ckanpublish.delete-ckan-dataset'
......@@ -86,10 +103,13 @@ class CKANDatasetOp(hook.DataOperationMixIn, hook.Operation):
datasetid = entity.ckan_dataset_id
config = self.cnx.vreg.config
if self.cnx.deleted_in_transaction(eid):
deleted = delete_dataset_resources(config, eid, datasetid)
self.info('deleted CKAN resources %s', ', '.join(deleted))
delete_dataset(config, eid, datasetid)
self.info('deleted CKAN dataset %s', datasetid)
else:
data = entity.cw_adapt_to('ICKANPublishable').ckan_data()
cpublish = entity.cw_adapt_to('ICKANPublishable')
data = cpublish.ckan_data()
if datasetid is not None:
update_dataset(config, eid, datasetid, data)
self.info('updated %s fields in CKAN dataset %s',
......@@ -100,3 +120,8 @@ class CKANDatasetOp(hook.DataOperationMixIn, hook.Operation):
'SET X ckan_dataset_id %(dsid)s WHERE X eid %(eid)s',
{'eid': eid, 'dsid': datasetid})
self.info('created CKAN dataset %s', datasetid)
for resource_data in cpublish.ckan_resources():
resource_id = add_dataset_resource(config, eid, datasetid,
resource_data)
self.info('add resource %s to CKAN dataset %s' %
(resource_id, datasetid))
......@@ -9,3 +9,6 @@ class CWDataSetCKANPublish(CKANPublishableAdapter):
def dataset_maintainer(self):
if self.entity.maintainer:
return self.entity.maintainer[0]
def dataset_resources(self):
return self.entity.resources
......@@ -11,3 +11,13 @@ class AddUpdateMaintainerHook(hook.Hook):
def __call__(self):
CKANDatasetOp.get_instance(self._cw).add_data(self.eidfrom)
class AddDeleteFileResourceHook(hook.Hook):
__regid__ = 'ckanpublish-tests.add-delete-file-resource'
__select__ = (hook.Hook.__select__ &
hook.match_rtype('resources', frometypes=('CWDataSet')))
events = ('after_add_relation', 'after_delete_relation')
def __call__(self):
CKANDatasetOp.get_instance(self._cw).add_data(self.eidfrom)
......@@ -10,3 +10,4 @@ class CWDataSet(EntityType):
'update': ()},
)
maintainer = SubjectRelation('CWUser', cardinality='?*')
resources = SubjectRelation('File', cardinality='*?', composite='subject')
"""cubicweb-ckanpublish unit tests for hooks"""
from cubicweb import Binary
from cubicweb.devtools.testlib import CubicWebTC
from cubes.ckanpublish.utils import ckan_post, CKANPostError
......@@ -42,6 +43,7 @@ class CKANPublishHooksTC(CubicWebTC):
cnx.commit()
yield self._check_entity_create, cnx, entity
yield self._check_entity_update, cnx, entity
yield self._check_entity_resources, cnx, entity
yield self._check_entity_delete, cnx, entity
def _check_entity_create(self, cnx, entity):
......@@ -73,14 +75,35 @@ class CKANPublishHooksTC(CubicWebTC):
self.assertEqual(result['maintainer'], 'T. Oto')
self.assertEqual(result['maintainer_email'], 'to@t.o')
def _check_entity_resources(self, cnx, entity):
self.set_description('entity resources')
resource = cnx.create_entity('File', data=Binary('yui'),
data_format=u'text/plain',
data_name=u'blurp',
reverse_resources=entity)
cnx.commit()
result = ckan_post(self.ckan_config, 'package_show',
{'id': entity.ckan_dataset_id})
resources = result['resources']
self.assertEqual(len(resources), 1)
r0 = resources[0]
iresource = resource.cw_adapt_to('IDownloadable')
self.assertEqual(r0['url'], iresource.download_url())
def _check_entity_delete(self, cnx, entity):
self.set_description('entity deletion')
ckanid = entity.ckan_dataset_id
result = ckan_post(self.ckan_config, 'package_show',
{'id': ckanid})
resource_id = result['resources'][0]['id']
entity.cw_delete()
cnx.commit()
result = ckan_post(self.ckan_config, 'package_show',
{'id': ckanid})
self.assertEqual(result['state'], 'deleted')
result = ckan_post(self.ckan_config, 'resource_show',
{'id': resource_id})
self.assertEqual(result['state'], 'deleted')
if __name__ == '__main__':
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment