86 lines
2.4 KiB
Python
86 lines
2.4 KiB
Python
import functools
|
|
import re
|
|
import urllib.parse as urllib
|
|
|
|
import flask
|
|
import flask_restful as restful
|
|
|
|
from craton.api.v1.validators import ensure_project_exists
|
|
from craton.api.v1.validators import request_validate
|
|
from craton.api.v1.validators import response_filter
|
|
|
|
|
|
SORT_KEY_SPLITTER = re.compile('[ ,]')
|
|
|
|
|
|
class Resource(restful.Resource):
|
|
method_decorators = [request_validate, ensure_project_exists,
|
|
response_filter]
|
|
|
|
|
|
def pagination_context(function):
|
|
@functools.wraps(function)
|
|
def wrapper(self, context, request_args):
|
|
pagination_parameters = {
|
|
'limit': limit_from(request_args),
|
|
'marker': request_args.pop('marker', None),
|
|
}
|
|
sort_keys = request_args.get('sort_keys')
|
|
if sort_keys is not None:
|
|
request_args['sort_keys'] = SORT_KEY_SPLITTER.split(sort_keys)
|
|
return function(self, context, request_args=request_args,
|
|
pagination_params=pagination_parameters)
|
|
return wrapper
|
|
|
|
|
|
def limit_from(filters, minimum=10, default=30, maximum=100):
|
|
"""Retrieve the limit from query filters."""
|
|
limit_str = filters.pop('limit', None)
|
|
|
|
if limit_str is None:
|
|
return default
|
|
|
|
limit = int(limit_str)
|
|
|
|
# NOTE(sigmavirus24): If our limit falls within in our constraints, just
|
|
# return that
|
|
if minimum <= limit <= maximum:
|
|
return limit
|
|
|
|
if limit < minimum:
|
|
return minimum
|
|
|
|
# NOTE(sigmavirus24): If our limit isn't within the constraints, and it
|
|
# isn't too small, then it must be too big. In that case, let's just
|
|
# return the maximum.
|
|
return maximum
|
|
|
|
|
|
def links_from(link_params):
|
|
"""Generate the list of hypermedia link relations from their parameters.
|
|
|
|
This uses the request thread-local to determine the endpoint and generate
|
|
URLs from that.
|
|
|
|
:param dict link_params:
|
|
A dictionary mapping the relation name to the query parameters.
|
|
:returns:
|
|
List of dictionaries to represent hypermedia link relations.
|
|
:rtype:
|
|
list
|
|
"""
|
|
links = []
|
|
relations = ["first", "prev", "self", "next"]
|
|
base_url = flask.request.base_url
|
|
|
|
for relation in relations:
|
|
query_params = link_params.get(relation)
|
|
if not query_params:
|
|
continue
|
|
link_rel = {
|
|
"rel": relation,
|
|
"href": base_url + "?" + urllib.urlencode(query_params),
|
|
}
|
|
links.append(link_rel)
|
|
return links
|