From 9cb8e045c0be63af8c6ad2421f40dfde5ac61cad Mon Sep 17 00:00:00 2001 From: Thomas NOEL Date: Tue, 19 Jun 2018 15:04:19 +0200 Subject: [PATCH] wf/backoffice_fields: log compute errors as functional errors only (#24645) --- tests/test_workflows.py | 38 +++++++++++++++++++++++++++++++++++++ wcs/wf/backoffice_fields.py | 23 ++++++++++++++++++---- wcs/workflows.py | 21 +++++++++++++++++--- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/tests/test_workflows.py b/tests/test_workflows.py index f4e3f91b..f1047c46 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -2972,6 +2972,7 @@ def test_profile(two_pubs): def test_set_backoffice_field(http_requests, two_pubs): Workflow.wipe() FormDef.wipe() + LoggedError.wipe() wf = Workflow(name='xxx') wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) wf.backoffice_fields_formdef.fields = [ @@ -3017,6 +3018,31 @@ def test_set_backoffice_field(http_requests, two_pubs): formdata = formdef.data_class().get(formdata.id) assert formdata.data['bo1'] == 'HELLO GOODBYE' + assert LoggedError.count() == 0 + + item.fields = [{'field_id': 'bo1', 'value': '= ~ invalid python ~'}] + item.perform(formdata) + formdata = formdef.data_class().get(formdata.id) + assert LoggedError.count() == 1 + logged_error = LoggedError.select()[0] + assert logged_error.summary == 'Failed to compute Python expression (error SyntaxError)' + assert logged_error.formdata_id == str(formdata.id) + assert logged_error.expression == ' ~ invalid python ~' + assert logged_error.expression_type == 'python' + assert logged_error.error_message == 'SyntaxError: invalid syntax (, line 1)' + + LoggedError.wipe() + item.fields = [{'field_id': 'bo1', 'value': '{% if bad django %}'}] + item.perform(formdata) + formdata = formdef.data_class().get(formdata.id) + assert LoggedError.count() == 1 + logged_error = LoggedError.select()[0] + assert logged_error.summary == 'Failed to compute template (error TemplateError)' + assert logged_error.formdata_id == str(formdata.id) + assert logged_error.expression == '{% if bad django %}' + assert logged_error.expression_type == 'template' + assert logged_error.error_message.startswith('TemplateError: syntax error in Django template') + def test_set_backoffice_field_file(http_requests, two_pubs): Workflow.wipe() FormDef.wipe() @@ -3138,14 +3164,21 @@ def test_set_backoffice_field_file(http_requests, two_pubs): item = SetBackofficeFieldsWorkflowStatusItem() item.parent = st1 item.fields = [{'field_id': 'bo1', 'value': value}] + + LoggedError.wipe() item.perform(formdata) formdata = formdef.data_class().get(formdata.id) if value is not None: # wrong value : do nothing assert formdata.data['bo1'].base_filename == 'hello.txt' assert formdata.data['bo1'].get_content() == 'HELLO WORLD' + assert LoggedError.count() == 1 + logged_error = LoggedError.select()[0] + assert logged_error.summary.startswith('Failed to convert') + assert logged_error.formdata_id == str(formdata.id) else: # empty value : remove field assert formdata.data['bo1'] is None + assert LoggedError.count() == 0 # check wrong field item = SetBackofficeFieldsWorkflowStatusItem() @@ -3309,6 +3342,7 @@ def test_set_backoffice_field_items(two_pubs): def test_set_backoffice_field_date(two_pubs): Workflow.wipe() FormDef.wipe() + LoggedError.wipe() wf = Workflow(name='xxx') wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) st1 = wf.add_status('Status1') @@ -3356,14 +3390,18 @@ def test_set_backoffice_field_date(two_pubs): assert datetime.date(*formdata.data['bo1'][:3]) == datetime.date(2017, 3, 23) # invalid values => do nothing + assert LoggedError.count() == 0 for value in ('plop', {}, []): item = SetBackofficeFieldsWorkflowStatusItem() item.parent = st1 item.fields = [{'field_id': 'bo1', 'value': value}] + LoggedError.wipe() item.perform(formdata) formdata = formdef.data_class().get(formdata.id) assert datetime.date(*formdata.data['bo1'][:3]) == datetime.date(2017, 3, 23) + assert LoggedError.count() == 1 + assert LoggedError.select()[0].summary.startswith('Failed to convert') # None : empty date item = SetBackofficeFieldsWorkflowStatusItem() diff --git a/wcs/wf/backoffice_fields.py b/wcs/wf/backoffice_fields.py index 2ed97abe..0413d7a7 100644 --- a/wcs/wf/backoffice_fields.py +++ b/wcs/wf/backoffice_fields.py @@ -97,16 +97,31 @@ class SetBackofficeFieldsWorkflowStatusItem(WorkflowStatusItem): continue try: - new_value = self.compute(field['value'], raises=True) + new_value = self.compute(field['value'], raises=True, + formdata=formdata, status_item=self) except: - get_publisher().notify_of_exception(sys.exc_info(), context='[BO_FIELDS]') continue if formdef_field.convert_value_from_anything: try: new_value = formdef_field.convert_value_from_anything(new_value) - except ValueError: - get_publisher().notify_of_exception(sys.exc_info(), context='[BO_FIELDS]') + except ValueError as e: + from wcs.logged_errors import LoggedError + summary = _('Failed to convert %(class)s value to %(kind)s field (%(id)s)') % { + 'class': type(new_value), + 'kind': _(getattr(formdef_field, 'description', 'unknown')), + 'id': field['field_id'], + } + plain_msg = _('Computed result: %(computed)r\n' + 'Computed result class: %(class)s') % { + 'computed': new_value, + 'class': type(new_value) + } + expression_dict = self.get_expression(field['value']) + LoggedError.record(summary, plain_msg, formdata=formdata, status_item=self, + expression=expression_dict['value'], + expression_type=expression_dict['type'], + error_message='%s: %s' % (e.__class__.__name__, e)) continue formdata.data['%s' % field['field_id']] = new_value diff --git a/wcs/workflows.py b/wcs/workflows.py index 52d13285..7a74294c 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -1677,7 +1677,7 @@ class WorkflowStatusItem(XmlSerialisable): return {'type': expression_type, 'value': expression_value} @classmethod - def compute(cls, var, render=True, raises=False, context=None): + def compute(cls, var, render=True, raises=False, context=None, formdata=None, status_item=None): if not isinstance(var, basestring): return var @@ -1692,17 +1692,32 @@ class WorkflowStatusItem(XmlSerialisable): vars = get_publisher().substitutions.get_context_variables() vars.update(context or {}) + def log_exception(e): + from wcs.logged_errors import LoggedError + summary = _('Failed to compute %(type)s (error %(error)s)') % { + 'type': {'text': _('text'), + 'template': _('template'), + 'python': _('Python expression')}.get(expression['type']), + 'error': e.__class__.__name__ + } + LoggedError.record(summary, formdata=formdata, status_item=status_item, + expression=expression['value'], + expression_type=expression['type'], + error_message='%s: %s' % (e.__class__.__name__, e)) + if expression['type'] == 'template': try: return Template(expression['value'], raises=raises, autoescape=False).render(vars) - except TemplateError: + except TemplateError as e: + log_exception(e) if raises: raise return var try: return eval(expression['value'], get_publisher().get_global_eval_dict(), vars) - except: + except Exception as e: + log_exception(e) if raises: raise return var -- 2.18.0