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

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

Rebuild applicants package (1st part). Applicants now have an applicant_id and a password and can use the regular login page to enter the portal.

Add user_type attribute to SIRPPrincipal objects.

Add some permissions in students package.

Some tests are still missing and will be re-added soon.

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