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

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

Add special permission and view for triggering transitions

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