def _pagination_links(resource, req, documents_count): """Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ _links = {'parent': home_link(), 'self': collection_link(resource)} if documents_count and config.DOMAIN[resource]['pagination']: if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, req.page + 1) _links['next'] = {'title': 'next page', 'href': '%s%s' % (resource_uri(resource), q)} if req.page > 1: q = querydef(req.max_results, req.where, req.sort, req.page - 1) _links['prev'] = {'title': 'previous page', 'href': '%s%s' % (resource_uri(resource), q)} return _links
def get_cfg(blueprints): cfg = {} protocol = capp.config['PREFERRED_URL_SCHEME'] home = home_link() cfg['base'] = '{}://{}'.format(protocol, home['href']) cfg['domains'] = {} cfg['server_name'] = capp.config['SERVER_NAME'] cfg['api_name'] = capp.config.get('API_NAME', 'API') for domain in capp.config['DOMAIN'].keys(): # empowering doc # added show_on_doc property where there aren't any item_methods nor resource_methods if capp.config['DOMAIN'][domain]['item_methods'] or capp.config[ 'DOMAIN'][domain][ 'resource_methods'] or 'show_on_doc' in capp.config[ 'DOMAIN'][domain]: cfg['domains'][domain] = {} cfg['domains'][domain] = paths(domain) if 'doc' in capp.config['DOMAIN'][domain]: cfg['domains'][domain]['doc'] = capp.config['DOMAIN'][domain][ 'doc'] for b in blueprints: resources = get_custom_functions(b) for domain in resources: cfg['domains'][domain] = resources[domain] return cfg
def _pagination_links(resource, req, documents_count): """Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ _links = {"parent": home_link(), "self": collection_link(resource)} if documents_count and config.DOMAIN[resource]["pagination"]: if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, req.page + 1) _links["next"] = {"title": "next page", "href": "%s%s" % (resource_uri(resource), q)} if req.page > 1: q = querydef(req.max_results, req.where, req.sort, req.page - 1) _links["prev"] = {"title": "previous page", "href": "%s%s" % (resource_uri(resource), q)} return _links
def _pagination_links(resource, req, documents_count): """Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ _links = {'parent': home_link(), 'self': collection_link(resource)} if documents_count and config.DOMAIN[resource]['pagination']: if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, req.page + 1) _links['next'] = { 'title': 'next page', 'href': '%s%s' % (resource_uri(resource), q) } if req.page > 1: q = querydef(req.max_results, req.where, req.sort, req.page - 1) _links['prev'] = { 'title': 'previous page', 'href': '%s%s' % (resource_uri(resource), q) } return _links
def getitem(resource, **lookup): """ Retrieves and returns a single document. :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.6 Support for HEAD requests. .. versionchanged:: 0.0.6 ETag added to payload. .. versionchanged:: 0.0.5 Support for user-restricted access to resources. Support for LAST_UPDATED field missing from documents, because they were created outside the API context. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ response = {} req = parse_request(resource) document = app.data.find_one(resource, **lookup) if document: # need to update the document field as well since the etag must # be computed on the same document representation that might have # been used in the collection 'get' method last_modified = document[config.LAST_UPDATED] = _last_updated(document) document["etag"] = document_etag(document) if req.if_none_match and document["etag"] == req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return response, last_modified, document["etag"], 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return response, last_modified, document["etag"], 304 response["_links"] = { "self": document_link(resource, document[config.ID_FIELD]), "collection": collection_link(resource), "parent": home_link(), } response.update(document) return response, last_modified, document["etag"], 200 abort(404)
def _pagination_links(resource, req, documents_count): """ Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. .. versionchanged:: 0.0.8 Link to last page is provided if pagination is enabled (and the current page is not the last one). .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ _links = { 'parent': home_link(), 'self': { 'title': config.DOMAIN[resource]['resource_title'], 'href': _collection_link(resource) } } if documents_count and config.DOMAIN[resource]['pagination']: if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, req.page + 1) _links['next'] = { 'title': 'next page', 'href': '%s%s' % (_collection_link(resource), q) } # in python 2.x dividing 2 ints produces an int and that's rounded # before the ceil call. Have to cast one value to float to get # a correct result. Wonder if 2 casts + ceil() call are actually # faster than documents_count // req.max_results and then adding # 1 if the modulo is non-zero... last_page = int(math.ceil(documents_count / float(req.max_results))) q = querydef(req.max_results, req.where, req.sort, last_page) _links['last'] = { 'title': 'last page', 'href': '%s%s' % (_collection_link(resource), q) } if req.page > 1: q = querydef(req.max_results, req.where, req.sort, req.page - 1) _links['prev'] = { 'title': 'previous page', 'href': '%s%s' % (_collection_link(resource), q) } return _links
def getitem(resource, **lookup): """ Retrieves and returns a single document. :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged:: 0.0.6 Support for HEAD requests. .. versionchanged:: 0.0.6 ETag added to payload. .. versionchanged:: 0.0.5 Support for user-restricted access to resources. Support for LAST_UPDATED field missing from documents, because they were created outside the API context. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ response = {} req = parse_request(resource) document = app.data.find_one(resource, **lookup) if document: # need to update the document field as well since the etag must # be computed on the same document representation that might have # been used in the collection 'get' method last_modified = document[config.LAST_UPDATED] = _last_updated(document) document['etag'] = document_etag(document) if req.if_none_match and document['etag'] == req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return response, last_modified, document['etag'], 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return response, last_modified, document['etag'], 304 response['_links'] = { 'self': document_link(resource, document[config.ID_FIELD]), 'collection': collection_link(resource), 'parent': home_link() } response.update(document) return response, last_modified, document['etag'], 200 abort(404)
def _pagination_links(resource, req, documents_count): """ Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. .. versionchanged:: 0.4 HATOEAS link for contains the business unit value even when regexes have been configured for the resource endpoint. .. versionchanged:: 0.0.8 Link to last page is provided if pagination is enabled (and the current page is not the last one). .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ _links = {'parent': home_link(), 'self': {'title': config.DOMAIN[resource]['resource_title'], 'href': resource_link()}} if documents_count and config.DOMAIN[resource]['pagination']: if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, req.page + 1) _links['next'] = {'title': 'next page', 'href': '%s%s' % (resource_link(), q)} # in python 2.x dividing 2 ints produces an int and that's rounded # before the ceil call. Have to cast one value to float to get # a correct result. Wonder if 2 casts + ceil() call are actually # faster than documents_count // req.max_results and then adding # 1 if the modulo is non-zero... last_page = int(math.ceil(documents_count / float(req.max_results))) q = querydef(req.max_results, req.where, req.sort, last_page) _links['last'] = {'title': 'last page', 'href': '%s%s' % (resource_link(), q)} if req.page > 1: q = querydef(req.max_results, req.where, req.sort, req.page - 1) _links['prev'] = {'title': 'previous page', 'href': '%s%s' % (resource_link(), q)} return _links
def get_cfg(): cfg = {} protocol = capp.config['PREFERRED_URL_SCHEME'] home = home_link() cfg['base'] = '{}://{}'.format(protocol, home['href']) cfg['domains'] = {} cfg['server_name'] = capp.config['SERVER_NAME'] cfg['api_name'] = capp.config.get('API_NAME', 'API') for domain in capp.config['DOMAIN'].keys(): if capp.config['DOMAIN'][domain]['item_methods'] or capp.config['DOMAIN'][domain]['resource_methods']: cfg['domains'][domain] = {} cfg['domains'][domain] = paths(domain) return cfg
def get_cfg(): cfg = {} protocol = capp.config['PREFERRED_URL_SCHEME'] home = home_link() cfg['base'] = '{}://{}'.format(protocol, home['href']) cfg['domains'] = {} cfg['server_name'] = capp.config['SERVER_NAME'] cfg['api_name'] = capp.config.get('API_NAME', 'API') for domain in capp.config['DOMAIN'].keys(): if capp.config['DOMAIN'][domain]['item_methods'] or \ capp.config['DOMAIN'][domain]['resource_methods']: # hide the shadow collection for document versioning if 'VERSIONS' not in capp.config or not \ domain.endswith(capp.config['VERSIONS']): cfg['domains'][domain] = {} cfg['domains'][domain] = paths(domain) return cfg
def getitem(resource, **lookup): """ Retrieves and returns a single document. :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ response = {} req = parse_request() document = app.data.find_one(resource, **lookup) if document: # need to update the document field as well since the etag must # be computed on the same document representation that might have # been used in the collection 'get' method last_modified = document[config.LAST_UPDATED] = \ document[config.LAST_UPDATED].replace(tzinfo=None) etag = document_etag(document) if req.if_none_match and etag == req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return response, last_modified, etag, 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return response, last_modified, etag, 304 response['_links'] = { 'self': document_link(resource, document[config.ID_FIELD]), 'collection': collection_link(resource), 'parent': home_link() } response.update(document) return response, last_modified, etag, 200 abort(404)
def get_cfg(): cfg = {} base = home_link()['href'] if '://' not in base: protocol = capp.config['PREFERRED_URL_SCHEME'] print(base) base = '{0}://{1}'.format(protocol, base) cfg['base'] = base cfg['domains'] = {} cfg['server_name'] = capp.config['SERVER_NAME'] cfg['api_name'] = capp.config.get('API_NAME', 'API') for domain, resource in list(capp.config['DOMAIN'].items()): if resource['item_methods'] or resource['resource_methods']: # hide the shadow collection for document versioning if 'VERSIONS' not in capp.config or not \ domain.endswith(capp.config['VERSIONS']): cfg['domains'][domain] = paths(domain, resource) return cfg
def get_cfg(): cfg = {} base = home_link()['href'] if '://' not in base: protocol = capp.config['PREFERRED_URL_SCHEME'] print base base = '{0}://{1}'.format(protocol, base) cfg['base'] = base cfg['domains'] = {} cfg['server_name'] = capp.config['SERVER_NAME'] cfg['api_name'] = capp.config.get('API_NAME', 'API') for domain, resource in capp.config['DOMAIN'].items(): if resource['item_methods'] or resource['resource_methods']: # hide the shadow collection for document versioning if 'VERSIONS' not in capp.config or not \ domain.endswith(capp.config['VERSIONS']): cfg['domains'][domain] = paths(domain, resource) return cfg
def _pagination_links(resource, req, documents_count): """Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. .. versionchanged:: 0.0.8 Link to last page is provided if pagination is enabled (and the current page is not the last one). .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ _links = {"parent": home_link(), "self": collection_link(resource)} if documents_count and config.DOMAIN[resource]["pagination"]: if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, req.page + 1) _links["next"] = {"title": "next page", "href": "%s%s" % (resource_uri(resource), q)} # in python 2.x dividing 2 ints produces an int and that's rounded # before the ceil call. Have to cast one value to float to get # a correct result. Wonder if 2 casts + ceil() call are actually # faster than documents_count // req.max_results and then adding # 1 if the modulo is non-zero... last_page = int(math.ceil(documents_count / float(req.max_results))) q = querydef(req.max_results, req.where, req.sort, last_page) _links["last"] = {"title": "last page", "href": "%s%s" % (resource_uri(resource), q)} if req.page > 1: q = querydef(req.max_results, req.where, req.sort, req.page - 1) _links["prev"] = {"title": "previous page", "href": "%s%s" % (resource_uri(resource), q)} return _links
def standard_links(resource): """Returns the standard set of resource links that are included in every kind of GET response. """ return [home_link(), collection_link(resource)]
def _pagination_links(resource, req, documents_count, document_id=None): """ Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. :param document_id: the document id (used for versions). Defaults to None. .. versionchanged:: 0.5 Create pagination links given a document ID to allow paginated versions pages (#475). Pagination links reflect current query. (#464) .. versionchanged:: 0.4 HATOEAS link for contains the business unit value even when regexes have been configured for the resource endpoint. .. versionchanged:: 0.0.8 Link to last page is provided if pagination is enabled (and the current page is not the last one). .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ version = None if config.DOMAIN[resource]['versioning'] is True: version = request.args.get(config.VERSION_PARAM) other_params = _other_params(req.args) # construct the default links q = querydef(req.max_results, req.where, req.sort, version, req.page, other_params) resource_title = config.DOMAIN[resource]['resource_title'] _links = {'parent': home_link(), 'self': {'title': resource_title, 'href': resource_link()}} # change links if document ID is given if document_id: _links['self'] = document_link(resource, document_id) _links['collection'] = {'title': resource_title, 'href': '%s%s' % (resource_link(), q)} # make more specific links for versioned requests if version in ('all', 'diffs'): _links['parent'] = {'title': resource_title, 'href': resource_link()} _links['collection'] = document_link(resource, document_id) elif version: _links['parent'] = document_link(resource, document_id) _links['collection'] = {'title': resource_title, 'href': '%s?version=all' % _links['parent']['href']} # modify the self link to add query params or version number if documents_count: _links['self']['href'] = '%s%s' % (_links['self']['href'], q) elif not documents_count and version and version not in ('all', 'diffs'): _links['self'] = document_link(resource, document_id, version) # create pagination links if documents_count and config.DOMAIN[resource]['pagination']: # strip any queries from the self link if present _pagination_link = _links['self']['href'].split('?')[0] if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, version, req.page + 1, other_params) _links['next'] = {'title': 'next page', 'href': '%s%s' % (_pagination_link, q)} # in python 2.x dividing 2 ints produces an int and that's rounded # before the ceil call. Have to cast one value to float to get # a correct result. Wonder if 2 casts + ceil() call are actually # faster than documents_count // req.max_results and then adding # 1 if the modulo is non-zero... last_page = int(math.ceil(documents_count / float(req.max_results))) q = querydef(req.max_results, req.where, req.sort, version, last_page, other_params) _links['last'] = {'title': 'last page', 'href': '%s%s' % (_pagination_link, q)} if req.page > 1: q = querydef(req.max_results, req.where, req.sort, version, req.page - 1, other_params) _links['prev'] = {'title': 'previous page', 'href': '%s%s' % (_pagination_link, q)} return _links
def getitem(resource, **lookup): """ Retrieves and returns a single document. :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged: 0.0.8 'on_getting_item' event is raised when a document has been read from the database and is about to be sent to the client. .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.6 Support for HEAD requests. .. versionchanged:: 0.0.6 ETag added to payload. .. versionchanged:: 0.0.5 Support for user-restricted access to resources. Support for LAST_UPDATED field missing from documents, because they were created outside the API context. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ response = {} req = parse_request(resource) document = app.data.find_one(resource, **lookup) if document: # need to update the document field as well since the etag must # be computed on the same document representation that might have # been used in the collection 'get' method last_modified = document[config.LAST_UPDATED] = _last_updated(document) document['etag'] = document_etag(document) if req.if_none_match and document['etag'] == req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return response, last_modified, document['etag'], 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return response, last_modified, document['etag'], 304 response['_links'] = { 'self': document_link(resource, document[config.ID_FIELD]), 'collection': collection_link(resource), 'parent': home_link() } # notify registered callback functions. Please note that, should the # functions modify the document, last_modified and etag won't be # updated to reflect the changes (they always reflect the documents # state on the database). getattr(app, "on_getting_item")(resource, document[config.ID_FIELD], document) response.update(document) return response, last_modified, document['etag'], 200 abort(404)
def _pagination_links(resource, req, documents_count, document_id=None): """ Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. :param document_id: the document id (used for versions). Defaults to None. .. versionchanged:: 0.5 Create pagination links given a document ID to allow paginated versions pages (#475). Pagination links reflect current query. (#464) .. versionchanged:: 0.4 HATOEAS link for contains the business unit value even when regexes have been configured for the resource endpoint. .. versionchanged:: 0.0.8 Link to last page is provided if pagination is enabled (and the current page is not the last one). .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ version = None if config.DOMAIN[resource]['versioning'] is True: version = request.args.get(config.VERSION_PARAM) # construct the default links q = querydef(req.max_results, req.where, req.sort, version, req.page) resource_title = config.DOMAIN[resource]['resource_title'] _links = {'parent': home_link(), 'self': {'title': resource_title, 'href': resource_link()}} # change links if document ID is given if document_id: _links['self'] = document_link(resource, document_id) _links['collection'] = {'title': resource_title, 'href': '%s%s' % (resource_link(), q)} # make more specific links for versioned requests if version in ('all', 'diffs'): _links['parent'] = {'title': resource_title, 'href': resource_link()} _links['collection'] = document_link(resource, document_id) elif version: _links['parent'] = document_link(resource, document_id) _links['collection'] = {'title': resource_title, 'href': '%s?version=all' % _links['parent']['href']} # modify the self link to add query params or version number if documents_count: _links['self']['href'] = '%s%s' % (_links['self']['href'], q) elif not documents_count and version and version not in ('all', 'diffs'): _links['self'] = document_link(resource, document_id, version) # create pagination links if documents_count and config.DOMAIN[resource]['pagination']: # strip any queries from the self link if present _pagination_link = _links['self']['href'].split('?')[0] if req.page * req.max_results < documents_count: q = querydef(req.max_results, req.where, req.sort, version, req.page + 1) _links['next'] = {'title': 'next page', 'href': '%s%s' % (_pagination_link, q)} # in python 2.x dividing 2 ints produces an int and that's rounded # before the ceil call. Have to cast one value to float to get # a correct result. Wonder if 2 casts + ceil() call are actually # faster than documents_count // req.max_results and then adding # 1 if the modulo is non-zero... last_page = int(math.ceil(documents_count / float(req.max_results))) q = querydef(req.max_results, req.where, req.sort, version, last_page) _links['last'] = {'title': 'last page', 'href': '%s%s' % (_pagination_link, q)} if req.page > 1: q = querydef(req.max_results, req.where, req.sort, version, req.page - 1) _links['prev'] = {'title': 'previous page', 'href': '%s%s' % (_pagination_link, q)} return _links
def getitem(resource, **lookup): """ :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged:: 0.3 Support for media fields. When IF_MATCH is disabled, no etag is included in the payload. .. versionchanged:: 0.1.1 Support for Embeded Resource Serialization. .. versionchanged:: 0.1.0 Support for optional HATEOAS. .. versionchanged: 0.0.8 'on_getting_item' event is raised when a document has been read from the database and is about to be sent to the client. .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.6 Support for HEAD requests. .. versionchanged:: 0.0.6 ETag added to payload. .. versionchanged:: 0.0.5 Support for user-restricted access to resources. Support for LAST_UPDATED field missing from documents, because they were created outside the API context. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ response = {} req = parse_request(resource) document = app.data.find_one(resource, **lookup) if document: # need to update the document field as well since the etag must # be computed on the same document representation that might have # been used in the collection 'get' method last_modified = document[config.LAST_UPDATED] = last_updated(document) document[config.DATE_CREATED] = date_created(document) etag = None if config.IF_MATCH: etag = document[config.ETAG] = document_etag(document) if req.if_none_match and document[config.ETAG] == \ req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return response, last_modified, etag, 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return response, last_modified, document.get(config.ETAG), 304 _resolve_embedded_documents(resource, req, [document]) _resolve_media_files(document, resource) if config.DOMAIN[resource]['hateoas']: response[config.LINKS] = { 'self': document_link(resource, document[config.ID_FIELD]), 'collection': { 'title': config.DOMAIN[resource]['resource_title'], 'href': _collection_link(resource, True) }, 'parent': home_link() } # notify registered callback functions. Please note that, should the # functions modify the document, last_modified and etag won't be # updated to reflect the changes (they always reflect the documents # state on the database). item_title = config.DOMAIN[resource]['item_title'].lower() getattr(app, "on_fetch_item")(resource, document[config.ID_FIELD], document) getattr(app, "on_fetch_item_%s" % item_title)(document[config.ID_FIELD], document) response.update(document) return response, last_modified, etag, 200 abort(404)
def getitem(resource, **lookup): """ :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged:: 0.4 HATOEAS link for contains the business unit value even when regexes have been configured for the resource endpoint. 'on_fetched' now returns the whole response (HATEOAS metafields included.) Support for document versioning. Changed ``on_fetch_*`` changed to ``on_fetched_*``. .. versionchanged:: 0.3 Support for media fields. When IF_MATCH is disabled, no etag is included in the payload. .. versionchanged:: 0.1.1 Support for Embeded Resource Serialization. .. versionchanged:: 0.1.0 Support for optional HATEOAS. .. versionchanged: 0.0.8 'on_getting_item' event is raised when a document has been read from the database and is about to be sent to the client. .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.6 Support for HEAD requests. .. versionchanged:: 0.0.6 ETag added to payload. .. versionchanged:: 0.0.5 Support for user-restricted access to resources. Support for LAST_UPDATED field missing from documents, because they were created outside the API context. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ req = parse_request(resource) resource_def = config.DOMAIN[resource] embedded_fields = resolve_embedded_fields(resource, req) document = app.data.find_one(resource, req, **lookup) if not document: abort(404) response = {} etag = None version = request.args.get(config.VERSION_PARAM) latest_doc = None # synthesize old document version(s) if resource_def['versioning'] is True: latest_doc = copy.deepcopy(document) document = get_old_document(resource, req, lookup, document, version) # meld into response document build_response_document(document, resource, embedded_fields, latest_doc) # last_modified for the response last_modified = document[config.LAST_UPDATED] # facilitate client caching by returning a 304 when appropriate if config.IF_MATCH: etag = document[config.ETAG] if req.if_none_match and etag == req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return {}, last_modified, document[config.ETAG], 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return {}, last_modified, document.get(config.ETAG), 304 if version == 'all' or version == 'diffs': # find all versions lookup[versioned_id_field()] = lookup[app.config['ID_FIELD']] del lookup[app.config['ID_FIELD']] if version == 'diffs' or req.sort is None: # default sort for 'all', required sort for 'diffs' req.sort = '[("%s", 1)]' % config.VERSION req.if_modified_since = None # we always want the full history here cursor = app.data.find(resource + config.VERSIONS, req, lookup) # build all versions documents = [] if cursor.count() == 0: # this is the scenario when the document existed before # document versioning got turned on documents.append(latest_doc) else: last_document = {} # if we aren't starting on page 1, then we need to init last_doc if version == 'diffs' and req.page > 1: # grab the last document on the previous page to diff from last_version = cursor[0][app.config['VERSION']] - 1 last_document = get_old_document(resource, req, lookup, latest_doc, last_version) for i, document in enumerate(cursor): document = synthesize_versioned_document( latest_doc, document, resource_def) build_response_document(document, resource, embedded_fields, latest_doc) if version == 'diffs': if i == 0: documents.append(document) else: documents.append( diff_document(resource_def, last_document, document)) last_document = document else: documents.append(document) # add documents to response if config.DOMAIN[resource]['hateoas']: response[config.ITEMS] = documents else: response = documents else: response = document # extra hateoas links if config.DOMAIN[resource]['hateoas']: if config.LINKS not in response: response[config.LINKS] = {} response[config.LINKS]['collection'] = { 'title': config.DOMAIN[resource]['resource_title'], 'href': resource_link() } response[config.LINKS]['parent'] = home_link() if version != 'all' and version != 'diffs': # TODO: callbacks not currently supported with ?version=all # notify registered callback functions. Please note that, should # the # functions modify the document, last_modified and etag # won't be updated to reflect the changes (they always reflect the # documents state on the database). getattr(app, "on_fetched_item")(resource, response) getattr(app, "on_fetched_item_%s" % resource)(response) return response, last_modified, etag, 200
def _pagination_links(resource, req, document_count, document_id=None): """ Returns the appropriate set of resource links depending on the current page and the total number of documents returned by the query. :param resource: the resource name. :param req: and instace of :class:`eve.utils.ParsedRequest`. :param document_count: the number of documents returned by the query. :param document_id: the document id (used for versions). Defaults to None. .. versionchanged:: 0.5 Create pagination links given a document ID to allow paginated versions pages (#475). Pagination links reflect current query. (#464) .. versionchanged:: 0.4 HATEOAS link for contains the business unit value even when regexes have been configured for the resource endpoint. .. versionchanged:: 0.0.8 Link to last page is provided if pagination is enabled (and the current page is not the last one). .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.5 Support for optional pagination. .. versionchanged:: 0.0.3 JSON links """ version = None if config.DOMAIN[resource]["versioning"] is True: version = request.args.get(config.VERSION_PARAM) other_params = _other_params(req.args) # construct the default links q = querydef(req.max_results, req.where, req.sort, version, req.page, other_params) resource_title = config.DOMAIN[resource]["resource_title"] _links = { "parent": home_link(), "self": {"title": resource_title, "href": resource_link()}, } # change links if document ID is given if document_id: _links["self"] = document_link(resource, document_id) _links["collection"] = { "title": resource_title, "href": "%s%s" % (resource_link(), q), } # make more specific links for versioned requests if version in ("all", "diffs"): _links["parent"] = {"title": resource_title, "href": resource_link()} _links["collection"] = document_link(resource, document_id) elif version: _links["parent"] = document_link(resource, document_id) _links["collection"] = { "title": resource_title, "href": "%s?version=all" % _links["parent"]["href"], } # modify the self link to add query params or version number if document_count: _links["self"]["href"] = "%s%s" % (_links["self"]["href"], q) elif not document_count and version and version not in ("all", "diffs"): _links["self"] = document_link(resource, document_id, version) # create pagination links if config.DOMAIN[resource]["pagination"]: # strip any queries from the self link if present _pagination_link = _links["self"]["href"].split("?")[0] if ( req.page * req.max_results < (document_count or 0) or config.OPTIMIZE_PAGINATION_FOR_SPEED ): q = querydef( req.max_results, req.where, req.sort, version, req.page + 1, other_params, ) _links["next"] = { "title": "next page", "href": "%s%s" % (_pagination_link, q), } if document_count: last_page = int(math.ceil(document_count / float(req.max_results))) q = querydef( req.max_results, req.where, req.sort, version, last_page, other_params, ) _links["last"] = { "title": "last page", "href": "%s%s" % (_pagination_link, q), } if req.page > 1: q = querydef( req.max_results, req.where, req.sort, version, req.page - 1, other_params, ) _links["prev"] = { "title": "previous page", "href": "%s%s" % (_pagination_link, q), } return _links
def getitem(resource, **lookup): """ :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged:: 0.3 Support for media fields. When IF_MATCH is disabled, no etag is included in the payload. .. versionchanged:: 0.1.1 Support for Embeded Resource Serialization. .. versionchanged:: 0.1.0 Support for optional HATEOAS. .. versionchanged: 0.0.8 'on_getting_item' event is raised when a document has been read from the database and is about to be sent to the client. .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.6 Support for HEAD requests. .. versionchanged:: 0.0.6 ETag added to payload. .. versionchanged:: 0.0.5 Support for user-restricted access to resources. Support for LAST_UPDATED field missing from documents, because they were created outside the API context. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ response = {} req = parse_request(resource) document = app.data.find_one(resource, **lookup) if document: # need to update the document field as well since the etag must # be computed on the same document representation that might have # been used in the collection 'get' method last_modified = document[config.LAST_UPDATED] = last_updated(document) document[config.DATE_CREATED] = date_created(document) etag = None if config.IF_MATCH: etag = document[config.ETAG] = document_etag(document) if req.if_none_match and document[config.ETAG] == \ req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return response, last_modified, etag, 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return response, last_modified, document.get(config.ETAG), 304 _resolve_embedded_documents(resource, req, [document]) _resolve_media_files(document, resource) if config.DOMAIN[resource]['hateoas']: response[config.LINKS] = { 'self': document_link(resource, document[config.ID_FIELD]), 'collection': {'title': config.DOMAIN[resource]['resource_title'], 'href': _collection_link(resource, True)}, 'parent': home_link() } # notify registered callback functions. Please note that, should the # functions modify the document, last_modified and etag won't be # updated to reflect the changes (they always reflect the documents # state on the database). item_title = config.DOMAIN[resource]['item_title'].lower() getattr(app, "on_fetch_item")(resource, document[config.ID_FIELD], document) getattr(app, "on_fetch_item_%s" % item_title)(document[config.ID_FIELD], document) response.update(document) return response, last_modified, etag, 200 abort(404)
def getitem(resource, **lookup): """ :param resource: the name of the resource to which the document belongs. :param **lookup: the lookup query. .. versionchanged:: 0.4 HATOEAS link for contains the business unit value even when regexes have been configured for the resource endpoint. 'on_fetched' now returns the whole response (HATEOAS metafields included.) Support for document versioning. Changed ``on_fetch_*`` changed to ``on_fetched_*``. .. versionchanged:: 0.3 Support for media fields. When IF_MATCH is disabled, no etag is included in the payload. .. versionchanged:: 0.1.1 Support for Embeded Resource Serialization. .. versionchanged:: 0.1.0 Support for optional HATEOAS. .. versionchanged: 0.0.8 'on_getting_item' event is raised when a document has been read from the database and is about to be sent to the client. .. versionchanged:: 0.0.7 Support for Rate-Limiting. .. versionchanged:: 0.0.6 Support for HEAD requests. .. versionchanged:: 0.0.6 ETag added to payload. .. versionchanged:: 0.0.5 Support for user-restricted access to resources. Support for LAST_UPDATED field missing from documents, because they were created outside the API context. .. versionchanged:: 0.0.4 Added the ``requires_auth`` decorator. .. versionchanged:: 0.0.3 Superflous ``response`` container removed. Links wrapped with ``_links``. Links are now properly JSON formatted. """ req = parse_request(resource) resource_def = config.DOMAIN[resource] embedded_fields = resolve_embedded_fields(resource, req) document = app.data.find_one(resource, req, **lookup) if not document: abort(404) response = {} etag = None version = request.args.get(config.VERSION_PARAM) latest_doc = None # synthesize old document version(s) if resource_def['versioning'] is True: latest_doc = copy.deepcopy(document) document = get_old_document( resource, req, lookup, document, version) # meld into response document build_response_document(document, resource, embedded_fields, latest_doc) # last_modified for the response last_modified = document[config.LAST_UPDATED] # facilitate client caching by returning a 304 when appropriate if config.IF_MATCH: etag = document[config.ETAG] if req.if_none_match and etag == req.if_none_match: # request etag matches the current server representation of the # document, return a 304 Not-Modified. return {}, last_modified, document[config.ETAG], 304 if req.if_modified_since and last_modified <= req.if_modified_since: # request If-Modified-Since conditional request match. We test # this after the etag since Last-Modified dates have lower # resolution (1 second). return {}, last_modified, document.get(config.ETAG), 304 if version == 'all' or version == 'diffs': # find all versions lookup[versioned_id_field()] = lookup[app.config['ID_FIELD']] del lookup[app.config['ID_FIELD']] if version == 'diffs' or req.sort is None: # default sort for 'all', required sort for 'diffs' req.sort = '[("%s", 1)]' % config.VERSION req.if_modified_since = None # we always want the full history here cursor = app.data.find(resource + config.VERSIONS, req, lookup) # build all versions documents = [] if cursor.count() == 0: # this is the scenario when the document existed before # document versioning got turned on documents.append(latest_doc) else: last_document = {} # if we aren't starting on page 1, then we need to init last_doc if version == 'diffs' and req.page > 1: # grab the last document on the previous page to diff from last_version = cursor[0][app.config['VERSION']] - 1 last_document = get_old_document( resource, req, lookup, latest_doc, last_version) for i, document in enumerate(cursor): document = synthesize_versioned_document( latest_doc, document, resource_def) build_response_document( document, resource, embedded_fields, latest_doc) if version == 'diffs': if i == 0: documents.append(document) else: documents.append(diff_document( resource_def, last_document, document)) last_document = document else: documents.append(document) # add documents to response if config.DOMAIN[resource]['hateoas']: response[config.ITEMS] = documents else: response = documents else: response = document # extra hateoas links if config.DOMAIN[resource]['hateoas']: if config.LINKS not in response: response[config.LINKS] = {} response[config.LINKS]['collection'] = { 'title': config.DOMAIN[resource]['resource_title'], 'href': resource_link()} response[config.LINKS]['parent'] = home_link() if version != 'all' and version != 'diffs': # TODO: callbacks not currently supported with ?version=all # notify registered callback functions. Please note that, should # the # functions modify the document, last_modified and etag # won't be updated to reflect the changes (they always reflect the # documents state on the database). getattr(app, "on_fetched_item")(resource, response) getattr(app, "on_fetched_item_%s" % resource)(response) return response, last_modified, etag, 200