-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rest: Add pagination support #1361
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -449,6 +449,19 @@ | |
# read-only from _prefix_spec | ||
_prefix_attrs = {k: v for k, v in _prefix_spec.items() if not _prefix_spec[k]['ro']} | ||
|
||
|
||
# list of all available search options on a prefix | ||
prefix_search_options_spec = { | ||
'parents_depth': 0, | ||
'children_depth': 0, | ||
'include_all_parents': False, | ||
'include_all_children': False, | ||
'include_neighbors': False, | ||
'max_result': 50, | ||
'offset': 0 | ||
} | ||
|
||
|
||
# list of all attributes on a vrf, including both writable and read-only values | ||
_vrf_spec = { | ||
'avps': { | ||
|
@@ -3091,6 +3104,7 @@ def search_prefix(self, auth, query, search_options=None): | |
* :attr:`children_depth` - How many levels of children to return. Set to :data:`-1` to include all children. | ||
* :attr:`include_all_parents` - Include all parents, no matter what depth is specified. | ||
* :attr:`include_all_children` - Include all children, no matter what depth is specified. | ||
* :attr:`include_neighbors` - Include neighbors. | ||
* :attr:`max_result` - The maximum number of prefixes to return (default :data:`50`). | ||
* :attr:`offset` - Offset the result list this many prefixes (default :data:`0`). | ||
|
||
|
@@ -3124,7 +3138,7 @@ def search_prefix(self, auth, query, search_options=None): | |
|
||
# include_parents | ||
if 'include_all_parents' not in search_options: | ||
search_options['include_all_parents'] = False | ||
search_options['include_all_parents'] = prefix_search_options_spec['include_all_parents'] | ||
else: | ||
if search_options['include_all_parents'] not in (True, False): | ||
raise NipapValueError( | ||
|
@@ -3133,15 +3147,15 @@ def search_prefix(self, auth, query, search_options=None): | |
|
||
# include_children | ||
if 'include_all_children' not in search_options: | ||
search_options['include_all_children'] = False | ||
search_options['include_all_children'] = prefix_search_options_spec['include_all_children'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (103 > 79 characters) |
||
else: | ||
if search_options['include_all_children'] not in (True, False): | ||
raise NipapValueError("Invalid value for option 'include_all_children'. Only true and false valid. " | ||
"Supplied value: '{}'".format(search_options['include_all_children'])) | ||
|
||
# parents_depth | ||
if 'parents_depth' not in search_options: | ||
search_options['parents_depth'] = 0 | ||
search_options['parents_depth'] = prefix_search_options_spec['parents_depth'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (89 > 79 characters) |
||
else: | ||
try: | ||
search_options['parents_depth'] = int(search_options['parents_depth']) | ||
|
@@ -3150,7 +3164,7 @@ def search_prefix(self, auth, query, search_options=None): | |
|
||
# children_depth | ||
if 'children_depth' not in search_options: | ||
search_options['children_depth'] = 0 | ||
search_options['children_depth'] = prefix_search_options_spec['children_depth'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (91 > 79 characters) |
||
else: | ||
try: | ||
search_options['children_depth'] = int(search_options['children_depth']) | ||
|
@@ -3159,15 +3173,15 @@ def search_prefix(self, auth, query, search_options=None): | |
|
||
# include_neighbors | ||
if 'include_neighbors' not in search_options: | ||
search_options['include_neighbors'] = False | ||
search_options['include_neighbors'] = prefix_search_options_spec['include_neighbors'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (97 > 79 characters) |
||
else: | ||
if search_options['include_neighbors'] not in (True, False): | ||
raise NipapValueError("Invalid value for option 'include_neighbors'. Only true and false valid. " | ||
"Supplied value: '{}'".format(search_options['include_neighbors'])) | ||
|
||
# max_result | ||
if 'max_result' not in search_options: | ||
search_options['max_result'] = 50 | ||
search_options['max_result'] = prefix_search_options_spec['max_result'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (83 > 79 characters) |
||
else: | ||
if search_options['max_result'] in (False, None): | ||
search_options['max_result'] = None | ||
|
@@ -3179,7 +3193,7 @@ def search_prefix(self, auth, query, search_options=None): | |
|
||
# offset | ||
if 'offset' not in search_options: | ||
search_options['offset'] = 0 | ||
search_options['offset'] = prefix_search_options_spec['offset'] | ||
else: | ||
try: | ||
search_options['offset'] = int(search_options['offset']) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,7 @@ | |
from flask import Flask, request, Response, got_request_exception, jsonify | ||
from flask_restful import Resource, Api, abort | ||
|
||
from .backend import Nipap, NipapError | ||
from .backend import Nipap, NipapError, prefix_search_options_spec | ||
import nipap | ||
from .authlib import AuthFactory, AuthError | ||
|
||
|
@@ -219,11 +219,15 @@ def get(self, args): | |
|
||
query = args.get('prefix') | ||
search_query = {} | ||
search_options = {} | ||
if query is not None: | ||
# Create search query dict from request params | ||
query_parts = [] | ||
for field, search_value in list(query.items()): | ||
query_parts.append(get_query_for_field(field, search_value)) | ||
for field, value in list(query.items()): | ||
if field in prefix_search_options_spec.keys(): | ||
search_options[field] = value | ||
else: | ||
query_parts.append(get_query_for_field(field, value)) | ||
search_query = query_parts[0] | ||
for query_part in query_parts[1:]: | ||
search_query = { | ||
|
@@ -233,7 +237,7 @@ def get(self, args): | |
} | ||
|
||
try: | ||
result = self.nip.search_prefix(args.get('auth'), search_query) | ||
result = self.nip.search_prefix(args.get('auth'), search_query, search_options) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (91 > 79 characters) |
||
|
||
# mangle result | ||
result['result'] = [ _mangle_prefix(prefix) for prefix in result['result'] ] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -481,6 +481,45 @@ def test_prefix_search_error_message(self): | |
|
||
self.assertTrue(get_prefix_request.text.__contains__('\'prefixeere\' unknown')) | ||
|
||
def test_prefix_pagination(self): | ||
""" Add prefixes with the same order_id, expect different number of prefixes in result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (86 > 79 characters) |
||
using max_result and offset | ||
""" | ||
|
||
# add test prefixes 1.33.[0-59].0/24 | ||
attr = {} | ||
attr['description'] = 'test edit prefix' | ||
attr['type'] = 'assignment' | ||
attr['order_id'] = 'test_rest' | ||
for i in range(0, 60): | ||
attr['prefix'] = '1.33.' + str(i) + '.0/24' | ||
self._add_prefix(attr) | ||
|
||
parameters = {'order_id': 'test_rest'} | ||
|
||
# Test default max result of 50 amd offset 0 | ||
get_prefix_request = requests.get(self.server_url, headers=self.headers, params=parameters) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (99 > 79 characters) |
||
result = json.loads(get_prefix_request.text) | ||
self.assertEqual(50, len(result)) | ||
self.assertEqual(result[0]['prefix'], '1.33.0.0/24') | ||
self.assertEqual(result[49]['prefix'], '1.33.49.0/24') | ||
|
||
# Test max result 100 | ||
parameters['max_result'] = 60 | ||
get_prefix_request = requests.get(self.server_url, headers=self.headers, params=parameters) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (99 > 79 characters) |
||
result = json.loads(get_prefix_request.text) | ||
self.assertEqual(60, len(result)) | ||
self.assertEqual(result[0]['prefix'], '1.33.0.0/24') | ||
self.assertEqual(result[59]['prefix'], '1.33.59.0/24') | ||
|
||
# Test offset 75 | ||
parameters['offset'] = 35 | ||
get_prefix_request = requests.get(self.server_url, headers=self.headers, params=parameters) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line too long (99 > 79 characters) |
||
result = json.loads(get_prefix_request.text) | ||
self.assertEqual(25, len(result)) | ||
self.assertEqual(result[0]['prefix'], '1.33.35.0/24') | ||
self.assertEqual(result[24]['prefix'], '1.33.59.0/24') | ||
|
||
|
||
if __name__ == '__main__': | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line too long (101 > 79 characters)