Skip to content

Commit

Permalink
Deleting a dataset now also deletes its resources
Browse files Browse the repository at this point in the history
Fixes #4705

@dassolkim is concerned that IResourceController.before_delete event is
not firing at any point when a dataset is deleted and then purged
(either with package_purge or the admin.Trash page). PR #4867 seeks to
implement the event in the admin.Trash page. But this PR proposes the
alternative, which is to actually delete the resource when the dataset
is deleted and fire the event then.

It seems an anomaly that we don't delete resources with the dataset. It
makes sense that the dataset and resources are both state=deleted.
However there is an argument that we shouldn't, because a sysadmin can still
see the deleted dataset, but with this PR it will have no resources.
  • Loading branch information
David Read committed Jul 12, 2019
1 parent 51e4130 commit 02c10a4
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 2 deletions.
25 changes: 24 additions & 1 deletion ckan/logic/action/delete.py
Expand Up @@ -92,6 +92,29 @@ def package_delete(context, data_dict):
rev.author = user
rev.message = _(u'REST API: Delete Package: %s') % entity.name

# delete the dataset's resources
pkg_dict = _get_action('package_show')(context, {'id': id})
for res in pkg_dict['resources']:
for plugin in plugins.PluginImplementations(
plugins.IResourceController):
plugin.before_delete(context, res,
pkg_dict.get('resources', []))

def pop_resource(pkg_dict, res_id):
for res in pkg_dict.get('resources', []):
if res['id'] == res_id:
pkg_dict['resources'].remove(res)
return

pkg_dict = _get_action('package_show')(context, {'id': id})
for res in entity.resources:
pop_resource(pkg_dict, res.id)
res.delete()
for plugin in plugins.PluginImplementations(
plugins.IResourceController):
plugin.after_delete(context, pkg_dict.get('resources', []))

# delete the dataset
for item in plugins.PluginImplementations(plugins.IPackageController):
item.delete(entity)

Expand Down Expand Up @@ -195,7 +218,7 @@ def resource_delete(context, data_dict):

for plugin in plugins.PluginImplementations(plugins.IResourceController):
plugin.after_delete(context, pkg_dict.get('resources', []))

model.repo.commit()


Expand Down
37 changes: 36 additions & 1 deletion ckan/tests/logic/action/test_delete.py
Expand Up @@ -21,7 +21,42 @@
raises = nose.tools.raises


class TestDelete:
class TestPackageDelete:

def setup(self):
helpers.reset_db()

def test_simple(self):
user = factories.User()
sysadmin = factories.Sysadmin()
dataset = factories.Dataset(user=user)

helpers.call_action('package_delete', id=dataset['id'])

# A sysadmin can still see it
dataset = helpers.call_action(
'package_show', {'user': sysadmin['name']}, id=dataset['id'])
assert_equals(dataset['state'], 'deleted')

def test_with_resource(self):
user = factories.User()
sysadmin = factories.Sysadmin()
dataset = factories.Dataset(user=user)
resource = factories.Resource(package_id=dataset['id'])

helpers.call_action('package_delete', id=dataset['id'])

dataset = helpers.call_action(
'package_show', {'user': sysadmin['name']}, id=dataset['id'])
assert_equals(dataset['state'], 'deleted')
# The resource is not shown though
assert_equals(dataset['resources'], [])
# The resource is still there but with state=deleted
res_obj = model.Resource.get(resource['id'])
assert_equals(res_obj.state, 'deleted')


class TestResourceDelete:

def setup(self):
helpers.reset_db()
Expand Down
Expand Up @@ -89,6 +89,27 @@ def test_resource_controller_plugin_delete(self):
assert plugin.counter['before_delete'] == 1, plugin.counter
assert plugin.counter['after_delete'] == 1, plugin.counter

def test_resource_controller_plugin_delete_via_dataset_delete(self):
user = factories.Sysadmin()
dataset = factories.Dataset(user=user)
factories.Resource(user=user, package_id=dataset['id'])
factories.Resource(user=user, package_id=dataset['id'])

ckan.plugins.load('example_iresourcecontroller')
plugin = ckan.plugins.get_plugin('example_iresourcecontroller')

# Deleting the package deletes its resources too
res = helpers.call_action('package_delete',
id=dataset['id'],
apikey=user['apikey'])

assert plugin.counter['before_create'] == 0, plugin.counter
assert plugin.counter['after_create'] == 0, plugin.counter
assert plugin.counter['before_update'] == 0, plugin.counter
assert plugin.counter['after_update'] == 0, plugin.counter
assert plugin.counter['before_delete'] == 2, plugin.counter
assert plugin.counter['after_delete'] == 2, plugin.counter

def test_resource_controller_plugin_show(self):
"""
Before show gets called by the other methods but we test it
Expand Down

0 comments on commit 02c10a4

Please sign in to comment.