source: waeup/branches/ulif-namespace/src/sirp/university/certificate.txt @ 4791

Last change on this file since 4791 was 4789, checked in by uli, 15 years ago

Merge changes from ulif-layout back into trunk (finally).

File size: 12.6 KB
Line 
1:mod:`waeup.university.certificate` -- Certificates for WAeUP
2*************************************************************
3
4.. module:: waeup.university.certificate
5
6Components that represent and manage certificates.
7
8:Test-Layer: unit
9
10Because certificates make use of components registered with the Zope
11Component Architecture (ZCA), we first have to grok the `waeup`
12package. This happens automatically in real-world use:
13
14    >>> import grok
15    >>> grok.testing.grok('waeup')
16
17
18Content Classes (models and containers)
19=======================================
20
21
22:class:`Certificate`
23--------------------
24
25.. class:: Certificate([code=u'NA',[ title=u'Unnamed Certificate',[ category=None,[ study_mode=None,[ start_level=None,[ end_level=None,[ application_category=None,[ m_prefix=u'',[  max_pass = u'']]]]]]]]])
26
27   Create a certificate object with the given parameters.
28
29   .. attribute:: grok.implements(ICertificate)
30
31   All parameters are optional:
32
33     >>> from waeup.university.certificate import Certificate
34     >>> mycertificate = Certificate()
35
36   Certificates have the attributes required by the `ICertificate` interface:
37
38     >>> from waeup.interfaces import ICertificate
39     >>> ICertificate.providedBy(mycertificate)
40     True
41
42     >>> from zope.interface.verify import verifyObject
43     >>> verifyObject(ICertificate, mycertificate)
44     True
45
46   Beside the attributes, certificates are containers for
47   certificate-courses (see :class:`CertificateCourse`). Each
48   certificate course can be accessed by the code of the course it wraps.
49
50   .. attribute:: title
51
52      Each certificate has a title:
53
54        >>> mycertificate.title
55        u'Unnamed Certificate'
56
57   .. attribute:: code
58
59      Each certificate holds a code, which might be a shortcut or
60      abbreviation of the real certificate name. By default the code
61      is ``NA`` (=not assigned):
62
63        >>> mycertificate.code
64        u'NA'
65
66   .. attribute:: review_state
67
68      The review state can have one of the ``checking`` states defined
69      in the WAeUP workflow. These are at least the states ``checked``
70      and ``unchecked``. After a certificate is created, the review
71      state is ``unchecked``:
72
73        >>> mycertificate.review_state
74        'unchecked'
75
76      .. seealso::
77         :meth:`Certificate.check` -- mark a certificate as ``checked``
78
79   .. attribute:: category
80
81      Each :class:`Certificate` instance has a category:
82
83        >>> print mycertificate.category
84        None
85
86      .. XXX: This is not a proper description
87
88   .. attribute:: study_mode
89
90      Each :class:`Certificate` instance has a study mode:
91
92        >>> print mycertificate.study_mode
93        None
94
95      .. XXX: This is not a proper description
96
97   .. attribute:: start_level
98
99      Each :class:`Certificate` instance has a start level:
100
101        >>> print mycertificate.start_level
102        None
103
104      .. XXX: This is not a proper description
105
106   .. attribute:: end_level
107
108      Each :class:`Certificate` instance has a end level:
109
110        >>> print mycertificate.end_level
111        None
112
113      .. XXX: This is not a proper description
114   
115
116   .. attribute:: application_category
117
118      Each :class:`Certificate` instance has an application category:
119
120        >>> print mycertificate.application_category
121        None
122
123      .. XXX: This is not a proper description
124
125   
126   .. attribute:: m_prefix
127
128      Each :class:`Certificate` instance has an ``m_prefix``:
129
130        >>> mycertificate.m_prefix
131        u''
132
133      .. XXX: This is not a proper description
134
135   
136   .. attribute:: max_pass
137
138      Each :class:`Certificate` instance has a maximum number of passes:
139
140        >>> mycertificate.max_pass
141        u''
142
143      .. XXX: This is not a proper description
144
145
146   .. method:: check()
147
148      Mark a certificate instance's review state as ``checked``:
149
150        >>> mycertificate.review_state
151        'unchecked'
152
153        >>> mycertificate.check()
154        >>> mycertificate.review_state
155        'checked'
156
157      We cannot uncheck a certificate:
158
159        >>> mycertificate.review_state = 'unchecked'
160        Traceback (most recent call last):
161        ...
162        NoTransitionAvailableError
163
164      The only states accepted at all are ``checked`` and
165      ``unchecked``. If we want to set something else this won't work:
166
167        >>> mycertificate.review_state = 'nonsense'
168        Traceback (most recent call last):
169        ...
170        NoTransitionAvailableError
171
172
173   .. method:: addCourseRef(course[, level=100,[ core_or_elective=True]])
174
175      Add a reference to a course. A course is an object implementing
176      :class:`waeup.interfaces.ICourse`.
177
178      Please don't be confused by the term 'reference'. This just
179      means an ordinary :class:`waeup.university.course.Course` object
180      in almost all cases. As this object will normaly be one stored
181      in a department, the course here will simply become a reference
182      to the 'real' one in the department container.
183
184   .. method:: delCourseRef(code)
185
186      Remove a course from a certificate.
187
188      The course must be given by its code number.
189
190:class:`CertificateCourse`
191--------------------------
192
193.. class:: CertificateCourse(course[, level=100[, core_or_elective=True]])
194
195   Create a certificate course.
196
197   A certificate-course is a course (:class:`Course`) which is part of
198   a certificate. Normally, certificate-courses are held in
199   certificates and refer to an existing :class:`Course` instance held
200   elsewhere.
201
202   A certificate can require several courses and one
203   course can be required by several certificates.
204
205   .. attribute:: course
206
207      An instance of :class:`ICourse`.
208
209   .. attribute:: level
210
211      An integer telling the level to which this course applies.
212
213   .. attribute:: core_or_elective
214
215      A bool stating whether this course is required or optional to
216      get the certificate.
217
218
219
220Utilities
221=========
222
223:class:`CertificateFactory`
224---------------------------
225
226.. class:: CertificateFactory()
227
228   .. attribute:: grok.name(u'waeup.Certificate')
229
230   .. attribute:: grok.implements(IFactory)
231
232   A named utility to deliver new instances of :class:`Certificate`
233   without the need to import the implementation before:
234
235     >>> from zope.component import createObject
236     >>> mycertificate = createObject(u'waeup.Certificate')
237     >>> mycertificate
238     <waeup.university.certificate.Certificate object at 0x...>
239
240   The factory complies with the specifications from the
241   :class:`IFactory` insterface:
242
243     >>> from zope.interface.verify import verifyClass
244     >>> from zope.component.interfaces import IFactory
245     >>> from waeup.university.certificate import CertificateFactory
246     >>> verifyClass(IFactory, CertificateFactory)
247     True
248
249   This means also, that we can get the interfaces of the created
250   object from the factory:
251
252     >>> certificate_factory = CertificateFactory()
253     >>> certificate_factory.getInterfaces()
254     <implementedBy waeup.university.certificate.Certificate>
255
256
257:class:`CertificateCourseFactory`
258---------------------------------
259
260.. class:: CertificateCourseFactory()
261
262   .. attribute:: grok.name(u'waeup.CertificateCourse')
263
264   .. attribute:: grok.implements(IFactory)
265
266   A named utility to deliver new instances of :class:`CertificateCourse`
267   without the need to import the implementation before:
268
269     >>> from zope.component import createObject
270     >>> mycertificatecourse = createObject(u'waeup.CertificateCourse')
271     >>> mycertificatecourse
272     <waeup.university.certificate.CertificateCourse object at 0x...>
273
274   The factory complies with the specifications from the
275   :class:`IFactory` insterface:
276
277     >>> from zope.interface.verify import verifyClass
278     >>> from zope.component.interfaces import IFactory
279     >>> from waeup.university.certificate import CertificateCourseFactory
280     >>> verifyClass(IFactory, CertificateCourseFactory)
281     True
282
283   This means also, that we can get the interfaces of the created
284   object from the factory:
285
286     >>> certcourse_factory = CertificateCourseFactory()
287     >>> certcourse_factory.getInterfaces()
288     <implementedBy waeup.university.certificate.CertificateCourse>
289
290
291Event Subscribers
292=================
293
294.. function:: removedCourseHandler(course, event)
295
296   An event subscriber triggered for
297   :class:`grok.IObjectRemovedEvent`s, when an :class:`ICourse`
298   instance is removed from a container.
299
300   Tries to remove all referencing :class:`CertificateCourse`
301   instances that reference the removed course.
302
303   To accomplish that, the parents of the removed course are looked up
304   for a certifcate container which contains a certificate-course that
305   contains a reference to the deleted course.
306
307   .. seealso:: :ref:`removecertificatecourses`
308
309   **handles:**
310     :class:`ICourse`
311
312   **event type:**
313     :class:`grok.IObjectRemovedEvent`
314
315Examples
316========
317
318Certificates
319------------
320
321We can create certificates:
322
323    >>> from waeup.university.certificate import Certificate
324    >>> mycertificate = Certificate()
325    >>> mycertificate
326    <waeup.university.certificate.Certificate object at 0x...>
327
328Another way to create certificates is by asking for a factory called
329``waeup.Certificate``. This way we can create a factory without
330importing a class:
331
332    >>> from zope.component import createObject
333    >>> mycertificate = createObject(u'waeup.Certificate')
334    >>> mycertificate
335    <waeup.university.certificate.Certificate object at 0x...>
336
337CertificateCourses
338------------------
339
340:class:`CertificateCourse` instances comply with the
341:class:`ICertificateCourse` interface:
342
343    >>> from waeup.interfaces import ICertificateCourse
344    >>> from waeup.university.certificate import CertificateCourse
345    >>> mycertcourse = CertificateCourse(None, 200, False)
346    >>> ICertificateCourse.providedBy(mycertcourse)
347    True
348
349    >>> from zope.interface.verify import verifyObject
350    >>> verifyObject(ICertificateCourse, mycertcourse)
351    True
352
353Also instances of :class:`CertificateCourse` can be created by asking
354the component architechture:
355
356    >>> from zope.component import createObject
357    >>> mycertcourse = createObject(u'waeup.CertificateCourse')
358    >>> mycertcourse
359    <waeup.university.certificate.CertificateCourse object at 0x...>
360
361.. _removecertificatecourses:
362
363Persistence of certificate courses
364----------------------------------
365
366If a certificate course requires a certain course and this is course
367is deleted, also the referencing certificate course is deleted.
368
369We setup a data structure that reflects typical usage. It looks like
370this::
371
372    Department-Instance
373    |
374    +---> courses
375    |        |
376    |        +--------------------> Course-Instance
377    |                                        ^
378    +---> certificates                       |
379             |                               |
380             +-----> Certificate-Instance    |
381                        |                    |
382                        +------> Certificate-Course
383
384The certifcate-Course here refers to a Course-Instance.
385
386In Python we build such a structure like this (from top to bottom):
387
388    >>> from zope.component import createObject
389    >>> mydept = createObject('waeup.Department')
390
391In real world use this data will be stored in a ZODB. We setup our own
392litte ZODB backend (which is easy!):
393
394    >>> from ZODB import FileStorage, DB
395    >>> dbpath = 'tinyData.fs'
396    >>> class TinyZODB(object):
397    ...   def __init__(self, path=dbpath):
398    ...     self.storage = FileStorage.FileStorage(path)
399    ...     self.db = DB(self.storage)
400    ...     self.connection = self.db.open()
401    ...     self.dbroot = self.connection.root()
402    ...   def close(self):
403    ...     self.connection.close()
404    ...     self.db.close()
405    ...     self.storage.close()
406
407Now we can use this ZODB as backend database and store our data
408structure:
409
410    >>> import transaction
411    >>> db = TinyZODB()
412    >>> dbroot = db.dbroot
413    >>> dbroot['mydept'] = mydept
414    >>> mycourse = createObject('waeup.Course')
415    >>> mycourse.code = 'MYCOURSE'
416    >>> mydept.courses.addCourse(mycourse)
417    >>> mycert = createObject('waeup.Certificate')
418    >>> mycert.code = 'MYCERT'
419    >>> mydept.certificates.addCertificate(mycert)
420    >>> mycert.addCourseRef(mycourse)
421
422    >>> transaction.commit()
423
424The data is now stored in the ZODB. We can close the DB, reopen it
425later and the data will still be there:
426
427    >>> db.close()
428    >>> newdb = TinyZODB()
429    >>> newdbroot = newdb.dbroot
430    >>> list(newdbroot)
431    ['mydept']
432
433The certificate-course we stored in the certificate is indeed a
434reference to the course, not a copy of it:
435
436    >>> course = newdbroot['mydept'].courses['MYCOURSE']
437    >>> certcourse = newdbroot['mydept'].certificates['MYCERT']['MYCOURSE_100']
438    >>> certcourse.course is course
439    True
440
441So, we can be sure that modifications to the course are immediately
442reflected in the certcourse.
443
Note: See TracBrowser for help on using the repository browser.