From 82b02b390ae9a5aef1e4e13e98468f882b902e58 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 26 Feb 2016 10:49:56 +0100 Subject: [PATCH 1/2] add anonymise parameter to JSON exports of formdata (#9146) - FormData.get_json_export_dict(), .get_json_dict(), .export_to_json(), FormDefUI.get_listing_items(), .export_to_json() get a new anonymise parameter. - in FormPage.json() and FormStatusPage().json if an anonymise parameter is present in the query string the anonymized mode is activated. --- wcs/backoffice/management.py | 10 +++++---- wcs/formdata.py | 50 ++++++++++++++++++++++++-------------------- wcs/forms/backoffice.py | 6 +++--- wcs/forms/common.py | 19 +++++++++++------ 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py index 450085e..aa764d9 100644 --- a/wcs/backoffice/management.py +++ b/wcs/backoffice/management.py @@ -1423,18 +1423,20 @@ class FormPage(Directory): return exporter.output.getvalue() def json(self): + anonymise = 'anonymise' in get_request().form self.check_access() get_response().set_content_type('application/json') - user = get_user_from_api_query_string() or get_request().user + user = get_user_from_api_query_string() or get_request().user if not anonymise else None selected_filter = self.get_filter_from_query(default='all') criterias = self.get_criterias_from_query() order_by = get_request().form.get('order_by', None) - query = get_request().form.get('q') + query = get_request().form.get('q') if not anonymise else None items, total_count = FormDefUI(self.formdef).get_listing_items( selected_filter, user=user, query=query, criterias=criterias, - order_by=order_by) + order_by=order_by, anonymise=anonymise) if get_request().form.get('full') == 'on': - output = [filled.get_json_export_dict(include_files=False) for filled in items] + output = [filled.get_json_export_dict(include_files=False, anonymise=anonymise) + for filled in items] else: output = [{'id': filled.id, 'url': filled.get_url(), diff --git a/wcs/formdata.py b/wcs/formdata.py index b78143e..966f22e 100644 --- a/wcs/formdata.py +++ b/wcs/formdata.py @@ -97,9 +97,11 @@ def flatten_dict(d): del d[k] -def get_json_dict(fields, data, include_files=True): +def get_json_dict(fields, data, include_files=True, anonymise=False): new_data = {} for field in fields: + if anonymise and field.anonymise: + continue if not field.varname: # exports only named fields continue if not include_files and isinstance(field, FileField): @@ -674,7 +676,7 @@ class FormData(StorableObject): evo.parts = None self.store() - def get_json_export_dict(self, include_files=True): + def get_json_export_dict(self, include_files=True, anonymise=False): data = {} data['id'] = '%s/%s' % (self.formdef.url_name, self.id) data['display_id'] = self.get_display_id() @@ -686,33 +688,35 @@ class FormData(StorableObject): data['criticality_level'] = self.criticality_level data['url'] = self.get_url() - try: - user = get_publisher().user_class.get(self.user_id) - except KeyError: - user = None - # this is custom code so it is possible to mark forms as anonyms, this - # is done through the VoteAnonymity field, this is very specific but - # isn't generalised yet into an useful extension mechanism, as it's not - # clear at the moment what could be useful. - for f in self.formdef.fields: - if f.key == 'vote-anonymity': + if not anonymise: + try: + user = get_publisher().user_class.get(self.user_id) + except KeyError: user = None - break - if user: - data['user'] = {'id': user.id, 'name': user.display_name} - if user.email: - data['user']['email'] = user.email - if user.name_identifiers: - data['user']['NameID'] = user.name_identifiers + # this is custom code so it is possible to mark forms as anonyms, this + # is done through the VoteAnonymity field, this is very specific but + # isn't generalised yet into an useful extension mechanism, as it's not + # clear at the moment what could be useful. + for f in self.formdef.fields: + if f.key == 'vote-anonymity': + user = None + break + if user: + data['user'] = {'id': user.id, 'name': user.display_name} + if user.email: + data['user']['email'] = user.email + if user.name_identifiers: + data['user']['NameID'] = user.name_identifiers data['fields'] = get_json_dict(self.formdef.fields, self.data, - include_files=include_files) + include_files=include_files, anonymise=anonymise) data['workflow'] = {} wf_status = self.get_visible_status() if wf_status: data['workflow']['status'] = {'id': wf_status.id, 'name': wf_status.name} - if self.workflow_data: + # Workflow data have unknown purpose, do not store them in anonymised export + if self.workflow_data and not anonymise: data['workflow']['data'] = self.workflow_data # add a roles dictionary, with workflow functions and two special @@ -744,8 +748,8 @@ class FormData(StorableObject): return data - def export_to_json(self, include_files=True): - data = self.get_json_export_dict(include_files=include_files) + def export_to_json(self, include_files=True, anonymise=False): + data = self.get_json_export_dict(include_files=include_files, anonymise=anonymise) return json.dumps(data, cls=qommon.misc.JSONEncoder, encoding=get_publisher().site_charset) diff --git a/wcs/forms/backoffice.py b/wcs/forms/backoffice.py index 3ae9e54..431c443 100644 --- a/wcs/forms/backoffice.py +++ b/wcs/forms/backoffice.py @@ -143,7 +143,7 @@ class FormDefUI(object): return r.getvalue() def get_listing_items(self, selected_filter='all', offset=None, - limit=None, query=None, order_by=None, user=None, criterias=None): + limit=None, query=None, order_by=None, user=None, criterias=None, anonymise=False): formdata_class = self.formdef.data_class() if selected_filter == 'all': item_ids = formdata_class.keys() @@ -172,7 +172,7 @@ class FormDefUI(object): select_ids = [x.id for x in formdata_class.select(clause=criterias)] item_ids = list(set(item_ids).intersection(select_ids)) - if item_ids: + if item_ids and not anonymise: # as we are in the backoffice, we don't have to care about the # situation where the user is the submitter, and we limit ourselves # to consider treating roles. @@ -185,7 +185,7 @@ class FormDefUI(object): 'concerned_roles', str(role))) item_ids = list(set(item_ids).intersection(concerned_ids)) - if order_by: + if order_by and not anonymise: ordered_ids = formdata_class.get_sorted_ids(order_by) new_item_ids = [] for item_id in ordered_ids: diff --git a/wcs/forms/common.py b/wcs/forms/common.py index 5ec9fd1..48ea23e 100644 --- a/wcs/forms/common.py +++ b/wcs/forms/common.py @@ -21,7 +21,7 @@ from quixote import get_publisher, get_request, get_response, get_session, redir from quixote.directory import Directory from quixote.html import TemplateIO, htmltext -from wcs.api_utils import get_user_from_api_query_string +from wcs.api_utils import get_user_from_api_query_string, is_url_signed from wcs.fields import WidgetField, FileField from wcs import file_validation from wcs.workflows import EditableWorkflowStatusItem @@ -135,14 +135,20 @@ class FormStatusPage(Directory): session = get_session() mine = False if api_call: - user = get_user_from_api_query_string() or get_request().user + if 'anonymise' in get_request().form: + if is_url_signed() or (get_request().user and get_request().user.is_admin): + return None + else: + raise errors.AccessUnauthorizedError() + else: + user = get_user_from_api_query_string() or get_request().user else: user = get_request().user if user and not user.anonymous: if self.filled.is_submitter(user): mine = True else: - if get_session() and get_session().is_anonymous_submitter(self.filled): + if session and session.is_anonymous_submitter(self.filled): mine = True self.check_receiver() @@ -150,7 +156,8 @@ class FormStatusPage(Directory): def json(self): self.check_auth(api_call=True) - return self.export_to_json() + anonymise = 'anonymise' in get_request().form + return self.export_to_json(anonymise=anonymise) def workflow_messages(self): if self.formdef.workflow: @@ -250,9 +257,9 @@ class FormStatusPage(Directory): r += self.form_status_buttons() return r.getvalue() - def export_to_json(self): + def export_to_json(self, anonymise=False): get_response().set_content_type('application/json') - return self.filled.export_to_json() + return self.filled.export_to_json(anonymise=anonymise) def form_status_buttons(self): if not get_response().iframe_mode: -- 2.1.4