source: main/waeup.sirp/trunk/src/waeup/sirp/students/student.py @ 7191

Last change on this file since 7191 was 7191, checked in by Henrik Bettermann, 13 years ago

Adjust copyright statement and svn keyword in students.

  • Property svn:keywords set to Id
File size: 8.6 KB
Line 
1## $Id: student.py 7191 2011-11-25 07:13:22Z 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"""
19Container for the various objects owned by students.
20"""
21import os
22import grok
23from grok import index
24from zope.component.interfaces import IFactory
25from zope.interface import implementedBy
26from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
27from zope.securitypolicy.interfaces import IPrincipalRoleManager
28from waeup.sirp.interfaces import (
29    IObjectHistory, IUserAccount, IFileStoreNameChooser, IFileStoreHandler)
30from waeup.sirp.image import WAeUPImageFile
31from waeup.sirp.imagestorage import DefaultFileStoreHandler
32from waeup.sirp.students.interfaces import (
33    IStudent, IStudentNavigation, IStudentClearanceEdit,
34    IStudentPersonalEdit)
35from waeup.sirp.students.studycourse import StudentStudyCourse
36from waeup.sirp.students.payments import StudentPaymentsContainer
37from waeup.sirp.students.accommodation import StudentAccommodation
38from waeup.sirp.utils.helpers import attrs_to_fields, get_current_principal
39from waeup.sirp.students.utils import generate_student_id
40
41class Student(grok.Container):
42    """This is a student container for the various objects
43    owned by students.
44    """
45    grok.implements(IStudent, IStudentNavigation,
46        IStudentPersonalEdit, IStudentClearanceEdit)
47    grok.provides(IStudent)
48
49    def __init__(self):
50        super(Student, self).__init__()
51        # The site doesn't exist in unit tests
52        try:
53            students = grok.getSite()['students']
54            self.student_id = generate_student_id(students,'?')
55        except TypeError:
56            self.student_id = u'Z654321'
57        self.password = None
58        return
59
60    def loggerInfo(self, ob_class, comment=None):
61        target = self.__name__
62        return grok.getSite()['students'].logger_info(ob_class,target,comment)
63
64    @property
65    def state(self):
66        state = IWorkflowState(self).getState()
67        return state
68
69    @property
70    def history(self):
71        history = IObjectHistory(self)
72        return history
73
74    def getStudent(self):
75        return self
76
77    @property
78    def certificate(self):
79        cert = getattr(self.get('studycourse', None), 'certificate', None)
80        return cert
81
82    @property
83    def current_session(self):
84        cert = getattr(self.get('studycourse', None), 'current_session', None)
85        return cert
86
87# Set all attributes of Student required in IStudent as field
88# properties. Doing this, we do not have to set initial attributes
89# ourselves and as a bonus we get free validation when an attribute is
90# set.
91Student = attrs_to_fields(Student)
92
93class StudentFactory(grok.GlobalUtility):
94    """A factory for students.
95    """
96    grok.implements(IFactory)
97    grok.name(u'waeup.Student')
98    title = u"Create a new student.",
99    description = u"This factory instantiates new student instances."
100
101    def __call__(self, *args, **kw):
102        return Student()
103
104    def getInterfaces(self):
105        return implementedBy(Student)
106
107@grok.subscribe(IStudent, grok.IObjectAddedEvent)
108def handle_student_added(student, event):
109    """If a student is added all subcontainers are automatically added
110    and the transition create is fired. The latter produces a logging message.
111    """
112    student.clearance_locked = True
113    studycourse = StudentStudyCourse()
114    student['studycourse'] = studycourse
115    payments = StudentPaymentsContainer()
116    student['payments'] = payments
117    accommodation = StudentAccommodation()
118    student['accommodation'] = accommodation
119    # Assign global student role for new student
120    account = IUserAccount(student)
121    account.roles = ['waeup.Student']
122    # Assign local StudentRecordOwner role
123    role_manager = IPrincipalRoleManager(student)
124    role_manager.assignRoleToPrincipal(
125        'waeup.local.StudentRecordOwner', student.student_id)
126    IWorkflowInfo(student).fireTransition('create')
127    return
128
129@grok.subscribe(IStudent, grok.IObjectRemovedEvent)
130def handle_student_removed(student, event):
131    """If a student is removed a message is logged.
132    """
133    comment = 'Student record removed'
134    target = student.student_id
135    # In some tests we don't have a principal
136    try:
137        user = get_current_principal().id
138    except (TypeError, AttributeError):
139        return
140    grok.getSite()['students'].logger.info('%s - %s - %s' % (
141        user, target, comment))
142    return
143
144#: The file id marker for student files
145STUDENT_FILE_STORE_NAME = 'file-student'
146
147class StudentFileNameChooser(grok.Adapter):
148    """A file id chooser for :class:`Student` objects.
149
150    `context` is an :class:`Student` instance.
151
152    The :class:`StudentImageNameChooser` can build/check file ids for
153    :class:`Student` objects suitable for use with
154    :class:`ExtFileStore` instances. The delivered file_id contains
155    the file id marker for :class:`Student` object and the student id
156    of the context student.
157
158    This chooser is registered as an adapter providing
159    :class:`waeup.sirp.interfaces.IFileStoreNameChooser`.
160
161    File store name choosers like this one are only convenience
162    components to ease the task of creating file ids for student
163    objects. You are nevertheless encouraged to use them instead of
164    manually setting up filenames for students.
165
166    .. seealso:: :mod:`waeup.sirp.imagestorage`
167
168    """
169    grok.context(IStudent)
170    grok.implements(IFileStoreNameChooser)
171
172    def checkName(self, name=None, attr=None):
173        """Check whether the given name is a valid file id for the context.
174
175        Returns ``True`` only if `name` equals the result of
176        :meth:`chooseName`.
177
178        """
179        return name == self.chooseName()
180
181    def chooseName(self, attr, name=None):
182        """Get a valid file id for student context.
183
184        *Example:*
185
186        For a student with student id ``'A123456'`` and
187        with attr ``'nice_image.jpeg'`` stored in
188        the students container this chooser would create:
189
190          ``'__file-student__students/A/A123456/nice_image_A123456.jpeg'``
191
192        meaning that the nice image of this applicant would be
193        stored in the site-wide file storage in path:
194
195          ``students/A/A123456/nice_image_A123456.jpeg``
196
197        """
198        basename, ext = os.path.splitext(attr)
199        stud_id = self.context.student_id
200        marked_filename = '__%s__%s/%s/%s_%s%s' % (
201            STUDENT_FILE_STORE_NAME, stud_id[0], stud_id, basename, stud_id, ext)
202        return marked_filename
203
204
205class StudentFileStoreHandler(DefaultFileStoreHandler, grok.GlobalUtility):
206    """Student specific file handling.
207
208    This handler knows in which path in a filestore to store student
209    files and how to turn this kind of data into some (browsable)
210    file object.
211
212    It is called from the global file storage, when it wants to
213    get/store a file with a file id starting with
214    ``__file-student__`` (the marker string for student files).
215
216    Like each other file store handler it does not handle the files
217    really (this is done by the global file store) but only computes
218    paths and things like this.
219    """
220    grok.implements(IFileStoreHandler)
221    grok.name(STUDENT_FILE_STORE_NAME)
222
223    def pathFromFileID(self, store, root, file_id):
224        """All student files are put in directory ``students``.
225        """
226        marker, filename, basename, ext = store.extractMarker(file_id)
227        sub_root = os.path.join(root, 'students')
228        return super(StudentFileStoreHandler, self).pathFromFileID(
229            store, sub_root, basename)
230
231    def createFile(self, store, root, filename, file_id, file):
232        """Create a browsable file-like object.
233        """
234        ext = os.path.splitext(filename)[1].lower()
235        # call super method to ensure that any old files with
236        # different filename extension are deleted.
237        file, path, file_obj =  super(
238            StudentFileStoreHandler, self).createFile(
239            store, root,  filename, file_id, file)
240        return file, path, WAeUPImageFile(
241            file_obj.filename, file_obj.data)
Note: See TracBrowser for help on using the repository browser.