source: main/waeup.sirp/trunk/src/waeup/sirp/students/vocabularies.py @ 7529

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

Add nationality vocab.

  • Property svn:keywords set to Id
File size: 6.6 KB
Line 
1## $Id: vocabularies.py 7523 2012-01-27 17:14:38Z 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"""Vocabularies and sources for the student section.
19"""
20from zope.component import getUtility, queryUtility
21from zope.catalog.interfaces import ICatalog
22from zope.interface import implements, directlyProvides
23from zope.schema.interfaces import ISource, IContextSourceBinder
24from zope.schema.interfaces import ValidationError
25from zc.sourcefactory.basic import BasicSourceFactory
26from zc.sourcefactory.contextual import BasicContextualSourceFactory
27from waeup.sirp.interfaces import SimpleSIRPVocabulary
28from waeup.sirp.students.lgas import LGAS
29from waeup.sirp.students.nats import NATS
30from waeup.sirp.university.vocabularies import course_levels
31
32lgas_vocab = SimpleSIRPVocabulary(
33    *sorted([(x[1],x[0]) for x in LGAS]))
34
35nats_vocab = SimpleSIRPVocabulary(
36    *sorted([(x[1],x[0]) for x in NATS]))
37
38def study_levels(studycourse):
39    try:
40        start_level = int(studycourse.certificate.start_level)
41        end_level = int(studycourse.certificate.end_level)
42        levels = [level for level in range(start_level,end_level+200,10)
43                   if level % 100 < 30 and level < end_level + 120]
44        return levels
45    except AttributeError:
46        return []
47
48class StudyLevelSource(BasicContextualSourceFactory):
49    """The StudyLevelSource is based on and extends the
50    course_levels vocabulary defined in the university package.
51    Repeating study levels are denoted by increments of 10, the
52    first spillover level by the certificate's end level plus 100
53    and the second spillover level by the end level plus 110.
54    """
55    def getValues(self, context):
56        return study_levels(context)
57
58    def getToken(self, context, value):
59        return str(value)
60
61    def getTitle(self, context, value):
62        end_level = int(context.certificate.end_level)
63        level,repeat = divmod(value, 100)
64        level = level * 100
65        repeat = repeat//10
66        title = course_levels.by_value[level].title
67        if level > end_level and repeat:
68            title = course_levels.by_value[level-100].title
69            title = "%s 2nd spillover" % title
70        elif level > end_level:
71            title = course_levels.by_value[level-100].title
72            title = "%s spillover" % title
73        elif repeat:
74            title = "%s on %d. probation" % (title, repeat)
75        return title
76
77verdicts = SimpleSIRPVocabulary(
78    ('not yet','0'),
79    ('Successful student','A'),
80    ('Student with carryover courses','B'),
81    ('Student on probation','C'),
82    ('Student who were previously on probation','E'),
83    ('Medical case','F'),
84    ('Absent from examination','G'),
85    ('Withheld results','H'),
86    ('Expelled/rusticated/suspended student','I'),
87    ('Temporary withdrawn from the university','J'),
88    ('Unregistered student','K'),
89    ('Referred student','L'),
90    ('Reinstatement','M'),
91    ('Student on transfer','N'),
92    ('NCE-III repeater','O'),
93    ('New 300 level student','X'),
94    ('No previous verdict','Y'),
95    ('Successful student (provisional)','Z'),
96    ('First Class','A1'),
97    ('Second Class Upper','A2'),
98    ('Second Class Lower','A3'),
99    ('Third Class','A4'),
100    ('Pass','A5'),
101    ('Distinction','A6'),
102    ('Credit','A7'),
103    ('Merit','A8'),
104    )
105
106
107class CertificateSource(BasicContextualSourceFactory):
108    """A certificate source delivers all certificates provided
109    in the portal.
110    """
111    def getValues(self, context):
112        catalog = getUtility(ICatalog, name='certificates_catalog')
113        return sorted(list(
114                catalog.searchResults(
115                    code=('', 'z*'))),
116                    key=lambda value: value.code)
117
118    def getToken(self, context, value):
119        return value.code
120
121    def getTitle(self, context, value):
122        return "%s - %s" % (value.code, value.title[:64])
123
124
125class GenderSource(BasicSourceFactory):
126    """A gender source delivers basically a mapping
127       ``{'m': 'Male', 'f': 'Female'}``
128
129       Using a source, we make sure that the tokens (which are
130       stored/expected for instance from CSV files) are something one
131       can expect and not cryptic IntIDs.
132    """
133    def getValues(self):
134        return ['m', 'f']
135
136    def getToken(self, value):
137        return value[0].lower()
138
139    def getTitle(self, value):
140        if value == 'm':
141            return 'Male'
142        if value == 'f':
143            return 'Female'
144
145class RegNumNotInSource(ValidationError):
146    """Registration number exists already
147    """
148    # The docstring of ValidationErrors is used as error description
149    # by zope.formlib.
150    pass
151
152class MatNumNotInSource(ValidationError):
153    """Matriculation number exists already
154    """
155    # The docstring of ValidationErrors is used as error description
156    # by zope.formlib.
157    pass
158
159class RegNumberSource(object):
160    implements(ISource)
161    cat_name = 'students_catalog'
162    field_name = 'reg_number'
163    validation_error = RegNumNotInSource
164    def __init__(self, context):
165        self.context = context
166        return
167
168    def __contains__(self, value):
169        cat = queryUtility(ICatalog, self.cat_name)
170        if cat is None:
171            return True
172        kw = {self.field_name: (value, value)}
173        results = cat.searchResults(**kw)
174        for entry in results:
175            if entry.student_id != self.context.student_id:
176                # XXX: sources should simply return False.
177                #      But then we get some stupid error message in forms
178                #      when validation fails.
179                raise self.validation_error(value)
180                #return False
181        return True
182
183def contextual_reg_num_source(context):
184    source = RegNumberSource(context)
185    return source
186directlyProvides(contextual_reg_num_source, IContextSourceBinder)
187
188class MatNumberSource(RegNumberSource):
189    field_name = 'matric_number'
190    validation_error = MatNumNotInSource
191
192def contextual_mat_num_source(context):
193    source = MatNumberSource(context)
194    return source
195directlyProvides(contextual_mat_num_source, IContextSourceBinder)
Note: See TracBrowser for help on using the repository browser.