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

Last change on this file since 17932 was 17798, checked in by Henrik Bettermann, 6 months ago

Make the certificate's longtitle customizable.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.3 KB
Line 
1## $Id: certificate.py 17798 2024-05-22 07:25:56Z 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, IKofaUtils
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 getUtility(
96            IKofaUtils).getCertLongTitle(self)
97
98
99    def addCertCourse(self, course, level=100,
100                      mandatory=True, course_category=None):
101        """Add a certificate course.
102        """
103        code = "%s_%s" % (course.code, level)
104        self[code] = CertificateCourse(course, level, mandatory, course_category)
105        self[code].__parent__ = self
106        self[code].__name__ = code
107        self._p_changed = True
108
109    def delCertCourses(self, code, level=None):
110        """Delete certificate courses.
111
112        We might have more than one certificate course for a course.
113        If level is not provided all certificate courses referring
114        to the same course will be deleted.
115        """
116        keys = list(self.keys()) # create list copy
117        for key in keys:
118            if self[key].getCourseCode() != code:
119                continue
120            if level is not None and str(self[key].level) != str(level):
121                # found a course with correct key but wrong level...
122                continue
123            del self[key]
124            self._p_changed = True
125        return
126
127    def moveCertificate(self, facname, depname, newcode):
128        self.moved = True
129        cert = self
130        oldcode = cert.code
131        cert.code = newcode
132        del self.__parent__[oldcode]
133        newdep = grok.getSite()['faculties'][facname][depname]
134        newdep.certificates[newcode] = cert
135        #self.__parent__._p_changed = True
136        cat = getUtility(ICatalog, name='students_catalog')
137        results = cat.searchResults(certcode=(oldcode, oldcode))
138        for student in results:
139            notify(grok.ObjectModifiedEvent(student))
140            student.__parent__.logger.info(
141                '%s - Certificate moved' % student.__name__)
142        return
143
144class CertificateFactory(grok.GlobalUtility):
145    """A factory for certificates.
146    """
147    grok.implements(IFactory)
148    grok.name(u'waeup.Certificate')
149    title = u"Create a new certificate.",
150    description = u"This factory instantiates new certificate instances."
151
152    def __call__(self, *args, **kw):
153        return Certificate(*args, **kw)
154
155    def getInterfaces(self):
156        return implementedBy(Certificate)
157
158class CertificateCourse(grok.Model):
159    grok.implements(ICertificateCourse)
160
161    def __init__(self, course=None, level=100,
162                 mandatory=True, course_category=None):
163        self.course = course
164        self.level = level
165        self.mandatory = mandatory
166        self.course_category = course_category
167
168    def getCourseCode(self):
169        """Get code of a course.
170        """
171        return self.course.code
172
173    @property
174    def longtitle(self):
175        return "%s in level %s" % (self.course.code,
176                   course_levels.getTerm(self.level).title)
177
178class CertificateCourseFactory(grok.GlobalUtility):
179    """A factory for certificate courses.
180    """
181    grok.implements(IFactory)
182    grok.name(u'waeup.CertificateCourse')
183    title = u"Create a new certificate course.",
184    description = u"This factory instantiates new certificate courses."
185
186    def __call__(self, *args, **kw):
187        return CertificateCourse(*args, **kw)
188
189    def getInterfaces(self):
190        return implementedBy(CertificateCourse)
191
192@grok.subscribe(ICertificate, grok.IObjectRemovedEvent)
193def handle_certificate_removed(certificate, event):
194    """If a certificate is deleted, we make sure that also referrers to
195    student studycourse objects are removed.
196    """
197    # Do not remove referrer if certificate is going to move
198    if getattr(certificate, 'moved', False):
199        return
200
201    code = certificate.code
202
203    # Find all student studycourses that refer to given certificate...
204    try:
205        cat = getUtility(ICatalog, name='students_catalog')
206    except ComponentLookupError:
207        # catalog not available. This might happen during tests.
208        return
209
210    results = cat.searchResults(certcode=(code, code))
211    for student in results:
212        # Remove that referrer...
213        studycourse = student['studycourse']
214        studycourse.certificate = None
215        notify(grok.ObjectModifiedEvent(student))
216        student.__parent__.logger.info(
217            'ObjectRemovedEvent - %s - removed: certificate' % student.__name__)
218    return
219
220class CertificatesPlugin(grok.GlobalUtility):
221    """A plugin that updates certificates.
222    """
223
224    grok.implements(IKofaPluggable)
225    grok.name('certificates')
226
227    deprecated_attributes = []
228
229    def setup(self, site, name, logger):
230        return
231
232    def update(self, site, name, logger):
233        cat = getUtility(ICatalog, name='certificates_catalog')
234        results = cat.apply({'code':(None,None)})
235        uidutil = getUtility(IIntIds, context=cat)
236        items = getFields(ICertificate).items()
237        for r in results:
238            o = uidutil.getObject(r)
239            # Add new attributes
240            for i in items:
241                if not hasattr(o,i[0]):
242                    setattr(o,i[0],i[1].missing_value)
243                    logger.info(
244                        'CertificatesPlugin: %s attribute %s added.' % (
245                        o.code,i[0]))
246            # Remove deprecated attributes
247            for i in self.deprecated_attributes:
248                try:
249                    delattr(o,i)
250                    logger.info(
251                        'CertificatesPlugin: %s attribute %s deleted.' % (
252                        o.code,i))
253                except AttributeError:
254                    pass
255        return
256
257class CertificateCoursesPlugin(grok.GlobalUtility):
258    """A plugin that updates certificate courses.
259    """
260
261    grok.implements(IKofaPluggable)
262    grok.name('certcourses')
263
264    deprecated_attributes = []
265
266    def setup(self, site, name, logger):
267        return
268
269    def update(self, site, name, logger):
270        cat = getUtility(ICatalog, name='certcourses_catalog')
271        results = cat.apply({'course_code':(None,None)})
272        uidutil = getUtility(IIntIds, context=cat)
273        items = getFields(ICertificateCourse).items()
274        for r in results:
275            o = uidutil.getObject(r)
276            # Add new attributes
277            for i in items:
278                if not hasattr(o,i[0]):
279                    setattr(o,i[0],i[1].missing_value)
280                    logger.info(
281                        'CertificateCoursesPlugin: %s/%s_%s attribute %s added.' % (
282                        o.__parent__.code,o.course.code,o.level,i[0]))
283            # Remove deprecated attributes
284            for i in self.deprecated_attributes:
285                try:
286                    delattr(o,i)
287                    logger.info(
288                        'CertificateCoursesPlugin: %s/%s_%s attribute %s deleted.' % (
289                        o.__parent__.code,o.course.code,o.level,i))
290                except AttributeError:
291                    pass
292        return
Note: See TracBrowser for help on using the repository browser.