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

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

Show correct link to application_slip.

  • Property svn:keywords set to Id
File size: 28.4 KB
RevLine 
[9138]13## $Id: viewlets.py 9397 2012-10-23 18:53:37Z henrik $
[7191]2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
[7106]18import os
[6642]19import grok
[7097]20from zope.component import getUtility
[6642]21from zope.interface import Interface
[7741]22from zope.i18n import translate
[7811]23from waeup.kofa.interfaces import (
[8467]24    IKofaObject, IExtFileStore, IFileStoreNameChooser)
[7811]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 (
[7591]29    PrimaryNavTab, ManageActionButton, AddActionButton)
[8106]30from waeup.kofa.browser.layout import (
[8467]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)
[7811]36from waeup.kofa.students.browser import (
[8735]37    StudentClearanceManageFormPage,
[8467]38    StudentBaseManageFormPage, StudentFilesUploadPage,
39    ExportPDFClearanceSlipPage, StudentsContainerPage,
[7591]40    StudentsContainerManagePage, StudentBaseDisplayFormPage,
41    StudentClearanceDisplayFormPage, StudentPersonalDisplayFormPage,
42    StudyCourseDisplayFormPage, StudyLevelDisplayFormPage,
43    CourseTicketDisplayFormPage, OnlinePaymentDisplayFormPage,
[8119]44    AccommodationManageFormPage, BedTicketDisplayFormPage,
45    StudentClearanceEditFormPage, StudentPersonalEditFormPage)
[7811]46from waeup.kofa.students.interfaces import (
[8467]47    IStudentsContainer, IStudent, IStudentStudyCourse, IStudentAccommodation,
48    IStudentStudyLevel, ICourseTicket, IStudentOnlinePayment, IBedTicket,
[7591]49    )
[8467]50from waeup.kofa.utils.helpers import get_fileformat
[6642]51
[7819]52grok.context(IKofaObject) # Make IKofaObject the default context
[6687]53grok.templatedir('browser_templates')
[6642]54
[7123]55ALLOWED_FILE_EXTENSIONS = ('jpg', 'png', 'pdf', 'tif')
56
[6687]57class StudentManageSidebar(grok.ViewletManager):
58    grok.name('left_studentmanage')
[6642]59
[6687]60class StudentManageLink(grok.Viewlet):
[6660]61    """A link displayed in the student box which shows up for StudentNavigation
[6642]62    objects.
63
64    """
65    grok.baseclass()
[6687]66    grok.viewletmanager(StudentManageSidebar)
[7819]67    grok.context(IKofaObject)
[6642]68    grok.view(Interface)
69    grok.order(5)
[6660]70    grok.require('waeup.viewStudent')
[6642]71
72    link = 'index'
[7738]73    text = _(u'Base Data')
[6642]74
75    def render(self):
[8736]76        url = self.view.url(self.context.student, self.link)
[7833]77        # Here we know that the cookie has been set
78        lang = self.request.cookies.get('kofa.language')
[7811]79        text = translate(self.text, 'waeup.kofa',
[7741]80            target_language=lang)
[7459]81        return u'<li><a href="%s">%s</a></li>' % (
[7741]82                url, text)
[6642]83
[7459]84class StudentManageApplicationLink(StudentManageLink):
[6687]85    grok.order(1)
[7351]86    link = 'application_slip'
[7738]87    text = _(u'Application Slip')
[7340]88
89    def render(self):
[7351]90        slip = getUtility(IExtFileStore).getFileByContext(
[8736]91            self.context.student, attr=self.link)
[7351]92        if slip:
[9397]93            url = self.view.url(self.context.student,self.link)
[7459]94            return u'<li><a href="%s">%s</a></li>' % (
[7340]95                    url, self.text)
96        return ''
97
[7459]98class StudentManageBaseLink(StudentManageLink):
99    grok.order(2)
100    link = 'index'
[7738]101    text = _(u'Base Data')
[7459]102
[6687]103class StudentManageClearanceLink(StudentManageLink):
[7340]104    grok.order(3)
[6687]105    link = 'view_clearance'
[7738]106    text = _(u'Clearance Data')
[6687]107
108class StudentManagePersonalLink(StudentManageLink):
[7340]109    grok.order(4)
[6687]110    link = 'view_personal'
[7738]111    text = _(u'Personal Data')
[6687]112
113class StudentManageStudyCourseLink(StudentManageLink):
[7340]114    grok.order(5)
[6687]115    link = 'studycourse'
[7738]116    text = _(u'Study Course')
[6687]117
118class StudentManagePaymentsLink(StudentManageLink):
[7340]119    grok.order(6)
[7181]120    grok.require('waeup.payStudent')
[6687]121    link = 'payments'
[7738]122    text = _(u'Payments')
[6687]123
124class StudentManageAccommodationLink(StudentManageLink):
[7340]125    grok.order(7)
[7181]126    grok.require('waeup.handleAccommodation')
[6687]127    link = 'accommodation'
[7738]128    text = _(u'Accommodation')
[6687]129
130class StudentManageHistoryLink(StudentManageLink):
[7340]131    grok.order(8)
[6687]132    link = 'history'
[7738]133    text = _(u'History')
[6687]134
[7591]135
136class StudentsContainerManageActionButton(ManageActionButton):
137    grok.order(1)
138    grok.context(IStudentsContainer)
139    grok.view(StudentsContainerPage)
140    grok.require('waeup.manageStudent')
[7738]141    text = _('Manage student section')
[7591]142
143class StudentsContainerAddActionButton(AddActionButton):
144    grok.order(1)
145    grok.context(IStudentsContainer)
146    grok.view(StudentsContainerManagePage)
147    grok.require('waeup.manageStudent')
[7738]148    text = _('Add student')
[7591]149    target = 'addstudent'
150
151class ContactActionButton(ManageActionButton):
[9191]152    grok.order(5)
[7591]153    grok.context(IStudent)
154    grok.view(StudentBaseDisplayFormPage)
155    grok.require('waeup.manageStudent')
156    icon = 'actionicon_mail.png'
[7738]157    text = _('Send email')
[7591]158    target = 'contactstudent'
159
160class StudentBaseManageActionButton(ManageActionButton):
161    grok.order(1)
162    grok.context(IStudent)
163    grok.view(StudentBaseDisplayFormPage)
164    grok.require('waeup.manageStudent')
[7738]165    text = _('Manage')
[7591]166    target = 'manage_base'
167
[9273]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
[9338]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
[9191]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
[9138]195class StudentTransfernButton(ManageActionButton):
[9191]196    grok.order(6)
[9124]197    grok.context(IStudent)
198    grok.view(StudentBaseDisplayFormPage)
199    grok.require('waeup.manageStudent')
[9138]200    text = _('Transfer student')
201    target = 'transfer'
202    icon = 'actionicon_redo.png'
203
204class StudentDeactivateActionButton(ManageActionButton):
[9191]205    grok.order(7)
[9138]206    grok.context(IStudent)
207    grok.view(StudentBaseDisplayFormPage)
208    grok.require('waeup.manageStudent')
[9124]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
[9145]219    @property
220    def onclick(self):
221        return "return window.confirm(%s);" % _(
222            "'A history message will be added. Are you sure?'")
223
[9124]224class StudentActivateActionButton(ManageActionButton):
[9191]225    grok.order(7)
[9124]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
[9145]239    @property
240    def onclick(self):
241        return "return window.confirm(%s);" % _(
242            "'A history message will be added. Are you sure?'")
243
[7591]244class StudentClearanceManageActionButton(ManageActionButton):
245    grok.order(1)
246    grok.context(IStudent)
247    grok.view(StudentClearanceDisplayFormPage)
248    grok.require('waeup.manageStudent')
[7738]249    text = _('Manage')
[8119]250    target = 'manage_clearance'
[7591]251
252class StudentClearActionButton(ManageActionButton):
253    grok.order(2)
254    grok.context(IStudent)
255    grok.view(StudentClearanceDisplayFormPage)
256    grok.require('waeup.clearStudent')
[7738]257    text = _('Clear student')
[7591]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')
[7738]272    text = _('Reject clearance')
[7591]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'
[7738]288    text = _('Download clearance slip')
[7591]289    target = 'clearance.pdf'
290
[8119]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
[8903]309class StudentPersonalManageActionButton(ManageActionButton):
[7591]310    grok.order(1)
311    grok.context(IStudent)
312    grok.view(StudentPersonalDisplayFormPage)
[8903]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')
[7738]322    text = _('Edit')
[7591]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')
[7738]330    text = _('Manage')
[7591]331    target = 'manage'
332
[9138]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
[8078]339class StudyLevelManageActionButton(ManageActionButton):
[7591]340    grok.order(1)
341    grok.context(IStudentStudyLevel)
342    grok.view(StudyLevelDisplayFormPage)
343    grok.require('waeup.manageStudent')
[7738]344    text = _('Manage')
[7591]345    target = 'manage'
346
[9138]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
[7591]354class StudentValidateCoursesActionButton(ManageActionButton):
355    grok.order(3)
356    grok.context(IStudentStudyLevel)
357    grok.view(StudyLevelDisplayFormPage)
358    grok.require('waeup.validateStudent')
[7738]359    text = _('Validate courses')
[7591]360    target = 'validate_courses'
361    icon = 'actionicon_accept.png'
362
363    @property
364    def target_url(self):
[9138]365        is_current = self.context.__parent__.is_current
[8736]366        if self.context.student.state != REGISTERED or \
[9138]367            str(self.context.__parent__.current_level) != self.context.__name__ or\
368            not is_current:
[7591]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')
[7738]377    text = _('Reject courses')
[7591]378    target = 'reject_courses'
379    icon = 'actionicon_reject.png'
380
381    @property
382    def target_url(self):
[9138]383        is_current = self.context.__parent__.is_current
[8736]384        if self.context.student.state not in (VALIDATED, REGISTERED) or \
[9138]385            str(self.context.__parent__.current_level) != self.context.__name__ or\
386            not is_current:
[7591]387            return ''
388        return self.view.url(self.view.context, self.target)
389
[8078]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.pdf'
398
[9138]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
[7591]406class CourseTicketManageActionButton(ManageActionButton):
407    grok.order(1)
408    grok.context(ICourseTicket)
409    grok.view(CourseTicketDisplayFormPage)
410    grok.require('waeup.manageStudent')
[7738]411    text = _('Manage')
[7591]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):
[9070]423    grok.order(9) # This button should always be the last one.
[7591]424    grok.context(IStudentOnlinePayment)
425    grok.view(OnlinePaymentDisplayFormPage)
426    grok.require('waeup.viewStudent')
427    icon = 'actionicon_pdf.png'
[8262]428    text = _('Download payment slip')
429    target = 'payment_slip.pdf'
[7591]430
431    @property
432    def target_url(self):
[8262]433        #if self.context.p_state != 'paid':
434        #    return ''
[7591]435        return self.view.url(self.view.context, self.target)
436
[8420]437class ApprovePaymentActionButton(ManageActionButton):
[9070]438    grok.order(8)
[7591]439    grok.context(IStudentOnlinePayment)
440    grok.view(OnlinePaymentDisplayFormPage)
[8420]441    grok.require('waeup.managePortal')
[8435]442    icon = 'actionicon_accept.png'
[8420]443    text = _('Approve payment')
444    target = 'approve'
[7591]445
446    @property
447    def target_url(self):
[7888]448        if self.context.p_state == 'paid':
[7591]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'
[7738]458    text = _('Book accommodation')
[7591]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'
[7738]467    text = _('Download bed allocation slip')
[7591]468    target = 'bed_allocation.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'
[7738]476    text = _('Relocate student')
[7591]477    target = 'relocate'
478
479class StudentBaseActionButton(ManageActionButton):
480    grok.order(1)
481    grok.context(IStudent)
482    grok.view(StudentBaseDisplayFormPage)
483    grok.require('waeup.handleStudent')
[7876]484    text = _('Edit')
[7591]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'
[7738]493    text = _('Change password')
[7591]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'
[7738]502    text = _('Change portrait')
[7591]503    target = 'change_portrait'
504
505    @property
506    def target_url(self):
[7671]507        if self.context.state != ADMITTED:
[7591]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'
[7738]517    text = _('Start clearance')
[7591]518    target = 'start_clearance'
519
520    @property
521    def target_url(self):
[7671]522        if self.context.state != ADMITTED:
[7591]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')
[7738]531    text = _('Edit')
[7591]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
[8476]540class StartSessionActionButton(ManageActionButton):
[7591]541    grok.order(1)
542    grok.context(IStudentStudyCourse)
543    grok.view(StudyCourseDisplayFormPage)
544    grok.require('waeup.handleStudent')
545    icon = 'actionicon_start.gif'
[8920]546    text = _('Start new session')
[8471]547    target = 'start_session'
[7591]548
549    @property
550    def target_url(self):
[9138]551        if self.context.next_session_allowed and self.context.is_current:
[8471]552            return self.view.url(self.view.context, self.target)
553        return False
[7591]554
555class AddStudyLevelActionButton(AddActionButton):
556    grok.order(1)
557    grok.context(IStudentStudyCourse)
558    grok.view(StudyCourseDisplayFormPage)
559    grok.require('waeup.handleStudent')
[7738]560    text = _('Add course list')
[7591]561    target = 'add'
562
563    @property
564    def target_url(self):
[8736]565        student = self.view.context.student
[7671]566        condition1 = student.state != PAID
[7591]567        condition2 = str(student['studycourse'].current_level) in \
568            self.view.context.keys()
[9138]569        condition3 = not self.context.is_current
570        if condition1 or condition2 or condition3:
[7591]571            return ''
572        return self.view.url(self.view.context, self.target)
573
574class StudyLevelEditActionButton(ManageActionButton):
[8078]575    grok.order(2)
[7591]576    grok.context(IStudentStudyLevel)
577    grok.view(StudyLevelDisplayFormPage)
578    grok.require('waeup.handleStudent')
[8920]579    text = _('Edit course list')
[7591]580    target = 'edit'
581
582    @property
583    def target_url(self):
[8736]584        student = self.view.context.student
[9257]585        condition1 = student.state == PAID
586        condition2 = self.view.context.is_current_level
[9138]587        is_current = self.context.__parent__.is_current
[9257]588        if condition1 and condition2 and is_current:
589            return self.view.url(self.view.context, self.target)
590        return ''
[7591]591
[7184]592class StudentsTab(PrimaryNavTab):
593    """Students tab in primary navigation.
594    """
595
[7819]596    grok.context(IKofaObject)
[7184]597    grok.order(4)
[7240]598    grok.require('waeup.viewStudentsTab')
[7184]599
600    pnav = 4
[7674]601    tab_title = _(u'Students')
[7184]602
603    @property
604    def link_target(self):
605        return self.view.application_url('students')
606
[6687]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)
[7243]617    template = default_primary_nav_template
[6687]618    grok.order(1)
[7184]619    grok.require('waeup.Authenticated')
[8467]620    pnav = 0
[6687]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
[7240]634class MyStudentDataTab(PrimaryStudentNavTab):
[7459]635    """MyData dropdown tab in primary navigation.
[6687]636    """
637    grok.order(3)
[7240]638    grok.require('waeup.viewMyStudentDataTab')
[7459]639    grok.template('mydatadropdowntabs')
[6687]640    pnav = 4
[7738]641    tab_title = _(u'My Data')
[6687]642
643    @property
[7459]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'
[7097]649
[7459]650    @property
651    def targets(self):
[9180]652        student = grok.getSite()['students'][self.request.principal.id]
653        student_url = self.view.url(student)
[9178]654        app_slip = getUtility(IExtFileStore).getFileByContext(
[9180]655            student, 'application_slip')
[7459]656        targets = []
[9178]657        if app_slip:
658            targets = [{'url':student_url + '/application_slip', 'title':'Application Slip'},]
[7459]659        targets += [
660            {'url':student_url, 'title':'Base Data'},
[8467]661            {'url':student_url + '/view_clearance',
662             'title':_('Clearance Data')},
[7738]663            {'url':student_url + '/view_personal', 'title':_('Personal Data')},
664            {'url':student_url + '/studycourse', 'title':_('Study Course')},
665            {'url':student_url + '/payments', 'title':_('Payments')},
[8467]666            {'url':student_url + '/accommodation',
667             'title':_('Accommodation Data')},
[7738]668            {'url':student_url + '/history', 'title':_('History')},
[7459]669            ]
670        return targets
671
[7107]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)
[8735]678    context.writeLogMessage(view, 'deleted: %s' % download_name)
[7738]679    view.flash(_('${a} deleted.', mapping = {'a':download_name}))
[7107]680    return
681
[7106]682def handle_file_upload(upload, context, view, max_size, download_name=None):
683    """Handle upload of student file.
[7097]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    """
[7106]690    # Check some file requirements first
[8467]691    size = file_size(upload)
692    if size > max_size:
693        view.flash(_('Uploaded file is too big.'))
[7106]694        return False
[8467]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.'))
[7106]700        return False
701    basename, expected_ext = os.path.splitext(download_name)
[7123]702    if expected_ext:
[8467]703        if '.' + file_format != expected_ext:
[7738]704            view.flash(_('${a} file extension expected.',
[8467]705                mapping = {'a':expected_ext[1:]}))
[7123]706            return False
707    else:
[8467]708        if not file_format in ALLOWED_FILE_EXTENSIONS:
[7123]709            view.flash(
[8467]710                _('Only the following extensions are allowed: ${a}',
[7738]711                mapping = {'a':', '.join(ALLOWED_FILE_EXTENSIONS)}))
[7123]712            return False
[8467]713        download_name += '.' + file_format
[7097]714    store = getUtility(IExtFileStore)
[7106]715    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
[7097]716    store.createFile(file_id, upload)
[8735]717    context.writeLogMessage(view, 'uploaded: %s (%s)' % (
[8467]718        download_name,upload.filename))
[7738]719    view.flash(_('File ${a} uploaded.', mapping = {'a':download_name}))
[7097]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()
[7993]731    grok.context(IStudent)
[7097]732    grok.viewletmanager(FileManager)
733    grok.view(StudentClearanceDisplayFormPage)
[8106]734    template = default_filedisplay_template
[7097]735    grok.order(1)
736    grok.require('waeup.viewStudent')
[7738]737    label = _(u'File')
738    title = _(u'Scan')
[7106]739    download_name = u'filename.jpg'
[7097]740
[7107]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
[7097]750class FileUpload(FileDisplay):
751    """Base upload viewlet.
752    """
753    grok.baseclass()
[7993]754    grok.context(IStudent)
[7097]755    grok.viewletmanager(FileManager)
756    grok.view(StudentClearanceManageFormPage)
[8106]757    template = default_fileupload_template
[7127]758    grok.require('waeup.uploadStudentFile')
[7491]759    tab_redirect = '?tab2'
[7097]760    mus = 1024 * 150
[7735]761    upload_button =_('Upload new file')
762    delete_button = _('Delete attachment')
[8135]763    show_viewlet = True
[7097]764
[7117]765    @property
766    def input_name(self):
767        return "%s" % self.__name__
768
[7097]769    def update(self):
770        self.max_upload_size = string_from_bytes(self.mus)
[7117]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)
[7108]775        if delete_button:
[7107]776            handle_file_delete(
777                context=self.context, view=self.view,
778                download_name=self.download_name)
779            self.view.redirect(
[7134]780                self.view.url(
781                    self.context, self.view.__name__) + self.tab_redirect)
[7107]782            return
[7108]783        if upload_button:
784            upload = self.request.form.get(self.input_name, None)
785            if upload:
786                # We got a fresh upload
[7111]787                handle_file_upload(upload,
788                    self.context, self.view, self.mus, self.download_name)
789                self.view.redirect(
[7134]790                    self.view.url(
791                        self.context, self.view.__name__) + self.tab_redirect)
[7117]792            else:
[7738]793                self.view.flash(_('No local file selected.'))
[7117]794                self.view.redirect(
[7134]795                    self.view.url(
796                        self.context, self.view.__name__) + self.tab_redirect)
[7097]797        return
798
[7112]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')
[7738]807    label = _(u'Passport Picture')
[7112]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)
[7136]816    grok.require('waeup.manageStudent')
[7112]817    grok.template('imageupload')
[7738]818    label = _(u'Passport Picture (jpg only)')
[7112]819    mus = 1024 * 50
820    download_name = u'passport.jpg'
[7491]821    tab_redirect = '?tab2'
[7112]822
823class PassportUploadEdit(PassportUploadManage):
824    """Passport upload viewlet for students.
825    """
[7114]826    grok.view(StudentFilesUploadPage)
[7127]827    grok.require('waeup.uploadStudentFile')
[7112]828
[7097]829class BirthCertificateDisplay(FileDisplay):
[7112]830    """Birth Certificate display viewlet.
[7097]831    """
832    grok.order(1)
[7738]833    label = _(u'Birth Certificate')
834    title = _(u'Birth Certificate Scan')
[7123]835    download_name = u'birth_certificate'
[7097]836
[7280]837class BirthCertificateSlip(BirthCertificateDisplay):
838    grok.view(ExportPDFClearanceSlipPage)
839
[7127]840class BirthCertificateUpload(FileUpload):
[7097]841    """Birth Certificate upload viewlet.
842    """
843    grok.order(1)
[7738]844    label = _(u'Birth Certificate')
845    title = _(u'Birth Certificate Scan')
[7097]846    mus = 1024 * 150
[7123]847    download_name = u'birth_certificate'
[7491]848    tab_redirect = '?tab2'
[7097]849
850class Image(grok.View):
[7351]851    """Renders images for students.
[7097]852    """
[7106]853    grok.baseclass()
[7097]854    grok.name('none.jpg')
[7993]855    grok.context(IStudent)
[7097]856    grok.require('waeup.viewStudent')
[7106]857    download_name = u'none.jpg'
[7097]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(
[7106]863            self.context, attr=self.download_name)
[7097]864        if image is None:
865            # show placeholder image
[7123]866            self.response.setHeader('Content-Type', 'image/jpeg')
[7097]867            return open(DEFAULT_IMAGE_PATH, 'rb').read()
[7123]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')
[7097]877        return image
878
[7112]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
[7351]886class ApplicationSlipImage(Image):
887    """Renders application slip scan.
888    """
889    grok.name('application_slip')
890    download_name = u'application_slip'
891
[7097]892class BirthCertificateImage(Image):
[7351]893    """Renders birth certificate scan.
[7097]894    """
[7123]895    grok.name('birth_certificate')
896    download_name = u'birth_certificate'
Note: See TracBrowser for help on using the repository browser.