diff --git a/composer/schema/README.txt b/composer/schema/README.txt index 61a54ff..77ddccd 100644 --- a/composer/schema/README.txt +++ b/composer/schema/README.txt @@ -93,8 +93,9 @@ Using a more specialized schema factory lastName Last name textline age Age number + Access and update a context object using a schema-based form ------------------------------------------------------------- +============================================================ >>> from zope.publisher.browser import TestRequest >>> from cybertools.composer.schema.browser.form import Form diff --git a/composer/schema/field.py b/composer/schema/field.py index 17bf4cd..6fc946d 100644 --- a/composer/schema/field.py +++ b/composer/schema/field.py @@ -170,6 +170,13 @@ class FileUploadFieldInstance(FieldInstance): return value +class EmailFieldInstance(FieldInstance): + + def validate(self, value, data=None): + if value and '@' not in value: + self.setError('invalid_email_address') + + class CalculatedFieldInstance(FieldInstance): def marshall(self, value): diff --git a/composer/schema/interfaces.py b/composer/schema/interfaces.py index 7e8ed7a..f80f47d 100644 --- a/composer/schema/interfaces.py +++ b/composer/schema/interfaces.py @@ -87,6 +87,8 @@ fieldTypes = SimpleVocabulary(( FieldType('number', 'number', u'Number', inputRenderer='input_textline', instanceName='number'), FieldType('date', 'date', u'Date'), + FieldType('email', 'email', u'E-Mail Address', + inputRenderer='input_textline', instanceName='email'), FieldType('fileupload', 'fileupload', u'File upload', instanceName='fileupload'), #FieldType('checkbox', 'checkbox', u'Checkbox'), diff --git a/composer/schema/schema.py b/composer/schema/schema.py index 50e5333..3a86f2e 100644 --- a/composer/schema/schema.py +++ b/composer/schema/schema.py @@ -90,4 +90,6 @@ formErrors = dict( u'Please enter data for required field.'), invalid_number=FormError(u'Invalid number', u'Please enter a number, only digits allowed.'), + invalid_email_address=FormError(u'Invalid E-Mail Address', + u'Please enter a correct email address.'), ) diff --git a/organize/browser/report.py b/organize/browser/report.py new file mode 100644 index 0000000..a3ce0a1 --- /dev/null +++ b/organize/browser/report.py @@ -0,0 +1,86 @@ +# +# Copyright (c) 2007 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 +from zope import component +from zope.cachedescriptors.property import Lazy +from cybertools.composer.interfaces import IInstance +from cybertools.stateful.interfaces import IStateful + + +class RegistrationsExportCsv(object): + + 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 getData(self): + withTemporary = self.request.get('with_temporary') + yield ['Service', 'Client ID', 'Organization', 'First Name', 'Last Name', 'E-Mail', + 'Number', 'State'] + for service in self.context.getServices(): + for clientName, reg in service.registrations.items(): + client = reg.client + data = IInstance(client).applyTemplate() + state = IStateful(reg).getStateObject() + if state.name == 'temporary' and not withTemporary: + continue + yield [encode(service.title) or service.name, + clientName, + encode(data.get('standard.organization', '')), + encode(data.get('standard.lastName', '')), + encode(data.get('standard.firstName', '')), + encode(data.get('standard.email', '')), + reg.number, + state.title + ] + + def render(self): + output = StringIO() + csv.writer(output).writerows(self.getData()) + result = output.getvalue() + self.setHeaders(len(result)) + return result + + def render2(self): + # using cybertools.reporter.resultset + rs = self.getData() # returns a ResultSet + result = rs.asCsv() + self.setHeaders(len(result)) + return result + + +def encode(text, encoding='UTF-8'): + if type(text) is unicode: + text = text.encode(encoding) + return text diff --git a/organize/browser/service.py b/organize/browser/service.py index f90823c..0db036b 100644 --- a/organize/browser/service.py +++ b/organize/browser/service.py @@ -276,6 +276,13 @@ class ServiceView(BaseView): def getRegistrations(self): return self.context.registrations + def listRegistrations(self): + if self.request.get('with_temporary'): + return self.getRegistrations() + regs = self.getRegistrations() + return (name for name, reg in regs.items() + if IStateful(reg).getState() != 'temporary') + def getRegistrationTemplate(self): context = self.context man = context.getManager()