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

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

Move year_range and academic_sessions_vocab to waeup.sirp.interfaces.

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