source: main/waeup.sirp/trunk/src/waeup/sirp/students/viewlets.py @ 7221

Last change on this file since 7221 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: 14.0 KB
Line 
1## $Id: viewlets.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##
18import os
19import grok
20from zope.component import getUtility
21from zope.interface import Interface
22from waeup.sirp.interfaces import (
23    IWAeUPObject, IExtFileStore, IFileStoreNameChooser)
24from waeup.sirp.utils.helpers import string_from_bytes, file_size
25from waeup.sirp.browser import DEFAULT_IMAGE_PATH
26from waeup.sirp.browser.viewlets import PrimaryNavTab
27from waeup.sirp.students.browser import (
28    StudentClearanceDisplayFormPage, StudentClearanceManageFormPage,
29    write_log_message, StudentBaseManageFormPage, StudentBaseDisplayFormPage,
30    StudentFilesUploadPage)
31from waeup.sirp.students.interfaces import IStudent, IStudentClearance
32
33grok.context(IWAeUPObject) # Make IWAeUPObject the default context
34grok.templatedir('browser_templates')
35
36ALLOWED_FILE_EXTENSIONS = ('jpg', 'png', 'pdf', 'tif')
37
38class StudentManageSidebar(grok.ViewletManager):
39    grok.name('left_studentmanage')
40
41class StudentManageLink(grok.Viewlet):
42    """A link displayed in the student box which shows up for StudentNavigation
43    objects.
44
45    """
46    grok.baseclass()
47    grok.viewletmanager(StudentManageSidebar)
48    grok.context(IWAeUPObject)
49    grok.view(Interface)
50    grok.order(5)
51    grok.require('waeup.viewStudent')
52
53    link = 'index'
54    text = u'Base Data'
55
56    def render(self):
57        url = self.view.url(self.context.getStudent(), self.link)
58        return u'<div class="portlet"><a href="%s">%s</a></div>' % (
59                url, self.text)
60
61class StudentManageBaseLink(StudentManageLink):
62    grok.order(1)
63    link = 'index'
64    text = u'Base Data'
65
66class StudentManageClearanceLink(StudentManageLink):
67    grok.order(2)
68    link = 'view_clearance'
69    text = u'Clearance Data'
70
71class StudentManagePersonalLink(StudentManageLink):
72    grok.order(2)
73    link = 'view_personal'
74    text = u'Personal Data'
75
76class StudentManageStudyCourseLink(StudentManageLink):
77    grok.order(3)
78    link = 'studycourse'
79    text = u'Study Course'
80
81class StudentManagePaymentsLink(StudentManageLink):
82    grok.order(4)
83    grok.require('waeup.payStudent')
84    link = 'payments'
85    text = u'Payments'
86
87class StudentManageAccommodationLink(StudentManageLink):
88    grok.order(5)
89    grok.require('waeup.handleAccommodation')
90    link = 'accommodation'
91    text = u'Accommodation Data'
92
93class StudentManageHistoryLink(StudentManageLink):
94    grok.order(6)
95    link = 'history'
96    text = u'History'
97
98
99class StudentMenu(grok.ViewletManager):
100    grok.name('top_student')
101
102class StudentLink(grok.Viewlet):
103    """A link displayed in the student box which shows up for StudentNavigation
104    objects.
105
106    """
107    grok.baseclass()
108    grok.viewletmanager(StudentMenu)
109    grok.context(IWAeUPObject)
110    grok.view(Interface)
111    grok.order(5)
112    grok.require('waeup.viewStudent')
113    template = grok.PageTemplateFile('browser_templates/plainactionbutton.pt')
114
115    link = 'index'
116    text = u'Base Data'
117
118    @property
119    def target_url(self):
120        """Get a URL to the target...
121        """
122        return self.view.url(self.context.getStudent(), self.link)
123
124class StudentBaseLink(StudentLink):
125    grok.order(1)
126    link = 'index'
127    text = u'Base Data'
128
129class StudentClearanceLink(StudentLink):
130    grok.order(2)
131    link = 'view_clearance'
132    text = u'Clearance Data'
133
134class StudentPersonalLink(StudentLink):
135    grok.order(2)
136    link = 'view_personal'
137    text = u'Personal Data'
138
139class StudentStudyCourseLink(StudentLink):
140    grok.order(3)
141    link = 'studycourse'
142    text = u'Study Course'
143
144class StudentPaymentsLink(StudentLink):
145    grok.order(4)
146    link = 'payments'
147    text = u'Payments'
148
149class StudentAccommodationLink(StudentLink):
150    grok.order(5)
151    link = 'accommodation'
152    text = u'Accommodation'
153
154class StudentHistoryLink(StudentLink):
155    grok.order(6)
156    link = 'history'
157    text = u'History'
158
159class StudentsTab(PrimaryNavTab):
160    """Students tab in primary navigation.
161    """
162
163    grok.context(IWAeUPObject)
164    grok.order(4)
165    grok.require('waeup.viewStudents')
166    grok.template('primarynavtab')
167
168    pnav = 4
169    tab_title = u'Students'
170
171    @property
172    def link_target(self):
173        return self.view.application_url('students')
174
175class PrimaryStudentNavManager(grok.ViewletManager):
176    """Viewlet manager for the primary navigation tab.
177    """
178    grok.name('primary_nav_student')
179
180class PrimaryStudentNavTab(grok.Viewlet):
181    """Base for primary student nav tabs.
182    """
183    grok.baseclass()
184    grok.viewletmanager(PrimaryStudentNavManager)
185    grok.template('primarynavtab')
186    grok.order(1)
187    grok.require('waeup.Authenticated')
188    pnav = 0
189    tab_title = u'Some Text'
190
191    @property
192    def link_target(self):
193        return self.view.application_url()
194
195    @property
196    def active(self):
197        view_pnav = getattr(self.view, 'pnav', 0)
198        if view_pnav == self.pnav:
199            return 'active'
200        return ''
201
202#class HomeTab(PrimaryStudentNavTab):
203#    """Home-tab in primary navigation.
204#    """
205#    grok.order(1)
206#    grok.require('waeup.Authenticated')
207#    pnav = 0
208#    tab_title = u'Home'
209
210#class ProspectusTab(PrimaryStudentNavTab):
211#    """Faculties-tab in primary navigation.
212#    """
213#    grok.order(2)
214#    grok.require('waeup.viewAcademics')
215#    pnav = 1
216#    tab_title = u'Prospectus'
217
218#    @property
219#    def link_target(self):
220#        return self.view.application_url('faculties')
221
222class MyDataTab(PrimaryStudentNavTab):
223    """MyData-tab in primary navigation.
224    """
225    grok.order(3)
226    grok.require('waeup.Authenticated')
227    pnav = 4
228    tab_title = u'My Data'
229
230    @property
231    def link_target(self):
232        rel_link = '/students/%s' % self.request.principal.id
233        return self.view.application_url() + rel_link
234
235def handle_file_delete(context, view, download_name):
236    """Handle deletion of student file.
237
238    """
239    store = getUtility(IExtFileStore)
240    store.deleteFileByContext(context, attr=download_name)
241    write_log_message(view, 'deleted: %s' % download_name)
242    view.flash('%s deleted.' % download_name)
243    return
244
245def handle_file_upload(upload, context, view, max_size, download_name=None):
246    """Handle upload of student file.
247
248    Returns `True` in case of success or `False`.
249
250    Please note that file pointer passed in (`upload`) most probably
251    points to end of file when leaving this function.
252    """
253    # Check some file requirements first
254    if upload.filename.count('.') == 0:
255        view.flash('File name has no extension.')
256        return False
257    if upload.filename.count('.') > 1:
258        view.flash('File name contains more than one dot.')
259        return False
260    basename, expected_ext = os.path.splitext(download_name)
261    dummy, ext = os.path.splitext(upload.filename)
262    ext.lower()
263    if expected_ext:
264        if ext != expected_ext:
265            view.flash('%s file extension expected.' %
266                expected_ext.replace('.',''))
267            return False
268    else:
269        if not ext.replace('.','') in ALLOWED_FILE_EXTENSIONS:
270            view.flash(
271                'Only the following extension are allowed: %s' %
272                ', '.join(ALLOWED_FILE_EXTENSIONS))
273            return False
274        download_name += ext
275    size = file_size(upload)
276    if size > max_size:
277        view.flash('Uploaded file is too big.')
278        return False
279    upload.seek(0) # file pointer moved when determining size
280    store = getUtility(IExtFileStore)
281    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
282    store.createFile(file_id, upload)
283    write_log_message(view, 'uploaded: %s (%s)' % (download_name,upload.filename))
284    view.flash('File %s uploaded.' % download_name)
285    return True
286
287class FileManager(grok.ViewletManager):
288    """Viewlet manager for uploading files, preferably scanned images.
289    """
290    grok.name('files')
291
292class FileDisplay(grok.Viewlet):
293    """Base file display viewlet.
294    """
295    grok.baseclass()
296    grok.context(IStudentClearance)
297    grok.viewletmanager(FileManager)
298    grok.view(StudentClearanceDisplayFormPage)
299    grok.template('filedisplay')
300    grok.order(1)
301    grok.require('waeup.viewStudent')
302    label = u'File:'
303    title = u'Scan'
304    download_name = u'filename.jpg'
305
306    @property
307    def file_exists(self):
308        image = getUtility(IExtFileStore).getFileByContext(
309            self.context, attr=self.download_name)
310        if image:
311            return True
312        else:
313            return False
314
315class FileUpload(FileDisplay):
316    """Base upload viewlet.
317    """
318    grok.baseclass()
319    grok.context(IStudentClearance)
320    grok.viewletmanager(FileManager)
321    grok.view(StudentClearanceManageFormPage)
322    grok.template('fileupload')
323    grok.require('waeup.uploadStudentFile')
324    tab_redirect = ''
325    mus = 1024 * 150
326
327    @property
328    def input_name(self):
329        return "%s" % self.__name__
330
331    def update(self):
332        self.max_upload_size = string_from_bytes(self.mus)
333        delete_button = self.request.form.get(
334            'delete_%s' % self.input_name, None)
335        upload_button = self.request.form.get(
336            'upload_%s' % self.input_name, None)
337        if delete_button:
338            handle_file_delete(
339                context=self.context, view=self.view,
340                download_name=self.download_name)
341            self.view.redirect(
342                self.view.url(
343                    self.context, self.view.__name__) + self.tab_redirect)
344            return
345        if upload_button:
346            upload = self.request.form.get(self.input_name, None)
347            if upload:
348                # We got a fresh upload
349                handle_file_upload(upload,
350                    self.context, self.view, self.mus, self.download_name)
351                self.view.redirect(
352                    self.view.url(
353                        self.context, self.view.__name__) + self.tab_redirect)
354            else:
355                self.view.flash('No local file selected.')
356                self.view.redirect(
357                    self.view.url(
358                        self.context, self.view.__name__) + self.tab_redirect)
359        return
360
361class PassportDisplay(FileDisplay):
362    """Passport display viewlet.
363    """
364    grok.order(1)
365    grok.context(IStudent)
366    grok.view(StudentBaseDisplayFormPage)
367    grok.require('waeup.viewStudent')
368    grok.template('imagedisplay')
369    label = u'Passport Picture:'
370    download_name = u'passport.jpg'
371
372class PassportUploadManage(FileUpload):
373    """Passport upload viewlet for officers.
374    """
375    grok.order(1)
376    grok.context(IStudent)
377    grok.view(StudentBaseManageFormPage)
378    grok.require('waeup.manageStudent')
379    grok.template('imageupload')
380    label = u'Passport Picture (jpg only):'
381    mus = 1024 * 50
382    download_name = u'passport.jpg'
383    tab_redirect = '#tab-2'
384
385class PassportUploadEdit(PassportUploadManage):
386    """Passport upload viewlet for students.
387    """
388    grok.view(StudentFilesUploadPage)
389    grok.require('waeup.uploadStudentFile')
390
391class BirthCertificateDisplay(FileDisplay):
392    """Birth Certificate display viewlet.
393    """
394    grok.order(1)
395    label = u'Birth Certificate:'
396    title = u'Birth Certificate Scan'
397    download_name = u'birth_certificate'
398
399class BirthCertificateUpload(FileUpload):
400    """Birth Certificate upload viewlet.
401    """
402    grok.order(1)
403    label = u'Birth Certificate:'
404    title = u'Birth Certificate Scan'
405    mus = 1024 * 150
406    download_name = u'birth_certificate'
407    tab_redirect = '#tab-2'
408
409class AcceptanceLetterDisplay(FileDisplay):
410    """Acceptance Letter display viewlet.
411    """
412    grok.order(1)
413    label = u'Acceptance Letter:'
414    title = u'Acceptance Letter Scan'
415    download_name = u'acceptance_letter'
416
417class AcceptanceLetterUpload(FileUpload):
418    """AcceptanceLetter upload viewlet.
419    """
420    grok.order(2)
421    label = u'Acceptance Letter:'
422    title = u'Acceptance Letter Scan'
423    mus = 1024 * 150
424    download_name = u'acceptance_letter'
425    tab_redirect = '#tab-2'
426
427class Image(grok.View):
428    """Renders jpeg images for students.
429    """
430    grok.baseclass()
431    grok.name('none.jpg')
432    grok.context(IStudentClearance)
433    grok.require('waeup.viewStudent')
434    download_name = u'none.jpg'
435
436    def render(self):
437        # A filename chooser turns a context into a filename suitable
438        # for file storage.
439        image = getUtility(IExtFileStore).getFileByContext(
440            self.context, attr=self.download_name)
441        if image is None:
442            # show placeholder image
443            self.response.setHeader('Content-Type', 'image/jpeg')
444            return open(DEFAULT_IMAGE_PATH, 'rb').read()
445        dummy,ext = os.path.splitext(image.name)
446        if ext == '.jpg':
447            self.response.setHeader('Content-Type', 'image/jpeg')
448        elif ext == '.png':
449            self.response.setHeader('Content-Type', 'image/png')
450        elif ext == '.pdf':
451            self.response.setHeader('Content-Type', 'application/pdf')
452        elif ext == '.tif':
453            self.response.setHeader('Content-Type', 'image/tiff')
454        return image
455
456class Passport(Image):
457    """Renders jpeg passport picture.
458    """
459    grok.name('passport.jpg')
460    download_name = u'passport.jpg'
461    grok.context(IStudent)
462
463class BirthCertificateImage(Image):
464    """Renders birth certificate jpeg scan.
465    """
466    grok.name('birth_certificate')
467    download_name = u'birth_certificate'
468
469class AcceptanceLetterImage(Image):
470    """Renders acceptance letter jpeg scan.
471    """
472    grok.name('acceptance_letter')
473    download_name = u'acceptance_letter'
Note: See TracBrowser for help on using the repository browser.