source: main/waeup.kofa/trunk/src/waeup/kofa/university/course.py @ 15450

Last change on this file since 15450 was 15422, checked in by Henrik Bettermann, 5 years ago

Implement course result validation workflow for lecturers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.2 KB
Line 
1## $Id: course.py 15422 2019-05-24 09:11:40Z 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"""Courses.
19"""
20import grok
21import zope.location.location
22from zope.catalog.interfaces import ICatalog
23from zope.interface import implementedBy
24from zope.schema import getFields
25from zope.intid.interfaces import IIntIds
26from zope.component import getUtility
27from zope.component.interfaces import IFactory, ComponentLookupError
28from waeup.kofa.interfaces import IKofaPluggable
29from waeup.kofa.university.interfaces import ICourse
30from waeup.kofa.utils.batching import VirtualExportJobContainer
31
32class VirtualCourseExportJobContainer(VirtualExportJobContainer):
33    """A virtual export job container for courses.
34    """
35
36class Course(grok.Model):
37    """A university course.
38    """
39    grok.implements(ICourse)
40
41    local_roles = ['waeup.local.Lecturer']
42
43    def __init__(self,
44                 title=u'Unnamed Course',
45                 code=u'NA',
46                 credits=0,
47                 passmark=40,
48                 semester=1,
49                 former_course=False,
50                 **kw):
51        super(Course, self).__init__(**kw)
52        self.title = title
53        self.code = code
54        self.credits = credits
55        self.passmark = passmark
56        self.semester = semester
57        self.former_course = former_course
58        self.results_validated_by = None
59        self.results_validation_date = None
60        self.results_validation_session = None
61
62    def traverse(self, name):
63        """Deliver appropriate containers.
64        """
65        if name == 'exports':
66            # create a virtual exports container and return it
67            container = VirtualCourseExportJobContainer()
68            zope.location.location.located(container, self, 'exports')
69            return container
70        return None
71
72    @property
73    def longtitle(self):
74        return "%s (%s)" % (self.title,self.code)
75
76class CourseFactory(grok.GlobalUtility):
77    """A factory for courses.
78    """
79    grok.implements(IFactory)
80    grok.name(u'waeup.Course')
81    title = u"Create a new course.",
82    description = u"This factory instantiates new course instances."
83
84    def __call__(self, *args, **kw):
85        return Course(*args, **kw)
86
87    def getInterfaces(self):
88        return implementedBy(Course)
89
90@grok.subscribe(ICourse, grok.IObjectRemovedEvent)
91def handle_course_removed(course, event):
92    """If a course is deleted, we make sure that also referrers in a
93       certificatescontainer are removed.
94    """
95    code = course.code
96
97    # Find all certificatecourses that refer to given course
98    try:
99        cat = getUtility(ICatalog, name='certcourses_catalog')
100    except ComponentLookupError:
101        # catalog not available. This might happen during tests.
102        return
103
104    results = cat.searchResults(course_code=(code, code))
105
106    # remove each found referrer (certs might refer to same course multiple
107    # times)
108    certs = [x.__parent__ for x in results]
109    unique_certs = list(set(certs))
110    for cert in unique_certs:
111        cert.delCertCourses(code)
112    return
113
114@grok.subscribe(ICourse, grok.IObjectModifiedEvent)
115def handle_set_former_course(course, event):
116    """If a former course attribute is set, we make sure that referrers in a
117       certificatescontainer are removed.
118    """
119    if event.object.former_course:
120        handle_course_removed(course, event)
121    return
122
123class CoursesPlugin(grok.GlobalUtility):
124    """A plugin that updates courses.
125    """
126
127    grok.implements(IKofaPluggable)
128    grok.name('courses')
129
130    deprecated_attributes = []
131
132    def setup(self, site, name, logger):
133        return
134
135    def update(self, site, name, logger):
136        cat = getUtility(ICatalog, name='courses_catalog')
137        results = cat.apply({'code':(None,None)})
138        uidutil = getUtility(IIntIds, context=cat)
139        items = getFields(ICourse).items()
140        for r in results:
141            o = uidutil.getObject(r)
142            # Add new attributes
143            for i in items:
144                if not hasattr(o,i[0]):
145                    setattr(o,i[0],i[1].missing_value)
146                    logger.info(
147                        'CoursesPlugin: %s attribute %s added.' % (
148                        o.code,i[0]))
149            # Remove deprecated attributes
150            for i in self.deprecated_attributes:
151                try:
152                    delattr(o,i)
153                    logger.info(
154                        'CoursesPlugin: %s attribute %s deleted.' % (
155                        o.code,i))
156                except AttributeError:
157                    pass
158        return
Note: See TracBrowser for help on using the repository browser.