Skip to content

Commit

Permalink
[#1572] dataset_purge action added
Browse files Browse the repository at this point in the history
  • Loading branch information
David Read committed Sep 10, 2015
1 parent a16261d commit a9c6c0e
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 9 deletions.
8 changes: 3 additions & 5 deletions ckan/lib/cli.py
Expand Up @@ -890,7 +890,6 @@ class DatasetCmd(CkanCommand):

def command(self):
self._load_config()
import ckan.model as model

if not self.args:
print self.usage
Expand Down Expand Up @@ -939,13 +938,12 @@ def delete(self, dataset_ref):
print '%s %s -> %s' % (dataset.name, old_state, dataset.state)

def purge(self, dataset_ref):
import ckan.model as model
dataset = self._get_dataset(dataset_ref)
name = dataset.name

rev = model.repo.new_revision()
dataset.purge()
model.repo.commit_and_remove()
context = {'user': self.site_user['name']}
logic.get_action('dataset_purge')(
context, {'id': dataset_ref})
print '%s purged' % name


Expand Down
42 changes: 42 additions & 0 deletions ckan/logic/action/delete.py
Expand Up @@ -44,6 +44,9 @@ def user_delete(context, data_dict):
def package_delete(context, data_dict):
'''Delete a dataset (package).
This makes the dataset disappear from all web & API views, apart from the
trash.
You must be authorized to delete the dataset.
:param id: the id or name of the dataset to delete
Expand Down Expand Up @@ -73,6 +76,45 @@ def package_delete(context, data_dict):
entity.delete()
model.repo.commit()


def dataset_purge(context, data_dict):
'''Purge a dataset.
.. warning:: Purging a dataset cannot be undone!
Purging a database completely removes the dataset from the CKAN database,
whereias deleting a dataset simply marks the dataset as deleted (it will no
longer show up in the front-end, but is still in the db).
You must be authorized to purge the dataset.
:param id: the name or id of the dataset to be purged
:type id: string
'''
model = context['model']
id = _get_or_bust(data_dict, 'id')

pkg = model.Package.get(id)
context['package'] = pkg
if pkg is None:
raise NotFound('Dataset was not found')

_check_access('dataset_purge', context, data_dict)

members = model.Session.query(model.Member) \
.filter(model.Member.table_id == pkg.id) \
.filter(model.Member.table_name == 'package')
if members.count() > 0:
for m in members.all():
m.purge()

pkg = model.Package.get(id)
model.repo.new_revision()
pkg.purge()
model.repo.commit_and_remove()


def resource_delete(context, data_dict):
'''Delete a resource from a dataset.
Expand Down
4 changes: 4 additions & 0 deletions ckan/logic/auth/delete.py
Expand Up @@ -17,6 +17,10 @@ def package_delete(context, data_dict):
# are essentially changing the state field
return _auth_update.package_update(context, data_dict)

def dataset_purge(context, data_dict):
# Only sysadmins are authorized to purge datasets
return {'success': False}

def resource_delete(context, data_dict):
model = context['model']
user = context.get('user')
Expand Down
8 changes: 4 additions & 4 deletions ckan/model/group.py
Expand Up @@ -104,11 +104,11 @@ def related_packages(self):
def __unicode__(self):
# refer to objects by name, not ID, to help debugging
if self.table_name == 'package':
table_info = 'package=%s' % meta.Session.query(_package.Package).\
get(self.table_id).name
pkg = meta.Session.query(_package.Package).get(self.table_id)
table_info = 'package=%s' % pkg.name if pkg else 'None'
elif self.table_name == 'group':
table_info = 'group=%s' % meta.Session.query(Group).\
get(self.table_id).name
group = meta.Session.query(Group).get(self.table_id)
table_info = 'group=%s' % group.name if group else 'None'
else:
table_info = 'table_name=%s table_id=%s' % (self.table_name,
self.table_id)
Expand Down
60 changes: 60 additions & 0 deletions ckan/tests/logic/action/test_delete.py
Expand Up @@ -140,3 +140,63 @@ def test_tag_delete_with_unicode_returns_unicode_error(self):
assert u'Delta symbol: \u0394' in unicode(e)
else:
assert 0, 'Should have raised NotFound'


class TestDatasetPurge(object):
def setup(self):
helpers.reset_db()

def test_a_non_sysadmin_cant_purge_dataset(self):
user = factories.User()
dataset = factories.Dataset(user=user)

assert_raises(logic.NotAuthorized,
helpers.call_action,
'dataset_purge',
context={'user': user['name'], 'ignore_auth': False},
id=dataset['name'])

def test_purged_dataset_does_not_show(self):
dataset = factories.Dataset()

helpers.call_action('dataset_purge',
context={'ignore_auth': True},
id=dataset['name'])

assert_raises(logic.NotFound, helpers.call_action, 'package_show',
context={}, id=dataset['name'])

def test_purged_dataset_leaves_no_trace_in_the_model(self):
factories.Group(name='group1')
dataset = factories.Dataset(
tags=[{'name': 'tag1'}],
groups=[{'name': 'group1'}],
extras=[{'key': 'testkey', 'value': 'testvalue'}])
num_revisions_before = model.Session.query(model.Revision).count()

helpers.call_action('dataset_purge',
context={'ignore_auth': True},
id=dataset['name'])
num_revisions_after = model.Session.query(model.Revision).count()

# the Package and related objects are gone
assert_equals(model.Session.query(model.Package).all(), [])
assert_equals(model.Session.query(model.PackageTag).all(), [])
# there is no clean-up of the tag object itself, just the PackageTag.
assert_equals([t.name for t in model.Session.query(model.Tag).all()],
['tag1'])
assert_equals(model.Session.query(model.PackageExtra).all(), [])
# the only member left is the user created by factories.Group()
assert_equals([m.table_name
for m in model.Session.query(model.Member).all()],
['user'])

# all the object revisions were purged too
assert_equals(model.Session.query(model.PackageRevision).all(), [])
assert_equals(model.Session.query(model.PackageTagRevision).all(), [])
assert_equals(model.Session.query(model.PackageExtraRevision).all(),
[])
# Member is not revisioned

# No Revision objects were purged, in fact 1 is created for the purge
assert_equals(num_revisions_after - num_revisions_before, 1)

0 comments on commit a9c6c0e

Please sign in to comment.