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

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

Add missing context directive.

Enable customization of MyStudentDataTab?.

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