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

Last change on this file since 5813 was 5758, checked in by uli, 14 years ago

Move more interfaces, disable two views and make tests work again.

File size: 21.4 KB
RevLine 
[5638]1##
2## interfaces.py
3## Login : <uli@pu.smp.net>
4## Started on  Sun Jan 16 15:30:01 2011 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2011 Uli Fouquet
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
[5676]22"""Interfaces regarding student applicants and related components.
[5638]23"""
[5753]24import os
25import waeup.sirp.browser
26from hurry.file import HurryFile
[5758]27from zc.sourcefactory.basic import BasicSourceFactory
[5638]28from zope import schema
[5758]29from zope.interface import Interface, Attribute
30from zope.pluggableauth.interfaces import IPrincipalInfo
31from zope.security.interfaces import IGroupClosureAwarePrincipal as IPrincipal
[5753]32from waeup.sirp.image.schema import ImageFile
[5681]33from waeup.sirp.interfaces import IWAeUPObject, SimpleWAeUPVocabulary
[5638]34
[5753]35IMAGE_PATH = os.path.join(
36    os.path.dirname(waeup.sirp.browser.__file__),
37    'static'
38    )
39DEFAULT_PASSPORT_IMAGE_MALE = HurryFile(
40    'passport.jpg',
41    open(os.path.join(IMAGE_PATH, 'placeholder_m.jpg')).read(),
42    )
43DEFAULT_PASSPORT_IMAGE_FEMALE = HurryFile(
44    'passport.jpg',
45    open(os.path.join(IMAGE_PATH, 'placeholder_f.jpg')).read(),
46    )
47
[5681]48#: Categories of applications we support.
49#: Yet not complete nor correct.
50APPLICATION_CATEGORIES = (
51    ('Direct Entry Screening Exam (PDE)', 'pde'),
52    ('Post-UME', 'pume'),
53    ('Post-UDE', 'pude'),
54    ('PCE', 'pce'),
55    ('Common Entry Screening Test (CEST)', 'cest'),
56    )
57
58#: A :class:`waeup.sirp.interfaces.SimpleWAeUPVocabulary` of supported
59#: application categories.
60application_categories_vocab = SimpleWAeUPVocabulary(*APPLICATION_CATEGORIES)
61
[5753]62class GenderSource(BasicSourceFactory):
63    """A gender source delivers basically a mapping
64       ``{'m': 'male', 'f': 'female'}``
65
66       Using a source, we make sure that the tokens (which are
67       stored/expected for instance from CSV files) are something one
68       can expect and not cryptic IntIDs.
69    """
70    def getValues(self):
71        return ['m', 'f']
72
73    def getToken(self, value):
74        return value[0].lower()
75       
76    def getTitle(self, value):
77        if value == 'm':
78            return 'male'
79        if value == 'f':
80            return 'female'
81
82class IResultEntry(IWAeUPObject):
83    subject = schema.TextLine(
84        title = u'Subject',
85        description = u'The subject',
86        required=False,
87        )
88    score = schema.TextLine(
89        title = u'Score',
90        description = u'The score',
91        required=False,
92        )
93
[5676]94class IApplicantsRoot(IWAeUPObject):
95    """A container for university applicants containers.
[5645]96    """
[5676]97    def addApplicantsContainer(container, name=None):
98        """Add an applicants container.
[5638]99
[5676]100        Adds an applicants container that implements `interface`
[5645]101        under the name `name`.
[5638]102
[5645]103        `container` the container instance to be added. Should
[5676]104          implement :class:`IApplicantsContainer`.
[5645]105
106        `name`
107          the name under which the container will be accessible. We
108          usually use names like ``pume_2011`` to indicate, that the
[5676]109          new container will contain university applicants for a
[5645]110          certain screening type (``pume``) and of the year 2011.
111        """
112
[5676]113class IApplicantsContainer(IWAeUPObject):
114    """An applicants container contains university applicants.
[5645]115
[5638]116    """
[5682]117    REQUIRES_JAMBDATA = schema.Bool(
118        title = u'JAMB data required',
119        description = u'This container requires JAMB data to be available.',
120        required = True,
121        default = False,
122        )
123       
124    name = schema.TextLine(
[5638]125        title = u'Internal ID',
126        required = True,
127        )
128
[5645]129    title = schema.TextLine(
[5676]130        title = u'Short description of the type of applicants stored here.',
[5645]131        required = True,
132        default = u'Untitled',
133        )
134   
135    description = schema.Text(
136        title = u'Human readable description in reST format',
[5638]137        required = False,
138        default = u'Not set.'
139        )
140
141    startdate = schema.Date(
[5645]142        title = u'Date when the application period starts',
[5638]143        required = False,
144        default = None,
145        )
146
147    enddate = schema.Date(
[5645]148        title = u'Date when the application period ends',
[5638]149        required = False,
150        default = None,
151        )
152
[5645]153    strict_deadline = schema.Bool(
154        title = u'Forbid additions after deadline (enddate)',
155        required = True,
156        default = True,
157        )
[5638]158
159    def archive(id=None):
[5676]160        """Create on-dist archive of applicants stored in this term.
[5638]161
[5676]162        If id is `None`, all applicants are archived.
[5638]163
164        If id contains a single id string, only the respective
[5676]165        applicants are archived.
[5638]166
167        If id contains a list of id strings all of the respective
[5676]168        applicants types are saved to disk.
[5638]169        """
170
171    def clear(id=None, archive=True):
[5676]172        """Remove applicants of type given by 'id'.
[5638]173
[5676]174        Optionally archive the applicants.
[5638]175       
[5676]176        If id is `None`, all applicants are archived.
[5638]177
178        If id contains a single id string, only the respective
[5676]179        applicants are archived.
[5638]180
181        If id contains a list of id strings all of the respective
[5676]182        applicant types are saved to disk.
[5638]183
184        If `archive` is ``False`` none of the archive-handling is done
[5676]185        and respective applicants are simply removed from the
[5638]186        database.
187        """
[5753]188class IApplicantBaseData(IWAeUPObject):
189    """The data for an applicant.
190
191    This is a base interface with no field (except ``reg_no``)
192    required. For use with importers, forms, etc., please use one of
193    the derived interfaces below, which set more fields to required
194    state, depending on use-case.
195    """
196    reg_no = schema.TextLine(
197        title = u'JAMB Registration Number',
198        )
199    access_code = schema.TextLine(
200        title = u'Access Code',
201        required = False,
202        )
203    serial = schema.TextLine(
204        title = u'Serial Number',
205        required = False,
206        )
207    course1 = schema.TextLine(
208        title = u'1st Choice Course of Study',
209        required = False,
210        )
211    course2 = schema.TextLine(
212        title = u'2nd Choice Course of Study',
213        required = False,
214        )
215    course3 = schema.TextLine(
216        title = u'3rd Choice Course of Study',
217        required = False,
218        )
219    firstname = schema.TextLine(
220        title = u'First Name',
221        required = False,
222        )
223    middlenames = schema.TextLine(
224        title = u'Middle Names',
225        required = False,
226        )
227    lastname = schema.TextLine(
228        title = u'Surname/Full Name',
229        required = False,
230        )
231    jamb_age = schema.Int(
232        title = u'Age (provided by JAMB)',
233        required = False,
234        )
235    date_of_birth = schema.Date(
236        title = u'Date of Birth',
237        required = False,
238        )
239    jamb_state = schema.TextLine(
240        title = u'State (provided by JAMB)',
241        required = False,
242        )
243    jamb_lga = schema.TextLine(
244        title = u'LGA (provided by JAMB)',
245        required = False,
246        )
247    lga = schema.TextLine(
248        # XXX: should be choice
249        title = u'State/LGA (confirmed by applicant)',
250        required = False,
251        )
252    sex = schema.Choice(
253        title = u'Sex',
254        source = GenderSource(),
255        default = u'm',
256        required = False,
257        )
258    email = schema.TextLine(
259        title = u'Email',
260        required = False,
261        )
262    phone = schema.TextLine(
263        title = u'Phone',
264        required = False,
265        )
266    #passport = schema.Bool(
267    #    title = u'Passport Photograph',
268    #    default = True,
269    #    required = False,
270    #    )
271    passport = ImageFile(
272        title = u'Passport Photograph',
273        default = DEFAULT_PASSPORT_IMAGE_MALE,
274        required = True,
275        )
276    aos = schema.TextLine(
277        # XXX: should be choice
278        title = u'Area of Specialisation',
279        required = False,
280        )
281    subj1 = schema.TextLine(
282        # XXX: should be choice
283        title = u'1st Choice of Study',
284        required = False,
285        )
286    subj2 = schema.TextLine(
287        # XXX: should be choice
288        title = u'2nd Choice of Study',
289        required = False,
290        )
291    subj3 = schema.TextLine(
292        # XXX: should be choice
293        title = u'3rd Choice of Study',
294        required = False,
295        )
296    #
297    # Higher Educational Data
298    #
299    hq_matric_no = schema.TextLine(
300        title = u'Former Matric Number',
301        required = False,
302        )
303    hq_type = schema.TextLine(
304        title = u'Higher Qualification',
305        required = False,
306        )
307    hq_grade = schema.TextLine(
308        title = u'Higher Qualification Grade',
309        required = False,
310        )
311    hq_school = schema.TextLine(
312        title = u'School Attended',
313        required = False,
314        )
315    hq_session = schema.TextLine(
316        title = u'Session Obtained',
317        required = False,
318        )
319    hq_disc = schema.TextLine(
320        title = u'Discipline',
321        required = False,
322        )
323    #
324    # First sitting data
325    #
326    fst_sit_fname = schema.TextLine(
327        title = u'Full Name',
328        required = False,
329        )
330    fst_sit_no = schema.TextLine(
331        title = u'Exam Number',
332        required = False,
333        )
334    fst_sit_date = schema.Date(
335        title = u'Exam Date (dd/mm/yyyy)',
336        required = False,
337        )
338    fst_sit_type = schema.TextLine(
339        # XXX: Should be choice
340        title = u'Exam Type',
341        required = False,
342        )
343    fst_sit_results = schema.List(
344        title = u'Results',
345        required = False,
346        value_type = schema.Object(
347            title = u'Entries',
348            schema = IResultEntry,
349            required = False,
350            )
351        )
352    scd_sit_fname = schema.TextLine(
353        title = u'Full Name',
354        required = False,
355        )
356    scd_sit_no = schema.TextLine(
357        title = u'Exam Number',
358        required = False,
359        )
360    scd_sit_date = schema.Date(
361        title = u'Exam Date (dd/mm/yyyy)',
362        required = False,
363        )
364    scd_sit_type = schema.TextLine(
365        # XXX: Should be choice
366        title = u'Exam Type',
367        required = False,
368        )
369    scd_sit_results = schema.TextLine(
370        # XXX: Should be nested list of choices
371        title = u'Results',
372        required = False,
373        )
374    #
375    # JAMB scores
376    #
377    eng_score = schema.TextLine(
378        title = u"'English' score",
379        required = False,
380        )
381    subj1score = schema.TextLine(
382        title = u'1st Choice of Study Score',
383        required = False,
384        )
385    subj2score = schema.TextLine(
386        title = u'2nd Choice of Study Score',
387        required = False,
388        )
389    subj3score = schema.TextLine(
390        title = u'3rd Choice of Study Score',
391        required = False,
392        )
393    # XXX: Total score???
394   
395    #
396    # Application Data
397    #
398    application_date = schema.Date(
399        title = u'Application Date',
400        required = False,
401        )
402    status = schema.TextLine(
403        # XXX: should be 'status' type
404        title = u'Application Status',
405        required = False,
406        )
407    screening_date = schema.Date(
408        title = u'Screening Date',
409        required = False,
410        )
411    screening_type = schema.TextLine(
412        # XXX: schould be choice
413        title = u'Screening Type',
414        required = False,
415        )
416    screening_score = schema.TextLine(
417        title = u'Screening Score',
418        required = False,
419        )
420    screening_venue = schema.TextLine(
421        title = u'Screening Venue',
422        required = False,
423        )
424    total_score = schema.TextLine(
425        title = u'Total Score',
426        required = False,
427        )
428    course_admitted = schema.TextLine(
429        # XXX: should be choice
430        title = u'Admitted Course of Study',
431        required = False,
432        )
433    department = schema.TextLine(
434        # XXX: if we have a course, dept. is not necessary
435        title = u'Department',
436        required = False,
437        )
438    faculty = schema.TextLine(
439        # XXX: if we have a course, faculty is not necessary
440        title = u'Faculty',
441        required = False,
442        )
443    entry_session = schema.TextLine(
444        # XXX: should be choice, should have sensible default: upcoming session
445        title = u'Entry Session',
446        required = False,
447        )
448    notice = schema.Text(
449        title = u'Notice',
450        required = False,
451        )
452    student_id = schema.TextLine(
453        title = u'Student ID',
454        required = False,
455        )
456    import_record_no = schema.TextLine(
457        title = u'Import Record No.',
458        required = False,
459        )
460    imported_by = schema.TextLine(
461        title = u'Imported By',
462        required = False,
463        )
464    import_date = schema.Datetime(
465        title = u'Import Date',
466        required = False,
467        )
468    import_from = schema.TextLine(
469        title = u'Import Source',
470        required = False,
471        )
472
473   
474class IApplicant(IApplicantBaseData):
475    """An applicant.
476
477    This is basically the applicant base data. Here we repeat the
478    fields from base data only with the `required` attribute of
479    required attributes set to True (which is the default).
480    """
481    access_code = schema.TextLine(
482        title = u'Access Code',
483        )
484    course1 = schema.TextLine(
485        title = u'1st Choice Course of Study',
486        )
487    firstname = schema.TextLine(
488        title = u'First Name',
489        )
490    middlenames = schema.TextLine(
491        title = u'Middle Names',
492        )
493    lastname = schema.TextLine(
494        title = u'Surname/Full Name',
495        )
496    date_of_birth = schema.Date(
497        title = u'Date of Birth',
498        )
499    jamb_state = schema.TextLine(
500        title = u'State (provided by JAMB)',
501        )
502    jamb_lga = schema.TextLine(
503        title = u'LGA (provided by JAMB)',
504        )
505    lga = schema.TextLine(
506        # XXX: should be choice
507        title = u'State/LGA (confirmed by applicant)',
508        )
509    sex = schema.Choice(
510        title = u'Sex',
511        source = GenderSource(),
512        default = u'm',
513        )
514    #passport = schema.Bool(
515    #    title = u'Passport Photograph',
516    #    default = True,
517    #    )
518    passport = ImageFile(
519        title = u'Passport Photograph',
520        default = DEFAULT_PASSPORT_IMAGE_MALE,
521        required = True,
522        )
523    #
524    # Higher Educational Data
525    #
526
527    #
528    # First sitting data
529    #
530    fst_sit_fname = schema.TextLine(
531        title = u'Full Name',
532        )
533
534    #
535    # Second sitting data
536    #
537    scd_sit_fname = schema.TextLine(
538        title = u'Full Name',
539        )
540    #
541    # JAMB scores
542    #
543   
544    #
545    # Application Data
546    #
547    application_date = schema.Date(
548        title = u'Application Date',
549        )
550    status = schema.TextLine(
551        # XXX: should be 'status' type
552        title = u'Application Status',
553        )
554    screening_date = schema.Date(
555        title = u'Screening Date',
556        )
557    screening_type = schema.TextLine(
558        # XXX: schould be choice
559        title = u'Screening Type',
560        )
561    screening_score = schema.TextLine(
562        title = u'Screening Score',
563        )
564    entry_session = schema.TextLine(
565        # XXX: should be choice
566        # XXX: should have sensible default: upcoming session
567        title = u'Entry Session',
568        )
569    import_record_no = schema.TextLine(
570        title = u'Import Record No.',
571        )
572    imported_by = schema.TextLine(
573        title = u'Imported By',
574        )
575    import_date = schema.Datetime(
576        title = u'Import Date',
577        )
578    import_from = schema.TextLine(
579        title = u'Import Source',
580        )
581
582class IApplicantPDEEditData(IWAeUPObject):
583    """The data set presented to PDE applicants.
584    """
585    reg_no = schema.TextLine(
586        title = u'JAMB Registration Number',
587        readonly = True,
588        )
589    access_code = schema.TextLine(
590        title = u'Access Code',
591        readonly = True,
592        )
593    course1 = schema.TextLine(
594        title = u'1st Choice Course of Study',
595        readonly = True,
596        )
597    course2 = schema.TextLine(
598        title = u'2nd Choice Course of Study',
599        required = False,
600        )
601    course3 = schema.TextLine(
602        title = u'3rd Choice Course of Study',
603        required = False,
604        )
605    lastname = schema.TextLine(
606        title = u'Name',
607        readonly = True,
608        )
609    jamb_age = schema.Int(
610        title = u'Age',
611        readonly = True,
612        )
613    date_of_birth = schema.Date(
614        title = u'Date of Birth',
615        required = True,
616        )
617    jamb_state = schema.TextLine(
618        title = u'State (provided by JAMB)',
619        readonly = True,
620        )
621    jamb_lga = schema.TextLine(
622        title = u'LGA (provided by JAMB)',
623        readonly = True,
624        )
625    lga = schema.TextLine(
626        # XXX: should be choice
627        title = u'State/LGA (confirmed by applicant)',
628        required = False,
629        )
630    email = schema.TextLine(
631        title = u'Email',
632        required = False,
633        )
634    phone = schema.TextLine(
635        title = u'Phone',
636        required = False,
637        )
638    aos = schema.TextLine(
639        # XXX: should be choice
640        title = u'Area of Specialisation',
641        required = False,
642        )
643    subj1 = schema.TextLine(
644        # XXX: should be choice
645        title = u'1st Choice of Study',
646        readonly = True,
647        )
648    subj2 = schema.TextLine(
649        # XXX: should be choice
650        title = u'2nd Choice of Study',
651        required = False,
652        )
653    subj3 = schema.TextLine(
654        # XXX: should be choice
655        title = u'3rd Choice of Study',
656        required = False,
657        )
658   
659    #
660    # Application Data
661    #
662    application_date = schema.Date(
663        title = u'Application Date',
664        readonly = True,
665        )
666    status = schema.TextLine(
667        # XXX: should be 'status' type
668        title = u'Application Status',
669        readonly = True,
670        )
671    screening_date = schema.Date(
672        title = u'Screening Date',
673        readonly = True,
674        )
675    #passport = schema.Bool(
676    #    title = u'Passport Photograph',
677    #    default = True,
678    #    required = False,
679    #    ),
680    #passport = schema.Bytes(
681    #    title = u'Passport Photograph',
682    #    required = True,
683    #    )
684    #passport = schema.Object(
685    #    title = u'Passport Photograph',
686    #    required = True,
687    #    schema = IImage)
688    passport = ImageFile(
689        title = u'Passport Photograph',
690        default = DEFAULT_PASSPORT_IMAGE_MALE,
691        required = True,
692        )
[5758]693
694class IApplicantPrincipalInfo(IPrincipalInfo):
695    """Infos about principals that are applicants.
696    """
697    reg_no = Attribute("The JAMB registration no. of the user")
698
699    access_code = Attribute("The Access Code the user purchased")
700
701class IApplicantPrincipal(IPrincipal):
702    """A principal that is an applicant.
703
704    This interface extends zope.security.interfaces.IPrincipal and
705    requires also an `id` and other attributes defined there.
706    """
707    reg_no = schema.TextLine(
708        title = u'Registration number',
709        description = u'The JAMB registration number',
710        required = True,
711        readonly = True)
712
713    access_code = schema.TextLine(
714        title = u'Access Code',
715        description = u'The access code purchased by the user.',
716        required = True,
717        readonly = True)
718
719class IApplicantsFormChallenger(Interface):
720    """A challenger that uses a browser form to collect applicant
721       credentials.
722    """
723    loginpagename = schema.TextLine(
724        title = u'Loginpagename',
725        description = u"""Name of the login form used by challenger.
726
727        The form must provide an ``access_code`` input field.
728        """)
729
730    accesscode_field = schema.TextLine(
731        title = u'Access code field',
732        description = u'''Field of the login page which is looked up for
733                          access_code''',
734        default = u'access_code',
735        )
736
737class IJAMBApplicantsFormChallenger(IApplicantsFormChallenger):
738    """A challenger that uses a browser form to collect applicant
739       credentials for applicants in JAMB process.
740
741       JAMB-screened applicants have to provide an extra registration
742       no. provided by JAMB.
743    """
744    jamb_reg_no_field = schema.TextLine(
745        title = u'JAMB registration no.',
746        description = u'''Field of the login page which is looked up for
747                          the JAMB registration number.''',
748        default = u'jamb_reg_no',
749        )
750
751class IApplicantSessionCredentials(Interface):
752    """Interface for storing and accessing applicant credentials in a
753       session.
754    """
755
756    def __init__(access_code):
757        """Create applicant session credentials."""
758
759    def getAccessCode():
760        """Return the access code."""
761
762
763class IJAMBApplicantSessionCredentials(IApplicantSessionCredentials):
764    """Interface for storing and accessing JAMB applicant credentials in a
765       session.
766    """
767
768    def __init__(access_code, jamb_reg_no):
769        """Create credentials for JAMB screened applicants."""
770
771    def getJAMBRegNo():
772        """Return the JAMB registration no."""
Note: See TracBrowser for help on using the repository browser.