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

Last change on this file since 8381 was 8098, checked in by Henrik Bettermann, 12 years ago

Extend default level range for postgraduates.

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