source: main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/viewlets.py @ 9169

Last change on this file since 9169 was 9169, checked in by uli, 12 years ago

Merge changes from trunk, r8786-HEAD

  • Property svn:keywords set to Id
File size: 28.3 KB
RevLine 
[9169]13## $Id: viewlets.py 9169 2012-09-10 11:05:07Z uli $
[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
[9169]168class StudentTransfernButton(ManageActionButton):
169    grok.order(5)
170    grok.context(IStudent)
171    grok.view(StudentBaseDisplayFormPage)
172    grok.require('waeup.manageStudent')
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')
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
192    @property
193    def onclick(self):
194        return "return window.confirm(%s);" % _(
195            "'A history message will be added. Are you sure?'")
196
197class StudentActivateActionButton(ManageActionButton):
198    grok.order(6)
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
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
[9169]282class StudentPersonalManageActionButton(ManageActionButton):
[7591]283    grok.order(1)
284    grok.context(IStudent)
285    grok.view(StudentPersonalDisplayFormPage)
[9169]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
[9169]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
[9169]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):
[9169]338        is_current = self.context.__parent__.is_current
[8736]339        if self.context.student.state != REGISTERED or \
[9169]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):
[9169]356        is_current = self.context.__parent__.is_current
[8736]357        if self.context.student.state not in (VALIDATED, REGISTERED) or \
[9169]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
[9169]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):
[9169]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):
[9169]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'
[9169]519    text = _('Start new session')
[8471]520    target = 'start_session'
[7591]521
522    @property
523    def target_url(self):
[9169]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()
[9169]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')
[9169]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
[9169]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.