From 72d4a8617925655038c4004af2f26c5e3689de8e Mon Sep 17 00:00:00 2001 From: Adam Coldrick Date: Thu, 23 Jun 2016 21:22:22 +0100 Subject: [PATCH] Allow users to be filtered by openid and email This will allow matching of Gerrit users to StoryBoard users to be done more easily and reliably. These are filtered only by exact matches to reduce the ease of brute-forcing the email addresses we keep private, and because there is no need to do substring matching on openids. Change-Id: Ibf824868cdbd2e654e1b108bb933dceddc53dcbf --- storyboard/api/v1/users.py | 14 ++++++++---- storyboard/db/api/users.py | 46 +++++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/storyboard/api/v1/users.py b/storyboard/api/v1/users.py index b06daed8..9835f0fe 100644 --- a/storyboard/api/v1/users.py +++ b/storyboard/api/v1/users.py @@ -58,16 +58,18 @@ class UsersController(rest.RestController): @decorators.db_exceptions @secure(checks.guest) @wsme_pecan.wsexpose([wmodels.User], int, int, int, wtypes.text, - wtypes.text, wtypes.text, wtypes.text) + wtypes.text, wtypes.text, wtypes.text, wtypes.text, + wtypes.text) def get(self, marker=None, offset=None, limit=None, full_name=None, - sort_field='id', sort_dir='asc'): + email=None, openid=None, sort_field='id', sort_dir='asc'): """Page and filter the users in storyboard. :param marker: The resource id where the page should begin. :param offset: The offset to start the page at. :param limit: The number of users to retrieve. - :param username: A string of characters to filter the username with. :param full_name: A string of characters to filter the full_name with. + :param email: A string of characters to filter the email with. + :param openid: A string of characters to filter the openid with. :param sort_field: The name of the field to sort on. :param sort_dir: Sort direction for results (asc, desc). """ @@ -85,10 +87,14 @@ class UsersController(rest.RestController): offset=offset, limit=limit, full_name=full_name, + email=email, + openid=openid, filter_non_public=True, sort_field=sort_field, sort_dir=sort_dir) - user_count = users_api.user_get_count(full_name=full_name) + user_count = users_api.user_get_count(full_name=full_name, + email=email, + openid=openid) # Apply the query response headers. if limit: diff --git a/storyboard/db/api/users.py b/storyboard/db/api/users.py index b5d83b4d..e35e3d45 100644 --- a/storyboard/db/api/users.py +++ b/storyboard/db/api/users.py @@ -26,17 +26,47 @@ def user_get(user_id, filter_non_public=False, session=None): return entity +def _build_user_query(full_name=None, email=None, openid=None): + query = api_base.model_query(models.User) + + query = api_base.apply_query_filters(query=query, + model=models.User, + full_name=full_name) + + if email: + query = query.filter(models.User.email == email) + + if openid: + query = query.filter(models.User.openid == openid) + + return query + + def user_get_all(marker=None, offset=None, limit=None, filter_non_public=False, sort_field=None, sort_dir=None, + full_name=None, email=None, openid=None, **kwargs): - return api_base.entity_get_all(models.User, - marker=marker, - offset=offset, - limit=limit, - filter_non_public=filter_non_public, - sort_field=sort_field, - sort_dir=sort_dir, - **kwargs) + query = _build_user_query(full_name=full_name, + email=email, + openid=openid) + + query = api_base.paginate_query(query=query, + model=models.User, + limit=limit, + marker=marker, + offset=offset, + sort_key=sort_field, + sort_dir=sort_dir) + + users = query.all() + if len(users) > 0 and filter_non_public: + sample_user = users[0] + public_fields = getattr(sample_user, "_public_fields", []) + + users = [api_base._filter_non_public_fields(user, public_fields) + for user in users] + + return users def user_get_count(**kwargs):