source: main/waeup.sirp/trunk/src/waeup/sirp/university/certificate.txt @ 6117

Last change on this file since 6117 was 5978, checked in by Henrik Bettermann, 14 years ago

Fix tests.

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