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

Last change on this file since 13480 was 12620, checked in by Henrik Bettermann, 10 years ago

Improve department and certificate movers. Add utility view for moving certificates.

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