218 lines
8.8 KiB
Python
218 lines
8.8 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']
|
|
|
|
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()
|
|
r = TemplateIO(html=True)
|
|
r += htmltext('<h2>%s</h2>') % self.error.summary
|
|
r += htmltext('<ul>')
|
|
r += htmltext(' <li>%s %s</li>') % (
|
|
_('First occurence:'),
|
|
localstrftime(self.error.first_occurence_timestamp))
|
|
r += htmltext(' <li>%s %s</li>') % (
|
|
_('Latest occurence:'),
|
|
localstrftime(self.error.latest_occurence_timestamp))
|
|
r += htmltext(' <li>%s %s</li>') % (_('Count:'), self.error.occurences_count)
|
|
|
|
formdef = self.error.get_formdef()
|
|
if formdef:
|
|
r += htmltext(' <li>%s <a href="%s">%s</a></li>') % (
|
|
_('%s:') % _(formdef.verbose_name),
|
|
formdef.get_admin_url(),
|
|
formdef.name)
|
|
|
|
workflow = self.error.get_workflow()
|
|
if workflow:
|
|
r += htmltext(' <li>%s <a href="/backoffice/workflows/%s/">%s</a></li>') % (
|
|
_('Workflow: '), workflow.id, workflow.name)
|
|
status = self.error.get_status()
|
|
if status:
|
|
r += htmltext('<ul>')
|
|
r += htmltext(
|
|
'<li>%s <a href="/backoffice/workflows/%s/status/%s/">%s</a></li>') % (
|
|
_('Status:'), workflow.id, status.id, status.name)
|
|
status_item = self.error.get_status_item()
|
|
if status_item:
|
|
r += htmltext(
|
|
'<li>%s <a href="/backoffice/workflows/%s/status/%s/items/%s/">%s</a></li>') % (
|
|
_('Action:'), workflow.id, status.id, status_item.id,
|
|
_(status_item.description))
|
|
r += htmltext('</ul>')
|
|
|
|
|
|
if self.error.expression or self.error.expression_type:
|
|
expression_title = {
|
|
'python': N_('Python Expression'),
|
|
'django': N_('Django Expression'),
|
|
'template': N_('Template'),
|
|
'text': N_('Text'),
|
|
}.get(self.error.expression_type, N_('Unknown'))
|
|
r += htmltext(' <li>%s <code>%s</code></li>') % (
|
|
_('%s:') % expression_title, self.error.expression)
|
|
|
|
if self.error.exception_class or self.error.exception_message:
|
|
r += htmltext(' <li>%s <code>%s: %s</code></li>') % (_('Error message:'),
|
|
self.error.exception_class,
|
|
self.error.exception_message)
|
|
|
|
if formdef:
|
|
formdata = self.error.get_formdata()
|
|
if formdata:
|
|
r += htmltext(' <li>%s <a href="%s">%s</a>') % (
|
|
_('Data: '), formdata.get_url(backoffice=True),
|
|
formdata.get_display_name())
|
|
r += htmltext(' (<a href="%sinspect">%s</a>)') % (
|
|
formdata.get_url(backoffice=True), _('inspector'))
|
|
r += htmltext('</li>')
|
|
|
|
r += htmltext('</ul>')
|
|
|
|
if not self.error.traceback:
|
|
return r.getvalue()
|
|
|
|
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>')
|
|
elif current_part:
|
|
r += htmltext('</table>')
|
|
current_part = line.rstrip(':')
|
|
r += htmltext('<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>')
|
|
elif current_part:
|
|
r += htmltext('</table>')
|
|
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_id=None, workflow_id=None):
|
|
errors = []
|
|
if formdef_id:
|
|
errors = LoggedError.get_with_indexed_value('formdef_id', formdef_id)
|
|
elif workflow_id:
|
|
errors = LoggedError.get_with_indexed_value('workflow_id', workflow_id)
|
|
return list(errors)
|
|
|
|
@classmethod
|
|
def errors_block(cls, formdef_id=None, workflow_id=None):
|
|
errors = cls.get_errors(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_id=None, workflow_id=None):
|
|
self.parent_dir = parent_dir
|
|
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_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)
|