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

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

Add StudentApplication? view components.

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