source: main/waeup.sirp/branches/henrik-bootstrap/src/waeup/sirp/students/vocabularies.py @ 9819

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

Replace the term 'WAeUP' by SIRP which is a WAeUP product.

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