From c9f4cffca576435893f6d4c16afa3c12a7aecda7 Mon Sep 17 00:00:00 2001 From: Thomas NOEL Date: Thu, 7 Jun 2018 12:16:20 +0200 Subject: [PATCH] can notify exceptions on formdata only in UI (#24327) --- tests/test_hobo_notify.py | 2 +- wcs/logged_errors.py | 32 +++++++++++++++++++------------- wcs/publisher.py | 9 +++++---- wcs/qommon/publisher.py | 6 +++--- wcs/workflows.py | 13 +++++++------ 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/tests/test_hobo_notify.py b/tests/test_hobo_notify.py index 1a497062..36c6e36f 100644 --- a/tests/test_hobo_notify.py +++ b/tests/test_hobo_notify.py @@ -587,7 +587,7 @@ def test_process_notification_user_provision(pub): else: # empty value : empty field assert User.select()[0].form_data['_birthdate'] is None -def notify_of_exception(exc_info, context): +def notify_of_exception(exc_info, context=None, formdata=None): raise Exception(exc_info) def test_process_notification_user_with_errors(pub): diff --git a/wcs/logged_errors.py b/wcs/logged_errors.py index 39e568fb..21d7ac0b 100644 --- a/wcs/logged_errors.py +++ b/wcs/logged_errors.py @@ -47,27 +47,33 @@ class LoggedError(XmlStorableObject): ('acked', 'bool')] @classmethod - def record(cls, error_summary, plain_error_msg, publisher): + def record(cls, error_summary, plain_error_msg, publisher=None, formdata=None): error = cls() error.summary = error_summary error.traceback = plain_error_msg - try: - context = publisher.substitutions.get_context_variables() - except: - return - formdef_urlname = context.get('form_slug') - if not formdef_urlname: + if formdata: + error.formdata_id = str(formdata.id) + error.formdef_id = formdata.formdef.id + error.workflow_id = formdata.formdef.workflow_id + + elif publisher: + try: + context = publisher.substitutions.get_context_variables() + except Exception as e: + return + error.formdata_id = context.get('form_number_raw') + formdef_urlname = context.get('form_slug') + if formdef_urlname: + formdef = FormDef.get_by_urlname(formdef_urlname) + error.formdef_id = formdef.id + error.workflow_id = formdef.workflow_id + + if not error.formdef_id: # cannot attach error to formdef, don't record in journal, it will # still be sent by email to administrators. return - error.formdata_id = context.get('form_number_raw') - if formdef_urlname: - formdef = FormDef.get_by_urlname(formdef_urlname) - error.formdef_id = formdef.id - error.workflow_id = formdef.workflow_id - error.first_occurence_timestamp = datetime.datetime.now() error.id = '%s-%s' % ( error.first_occurence_timestamp.strftime('%Y%m%d-%H%M%S'), diff --git a/wcs/publisher.py b/wcs/publisher.py index 2a1e49c6..5b4900ba 100644 --- a/wcs/publisher.py +++ b/wcs/publisher.py @@ -283,11 +283,12 @@ class WcsPublisher(StubWcsPublisher): conn.commit() cur.close() - def log_internal_error(self, error_summary, plain_error_msg, record=False): - super(WcsPublisher, self).log_internal_error(error_summary, - plain_error_msg, record=record) + def log_internal_error(self, error_summary, plain_error_msg, record=False, formdata=None): + if not formdata: + super(WcsPublisher, self).log_internal_error(error_summary, + plain_error_msg, record=record) if record: - LoggedError.record(error_summary, plain_error_msg, publisher=self) + LoggedError.record(error_summary, plain_error_msg, publisher=self, formdata=formdata) def apply_global_action_timeouts(self): from wcs.workflows import Workflow, WorkflowGlobalActionTimeoutTrigger diff --git a/wcs/qommon/publisher.py b/wcs/qommon/publisher.py index d45f273f..d166522c 100644 --- a/wcs/qommon/publisher.py +++ b/wcs/qommon/publisher.py @@ -238,7 +238,7 @@ class QommonPublisher(Publisher, object): return error_file.getvalue() - def notify_of_exception(self, exc_tuple, context=None): + def notify_of_exception(self, exc_tuple, context=None, formdata=None): exc_type, exc_value, tb = exc_tuple error_summary = traceback.format_exception_only(exc_type, exc_value) error_summary = error_summary[0][0:-1] # de-listify and strip newline @@ -254,9 +254,9 @@ class QommonPublisher(Publisher, object): self.notify_sentry(exc_tuple, request=self.get_request(), context=context) - self.log_internal_error(error_summary, plain_error_msg, record=True) + self.log_internal_error(error_summary, plain_error_msg, record=True, formdata=formdata) - def log_internal_error(self, error_summary, plain_error_msg, record=False): + def log_internal_error(self, error_summary, plain_error_msg, record=False, formdata=None): try: self.logger.log_internal_error(error_summary, plain_error_msg) except socket.error: diff --git a/wcs/workflows.py b/wcs/workflows.py index bc064e5f..836a4a28 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -1725,12 +1725,13 @@ class WorkflowStatusItem(XmlSerialisable): return [] targets = [x for x in self.parent.parent.possible_status if x.id == self.status] - if not targets: - get_publisher().get_app_logger().error( - 'reference to invalid status in workflow %r, status %r, item %r' % ( - self.parent.parent.name, - self.parent.name, - self.description)) + if not targets and formdata: # do not log in presentation context, formdata is needed + try: + raise IndexError('reference to invalid status in workflow %r, status %r, item %r' % + (self.parent.parent.name, self.parent.name, self.description)) + except IndexError as e: + get_publisher().notify_of_exception(sys.exc_info(), formdata=formdata) + return targets def get_jump_label(self): -- 2.17.1