diff --git a/organize/browser/configure.zcml b/organize/browser/configure.zcml new file mode 100644 index 0000000..556aa8d --- /dev/null +++ b/organize/browser/configure.zcml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/organize/browser/service.py b/organize/browser/service.py new file mode 100644 index 0000000..23e75f5 --- /dev/null +++ b/organize/browser/service.py @@ -0,0 +1,92 @@ +# +# 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 +# + +""" +Basic browser view classes for composer.schema. + +$Id$ +""" + +from zope import component +from zope.cachedescriptors.property import Lazy + +from cybertools.organize.interfaces import IClientRegistrations +from cybertools.composer.schema.interfaces import IClientFactory + + +class RegistrationTemplateView(object): + + clientName = None + + def __init__(self, context, request): + self.context = context + self.request = request + + @Lazy + def services(self): + return self.context.services + + def getRegistrations(self): + if not self.clientName: + form = self.request.form + self.clientName = form.get('id') + clientName = self.clientName + if not clientName: + return [] + manager = self.context.getManager() + client = manager.getClients().get(clientName) + if client is None: + return [] + regs = IClientRegistrations(client) + regs.template = self.context + return regs.getRegistrations() + + def update(self): + form = self.request.form + if not self.clientName: + self.clientName = form.get('id') + clientName = self.clientName + if not form.get('action'): + return True + manager = self.context.getManager() + if clientName: + client = manager.getClients().get(clientName) + if client is None: + return True + else: + client = IClientFactory(manager)() + clientName = self.clientName = manager.addClient(client) + regs = IClientRegistrations(client) + regs.template = self.context + allServices = self.context.services.values() + oldServices = [r.service for r in regs.getRegistrations()] + newServices = [manager.services[token] + for token in form.get('service_tokens', [])] + regs.register(newServices) + 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.nextUrl) + #return False + + @Lazy + def nextUrl(self): + from zope.traversing.browser import absoluteURL + url = absoluteURL(self.context, self.request) + return '%s/thankyou.html?id=%s' % (url, self.clientName) diff --git a/organize/interfaces.py b/organize/interfaces.py index a270565..9a68445 100644 --- a/organize/interfaces.py +++ b/organize/interfaces.py @@ -141,7 +141,11 @@ class IService(Interface): """ A service that clients may register with. """ - serviceGroup = Attribute('The service group this object is an instance of.') + category = schema.TextLine( + title=_(u'Category'), + description=_(u'A tokenized term characterizing the type of ' + 'this service, e.g. an event or a transport.'), + required=False,) capacity = schema.Int( title=_(u'Capacity'), description=_(u'The capacity (maximum number of clients) ' @@ -152,6 +156,13 @@ class IService(Interface): 'still available; a negative number means: ' 'no restriction, i.e. unlimited capacity; ' 'read-only') + + token = Attribute('A name unique within the manager of this service ' + 'used for identifying the service e.g. in forms.') + serviceGroup = Attribute('The service group this object is an instance of.') + classification = Attribute('A sequence of tokenized terms characterizing ' + 'this service within a hierarchy of concepts.') + serviceProviders = Attribute('A collection of one or more service providers.') resources = Attribute('A collection of one or more resources.') registrations = Attribute('A collection of client registrations.') @@ -162,6 +173,10 @@ class IService(Interface): (e.g. if the service's capacity is exhausted) return None. """ + def unregister(client): + """ Remove the client from this service's registrations. + """ + class IScheduledService(IService): """ A service that starts at a certain date/time and @@ -205,9 +220,42 @@ class IRegistration(Interface): class IRegistrationTemplate(Interface): - """ Provides and processes data for a service registration form. + """ A content object controlling access to service registrations + of a certain client. + + The client should be accessed via an IClientRegistrations adapter. """ + # TODO: provide fields for criteria for selecting the services + # that should be handled by this object, e.g. service + # category/ies or classification(s). + + manager = Attribute('The service manager this object belongs to.') + services = Attribute('A collection of services to which this ' + 'object provides access. This may be all or part ' + 'of the services managed by the manager.') + + +class IClientRegistrations(Interface): + """ Provides access to a client object and allows to manage its service + registrations. + """ + + template = Attribute('A regstration template that is used ' + 'for controlling the registration process.') + + def register(services): + """ Register the client for the services given. + """ + + def unregister(services): + """ Remove the client from the services given. + """ + + def getRegistrations(): + """ Return the client's service registrations. + """ + class IResource(Interface): """ A resource is needed by a service to be able to work, e.g. a diff --git a/organize/service.py b/organize/service.py index 76faf8e..3667a3a 100644 --- a/organize/service.py +++ b/organize/service.py @@ -29,20 +29,24 @@ from zope.interface import implements from cybertools.composer.interfaces import IInstance from cybertools.util.jeep import Jeep -from cybertools.composer.schema.interfaces import IClientManager +from cybertools.composer.schema.interfaces import IClientManager, IClient from cybertools.organize.interfaces import IServiceManager from cybertools.organize.interfaces import IService, IScheduledService from cybertools.organize.interfaces import IRegistration, IRegistrationTemplate +from cybertools.organize.interfaces import IClientRegistrations class ServiceManager(object): implements(IServiceManager, IClientManager) - servicesFactory = list + servicesFactory = Jeep clientSchemasFactory = Jeep clientsFactory = OOBTree + services = None + clients = None + clientNum = 0 def __init__(self): @@ -73,9 +77,17 @@ class Service(object): implements(IService) - def __init__(self, capacity=-1): + registrationsFactory = OOBTree + + def __init__(self, name=None, capacity=-1): + self.name = name self.capacity = capacity - self.registrations = [] + if self.registrationsFactory is not None: + self.registrations = self.registrationsFactory() + + @property + def token(self): + return self.name @property def availableCapacity(self): @@ -84,27 +96,74 @@ class Service(object): return self.capacity - len(self.registrations) def register(self, client): + clientName = client.__name__ + if clientName in self.registrations: + return self.registrations[clientName] if self.availableCapacity: - reg = Registration(client) - self.registrations.append(reg) + reg = Registration(client, self) + self.registrations[clientName] = reg return reg return None + def unregister(self, client): + clientName = client.__name__ + if clientName in self.registrations: + del self.registrations[clientName] + class ScheduledService(Service): implements(IScheduledService) +# registration + class Registration(object): implements(IRegistration) - def __init__(self, client): + def __init__(self, client, service): self.client = client + self.service = service class RegistrationTemplate(object): implements(IRegistrationTemplate) + def __init__(self, name=None, manager=None): + self.name = name + self.manager = manager + + @property + def services(self): + return self.manager.services + + def getManager(self): + return self.manager + + +class ClientRegistrations(object): + + implements(IClientRegistrations) + adapts(IClient) + + template = None + + def __init__(self, context): + self.context = context + + def register(self, services): + for service in services: + service.register(self.context) + + def unregister(self, services): + for service in services: + service.unregister(self.context) + + def getRegistrations(self): + for service in self.template.services: + for reg in service.registrations.values(): + if self.context == reg.client: + yield reg +