source: main/waeup.sirp/branches/accesscodes-with-workflow/src/waeup/sirp/university/certificatecontainer.py @ 6401

Last change on this file since 6401 was 6243, checked in by Henrik Bettermann, 13 years ago

Use DuplicationError? exception for batching (data import).

File size: 4.5 KB
Line 
1"""Containers for certificates.
2"""
3import grok
4from zope.catalog.interfaces import ICatalog
5from zope.component.interfaces import IFactory
6from zope.component import queryUtility
7from zope.interface import implementedBy
8from waeup.sirp.interfaces import DuplicationError
9from waeup.sirp.university.interfaces import (
10    ICertificateContainer, ICertificate)
11
12class CertificateContainer(grok.Container):
13    """A storage for certificates.
14
15    A :class:`CertificateContainer` stores
16    :class:`waeup.sirp.university.Certificate` instances.
17
18    It is a :class:`grok.Container` basically acting like a standard
19    Python dictionary. That means you can add certificates like items
20    in a normal dictionary and also get certificates by using
21    :meth:`values`, :meth:`keys`, and :meth:`items`.
22
23    This container type is picky about its contents: only real
24    certificates can be stored here and each new certificate must
25    provide a unique `code`. See :meth:`addCertificate` for details.
26
27    Each :class:`CertificateContainer` provides
28    :iface:`ICertificateContainer`.
29    """
30    grok.implements(ICertificateContainer)
31    grok.require('waeup.manageUniversity')
32
33    def __setitem__(self, name, certificate):
34        """Insert `certificate` with `name` as key into container.
35
36        The `certificate` must be an object implementing
37        :iface:`waeup.sirp.university.interfaces.ICertificate`. If
38        not, a :exc:`TypeError` is raised.
39
40        If the certificate `code` does not equal `name` a
41        :exc:`ValueError` is raised.
42
43        If the `code` attribute of `certificate` is already in use by
44        another certificate stored in the local site
45        (:class:`waeup.sirp.app.University` instance), then a
46        :exc:`waeup.sirp.interfaces.DuplicationError` will be raised.
47
48        If `name` is already used as a key, a :exc:`KeyError` will be
49        raised.
50        """
51        if not ICertificate.providedBy(certificate):
52            raise TypeError('CertificateContainers contain only '
53                            'ICertificate instances')
54
55        # Only accept certs with code == key.
56        if certificate.code != name:
57            raise ValueError('key must match certificate code: '
58                             '%s, %s' % (name, certificate.code))
59
60        # Lookup catalog. If we find none: no duplicates possible.
61        cat = queryUtility(ICatalog, name='certificates_catalog', default=None)
62        if cat is not None:
63            entries = cat.searchResults(
64                code=(certificate.code,certificate.code))
65            if len(entries) > 0:
66                raise DuplicationError(
67                    'Certificate exists already elsewhere.', entries)
68        else:
69            # No catalog, then this addition won't do harm to anything.
70            pass
71        super(CertificateContainer, self).__setitem__(name, certificate)
72
73    def addCertificate(self, certificate):
74        """Add `certificate` to the container.
75
76        The certificate must be an object implementing
77        :iface:`waeup.sirp.university.interfaces.ICertificate`. If
78        not, a :exc:`TypeError` is raised.
79
80        The certificate will be stored in the container with its
81        `code` attribute as key. If this key is already used for
82        another certificate stored in the local site
83        (:class:`waeup.sirp.app.University` instance), then a
84        :exc:`waeup.sirp.interfaces.DuplicationError` will be raised.
85        """
86        self[getattr(certificate, 'code', None)] = certificate
87
88    def clear(self):
89        """Remove all contents from the certificate container.
90
91        This methods is pretty fast and optimized. Use it instead of
92        removing all items manually yourself.
93        """
94        # This internal function is implemented in C and thus much
95        # faster as we could do it in pure Python.
96        self._SampleContainer__data.clear()
97        # The length attribute is 'lazy'. See `zope.container` for details.
98        # This way we make sure, the next time len() is called, it returns
99        # the real value and not a cached one.
100        del self.__dict__['_BTreeContainer__len']
101
102class CertificateContainerFactory(grok.GlobalUtility):
103    """A factory for certificate containers.
104    """
105    grok.implements(IFactory)
106    grok.name(u'waeup.CertificateContainer')
107    title = u"Create a new certificate container.",
108    description = u"This factory instantiates new certificate containers."
109
110    def __call__(self, *args, **kw):
111        return CertificateContainer(*args, **kw)
112
113    def getInterfaces(self):
114        return implementedBy(CertificateContainer)
Note: See TracBrowser for help on using the repository browser.