Repository: ckan/ckan

Issue:
Document undocumented action functions
Currently the docs read:

> TODO: What does this function do?

and this is the first function on our [api docs page](http://docs.ckan.org/en/latest/ckan.logic.action.update.html) which looks quite bad. All action functions should have docstrings.

**Update**: a number of action functions have no docstrings. They should all have docstrings as described in the coding standards.



Discussion:
I think we should also add a test to check each action has a docstring too


Resolving patch:
diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py
--- a/ckan/logic/action/create.py
+++ b/ckan/logic/action/create.py
@@ -3,7 +3,7 @@
 import logging
 
 from pylons import config
-from paste.deploy.converters import asbool
+import paste.deploy.converters
 
 import ckan.lib.plugins as lib_plugins
 import ckan.logic as logic
@@ -914,7 +914,8 @@ def activity_create(context, activity_dict, ignore_auth=False):
     :rtype: dictionary
 
     '''
-    if not asbool(config.get('ckan.activity_streams_enabled', 'true')):
+    if not paste.deploy.converters.asbool(
+            config.get('ckan.activity_streams_enabled', 'true')):
         return
 
     model = context['model']
@@ -1141,10 +1142,41 @@ def _group_or_org_member_create(context, data_dict, is_org=False):
     logic.get_action('member_create')(member_create_context, member_dict)
 
 def group_member_create(context, data_dict):
+    '''Make a user a member of a group.
+
+    You must be authorized to edit the group.
+
+    :param id: the id or name of the group
+    :type id: string
+    :param username: name or id of the user to be made member of the group
+    :type username: string
+    :param role: role of the user in the group. One of ``member``, ``editor``,
+        or ``admin``
+    :type role: string
+
+    :returns: the newly created (or updated) membership
+    :rtype: dictionary
+    '''
     _check_access('group_member_create', context, data_dict)
     return _group_or_org_member_create(context, data_dict)
 
 def organization_member_create(context, data_dict):
+    '''Make a user a member of an organization.
+
+    You must be authorized to edit the organization.
+
+    :param id: the id or name of the organization
+    :type id: string
+    :param username: name or id of the user to be made member of the
+        organization
+    :type username: string
+    :param role: role of the user in the organization. One of ``member``,
+        ``editor``, or ``admin``
+    :type role: string
+
+    :returns: the newly created (or updated) membership
+    :rtype: dictionary
+    '''
     _check_access('organization_member_create', context, data_dict)
     return _group_or_org_member_create(context, data_dict, is_org=True)
 
diff --git a/ckan/logic/action/delete.py b/ckan/logic/action/delete.py
--- a/ckan/logic/action/delete.py
+++ b/ckan/logic/action/delete.py
@@ -419,7 +419,8 @@ def _group_or_org_member_delete(context, data_dict=None):
 
     group_id = data_dict.get('id')
     group = model.Group.get(group_id)
-    user_id = data_dict.get('user_id')
+    user_id = data_dict.get('username')
+    user_id = data_dict.get('user_id') if user_id is None else user_id
     member_dict = {
         'id': group.id,
         'object': user_id,
@@ -434,9 +435,29 @@ def _group_or_org_member_delete(context, data_dict=None):
 
 
 def group_member_delete(context, data_dict=None):
+    '''Remove a user from a group.
+
+    You must be authorized to edit the group.
+
+    :param id: the id or name of the group
+    :type id: string
+    :param username: name or id of the user to be removed
+    :type username: string
+
+    '''
     return _group_or_org_member_delete(context, data_dict)
 
 def organization_member_delete(context, data_dict=None):
+    '''Remove a user from an organization.
+
+    You must be authorized to edit the organization.
+
+    :param id: the id or name of the organization
+    :type id: string
+    :param username: name or id of the user to be removed
+    :type username: string
+
+    '''
     return _group_or_org_member_delete(context, data_dict)
 
 
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -670,12 +670,13 @@ def user_list(context, data_dict):
 def package_relationships_list(context, data_dict):
     '''Return a dataset (package)'s relationships.
 
-    :param id: the id or name of the package
+    :param id: the id or name of the first package
+    :type id: string
+    :param id2: the id or name of the second package
     :type id: string
-    :param id2:
-    :type id2:
-    :param rel:
-    :type rel:
+    :param rel: relationship as string see
+        :func:`ckan.logic.action.create.package_relationship_create()` for the
+        relationship types (optional)
 
     :rtype: list of dictionaries
 
@@ -2799,4 +2800,12 @@ def _unpick_search(sort, allowed_fields=None, total=None):
 
 
 def member_roles_list(context, data_dict):
+    '''Return the possible roles for members of groups and organizations.
+
+    :returns: a list of dictionaries each with two keys: "text" (the display
+        name of the role, e.g. "Admin") and "value" (the internal name of the
+        role, e.g. "admin")
+    :rtype: list of dictionaries
+
+    '''
     return new_authz.roles_list()


Test patch:
diff --git a/ckan/tests/test_coding_standards.py b/ckan/tests/test_coding_standards.py
--- a/ckan/tests/test_coding_standards.py
+++ b/ckan/tests/test_coding_standards.py
@@ -991,16 +991,11 @@ class TestActionAuth(object):
 
     ACTION_NO_DOC_STR_BLACKLIST = [
         'create: group_create_rest',
-        'create: group_member_create',
-        'create: organization_member_create',
         'create: package_create_rest',
         'create: package_relationship_create_rest',
-        'delete: group_member_delete',
-        'delete: organization_member_delete',
         'delete: package_relationship_delete_rest',
         'get: get_site_user',
         'get: group_show_rest',
-        'get: member_roles_list',
         'get: package_show_rest',
         'get: tag_show_rest',
         'update: group_update_rest',