176 lines
6.9 KiB
Python
176 lines
6.9 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/>.
|
|
|
|
import re
|
|
|
|
from django.utils.text import Truncator
|
|
from quixote import get_response, get_publisher, redirect
|
|
from quixote.directory import Directory
|
|
from quixote.html import TemplateIO, htmltext
|
|
from wcs.qommon import _, ngettext, N_, template
|
|
from wcs.qommon import errors, get_cfg
|
|
from wcs.qommon.misc import localstrftime
|
|
|
|
from wcs.logged_errors import LoggedError
|
|
|
|
|
|
class LoggedErrorDirectory(Directory):
|
|
_q_exports = ['', 'delete', 'ack']
|
|
do_not_call_in_templates = True
|
|
|
|
def __init__(self, parent_dir, error):
|
|
self.parent_dir = parent_dir
|
|
self.error = error
|
|
|
|
def _q_index(self):
|
|
get_response().breadcrumb.append(('%s/' % self.error.id, self.error.summary))
|
|
self.parent_dir.html_top(_('Logged Errors - %s') % self.error.summary)
|
|
get_response().filter['sidebar'] = self.get_sidebar()
|
|
|
|
return template.QommonTemplateResponse(
|
|
templates=['wcs/backoffice/logged-error.html'],
|
|
context={
|
|
'view': self,
|
|
'error': self.error,
|
|
'formdef': self.error.get_formdef(),
|
|
'workflow': self.error.get_workflow(),
|
|
'status': self.error.get_status(),
|
|
'status_item': self.error.get_status_item(),
|
|
'formdata': self.error.get_formdata(),
|
|
})
|
|
|
|
def error_expression_type_label(self):
|
|
return {
|
|
'python': _('Python Expression'),
|
|
'django': _('Django Expression'),
|
|
'template': _('Template'),
|
|
'text': _('Text'),
|
|
}.get(self.error.expression_type, _('Unknown'))
|
|
|
|
def get_html_traceback(self):
|
|
r = TemplateIO(html=True)
|
|
parts = (N_('Exception'), N_('Stack trace (most recent call first)'),
|
|
N_('Form'), N_('Cookies'), N_('Environment'))
|
|
current_part = None
|
|
for line in self.error.traceback.splitlines():
|
|
if line.endswith(':') and line.rstrip(':') in parts:
|
|
if current_part in parts[:2]:
|
|
r += htmltext('</pre></div>')
|
|
elif current_part:
|
|
r += htmltext('</table></div>')
|
|
current_part = line.rstrip(':')
|
|
r += htmltext('<div class="section"><h3>%s</h3>') % _(current_part)
|
|
if current_part in parts[:2]:
|
|
r += htmltext('<pre class="traceback">')
|
|
else:
|
|
r += htmltext('<table class="main compact code">')
|
|
continue
|
|
if current_part in parts[:2]:
|
|
r += line + '\n'
|
|
elif line:
|
|
r += htmltext('<tr><td>%s</td><td>%s</td></tr>') % tuple(
|
|
re.split(r'\s+', line, maxsplit=1))
|
|
|
|
if current_part in parts[:2]:
|
|
r += htmltext('</pre></div>')
|
|
elif current_part:
|
|
r += htmltext('</table></div>')
|
|
return r.getvalue()
|
|
|
|
def get_sidebar(self):
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<ul id="sidebar-actions">')
|
|
if not self.error.acked:
|
|
r += htmltext('<li><a href="ack">%s</a></li>') % ('Ack')
|
|
else:
|
|
r += htmltext('<li>%s</li>' % _('Acked'))
|
|
r += htmltext('<li><a href="delete">%s</a></li>') % _('Delete')
|
|
r += htmltext('</ul>')
|
|
return r.getvalue()
|
|
|
|
def ack(self):
|
|
self.error.acked = True
|
|
self.error.store()
|
|
return redirect('.')
|
|
|
|
def delete(self):
|
|
self.error.remove_self()
|
|
return redirect('..')
|
|
|
|
|
|
class LoggedErrorsDirectory(Directory):
|
|
_q_exports = ['']
|
|
|
|
@classmethod
|
|
def get_errors(cls, formdef_class=None, formdef_id=None, workflow_id=None):
|
|
errors = []
|
|
if formdef_id and formdef_class:
|
|
errors = [e for e in LoggedError.get_with_indexed_value('formdef_id', formdef_id) if e.formdef_class == formdef_class.__name__]
|
|
elif workflow_id:
|
|
errors = LoggedError.get_with_indexed_value('workflow_id', workflow_id)
|
|
return list(errors)
|
|
|
|
@classmethod
|
|
def errors_block(cls, formdef_class=None, formdef_id=None, workflow_id=None):
|
|
errors = cls.get_errors(formdef_class=formdef_class, formdef_id=formdef_id, workflow_id=workflow_id)
|
|
if not errors:
|
|
return ''
|
|
errors.sort(key=lambda x: x.id, reverse=True)
|
|
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<div class="bo-block logged-errors">')
|
|
r += htmltext('<h3><a href="logged-errors/">%s</a></h3>') % ngettext(
|
|
'%(count)d error', '%(count)d errors', len(errors)) % {'count': len(errors)}
|
|
r += htmltext('<ul>')
|
|
for error in errors[:3]:
|
|
r += htmltext('<li><a href="logged-errors/%s/">%s</a> ') % (error.id, error.summary)
|
|
if error.exception_class or error.exception_message:
|
|
message = _('error %(class)s (%(message)s)') % {
|
|
'class': error.exception_class,
|
|
'message': error.exception_message,
|
|
}
|
|
message = Truncator(message).chars(80, truncate='…')
|
|
r += htmltext(message)
|
|
r += htmltext('</li>')
|
|
if len(errors) > 3:
|
|
r += htmltext('<li>...</li>')
|
|
r += htmltext('</ul>')
|
|
r += htmltext('</div>')
|
|
return r.getvalue()
|
|
|
|
def __init__(self, parent_dir, formdef_class=None, formdef_id=None, workflow_id=None):
|
|
self.parent_dir = parent_dir
|
|
self.formdef_class = formdef_class
|
|
self.formdef_id = formdef_id
|
|
self.workflow_id = workflow_id
|
|
|
|
def _q_index(self):
|
|
get_response().breadcrumb.append(('logged-errors/', _('Logged Errors')))
|
|
self.parent_dir.html_top(_('Logged Errors'))
|
|
return template.QommonTemplateResponse(
|
|
templates=['wcs/backoffice/logged-errors.html'],
|
|
context={
|
|
'errors': self.get_errors(formdef_class=self.formdef_class, formdef_id=self.formdef_id, workflow_id=self.workflow_id),
|
|
})
|
|
|
|
def _q_lookup(self, component):
|
|
try:
|
|
error = LoggedError.get(component)
|
|
except KeyError:
|
|
raise errors.TraversalError()
|
|
get_response().breadcrumb.append(('logged-errors/', _('Logged Errors')))
|
|
return LoggedErrorDirectory(self.parent_dir, error)
|