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

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

Use fixed start_level and end_level if no certificate has yet been assigned. This way, we can import certificate end current_level at the same time.

Extend conversion checking so that current_level does not exceed level limits given by the certificate.

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