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

Last change on this file since 15610 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
RevLine 
[7195]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##
[4789]18"""Courses.
19"""
20import grok
[9843]21import zope.location.location
[7207]22from zope.catalog.interfaces import ICatalog
[4789]23from zope.interface import implementedBy
[9220]24from zope.schema import getFields
25from zope.intid.interfaces import IIntIds
[7207]26from zope.component import getUtility
27from zope.component.interfaces import IFactory, ComponentLookupError
[9220]28from waeup.kofa.interfaces import IKofaPluggable
[10685]29from waeup.kofa.university.interfaces import ICourse
[9843]30from waeup.kofa.utils.batching import VirtualExportJobContainer
[4789]31
[9843]32class VirtualCourseExportJobContainer(VirtualExportJobContainer):
33    """A virtual export job container for courses.
34    """
35
[4789]36class Course(grok.Model):
37    """A university course.
38    """
[10685]39    grok.implements(ICourse)
[4789]40
[9002]41    local_roles = ['waeup.local.Lecturer']
[8996]42
[4789]43    def __init__(self,
44                 title=u'Unnamed Course',
45                 code=u'NA',
46                 credits=0,
47                 passmark=40,
[9220]48                 semester=1,
49                 former_course=False,
50                 **kw):
[4789]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
[9220]57        self.former_course = former_course
[15422]58        self.results_validated_by = None
59        self.results_validation_date = None
60        self.results_validation_session = None
[6566]61
[9843]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
[10650]72    @property
[6008]73    def longtitle(self):
[6566]74        return "%s (%s)" % (self.title,self.code)
75
[4789]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)
[7207]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
[7333]93       certificatescontainer are removed.
[7207]94    """
95    code = course.code
96
[9824]97    # Find all certificatecourses that refer to given course
[7207]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))
[9828]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:
[9826]111        cert.delCertCourses(code)
[7811]112    return
[9220]113
[9227]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
[9220]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
[9828]158        return
Note: See TracBrowser for help on using the repository browser.