1 | ## $Id: reports.py 11949 2014-11-13 14:40:27Z henrik $ |
---|
2 | ## |
---|
3 | ## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann |
---|
4 | ## This program is free software; you can redistribute it and/or modify |
---|
5 | ## it under the terms of the GNU General Public License as published by |
---|
6 | ## the Free Software Foundation; either version 2 of the License, or |
---|
7 | ## (at your option) any later version. |
---|
8 | ## |
---|
9 | ## This program is distributed in the hope that it will be useful, |
---|
10 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
12 | ## GNU General Public License for more details. |
---|
13 | ## |
---|
14 | ## You should have received a copy of the GNU General Public License |
---|
15 | ## along with this program; if not, write to the Free Software |
---|
16 | ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
17 | ## |
---|
18 | """Browser components for report generation. |
---|
19 | """ |
---|
20 | import grok |
---|
21 | from zope.component import getUtility, queryUtility |
---|
22 | from zope.location.location import located |
---|
23 | from waeup.ikoba.interfaces import IJobManager, IIkobaUtils |
---|
24 | from waeup.ikoba.interfaces import MessageFactory as _ |
---|
25 | from waeup.ikoba.browser.layout import IkobaPage |
---|
26 | from waeup.ikoba.reports import IReportsContainer, IReportGenerator |
---|
27 | from waeup.ikoba.reports import get_generators |
---|
28 | |
---|
29 | grok.templatedir('templates') |
---|
30 | |
---|
31 | class ReportsContainerPage(IkobaPage): |
---|
32 | """A view on a reports container. |
---|
33 | """ |
---|
34 | grok.name('index') |
---|
35 | grok.context(IReportsContainer) |
---|
36 | grok.require('waeup.manageReports') |
---|
37 | label = _('Reports') |
---|
38 | |
---|
39 | def _report_url(self, job_id): |
---|
40 | """Get the PDF download URL of a report. |
---|
41 | """ |
---|
42 | return self.url(self.context, '%s/pdf' % job_id) |
---|
43 | |
---|
44 | def update(self, job_id=None, DISCARD=None, DOWNLOAD=None): |
---|
45 | self.entries = [] |
---|
46 | if job_id and DISCARD: |
---|
47 | entry = self.context.report_entry_from_job_id(job_id) |
---|
48 | self.context.delete_report_entry(entry) |
---|
49 | self.flash('Report discarded: %s' % job_id) |
---|
50 | ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','') |
---|
51 | grok.getSite().logger.info( |
---|
52 | '%s - report %s discarded' % (ob_class, job_id)) |
---|
53 | self.entries = self._generate_entries(user_id=None) |
---|
54 | if job_id and DOWNLOAD: |
---|
55 | self.redirect(self._report_url(job_id)) |
---|
56 | return |
---|
57 | return |
---|
58 | |
---|
59 | def _generate_entries(self, user_id=None): |
---|
60 | entries = [] |
---|
61 | for entry in self.context.get_running_report_jobs(user_id=user_id): |
---|
62 | job_id, gen_name, user = entry |
---|
63 | job = getUtility(IJobManager).get(job_id) |
---|
64 | generator = queryUtility(IReportGenerator, name=gen_name) |
---|
65 | gen_title = getattr(generator, 'title', 'Unknown') |
---|
66 | args = ', '.join([str(x) for x in job.kwargs['kw'].values()]) |
---|
67 | descr = '%s (%s)' % (gen_title, args) |
---|
68 | status = job.finished and 'ready' or 'running' |
---|
69 | status = job.failed and 'FAILED' or status |
---|
70 | starttime = getattr(job, 'begin_after', None) |
---|
71 | if starttime: |
---|
72 | starttime = starttime.astimezone( |
---|
73 | getUtility( |
---|
74 | IIkobaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z") |
---|
75 | new_entry = (job_id, descr, status, job.finished, job.finished \ |
---|
76 | and not job.failed, not job.finished, starttime, user) |
---|
77 | entries.append(new_entry) |
---|
78 | return entries |
---|
79 | |
---|
80 | |
---|
81 | class ReportsContainerTraverser(grok.Traverser): |
---|
82 | """A traverser for reports containers. |
---|
83 | """ |
---|
84 | grok.context(IReportsContainer) |
---|
85 | def traverse(self, name): |
---|
86 | """Return a report generator or report if one is registered under |
---|
87 | `name`. |
---|
88 | |
---|
89 | Generators are registered by their utility names while reports |
---|
90 | are looked up by their job id. So, `name` must be a report |
---|
91 | generator name or a valid job_id of a report job. |
---|
92 | """ |
---|
93 | generators = dict(list(get_generators())) |
---|
94 | result = generators.get(name, None) |
---|
95 | if result: |
---|
96 | # give generator a location in URLs (make url() work) |
---|
97 | return located(result, self.context, name) |
---|
98 | result = self.context.report_entry_from_job_id(name) |
---|
99 | if result: |
---|
100 | manager = getUtility(IJobManager) |
---|
101 | job = manager.get(name) |
---|
102 | report = job.result |
---|
103 | return located(report, self.context, name) |
---|
104 | return None |
---|
105 | |
---|
106 | class ReportsContainerCreate(IkobaPage): |
---|
107 | """Create a new report. |
---|
108 | """ |
---|
109 | grok.name('create') |
---|
110 | grok.context(IReportsContainer) |
---|
111 | grok.require('waeup.manageReports') |
---|
112 | label = _('Create report') |
---|
113 | |
---|
114 | def update(self, START_GENERATOR=None, generator=None): |
---|
115 | self.creators = self.get_creators() |
---|
116 | self.generator_names = [x[1] for x in self.creators] |
---|
117 | if START_GENERATOR and generator and generator in self.generator_names: |
---|
118 | self.redirect(self.url(self.context, generator)) |
---|
119 | pass |
---|
120 | |
---|
121 | def get_creators(self): |
---|
122 | """Get all registered report generator names. |
---|
123 | |
---|
124 | Returns a list of tuples (<TITLE>, <NAME>) with ``<TITLE>`` |
---|
125 | being a human readable description of the respective generator |
---|
126 | and ``<NAME>`` being the registration name with the ZCA. |
---|
127 | """ |
---|
128 | result = [(gen.title, name) for name, gen in get_generators()] |
---|
129 | return result |
---|