Skip to content
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

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions nipap/nipap/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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': {
Expand Down Expand Up @@ -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`).

Expand Down Expand Up @@ -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']

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)

else:
if search_options['include_all_parents'] not in (True, False):
raise NipapValueError(
Expand All @@ -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']

Choose a reason for hiding this comment

The 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']

Choose a reason for hiding this comment

The 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'])
Expand All @@ -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']

Choose a reason for hiding this comment

The 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'])
Expand All @@ -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']

Choose a reason for hiding this comment

The 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']

Choose a reason for hiding this comment

The 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
Expand All @@ -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'])
Expand Down
12 changes: 8 additions & 4 deletions nipap/nipap/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 = {
Expand All @@ -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)

Choose a reason for hiding this comment

The 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'] ]
Expand Down
39 changes: 39 additions & 0 deletions tests/test_rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Choose a reason for hiding this comment

The 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)

Choose a reason for hiding this comment

The 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)

Choose a reason for hiding this comment

The 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)

Choose a reason for hiding this comment

The 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__':

Expand Down
Loading