"""Containers for certificates. """ import grok from zope.catalog.interfaces import ICatalog from zope.component.interfaces import IFactory from zope.component import queryUtility from zope.interface import implementedBy from waeup.sirp.interfaces import DuplicationError from waeup.sirp.university.interfaces import ( ICertificateContainer, ICertificate) class CertificateContainer(grok.Container): """A storage for certificates. A :class:`CertificateContainer` stores :class:`waeup.sirp.university.Certificate` instances. It is a :class:`grok.Container` basically acting like a standard Python dictionary. That means you can add certificates like items in a normal dictionary and also get certificates by using :meth:`values`, :meth:`keys`, and :meth:`items`. This container type is picky about its contents: only real certificates can be stored here and each new certificate must provide a unique `code`. See :meth:`addCertificate` for details. Each :class:`CertificateContainer` provides :class:`ICertificateContainer`. """ grok.implements(ICertificateContainer) grok.require('waeup.manageUniversity') def __setitem__(self, name, certificate): """Insert `certificate` with `name` as key into container. The `certificate` must be an object implementing :class:`waeup.sirp.university.interfaces.ICertificate`. If not, a :exc:`TypeError` is raised. If the certificate `code` does not equal `name` a :exc:`ValueError` is raised. If the `code` attribute of `certificate` is already in use by another certificate stored in the local site (:class:`waeup.sirp.app.University` instance), then a :exc:`waeup.sirp.interfaces.DuplicationError` will be raised. If `name` is already used as a key, a :exc:`KeyError` will be raised. """ if not ICertificate.providedBy(certificate): raise TypeError('CertificateContainers contain only ' 'ICertificate instances') # Only accept certs with code == key. if certificate.code != name: raise ValueError('key must match certificate code: ' '%s, %s' % (name, certificate.code)) # Lookup catalog. If we find none: no duplicates possible. cat = queryUtility(ICatalog, name='certificates_catalog', default=None) if cat is not None: entries = cat.searchResults( code=(certificate.code,certificate.code)) if len(entries) > 0: raise DuplicationError( 'Certificate exists already elsewhere.', entries) else: # No catalog, then this addition won't do harm to anything. pass super(CertificateContainer, self).__setitem__(name, certificate) def addCertificate(self, certificate): """Add `certificate` to the container. The certificate must be an object implementing :class:`waeup.sirp.university.interfaces.ICertificate`. If not, a :exc:`TypeError` is raised. The certificate will be stored in the container with its `code` attribute as key. If this key is already used for another certificate stored in the local site (:class:`waeup.sirp.app.University` instance), then a :exc:`waeup.sirp.interfaces.DuplicationError` will be raised. """ self[getattr(certificate, 'code', None)] = certificate def clear(self): """Remove all contents from the certificate container. This methods is pretty fast and optimized. Use it instead of removing all items manually yourself. """ # This internal function is implemented in C and thus much # faster as we could do it in pure Python. self._SampleContainer__data.clear() # The length attribute is 'lazy'. See `zope.container` for details. # This way we make sure, the next time len() is called, it returns # the real value and not a cached one. del self.__dict__['_BTreeContainer__len'] class CertificateContainerFactory(grok.GlobalUtility): """A factory for certificate containers. """ grok.implements(IFactory) grok.name(u'waeup.CertificateContainer') title = u"Create a new certificate container.", description = u"This factory instantiates new certificate containers." def __call__(self, *args, **kw): return CertificateContainer(*args, **kw) def getInterfaces(self): return implementedBy(CertificateContainer)