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

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

Add onclick attribute to action buttons and protect the deactivate and activate buttons by a warning message.

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