source: main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py @ 9479

Last change on this file since 9479 was 9452, checked in by Henrik Bettermann, 12 years ago

Move student workflow history to the bottom. Reformat pdf slips slightly.

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