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

Last change on this file since 10793 was 10771, checked in by Henrik Bettermann, 11 years ago

For customization we need to name the tab viewlets.

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