source: main/waeup.kofa/trunk/src/waeup/kofa/students/vocabularies.py @ 7939

Last change on this file since 7939 was 7915, checked in by uli, 13 years ago

Move CertificateSource? to university package. I think this is the right place.

  • Property svn:keywords set to Id
File size: 6.3 KB
Line 
1## $Id: vocabularies.py 7915 2012-03-19 04:21:47Z uli $
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.kofa.interfaces import SimpleKofaVocabulary
28from waeup.kofa.interfaces import MessageFactory as _
29from waeup.kofa.students.lgas import LGAS
30from waeup.kofa.students.nats import NATS
31from waeup.kofa.university.vocabularies import course_levels
32
33lgas_vocab = SimpleKofaVocabulary(
34    *sorted([(x[1],x[0]) for x in LGAS]))
35
36nats_vocab = SimpleKofaVocabulary(
37    *sorted([(x[1],x[0]) for x in NATS]))
38
39def study_levels(studycourse):
40    if studycourse.certificate is not None:
41        start_level = int(studycourse.certificate.start_level)
42        end_level = int(studycourse.certificate.end_level)
43        if start_level == 10:
44            levels = [10,] + [level for level in range(100,end_level+200,10)
45                if level % 100 < 30]
46        else:
47            levels = [level for level in range(start_level,end_level+200,10)
48                if level % 100 < 30]
49    else:
50        # default level range
51        levels = [level for level in range(100,800,10) if level % 100 < 30]
52    return levels
53
54
55class StudyLevelSource(BasicContextualSourceFactory):
56    """The StudyLevelSource is based on and extends the
57    course_levels vocabulary defined in the university package.
58    Repeating study levels are denoted by increments of 10, the
59    first spillover level by the certificate's end level plus 100
60    and the second spillover level by the end level plus 110.
61    """
62    def getValues(self, context):
63        return study_levels(context)
64
65    def getToken(self, context, value):
66        return str(value)
67
68    def getTitle(self, context, value):
69        if context.certificate is not None:
70            start_level = int(context.certificate.start_level)
71            end_level = int(context.certificate.end_level)
72        else:
73            # default level range
74            start_level = 100
75            end_level = 600
76        if value < start_level or value > end_level + 120:
77            return _('Error: level id ${value} out of range',
78                mapping={'value': value})
79        # Special treatment for pre-studies level
80        if value == 10:
81            return course_levels.by_value[value].title
82        level,repeat = divmod(value, 100)
83        level = level * 100
84        repeat = repeat//10
85        title = course_levels.by_value[level].title
86        if level > end_level and repeat == 1:
87            title = course_levels.by_value[level - 100].title
88            return _('${title} 2nd spillover', mapping={'title': title})
89        if level > end_level and repeat == 2:
90            title = course_levels.by_value[level - 100].title
91            return _('${title} 3rd spillover', mapping={'title': title})
92        if level > end_level:
93            title = course_levels.by_value[level - 100].title
94            return  _('${title} 1st spillover', mapping={'title': title})
95        if repeat == 1:
96            return _('${title} on 1st probation', mapping={'title': title})
97        if repeat == 2:
98            return _('${title} on 2nd probation', mapping={'title': title})
99        return title
100
101class GenderSource(BasicSourceFactory):
102    """A gender source delivers basically a mapping
103       ``{'m': 'Male', 'f': 'Female'}``
104
105       Using a source, we make sure that the tokens (which are
106       stored/expected for instance from CSV files) are something one
107       can expect and not cryptic IntIDs.
108    """
109    def getValues(self):
110        return ['m', 'f']
111
112    def getToken(self, value):
113        return value[0].lower()
114
115    def getTitle(self, value):
116        if value == 'm':
117            return _('male')
118        if value == 'f':
119            return _('female')
120
121class RegNumNotInSource(ValidationError):
122    """Registration number exists already
123    """
124    # The docstring of ValidationErrors is used as error description
125    # by zope.formlib.
126    pass
127
128class MatNumNotInSource(ValidationError):
129    """Matriculation number exists already
130    """
131    # The docstring of ValidationErrors is used as error description
132    # by zope.formlib.
133    pass
134
135class RegNumberSource(object):
136    implements(ISource)
137    cat_name = 'students_catalog'
138    field_name = 'reg_number'
139    validation_error = RegNumNotInSource
140    def __init__(self, context):
141        self.context = context
142        return
143
144    def __contains__(self, value):
145        cat = queryUtility(ICatalog, self.cat_name)
146        if cat is None:
147            return True
148        kw = {self.field_name: (value, value)}
149        results = cat.searchResults(**kw)
150        for entry in results:
151            if entry.student_id != self.context.student_id:
152                # XXX: sources should simply return False.
153                #      But then we get some stupid error message in forms
154                #      when validation fails.
155                raise self.validation_error(value)
156                #return False
157        return True
158
159def contextual_reg_num_source(context):
160    source = RegNumberSource(context)
161    return source
162directlyProvides(contextual_reg_num_source, IContextSourceBinder)
163
164class MatNumberSource(RegNumberSource):
165    field_name = 'matric_number'
166    validation_error = MatNumNotInSource
167
168def contextual_mat_num_source(context):
169    source = MatNumberSource(context)
170    return source
171directlyProvides(contextual_mat_num_source, IContextSourceBinder)
Note: See TracBrowser for help on using the repository browser.