From ba050028ca2c3c537e2b02a9cd776242174d6a1c Mon Sep 17 00:00:00 2001 From: sayali Date: Wed, 6 Jan 2021 11:28:18 -0800 Subject: [PATCH] Paginate valid certificate fetch API --- lemur/certificates/service.py | 12 ++++++++++-- lemur/certificates/views.py | 20 ++++++++++++++------ lemur/database.py | 4 +++- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lemur/certificates/service.py b/lemur/certificates/service.py index 5999760f..e6414933 100644 --- a/lemur/certificates/service.py +++ b/lemur/certificates/service.py @@ -563,10 +563,15 @@ def query_common_name(common_name, args): :return: """ owner = args.pop("owner") + page = args.pop("page") + count = args.pop("count") + + paginate = page and count + query = database.session_query(Certificate) if paginate else Certificate.query + # only not expired certificates current_time = arrow.utcnow() - - query = Certificate.query.filter(Certificate.not_after >= current_time.format("YYYY-MM-DD"))\ + query = query.filter(Certificate.not_after >= current_time.format("YYYY-MM-DD"))\ .filter(not_(Certificate.revoked))\ .filter(not_(Certificate.replaced.any())) # ignore rotated certificates to avoid duplicates @@ -577,6 +582,9 @@ def query_common_name(common_name, args): # if common_name is a wildcard ('%'), no need to include it in the query query = query.filter(Certificate.cn.ilike(common_name)) + if paginate: + return database.paginate(query, page, count) + return query.all() diff --git a/lemur/certificates/views.py b/lemur/certificates/views.py index 56d0a9c8..47c076fc 100644 --- a/lemur/certificates/views.py +++ b/lemur/certificates/views.py @@ -51,17 +51,20 @@ class CertificatesListValid(AuthenticatedResource): """ .. http:get:: /certificates/valid/ - The current list of not-expired certificates for a given common name, and owner + The current list of not-expired certificates for a given common name, and owner. The API offers + optional pagination. One can send page number(>=1) and desired count per page. The returned data + contains total number of certificates which can help in determining the last page. Pagination + will not be offered if page or count info is not sent or if it is zero. **Example request**: .. sourcecode:: http - GET /certificates/valid?filter=cn;*.test.example.net&owner=joe@example.com + GET /certificates/valid?filter=cn;*.test.example.net&owner=joe@example.com&page=1&count=20 HTTP/1.1 Host: example.com Accept: application/json, text/javascript - **Example response**: + **Example response (with single cert to be concise)**: .. sourcecode:: http @@ -128,10 +131,15 @@ class CertificatesListValid(AuthenticatedResource): :statuscode 403: unauthenticated """ - parser = paginated_parser.copy() - args = parser.parse_args() + # using non-paginated parser to ensure backward compatibility + self.reqparse.add_argument("filter", type=str, location="args") + self.reqparse.add_argument("owner", type=str, location="args") + self.reqparse.add_argument("count", type=int, location="args") + self.reqparse.add_argument("page", type=int, location="args") + + args = self.reqparse.parse_args() args["user"] = g.user - common_name = args["filter"].split(";")[1] + common_name = args.pop("filter").split(";")[1] return service.query_common_name(common_name, args) diff --git a/lemur/database.py b/lemur/database.py index a9610325..0453c381 100644 --- a/lemur/database.py +++ b/lemur/database.py @@ -225,7 +225,9 @@ def paginate(query, page, count): :param page: :param count: """ - return query.paginate(page, count) + total = get_count(query) + items = query.paginate(page, count).items + return dict(items=items, total=total, current=len(items)) def update_list(model, model_attr, item_model, items):