From ea4a5111f8f89ec103da41e1dc83ae4fe6823b83 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Wed, 8 Jun 2022 12:43:45 +0200 Subject: [PATCH] api: filter drafts using SQL to honor limit and offset (#66039) --- tests/api/test_user.py | 8 ++++++++ wcs/api.py | 28 ++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/tests/api/test_user.py b/tests/api/test_user.py index 894cbc425..43419176f 100644 --- a/tests/api/test_user.py +++ b/tests/api/test_user.py @@ -441,6 +441,14 @@ def test_user_forms_limit_offset(pub, local_user): formdata.jump_status('new') formdata.store() + for i in range(50): + formdata = formdef.data_class()() + formdata.data = {'0': 'foo@localhost', '1': str(i)} + formdata.user_id = local_user.id + formdata.status = 'draft' + formdata.receipt_time = (datetime.datetime.now() - datetime.timedelta(days=i)).timetuple() + formdata.store() + resp = get_app(pub).get(sign_uri('/api/users/%s/forms' % local_user.id)) assert resp.json['err'] == 0 assert len(resp.json['data']) == 50 diff --git a/wcs/api.py b/wcs/api.py index b62c5c8e3..aae80fd07 100644 --- a/wcs/api.py +++ b/wcs/api.py @@ -53,7 +53,7 @@ from .qommon.errors import ( UnknownNameIdAccessForbiddenError, ) from .qommon.form import ComputedExpressionWidget -from .qommon.storage import Contains, Equal, Intersects, Or, StrictNotEqual +from .qommon.storage import Contains, Equal, Intersects, NotContains, Or, StrictNotEqual from .qommon.template import Template, TemplateError @@ -913,7 +913,7 @@ class ApiUserDirectory(Directory): user_info['user_roles'] = [x.get_json_export_dict() for x in user_roles if x] return json.dumps(user_info, cls=misc.JSONEncoder) - def get_user_forms(self, user): + def get_user_forms(self, user, include_drafts=False, include_non_drafts=True): if not (FormDef.exists()): # early return, this avoids running a query against a missing SQL view. return [] @@ -954,6 +954,23 @@ class ApiUserDirectory(Directory): else: return HttpResponseBadRequest('invalid status parameter value') + if include_drafts: + disabled_formdef_ids = [formdef.id for formdef in FormDef.select() if formdef.is_disabled()] + if disabled_formdef_ids: + criterias.append( + Or( + [ + StrictNotEqual('status', 'draft'), + NotContains('formdef_id', disabled_formdef_ids), + ] + ) + ) + else: + criterias.append(StrictNotEqual('status', 'draft')) + + if not include_non_drafts: + criterias.append(Equal('status', 'draft')) + user_forms = sql.AnyFormData.select( criterias, limit=misc.get_int_or_400(get_request().form.get('limit')), @@ -1010,6 +1027,8 @@ class ApiUserDirectory(Directory): return self.forms(include_drafts=True, include_non_drafts=False) def forms(self, include_drafts=False, include_non_drafts=True): + include_drafts = include_drafts or get_query_flag('include-drafts') + get_response().set_content_type('application/json') try: user = self.user or get_user_from_api_query_string() or get_request().user @@ -1024,7 +1043,9 @@ class ApiUserDirectory(Directory): if query_user and query_user.is_api_user and query_user.api_access.restrict_to_anonymised_data: raise AccessForbiddenError('restricted API access') - forms = self.get_user_forms(user) + forms = self.get_user_forms( + user, include_drafts=include_drafts, include_non_drafts=include_non_drafts + ) if self.user: # call to /api/users//forms, this returns the forms of the @@ -1048,7 +1069,6 @@ class ApiUserDirectory(Directory): # ignore confidential forms forms = [x for x in forms if x.readable or not x.formdef.skip_from_360_view] - include_drafts = include_drafts or get_query_flag('include-drafts') result = [] for form in forms: if form.is_draft(): -- 2.35.1