From b70051236afa5e74cd9925126aa78aa33d60ec63 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 | 41 +++++++++++++++++++++++++++++++++++++ wcs/wf/backoffice_fields.py | 18 ++++++++++++---- wcs/workflows.py | 19 ++++++++++++++--- 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/tests/test_workflows.py b/tests/test_workflows.py index b94319b3..96d8b8a9 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -2975,6 +2975,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 = [ @@ -3020,6 +3021,33 @@ 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' + assert logged_error.formdata_id == str(formdata.id) + assert logged_error.expression == ' ~ invalid python ~' + assert logged_error.expression_type == 'python' + assert logged_error.exception_class == 'SyntaxError' + assert logged_error.exception_message == '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' + assert logged_error.formdata_id == str(formdata.id) + assert logged_error.expression == '{% if bad django %}' + assert logged_error.expression_type == 'template' + assert logged_error.exception_class == 'TemplateError' + assert logged_error.exception_message.startswith('syntax error in Django template') + def test_set_backoffice_field_file(http_requests, two_pubs): Workflow.wipe() FormDef.wipe() @@ -3141,14 +3169,22 @@ 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) + assert logged_error.exception_class == 'ValueError' else: # empty value : remove field assert formdata.data['bo1'] is None + assert LoggedError.count() == 0 # check wrong field item = SetBackofficeFieldsWorkflowStatusItem() @@ -3312,6 +3348,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') @@ -3359,14 +3396,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..a738992f 100644 --- a/wcs/wf/backoffice_fields.py +++ b/wcs/wf/backoffice_fields.py @@ -97,16 +97,26 @@ 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'], + } + expression_dict = self.get_expression(field['value']) + LoggedError.record(summary, formdata=formdata, status_item=self, + expression=expression_dict['value'], + expression_type=expression_dict['type'], + exception=e) continue formdata.data['%s' % field['field_id']] = new_value diff --git a/wcs/workflows.py b/wcs/workflows.py index b48df30f..ff718870 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -1680,7 +1680,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 @@ -1695,17 +1695,30 @@ class WorkflowStatusItem(XmlSerialisable): vars = get_publisher().substitutions.get_context_variables() vars.update(context or {}) + def log_exception(exception): + from wcs.logged_errors import LoggedError + if expression['type'] == 'template': + summary = _('Failed to compute Template') + else: + summary = _('Failed to compute Python Expression') + LoggedError.record(summary, formdata=formdata, status_item=status_item, + expression=expression['value'], + expression_type=expression['type'], + exception=exception) + 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