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

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

Fix getTitle method.

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