Allow disabling, or per-day scheduling, of problem reports
This commit is contained in:
parent
163c65600d
commit
e4392cd00a
17
tailbone/templates/deform/problem_report_days.pt
Normal file
17
tailbone/templates/deform/problem_report_days.pt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div tal:define="name name|field.name;"
|
||||||
|
tal:omit-tag="">
|
||||||
|
<div tal:define="vmodel vmodel|'field_model_' + name;"
|
||||||
|
tal:omit-tag="">
|
||||||
|
<b-field grouped>
|
||||||
|
<input type="hidden" name="${name}"
|
||||||
|
tal:attributes=":value 'JSON.stringify('+vmodel+')';" />
|
||||||
|
<b-checkbox v-model="${vmodel}.day0">${day_labels[0]['abbr']}</b-checkbox>
|
||||||
|
<b-checkbox v-model="${vmodel}.day1">${day_labels[1]['abbr']}</b-checkbox>
|
||||||
|
<b-checkbox v-model="${vmodel}.day2">${day_labels[2]['abbr']}</b-checkbox>
|
||||||
|
<b-checkbox v-model="${vmodel}.day3">${day_labels[3]['abbr']}</b-checkbox>
|
||||||
|
<b-checkbox v-model="${vmodel}.day4">${day_labels[4]['abbr']}</b-checkbox>
|
||||||
|
<b-checkbox v-model="${vmodel}.day5">${day_labels[5]['abbr']}</b-checkbox>
|
||||||
|
<b-checkbox v-model="${vmodel}.day6">${day_labels[6]['abbr']}</b-checkbox>
|
||||||
|
</b-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -66,6 +66,10 @@
|
||||||
${parent.modify_this_page_vars()}
|
${parent.modify_this_page_vars()}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
% if weekdays_data is not Undefined:
|
||||||
|
${form.component_studly}Data.weekdaysData = ${json.dumps(weekdays_data)|n}
|
||||||
|
% endif
|
||||||
|
|
||||||
ThisPageData.runReportShowDialog = false
|
ThisPageData.runReportShowDialog = false
|
||||||
ThisPageData.runReportSubmitting = false
|
ThisPageData.runReportSubmitting = false
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ Reporting views
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
import calendar
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
@ -563,7 +565,6 @@ class ProblemReportView(MasterView):
|
||||||
url_prefix = '/reports/problems'
|
url_prefix = '/reports/problems'
|
||||||
|
|
||||||
creatable = False
|
creatable = False
|
||||||
editable = False
|
|
||||||
deletable = False
|
deletable = False
|
||||||
filterable = False
|
filterable = False
|
||||||
pageable = False
|
pageable = False
|
||||||
|
@ -571,6 +572,7 @@ class ProblemReportView(MasterView):
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
'system_key': "System",
|
'system_key': "System",
|
||||||
|
'days': "Schedule",
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
|
@ -580,32 +582,17 @@ class ProblemReportView(MasterView):
|
||||||
'email_recipients',
|
'email_recipients',
|
||||||
]
|
]
|
||||||
|
|
||||||
form_fields = [
|
|
||||||
'system_key',
|
|
||||||
'problem_title',
|
|
||||||
'email_key',
|
|
||||||
'email_recipients',
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(ProblemReportView, self).__init__(request)
|
super(ProblemReportView, self).__init__(request)
|
||||||
|
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
self.handler = app.get_problem_report_handler()
|
self.problem_handler = app.get_problem_report_handler()
|
||||||
|
# TODO: deprecate / remove this
|
||||||
|
self.handler = self.problem_handler
|
||||||
|
|
||||||
def normalize(self, report, keep_report=True):
|
def normalize(self, report, keep_report=True):
|
||||||
data = {
|
data = self.problem_handler.normalize_problem_report(
|
||||||
'system_key': report.system_key,
|
report, include_schedule=True, include_recipients=True)
|
||||||
'problem_key': report.problem_key,
|
|
||||||
'problem_title': report.problem_title,
|
|
||||||
'email_key': self.handler.get_email_key(report),
|
|
||||||
}
|
|
||||||
|
|
||||||
app = self.get_rattail_app()
|
|
||||||
handler = app.get_email_handler()
|
|
||||||
email = handler.get_email(data['email_key'])
|
|
||||||
data['email_recipients'] = email.get_recips('all')
|
|
||||||
|
|
||||||
if keep_report:
|
if keep_report:
|
||||||
data['_report'] = report
|
data['_report'] = report
|
||||||
return data
|
return data
|
||||||
|
@ -653,28 +640,159 @@ class ProblemReportView(MasterView):
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(ProblemReportView, self).configure_form(f)
|
super(ProblemReportView, self).configure_form(f)
|
||||||
|
|
||||||
f.set_renderer('email_key', self.render_email_key)
|
# email_*
|
||||||
f.set_renderer('email_recipients', self.render_email_recipients)
|
if self.editing:
|
||||||
|
f.remove('email_key',
|
||||||
|
'email_recipients')
|
||||||
|
else:
|
||||||
|
f.set_renderer('email_key', self.render_email_key)
|
||||||
|
f.set_renderer('email_recipients', self.render_email_recipients)
|
||||||
|
|
||||||
|
# enabled
|
||||||
|
f.set_type('enabled', 'boolean')
|
||||||
|
|
||||||
|
# days
|
||||||
|
f.set_renderer('days', self.render_days)
|
||||||
|
f.set_widget('days', DaysWidget())
|
||||||
|
f.set_vuejs_field_converter('days', self.convert_vuejs_days)
|
||||||
|
f.set_helptext('days', "NB. enabling a given day means you want the "
|
||||||
|
"report to be available that morning (assuming that "
|
||||||
|
"reports run overnight)")
|
||||||
|
|
||||||
|
# only allow edit of certain fields
|
||||||
|
if self.editing:
|
||||||
|
editable = ('enabled', 'days')
|
||||||
|
for field in f:
|
||||||
|
if field not in editable:
|
||||||
|
f.set_readonly(field)
|
||||||
|
|
||||||
|
def convert_vuejs_days(self, days):
|
||||||
|
days = dict(days)
|
||||||
|
for key in days:
|
||||||
|
if days[key] is colander.null:
|
||||||
|
days[key] = 'null'
|
||||||
|
return days
|
||||||
|
|
||||||
def render_email_recipients(self, report_info, field):
|
def render_email_recipients(self, report_info, field):
|
||||||
recips = report_info['email_recipients']
|
recips = report_info['email_recipients']
|
||||||
return ', '.join(recips)
|
return ', '.join(recips)
|
||||||
|
|
||||||
|
def render_days(self, report_info, field):
|
||||||
|
g = self.get_grid_factory()('days', [],
|
||||||
|
columns=['weekday_name', 'enabled'],
|
||||||
|
labels={'weekday_name': "Weekday"})
|
||||||
|
return HTML.literal(g.render_buefy_table_element(data_prop='weekdaysData'))
|
||||||
|
|
||||||
|
def template_kwargs_view(self, **kwargs):
|
||||||
|
kwargs = super(ProblemReportView, self).template_kwargs_view(**kwargs)
|
||||||
|
report_info = kwargs['instance']
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for i in range(7):
|
||||||
|
data.append({
|
||||||
|
'weekday': i,
|
||||||
|
'weekday_name': calendar.day_name[i],
|
||||||
|
'enabled': "Yes" if report_info['day{}'.format(i)] else "No",
|
||||||
|
})
|
||||||
|
kwargs['weekdays_data'] = data
|
||||||
|
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def save_edit_form(self, form):
|
||||||
|
app = self.get_rattail_app()
|
||||||
|
session = self.Session()
|
||||||
|
data = form.validated
|
||||||
|
report = self.get_instance()
|
||||||
|
key = '{}.{}'.format(report['system_key'],
|
||||||
|
report['problem_key'])
|
||||||
|
|
||||||
|
app.save_setting(session, 'rattail.problems.{}.enabled'.format(key),
|
||||||
|
six.text_type(data['enabled']).lower())
|
||||||
|
|
||||||
|
for i in range(7):
|
||||||
|
daykey = 'day{}'.format(i)
|
||||||
|
app.save_setting(session, 'rattail.problems.{}.{}'.format(key, daykey),
|
||||||
|
six.text_type(data['days'][daykey]).lower())
|
||||||
|
|
||||||
def execute_instance(self, report_info, user, progress=None, **kwargs):
|
def execute_instance(self, report_info, user, progress=None, **kwargs):
|
||||||
report = report_info['_report']
|
report = report_info['_report']
|
||||||
problems = self.handler.run_problem_report(report, progress=progress)
|
problems = self.handler.run_problem_report(report, progress=progress,
|
||||||
|
force=True)
|
||||||
return "Report found {} problems".format(len(problems))
|
return "Report found {} problems".format(len(problems))
|
||||||
|
|
||||||
|
|
||||||
|
class ProblemReportDays(colander.MappingSchema):
|
||||||
|
|
||||||
|
day0 = colander.SchemaNode(colander.Boolean(),
|
||||||
|
title=calendar.day_abbr[0])
|
||||||
|
day1 = colander.SchemaNode(colander.Boolean(),
|
||||||
|
title=calendar.day_abbr[1])
|
||||||
|
day2 = colander.SchemaNode(colander.Boolean(),
|
||||||
|
title=calendar.day_abbr[2])
|
||||||
|
day3 = colander.SchemaNode(colander.Boolean(),
|
||||||
|
title=calendar.day_abbr[3])
|
||||||
|
day4 = colander.SchemaNode(colander.Boolean(),
|
||||||
|
title=calendar.day_abbr[4])
|
||||||
|
day5 = colander.SchemaNode(colander.Boolean(),
|
||||||
|
title=calendar.day_abbr[5])
|
||||||
|
day6 = colander.SchemaNode(colander.Boolean(),
|
||||||
|
title=calendar.day_abbr[6])
|
||||||
|
|
||||||
|
|
||||||
class ProblemReportSchema(colander.MappingSchema):
|
class ProblemReportSchema(colander.MappingSchema):
|
||||||
|
|
||||||
system_key = colander.SchemaNode(colander.String())
|
system_key = colander.SchemaNode(colander.String(),
|
||||||
|
missing=colander.null)
|
||||||
|
|
||||||
problem_key = colander.SchemaNode(colander.String())
|
problem_key = colander.SchemaNode(colander.String(),
|
||||||
|
missing=colander.null)
|
||||||
|
|
||||||
problem_title = colander.SchemaNode(colander.String())
|
problem_title = colander.SchemaNode(colander.String(),
|
||||||
|
missing=colander.null)
|
||||||
|
|
||||||
email_key = colander.SchemaNode(colander.String())
|
description = colander.SchemaNode(colander.String(),
|
||||||
|
missing=colander.null)
|
||||||
|
|
||||||
|
email_key = colander.SchemaNode(colander.String(),
|
||||||
|
missing=colander.null)
|
||||||
|
|
||||||
|
email_recipients = colander.SchemaNode(colander.String(),
|
||||||
|
missing=colander.null)
|
||||||
|
|
||||||
|
enabled = colander.SchemaNode(colander.Boolean())
|
||||||
|
|
||||||
|
days = ProblemReportDays()
|
||||||
|
|
||||||
|
|
||||||
|
class DaysWidget(dfwidget.Widget):
|
||||||
|
template = 'problem_report_days'
|
||||||
|
|
||||||
|
def serialize(self, field, cstruct, **kw):
|
||||||
|
if cstruct in (colander.null, None):
|
||||||
|
cstruct = ""
|
||||||
|
readonly = kw.get("readonly", self.readonly)
|
||||||
|
template = self.template
|
||||||
|
values = dict(kw)
|
||||||
|
if 'day_labels' not in values:
|
||||||
|
values['day_labels'] = self.get_day_labels()
|
||||||
|
values = self.get_template_values(field, cstruct, values)
|
||||||
|
return field.renderer(template, **values)
|
||||||
|
|
||||||
|
def get_day_labels(self):
|
||||||
|
labels = {}
|
||||||
|
for i in range(7):
|
||||||
|
labels[i] = {'name': calendar.day_name[i],
|
||||||
|
'abbr': calendar.day_abbr[i]}
|
||||||
|
return labels
|
||||||
|
|
||||||
|
def deserialize(self, field, pstruct):
|
||||||
|
from deform.compat import string_types
|
||||||
|
if pstruct is colander.null:
|
||||||
|
return colander.null
|
||||||
|
elif not isinstance(pstruct, string_types):
|
||||||
|
raise colander.Invalid(field.schema, "Pstruct is not a string")
|
||||||
|
pstruct = json.loads(pstruct)
|
||||||
|
return pstruct
|
||||||
|
|
||||||
|
|
||||||
def add_routes(config):
|
def add_routes(config):
|
||||||
|
|
Loading…
Reference in a new issue