source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/interfaces.py @ 7262

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

Add Applicant Importer (tests will follow).

  • Property svn:keywords set to Id
File size: 14.1 KB
Line 
1## $Id: interfaces.py 7262 2011-12-04 08:36:14Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""Interfaces of the university application package.
19"""
20
21from grokcore.content.interfaces import IContainer
22
23from zope import schema
24from zope.interface import Interface, Attribute
25from zope.component import getUtilitiesFor
26from zc.sourcefactory.basic import BasicSourceFactory
27from waeup.sirp.interfaces import (
28    IWAeUPObject, year_range, validate_email, academic_sessions_vocab)
29from waeup.sirp.university.vocabularies import application_categories
30from waeup.sirp.students.vocabularies import (
31  lgas_vocab, CertificateSource, GenderSource,
32  )
33from waeup.sirp.applicants.vocabularies import (
34  application_types_vocab, application_pins_vocab,
35  AppCatCertificateSource,
36  )
37from waeup.sirp.payments.interfaces import IOnlinePayment
38
39#: Maximum upload size for applicant passport photographs (in bytes)
40MAX_UPLOAD_SIZE = 1024 * 20
41
42class ApplicantContainerProviderSource(BasicSourceFactory):
43    """A source offering all available applicants container types.
44
45    The values returned by this source are names of utilities that can
46    create :class:`ApplicantContainer` instances. So, if you get a
47    name like ``'myactype'`` from this source, then you can do:
48
49      >>> from zope.component import getUtility
50      >>> p = getUtility(IApplicantsContainerProvider, name=myactype)
51      >>> my_applicants_container = p.factory()
52
53    Or you can access class-attributes like
54
55      >>> my_applicants_container.container_title
56      'Pretty'
57
58    """
59    def getValues(self):
60        """Returns a list of ``(<name>, <provider>)`` tuples.
61
62        Here ``<name>`` is the name under which an
63        :class:``ApplicantContainerProvider`` was registered as a
64        utility and ``<provider>`` is the utility itself.
65        """
66        return getUtilitiesFor(IApplicantsContainerProvider)
67
68    def getToken(self, value):
69        """Return the name of the ``(<name>, <provider>)`` tuple.
70        """
71        return value[0]
72
73    def getTitle(self, value):
74        """Get a 'title - description' string for a container type.
75        """
76        factory = value[1].factory
77        return "%s - %s" % (
78            factory.container_title, factory.container_description)
79
80class IApplicantsRoot(IWAeUPObject, IContainer):
81    """A container for university applicants containers.
82    """
83    pass
84
85class IApplicantsContainer(IWAeUPObject):
86    """An applicants container contains university applicants.
87
88    """
89
90    container_title = Attribute(
91        u'classattribute: title for type of container')
92    container_description = Attribute(
93        u'classattribute: description for type of container')
94
95
96    code = schema.TextLine(
97        title = u'Code',
98        default = u'-',
99        required = True,
100        readonly = True,
101        )
102
103    title = schema.TextLine(
104        title = u'Title',
105        required = True,
106        default = u'-',
107        readonly = True,
108        )
109
110    prefix = schema.Choice(
111        title = u'Application target',
112        required = True,
113        default = None,
114        source = application_types_vocab,
115        readonly = True,
116        )
117
118    year = schema.Choice(
119        title = u'Year of entrance',
120        required = True,
121        default = None,
122        values = year_range(),
123        readonly = True,
124        )
125
126    provider = schema.Choice(
127        title = u'Applicants container type',
128        required = True,
129        default = None,
130        source = ApplicantContainerProviderSource(),
131        readonly = True,
132        )
133
134    ac_prefix = schema.Choice(
135        title = u'Access code prefix',
136        required = True,
137        default = None,
138        source = application_pins_vocab,
139        )
140
141    application_category = schema.Choice(
142        title = u'Category for the grouping of certificates',
143        required = True,
144        default = None,
145        source = application_categories,
146        )
147
148    description = schema.Text(
149        title = u'Human readable description in reST format',
150        required = False,
151        default = u'''This text can been seen by anonymous users.
152Here we put information about the study courses provided, the application procedure and deadlines.'''
153        )
154
155    startdate = schema.Date(
156        title = u'Application start date',
157        required = False,
158        default = None,
159        )
160
161    enddate = schema.Date(
162        title = u'Application closing date',
163        required = False,
164        default = None,
165        )
166
167    strict_deadline = schema.Bool(
168        title = u'Forbid additions after deadline (enddate)',
169        required = True,
170        default = True,
171        )
172
173    def archive(id=None):
174        """Create on-dist archive of applicants stored in this term.
175
176        If id is `None`, all applicants are archived.
177
178        If id contains a single id string, only the respective
179        applicants are archived.
180
181        If id contains a list of id strings all of the respective
182        applicants types are saved to disk.
183        """
184
185    def clear(id=None, archive=True):
186        """Remove applicants of type given by 'id'.
187
188        Optionally archive the applicants.
189
190        If id is `None`, all applicants are archived.
191
192        If id contains a single id string, only the respective
193        applicants are archived.
194
195        If id contains a list of id strings all of the respective
196        applicant types are saved to disk.
197
198        If `archive` is ``False`` none of the archive-handling is done
199        and respective applicants are simply removed from the
200        database.
201        """
202
203class IApplicantsContainerAdd(IApplicantsContainer):
204    """An applicants container contains university applicants.
205    """
206    prefix = schema.Choice(
207        title = u'Application target',
208        required = True,
209        default = None,
210        source = application_types_vocab,
211        readonly = False,
212        )
213
214    year = schema.Choice(
215        title = u'Year of entrance',
216        required = True,
217        default = None,
218        values = year_range(),
219        readonly = False,
220        )
221
222    provider = schema.Choice(
223        title = u'Applicants container type',
224        required = True,
225        default = None,
226        source = ApplicantContainerProviderSource(),
227        readonly = False,
228        )
229
230IApplicantsContainerAdd[
231    'prefix'].order =  IApplicantsContainer['prefix'].order
232IApplicantsContainerAdd[
233    'year'].order =  IApplicantsContainer['year'].order
234IApplicantsContainerAdd[
235    'provider'].order =  IApplicantsContainer['provider'].order
236
237class IApplicantBaseData(IWAeUPObject):
238    """The data for an applicant.
239
240    This is a base interface with no field
241    required. For use with importers, forms, etc., please use one of
242    the derived interfaces below, which set more fields to required
243    state, depending on use-case.
244    """
245    history = Attribute('Object history, a list of messages.')
246    state = Attribute('The application state of an applicant')
247    fullname = Attribute('The fullname of an applicant')
248    application_date = Attribute('Date of submission, used for export only')
249    password = Attribute('Encrypted password of a applicant')
250    application_number = Attribute('The key under which the record is stored')
251
252    def loggerInfo(ob_class, comment):
253        """Adds an INFO message to the log file
254        """
255
256    applicant_id = schema.TextLine(
257        title = u'Applicant Id',
258        required = False,
259        readonly = False,
260        )
261    reg_no = schema.TextLine(
262        title = u'JAMB Registration Number',
263        readonly = True,
264        required = False,
265        )
266    access_code = schema.TextLine(
267        title = u'Access Code',
268        required = False,
269        readonly = True,
270        )
271    firstname = schema.TextLine(
272        title = u'First Name',
273        required = True,
274        )
275    middlenames = schema.TextLine(
276        title = u'Middle Names',
277        required = False,
278        )
279    lastname = schema.TextLine(
280        title = u'Last Name (Surname)',
281        required = True,
282        )
283    date_of_birth = schema.Date(
284        title = u'Date of Birth',
285        required = True,
286        )
287    lga = schema.Choice(
288        source = lgas_vocab,
289        title = u'State/LGA',
290        default = 'foreigner',
291        required = True,
292        )
293    sex = schema.Choice(
294        title = u'Sex',
295        source = GenderSource(),
296        default = u'm',
297        required = True,
298        )
299    email = schema.ASCIILine(
300        title = u'Email',
301        required = True,
302        constraint=validate_email,
303        )
304    phone = schema.Int(
305        title = u'Phone',
306        description = u'Enter phone number with country code and without spaces.',
307        required = False,
308        )
309    course1 = schema.Choice(
310        title = u'1st Choice Course of Study',
311        source = CertificateSource(),
312        required = True,
313        )
314    course2 = schema.Choice(
315        title = u'2nd Choice Course of Study',
316        source = CertificateSource(),
317        required = False,
318        )
319
320    #
321    # Process Data
322    #
323    screening_score = schema.Int(
324        title = u'Screening Score',
325        required = False,
326        )
327    screening_venue = schema.TextLine(
328        title = u'Screening Venue',
329        required = False,
330        )
331    course_admitted = schema.Choice(
332        title = u'Admitted Course of Study',
333        source = CertificateSource(),
334        default = None,
335        required = False,
336        )
337    notice = schema.Text(
338        title = u'Notice',
339        required = False,
340        )
341    student_id = schema.TextLine(
342        title = u'Student Id',
343        required = False,
344        readonly = True,
345        )
346    locked = schema.Bool(
347        title = u'Form locked',
348        default = False,
349        )
350
351class IApplicant(IApplicantBaseData):
352    """An applicant.
353
354    This is basically the applicant base data. Here we repeat the
355    fields from base data if we have to set the `required` attribute
356    to True (which is the default).
357    """
358
359class IApplicantEdit(IApplicantBaseData):
360    """An applicant.
361
362    Here we can repeat the fields from base data and set the
363    `required` and `readonly` attributes to True to further restrict
364    the data access. Or we can allow only certain certificates to be
365    selected by choosing the appropriate source.
366
367    We cannot omit fields here. This has to be done in the
368    respective form page.
369    """
370
371    course1 = schema.Choice(
372        title = u'1st Choice Course of Study',
373        source = AppCatCertificateSource(),
374        required = True,
375        )
376    course2 = schema.Choice(
377        title = u'2nd Choice Course of Study',
378        source = AppCatCertificateSource(),
379        required = False,
380        )
381    screening_score = schema.Int(
382        title = u'Screening Score',
383        required = False,
384        readonly = True,
385        )
386    screening_venue = schema.TextLine(
387        title = u'Screening Venue',
388        required = False,
389        readonly = True,
390        )
391    course_admitted = schema.Choice(
392        title = u'Admitted Course of Study',
393        source = CertificateSource(),
394        default = None,
395        required = False,
396        readonly = True,
397        )
398    notice = schema.Text(
399        title = u'Notice',
400        required = False,
401        readonly = True,
402        )
403
404class IApplicantOnlinePayment(IOnlinePayment):
405    """An applicant payment via payment gateways.
406
407    """
408    p_year = schema.Choice(
409        title = u'Payment Session',
410        source = academic_sessions_vocab,
411        required = False,
412        )
413
414IApplicantOnlinePayment['p_year'].order = IApplicantOnlinePayment[
415    'p_year'].order
416
417class IApplicantsContainerProvider(Interface):
418    """A provider for applicants containers.
419
420    Applicants container providers are meant to be looked up as
421    utilities. This way we can find all applicant container types
422    defined somewhere.
423
424    Each applicants container provider registered as utility provides
425    one container type and one should be able to call the `factory`
426    attribute to create an instance of the requested container type.
427
428    .. THE FOLLOWING SHOULD GO INTO SPHINX DOCS (and be tested)
429
430    Samples:
431
432    Given, you had an IApplicantsContainer implementation somewhere
433    and you would like to make it findable on request, then you would
434    normally create an appropriate provider utility like this::
435
436      import grok
437      from waeup.sirp.applicants.interfaces import IApplicantsContainerProvider
438
439      class MyContainerProvider(grok.GlobalUtility):
440          grok.implements(IApplicantsContainerProvider)
441          grok.name('MyContainerProvider') # Must be unique
442          factory = MyContainer # A class implementing IApplicantsContainer
443                                # or derivations thereof.
444
445    This utility would be registered on startup and could then be used
446    like this:
447
448      >>> from zope.component import getAllUtilitiesRegisteredFor
449      >>> from waeup.sirp.applicants.interfaces import (
450      ...     IApplicantsContainerProvider)
451      >>> all_providers = getAllUtilitiesRegisteredFor(
452      ...     IApplicantsContainerProvider)
453      >>> all_providers
454      [<MyContainerProvider object at 0x...>]
455
456    You could look up this specific provider by name:
457
458      >>> from zope.component import getUtility
459      >>> p = getUtility(IApplicantsContainerProvider, name='MyProvider')
460      >>> p
461      <MyContainerProvider object at 0x...>
462
463    An applicants container would then be created like this:
464
465      >>> provider = all_providers[0]
466      >>> container = provider.factory()
467      >>> container
468      <MyContainer object at 0x...>
469
470    """
471    factory = Attribute("A class that can create instances of the "
472                        "requested container type")
Note: See TracBrowser for help on using the repository browser.