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

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

Make waeup.local.ClearanceOfficer? role assignable at certificate level.

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