Skip to content

Commit

Permalink
* user_show now returns draft and private datasets if asked by the same
Browse files Browse the repository at this point in the history
  user as is being viewed, or a sysadmin.
* Standardize number_created_packages to mean excluding private datasets
  (changes behaviour in user_list)
* Improved docs and new_tests for user_list and user_show
  • Loading branch information
David Read authored and amercader committed Feb 4, 2015
1 parent df2ab76 commit f4cf6c7
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 71 deletions.
41 changes: 31 additions & 10 deletions ckan/logic/action/get.py
Expand Up @@ -772,10 +772,13 @@ def user_list(context, data_dict):
(optional)
:type q: string
:param order_by: which field to sort the list by (optional, default:
``'name'``)
``'name'``). Can be any user field or ``edits`` (i.e. number_of_edits).
:type order_by: string
:rtype: list of dictionaries
:rtype: list of user dictionaries. User properties include:
``number_of_edits`` which counts the revisions by the user and
``number_created_packages`` which excludes datasets which are private
or draft state.
'''
model = context['model']
Expand All @@ -801,6 +804,7 @@ def user_list(context, data_dict):
_and_(
model.Package.creator_user_id == model.User.id,
model.Package.state == 'active',
model.Package.private == False,
)).label('number_created_packages')
)

Expand Down Expand Up @@ -1296,17 +1300,19 @@ def user_show(context, data_dict):
:type id: string
:param user_obj: the user dictionary of the user (optional)
:type user_obj: user dictionary
:param include_datasets: Include datasets user has created
:param include_datasets: Include a list of datasets the user has created.
If it is the same user or a sysadmin requesting, it includes datasets
that are draft or private.
(optional, default:``False``, limit:50)
:type include_datasets: boolean
:param include_num_followers: Include the number of followers the user has
(optional, default:``False``)
:type include_num_followers: boolean
:returns: the details of the user. Includes email_hash, number_of_edits and
number_created_packages. Excludes the password (hash) and reset_key.
The email and apikey are included if it is the user or a sysadmin
requesting.
number_created_packages (which always excludes draft or private
datasets). Excludes the password (hash) and reset_key. If it is the
same user or a sysadmin requesting, the email and apikey are included.
:rtype: dictionary
'''
Expand Down Expand Up @@ -1334,12 +1340,27 @@ def user_show(context, data_dict):
return user_dict

if data_dict.get('include_datasets', False):
# show private and draft datasets?
requester = context.get('user')
if requester:
requester_looking_at_own_account = requester == user_obj.name
show_private_and_draft_datasets = \
new_authz.is_sysadmin(requester) or \
requester_looking_at_own_account

user_dict['datasets'] = []
dataset_q = (model.Session.query(model.Package)
dataset_q = model.Session.query(model.Package) \
.filter_by(creator_user_id=user_dict['id'])
.filter_by(state='active')
.filter_by(private=False)
.limit(50))
if not show_private_and_draft_datasets:
dataset_q = dataset_q \
.filter_by(state='active') \
.filter_by(private=False)
else:
dataset_q = dataset_q \
.filter(_or_(model.Package.state=='active',
model.Package.state=='draft'))
dataset_q = dataset_q.limit(50)


for dataset in dataset_q:
try:
Expand Down
127 changes: 127 additions & 0 deletions ckan/new_tests/logic/action/test_get.py
Expand Up @@ -364,16 +364,78 @@ def test_organization_show_private_packages_not_returned(self):
assert org_dict['packages'][0]['name'] == 'dataset_1'
assert org_dict['package_count'] == 1

def test_user_list_default_values(self):

user = factories.User()

got_users = helpers.call_action('user_list')
remove_pseudo_users(got_users)

assert len(got_users) == 1
got_user = got_users[0]
assert got_user['id'] == user['id']
assert got_user['name'] == user['name']
assert got_user['fullname'] == user['fullname']
assert got_user['display_name'] == user['display_name']
assert got_user['created'] == user['created']
assert got_user['about'] == user['about']
assert got_user['sysadmin'] == user['sysadmin']
assert got_user['number_of_edits'] == 0
assert got_user['number_created_packages'] == 0
assert 'password' not in got_user
assert 'reset_key' not in got_user
assert 'apikey' not in got_user
assert 'email' not in got_user
assert 'datasets' not in got_user

def test_user_list_edits(self):

user = factories.User()
dataset = factories.Dataset(user=user)
dataset['title'] = 'Edited title'
helpers.call_action('package_update',
context={'user': user['name']},
**dataset)

got_users = helpers.call_action('user_list')
remove_pseudo_users(got_users)

assert len(got_users) == 1
got_user = got_users[0]
assert got_user['number_created_packages'] == 1
assert got_user['number_of_edits'] == 2

def test_user_list_excludes_deleted_users(self):

user = factories.User()
factories.User(state='deleted')

got_users = helpers.call_action('user_list')
remove_pseudo_users(got_users)

assert len(got_users) == 1
assert got_users[0]['name'] == user['name']

def test_user_show_default_values(self):

user = factories.User()

got_user = helpers.call_action('user_show', id=user['id'])

assert got_user['id'] == user['id']
assert got_user['name'] == user['name']
assert got_user['fullname'] == user['fullname']
assert got_user['display_name'] == user['display_name']
assert got_user['created'] == user['created']
assert got_user['about'] == user['about']
assert got_user['sysadmin'] == user['sysadmin']
assert got_user['number_of_edits'] == 0
assert got_user['number_created_packages'] == 0
assert 'password' not in got_user
assert 'reset_key' not in got_user
assert 'apikey' not in got_user
assert 'email' not in got_user
assert 'datasets' not in got_user

def test_user_show_keep_email(self):

Expand Down Expand Up @@ -401,6 +463,19 @@ def test_user_show_keep_apikey(self):
assert 'password' not in got_user
assert 'reset_key' not in got_user

def test_user_show_for_myself(self):

user = factories.User()

got_user = helpers.call_action('user_show',
context={'user': user['name']},
id=user['id'])

assert got_user['email'] == user['email']
assert got_user['apikey'] == user['apikey']
assert 'password' not in got_user
assert 'reset_key' not in got_user

def test_user_show_sysadmin_values(self):

user = factories.User()
Expand All @@ -416,6 +491,52 @@ def test_user_show_sysadmin_values(self):
assert 'password' not in got_user
assert 'reset_key' not in got_user

def test_user_show_include_datasets(self):

user = factories.User()
dataset = factories.Dataset(user=user)

got_user = helpers.call_action('user_show',
include_datasets=True,
id=user['id'])

assert len(got_user['datasets']) == 1
assert got_user['datasets'][0]['name'] == dataset['name']

def test_user_show_include_datasets_excludes_draft_and_private(self):

user = factories.User()
org = factories.Organization(user=user)
dataset = factories.Dataset(user=user)
factories.Dataset(user=user, state='deleted')
factories.Dataset(user=user, state='draft')
factories.Dataset(user=user, private=True, owner_org=org['name'])

got_user = helpers.call_action('user_show',
include_datasets=True,
id=user['id'])

assert len(got_user['datasets']) == 1
assert got_user['datasets'][0]['name'] == dataset['name']

def test_user_show_include_datasets_includes_draft_and_private_for_myself(self):

user = factories.User()
org = factories.Organization(user=user)
factories.Dataset(user=user)
dataset_deleted = factories.Dataset(user=user, state='deleted')
factories.Dataset(user=user, state='draft')
factories.Dataset(user=user, private=True, owner_org=org['name'])

got_user = helpers.call_action('user_show',
context={'user': user['name']},
include_datasets=True,
id=user['id'])

assert len(got_user['datasets']) == 3
datasets_got = set([user_['name'] for user_ in got_user['datasets']])
assert dataset_deleted['name'] not in datasets_got

def test_related_list_with_no_params(self):
'''
Test related_list with no parameters and default sort
Expand Down Expand Up @@ -1029,3 +1150,9 @@ def test_help_show_not_found(self):
nose.tools.assert_raises(
logic.NotFound,
helpers.call_action, 'help_show', name=function_name)


def remove_pseudo_users(user_list):
pseudo_users = set(('logged_in', 'visitor'))
user_list[:] = [user for user in user_list
if user['name'] not in pseudo_users]
61 changes: 0 additions & 61 deletions ckan/tests/logic/test_action.py
Expand Up @@ -313,67 +313,6 @@ def test_42_create_resource_with_error(self):
assert json.loads(res.body)['error'] == {"__type": "Validation Error", "created": ["Date format incorrect"]}



def test_04_user_list(self):
# Create deleted user to make sure he won't appear in the user_list
deleted_user = CreateTestData.create_user('deleted_user')
deleted_user.delete()
model.repo.commit()

postparams = '%s=1' % json.dumps({})
res = self.app.post('/api/action/user_list', params=postparams)
res_obj = json.loads(res.body)
assert "/api/3/action/help_show?name=user_list" in res_obj['help']
assert res_obj['success'] == True
assert len(res_obj['result']) == 7
assert res_obj['result'][0]['name'] == 'annafan'
assert res_obj['result'][0]['about'] == 'I love reading Annakarenina. My site: http://anna.com'
assert not 'apikey' in res_obj['result'][0]

def test_05_user_show(self):
# Anonymous request
postparams = '%s=1' % json.dumps({'id':'annafan'})
res = self.app.post('/api/action/user_show', params=postparams)
res_obj = json.loads(res.body)
assert "/api/3/action/help_show?name=user_show" in res_obj['help']
assert res_obj['success'] == True
result = res_obj['result']
assert result['name'] == 'annafan'
assert result['about'] == 'I love reading Annakarenina. My site: http://anna.com'
assert 'created' in result
assert 'display_name' in result
assert 'number_created_packages' in result
assert 'number_of_edits' in result
assert not 'apikey' in result
assert not 'reset_key' in result

# Same user can see his api key
res = self.app.post('/api/action/user_show', params=postparams,
extra_environ={'Authorization': str(self.normal_user.apikey)})

res_obj = json.loads(res.body)
result = res_obj['result']
assert result['name'] == 'annafan'
assert 'apikey' in result

# Sysadmin user can see everyone's api key
res = self.app.post('/api/action/user_show', params=postparams,
extra_environ={'Authorization': str(self.sysadmin_user.apikey)})

res_obj = json.loads(res.body)
result = res_obj['result']
assert result['name'] == 'annafan'
assert 'apikey' in result

def test_05b_user_show_datasets(self):
postparams = '%s=1' % json.dumps({'id':'annafan', 'include_datasets': True})
res = self.app.post('/api/action/user_show', params=postparams)
res_obj = json.loads(res.body)
result = res_obj['result']
datasets = result['datasets']
assert_equal(len(datasets), 0) # No datasets created


def test_10_user_create_parameters_missing(self):
user_dict = {}

Expand Down

0 comments on commit f4cf6c7

Please sign in to comment.