diff --git a/composer/schema/browser/common.py b/composer/schema/browser/common.py index c0366b3..a6fd954 100644 --- a/composer/schema/browser/common.py +++ b/composer/schema/browser/common.py @@ -22,6 +22,8 @@ Common base class(es) for schema and other template views. $Id$ """ +from datetime import datetime +import time from zope import component from zope.app.pagetemplate import ViewPageTemplateFile from zope.app.session.interfaces import ISession @@ -29,6 +31,7 @@ from zope.cachedescriptors.property import Lazy from cybertools.composer.interfaces import IInstance from cybertools.composer.schema.interfaces import IClientFactory, ISchema +from cybertools.util.format import formatDate schema_macros = ViewPageTemplateFile('schema_macros.pt') @@ -173,3 +176,14 @@ class BaseView(object): result.append(dict(label=f.title, value=data.get(f.name))) return result + def getFormattedDate(self, date=None, type='date', variant='medium', + adjustTz=False): + if date is not None and not isinstance(date, (int, float)): + return '???' + if adjustTz: + date = time.gmtime(date)[:6] + else: + date = time.localtime(date)[:6] + date = datetime(*date) + return formatDate(date, type=type, variant=variant, lang=self.getLanguage()) + diff --git a/composer/schema/browser/report.py b/composer/schema/browser/report.py new file mode 100644 index 0000000..c987f6c --- /dev/null +++ b/composer/schema/browser/report.py @@ -0,0 +1,112 @@ +# +# Copyright (c) 2010 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 CSV export. + +$Id$ +""" + +import csv +from cStringIO import StringIO +import itertools +from zope import component +from zope.cachedescriptors.property import Lazy +from cybertools.composer.interfaces import IInstance +from cybertools.composer.schema.interfaces import ISchema +from cybertools.composer.schema.browser.schema import FormManagerView +from cybertools.stateful.interfaces import IStateful + + +class RegistrationsExportCsv(FormManagerView): + + encoding = 'ISO8859-15' + #delimiter = ';' + delimiter = ',' + + def __init__(self, context, request): + self.context = context + self.request = request + + def setHeaders(self, size, filename=None): + filename = filename or 'registrations.csv' + response = self.request.response + response.setHeader('Content-Disposition', + 'attachment; filename=%s' % filename) + response.setHeader('Content-Type', 'text/x-comma-separated-values') + response.setHeader('Content-Length', size) + + def getAllDataInColumns(self): + """ Yield all data available, with + columns for all data fields of all data templates. + """ + withTemporary = self.request.get('with_temporary') + context = self.context + schemas = [s for s in context.getClientSchemas() if ISchema.providedBy(s)] + headline = (['Client ID', 'Time Stamp'] + + list(itertools.chain(*[[self.encode(f.title) + for f in s.fields + if f.storeData] + for s in schemas]))) + lines = [] + clients = context.getClients() + for name, client in clients.items(): + timeStamp = client.timeStamp + line = [name, timeStamp] + for schema in schemas: + instance = IInstance(client) + instance.template = schema + data = instance.applyTemplate() + for f in schema.fields: + if f.storeData: + line.append(self.encode(data.get(f.name, ''))) + lines.append(line) + lines.sort(key=lambda x: x[1]) + for l in lines: + l[1] = self.getFormattedDate(l[1], type='dateTime', variant='short') + return [headline] + lines + + def render(self): + delimiter = self.delimiter + xlsv = self.request.form.get('xlsv') + if xlsv == '2007': + delimiter = ';' + methodName = self.request.get('get_data_method', 'getAllDataInColumns') + method = getattr(self, methodName, self.getAllDataInColumns) + output = StringIO() + try: + csv.writer(output, dialect='excel', delimiter=delimiter, + quoting=csv.QUOTE_NONNUMERIC).writerows(method()) + except: + import traceback; traceback.print_exc() + raise + result = output.getvalue() + self.setHeaders(len(result)) + return result + + def encode(self, text): + if type(text) is unicode: + result = [] + for c in text: + try: + c = c.encode(self.encoding) + except UnicodeEncodeError: + c = '?' + result.append(c) + text = ''.join(result) + return text diff --git a/composer/schema/client.py b/composer/schema/client.py index faffda0..9aa84e9 100644 --- a/composer/schema/client.py +++ b/composer/schema/client.py @@ -24,6 +24,7 @@ $Id$ from BTrees.OOBTree import OOBTree from persistent import Persistent +from time import time from zope.cachedescriptors.property import Lazy from zope.component import adapts from zope.interface import implements @@ -88,8 +89,11 @@ class Client(Persistent): implements(IClient) + timeStamp = None + def __init__(self, manager=None): self.manager = manager + self.timeStamp = int(time()) class ClientFactory(object): diff --git a/composer/schema/field.py b/composer/schema/field.py index f47b23b..0a90b8a 100644 --- a/composer/schema/field.py +++ b/composer/schema/field.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2009 Helmut Merz helmutm@cy55.de +# Copyright (c) 2010 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 diff --git a/composer/schema/instance.py b/composer/schema/instance.py index 33bee8f..682898f 100644 --- a/composer/schema/instance.py +++ b/composer/schema/instance.py @@ -163,14 +163,14 @@ class ClientInstance(object): template = self.template if template is not None: values = attrs.get(self.aspect, {}) - for f in template.fields: + for f in template.getFields(): if not f.storeData: # a dummy field, e.g. a spacer continue fi = f.getFieldInstance(self) name = f.name #value = values.get(name, u'') - value = values.get(name, f.defaultValue) + value = values.get(name, f.getDefaultValue()) value = mode == 'view' and fi.display(value) or fi.marshall(value) result[name] = value # update result with standard fields: diff --git a/organize/browser/report.py b/organize/browser/report.py index ffa4283..e108e48 100644 --- a/organize/browser/report.py +++ b/organize/browser/report.py @@ -87,7 +87,8 @@ class RegistrationsExportCsv(BaseView): schemas = [s for s in context.getClientSchemas() if ISchema.providedBy(s)] headline = (['Client ID', 'Time Stamp'] + list(itertools.chain(*[[self.encode(f.title) - for f in s.fields] + for f in s.fields + if f.storeData] for s in schemas]))) for s in services: headline.append(self.encode(s.title)) @@ -134,7 +135,8 @@ class RegistrationsExportCsv(BaseView): instance.template = schema data = instance.applyTemplate() for f in schema.fields: - line.append(self.encode(data.get(f.name, ''))) + if f.storeData: + line.append(self.encode(data.get(f.name, ''))) line += regs #if withWaitingList: # line += waiting diff --git a/organize/browser/service.py b/organize/browser/service.py index 84d4d38..979a709 100644 --- a/organize/browser/service.py +++ b/organize/browser/service.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2009 Helmut Merz helmutm@cy55.de +# Copyright (c) 2010 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 @@ -57,15 +57,6 @@ class BaseView(SchemaBaseView): # output formatting - def getFormattedDate(self, date=None, type='date', variant='medium', - adjustTz=False): - if adjustTz: - date = time.gmtime(date)[:6] - else: - date = time.localtime(date)[:6] - date = datetime(*date) - return formatDate(date, type=type, variant=variant, lang=self.getLanguage()) - def getFromTo(self, service=None): if service is None: service = self.context