[ckan-changes] [okfn/ckan] 817cba: [2330] First stab at making the get.py logic actio...

GitHub noreply at github.com
Fri May 4 16:40:18 UTC 2012


  Branch: refs/heads/feature-2330-make-api-read-actions-GETable
  Home:   https://github.com/okfn/ckan
  Commit: 817cba888ba5b5d90d583004cd7350365f5b49b4
      https://github.com/okfn/ckan/commit/817cba888ba5b5d90d583004cd7350365f5b49b4
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-03 (Thu, 03 May 2012)

  Changed paths:
    M ckan/controllers/api.py
    M ckan/lib/base.py
    M ckan/logic/__init__.py
    M ckan/tests/functional/api/test_api.py

  Log Message:
  -----------
  [2330] First stab at making the get.py logic actions GETable


diff --git a/ckan/controllers/api.py b/ckan/controllers/api.py
index a587f3d..76fb5ec 100644
--- a/ckan/controllers/api.py
+++ b/ckan/controllers/api.py
@@ -154,7 +154,8 @@ def action(self, logic_function, ver=None):
         model.Session()._context = context
         return_dict = {'help': function.__doc__}
         try:
-            request_data = self._get_request_data()
+            side_effect_free = getattr(function, 'side_effect_free', False)
+            request_data = self._get_request_data(try_url_params=side_effect_free)
         except ValueError, inst:
             log.error('Bad request data: %s' % str(inst))
             return self._finish_bad_request(
diff --git a/ckan/lib/base.py b/ckan/lib/base.py
index 4f77150..aff9707 100644
--- a/ckan/lib/base.py
+++ b/ckan/lib/base.py
@@ -271,19 +271,38 @@ def _get_tag(self, reference):
         return model.Tag.get(reference)
 
     @classmethod
-    def _get_request_data(cls):
-        '''Returns a dictionary, extracted from a request. The request data is
-        in POST data and formatted as a dictionary that has been
-        JSON-encoded.
+    def _get_request_data(cls, try_url_params=False):
+        '''Returns a dictionary, extracted from a request.
 
         If there is no data, None or "" is returned.
         ValueError will be raised if the data is not a JSON-formatted dict.
 
+        The data is retrieved as a JSON-encoded dictionary from the request
+        body.  If the `try_url_params` argument is True, then an attempt is
+        made to read the data from the url parameters of the request (if the
+        request is a GET request).
+
+        try_url_params
+            If try_url_params is False, then the data_dict is read from the
+            request body.
+
+            If the try_url_params is True and the request is a GET request,
+            then the data is read from the url parameters.  The data can either
+            be read directly from the url parameters, with each url parameter
+            describing the dict's key and value pair.  For the situation where
+            a nested dict is required, it's possible to pass a single url
+            parameter named 'data_dict', where the value is the JSON-encoded
+            data_dict.
+
         This function is only used by the API, so no strings need to be
         translated.
+
+        TODO: If this is only used by the API, then perhaps it should be
+              moved to the api controller class?
         '''
         cls.log.debug('Retrieving request params: %r' % request.params)
         cls.log.debug('Retrieving request POST: %r' % request.POST)
+        cls.log.debug('Retrieving request GET: %r' % request.GET)
         request_data = None
         if request.POST:
             try:
@@ -298,6 +317,21 @@ def _get_request_data(cls):
                 msg = "Could not find the POST data: %r : %s" % \
                       (request.POST, inst)
                 raise ValueError, msg
+
+        elif try_url_params and request.GET:
+            # Accept two ways of clients passing the data_dict via a GET
+            # request.
+
+            # First, a client can json-encode the whole data_dict in a single
+            # url parameter named 'data_dict'.
+            if len(request.GET) == 1 and request.GET.keys()[0] == 'data_dict':
+                request_data = request.GET.get('data_dict')
+
+            # Otherwise, the data_dict is flat, and can be constructed from the
+            # url parameters.
+            else:
+                return request.GET.mixed()
+
         else:
             try:
                 request_data = request.body
diff --git a/ckan/logic/__init__.py b/ckan/logic/__init__.py
index fa37d8a..d88e67c 100644
--- a/ckan/logic/__init__.py
+++ b/ckan/logic/__init__.py
@@ -1,4 +1,6 @@
 import logging
+import types
+
 from ckan.lib.base import _
 import ckan.authz
 from ckan.new_authz import is_authorized
@@ -206,6 +208,14 @@ def get_action(action):
         for k, v in module.__dict__.items():
             if not k.startswith('_'):
                 _actions[k] = v
+
+                # Whitelist all actions defined in logic/action/get.py as
+                # being side-effect free.
+                if isinstance(v, types.FunctionType):
+                    v.side_effect_free = action_module_name == 'get'
+                else:
+                    log.warning("Non-function type action: %s", k)
+
     # Then overwrite them with any specific ones in the plugins:
     resolved_action_plugins = {}
     fetched_actions = {}
diff --git a/ckan/tests/functional/api/test_api.py b/ckan/tests/functional/api/test_api.py
index 4bb17d1..62499d7 100644
--- a/ckan/tests/functional/api/test_api.py
+++ b/ckan/tests/functional/api/test_api.py
@@ -1,5 +1,10 @@
+import json
+
 from ckan.tests.functional.api.base import *
 
+import ckan.tests
+assert_in = ckan.tests.assert_in
+
 class ApiTestCase(ApiTestCase, ControllerTestCase): 
 
     def test_get_api(self):
@@ -13,6 +18,46 @@ def assert_version_data(self, res):
         expected_version = self.get_expected_api_version()
         self.assert_equal(data['version'], expected_version) 
 
+class TestApi3(Api3TestCase, ApiTestCase):
+
+    def test_readonly_is_get_able_with_normal_url_params(self):
+        '''Test that a read-only action is GET-able
+
+        Picks an action within `get.py` and checks that it works if it's
+        invoked with a http GET request.
+        '''
+        offset = self.offset('/action/package_search')
+        params = {'q': 'russian'}
+        res = self.app.get(offset, params=params, status=[200])
+
+    def test_readonly_is_get_able_with_json_param(self):
+        '''Test that a read-only action is GET-able
+
+        Picks an action within `get.py` and checks that it works if it's
+        invoked with a http GET request.
+        '''
+        offset = self.offset('/action/package_search')
+        data_dict = {'q': 'russian'}
+        params = {'data_dict': json.dumps(data_dict)}
+        res = self.app.get(offset, params=params, status=[200])
+
+    def test_sideeffect_action_is_not_get_able(self):
+        '''Test that a non-readonly action is not GET-able.
+
+        Picks an action outside of `get.py`, and checks that it 400s if an
+        attempt to invoke with a http GET request is made.
+        '''
+        offset = self.offset('/action/package_create')
+        data_dict = {
+            'type': 'dataset',
+            'name': 'a-name'
+        }
+        res = self.app.get(offset,
+                           params=data_dict,
+                           status=[400],
+                           expect_errors=True)
+        assert_in('Bad request - JSON Error: No request body data',
+                  res.body)
 
 # Tests for Version 1 of the API.
 class TestApi1(Api1TestCase, ApiTestCase): pass


================================================================
  Commit: d94f0108a3387ff439d525f0553a5152e6c038d1
      https://github.com/okfn/ckan/commit/d94f0108a3387ff439d525f0553a5152e6c038d1
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-03 (Thu, 03 May 2012)

  Changed paths:
    M ckan/logic/__init__.py
    M ckan/plugins/interfaces.py

  Log Message:
  -----------
  [2330] Created a decorator for marking actions as side-effect-free.

For use by users defining their own actions through the IActions interface.


diff --git a/ckan/logic/__init__.py b/ckan/logic/__init__.py
index d88e67c..18c7cd5 100644
--- a/ckan/logic/__init__.py
+++ b/ckan/logic/__init__.py
@@ -1,3 +1,4 @@
+import functools
 import logging
 import types
 
@@ -199,7 +200,7 @@ def get_action(action):
     # First get the default ones in the ckan/logic/action directory
     # 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 
+    # be an action
     for action_module_name in ['get', 'create', 'update','delete']:
         module_path = 'ckan.logic.action.'+action_module_name
         module = __import__(module_path)
@@ -261,3 +262,21 @@ def get_or_bust(data_dict, keys):
     if len(values) == 1:
         return values[0]
     return tuple(values)
+
+def side_effect_free(action):
+    '''A decorator that marks the given action as side-effect-free.
+
+    The consequence of which is that the action becomes available through a
+    GET request in the action API.
+
+    This decorator is for users defining their own actions through the IAction
+    interface, and they want to expose their action with a GET request as well
+    as the usual POST request.
+    '''
+
+    @functools.wraps(action)
+    def wrapper(context, data_dict):
+        return action(context, data_dict)
+    wrapper.side_effect_free = True
+
+    return wrapper
diff --git a/ckan/plugins/interfaces.py b/ckan/plugins/interfaces.py
index 4ca74f2..e8c066f 100644
--- a/ckan/plugins/interfaces.py
+++ b/ckan/plugins/interfaces.py
@@ -406,6 +406,10 @@ def get_actions(self):
         """
         Should return a dict, the keys being the name of the logic
         function and the values being the functions themselves.
+
+        By decorating a function with the `ckan.logic.side_effect_free`
+        decorator, the associated action will be made available by a GET
+        request (as well as the usual POST request) through the action API.
         """
 
 


================================================================
  Commit: fd49c456c75e7cabb9e9fc7a7591a07379996914
      https://github.com/okfn/ckan/commit/fd49c456c75e7cabb9e9fc7a7591a07379996914
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-03 (Thu, 03 May 2012)

  Changed paths:
    M ckan/logic/__init__.py

  Log Message:
  -----------
  [2330] Only load functions from the action module.

We were loading every public object in the module as an action.  Whilst not perfect, this at least
ensures that only functions are loaded, and not things like get.log


diff --git a/ckan/logic/__init__.py b/ckan/logic/__init__.py
index 18c7cd5..c4880d4 100644
--- a/ckan/logic/__init__.py
+++ b/ckan/logic/__init__.py
@@ -208,14 +208,14 @@ def get_action(action):
             module = getattr(module, part)
         for k, v in module.__dict__.items():
             if not k.startswith('_'):
-                _actions[k] = v
-
-                # Whitelist all actions defined in logic/action/get.py as
-                # being side-effect free.
+                # Only load functions from the action module.
                 if isinstance(v, types.FunctionType):
-                    v.side_effect_free = action_module_name == 'get'
-                else:
-                    log.warning("Non-function type action: %s", k)
+                    _actions[k] = v
+
+                    # Whitelist all actions defined in logic/action/get.py as
+                    # being side-effect free.
+                    v.side_effect_free = getattr(v, 'side_effect_free', True) and \
+                                         action_module_name == 'get'
 
     # Then overwrite them with any specific ones in the plugins:
     resolved_action_plugins = {}


================================================================
  Commit: 55d8ea418b94a9cedab3f95e4c50b929f2f527d1
      https://github.com/okfn/ckan/commit/55d8ea418b94a9cedab3f95e4c50b929f2f527d1
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-04 (Fri, 04 May 2012)

  Changed paths:
    M ckan/tests/functional/api/test_api.py

  Log Message:
  -----------
  [2330] Some comments


diff --git a/ckan/tests/functional/api/test_api.py b/ckan/tests/functional/api/test_api.py
index 62499d7..03aba7c 100644
--- a/ckan/tests/functional/api/test_api.py
+++ b/ckan/tests/functional/api/test_api.py
@@ -24,7 +24,8 @@ def test_readonly_is_get_able_with_normal_url_params(self):
         '''Test that a read-only action is GET-able
 
         Picks an action within `get.py` and checks that it works if it's
-        invoked with a http GET request.
+        invoked with a http GET request.  The action's data_dict is
+        populated from the url parameters.
         '''
         offset = self.offset('/action/package_search')
         params = {'q': 'russian'}
@@ -34,7 +35,8 @@ def test_readonly_is_get_able_with_json_param(self):
         '''Test that a read-only action is GET-able
 
         Picks an action within `get.py` and checks that it works if it's
-        invoked with a http GET request.
+        invoked with a http GET request.  The action's data_dict is constructed
+        from a json-encoded string in the 'data_dict' url parameter.
         '''
         offset = self.offset('/action/package_search')
         data_dict = {'q': 'russian'}


================================================================
  Commit: 3bd5b89b9a44372fe37e10edb67a6e7910ab141a
      https://github.com/okfn/ckan/commit/3bd5b89b9a44372fe37e10edb67a6e7910ab141a
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-04 (Fri, 04 May 2012)

  Changed paths:
    M ckan/logic/action/get.py

  Log Message:
  -----------
  [2330] Ensured that only action functions (in get.py) are turned into actions by the actin API

 - renamed functions not being exported by the module to have an underscore
   prefix, ensuring that they are then not exposed as actions in the action
   API.
 - fixed sqlalchemy imports


diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
index b2afe94..c2b23f9 100644
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -4,9 +4,7 @@
 from pylons import config
 from pylons.i18n import _
 import webhelpers.html
-from sqlalchemy.sql import select
-from sqlalchemy.orm import aliased
-from sqlalchemy import or_, and_, func, desc, case, text
+import sqlalchemy
 
 import ckan
 import ckan.authz
@@ -23,15 +21,26 @@
 
 log = logging.getLogger('ckan.logic')
 
-# define some shortcuts
-validate = ckan.lib.navl.dictization_functions.validate
-table_dictize = ckan.lib.dictization.table_dictize
-render = ckan.lib.base.render
+# Define some shortcuts
+# Ensure they are module-private so that they don't get loaded as available
+# actions in the action API.
+_validate = ckan.lib.navl.dictization_functions.validate
+_table_dictize = ckan.lib.dictization.table_dictize
+_render = ckan.lib.base.render
 Authorizer = ckan.authz.Authorizer
-check_access = logic.check_access
+_check_access = logic.check_access
 NotFound = logic.NotFound
 ValidationError = logic.ValidationError
-get_or_bust = logic.get_or_bust
+_get_or_bust = logic.get_or_bust
+
+_select = sqlalchemy.sql.select
+_aliased = sqlalchemy.orm.aliased
+_or_ = sqlalchemy.or_
+_and_ = sqlalchemy.and_
+_func = sqlalchemy.func
+_desc = sqlalchemy.desc
+_case = sqlalchemy.case
+_text = sqlalchemy.text
 
 def _package_list_with_resources(context, package_revision_list):
     package_list = []
@@ -42,7 +51,7 @@ def _package_list_with_resources(context, package_revision_list):
     return package_list
 
 def site_read(context,data_dict=None):
-    check_access('site_read',context,data_dict)
+    _check_access('site_read',context,data_dict)
     return True
 
 def package_list(context, data_dict):
@@ -53,7 +62,7 @@ def package_list(context, data_dict):
     api = context.get("api_version", 1)
     ref_package_by = 'id' if api == 2 else 'name'
 
-    check_access('package_list', context, data_dict)
+    _check_access('package_list', context, data_dict)
 
     query = model.Session.query(model.PackageRevision)
     query = query.filter(model.PackageRevision.state=='active')
@@ -68,7 +77,7 @@ def current_package_list_with_resources(context, data_dict):
     limit = data_dict.get("limit")
     page = int(data_dict.get('page', 1))
 
-    check_access('current_package_list_with_resources', context, data_dict)
+    _check_access('current_package_list_with_resources', context, data_dict)
 
     query = model.Session.query(model.PackageRevision)
     query = query.filter(model.PackageRevision.state=='active')
@@ -85,7 +94,7 @@ def revision_list(context, data_dict):
 
     model = context['model']
 
-    check_access('revision_list', context, data_dict)
+    _check_access('revision_list', context, data_dict)
 
     revs = model.Session.query(model.Revision).all()
     return [rev.id for rev in revs]
@@ -97,7 +106,7 @@ def package_revision_list(context, data_dict):
     if pkg is None:
         raise NotFound
 
-    check_access('package_revision_list',context, data_dict)
+    _check_access('package_revision_list',context, data_dict)
 
     revision_dicts = []
     for revision, object_revisions in pkg.all_related_revisions:
@@ -127,11 +136,11 @@ def related_show(context, data_dict=None):
     if related is None:
         raise NotFound
 
-    check_access('related_show',context, data_dict)
+    _check_access('related_show',context, data_dict)
 
     schema = context.get('schema') or ckan.logic.schema.default_related_schema()
     related_dict = model_dictize.related_dictize(related, context)
-    related_dict, errors = validate(related_dict, schema, context=context)
+    related_dict, errors = _validate(related_dict, schema, context=context)
 
     return related_dict
 
@@ -161,7 +170,7 @@ def related_list(context, data_dict=None):
     if not dataset:
         raise NotFound
 
-    check_access('related_show',context, data_dict)
+    _check_access('related_show',context, data_dict)
 
     relateds = model.Related.get_for_dataset(dataset, status='active')
     related_items = (r.related for r in relateds)
@@ -193,7 +202,7 @@ def member_list(context, data_dict=None):
     capacity = data_dict.get('capacity', None)
 
     # User must be able to update the group to remove a member from it
-    check_access('group_show', context, data_dict)
+    _check_access('group_show', context, data_dict)
 
     q = model.Session.query(model.Member).\
             filter(model.Member.group_id == group.id).\
@@ -228,7 +237,7 @@ def group_list(context, data_dict):
         raise logic.ParameterError('"order_by" value %r not implemented.' % order_by)
     all_fields = data_dict.get('all_fields',None)
 
-    check_access('group_list',context, data_dict)
+    _check_access('group_list',context, data_dict)
 
     query = model.Session.query(model.Group).join(model.GroupRevision)
     query = query.filter(model.GroupRevision.state=='active')
@@ -261,7 +270,7 @@ def group_list_authz(context, data_dict):
     user = context['user']
     available_only = data_dict.get('available_only',False)
 
-    check_access('group_list_authz',context, data_dict)
+    _check_access('group_list_authz',context, data_dict)
 
     query = Authorizer().authorized_query(user, model.Group, model.Action.EDIT)
     groups = set(query.all())
@@ -280,7 +289,7 @@ def group_revision_list(context, data_dict):
     if group is None:
         raise NotFound
 
-    check_access('group_revision_list',context, data_dict)
+    _check_access('group_revision_list',context, data_dict)
 
     revision_dicts = []
     for revision, object_revisions in group.all_related_revisions:
@@ -292,7 +301,7 @@ def group_revision_list(context, data_dict):
 def licence_list(context, data_dict):
     model = context["model"]
 
-    check_access('licence_list',context, data_dict)
+    _check_access('licence_list',context, data_dict)
 
     license_register = model.Package.get_license_register()
     licenses = license_register.values()
@@ -319,7 +328,7 @@ def tag_list(context, data_dict):
         query = query.strip()
     all_fields = data_dict.get('all_fields', None)
 
-    check_access('tag_list', context, data_dict)
+    _check_access('tag_list', context, data_dict)
 
     if query:
         tags = _tag_search(context, data_dict)
@@ -342,7 +351,7 @@ def user_list(context, data_dict):
     model = context['model']
     user = context['user']
 
-    check_access('user_list',context, data_dict)
+    _check_access('user_list',context, data_dict)
 
     q = data_dict.get('q','')
     order_by = data_dict.get('order_by','name')
@@ -354,12 +363,12 @@ def user_list(context, data_dict):
         model.User.about.label('about'),
         model.User.about.label('email'),
         model.User.created.label('created'),
-        select([func.count(model.Revision.id)], or_(
+        _select([_func.count(model.Revision.id)], _or_(
                 model.Revision.author==model.User.name,
                 model.Revision.author==model.User.openid
                 )
         ).label('number_of_edits'),
-        select([func.count(model.UserObjectRole.id)], and_(
+        _select([_func.count(model.UserObjectRole.id)], _and_(
             model.UserObjectRole.user_id==model.User.id,
             model.UserObjectRole.context=='Package',
             model.UserObjectRole.role=='admin'
@@ -371,15 +380,15 @@ def user_list(context, data_dict):
         query = model.User.search(q, query)
 
     if order_by == 'edits':
-        query = query.order_by(desc(
-            select([func.count(model.Revision.id)], or_(
+        query = query.order_by(_desc(
+            _select([_func.count(model.Revision.id)], _or_(
                 model.Revision.author==model.User.name,
                 model.Revision.author==model.User.openid
                 ))
         ))
     else:
         query = query.order_by(
-            case([(or_(model.User.fullname == None, model.User.fullname == ''),
+            _case([(_or_(model.User.fullname == None, model.User.fullname == ''),
                    model.User.name)],
                  else_=model.User.fullname)
         )
@@ -420,7 +429,7 @@ def package_relationships_list(context, data_dict):
     if rel == 'relationships':
         rel = None
 
-    check_access('package_relationships_list',context, data_dict)
+    _check_access('package_relationships_list',context, data_dict)
 
     # TODO: How to handle this object level authz?
     relationships = Authorizer().\
@@ -449,7 +458,7 @@ def package_show(context, data_dict):
 
     context['package'] = pkg
 
-    check_access('package_show', context, data_dict)
+    _check_access('package_show', context, data_dict)
 
     package_dict = model_dictize.package_dictize(pkg, context)
 
@@ -466,7 +475,7 @@ def package_show(context, data_dict):
         schema = package_plugin.db_to_form_schema()
 
     if schema and context.get('validate', True):
-        package_dict, errors = validate(package_dict, schema, context=context)
+        package_dict, errors = _validate(package_dict, schema, context=context)
 
     return package_dict
 
@@ -480,24 +489,24 @@ def resource_show(context, data_dict):
     if not resource:
         raise NotFound
 
-    check_access('resource_show', context, data_dict)
+    _check_access('resource_show', context, data_dict)
     return model_dictize.resource_dictize(resource, context)
 
 def resource_status_show(context, data_dict):
 
     model = context['model']
-    id = get_or_bust(data_dict, 'id')
+    id = _get_or_bust(data_dict, 'id')
 
-    check_access('resource_status_show', context, data_dict)
+    _check_access('resource_status_show', context, data_dict)
 
     # needs to be text query as celery tables are not in our model
-    q = text("""select status, date_done, traceback, task_status.*
+    q = _text("""select status, date_done, traceback, task_status.*
                 from task_status left join celery_taskmeta
                 on task_status.value = celery_taskmeta.task_id and key = 'celery_task_id'
                 where entity_id = :entity_id """)
 
     result = model.Session.connection().execute(q, entity_id=id)
-    result_list = [table_dictize(row, context) for row in result]
+    result_list = [_table_dictize(row, context) for row in result]
 
     return result_list
 
@@ -526,7 +535,7 @@ def group_show(context, data_dict):
     if group is None:
         raise NotFound
 
-    check_access('group_show',context, data_dict)
+    _check_access('group_show',context, data_dict)
 
     group_dict = model_dictize.group_dictize(group, context)
 
@@ -543,7 +552,7 @@ def group_show(context, data_dict):
         schema = group_plugin.db_to_form_schema()
 
     if schema:
-        package_dict, errors = validate(group_dict, schema, context=context)
+        package_dict, errors = _validate(group_dict, schema, context=context)
 
     return group_dict
 
@@ -561,7 +570,7 @@ def group_package_show(context, data_dict):
     if group is None:
         raise NotFound
 
-    check_access('group_show', context, data_dict)
+    _check_access('group_show', context, data_dict)
 
     query = model.Session.query(model.PackageRevision)\
         .filter(model.PackageRevision.state=='active')\
@@ -595,7 +604,7 @@ def tag_show(context, data_dict):
     if tag is None:
         raise NotFound
 
-    check_access('tag_show',context, data_dict)
+    _check_access('tag_show',context, data_dict)
 
     tag_dict = model_dictize.tag_dictize(tag,context)
 
@@ -625,7 +634,7 @@ def user_show(context, data_dict):
     else:
         raise NotFound
 
-    check_access('user_show',context, data_dict)
+    _check_access('user_show',context, data_dict)
 
     user_dict = model_dictize.user_dictize(user_obj,context)
 
@@ -660,7 +669,7 @@ def user_show(context, data_dict):
 
 def package_show_rest(context, data_dict):
 
-    check_access('package_show_rest',context, data_dict)
+    _check_access('package_show_rest',context, data_dict)
 
     logic.get_action('package_show')(context, data_dict)
 
@@ -672,7 +681,7 @@ def package_show_rest(context, data_dict):
 
 def group_show_rest(context, data_dict):
 
-    check_access('group_show_rest',context, data_dict)
+    _check_access('group_show_rest',context, data_dict)
 
     logic.get_action('group_show')(context, data_dict)
     group = context['group']
@@ -683,7 +692,7 @@ def group_show_rest(context, data_dict):
 
 def tag_show_rest(context, data_dict):
 
-    check_access('tag_show_rest',context, data_dict)
+    _check_access('tag_show_rest',context, data_dict)
 
     logic.get_action('tag_show')(context, data_dict)
     tag = context['tag']
@@ -703,12 +712,12 @@ def package_autocomplete(context, data_dict):
 
     like_q = u"%s%%" % q
 
-    check_access('package_autocomplete', context, data_dict)
+    _check_access('package_autocomplete', context, data_dict)
 
     query = model.Session.query(model.PackageRevision)
     query = query.filter(model.PackageRevision.state=='active')
     query = query.filter(model.PackageRevision.current==True)
-    query = query.filter(or_(model.PackageRevision.name.ilike(like_q),
+    query = query.filter(_or_(model.PackageRevision.name.ilike(like_q),
                                 model.PackageRevision.title.ilike(like_q)))
     query = query.limit(10)
 
@@ -733,7 +742,7 @@ def format_autocomplete(context, data_dict):
     session = context['session']
     user = context['user']
 
-    check_access('format_autocomplete', context, data_dict)
+    _check_access('format_autocomplete', context, data_dict)
 
     q = data_dict.get('q', None)
     if not q:
@@ -743,8 +752,8 @@ def format_autocomplete(context, data_dict):
     like_q = u'%' + q + u'%'
 
     query = session.query(model.ResourceRevision.format,
-        func.count(model.ResourceRevision.format).label('total'))\
-        .filter(and_(
+        _func.count(model.ResourceRevision.format).label('total'))\
+        .filter(_and_(
             model.ResourceRevision.state == 'active',
             model.ResourceRevision.current == True
         ))\
@@ -764,7 +773,7 @@ def user_autocomplete(context, data_dict):
     if not q:
         return []
 
-    check_access('user_autocomplete', context, data_dict)
+    _check_access('user_autocomplete', context, data_dict)
 
     limit = data_dict.get('limit',20)
 
@@ -785,7 +794,7 @@ def package_search(context, data_dict):
     session = context['session']
     user = context['user']
 
-    check_access('package_search', context, data_dict)
+    _check_access('package_search', context, data_dict)
 
     # check if some extension needs to modify the search params
     for item in plugins.PluginImplementations(plugins.IPackageController):
@@ -807,7 +816,7 @@ def package_search(context, data_dict):
             # get the package object
             pkg_query = session.query(model.PackageRevision)\
                 .filter(model.PackageRevision.id == package)\
-                .filter(and_(
+                .filter(_and_(
                     model.PackageRevision.state == u'active',
                     model.PackageRevision.current == True
                 ))
@@ -895,7 +904,7 @@ def resource_search(context, data_dict):
             elif field in model.Resource.get_extra_columns():
                 model_attr = getattr(model.Resource, 'extras')
 
-                like = or_(
+                like = _or_(
                     model_attr.ilike(u'''%%"%s": "%%%s%%",%%''' % (field, term)),
                     model_attr.ilike(u'''%%"%s": "%%%s%%"}''' % (field, term))
                 )
@@ -990,7 +999,7 @@ def tag_search(context, data_dict):
     '''
     tags = _tag_search(context, data_dict)
     return {'count': len(tags),
-            'results': [table_dictize(tag, context) for tag in tags]}
+            'results': [_table_dictize(tag, context) for tag in tags]}
 
 def tag_autocomplete(context, data_dict):
     '''Return a list of tag names that contain the given string.
@@ -1003,7 +1012,7 @@ def tag_autocomplete(context, data_dict):
     belonging to the given vocabulary (id or name) will be searched instead.
 
     '''
-    check_access('tag_autocomplete', context, data_dict)
+    _check_access('tag_autocomplete', context, data_dict)
     matching_tags = _tag_search(context, data_dict)
     if matching_tags:
         return [tag.name for tag in matching_tags]
@@ -1018,7 +1027,7 @@ def task_status_show(context, data_dict):
         task_status = model.TaskStatus.get(id)
     else:
         query = model.Session.query(model.TaskStatus)\
-            .filter(and_(
+            .filter(_and_(
                 model.TaskStatus.entity_id == data_dict['entity_id'],
                 model.TaskStatus.task_type == data_dict['task_type'],
                 model.TaskStatus.key == data_dict['key']
@@ -1030,7 +1039,7 @@ def task_status_show(context, data_dict):
     if task_status is None:
         raise NotFound
 
-    check_access('task_status_show', context, data_dict)
+    _check_access('task_status_show', context, data_dict)
 
     task_status_dict = model_dictize.task_status_dictize(task_status, context)
     return task_status_dict
@@ -1041,7 +1050,7 @@ def term_translation_show(context, data_dict):
 
     trans_table = model.term_translation_table
 
-    q = select([trans_table])
+    q = _select([trans_table])
 
     if 'terms' not in data_dict:
         raise ValidationError({'terms': 'terms not in data'})
@@ -1057,12 +1066,12 @@ def term_translation_show(context, data_dict):
     results = []
 
     for row in cursor:
-        results.append(table_dictize(row, context))
+        results.append(_table_dictize(row, context))
 
     return results
 
 def get_site_user(context, data_dict):
-    check_access('get_site_user', context, data_dict)
+    _check_access('get_site_user', context, data_dict)
     model = context['model']
     site_id = config.get('ckan.site_id', 'ckan_site_user')
     user = model.User.get(site_id)
@@ -1117,13 +1126,13 @@ def roles_show(context, data_dict):
         if not authgroup:
             raise NotFound('unknown authorization group:' + repr(authgroup_ref))
         # we need an alias as we join to model.AuthorizationGroup table twice
-        ag = aliased(model.AuthorizationGroup)
+        ag = _aliased(model.AuthorizationGroup)
         query = query.join(ag, model.AuthorizationGroupRole.authorized_group) \
                 .filter_by(id=authgroup.id)
 
     uors = query.all()
 
-    uors_dictized = [table_dictize(uor, context) for uor in uors]
+    uors_dictized = [_table_dictize(uor, context) for uor in uors]
 
     result = {'domain_object_type': type(domain_object).__name__,
               'domain_object_id': domain_object.id,
@@ -1169,7 +1178,7 @@ def user_activity_list(context, data_dict):
     user_id = data_dict['id']
     query = model.Session.query(model.Activity)
     query = query.filter_by(user_id=user_id)
-    query = query.order_by(desc(model.Activity.timestamp))
+    query = query.order_by(_desc(model.Activity.timestamp))
     query = query.limit(15)
     activity_objects = query.all()
     return model_dictize.activity_list_dictize(activity_objects, context)
@@ -1180,7 +1189,7 @@ def package_activity_list(context, data_dict):
     package_id = data_dict['id']
     query = model.Session.query(model.Activity)
     query = query.filter_by(object_id=package_id)
-    query = query.order_by(desc(model.Activity.timestamp))
+    query = query.order_by(_desc(model.Activity.timestamp))
     query = query.limit(15)
     activity_objects = query.all()
     return model_dictize.activity_list_dictize(activity_objects, context)
@@ -1191,7 +1200,7 @@ def group_activity_list(context, data_dict):
     group_id = data_dict['id']
     query = model.Session.query(model.Activity)
     query = query.filter_by(object_id=group_id)
-    query = query.order_by(desc(model.Activity.timestamp))
+    query = query.order_by(_desc(model.Activity.timestamp))
     query = query.limit(15)
     activity_objects = query.all()
     return model_dictize.activity_list_dictize(activity_objects, context)
@@ -1204,7 +1213,7 @@ def recently_changed_packages_activity_list(context, data_dict):
     model = context['model']
     query = model.Session.query(model.Activity)
     query = query.filter(model.Activity.activity_type.endswith('package'))
-    query = query.order_by(desc(model.Activity.timestamp))
+    query = query.order_by(_desc(model.Activity.timestamp))
     query = query.limit(15)
     activity_objects = query.all()
     return model_dictize.activity_list_dictize(activity_objects, context)
@@ -1219,43 +1228,43 @@ def activity_detail_list(context, data_dict):
     return model_dictize.activity_detail_list_dictize(activity_detail_objects, context)
 
 def render_new_package_activity(context, activity):
-    return render('activity_streams/new_package.html',
+    return _render('activity_streams/new_package.html',
         extra_vars = {'activity': activity})
 
 def render_deleted_package_activity(context, activity):
-    return render('activity_streams/deleted_package.html',
+    return _render('activity_streams/deleted_package.html',
         extra_vars = {'activity': activity})
 
 def render_new_resource_activity(context, activity, detail):
-    return render('activity_streams/new_resource.html',
+    return _render('activity_streams/new_resource.html',
         extra_vars = {'activity': activity, 'detail': detail})
 
 def render_changed_resource_activity(context, activity, detail):
-    return render('activity_streams/changed_resource.html',
+    return _render('activity_streams/changed_resource.html',
         extra_vars = {'activity': activity, 'detail': detail})
 
 def render_deleted_resource_activity(context, activity, detail):
-    return render('activity_streams/deleted_resource.html',
+    return _render('activity_streams/deleted_resource.html',
         extra_vars = {'activity': activity, 'detail': detail})
 
 def render_added_tag_activity(context, activity, detail):
-    return render('activity_streams/added_tag.html',
+    return _render('activity_streams/added_tag.html',
             extra_vars = {'activity': activity, 'detail': detail})
 
 def render_removed_tag_activity(context, activity, detail):
-    return render('activity_streams/removed_tag.html',
+    return _render('activity_streams/removed_tag.html',
             extra_vars = {'activity': activity, 'detail': detail})
 
 def render_new_package_extra_activity(context, activity, detail):
-    return render('activity_streams/new_package_extra.html',
+    return _render('activity_streams/new_package_extra.html',
         extra_vars = {'activity': activity, 'detail': detail})
 
 def render_changed_package_extra_activity(context, activity, detail):
-    return render('activity_streams/changed_package_extra.html',
+    return _render('activity_streams/changed_package_extra.html',
         extra_vars = {'activity': activity, 'detail': detail})
 
 def render_deleted_package_extra_activity(context, activity, detail):
-    return render('activity_streams/deleted_package_extra.html',
+    return _render('activity_streams/deleted_package_extra.html',
         extra_vars = {'activity': activity, 'detail': detail})
 
 def render_changed_package_activity(context, activity):
@@ -1290,27 +1299,27 @@ def render_changed_package_activity(context, activity):
                 renderer = activity_detail_renderers[object_type][activity_type]
                 return renderer(context, activity, detail)
 
-    return render('activity_streams/changed_package.html',
+    return _render('activity_streams/changed_package.html',
         extra_vars = {'activity': activity})
 
 def render_new_user_activity(context, activity):
-    return render('activity_streams/new_user.html',
+    return _render('activity_streams/new_user.html',
         extra_vars = {'activity': activity})
 
 def render_changed_user_activity(context, activity):
-    return render('activity_streams/changed_user.html',
+    return _render('activity_streams/changed_user.html',
         extra_vars = {'activity': activity})
 
 def render_new_group_activity(context, activity):
-    return render('activity_streams/new_group.html',
+    return _render('activity_streams/new_group.html',
         extra_vars = {'activity': activity})
 
 def render_changed_group_activity(context, activity):
-    return render('activity_streams/changed_group.html',
+    return _render('activity_streams/changed_group.html',
         extra_vars = {'activity': activity})
 
 def render_deleted_group_activity(context, activity):
-    return render('activity_streams/deleted_group.html',
+    return _render('activity_streams/deleted_group.html',
         extra_vars = {'activity': activity})
 
 # Global dictionary mapping activity types to functions that render activity


================================================================
  Commit: c4a0d488302bb6d5083c479ffd0b18f85c20ae07
      https://github.com/okfn/ckan/commit/c4a0d488302bb6d5083c479ffd0b18f85c20ae07
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-04 (Fri, 04 May 2012)

  Changed paths:
    M doc/apiv3.rst

  Log Message:
  -----------
  [2330] Docs


diff --git a/doc/apiv3.rst b/doc/apiv3.rst
index 45c492d..d93fe2d 100644
--- a/doc/apiv3.rst
+++ b/doc/apiv3.rst
@@ -30,6 +30,10 @@ The Action API is a powerful RPC-style way of accessing CKAN data. Its intention
 
 A client supplies parameters to the Action API via a JSON dictionary of a POST request, and returns results, help information and any error diagnostics in a JSON dictionary too. This is a departure from the CKAN API versions 1 and 2, which being RESTful required all the request parameters to be part of the URL.
 
+In addition to the above, any of the actions defined in
+`ckan/logic/action/get.py` can be accessed with a GET request to the same URI
+endpoint.  See below for examples.
+
 Requests
 --------
 
@@ -269,14 +273,40 @@ lang_code        "de"                      The language of the translation, a la
 Parameters
 ==========
 
-Requests must be a POST, including parameters in a JSON dictionary. If there are no parameters required, then an empty dictionary is still required (or you get a 400 error).
+All actions accept POST request including parameters in a JSON dictionary. If there are no parameters required, then an empty dictionary is still required (or you get a 400 error).
 
 Examples::
 
  curl http://test.ckan.net/api/action/package_list -d '{}'
  curl http://test.ckan.net/api/action/package_show -d '{"id": "fd788e57-dce4-481c-832d-497235bf9f78"}'
 
+GET-able Actions
+----------------
+
+Actions defined in get.py can also be accessed with a GET request **in
+addition** to the POST method described just above.  There are two ways of
+passing the required arguments to the GET-able action.
+
+Firstly, each parameter can be specified as a url parameter, for example: ::
+
+ curl http://test.ckan.net/api/3/action/package_search?q=police
+
+Alternatively, the action's parameters can be JSON-encoded in a dictionary, and
+passed in with a single ``data_dict`` url parameter.  For example: ::
+
+ curl http://ian-laptop:5000/api/3/action/package_search?data_dict=%7B%22q%22%3A+%22police%22%7D
+
+or, perhaps more clearly, in python: ::
+
+ import requests
+ import json
+
+ url = 'http://test.ckan.net/api/3/action/package_search'
+ search_params = {'q': 'police'}
+ requests.get(url, params={'data_dict': json.dumps(search_params)})
 
+The second, slightly less convenient, method of passing the action's parameters
+is to allow a more complex data_dict to be passed, eg. a nested dict.
 
 Responses
 =========


================================================================
  Commit: 52e1c1eb46b7da5a5ec761f560e6e9f5bd74a0eb
      https://github.com/okfn/ckan/commit/52e1c1eb46b7da5a5ec761f560e6e9f5bd74a0eb
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-04 (Fri, 04 May 2012)

  Changed paths:
    M ckan/logic/action/create.py
    M ckan/logic/action/delete.py
    M ckan/logic/action/get.py
    M ckan/logic/action/update.py

  Log Message:
  -----------
  [2330] Use get_or_bust in the actions layer.

This function raises a ValidationError if the key doesn't exist in the given
(data_)dict.  This means better error messages for the user.


diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py
index aee73a3..debdd95 100644
--- a/ckan/logic/action/create.py
+++ b/ckan/logic/action/create.py
@@ -24,6 +24,7 @@
 get_action = logic.get_action
 ValidationError = logic.ValidationError
 NotFound = logic.NotFound
+_get_or_bust = logic.get_or_bust
 
 def package_create(context, data_dict):
 
@@ -149,9 +150,7 @@ def package_relationship_create(context, data_dict):
     api = context.get('api_version')
     ref_package_by = 'id' if api == 2 else 'name'
 
-    id = data_dict['subject']
-    id2 = data_dict['object']
-    rel_type = data_dict['type']
+    id, id2, rel_type = _get_or_bust(data_dict, ['subject', 'object', 'type'])
     comment = data_dict.get('comment', u'')
 
     pkg1 = model.Package.get(id)
@@ -213,9 +212,7 @@ def member_create(context, data_dict=None):
     else:
         rev.message = _(u'REST API: Create member object %s') % data_dict.get("name", "")
 
-    obj_id   = data_dict['object']
-    obj_type = data_dict['object_type']
-    capacity = data_dict['capacity']
+    obj_id, obj_type, capacity = _get_or_bust(data_dict, ['object', 'object_type', 'capacity'])
 
     # User must be able to update the group to add a member to it
     check_access('group_update', context, data_dict)
diff --git a/ckan/logic/action/delete.py b/ckan/logic/action/delete.py
index c806a51..ecfe6f7 100644
--- a/ckan/logic/action/delete.py
+++ b/ckan/logic/action/delete.py
@@ -8,12 +8,13 @@
 ValidationError = ckan.logic.ValidationError
 NotFound = ckan.logic.NotFound
 check_access = ckan.logic.check_access
+_get_or_bust = ckan.logic.get_or_bust
 
 def package_delete(context, data_dict):
 
     model = context['model']
     user = context['user']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     entity = model.Package.get(id)
 
@@ -36,9 +37,7 @@ def package_relationship_delete(context, data_dict):
 
     model = context['model']
     user = context['user']
-    id = data_dict['subject']
-    id2 = data_dict['object']
-    rel = data_dict['type']
+    id, id2, rel = _get_or_bust(data_dict, ['subject', 'object', 'type'])
 
     pkg1 = model.Package.get(id)
     pkg2 = model.Package.get(id2)
@@ -67,7 +66,7 @@ def package_relationship_delete(context, data_dict):
 def related_delete(context, data_dict):
     model = context['model']
     user = context['user']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     entity = model.Related.get(id)
 
@@ -99,9 +98,8 @@ def member_delete(context, data_dict=None):
     user = context['user']
     group = context['group']
 
-    group_id = data_dict['group']
-    obj_id   = data_dict['object']
-    obj_type = data_dict['object_type']
+    group_id, obj_id, obj_type = _get_or_bust(data_dict,
+                                              ['group', 'object', 'object_type'])
 
     # User must be able to update the group to remove a member from it
     check_access('group_update', context, data_dict)
@@ -119,7 +117,7 @@ def group_delete(context, data_dict):
 
     model = context['model']
     user = context['user']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     group = model.Group.get(id)
     context['group'] = group
@@ -143,7 +141,7 @@ def group_delete(context, data_dict):
 def task_status_delete(context, data_dict):
     model = context['model']
     user = context['user']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
     model.Session.remove()
     model.Session()._context = context
 
@@ -178,7 +176,7 @@ def tag_delete(context, data_dict):
 
     if not data_dict.has_key('id') or not data_dict['id']:
         raise ValidationError({'id': _('id not in data')})
-    tag_id_or_name = data_dict['id']
+    tag_id_or_name = _get_or_bust(data_dict, 'id')
 
     vocab_id_or_name = data_dict.get('vocabulary_id')
 
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
index c2b23f9..b046fc3 100644
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -101,7 +101,7 @@ def revision_list(context, data_dict):
 
 def package_revision_list(context, data_dict):
     model = context["model"]
-    id = data_dict["id"]
+    id = _get_or_bust(data_dict, "id")
     pkg = model.Package.get(id)
     if pkg is None:
         raise NotFound
@@ -128,7 +128,7 @@ def related_show(context, data_dict=None):
         id - The ID of the related item we want to show
     """
     model = context['model']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     related = model.Related.get(id)
     context['related'] = related
@@ -197,7 +197,7 @@ def member_list(context, data_dict=None):
     user = context['user']
     group = context['group']
 
-    group_id = data_dict['group']
+    group_id = _get_or_bust(data_dict, 'group')
     obj_type = data_dict.get('object_type', None)
     capacity = data_dict.get('capacity', None)
 
@@ -284,7 +284,7 @@ def group_list_authz(context, data_dict):
 
 def group_revision_list(context, data_dict):
     model = context['model']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
     group = model.Group.get(id)
     if group is None:
         raise NotFound
@@ -413,7 +413,7 @@ def package_relationships_list(context, data_dict):
     user = context['user']
     api = context.get('api_version')
 
-    id = data_dict["id"]
+    id = _get_or_bust(data_dict, "id")
     id2 = data_dict.get("id2")
     rel = data_dict.get("rel")
     ref_package_by = 'id' if api == 2 else 'name';
@@ -449,7 +449,7 @@ def package_show(context, data_dict):
 
     model = context['model']
     context['session'] = model.Session
-    name_or_id = data_dict.get("id") or data_dict['name_or_id']
+    name_or_id = data_dict.get("id") or _get_or_bust(data_dict, 'name_or_id')
 
     pkg = model.Package.get(name_or_id)
 
@@ -481,7 +481,7 @@ def package_show(context, data_dict):
 
 def resource_show(context, data_dict):
     model = context['model']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     resource = model.Resource.get(id)
     context['resource'] = resource
@@ -514,7 +514,7 @@ def resource_status_show(context, data_dict):
 def revision_show(context, data_dict):
     model = context['model']
     api = context.get('api_version')
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
     ref_package_by = 'id' if api == 2 else 'name'
 
     rev = model.Session.query(model.Revision).get(id)
@@ -527,7 +527,7 @@ def revision_show(context, data_dict):
 def group_show(context, data_dict):
     '''Shows group details'''
     model = context['model']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     group = model.Group.get(id)
     context['group'] = group
@@ -562,7 +562,7 @@ def group_package_show(context, data_dict):
     """
     model = context["model"]
     user = context["user"]
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
     limit = data_dict.get("limit")
 
     group = model.Group.get(id)
@@ -596,7 +596,7 @@ def tag_show(context, data_dict):
     '''Shows tag details'''
 
     model = context['model']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     tag = model.Tag.get(id)
     context['tag'] = tag
@@ -708,7 +708,7 @@ def package_autocomplete(context, data_dict):
     model = context['model']
     session = context['session']
     user = context['user']
-    q = data_dict['q']
+    q = _get_or_bust(data_dict, 'q')
 
     like_q = u"%s%%" % q
 
@@ -883,7 +883,7 @@ def resource_search(context, data_dict):
     model = context['model']
     session = context['session']
 
-    fields = data_dict['fields']
+    fields = _get_or_bust(data_dict, 'fields')
     order_by = data_dict.get('order_by')
     offset = data_dict.get('offset')
     limit = data_dict.get('limit')
@@ -957,7 +957,7 @@ def _tag_search(context, data_dict):
 
     if data_dict.has_key('vocabulary_id'):
         # Filter by vocabulary.
-        vocab = model.Vocabulary.get(data_dict['vocabulary_id'])
+        vocab = model.Vocabulary.get(_get_or_bust(data_dict, 'vocabulary_id'))
         if not vocab:
             raise NotFound
         q = q.filter(model.Tag.vocabulary_id == vocab.id)
@@ -1028,9 +1028,9 @@ def task_status_show(context, data_dict):
     else:
         query = model.Session.query(model.TaskStatus)\
             .filter(_and_(
-                model.TaskStatus.entity_id == data_dict['entity_id'],
-                model.TaskStatus.task_type == data_dict['task_type'],
-                model.TaskStatus.key == data_dict['key']
+                model.TaskStatus.entity_id == _get_or_bust(data_dict, 'entity_id'),
+                model.TaskStatus.task_type == _get_or_bust(data_dict, 'task_type'),
+                model.TaskStatus.key == _get_or_bust(data_dict, 'key')
             ))
         task_status = query.first()
 
@@ -1055,10 +1055,10 @@ def term_translation_show(context, data_dict):
     if 'terms' not in data_dict:
         raise ValidationError({'terms': 'terms not in data'})
 
-    q = q.where(trans_table.c.term.in_(data_dict['terms']))
+    q = q.where(trans_table.c.term.in_(_get_or_bust(data_dict, 'terms')))
 
     if 'lang_codes' in data_dict:
-        q = q.where(trans_table.c.lang_code.in_(data_dict['lang_codes']))
+        q = q.where(trans_table.c.lang_code.in_(_get_or_bust(data_dict, 'lang_codes')))
 
     conn = model.Session.connection()
     cursor = conn.execute(q)
@@ -1099,7 +1099,7 @@ def roles_show(context, data_dict):
     '''
     model = context['model']
     session = context['session']
-    domain_object_ref = data_dict['domain_object']
+    domain_object_ref = _get_or_bust(data_dict, 'domain_object')
     user_ref = data_dict.get('user')
     authgroup_ref = data_dict.get('authorization_group')
 
@@ -1175,7 +1175,7 @@ def vocabulary_show(context, data_dict):
 def user_activity_list(context, data_dict):
     '''Return a user\'s public activity stream as a list of dicts.'''
     model = context['model']
-    user_id = data_dict['id']
+    user_id = _get_or_bust(data_dict, 'id')
     query = model.Session.query(model.Activity)
     query = query.filter_by(user_id=user_id)
     query = query.order_by(_desc(model.Activity.timestamp))
@@ -1186,7 +1186,7 @@ def user_activity_list(context, data_dict):
 def package_activity_list(context, data_dict):
     '''Return a package\'s public activity stream as a list of dicts.'''
     model = context['model']
-    package_id = data_dict['id']
+    package_id = _get_or_bust(data_dict, 'id')
     query = model.Session.query(model.Activity)
     query = query.filter_by(object_id=package_id)
     query = query.order_by(_desc(model.Activity.timestamp))
@@ -1197,7 +1197,7 @@ def package_activity_list(context, data_dict):
 def group_activity_list(context, data_dict):
     '''Return a group\'s public activity stream as a list of dicts.'''
     model = context['model']
-    group_id = data_dict['id']
+    group_id = _get_or_bust(data_dict, 'id')
     query = model.Session.query(model.Activity)
     query = query.filter_by(object_id=group_id)
     query = query.order_by(_desc(model.Activity.timestamp))
@@ -1222,7 +1222,7 @@ def activity_detail_list(context, data_dict):
     '''Return an activity\'s list of activity detail items, as a list of dicts.
     '''
     model = context['model']
-    activity_id = data_dict['id']
+    activity_id = _get_or_bust(data_dict, 'id')
     activity_detail_objects = model.Session.query(
         model.activity.ActivityDetail).filter_by(activity_id=activity_id).all()
     return model_dictize.activity_detail_list_dictize(activity_detail_objects, context)
diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py
index cd5aa2f..b0e42dc 100644
--- a/ckan/logic/action/update.py
+++ b/ckan/logic/action/update.py
@@ -23,6 +23,7 @@
 check_access = logic.check_access
 NotFound = logic.NotFound
 ValidationError = logic.ValidationError
+_get_or_bust = logic.get_or_bust
 
 def _make_latest_rev_active(context, q):
 
@@ -60,7 +61,7 @@ def make_latest_pending_package_active(context, data_dict):
     model = context['model']
     session = model.Session
     SQLAlchemySession.setattr(session, 'revisioning_disabled', True)
-    id = data_dict["id"]
+    id = _get_or_bust(data_dict, "id")
     pkg = model.Package.get(id)
 
     check_access('make_latest_pending_package_active', context, data_dict)
@@ -101,7 +102,7 @@ def make_latest_pending_package_active(context, data_dict):
 def related_update(context, data_dict):
     model = context['model']
     user = context['user']
-    id = data_dict["id"]
+    id = _get_or_bust(data_dict, "id")
 
     schema = context.get('schema') or ckan.logic.schema.default_related_schema()
     model.Session.remove()
@@ -130,7 +131,7 @@ def related_update(context, data_dict):
 def resource_update(context, data_dict):
     model = context['model']
     user = context['user']
-    id = data_dict["id"]
+    id = _get_or_bust(data_dict, "id")
     schema = context.get('schema') or ckan.logic.schema.default_update_resource_schema()
     model.Session.remove()
 
@@ -221,7 +222,7 @@ def package_update_validate(context, data_dict):
     model = context['model']
     user = context['user']
 
-    id = data_dict["id"]
+    id = _get_or_bust(data_dict, "id")
     model.Session.remove()
     model.Session()._context = context
 
@@ -275,9 +276,7 @@ def package_relationship_update(context, data_dict):
     user = context['user']
     schema = context.get('schema') or ckan.logic.schema.default_update_relationship_schema()
 
-    id = data_dict['subject']
-    id2 = data_dict['object']
-    rel = data_dict['type']
+    id, id2, rel = _get_or_bust(data_dict, ['subject', 'object', 'type'])
 
     pkg1 = model.Package.get(id)
     pkg2 = model.Package.get(id2)
@@ -306,7 +305,7 @@ def group_update(context, data_dict):
     model = context['model']
     user = context['user']
     session = context['session']
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
     parent = context.get('parent', None)
 
     group = model.Group.get(id)
@@ -402,7 +401,7 @@ def user_update(context, data_dict):
     user = context['user']
     session = context['session']
     schema = context.get('schema') or ckan.logic.schema.default_update_user_schema()
-    id = data_dict['id']
+    id = _get_or_bust(data_dict, 'id')
 
     user_obj = model.User.get(id)
     context['user_obj'] = user_obj
@@ -570,7 +569,7 @@ def package_update_rest(context, data_dict):
 def group_update_rest(context, data_dict):
 
     model = context['model']
-    id = data_dict["id"]
+    id = _get_or_bust(data_dict, "id")
     group = model.Group.get(id)
     context["group"] = group
     context["allow_partial_update"] = True
@@ -646,7 +645,7 @@ def user_role_update(context, data_dict):
     new_authgroup_ref = data_dict.get('authorization_group') # the authgroup who is being given the new role
     if bool(new_user_ref) == bool(new_authgroup_ref):
         raise logic.ParameterError('You must provide either "user" or "authorization_group" parameter.')
-    domain_object_ref = data_dict['domain_object']
+    domain_object_ref = _get_or_bust(data_dict, 'domain_object')
     if not isinstance(data_dict['roles'], (list, tuple)):
         raise logic.ParameterError('Parameter "%s" must be of type: "%s"' % ('role', 'list'))
     desired_roles = set(data_dict['roles'])


================================================================
  Commit: f2ddf0dfb5c31018d2e4e03fd7522d54bc9de930
      https://github.com/okfn/ckan/commit/f2ddf0dfb5c31018d2e4e03fd7522d54bc9de930
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-04 (Fri, 04 May 2012)

  Changed paths:
    M ckan/logic/__init__.py

  Log Message:
  -----------
  [2330] Small fix to get_or_bust() function.

It should only raise a ValidationError if the key cannot be found.  And not
if the value is false-y.


diff --git a/ckan/logic/__init__.py b/ckan/logic/__init__.py
index c4880d4..098b7ed 100644
--- a/ckan/logic/__init__.py
+++ b/ckan/logic/__init__.py
@@ -253,10 +253,11 @@ def get_or_bust(data_dict, keys):
     if isinstance(keys, basestring):
         keys = [keys]
     for key in keys:
-        value = data_dict.get(key)
-        if not value:
+        try:
+            value = data_dict[key]
+            values.append(value)
+        except KeyError:
             errors[key] = _('Missing value')
-        values.append(value)
     if errors:
         raise ValidationError(errors)
     if len(values) == 1:


================================================================
  Commit: aa1a09b9878060fbe21ee78038bb9c3f8def8a3f
      https://github.com/okfn/ckan/commit/aa1a09b9878060fbe21ee78038bb9c3f8def8a3f
  Author: Ian Murray <ian.murray at okfn.org>
  Date:   2012-05-04 (Fri, 04 May 2012)

  Changed paths:
    M ckan/logic/action/create.py
    M ckan/logic/action/delete.py
    M ckan/logic/action/update.py

  Log Message:
  -----------
  [2330] Ensure that only action functions in the action modules are exposed through the action API


diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py
index debdd95..b3873eb 100644
--- a/ckan/logic/action/create.py
+++ b/ckan/logic/action/create.py
@@ -17,11 +17,13 @@
 
 log = logging.getLogger(__name__)
 
-# define some shortcuts
-error_summary = ckan.logic.action.error_summary
-validate = ckan.lib.navl.dictization_functions.validate
-check_access = logic.check_access
-get_action = logic.get_action
+# Define some shortcuts
+# Ensure they are module-private so that they don't get loaded as available
+# actions in the action API.
+_error_summary = ckan.logic.action.error_summary
+_validate = ckan.lib.navl.dictization_functions.validate
+_check_access = logic.check_access
+_get_action = logic.get_action
 ValidationError = logic.ValidationError
 NotFound = logic.NotFound
 _get_or_bust = logic.get_or_bust
@@ -42,7 +44,7 @@ def package_create(context, data_dict):
     except AttributeError:
         schema = package_plugin.form_to_db_schema()
 
-    check_access('package_create', context, data_dict)
+    _check_access('package_create', context, data_dict)
 
     if 'api_version' not in context:
         # old plugins do not support passing the schema so we need
@@ -52,11 +54,11 @@ def package_create(context, data_dict):
         except TypeError:
             package_plugin.check_data_dict(data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -85,7 +87,7 @@ def package_create(context, data_dict):
     ## this is added so that the rest controller can make a new location
     context["id"] = pkg.id
     log.debug('Created object %s' % str(pkg.name))
-    return get_action('package_show')(context, {'id':context['id']})
+    return _get_action('package_show')(context, {'id':context['id']})
 
 def package_create_validate(context, data_dict):
     model = context['model']
@@ -93,13 +95,13 @@ def package_create_validate(context, data_dict):
     model.Session.remove()
     model.Session()._context = context
 
-    check_access('package_create',context,data_dict)
+    _check_access('package_create',context,data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
     else:
         return data
 
@@ -109,7 +111,7 @@ def resource_create(context, data_dict):
     model = context['model']
     user = context['user']
 
-    data, errors = validate(data_dict,
+    data, errors = _validate(data_dict,
                             ckan.logic.schema.default_resource_schema(),
                             context)
 
@@ -120,12 +122,12 @@ def related_create(context, data_dict):
     userobj = model.User.get(user)
 
     data_dict["owner_id"] = userobj.id
-    data, errors = validate(data_dict,
+    data, errors = _validate(data_dict,
                             ckan.logic.schema.default_related_schema(),
                             context)
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     related = model_save.related_dict_save(data, context)
     if not context.get('defer_commit'):
@@ -160,13 +162,13 @@ def package_relationship_create(context, data_dict):
     if not pkg2:
         return NotFound('Object package %r was not found.' % id2)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
-    check_access('package_relationship_create', context, data_dict)
+    _check_access('package_relationship_create', context, data_dict)
 
     # Create a Package Relationship.
     existing_rels = pkg1.get_relationships_with(pkg2, rel_type)
@@ -215,7 +217,7 @@ def member_create(context, data_dict=None):
     obj_id, obj_type, capacity = _get_or_bust(data_dict, ['object', 'object_type', 'capacity'])
 
     # User must be able to update the group to add a member to it
-    check_access('group_update', context, data_dict)
+    _check_access('group_update', context, data_dict)
 
     # Look up existing, in case it exists
     member = model.Session.query(model.Member).\
@@ -242,7 +244,7 @@ def group_create(context, data_dict):
     session = context['session']
     parent = context.get('parent', None)
 
-    check_access('group_create', context, data_dict)
+    _check_access('group_create', context, data_dict)
 
     # get the schema
     group_plugin = lib_plugins.lookup_group_plugin()
@@ -253,11 +255,11 @@ def group_create(context, data_dict):
     except AttributeError:
         schema = group_plugin.form_to_db_schema()
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -350,13 +352,13 @@ def user_create(context, data_dict):
     schema = context.get('schema') or ckan.logic.schema.default_user_schema()
     session = context['session']
 
-    check_access('user_create', context, data_dict)
+    _check_access('user_create', context, data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     user = model_save.user_dict_save(data, context)
 
@@ -389,10 +391,10 @@ def user_create(context, data_dict):
 
 def package_create_rest(context, data_dict):
 
-    check_access('package_create_rest', context, data_dict)
+    _check_access('package_create_rest', context, data_dict)
 
     dictized_package = model_save.package_api_to_dict(data_dict, context)
-    dictized_after = get_action('package_create')(context, dictized_package)
+    dictized_after = _get_action('package_create')(context, dictized_package)
 
     pkg = context['package']
 
@@ -404,10 +406,10 @@ def package_create_rest(context, data_dict):
 
 def group_create_rest(context, data_dict):
 
-    check_access('group_create_rest', context, data_dict)
+    _check_access('group_create_rest', context, data_dict)
 
     dictized_group = model_save.group_api_to_dict(data_dict, context)
-    dictized_after = get_action('group_create')(context, dictized_group)
+    dictized_after = _get_action('group_create')(context, dictized_group)
 
     group = context['group']
 
@@ -425,13 +427,13 @@ def vocabulary_create(context, data_dict):
     model.Session.remove()
     model.Session()._context = context
 
-    check_access('vocabulary_create', context, data_dict)
+    _check_access('vocabulary_create', context, data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     vocabulary = model_save.vocabulary_dict_save(data, context)
 
@@ -458,10 +460,10 @@ def activity_create(context, activity_dict, ignore_auth=False):
         activity_dict['revision_id'] = None
 
     if not ignore_auth:
-        check_access('activity_create', context, activity_dict)
+        _check_access('activity_create', context, activity_dict)
 
     schema = context.get('schema') or ckan.logic.schema.default_create_activity_schema()
-    data, errors = validate(activity_dict, schema, context)
+    data, errors = _validate(activity_dict, schema, context)
     if errors:
         raise ValidationError(errors)
 
@@ -482,7 +484,7 @@ def package_relationship_create_rest(context, data_dict):
     # object and type to override the URL parameters.
     data_dict = ckan.logic.action.rename_keys(data_dict, key_map, destructive=False)
 
-    relationship_dict = get_action('package_relationship_create')(context, data_dict)
+    relationship_dict = _get_action('package_relationship_create')(context, data_dict)
     return relationship_dict
 
 def tag_create(context, tag_dict):
@@ -490,10 +492,10 @@ def tag_create(context, tag_dict):
 
     model = context['model']
 
-    check_access('tag_create', context, tag_dict)
+    _check_access('tag_create', context, tag_dict)
 
     schema = context.get('schema') or ckan.logic.schema.default_create_tag_schema()
-    data, errors = validate(tag_dict, schema, context)
+    data, errors = _validate(tag_dict, schema, context)
     if errors:
         raise ValidationError(errors)
 
diff --git a/ckan/logic/action/delete.py b/ckan/logic/action/delete.py
index ecfe6f7..0c509c2 100644
--- a/ckan/logic/action/delete.py
+++ b/ckan/logic/action/delete.py
@@ -4,10 +4,12 @@
 import ckan.logic.action
 import ckan.plugins as plugins
 
-# define some shortcuts
+# Define some shortcuts
+# Ensure they are module-private so that they don't get loaded as available
+# actions in the action API.
 ValidationError = ckan.logic.ValidationError
 NotFound = ckan.logic.NotFound
-check_access = ckan.logic.check_access
+_check_access = ckan.logic.check_access
 _get_or_bust = ckan.logic.get_or_bust
 
 def package_delete(context, data_dict):
@@ -21,7 +23,7 @@ def package_delete(context, data_dict):
     if entity is None:
         raise NotFound
 
-    check_access('package_delete',context, data_dict)
+    _check_access('package_delete',context, data_dict)
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -54,7 +56,7 @@ def package_relationship_delete(context, data_dict):
     revisioned_details = 'Package Relationship: %s %s %s' % (id, rel, id2)
 
     context['relationship'] = relationship
-    check_access('package_relationship_delete', context, data_dict)
+    _check_access('package_relationship_delete', context, data_dict)
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -73,7 +75,7 @@ def related_delete(context, data_dict):
     if entity is None:
         raise NotFound
 
-    check_access('related_delete',context, data_dict)
+    _check_access('related_delete',context, data_dict)
 
     entity.delete()
     model.repo.commit()
@@ -102,7 +104,7 @@ def member_delete(context, data_dict=None):
                                               ['group', 'object', 'object_type'])
 
     # User must be able to update the group to remove a member from it
-    check_access('group_update', context, data_dict)
+    _check_access('group_update', context, data_dict)
 
     member = model.Session.query(model.Member).\
             filter(model.Member.table_name == obj_type).\
@@ -126,7 +128,7 @@ def group_delete(context, data_dict):
 
     revisioned_details = 'Group: %s' % group.name
 
-    check_access('group_delete', context, data_dict)
+    _check_access('group_delete', context, data_dict)
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -150,7 +152,7 @@ def task_status_delete(context, data_dict):
     if entity is None:
         raise NotFound
 
-    check_access('task_status_delete', context, data_dict)
+    _check_access('task_status_delete', context, data_dict)
 
     entity.delete()
     model.Session.commit()
@@ -166,7 +168,7 @@ def vocabulary_delete(context, data_dict):
     if vocab_obj is None:
         raise NotFound(_('Could not find vocabulary "%s"') % vocab_id)
 
-    check_access('vocabulary_delete', context, data_dict)
+    _check_access('vocabulary_delete', context, data_dict)
 
     vocab_obj.delete()
     model.repo.commit()
@@ -185,7 +187,7 @@ def tag_delete(context, data_dict):
     if tag_obj is None:
         raise NotFound(_('Could not find tag "%s"') % tag_id_or_name)
 
-    check_access('tag_delete', context, data_dict)
+    _check_access('tag_delete', context, data_dict)
 
     tag_obj.delete()
     model.repo.commit()
diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py
index b0e42dc..5c79364 100644
--- a/ckan/logic/action/update.py
+++ b/ckan/logic/action/update.py
@@ -16,11 +16,13 @@
 
 log = logging.getLogger(__name__)
 
-# define some shortcuts
-validate = ckan.lib.navl.dictization_functions.validate
-error_summary = logic.action.error_summary
-get_action = logic.get_action
-check_access = logic.check_access
+# Define some shortcuts
+# Ensure they are module-private so that they don't get loaded as available
+# actions in the action API.
+_validate = ckan.lib.navl.dictization_functions.validate
+_error_summary = logic.action.error_summary
+_get_action = logic.get_action
+_check_access = logic.check_access
 NotFound = logic.NotFound
 ValidationError = logic.ValidationError
 _get_or_bust = logic.get_or_bust
@@ -64,7 +66,7 @@ def make_latest_pending_package_active(context, data_dict):
     id = _get_or_bust(data_dict, "id")
     pkg = model.Package.get(id)
 
-    check_access('make_latest_pending_package_active', context, data_dict)
+    _check_access('make_latest_pending_package_active', context, data_dict)
 
     #packages
     q = session.query(model.PackageRevision).filter_by(id=pkg.id)
@@ -114,12 +116,12 @@ def related_update(context, data_dict):
         logging.error('Could not find related ' + id)
         raise NotFound(_('Related was not found.'))
 
-    check_access('related_update', context, data_dict)
-    data, errors = validate(data_dict, schema, context)
+    _check_access('related_update', context, data_dict)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     related = model_save.related_dict_save(data, context)
     if not context.get('defer_commit'):
@@ -142,13 +144,13 @@ def resource_update(context, data_dict):
         logging.error('Could not find resource ' + id)
         raise NotFound(_('Resource was not found.'))
 
-    check_access('resource_update', context, data_dict)
+    _check_access('resource_update', context, data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -178,7 +180,7 @@ def package_update(context, data_dict):
     context["package"] = pkg
     data_dict["id"] = pkg.id
 
-    check_access('package_update', context, data_dict)
+    _check_access('package_update', context, data_dict)
 
     # get the schema
     package_plugin = lib_plugins.lookup_package_plugin(pkg.type)
@@ -197,11 +199,11 @@ def package_update(context, data_dict):
         except TypeError:
             package_plugin.check_data_dict(data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -216,7 +218,7 @@ def package_update(context, data_dict):
         item.edit(pkg)
     if not context.get('defer_commit'):
         model.repo.commit()
-    return get_action('package_show')(context, data_dict)
+    return _get_action('package_show')(context, data_dict)
 
 def package_update_validate(context, data_dict):
     model = context['model']
@@ -242,14 +244,14 @@ def package_update_validate(context, data_dict):
     except AttributeError:
         schema = package_plugin.form_to_db_schema()
 
-    check_access('package_update', context, data_dict)
+    _check_access('package_update', context, data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
     return data
 
 
@@ -285,13 +287,13 @@ def package_relationship_update(context, data_dict):
     if not pkg2:
         return NotFound('Object package %r was not found.' % id2)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
-    check_access('package_relationship_update', context, data_dict)
+    _check_access('package_relationship_update', context, data_dict)
 
     existing_rels = pkg1.get_relationships_with(pkg2, rel)
     if not existing_rels:
@@ -322,12 +324,12 @@ def group_update(context, data_dict):
     except AttributeError:
         schema = group_plugin.form_to_db_schema()
 
-    check_access('group_update', context, data_dict)
+    _check_access('group_update', context, data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
     if errors:
         session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     rev = model.repo.new_revision()
     rev.author = user
@@ -384,7 +386,7 @@ def group_update(context, data_dict):
             'defer_commit':True,
             'session': session
         }
-        get_action('activity_create')(activity_create_context, activity_dict,
+        _get_action('activity_create')(activity_create_context, activity_dict,
                 ignore_auth=True)
         # TODO: Also create an activity detail recording what exactly changed
         # in the group.
@@ -408,12 +410,12 @@ def user_update(context, data_dict):
     if user_obj is None:
         raise NotFound('User was not found.')
 
-    check_access('user_update', context, data_dict)
+    _check_access('user_update', context, data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
     if errors:
         session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     user = model_save.user_dict_save(data, context)
 
@@ -428,7 +430,7 @@ def user_update(context, data_dict):
         'defer_commit':True,
         'session': session
     }
-    get_action('activity_create')(activity_create_context, activity_dict, ignore_auth=True)
+    _get_action('activity_create')(activity_create_context, activity_dict, ignore_auth=True)
     # TODO: Also create an activity detail recording what exactly changed in
     # the user.
 
@@ -452,13 +454,13 @@ def task_status_update(context, data_dict):
         if task_status is None:
             raise NotFound(_('TaskStatus was not found.'))
 
-    check_access('task_status_update', context, data_dict)
+    _check_access('task_status_update', context, data_dict)
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         session.rollback()
-        raise ValidationError(errors, error_summary(errors))
+        raise ValidationError(errors, _error_summary(errors))
 
     task_status = model_save.task_status_dict_save(data, context)
 
@@ -472,7 +474,7 @@ def task_status_update_many(context, data_dict):
     deferred = context.get('defer_commit')
     context['defer_commit'] = True
     for data in data_dict['data']:
-        results.append(get_action('task_status_update')(context, data))
+        results.append(_get_action('task_status_update')(context, data))
     if not deferred:
         context.pop('defer_commit')
     if not context.get('defer_commit'):
@@ -482,13 +484,13 @@ def task_status_update_many(context, data_dict):
 def term_translation_update(context, data_dict):
     model = context['model']
 
-    check_access('term_translation_update', context, data_dict)
+    _check_access('term_translation_update', context, data_dict)
 
     schema = {'term': [validators.not_empty, unicode],
               'term_translation': [validators.not_empty, unicode],
               'lang_code': [validators.not_empty, unicode]}
 
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
@@ -556,9 +558,9 @@ def package_update_rest(context, data_dict):
     context["allow_partial_update"] = False
     dictized_package = model_save.package_api_to_dict(data_dict, context)
 
-    check_access('package_update_rest', context, dictized_package)
+    _check_access('package_update_rest', context, dictized_package)
 
-    dictized_after = get_action('package_update')(context, dictized_package)
+    dictized_after = _get_action('package_update')(context, dictized_package)
 
     pkg = context['package']
 
@@ -575,9 +577,9 @@ def group_update_rest(context, data_dict):
     context["allow_partial_update"] = True
     dictized_group = model_save.group_api_to_dict(data_dict, context)
 
-    check_access('group_update_rest', context, dictized_group)
+    _check_access('group_update_rest', context, dictized_group)
 
-    dictized_after = get_action('group_update')(context, dictized_group)
+    dictized_after = _get_action('group_update')(context, dictized_group)
 
     group = context['group']
 
@@ -601,10 +603,10 @@ def vocabulary_update(context, data_dict):
         if data_dict['name'] == vocab.name:
             del data_dict['name']
 
-    check_access('vocabulary_update', context, data_dict)
+    _check_access('vocabulary_update', context, data_dict)
 
     schema = context.get('schema') or ckan.logic.schema.default_update_vocabulary_schema()
-    data, errors = validate(data_dict, schema, context)
+    data, errors = _validate(data_dict, schema, context)
 
     if errors:
         model.Session.rollback()
@@ -630,7 +632,7 @@ def package_relationship_update_rest(context, data_dict):
     # these values.
     data_dict = logic.action.rename_keys(data_dict, key_map, destructive=True)
 
-    relationship_dict = get_action('package_relationship_update')(context, data_dict)
+    relationship_dict = _get_action('package_relationship_update')(context, data_dict)
 
     return relationship_dict
 
@@ -668,11 +670,11 @@ def user_role_update(context, data_dict):
     domain_object = logic.action.get_domain_object(model, domain_object_ref)
     data_dict['id'] = domain_object.id
     if isinstance(domain_object, model.Package):
-        check_access('package_edit_permissions', context, data_dict)
+        _check_access('package_edit_permissions', context, data_dict)
     elif isinstance(domain_object, model.Group):
-        check_access('group_edit_permissions', context, data_dict)
+        _check_access('group_edit_permissions', context, data_dict)
     elif isinstance(domain_object, model.AuthorizationGroup):
-        check_access('authorization_group_edit_permissions', context, data_dict)
+        _check_access('authorization_group_edit_permissions', context, data_dict)
     # Todo: 'system' object
     else:
         raise logic.ParameterError('Not possible to update roles for domain object type %s' % type(domain_object))
@@ -680,7 +682,7 @@ def user_role_update(context, data_dict):
     # current_uors: in order to avoid either creating a role twice or
     # deleting one which is non-existent, we need to get the users\'
     # current roles (if any)
-    current_role_dicts = get_action('roles_show')(context, data_dict)['roles']
+    current_role_dicts = _get_action('roles_show')(context, data_dict)['roles']
     current_roles = set([role_dict['role'] for role_dict in current_role_dicts])
 
     # Whenever our desired state is different from our current state,
@@ -694,7 +696,7 @@ def user_role_update(context, data_dict):
     if not (current_roles == desired_roles):
         model.repo.commit_and_remove()
 
-    return get_action('roles_show')(context, data_dict)
+    return _get_action('roles_show')(context, data_dict)
 
 def user_role_bulk_update(context, data_dict):
     '''
@@ -717,4 +719,4 @@ def user_role_bulk_update(context, data_dict):
                              'roles': roles_by_user[user],
                              'domain_object': data_dict['domain_object']}
             user_role_update(context, uro_data_dict)
-    return get_action('roles_show')(context, data_dict)
+    return _get_action('roles_show')(context, data_dict)


================================================================
Compare: https://github.com/okfn/ckan/compare/817cba8^...aa1a09b


More information about the ckan-changes mailing list