api: remove include-{drafts,own} flags from /api/forms/ (#56639)

This commit is contained in:
Frédéric Péters 2021-09-03 19:52:46 +02:00
parent ef24d19cab
commit d9501f88bf
3 changed files with 74 additions and 142 deletions

View File

@ -1497,13 +1497,21 @@ def test_api_include_anonymised(pub, local_user):
assert len(resp.json['data']) == 9
def test_api_submitter_and_include_drafts(pub, local_user):
def test_globla_forms_api_user_uuid_filter(pub, local_user):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
return
pub.role_class.wipe()
role = pub.role_class(name='test')
role.store()
local_user.roles = [role.id]
local_user.store()
another_user = get_publisher().user_class()
another_user.name = 'Antoher'
another_user.name = 'Another'
another_user.name_identifiers = ['ABCDEF']
another_user.store()
FormDef.wipe()
@ -1512,26 +1520,35 @@ def test_api_submitter_and_include_drafts(pub, local_user):
formdef.fields = [
fields.StringField(id='0', label='foobar', varname='foobar'),
]
formdef.workflow_roles = {'_receiver': role.id}
formdef.store()
data_class = formdef.data_class()
data_class.wipe()
# a submitted form
formdata = data_class()
formdata.data = {'0': 'FOO BAR'}
formdata.user_id = local_user.id
formdata.just_created()
formdata.jump_status('new')
formdata.store()
formdata1 = data_class()
formdata1.data = {'0': 'FOO BAR'}
formdata1.user_id = local_user.id
formdata1.just_created()
formdata1.jump_status('new')
formdata1.store()
# a submitted form for another user
formdata = data_class()
formdata.data = {'0': 'FOO BAR'}
formdata.user_id = another_user.id
formdata.just_created()
formdata.jump_status('new')
formdata.store()
formdata2 = data_class()
formdata2.data = {'0': 'FOO BAR'}
formdata2.user_id = another_user.id
formdata2.just_created()
formdata2.jump_status('new')
formdata2.store()
# another submitted form for another user
formdata3 = data_class()
formdata3.data = {'0': 'FOO BAR'}
formdata3.user_id = another_user.id
formdata3.just_created()
formdata3.jump_status('new')
formdata3.store()
# a draft by user
formdata = data_class()
@ -1547,56 +1564,22 @@ def test_api_submitter_and_include_drafts(pub, local_user):
formdata.status = 'draft'
formdata.store()
resp = get_app(pub).get(sign_uri('/api/forms/?status=all', user=local_user))
assert len(resp.json['data']) == 0
def get_ids(url):
resp = get_app(pub).get(url)
return {int(x['form_number_raw']) for x in resp.json['data']}
resp = get_app(pub).get(sign_uri('/api/forms/?status=all&include-own=on', user=local_user))
assert len(resp.json['data']) == 1
resp = get_ids(sign_uri('/api/forms/?status=all', user=local_user))
assert resp == {formdata1.id, formdata2.id, formdata3.id}
resp = get_app(pub).get(
sign_uri('/api/forms/?status=all&include-own=on&include-drafts=off', user=local_user)
)
assert len(resp.json['data']) == 1
resp = get_ids(sign_uri('/api/forms/?filter-user-uuid=ABCDEF', user=local_user))
assert resp == {formdata2.id, formdata3.id}
resp = get_app(pub).get(
sign_uri('/api/forms/?status=all&include-own=on&include-drafts=on', user=local_user)
)
assert len(resp.json['data']) == 2
resp = get_app(pub).get(
sign_uri('/api/forms/?status=done&include-own=on&include-drafts=on', user=local_user)
)
assert len(resp.json['data']) == 1
# make forms accessible by user, but add filter-user-uuid to ignore them
pub.role_class.wipe()
role = pub.role_class(name='test')
role.store()
local_user.roles = [role.id]
# remove role
local_user.roles = []
local_user.store()
formdef.workflow_roles = {'_receiver': role.id}
formdef.store()
formdef.data_class().rebuild_security()
resp = get_app(pub).get(
sign_uri('/api/forms/?status=all&include-own=on&include-drafts=off', user=local_user)
)
assert len(resp.json['data']) == 2
resp = get_app(pub).get(
sign_uri('/api/forms/?status=all&include-own=on&include-drafts=on', user=local_user)
)
assert len(resp.json['data']) == 3
resp = get_app(pub).get(
sign_uri(
'/api/forms/?status=all&include-own=on&include-drafts=on&filter-user-uuid=0123456789',
user=local_user,
)
)
assert len(resp.json['data']) == 2
resp = get_ids(sign_uri('/api/forms/?status=all', user=local_user))
assert resp == set()
def test_api_ics_formdata(pub, local_user, ics_data):

View File

@ -389,7 +389,6 @@ class ApiFormsDirectory(Directory):
self.check_access()
get_request()._user = get_user_from_api_query_string() or get_request().user
ignore_roles_flag = get_query_flag('ignore-roles')
if get_request().form.get('full') == 'on':
raise RequestError('no such parameter "full"')
@ -402,23 +401,10 @@ class ApiFormsDirectory(Directory):
from wcs import sql
management_directory = ManagementDirectory()
criterias = management_directory.get_global_listing_criterias(
include_own=bool(
get_request()._user and not get_request()._user.is_api_user and get_query_flag('include-own')
),
include_drafts=get_query_flag('include-drafts'),
)
if ignore_roles_flag:
criterias = management_directory.get_global_listing_criterias()
if get_query_flag('ignore-roles'):
roles_criterias = criterias
criterias = management_directory.get_global_listing_criterias(
ignore_user_roles=True,
include_own=bool(
get_request()._user
and not get_request()._user.is_api_user
and get_query_flag('include-own')
),
include_drafts=get_query_flag('include-drafts'),
)
criterias = management_directory.get_global_listing_criterias(ignore_user_roles=True)
if not get_query_flag('include-anonymised', default=True):
criterias.append(st.Null('anonymised'))
@ -434,7 +420,7 @@ class ApiFormsDirectory(Directory):
)
formdatas = sql.AnyFormData.select(criterias, order_by=order_by, limit=limit, offset=offset)
if ignore_roles_flag:
if get_query_flag('ignore-roles'):
# When ignoring roles formdatas will be returned even if they are
# not readable by the user, an additional attribute (readable) is
# added to differentiate readable and non-readable formdatas.
@ -447,24 +433,21 @@ class ApiFormsDirectory(Directory):
roles_criterias, order_by=order_by, limit=limit, offset=offset
)
]
output = []
for formdata in formdatas:
if ignore_roles_flag:
output = []
for formdata in formdatas:
readable = bool((formdata.formdef.id, formdata.id) in limited_formdatas)
if not readable and formdata.formdef.skip_from_360_view:
continue
else:
# do not consider skip_from_360_view when not ignoring roles;
# it could actually be useful when filtering on a specific user,
# as it's available in /api/users/<id>/forms but this is
# ignored for now.
readable = True
formdata_dict = get_formdata_dict(
formdata, user=get_request().user, consider_status_visibility=False
)
formdata_dict['readable'] = readable
output.append(formdata_dict)
formdata_dict = get_formdata_dict(
formdata, user=get_request().user, consider_status_visibility=False
)
formdata_dict['readable'] = readable
output.append(formdata_dict)
else:
output = [
get_formdata_dict(x, user=get_request().user, consider_status_visibility=False)
for x in formdatas
]
get_response().set_content_type('application/json')
return json.dumps({'data': output}, cls=misc.JSONEncoder)

View File

@ -65,7 +65,6 @@ from ..qommon.form import (
)
from ..qommon.misc import C_, ellipsize
from ..qommon.storage import (
And,
Contains,
Equal,
FtsMatch,
@ -515,16 +514,14 @@ class ManagementDirectory(Directory):
r += htmltext('</ul>')
return r.getvalue()
def get_global_listing_criterias(self, ignore_user_roles=False, include_own=False, include_drafts=False):
def get_global_listing_criterias(self, ignore_user_roles=False):
parsed_values = {}
user_roles = [logged_users_role().id]
if get_request().user:
user_roles.extend(get_request().user.get_roles())
criterias = get_global_criteria(get_request(), parsed_values, include_drafts=include_drafts)
criterias = get_global_criteria(get_request(), parsed_values)
query_parameters = (get_request().form or {}).copy()
query_parameters.pop('callback', None) # when using jsonp
status = query_parameters.get('status', 'waiting')
if query_parameters.get('waiting') == 'yes':
# compatibility with ?waiting=yes|no parameter, still used in
@ -532,50 +529,21 @@ class ManagementDirectory(Directory):
status = 'waiting'
elif query_parameters.get('waiting') == 'no':
status = 'open'
roles_array_column = 'concerned_roles_array'
status_criterias = []
if status == 'waiting':
status_criterias.append(Equal('is_at_endpoint', False))
roles_array_column = 'actions_roles_array'
criterias.append(Equal('is_at_endpoint', False))
if not ignore_user_roles:
criterias.append(Intersects('actions_roles_array', user_roles))
elif status == 'open':
status_criterias.append(Equal('is_at_endpoint', False))
criterias.append(Equal('is_at_endpoint', False))
if not ignore_user_roles:
criterias.append(Intersects('concerned_roles_array', user_roles))
elif status == 'done':
status_criterias.append(Equal('is_at_endpoint', True))
if not ignore_user_roles:
roles_criteria = Intersects(roles_array_column, user_roles)
if include_own and get_request().user and not get_request().user.is_api_user:
roles_criteria = Or(
[
roles_criteria,
And(
[
Equal('user_id', str(get_request().user.id)),
Intersects(roles_array_column, ['_submitter']),
]
),
]
)
status_criterias.append(roles_criteria)
if include_drafts and get_request().user and not get_request().user.is_api_user:
# include user drafts, without any endpoint / roles array criteria
status_criterias = [
Or(
[
And(status_criterias),
And(
[
Equal('status', 'draft'),
Equal('user_id', str(get_request().user.id)),
]
),
]
)
]
criterias.extend(status_criterias)
criterias.append(Equal('is_at_endpoint', True))
if not ignore_user_roles:
criterias.append(Intersects('concerned_roles_array', user_roles))
elif status == 'all':
if not ignore_user_roles:
criterias.append(Intersects('concerned_roles_array', user_roles))
name_id = query_parameters.get('filter-user-uuid')
if name_id:
@ -3500,15 +3468,13 @@ $(document).ready(function(){
return r.getvalue()
def get_global_criteria(request, parsed_values=None, include_drafts=False):
def get_global_criteria(request, parsed_values=None):
"""
Parses the request query string and returns a list of criterias suitable
for select() usage. The parsed_values parameter can be given a dictionary,
to be filled with the parsed values.
"""
criterias = []
if not include_drafts:
criterias.append(NotEqual('status', 'draft'))
criterias = [NotEqual('status', 'draft')]
try:
period_start = misc.get_as_datetime(request.form.get('start')).timetuple()
criterias.append(GreaterOrEqual('receipt_time', period_start))