Skip to content

Commit

Permalink
Merge pull request #2003 from wardi/2003-package-patch-simple-version
Browse files Browse the repository at this point in the history
package_patch (simple version)
  • Loading branch information
David Read committed Nov 21, 2014
2 parents 36718f2 + 0ca9f88 commit b455441
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 2 deletions.
2 changes: 1 addition & 1 deletion ckan/logic/__init__.py
Expand Up @@ -360,7 +360,7 @@ def get_action(action):
# Rather than writing them out in full will use __import__
# to load anything from ckan.logic.action that looks like it might
# be an action
for action_module_name in ['get', 'create', 'update', 'delete']:
for action_module_name in ['get', 'create', 'update', 'delete', 'patch']:
module_path = 'ckan.logic.action.' + action_module_name
module = __import__(module_path)
for part in module_path.split('.')[1:]:
Expand Down
130 changes: 130 additions & 0 deletions ckan/logic/action/patch.py
@@ -0,0 +1,130 @@
'''API functions for partial updates of existing data in CKAN'''

import ckan.logic.action.update as _update
from ckan.logic import (
get_action as _get_action,
check_access as _check_access,
get_or_bust as _get_or_bust,
)


def package_patch(context, data_dict):
'''Patch a dataset (package).
:param id: the id or name of the dataset
:type id: string
The difference between the update and patch methods is that the patch will
perform an update of the provided parameters, while leaving all other
parameters unchanged, whereas the update methods deletes all parameters
not explicitly provided in the data_dict
You must be authorized to edit the dataset and the groups that it belongs
to.
'''
_check_access('package_patch', context, data_dict)

show_context = {
'model': context['model'],
'session': context['session'],
'user': context['user'],
'auth_user_obj': context['auth_user_obj'],
}

package_dict = _get_action('package_show')(
show_context,
{'id': _get_or_bust(data_dict, 'id')})

patched = dict(package_dict)
patched.update(data_dict)
patched['id'] = package_dict['id']
return _update.package_update(context, patched)


def resource_patch(context, data_dict):
'''Patch a resource
:param id: the id of the resource
:type id: string
The difference between the update and patch methods is that the patch will
perform an update of the provided parameters, while leaving all other
parameters unchanged, whereas the update methods deletes all parameters
not explicitly provided in the data_dict
'''
_check_access('resource_patch', context, data_dict)

show_context = {
'model': context['model'],
'session': context['session'],
'user': context['user'],
'auth_user_obj': context['auth_user_obj'],
}

resource_dict = _get_action('resource_show')(
show_context,
{'id': _get_or_bust(data_dict, 'id')})

patched = dict(resource_dict)
patched.update(data_dict)
return _update.resource_update(context, patched)


def group_patch(context, data_dict):
'''Patch a group
:param id: the id or name of the group
:type id: string
The difference between the update and patch methods is that the patch will
perform an update of the provided parameters, while leaving all other
parameters unchanged, whereas the update methods deletes all parameters
not explicitly provided in the data_dict
'''
_check_access('group_patch', context, data_dict)

show_context = {
'model': context['model'],
'session': context['session'],
'user': context['user'],
'auth_user_obj': context['auth_user_obj'],
}

group_dict = _get_action('group_show')(
show_context,
{'id': _get_or_bust(data_dict, 'id')})

patched = dict(group_dict)
patched.pop('display_name', None)
patched.update(data_dict)
return _update.group_update(context, patched)


def organization_patch(context, data_dict):
'''Patch an organization
:param id: the id or name of the organization
:type id: string
The difference between the update and patch methods is that the patch will
perform an update of the provided parameters, while leaving all other
parameters unchanged, whereas the update methods deletes all parameters
not explicitly provided in the data_dict
'''
_check_access('organization_patch', context, data_dict)

show_context = {
'model': context['model'],
'session': context['session'],
'user': context['user'],
'auth_user_obj': context['auth_user_obj'],
}

organization_dict = _get_action('organization_show')(
show_context,
{'id': _get_or_bust(data_dict, 'id')})

patched = dict(organization_dict)
patched.pop('display_name', None)
patched.update(data_dict)
return _update.organization_update(context, patched)
10 changes: 10 additions & 0 deletions ckan/logic/auth/patch.py
@@ -0,0 +1,10 @@
from ckan import logic
import ckan.logic.auth.update as _update

package_patch = _update.package_update

resource_patch = _update.resource_update

group_patch = _update.group_update

organization_patch = _update.organization_update
2 changes: 1 addition & 1 deletion ckan/new_authz.py
Expand Up @@ -44,7 +44,7 @@ def _build(self):

module_root = 'ckan.logic.auth'

for auth_module_name in ['get', 'create', 'update', 'delete']:
for auth_module_name in ['get', 'create', 'update', 'delete', 'patch']:
module_path = '%s.%s' % (module_root, auth_module_name,)
try:
module = __import__(module_path)
Expand Down
97 changes: 97 additions & 0 deletions ckan/new_tests/logic/action/test_patch.py
@@ -0,0 +1,97 @@
'''Unit tests for ckan/logic/action/patch.py.'''
import datetime

from nose.tools import assert_equals, assert_raises
import mock
import pylons.config as config

from ckan.new_tests import helpers, factories


class TestPatch(helpers.FunctionalTestBase):

def test_package_patch_updating_single_field(self):
user = factories.User()
dataset = factories.Dataset(
name='annakarenina',
notes='some test now',
user=user)

dataset = helpers.call_action(
'package_patch',
id=dataset['id'],
name='somethingnew')

assert_equals(dataset['name'], 'somethingnew')
assert_equals(dataset['notes'], 'some test now')

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

assert_equals(dataset2['name'], 'somethingnew')
assert_equals(dataset2['notes'], 'some test now')

def test_resource_patch_updating_single_field(self):
user = factories.User()
dataset = factories.Dataset(
name='annakarenina',
notes='some test now',
user=user,
resources=[{'url': 'http://example.com/resource'}])

resource = helpers.call_action(
'resource_patch',
id=dataset['resources'][0]['id'],
name='somethingnew')

assert_equals(resource['name'], 'somethingnew')
assert_equals(resource['url'], 'http://example.com/resource')

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

resource2 = dataset2['resources'][0]
assert_equals(resource2['name'], 'somethingnew')
assert_equals(resource2['url'], 'http://example.com/resource')

def test_group_patch_updating_single_field(self):
user = factories.User()
group = factories.Group(
name='economy',
description='some test now',
user=user)

group = helpers.call_action(
'group_patch',
id=group['id'],
description='somethingnew',
context={'user': user['name']})

assert_equals(group['name'], 'economy')
assert_equals(group['description'], 'somethingnew')

group2 = helpers.call_action('group_show', id=group['id'])

assert_equals(group2['name'], 'economy')
assert_equals(group2['description'], 'somethingnew')

def test_organization_patch_updating_single_field(self):
user = factories.User()
organization = factories.Organization(
name='economy',
description='some test now',
user=user)

organization = helpers.call_action(
'organization_patch',
id=organization['id'],
description='somethingnew',
context={'user': user['name']})

assert_equals(organization['name'], 'economy')
assert_equals(organization['description'], 'somethingnew')

organization2 = helpers.call_action(
'organization_show',
id=organization['id'])

assert_equals(organization2['name'], 'economy')
assert_equals(organization2['description'], 'somethingnew')
8 changes: 8 additions & 0 deletions doc/api/index.rst
Expand Up @@ -381,6 +381,14 @@ ckan.logic.action.update
.. automodule:: ckan.logic.action.update
:members:

ckan.logic.action.patch
=======================

.. versionadded:: 2.3

.. automodule:: ckan.logic.action.patch
:members:

ckan.logic.action.delete
========================

Expand Down

0 comments on commit b455441

Please sign in to comment.