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

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

Use workflow state constants instead of strings in students components.

  • Property svn:keywords set to Id
File size: 24.6 KB
Line 
1## $Id: viewlets.py 7671 2012-02-20 08:56:44Z 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 (
27    PrimaryNavTab, ManageActionButton, AddActionButton)
28from waeup.sirp.browser.layout import default_primary_nav_template
29from waeup.sirp.students.workflow import (ADMITTED, PAID,
30    CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED, VALIDATED)
31from waeup.sirp.students.browser import (
32    StudentClearanceManageFormPage,
33    write_log_message, StudentBaseManageFormPage,
34    StudentFilesUploadPage, ExportPDFClearanceSlipPage, StudentsContainerPage,
35    StudentsContainerManagePage, StudentBaseDisplayFormPage,
36    StudentClearanceDisplayFormPage, StudentPersonalDisplayFormPage,
37    StudyCourseDisplayFormPage, StudyLevelDisplayFormPage,
38    CourseTicketDisplayFormPage, OnlinePaymentDisplayFormPage,
39    AccommodationManageFormPage, BedTicketDisplayFormPage,)
40from waeup.sirp.students.interfaces import (
41    IStudentsContainer, IStudent, IStudentClearance,
42    IStudentStudyCourse, IStudentAccommodation, IStudentStudyLevel,
43    ICourseTicket, IStudentOnlinePayment, IBedTicket,
44    )
45
46grok.context(ISIRPObject) # Make ISIRPObject the default context
47grok.templatedir('browser_templates')
48
49ALLOWED_FILE_EXTENSIONS = ('jpg', 'png', 'pdf', 'tif')
50
51class StudentManageSidebar(grok.ViewletManager):
52    grok.name('left_studentmanage')
53
54class StudentManageLink(grok.Viewlet):
55    """A link displayed in the student box which shows up for StudentNavigation
56    objects.
57
58    """
59    grok.baseclass()
60    grok.viewletmanager(StudentManageSidebar)
61    grok.context(ISIRPObject)
62    grok.view(Interface)
63    grok.order(5)
64    grok.require('waeup.viewStudent')
65
66    link = 'index'
67    text = u'Base Data'
68
69    def render(self):
70        url = self.view.url(self.context.getStudent(), self.link)
71        return u'<li><a href="%s">%s</a></li>' % (
72                url, self.text)
73
74class StudentManageApplicationLink(StudentManageLink):
75    grok.order(1)
76    link = 'application_slip'
77    text = u'Application Slip'
78
79    def render(self):
80        slip = getUtility(IExtFileStore).getFileByContext(
81            self.context.getStudent(), attr=self.link)
82        if slip:
83            url = self.view.url(self.context,self.link)
84            return u'<li><a href="%s">%s</a></li>' % (
85                    url, self.text)
86        return ''
87
88class StudentManageBaseLink(StudentManageLink):
89    grok.order(2)
90    link = 'index'
91    text = u'Base Data'
92
93class StudentManageClearanceLink(StudentManageLink):
94    grok.order(3)
95    link = 'view_clearance'
96    text = u'Clearance Data'
97
98class StudentManagePersonalLink(StudentManageLink):
99    grok.order(4)
100    link = 'view_personal'
101    text = u'Personal Data'
102
103class StudentManageStudyCourseLink(StudentManageLink):
104    grok.order(5)
105    link = 'studycourse'
106    text = u'Study Course'
107
108class StudentManagePaymentsLink(StudentManageLink):
109    grok.order(6)
110    grok.require('waeup.payStudent')
111    link = 'payments'
112    text = u'Payments'
113
114class StudentManageAccommodationLink(StudentManageLink):
115    grok.order(7)
116    grok.require('waeup.handleAccommodation')
117    link = 'accommodation'
118    text = u'Accommodation'
119
120class StudentManageHistoryLink(StudentManageLink):
121    grok.order(8)
122    link = 'history'
123    text = u'History'
124
125
126class StudentsContainerManageActionButton(ManageActionButton):
127    grok.order(1)
128    grok.context(IStudentsContainer)
129    grok.view(StudentsContainerPage)
130    grok.require('waeup.manageStudent')
131    text = 'Manage student section'
132
133class StudentsContainerAddActionButton(AddActionButton):
134    grok.order(1)
135    grok.context(IStudentsContainer)
136    grok.view(StudentsContainerManagePage)
137    grok.require('waeup.manageStudent')
138    text = 'Add student'
139    target = 'addstudent'
140
141class ContactActionButton(ManageActionButton):
142    grok.order(4)
143    grok.context(IStudent)
144    grok.view(StudentBaseDisplayFormPage)
145    grok.require('waeup.manageStudent')
146    icon = 'actionicon_mail.png'
147    text = 'Send email'
148    target = 'contactstudent'
149
150class StudentBaseManageActionButton(ManageActionButton):
151    grok.order(1)
152    grok.context(IStudent)
153    grok.view(StudentBaseDisplayFormPage)
154    grok.require('waeup.manageStudent')
155    text = 'Manage'
156    target = 'manage_base'
157
158class StudentClearanceManageActionButton(ManageActionButton):
159    grok.order(1)
160    grok.context(IStudent)
161    grok.view(StudentClearanceDisplayFormPage)
162    grok.require('waeup.manageStudent')
163    text = 'Manage'
164    target = 'edit_clearance'
165
166class StudentClearActionButton(ManageActionButton):
167    grok.order(2)
168    grok.context(IStudent)
169    grok.view(StudentClearanceDisplayFormPage)
170    grok.require('waeup.clearStudent')
171    text = 'Clear student'
172    target = 'clear'
173    icon = 'actionicon_accept.png'
174
175    @property
176    def target_url(self):
177        if self.context.state != REQUESTED:
178            return ''
179        return self.view.url(self.view.context, self.target)
180
181class StudentRejectClearanceActionButton(ManageActionButton):
182    grok.order(3)
183    grok.context(IStudent)
184    grok.view(StudentClearanceDisplayFormPage)
185    grok.require('waeup.clearStudent')
186    text = 'Reject clearance'
187    target = 'reject_clearance'
188    icon = 'actionicon_reject.png'
189
190    @property
191    def target_url(self):
192        if self.context.state not in (REQUESTED, CLEARED):
193            return ''
194        return self.view.url(self.view.context, self.target)
195
196class ClearanceSlipActionButton(ManageActionButton):
197    grok.order(4)
198    grok.context(IStudent)
199    grok.view(StudentClearanceDisplayFormPage)
200    grok.require('waeup.viewStudent')
201    icon = 'actionicon_pdf.png'
202    text = 'Download clearance slip'
203    target = 'clearance.pdf'
204
205class StudentPersonalEditActionButton(ManageActionButton):
206    grok.order(1)
207    grok.context(IStudent)
208    grok.view(StudentPersonalDisplayFormPage)
209    grok.require('waeup.viewStudent')
210    text = 'Edit'
211    target = 'edit_personal'
212
213class StudyCourseManageActionButton(ManageActionButton):
214    grok.order(1)
215    grok.context(IStudentStudyCourse)
216    grok.view(StudyCourseDisplayFormPage)
217    grok.require('waeup.manageStudent')
218    text = 'Manage'
219    target = 'manage'
220
221class CourseRegistrationSlipActionButton(ManageActionButton):
222    grok.order(1)
223    grok.context(IStudentStudyLevel)
224    grok.view(StudyLevelDisplayFormPage)
225    grok.require('waeup.viewStudent')
226    icon = 'actionicon_pdf.png'
227    text = 'Download course registration slip'
228    target = 'course_registration.pdf'
229
230class StudyLevelManageActionButton(ManageActionButton):
231    grok.order(2)
232    grok.context(IStudentStudyLevel)
233    grok.view(StudyLevelDisplayFormPage)
234    grok.require('waeup.manageStudent')
235    text = 'Manage'
236    target = 'manage'
237
238class StudentValidateCoursesActionButton(ManageActionButton):
239    grok.order(3)
240    grok.context(IStudentStudyLevel)
241    grok.view(StudyLevelDisplayFormPage)
242    grok.require('waeup.validateStudent')
243    text = 'Validate courses'
244    target = 'validate_courses'
245    icon = 'actionicon_accept.png'
246
247    @property
248    def target_url(self):
249        if self.context.getStudent().state != REGISTERED or \
250            str(self.context.__parent__.current_level) != self.context.__name__:
251            return ''
252        return self.view.url(self.view.context, self.target)
253
254class StudentRejectCoursesActionButton(ManageActionButton):
255    grok.order(4)
256    grok.context(IStudentStudyLevel)
257    grok.view(StudyLevelDisplayFormPage)
258    grok.require('waeup.validateStudent')
259    text = 'Reject courses'
260    target = 'reject_courses'
261    icon = 'actionicon_reject.png'
262
263    @property
264    def target_url(self):
265        if self.context.getStudent().state not in (VALIDATED, REGISTERED) or \
266            str(self.context.__parent__.current_level) != self.context.__name__:
267            return ''
268        return self.view.url(self.view.context, self.target)
269
270class CourseTicketManageActionButton(ManageActionButton):
271    grok.order(1)
272    grok.context(ICourseTicket)
273    grok.view(CourseTicketDisplayFormPage)
274    grok.require('waeup.manageStudent')
275    text = 'Manage'
276    target = 'manage'
277
278#class OnlinePaymentManageActionButton(ManageActionButton):
279#    grok.order(1)
280#    grok.context(IStudentPaymentsContainer)
281#    grok.view(PaymentsDisplayFormPage)
282#    grok.require('waeup.manageStudent')
283#    text = 'Manage payments'
284#    target = 'manage'
285
286class PaymentReceiptActionButton(ManageActionButton):
287    grok.order(1)
288    grok.context(IStudentOnlinePayment)
289    grok.view(OnlinePaymentDisplayFormPage)
290    grok.require('waeup.viewStudent')
291    icon = 'actionicon_pdf.png'
292    text = 'Download payment receipt'
293    target = 'payment_receipt.pdf'
294
295    @property
296    def target_url(self):
297        if self.context.p_state != 'paid':
298            return ''
299        return self.view.url(self.view.context, self.target)
300
301class RequestCallbackActionButton(ManageActionButton):
302    grok.order(2)
303    grok.context(IStudentOnlinePayment)
304    grok.view(OnlinePaymentDisplayFormPage)
305    grok.require('waeup.payStudent')
306    icon = 'actionicon_call.png'
307    text = 'Request callback'
308    target = 'callback'
309
310    @property
311    def target_url(self):
312        if self.context.p_state != 'unpaid':
313            return ''
314        return self.view.url(self.view.context, self.target)
315
316class AddBedTicketActionButton(ManageActionButton):
317    grok.order(1)
318    grok.context(IStudentAccommodation)
319    grok.view(AccommodationManageFormPage)
320    grok.require('waeup.handleAccommodation')
321    icon = 'actionicon_home.png'
322    text = 'Book accommodation'
323    target = 'add'
324
325class BedTicketSlipActionButton(ManageActionButton):
326    grok.order(1)
327    grok.context(IBedTicket)
328    grok.view(BedTicketDisplayFormPage)
329    grok.require('waeup.handleAccommodation')
330    icon = 'actionicon_pdf.png'
331    text = 'Download bed allocation slip'
332    target = 'bed_allocation.pdf'
333
334class RelocateStudentActionButton(ManageActionButton):
335    grok.order(2)
336    grok.context(IBedTicket)
337    grok.view(BedTicketDisplayFormPage)
338    grok.require('waeup.manageHostels')
339    icon = 'actionicon_reload.png'
340    text = 'Relocate student'
341    target = 'relocate'
342
343class StudentBaseActionButton(ManageActionButton):
344    grok.order(1)
345    grok.context(IStudent)
346    grok.view(StudentBaseDisplayFormPage)
347    grok.require('waeup.handleStudent')
348    text = 'Edit base data'
349    target = 'edit_base'
350
351class StudentPasswordActionButton(ManageActionButton):
352    grok.order(2)
353    grok.context(IStudent)
354    grok.view(StudentBaseDisplayFormPage)
355    grok.require('waeup.handleStudent')
356    icon = 'actionicon_key.png'
357    text = 'Change password'
358    target = 'change_password'
359
360class StudentPassportActionButton(ManageActionButton):
361    grok.order(3)
362    grok.context(IStudent)
363    grok.view(StudentBaseDisplayFormPage)
364    grok.require('waeup.handleStudent')
365    icon = 'actionicon_portrait.png'
366    text = 'Change portrait'
367    target = 'change_portrait'
368
369    @property
370    def target_url(self):
371        if self.context.state != ADMITTED:
372            return ''
373        return self.view.url(self.view.context, self.target)
374
375class StudentClearanceStartActionButton(ManageActionButton):
376    grok.order(1)
377    grok.context(IStudent)
378    grok.view(StudentClearanceDisplayFormPage)
379    grok.require('waeup.handleStudent')
380    icon = 'actionicon_start.gif'
381    text = 'Start clearance'
382    target = 'start_clearance'
383
384    @property
385    def target_url(self):
386        if self.context.state != ADMITTED:
387            return ''
388        return self.view.url(self.view.context, self.target)
389
390class StudentClearanceEditActionButton(ManageActionButton):
391    grok.order(1)
392    grok.context(IStudent)
393    grok.view(StudentClearanceDisplayFormPage)
394    grok.require('waeup.handleStudent')
395    text = 'Edit'
396    target = 'cedit'
397
398    @property
399    def target_url(self):
400        if self.context.clearance_locked:
401            return ''
402        return self.view.url(self.view.context, self.target)
403
404class CourseRegistrationStartActionButton(ManageActionButton):
405    grok.order(1)
406    grok.context(IStudentStudyCourse)
407    grok.view(StudyCourseDisplayFormPage)
408    grok.require('waeup.handleStudent')
409    icon = 'actionicon_start.gif'
410    text = 'Start course registration'
411    target = 'start_course_registration'
412
413    @property
414    def target_url(self):
415        if not self.context.getStudent().state in (CLEARED,RETURNING):
416            return ''
417        return self.view.url(self.view.context, self.target)
418
419class AddStudyLevelActionButton(AddActionButton):
420    grok.order(1)
421    grok.context(IStudentStudyCourse)
422    grok.view(StudyCourseDisplayFormPage)
423    grok.require('waeup.handleStudent')
424    text = 'Add course list'
425    target = 'add'
426
427    @property
428    def target_url(self):
429        student = self.view.context.getStudent()
430        condition1 = student.state != PAID
431        condition2 = str(student['studycourse'].current_level) in \
432            self.view.context.keys()
433        if condition1 or condition2:
434            return ''
435        return self.view.url(self.view.context, self.target)
436
437class StudyLevelEditActionButton(ManageActionButton):
438    grok.order(1)
439    grok.context(IStudentStudyLevel)
440    grok.view(StudyLevelDisplayFormPage)
441    grok.require('waeup.handleStudent')
442    text = 'Add and remove courses'
443    target = 'edit'
444
445    @property
446    def target_url(self):
447        student = self.view.context.getStudent()
448        condition1 = student.state != PAID
449        condition2 = student[
450            'studycourse'].current_level != self.view.context.level
451        if condition1 or condition2:
452            return ''
453        return self.view.url(self.view.context, self.target)
454
455class StudentsTab(PrimaryNavTab):
456    """Students tab in primary navigation.
457    """
458
459    grok.context(ISIRPObject)
460    grok.order(4)
461    grok.require('waeup.viewStudentsTab')
462
463    pnav = 4
464    tab_title = u'Students'
465
466    @property
467    def link_target(self):
468        return self.view.application_url('students')
469
470class PrimaryStudentNavManager(grok.ViewletManager):
471    """Viewlet manager for the primary navigation tab.
472    """
473    grok.name('primary_nav_student')
474
475class PrimaryStudentNavTab(grok.Viewlet):
476    """Base for primary student nav tabs.
477    """
478    grok.baseclass()
479    grok.viewletmanager(PrimaryStudentNavManager)
480    template = default_primary_nav_template
481    grok.order(1)
482    grok.require('waeup.Authenticated')
483    pnav = 0
484    tab_title = u'Some Text'
485
486    @property
487    def link_target(self):
488        return self.view.application_url()
489
490    @property
491    def active(self):
492        view_pnav = getattr(self.view, 'pnav', 0)
493        if view_pnav == self.pnav:
494            return 'active'
495        return ''
496
497class MyStudentDataTab(PrimaryStudentNavTab):
498    """MyData dropdown tab in primary navigation.
499    """
500    grok.order(3)
501    grok.require('waeup.viewMyStudentDataTab')
502    grok.template('mydatadropdowntabs')
503    pnav = 4
504    tab_title = u'My Data'
505
506    @property
507    def active(self):
508        view_pnav = getattr(self.view, 'pnav', 0)
509        if view_pnav == self.pnav:
510            return 'active dropdown'
511        return 'dropdown'
512
513    @property
514    def targets(self):
515        student_url = self.view.application_url() + (
516            '/students/%s' % self.request.principal.id)
517        #app_slip = getUtility(IExtFileStore).getFileByContext(
518        #    self.context.getStudent(), 'application_slip')
519        targets = []
520        #if app_slip:
521        #    targets = [{'url':student_url + '/application_slip', 'title':'Application Slip'},]
522        targets += [
523            {'url':student_url, 'title':'Base Data'},
524            {'url':student_url + '/view_clearance', 'title':'Clearance Data'},
525            {'url':student_url + '/view_personal', 'title':'Personal Data'},
526            {'url':student_url + '/studycourse', 'title':'Study Course'},
527            {'url':student_url + '/payments', 'title':'Payments'},
528            {'url':student_url + '/accommodation', 'title':'Accommodation Data'},
529            {'url':student_url + '/history', 'title':'History'},
530            ]
531        return targets
532
533def handle_file_delete(context, view, download_name):
534    """Handle deletion of student file.
535
536    """
537    store = getUtility(IExtFileStore)
538    store.deleteFileByContext(context, attr=download_name)
539    write_log_message(view, 'deleted: %s' % download_name)
540    view.flash('%s deleted.' % download_name)
541    return
542
543def handle_file_upload(upload, context, view, max_size, download_name=None):
544    """Handle upload of student file.
545
546    Returns `True` in case of success or `False`.
547
548    Please note that file pointer passed in (`upload`) most probably
549    points to end of file when leaving this function.
550    """
551    # Check some file requirements first
552    if upload.filename.count('.') == 0:
553        view.flash('File name has no extension.')
554        return False
555    if upload.filename.count('.') > 1:
556        view.flash('File name contains more than one dot.')
557        return False
558    basename, expected_ext = os.path.splitext(download_name)
559    dummy, ext = os.path.splitext(upload.filename)
560    ext.lower()
561    if expected_ext:
562        if ext != expected_ext:
563            view.flash('%s file extension expected.' %
564                expected_ext.replace('.',''))
565            return False
566    else:
567        if not ext.replace('.','') in ALLOWED_FILE_EXTENSIONS:
568            view.flash(
569                'Only the following extension are allowed: %s' %
570                ', '.join(ALLOWED_FILE_EXTENSIONS))
571            return False
572        download_name += ext
573    size = file_size(upload)
574    if size > max_size:
575        view.flash('Uploaded file is too big.')
576        return False
577    upload.seek(0) # file pointer moved when determining size
578    store = getUtility(IExtFileStore)
579    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
580    store.createFile(file_id, upload)
581    write_log_message(view, 'uploaded: %s (%s)' % (download_name,upload.filename))
582    view.flash('File %s uploaded.' % download_name)
583    return True
584
585class FileManager(grok.ViewletManager):
586    """Viewlet manager for uploading files, preferably scanned images.
587    """
588    grok.name('files')
589
590class FileDisplay(grok.Viewlet):
591    """Base file display viewlet.
592    """
593    grok.baseclass()
594    grok.context(IStudentClearance)
595    grok.viewletmanager(FileManager)
596    grok.view(StudentClearanceDisplayFormPage)
597    grok.template('filedisplay')
598    grok.order(1)
599    grok.require('waeup.viewStudent')
600    label = u'File'
601    title = u'Scan'
602    download_name = u'filename.jpg'
603
604    @property
605    def file_exists(self):
606        image = getUtility(IExtFileStore).getFileByContext(
607            self.context, attr=self.download_name)
608        if image:
609            return True
610        else:
611            return False
612
613class FileUpload(FileDisplay):
614    """Base upload viewlet.
615    """
616    grok.baseclass()
617    grok.context(IStudentClearance)
618    grok.viewletmanager(FileManager)
619    grok.view(StudentClearanceManageFormPage)
620    grok.template('fileupload')
621    grok.require('waeup.uploadStudentFile')
622    tab_redirect = '?tab2'
623    mus = 1024 * 150
624
625    @property
626    def input_name(self):
627        return "%s" % self.__name__
628
629    def update(self):
630        self.max_upload_size = string_from_bytes(self.mus)
631        delete_button = self.request.form.get(
632            'delete_%s' % self.input_name, None)
633        upload_button = self.request.form.get(
634            'upload_%s' % self.input_name, None)
635        if delete_button:
636            handle_file_delete(
637                context=self.context, view=self.view,
638                download_name=self.download_name)
639            self.view.redirect(
640                self.view.url(
641                    self.context, self.view.__name__) + self.tab_redirect)
642            return
643        if upload_button:
644            upload = self.request.form.get(self.input_name, None)
645            if upload:
646                # We got a fresh upload
647                handle_file_upload(upload,
648                    self.context, self.view, self.mus, self.download_name)
649                self.view.redirect(
650                    self.view.url(
651                        self.context, self.view.__name__) + self.tab_redirect)
652            else:
653                self.view.flash('No local file selected.')
654                self.view.redirect(
655                    self.view.url(
656                        self.context, self.view.__name__) + self.tab_redirect)
657        return
658
659class PassportDisplay(FileDisplay):
660    """Passport display viewlet.
661    """
662    grok.order(1)
663    grok.context(IStudent)
664    grok.view(StudentBaseDisplayFormPage)
665    grok.require('waeup.viewStudent')
666    grok.template('imagedisplay')
667    label = u'Passport Picture'
668    download_name = u'passport.jpg'
669
670class PassportUploadManage(FileUpload):
671    """Passport upload viewlet for officers.
672    """
673    grok.order(1)
674    grok.context(IStudent)
675    grok.view(StudentBaseManageFormPage)
676    grok.require('waeup.manageStudent')
677    grok.template('imageupload')
678    label = u'Passport Picture (jpg only)'
679    mus = 1024 * 50
680    download_name = u'passport.jpg'
681    tab_redirect = '?tab2'
682
683class PassportUploadEdit(PassportUploadManage):
684    """Passport upload viewlet for students.
685    """
686    grok.view(StudentFilesUploadPage)
687    grok.require('waeup.uploadStudentFile')
688
689class BirthCertificateDisplay(FileDisplay):
690    """Birth Certificate display viewlet.
691    """
692    grok.order(1)
693    label = u'Birth Certificate'
694    title = u'Birth Certificate Scan'
695    download_name = u'birth_certificate'
696
697class BirthCertificateSlip(BirthCertificateDisplay):
698    grok.view(ExportPDFClearanceSlipPage)
699
700class BirthCertificateUpload(FileUpload):
701    """Birth Certificate upload viewlet.
702    """
703    grok.order(1)
704    label = u'Birth Certificate'
705    title = u'Birth Certificate Scan'
706    mus = 1024 * 150
707    download_name = u'birth_certificate'
708    tab_redirect = '?tab2'
709
710class AcceptanceLetterDisplay(FileDisplay):
711    """Acceptance Letter display viewlet.
712    """
713    grok.order(1)
714    label = u'Acceptance Letter'
715    title = u'Acceptance Letter Scan'
716    download_name = u'acceptance_letter'
717
718class AcceptanceLetterSlip(AcceptanceLetterDisplay):
719    grok.view(ExportPDFClearanceSlipPage)
720
721class AcceptanceLetterUpload(FileUpload):
722    """AcceptanceLetter upload viewlet.
723    """
724    grok.order(2)
725    label = u'Acceptance Letter'
726    title = u'Acceptance Letter Scan'
727    mus = 1024 * 150
728    download_name = u'acceptance_letter'
729    tab_redirect = '?tab2'
730
731class Image(grok.View):
732    """Renders images for students.
733    """
734    grok.baseclass()
735    grok.name('none.jpg')
736    grok.context(IStudentClearance)
737    grok.require('waeup.viewStudent')
738    download_name = u'none.jpg'
739
740    def render(self):
741        # A filename chooser turns a context into a filename suitable
742        # for file storage.
743        image = getUtility(IExtFileStore).getFileByContext(
744            self.context, attr=self.download_name)
745        if image is None:
746            # show placeholder image
747            self.response.setHeader('Content-Type', 'image/jpeg')
748            return open(DEFAULT_IMAGE_PATH, 'rb').read()
749        dummy,ext = os.path.splitext(image.name)
750        if ext == '.jpg':
751            self.response.setHeader('Content-Type', 'image/jpeg')
752        elif ext == '.png':
753            self.response.setHeader('Content-Type', 'image/png')
754        elif ext == '.pdf':
755            self.response.setHeader('Content-Type', 'application/pdf')
756        elif ext == '.tif':
757            self.response.setHeader('Content-Type', 'image/tiff')
758        return image
759
760class Passport(Image):
761    """Renders jpeg passport picture.
762    """
763    grok.name('passport.jpg')
764    download_name = u'passport.jpg'
765    grok.context(IStudent)
766
767class ApplicationSlipImage(Image):
768    """Renders application slip scan.
769    """
770    grok.name('application_slip')
771    download_name = u'application_slip'
772
773class BirthCertificateImage(Image):
774    """Renders birth certificate scan.
775    """
776    grok.name('birth_certificate')
777    download_name = u'birth_certificate'
778
779class AcceptanceLetterImage(Image):
780    """Renders acceptance letter scan.
781    """
782    grok.name('acceptance_letter')
783    download_name = u'acceptance_letter'
Note: See TracBrowser for help on using the repository browser.