source: main/waeup.kofa/trunk/src/waeup/kofa/university/certificate.py @ 13621

Last change on this file since 13621 was 13617, checked in by Henrik Bettermann, 9 years ago

Add DegreeSource? and degree field to Certificate. Plugins must be updated!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.7 KB
Line 
1## $Id: certificate.py 13617 2016-01-15 15:34:03Z 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"""Kofa certificates and certificate courses
19"""
20import grok
21import zope.location.location
22from zope.event import notify
23from zope.catalog.interfaces import ICatalog
24from zope.intid.interfaces import IIntIds
25from zope.schema import getFields
26from zope.component import getUtility
27from zope.component.interfaces import IFactory, ComponentLookupError
28from zope.interface import implementedBy
29from waeup.kofa.interfaces import IKofaPluggable
30from waeup.kofa.university.interfaces import (
31    ICertificate, ICertificateCourse)
32from waeup.kofa.university.vocabularies import course_levels
33from waeup.kofa.utils.batching import VirtualExportJobContainer
34
35class VirtualCertificateExportJobContainer(VirtualExportJobContainer):
36    """A virtual export job container for certificates.
37    """
38
39class Certificate(grok.Container):
40    """A certificate.
41    """
42    grok.implements(ICertificate)
43
44    local_roles = [
45        'waeup.local.CourseAdviser100',
46        'waeup.local.CourseAdviser200',
47        'waeup.local.CourseAdviser300',
48        'waeup.local.CourseAdviser400',
49        'waeup.local.CourseAdviser500',
50        'waeup.local.CourseAdviser600',
51        'waeup.local.CourseAdviser700',
52        'waeup.local.CourseAdviser800',
53        'waeup.local.DepartmentOfficer',
54        ]
55
56    def __init__(self, code=u'NA', title=u'Unnamed Certificate',
57                 study_mode=None, start_level=None,
58                 end_level=None, application_category=None,
59                 school_fee_1=None, school_fee_2=None,
60                 school_fee_3=None, school_fee_4=None,
61                 ratio=None, degree=None,
62                 custom_textline_1=None, custom_textline_2=None,
63                 custom_float_1=None, custom_float_2=None):
64        super(Certificate, self).__init__()
65        self.code = code
66        self.title = title
67        self.study_mode = study_mode
68        self.start_level = start_level
69        self.end_level = end_level
70        self.application_category = application_category
71        self.school_fee_1 = school_fee_1
72        self.school_fee_2 = school_fee_2
73        self.school_fee_3 = school_fee_3
74        self.school_fee_4 = school_fee_4
75        self.ratio = ratio
76        self.degree = degree
77        self.custom_textline_1 = custom_textline_1
78        self.custom_textline_2 = custom_textline_2
79        self.custom_float_1 = custom_float_1
80        self.custom_float_2 = custom_float_2
81
82    def traverse(self, name):
83        """Deliver appropriate containers.
84        """
85        if name == 'exports':
86            # create a virtual exports container and return it
87            container = VirtualCertificateExportJobContainer()
88            zope.location.location.located(container, self, 'exports')
89            return container
90        return None
91
92    @property
93    def longtitle(self):
94        return "%s (%s)" % (self.title,self.code)
95
96    def addCertCourse(self, course, level=100, mandatory=True):
97        """Add a certificate course.
98        """
99        code = "%s_%s" % (course.code, level)
100        self[code] = CertificateCourse(course, level, mandatory)
101        self[code].__parent__ = self
102        self[code].__name__ = code
103        self._p_changed = True
104
105    def delCertCourses(self, code, level=None):
106        """Delete certificate courses.
107
108        We might have more than one certificate course for a course.
109        If level is not provided all certificate courses referring
110        to the same course will be deleted.
111        """
112        keys = list(self.keys()) # create list copy
113        for key in keys:
114            if self[key].getCourseCode() != code:
115                continue
116            if level is not None and str(self[key].level) != str(level):
117                # found a course with correct key but wrong level...
118                continue
119            del self[key]
120            self._p_changed = True
121        return
122
123    def moveCertificate(self, facname, depname, newcode):
124        self.moved = True
125        cert = self
126        oldcode = cert.code
127        cert.code = newcode
128        del self.__parent__[oldcode]
129        newdep = grok.getSite()['faculties'][facname][depname]
130        newdep.certificates[newcode] = cert
131        #self.__parent__._p_changed = True
132        cat = getUtility(ICatalog, name='students_catalog')
133        results = cat.searchResults(certcode=(oldcode, oldcode))
134        for student in results:
135            notify(grok.ObjectModifiedEvent(student))
136            student.__parent__.logger.info(
137                '%s - Certificate moved' % student.__name__)
138        return
139
140class CertificateFactory(grok.GlobalUtility):
141    """A factory for certificates.
142    """
143    grok.implements(IFactory)
144    grok.name(u'waeup.Certificate')
145    title = u"Create a new certificate.",
146    description = u"This factory instantiates new certificate instances."
147
148    def __call__(self, *args, **kw):
149        return Certificate(*args, **kw)
150
151    def getInterfaces(self):
152        return implementedBy(Certificate)
153
154class CertificateCourse(grok.Model):
155    grok.implements(ICertificateCourse)
156
157    def __init__(self, course=None, level=100, mandatory=True):
158        self.course = course
159        self.level = level
160        self.mandatory = mandatory
161
162    def getCourseCode(self):
163        """Get code of a course.
164        """
165        return self.course.code
166
167    @property
168    def longtitle(self):
169        return "%s in level %s" % (self.course.code,
170                   course_levels.getTerm(self.level).title)
171
172class CertificateCourseFactory(grok.GlobalUtility):
173    """A factory for certificate courses.
174    """
175    grok.implements(IFactory)
176    grok.name(u'waeup.CertificateCourse')
177    title = u"Create a new certificate course.",
178    description = u"This factory instantiates new certificate courses."
179
180    def __call__(self, *args, **kw):
181        return CertificateCourse(*args, **kw)
182
183    def getInterfaces(self):
184        return implementedBy(CertificateCourse)
185
186@grok.subscribe(ICertificate, grok.IObjectRemovedEvent)
187def handle_certificate_removed(certificate, event):
188    """If a certificate is deleted, we make sure that also referrers to
189    student studycourse objects are removed.
190    """
191    # Do not remove referrer if certificate is going to move
192    if getattr(certificate, 'moved', False):
193        return
194
195    code = certificate.code
196
197    # Find all student studycourses that refer to given certificate...
198    try:
199        cat = getUtility(ICatalog, name='students_catalog')
200    except ComponentLookupError:
201        # catalog not available. This might happen during tests.
202        return
203
204    results = cat.searchResults(certcode=(code, code))
205    for student in results:
206        # Remove that referrer...
207        studycourse = student['studycourse']
208        studycourse.certificate = None
209        notify(grok.ObjectModifiedEvent(student))
210        student.__parent__.logger.info(
211            'ObjectRemovedEvent - %s - removed: certificate' % student.__name__)
212    return
213
214class CertificatesPlugin(grok.GlobalUtility):
215    """A plugin that updates certificates.
216    """
217
218    grok.implements(IKofaPluggable)
219    grok.name('certificates')
220
221    deprecated_attributes = []
222
223    def setup(self, site, name, logger):
224        return
225
226    def update(self, site, name, logger):
227        cat = getUtility(ICatalog, name='certificates_catalog')
228        results = cat.apply({'code':(None,None)})
229        uidutil = getUtility(IIntIds, context=cat)
230        items = getFields(ICertificate).items()
231        for r in results:
232            o = uidutil.getObject(r)
233            # Add new attributes
234            for i in items:
235                if not hasattr(o,i[0]):
236                    setattr(o,i[0],i[1].missing_value)
237                    logger.info(
238                        'CertificatesPlugin: %s attribute %s added.' % (
239                        o.code,i[0]))
240            # Remove deprecated attributes
241            for i in self.deprecated_attributes:
242                try:
243                    delattr(o,i)
244                    logger.info(
245                        'CertificatesPlugin: %s attribute %s deleted.' % (
246                        o.code,i))
247                except AttributeError:
248                    pass
249        return
Note: See TracBrowser for help on using the repository browser.