wcs/wcs/logged_errors.py

170 lines
5.4 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2017 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
from django.utils.timezone import now
from wcs.carddef import CardDef
from wcs.formdef import FormDef
from wcs.workflows import Workflow
from .qommon.misc import simplify
class LoggedError:
_names = 'logged-errors'
id = None
tech_id = None
summary = None
formdef_class = None
formdata_id = None
formdef_id = None
workflow_id = None
status_id = None
status_item_id = None
expression = None
expression_type = None
traceback = None
exception_class = None
exception_message = None
occurences_count = 0
first_occurence_timestamp = None
latest_occurence_timestamp = None
@classmethod
def record(
cls,
error_summary,
plain_error_msg=None,
formdata=None,
formdef=None,
workflow=None,
status=None,
status_item=None,
expression=None,
expression_type=None,
exception=None,
):
error = cls()
error.summary = error_summary
error.traceback = plain_error_msg
error.expression = expression
error.expression_type = expression_type
if exception:
error.exception_class = exception.__class__.__name__
error.exception_message = str(exception)
if formdata:
error.formdata_id = str(formdata.id)
formdef = formdata.formdef
if formdef:
error.formdef_id = formdef.id
error.workflow_id = formdef.workflow.id
error.formdef_class = formdef.__class__.__name__
elif workflow:
error.workflow_id = workflow.id
if status_item:
error.status_item_id = status_item.id
if getattr(status_item, 'parent', None):
error.status_id = status_item.parent.id
if status:
error.status_id = status.id
error.first_occurence_timestamp = now()
error.tech_id = error.build_tech_id()
existing_errors = list(cls.get_with_indexed_value('tech_id', error.tech_id))
if existing_errors:
error = existing_errors[0]
error.occurences_count += 1
error.latest_occurence_timestamp = now()
error.store()
return error
@classmethod
def record_exception(cls, error_summary, plain_error_msg, publisher):
try:
context = publisher.substitutions.get_context_variables()
except Exception:
return
formdata_id = context.get('form_number_raw')
formdef_urlname = context.get('form_slug')
if formdef_urlname:
klass = FormDef
if context.get('form_class_name') == 'CardDef':
klass = CardDef
formdef = klass.get_by_urlname(formdef_urlname)
formdata = formdef.data_class().get(formdata_id, ignore_errors=True)
workflow = formdef.workflow
else:
formdef = formdata = workflow = None
return cls.record(
error_summary, plain_error_msg, formdata=formdata, formdef=formdef, workflow=workflow
)
def build_tech_id(self):
tech_id = ''
if self.formdef_id:
tech_id += '%s-' % self.formdef_id
tech_id += '%s-' % self.workflow_id
if self.status_id:
tech_id += '%s-' % self.status_id
if self.status_item_id:
tech_id += '%s-' % self.status_item_id
tech_id += '%s' % simplify(self.summary)
if self.exception_class:
tech_id += '-%s' % self.exception_class
if self.exception_message:
tech_id += '-%s' % simplify(self.exception_message)
return tech_id[:200]
def get_formdef(self):
if self.formdef_class == 'CardDef':
return CardDef.get(self.formdef_id, ignore_errors=True)
return FormDef.get(self.formdef_id, ignore_errors=True)
def get_workflow(self):
return Workflow.get(self.workflow_id, ignore_errors=True)
def get_formdata(self):
if not self.formdata_id:
return None
formdef = self.get_formdef()
if not formdef:
return None
return formdef.data_class().get(self.formdata_id, ignore_errors=True)
def get_status(self):
if not self.status_id:
return None
workflow = self.get_workflow()
if not workflow:
return None
for status in workflow.possible_status:
if status.id == self.status_id:
return status
return None
def get_status_item(self):
status = self.get_status()
if not status or not status.items:
return None
for status_item in status.items:
if status_item.id == self.status_item_id:
return status_item
return None