Search: implemented pagination
- Got rid of the nasty off-by-one logic in the JavaScript. - Implemented pagination at the API.
This commit is contained in:
@@ -12,6 +12,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
NODE_AGG_TERMS = ['node_type', 'media', 'tags', 'is_free']
|
||||
USER_AGG_TERMS = ['roles', ]
|
||||
ITEMS_PER_PAGE = 10
|
||||
|
||||
# Will be set in setup_app()
|
||||
client: Elasticsearch = None
|
||||
@@ -54,7 +55,7 @@ def nested_bool(must: list, should: list, terms: dict, *, index_alias: str) -> S
|
||||
return search
|
||||
|
||||
|
||||
def do_node_search(query: str, terms: dict) -> dict:
|
||||
def do_node_search(query: str, terms: dict, page: int) -> dict:
|
||||
"""
|
||||
Given user query input and term refinements
|
||||
search for public published nodes
|
||||
@@ -82,6 +83,7 @@ def do_node_search(query: str, terms: dict) -> dict:
|
||||
if not query:
|
||||
search = search.sort('-created_at')
|
||||
add_aggs_to_search(search, NODE_AGG_TERMS)
|
||||
search = paginate(search, page)
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug(json.dumps(search.to_dict(), indent=4))
|
||||
@@ -94,12 +96,13 @@ def do_node_search(query: str, terms: dict) -> dict:
|
||||
return response.to_dict()
|
||||
|
||||
|
||||
def do_user_search(query: str, terms: dict) -> dict:
|
||||
def do_user_search(query: str, terms: dict, page: int) -> dict:
|
||||
""" return user objects represented in elasicsearch result dict"""
|
||||
|
||||
must, should = _common_user_search(query)
|
||||
search = nested_bool(must, should, terms, index_alias='USER')
|
||||
add_aggs_to_search(search, USER_AGG_TERMS)
|
||||
search = paginate(search, page)
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug(json.dumps(search.to_dict(), indent=4))
|
||||
@@ -130,7 +133,7 @@ def _common_user_search(query: str) -> (typing.List[Query], typing.List[Query]):
|
||||
return [], should
|
||||
|
||||
|
||||
def do_user_search_admin(query: str, terms: dict) -> dict:
|
||||
def do_user_search_admin(query: str, terms: dict, page: int) -> dict:
|
||||
"""
|
||||
return users seach result dict object
|
||||
search all user fields and provide aggregation information
|
||||
@@ -150,6 +153,7 @@ def do_user_search_admin(query: str, terms: dict) -> dict:
|
||||
|
||||
search = nested_bool(must, should, terms, index_alias='USER')
|
||||
add_aggs_to_search(search, USER_AGG_TERMS)
|
||||
search = paginate(search, page)
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug(json.dumps(search.to_dict(), indent=4))
|
||||
@@ -162,6 +166,10 @@ def do_user_search_admin(query: str, terms: dict) -> dict:
|
||||
return response.to_dict()
|
||||
|
||||
|
||||
def paginate(search: Search, page_idx: int) -> Search:
|
||||
return search[page_idx * ITEMS_PER_PAGE:(page_idx + 1) * ITEMS_PER_PAGE]
|
||||
|
||||
|
||||
def setup_app(app):
|
||||
global client
|
||||
|
||||
|
@@ -10,7 +10,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
blueprint_search = Blueprint('elksearch', __name__)
|
||||
|
||||
|
||||
TERMS = [
|
||||
'node_type', 'media',
|
||||
'tags', 'is_free', 'projectname',
|
||||
@@ -35,25 +34,38 @@ def _term_filters() -> dict:
|
||||
return {term: request.args.get(term, '') for term in TERMS}
|
||||
|
||||
|
||||
def _page_index() -> int:
|
||||
"""Return the page index from the query string."""
|
||||
try:
|
||||
page_idx = int(request.args.get('page') or '0')
|
||||
except TypeError:
|
||||
log.info('invalid page number %r received', request.args.get('page'))
|
||||
raise wz_exceptions.BadRequest()
|
||||
return page_idx
|
||||
|
||||
|
||||
@blueprint_search.route('/')
|
||||
def search_nodes():
|
||||
searchword = _valid_search()
|
||||
terms = _term_filters()
|
||||
data = queries.do_node_search(searchword, terms)
|
||||
return jsonify(data)
|
||||
page_idx = _page_index()
|
||||
|
||||
result = queries.do_node_search(searchword, terms, page_idx)
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@blueprint_search.route('/user')
|
||||
def search_user():
|
||||
searchword = _valid_search()
|
||||
terms = _term_filters()
|
||||
# data is the raw elasticseach output.
|
||||
page_idx = _page_index()
|
||||
# result is the raw elasticseach output.
|
||||
# we need to filter fields in case of user objects.
|
||||
data = queries.do_user_search(searchword, terms)
|
||||
result = queries.do_user_search(searchword, terms, page_idx)
|
||||
|
||||
# filter sensitive stuff
|
||||
# we only need. objectID, full_name, username
|
||||
hits = data.get('hits')
|
||||
hits = result.get('hits', {})
|
||||
|
||||
new_hits = []
|
||||
|
||||
@@ -70,9 +82,9 @@ def search_user():
|
||||
new_hits.append(single_hit)
|
||||
|
||||
# replace search result with safe subset
|
||||
data['hits']['hits'] = new_hits
|
||||
result['hits']['hits'] = new_hits
|
||||
|
||||
return jsonify(data)
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@blueprint_search.route('/admin/user')
|
||||
@@ -84,6 +96,7 @@ def search_user_admin():
|
||||
|
||||
searchword = _valid_search()
|
||||
terms = _term_filters()
|
||||
data = queries.do_user_search_admin(searchword, terms)
|
||||
page_idx = _page_index()
|
||||
result = queries.do_user_search_admin(searchword, terms, page_idx)
|
||||
|
||||
return jsonify(data)
|
||||
return jsonify(result)
|
||||
|
Reference in New Issue
Block a user