blob: 16e66faf23e65e99ae884db6f733d8404b4a2f32 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2020 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file.
4
5from __future__ import print_function
6from __future__ import division
7from __future__ import absolute_import
8
9from framework import exceptions
10from framework import paginate
11from proto import secrets_pb2
12
13
14def CoercePageSize(page_size, max_size, default_size=None):
15 # type: (int, int, Optional[int]) -> int
16 """Validates page_size and coerces it to max_size if needed.
17
18 Args:
19 page_size: The page_size requested by the user.
20 max_size: the maximum page size allowed. Must be > 0.
21 Also used as default if default_size not provided
22 default_size: default size to use if page_size not provided. Must be > 0.
23
24 Returns:
25 The appropriate page size to use for the request, based on the parameters.
26 Specifically this means
27 - page_size if not greater than max_size
28 - max_size if page_size > max_size
29 - max_size if page_size is not provided and default_size is not provided
30 - default_size if page_size is not provided
31
32 Raises:
33 InputException: if page_size is negative.
34 """
35 # These are programming errors. They are not user input.
36 assert max_size > 0
37 assert default_size is None or default_size > 0
38
39 # Check for invalid user provided page_size.
40 if page_size and page_size < 0:
41 raise exceptions.InputException('`page_size` cannot be negative.')
42
43 if not page_size:
44 return default_size or max_size
45 if page_size > max_size:
46 return max_size
47 return page_size
48
49
50class Paginator(object):
51 """Class to manage API pagination.
52
53 Paginator handles the pagination tasks and info of a single List or
54 Search API method implementation, given the contents of the request.
55 """
56
57 def __init__(self, parent=None, page_size=None, order_by=None,
58 filter_str=None, query=None, projects=None):
59 # type: (Optional[str], Optional[int], Optional[str], Optional[str],
60 # Optional[str], Optional[Collection[str]]]) -> None
61 self.request_contents = secrets_pb2.ListRequestContents(
62 parent=parent, page_size=page_size, order_by=order_by,
63 filter=filter_str, query=query, projects=projects)
64
65 def GetStart(self, page_token):
66 # type: (Optional[str]) -> int
67 """Validates a request.page_token and returns the start index for it."""
68 if page_token:
69 # TODO(crbug.com/monorail/6758): Proto string fields are unicode types in
70 # python 2. In python 3 these unicode strings will be represented with
71 # string types. paginate.ValidateAndParsePageToken requires a string token
72 # during validation (compare_digest()). Once we move to python 3, we can
73 # remove this string casting.
74 token = str(page_token)
75 return paginate.ValidateAndParsePageToken(token, self.request_contents)
76 return 0
77
78 def GenerateNextPageToken(self, next_start):
79 # type: (Optional[int]) -> str
80 """Generates the `next_page_token` for the API response.
81
82 Args:
83 next_start: The start index of the next page, or None if no more results.
84
85 Returns:
86 A string clients can use to request the next page. Returns None if
87 next_start was None
88 """
89 if next_start is None:
90 return None
91 return paginate.GeneratePageToken(self.request_contents, next_start)