Users can be filtered with LIKE clauses

In order to allow easy assigning of users, I've taught the API to
accept 'fuzzy' matching on two possible text fields on the user
record. API parameters are passed to the DB API, which parses through
kwargs and determines whether the parameter is on the model queried,
and whether it should be filtered using LIKE or ===.

Change-Id: Ia676506e5944e2be06c615b04be4d7cee33839a7
This commit is contained in:
Michael Krotscheck
2014-04-24 13:00:31 -07:00
parent efeca96410
commit 12f8a16c89
3 changed files with 47 additions and 12 deletions

View File

@@ -70,12 +70,14 @@ class UsersController(rest.RestController):
"""Manages users."""
@secure(checks.guest)
@wsme_pecan.wsexpose([User], int, int)
def get(self, marker=None, limit=None):
"""Retrieve definitions of all of the users.
@wsme_pecan.wsexpose([User], int, int, unicode, unicode)
def get(self, marker=None, limit=None, username=None, full_name=None):
"""Page and filter the users in storyboard.
:param marker: The resource id where the page should begin.
: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.
"""
# Boundary check on limit.
@@ -87,8 +89,10 @@ class UsersController(rest.RestController):
marker_user = users_api.user_get(marker)
users = users_api.user_get_all(marker=marker_user, limit=limit,
username=username, full_name=full_name,
filter_non_public=True)
user_count = users_api.user_get_count()
user_count = users_api.user_get_count(username=username,
full_name=full_name)
# Apply the query response headers.
response.headers['X-Limit'] = str(limit)

View File

@@ -17,6 +17,7 @@ import copy
from oslo.config import cfg
import six
import sqlalchemy.types as types
from storyboard.common import exception as exc
from storyboard.db import models
@@ -70,6 +71,25 @@ def _destroy_facade_instance():
_FACADE = None
def _apply_query_filters(query, model, **kwargs):
"""Parses through a list of kwargs to determine which exist on the model,
which should be filtered as ==, and which should be filtered as LIKE
"""
for k, v in kwargs.iteritems():
if v and hasattr(model, k):
column = getattr(model, k)
if column.is_attribute:
if isinstance(column.type, types.String):
# Filter strings with LIKE
query = query.filter(column.like("%" + v + "%"))
else:
# Everything else is a strict equal
query = query.filter(column == v)
return query
def get_engine():
"""Returns the global instance of our database engine.
"""
@@ -117,12 +137,15 @@ def entity_get(kls, entity_id, filter_non_public=False):
def entity_get_all(kls, filter_non_public=False, marker=None, limit=None,
**kwargs):
# Construct the query
query = model_query(kls)
# Sanity check on input parameters
kwargs = dict((k, v) for k, v in kwargs.iteritems() if v)
query = _apply_query_filters(query=query,
model=kls,
**kwargs)
# Construct the query
query = model_query(kls).filter_by(**kwargs)
query = paginate_query(query=query,
model=kls,
limit=limit,
@@ -143,9 +166,15 @@ def entity_get_all(kls, filter_non_public=False, marker=None, limit=None,
def entity_get_count(kls, **kwargs):
kwargs = dict((k, v) for k, v in kwargs.iteritems() if v)
# Construct the query
query = model_query(kls)
count = model_query(kls).filter_by(**kwargs).count()
# Sanity check on input parameters
query = _apply_query_filters(query=query,
model=kls,
**kwargs)
count = query.count()
return count

View File

@@ -26,15 +26,17 @@ def user_get(user_id, filter_non_public=False):
return entity
def user_get_all(marker=None, limit=None, filter_non_public=False):
def user_get_all(marker=None, limit=None, filter_non_public=False,
**kwargs):
return api_base.entity_get_all(models.User,
marker=marker,
limit=limit,
filter_non_public=filter_non_public)
filter_non_public=filter_non_public,
**kwargs)
def user_get_count():
return api_base.entity_get_count(models.User)
def user_get_count(**kwargs):
return api_base.entity_get_count(models.User, **kwargs)
def user_get_by_openid(openid):