From e16f3e5ccf7cffac26d2fe54fc28e5fbae7ecb9a Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Fri, 13 Mar 2015 14:27:30 +0100 Subject: [PATCH] provide CSV download view for reports; use for work and qualification listings --- expert/browser/export.py | 77 ++++++++++++++++++++++++++ expert/field.py | 21 ++++++- knowledge/qualification/browser.py | 8 ++- knowledge/qualification/configure.zcml | 6 ++ organize/work/README.txt | 12 ++++ organize/work/configure.zcml | 6 ++ organize/work/report.py | 6 ++ 7 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 expert/browser/export.py diff --git a/expert/browser/export.py b/expert/browser/export.py new file mode 100644 index 0000000..8c06e21 --- /dev/null +++ b/expert/browser/export.py @@ -0,0 +1,77 @@ +# +# Copyright (c) 2015 Helmut Merz helmutm@cy55.de +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +View classes for export of report results. +""" + +import csv +from cStringIO import StringIO +from zope.i18n import translate + +from loops.expert.browser.report import ReportConceptView +from loops.interfaces import ILoopsObject +from loops.util import _ + + +class ReportConceptCSVExport(ReportConceptView): + + isToplevel = True + reportMode = 'export' + + delimiter = ';' + encoding = 'UTF-8' + + def getFileName(self): + return 'output' + + def getColumnTitle(self, field): + lang = self.languageInfo.language + return translate(_(field.title), target_language=lang) + + def __call__(self): + fields = self.displayedColumns + fieldNames = [f.name for f in fields] + output = StringIO() + writer = csv.DictWriter(output, fieldNames, delimiter=self.delimiter) + output.write(self.delimiter.join( + [self.getColumnTitle(f) for f in fields]) + '\n') + results = self.reportInstance.getResults() + for row in results: + data = {} + for f in fields: + value = f.getValue(row) + if ILoopsObject.providedBy(value): + value = value.title + if isinstance(value, unicode): + value = value.encode(self.encoding) + data[f.name] = value + writer.writerow(data) + text = output.getvalue() + self.setDownloadHeader(text) + return text + + def setDownloadHeader(self, text): + response = self.request.response + response.setHeader('Content-Disposition', + 'attachment; filename=%s.csv' % + self.getFileName()) + response.setHeader('Cache-Control', '') + response.setHeader('Pragma', '') + response.setHeader('Content-Type', 'text/csv') + response.setHeader('Content-Length', len(text)) diff --git a/expert/field.py b/expert/field.py index e54d998..2263b84 100644 --- a/expert/field.py +++ b/expert/field.py @@ -22,6 +22,7 @@ Field definitions for reports. from zope.app.form.browser.interfaces import ITerms from zope import component +from zope.i18n import translate from zope.i18n.locales import locales from zope.schema.interfaces import IVocabularyFactory, IContextSourceBinder @@ -92,6 +93,11 @@ class DateField(Field): format = ('date', 'short') cssClass = 'center' + def getValue(self, row): + if getattr(row.parent.context.view, 'reportMode', None) == 'export': + return self.getDisplayValue(row) + super(DateField, self).getValue(row) + def getDisplayValue(self, row): value = self.getRawValue(row) if not value: @@ -132,6 +138,15 @@ class WorkItemStateField(Field): statesDefinition = 'workItemStates' renderer = 'workitem_state' + def getValue(self, row): + view = row.parent.context.view + if getattr(view, 'reportMode', None) == 'export': + stateObject = row.context.getStateObject() + lang = view.languageInfo.language + return translate(util._(stateObject.title), target_language=lang) + return super(WorkItemStateField, self).getValue(row) + + def getDisplayValue(self, row): if row.context is None: return None @@ -241,14 +256,18 @@ class TrackDateField(Field): cssClass = 'right' def getValue(self, row): + reportMode = getattr(row.parent.context.view, 'reportMode', None) + if reportMode == 'export': + return self.getDisplayValue(row) value = self.getRawValue(row) if not value: return None return timeStamp2Date(value) def getDisplayValue(self, row): - value = self.getValue(row) + value = self.getRawValue(row) if value: + value = timeStamp2Date(value) view = row.parent.context.view return formatDate(value, self.part, self.format, view.languageInfo.language) diff --git a/knowledge/qualification/browser.py b/knowledge/qualification/browser.py index 9d5b619..186642f 100644 --- a/knowledge/qualification/browser.py +++ b/knowledge/qualification/browser.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2014 Helmut Merz helmutm@cy55.de +# Copyright (c) 2015 Helmut Merz helmutm@cy55.de # # 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 @@ -26,6 +26,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy from loops.browser.concept import ConceptView +from loops.expert.browser.export import ReportConceptCSVExport from loops.expert.browser.report import ResultsConceptView from loops.organize.party import getPersonForUser from loops.util import _ @@ -35,3 +36,8 @@ class Qualifications(ResultsConceptView): reportName = 'qualification_overview' + +class QualificationsCSVExport(ReportConceptCSVExport): + + reportName = 'qualification_overview' + diff --git a/knowledge/qualification/configure.zcml b/knowledge/qualification/configure.zcml index e4f02c9..b6a1a5e 100644 --- a/knowledge/qualification/configure.zcml +++ b/knowledge/qualification/configure.zcml @@ -23,6 +23,12 @@ factory="loops.knowledge.qualification.browser.Qualifications" permission="zope.View" /> + + >> results.totals.data {'effort': 900} +Export of work data +------------------- + + >>> from loops.organize.work.report import WorkStatementCSVExport + >>> reportView = WorkStatementCSVExport(task01, TestRequest()) + >>> reportView.nodeView = nodeView + + >>> output = reportView() + >>> print output + Day;Start;End;Task;Party;Title;Duration;Effort;State + 08/12/28;19:00;20:15;loops Development;john;;1.25;0.25;finished + Meeting Minutes =============== diff --git a/organize/work/configure.zcml b/organize/work/configure.zcml index 17dac6c..d4eab19 100644 --- a/organize/work/configure.zcml +++ b/organize/work/configure.zcml @@ -101,6 +101,12 @@ class="loops.organize.work.report.WorkStatementView" permission="zope.View" /> + +