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

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

Replace the term 'WAeUP' by SIRP which is a WAeUP product.

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