RegistrationTemplate: headlines, error messages, capacity check; ServiceManager: redirect to registration; dropdown field: empty default entry with informational text

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2126 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-10-29 16:40:00 +00:00
parent 89510875c9
commit dcbe6f15eb
8 changed files with 110 additions and 23 deletions

View file

@ -124,7 +124,10 @@ class BaseView(object):
submit=getCheckoutView,
)
#@Lazy # must be method for Zope 2.9 compatibility :-( ???
@Lazy
def nextUrl(self):
return self.getNextUrl()
def getNextUrl(self):
#viewName = 'thankyou.html'
viewName = ''

View file

@ -73,7 +73,7 @@ class SchemaView(BaseView):
return True
if self.isManageMode:
# Don't store anything when editing
self.request.response.redirect(self.nextUrl())
self.request.response.redirect(self.getNextUrl())
return False
manager = self.context.getManager()
if clientName:

View file

@ -93,9 +93,11 @@ class Field(Component):
def getFieldTypeInfo(self):
return fieldTypes.getTerm(self.fieldType)
def getFieldInstance(self):
def getFieldInstance(self, clientInstance=None):
instanceName = self.getFieldTypeInfo().instanceName
return component.getAdapter(self, IFieldInstance, name=instanceName)
fi = component.getAdapter(self, IFieldInstance, name=instanceName)
fi.clientInstance = clientInstance
return fi
class FieldInstance(object):
@ -111,7 +113,7 @@ class FieldInstance(object):
self.change = None
def marshall(self, value):
return value
return value or u''
#return toStr(value)
def display(self, value):
@ -140,7 +142,7 @@ class NumberFieldInstance(FieldInstance):
def display(self, value):
if value is None:
return '-'
return ''
return str(value)
def unmarshall(self, value):
@ -166,3 +168,9 @@ class FileUploadFieldInstance(FieldInstance):
def unmarshall(self, value):
return value
class CalculatedFieldInstance(FieldInstance):
def marshall(self, value):
return str(value)

View file

@ -50,7 +50,7 @@ class Instance(BaseInstance):
if not f.storeData:
# a dummy field, e.g. a spacer
continue
fi = f.getFieldInstance()
fi = f.getFieldInstance(self)
name = f.name
value = getattr(self.context, name, f.defaultValue)
#value = getattr(self.context, name, u'')
@ -147,9 +147,10 @@ class ClientInstance(object):
if not f.storeData:
# a dummy field, e.g. a spacer
continue
fi = f.getFieldInstance()
fi = f.getFieldInstance(self)
name = f.name
value = values.get(name, u'')
#value = values.get(name, u'')
value = values.get(name, f.defaultValue)
value = mode == 'view' and fi.display(value) or fi.marshall(value)
result[name] = value
# update result with standard fields:

View file

@ -91,17 +91,21 @@ fieldTypes = SimpleVocabulary((
instanceName='fileupload'),
#FieldType('checkbox', 'checkbox', u'Checkbox'),
FieldType('dropdown', 'dropdown', u'Drop-down selection'),
FieldType('calculated', 'display', u'Calculated Value',
instanceName='calculated'),
FieldType('spacer', 'spacer', u'Spacer',
fieldRenderer='field_spacer', storeData=False),
))
# TODO: move this to organize.service...
# TODO: move this to organize.service... (???)
standardFieldNames = SimpleVocabulary((
SimpleTerm('', '', 'Not selected'),
SimpleTerm('lastName', 'lastName', 'Last name'),
SimpleTerm('firstName', 'firstName', 'First name'),
SimpleTerm('organization', 'organization', 'Organization'),
SimpleTerm('email', 'email', 'E-Mail address'),
SimpleTerm('number', 'number', 'Number of participants'),
# TODO: on organize.service: extend this list, e.g. with 'totalCost'
))
class IField(IComponent):
@ -135,7 +139,8 @@ class IField(IComponent):
vocabulary=standardFieldNames,)
defaultValue = schema.TextLine(
title=_(u'Default'),
description=_(u'Value with which to pre-set the field contents'),
description=_(u'Value with which to pre-set the field contents. '
'Use this also for populating a calculated field.'),
required=False,)
required = schema.Bool(
title=_(u'Required'),

View file

@ -72,7 +72,11 @@ class BaseView(SchemaBaseView):
class ServiceManagerView(BaseView):
isManageMode = False
def getCustomView(self):
if self.isManageMode:
return None
viewName = self.context.getViewName()
if viewName:
return component.getMultiAdapter((self.context, self.request),
@ -103,6 +107,10 @@ class ServiceManagerView(BaseView):
tpl = self.getRegistrationTemplate()
return self.getUrlForObject(tpl)
def redirectToRegistration(self):
self.request.response.redirect(self.registrationUrl())
return 'redirect' # let template skip rendering
def overview(self, includeCategories=None):
result = []
classific = []
@ -270,6 +278,8 @@ class ServiceView(BaseView):
class RegistrationTemplateView(BaseView):
state = None
@Lazy
def services(self):
return self.getServices()
@ -278,6 +288,11 @@ class RegistrationTemplateView(BaseView):
return self.context.getServices()
#return sorted(self.context.getServices().values(), key=self.sortKey)
def overview(self):
categories = self.context.categories or None
mv = ServiceManagerView(self.context.getManager(), self.request)
return mv.overview(categories)
def sortKey(self, svc):
return (svc.category, svc.getClassification(), svc.start)
@ -314,6 +329,7 @@ class RegistrationTemplateView(BaseView):
return instance.applyTemplate()
def update(self):
newClient = False
form = self.request.form
clientName = self.getClientName()
if not form.get('action'):
@ -325,13 +341,11 @@ class RegistrationTemplateView(BaseView):
return True
else:
client = IClientFactory(manager)()
clientName = manager.addClient(client)
self.setClientName(clientName)
regs = IClientRegistrations(client)
newClient = True # make persistent later
regs = self.state = IClientRegistrations(client)
regs.template = self.context
services = manager.getServices() # a mapping!
allServices = services.values()
oldServices = [r.service for r in regs.getRegistrations()]
# collect check boxes:
newServices = [services[token]
for token in form.get('service_tokens', [])]
@ -345,10 +359,18 @@ class RegistrationTemplateView(BaseView):
if value > 0:
newServices.append(svc)
numbers.append(value)
regs.validate(clientName, newServices, numbers)
if regs.severity > 0:
return True
if newClient:
clientName = manager.addClient(client)
self.setClientName(clientName)
regs.register(newServices, numbers=numbers)
oldServices = [r.service for r in regs.getRegistrations()]
toDelete = [s for s in oldServices
if s in allServices and s not in newServices]
regs.unregister(toDelete)
#return True
self.request.response.redirect(self.getNextUrl())
return False

View file

@ -128,6 +128,8 @@ class ITask(Interface):
serviceManagerViews = SimpleVocabulary((
SimpleTerm('', '', u'Default view'),
SimpleTerm('events_overview.html', 'events_overview.html', u'Events overview'),
SimpleTerm('redirect_registration.html', 'redirect_registration.html',
u'Redirect to registration')
))
class IServiceManager(Interface):
@ -145,7 +147,7 @@ class IServiceManager(Interface):
viewName = schema.Choice(
title=_(u'View name'),
description=_(u'Select the name of a specialized view to be used '
'for presenting this object.'),
'for presenting this object for visitors.'),
vocabulary=serviceManagerViews,
default='',
required=False,)

View file

@ -160,9 +160,10 @@ class Service(object):
@property
def availableCapacity(self):
if self.capacity >= 0 and len(self.registrations) >= self.capacity:
number = self.getNumberRegistered()
if self.capacity >= 0 and number >= self.capacity:
return 0
return self.capacity - len(self.registrations)
return self.capacity - number
def register(self, client, number=1):
clientName = client.__name__
@ -170,20 +171,22 @@ class Service(object):
reg = self.registrations[clientName]
if number != reg.number:
reg.number = number
#self.registrations[clientName] = reg # persistence hack
return reg
reg = self.registrationFactory(client, self, number)
self.registrations[clientName] = reg
return reg
#if self.availableCapacity:
# TODO: handle case when no capacity available -
# probably on 'submit' transition; UI feedback?
def unregister(self, client):
clientName = client.__name__
if clientName in self.registrations:
del self.registrations[clientName]
def getNumberRegistered(self):
result = 0
for r in self.registrations.values():
result += r.number
return result
# default methods
def getAllowRegWithNumberFromManager(self):
return getattr(self.getManager(), 'allowRegWithNumber', None)
@ -240,6 +243,9 @@ class ClientRegistrations(object):
registrationsAttributeName = '__service_registrations__'
errors = None
severity = 0
def __init__(self, context):
self.context = context
@ -266,6 +272,46 @@ class ClientRegistrations(object):
regs = (r for r in regs if r.service in svcs)
return regs
def validate(self, clientName, services, numbers=None):
self.errors = {}
if numbers is None:
numbers = len(services) * [1]
for svc, n in zip(services, numbers):
oldReg = svc.registrations.get(clientName, None)
oldN = oldReg and oldReg.number or 0
if svc.capacity and svc.capacity > 0 and svc.availableCapacity < n - oldN:
error = registrationErrors['capacity_exceeded']
entry = self.errors.setdefault(svc.token, [])
entry.append(error)
self.severity = max(self.severity, error.severity)
class RegistrationError(object):
def __init__(self, title, description=None, severity=5, **kw):
self.title = title
self.description = description or title
self.severity = severity
for k, v in kw.items():
setattr(self, k, v)
def __str__(self):
return self.title
def __repr__(self):
return "RegistrationError('%s')" % self.title
registrationErrors = dict(
capacity_exceeded=RegistrationError(
u'The capacity for this service has been exceeded.'),
time_conflict=RegistrationError(
u'You have registered already for another service at the same time.'),
number_exceeded=RegistrationError(
u'The total number of participants you are registering is less than the '
'number of persons you want to register for this service.'),
)
# registration states