From 7f6fe74074f66301a87de7ce066c13fce6c9cede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Sun, 3 Jan 2016 14:05:46 +0100 Subject: [PATCH] formdata: always create a display identifier (#9135) --- tests/test_backoffice_pages.py | 58 ++++++++++++++++++++---------------------- tests/test_formdata.py | 12 +++++++-- tests/test_workflows.py | 8 +++--- wcs/formdata.py | 17 ++++++++++++- wcs/formdef.py | 8 ++++++ wcs/forms/common.py | 2 +- wcs/sql.py | 6 +++++ 7 files changed, 73 insertions(+), 38 deletions(-) diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py index 54cb98c..26114bb 100644 --- a/tests/test_backoffice_pages.py +++ b/tests/test_backoffice_pages.py @@ -457,7 +457,7 @@ def test_backoffice_handling(pub): create_user(pub) create_environment(pub) form_class = FormDef.get_by_urlname('form-title').data_class() - number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0].id + number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0] app = login(get_app(pub)) resp = app.get('/backoffice/management/form-title/') assert re.findall('', resp.body, re.DOTALL)[0].count('Foo

' in resp.body # add an info text to the button commentable.backoffice_info_text = '

Bar

' workflow.store() - resp = app.get('/backoffice/management/form-title/%s/' % number31) + resp = app.get('/backoffice/management/form-title/%s/' % number31.id) assert 'backoffice-description' in resp.body assert '

Foo

' in resp.body assert '

Bar

' in resp.body @@ -608,7 +607,7 @@ def test_backoffice_info_text(pub): # remove info text from the status st1.backoffice_info_text = None workflow.store() - resp = app.get('/backoffice/management/form-title/%s/' % number31) + resp = app.get('/backoffice/management/form-title/%s/' % number31.id) assert 'backoffice-description' in resp.body assert not '

Foo

' in resp.body assert '

Bar

' in resp.body @@ -616,7 +615,7 @@ def test_backoffice_info_text(pub): # add info text to second button commentable2.backoffice_info_text = '

Baz

' workflow.store() - resp = app.get('/backoffice/management/form-title/%s/' % number31) + resp = app.get('/backoffice/management/form-title/%s/' % number31.id) assert 'backoffice-description' in resp.body assert not '

Foo

' in resp.body assert '

Bar

' in resp.body @@ -625,7 +624,7 @@ def test_backoffice_info_text(pub): # remove info text from first button commentable.backoffice_info_text = None workflow.store() - resp = app.get('/backoffice/management/form-title/%s/' % number31) + resp = app.get('/backoffice/management/form-title/%s/' % number31.id) assert not 'backoffice-description' in resp.body def test_backoffice_handling_post_dispatch(pub): @@ -638,18 +637,18 @@ def test_backoffice_handling_post_dispatch(pub): user1.store() create_environment(pub) form_class = FormDef.get_by_urlname('form-title').data_class() - number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0].id + number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0] app = login(get_app(pub)) # check there's no access at the moment resp = app.get('/backoffice/management/') assert not 'form-title/' in resp.body resp = app.get('/backoffice/management/form-title/', status=403) - resp = app.get('/backoffice/management/form-title/%s/' % number31, status=403) + resp = app.get('/backoffice/management/form-title/%s/' % number31.id, status=403) # emulate a dispatch (setting formdata.workflow_roles), receiver of that # formdata is now the local role we gave to the user. - formdata31 = form_class.get(number31) + formdata31 = form_class.get(number31.id) formdata31.workflow_roles = {'_receiver': role.id} formdata31.store() @@ -669,12 +668,12 @@ def test_backoffice_handling_post_dispatch(pub): # check formdata is accessible, and that it's possible to perform an action # on it. - resp = resp.click(href='%s/' % number31) - assert (' with the number %s.' % number31) in resp.body + resp = resp.click(href='%s/' % number31.id) + assert (' with the number %s.' % number31.get_display_id()) in resp.body resp.forms[0]['comment'] = 'HELLO WORLD' resp = resp.forms[0].submit('button_accept') resp = resp.follow() - assert FormDef.get_by_urlname('form-title').data_class().get(number31).status == 'wf-accepted' + assert FormDef.get_by_urlname('form-title').data_class().get(number31.id).status == 'wf-accepted' assert 'HELLO WORLD' in resp.body def test_global_statisticspub(pub): @@ -1073,12 +1072,11 @@ def test_backoffice_wscall_failure_display(pub): formdef = FormDef.get_by_urlname('form-title') form_class = formdef.data_class() - number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0].id - number31_status = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0].status + number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0] # attach a custom workflow workflow = Workflow(name='wscall') - st1 = workflow.add_status('Status1', number31_status.split('-')[1]) + st1 = workflow.add_status('Status1', number31.status.split('-')[1]) wscall = WebserviceCallStatusItem() wscall.id = '_wscall' @@ -1104,16 +1102,16 @@ def test_backoffice_wscall_failure_display(pub): app = login(get_app(pub)) - resp = app.get('/backoffice/management/form-title/%s/' % number31) - assert (' with the number %s.' % number31) in resp.body + resp = app.get('/backoffice/management/form-title/%s/' % number31.id) + assert (' with the number %s.' % number31.get_display_id()) in resp.body assert 'Again' in resp.body resp = resp.forms[0].submit('button_again') resp = resp.follow() assert 'Error during webservice call' in resp.body # the failure message shouldn't be displayed in the frontoffice - resp = app.get('/form-title/%s/' % number31) - assert (' with the number %s.' % number31) in resp.body + resp = app.get('/form-title/%s/' % number31.id) + assert (' with the number %s.' % number31.get_display_id()) in resp.body assert not 'Error during webservice call' in resp.body def test_backoffice_wfedit(pub): @@ -1141,7 +1139,7 @@ def test_backoffice_wfedit(pub): app = login(get_app(pub)) resp = app.get('/backoffice/management/form-title/%s/' % number31.id) - assert (' with the number %s.' % number31.id) in resp.body + assert (' with the number %s.' % number31.get_display_id()) in resp.body resp = resp.form.submit('button_wfedit') resp = resp.follow() assert resp.form['f1'].value == number31.data['1'] @@ -1264,7 +1262,7 @@ def test_backoffice_sidebar_user_context(pub): # click on a formdata resp = resp.click(href='%s/' % number31.id) - assert (' with the number %s.' % number31.id) in resp.body + assert (' with the number %s.' % number31.get_display_id()) in resp.body # check there's nothing in the sidebar assert not 'User Pending Forms' in resp.body diff --git a/tests/test_formdata.py b/tests/test_formdata.py index e71b074..366b456 100644 --- a/tests/test_formdata.py +++ b/tests/test_formdata.py @@ -53,13 +53,21 @@ def test_saved(pub): formdata = formdef.data_class()() formdata.store() substvars = formdata.get_substitution_variables() - assert substvars.get('form_number') == '1' + assert substvars.get('form_number') == '%s-1' % formdef.id assert substvars.get('form_number_raw') == '1' assert substvars.get('form_url').endswith('/foobar/1/') assert substvars.get('form_url_backoffice').endswith('/backoffice/management/foobar/1/') assert substvars.get('form_status_url').endswith('/foobar/1/status') -def test_display_id(pub): +def test_auto_display_id(pub): + formdef.data_class().wipe() + formdata = formdef.data_class()() + formdata.store() + substvars = formdata.get_substitution_variables() + assert substvars.get('form_number') == '%s-%s' % (formdef.id, formdata.id) + assert substvars.get('form_number_raw') == str(formdata.id) + +def test_manual_display_id(pub): formdef.data_class().wipe() formdata = formdef.data_class()() formdata.id_display = 'bar' diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 4b55f01..1b65900 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -404,7 +404,7 @@ def test_webservice_call(pub): assert http_requests.get_last('method') == 'POST' payload = json.loads(http_requests.get_last('body')) assert payload['url'] == 'http://example.net/baz/%s/' % formdata.id - assert int(payload['display_id']) == 1 + assert payload['display_id'] == formdata.get_display_id() item = WebserviceCallStatusItem() item.url = 'http://remote.example.net' @@ -423,7 +423,7 @@ def test_webservice_call(pub): assert http_requests.get_last('url') == 'http://remote.example.net' assert http_requests.get_last('method') == 'POST' payload = json.loads(http_requests.get_last('body')) - assert payload == {'one': 1, 'str': 'abcd', 'evalme': formdata.id} + assert payload == {'one': 1, 'str': 'abcd', 'evalme': formdata.get_display_id()} item = WebserviceCallStatusItem() item.url = 'http://remote.example.net' @@ -434,9 +434,9 @@ def test_webservice_call(pub): assert http_requests.get_last('url') == 'http://remote.example.net' assert http_requests.get_last('method') == 'POST' payload = json.loads(http_requests.get_last('body')) - assert payload['extra'] == {'one': 1, 'str': 'abcd', 'evalme': formdata.id} + assert payload['extra'] == {'one': 1, 'str': 'abcd', 'evalme': formdata.get_display_id()} assert payload['url'] == 'http://example.net/baz/%s/' % formdata.id - assert int(payload['display_id']) == 1 + assert payload['display_id'] == formdata.get_display_id() item = WebserviceCallStatusItem() item.url = 'http://remote.example.net/json' diff --git a/wcs/formdata.py b/wcs/formdata.py index 9c30379..7ceaced 100644 --- a/wcs/formdata.py +++ b/wcs/formdata.py @@ -18,6 +18,7 @@ import copy import datetime import json import re +from cStringIO import StringIO import sys import time @@ -26,6 +27,7 @@ from quixote.http_request import Upload from qommon.storage import StorableObject import qommon.misc +from qommon import ezt from qommon.substitution import Substitutions from roles import Role @@ -71,7 +73,7 @@ def get_dict_with_varnames(fields, data, formdata=None, varnames_only=False): formdata.get_url(), field.id) elif raw_value: new_data['var_%s_raw' % field.varname] = raw_value - if field.store_structured_value: + if field.store_structured_value and data is not None: structured_value = data.get('%s_structured' % field.id) if type(structured_value) is dict: for k, v in structured_value.items(): @@ -211,6 +213,10 @@ class FormData(StorableObject): setattr(sys.modules['formdef'], self._formdef.url_name.title(), self.__class__) setattr(sys.modules['wcs.formdef'], self._formdef.url_name.title(), self.__class__) super(FormData, self).store(*args, **kwargs) + if not self.id_display: + self.set_auto_display_id() + if self.id_display: + self.store(*args, **kwargs) def get_user(self): if self.user_id and self.user_id != 'ultra-user': @@ -256,6 +262,15 @@ class FormData(StorableObject): evo.status = self.status self.evolution = [evo] + def set_auto_display_id(self): + processor = ezt.Template(compress_whitespace=True) + processor.parse(self.formdef.get_display_id_format().strip()) + fd = StringIO() + ctx = self.get_substitution_variables(minimal=True) + ctx['formdef_id'] = self.formdef.id + processor.generate(fd, ctx) + self.id_display = fd.getvalue() + def perform_workflow(self): url = None get_publisher().substitutions.feed(self) diff --git a/wcs/formdef.py b/wcs/formdef.py index 7cc8fde..0a7f48c 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -102,6 +102,10 @@ class FormDef(StorableObject): 'always_advertise', 'private_status_and_history', 'has_captcha', 'skip_from_360_view'] + def __init__(self, *args, **kwargs): + super(FormDef, self).__init__(*args, **kwargs) + self.fields = [] + def migrate(self): changed = False @@ -408,6 +412,8 @@ class FormDef(StorableObject): base_url = get_publisher().get_frontoffice_url() return '%s/%s/' % (base_url, self.url_name) + def get_display_id_format(self): + return '[formdef_id]-[form_number_raw]' def create_form(self, page_no = 0, displayed_fields = None): form = Form(enctype = "multipart/form-data", use_tokens = False) @@ -832,6 +838,8 @@ class FormDef(StorableObject): if isinstance(field, (fields.SubtitleField, fields.TitleField, fields.CommentField, fields.PageField)): continue + if data is None: + continue if data.get(field.id) is None: continue if data.get(field.id + '_display'): diff --git a/wcs/forms/common.py b/wcs/forms/common.py index c04412b..70def1a 100644 --- a/wcs/forms/common.py +++ b/wcs/forms/common.py @@ -462,7 +462,7 @@ class FormStatusPage(Directory): tm = '???' r += htmltext("

") r += _('The form has been recorded on %(date)s with the number %(number)s.') % { - 'date': tm, 'number': self.filled.id} + 'date': tm, 'number': self.filled.get_display_id()} r += htmltext("

") if self.filled.anonymised: diff --git a/wcs/sql.py b/wcs/sql.py index e38da37..858baf4 100644 --- a/wcs/sql.py +++ b/wcs/sql.py @@ -1125,6 +1125,12 @@ class SqlFormData(SqlMixin, wcs.formdata.FormData): cur.execute(sql_statement, sql_dict) self.id = cur.fetchone()[0] + if not self.id_display: + sql_statement = '''UPDATE %s SET id_display = %%(id_display)s + WHERE id = %%(id)s''' % self._table_name + self.set_auto_display_id() + cur.execute(sql_statement, {'id': self.id, 'id_display': self.id_display}) + if self._evolution: for evo in self._evolution: sql_dict = {} -- 2.6.4