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

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

Make AddPreviousPaymentActionButton? customizable.

  • Property svn:keywords set to Id
File size: 32.9 KB
Line 
13## $Id: viewlets.py 10811 2013-11-29 08:25:23Z henrik $
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##
18import os
19import grok
20from zope.component import getUtility
21from zope.interface import Interface
22from zope.i18n import translate
23from waeup.kofa.interfaces import (
24    IKofaObject, IExtFileStore, IFileStoreNameChooser)
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 (
29    PrimaryNavTab, ManageActionButton, AddActionButton)
30from waeup.kofa.browser.layout import (
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, GRADUATED, TRANSCRIPT)
36from waeup.kofa.students.browser import (
37    clearance_disabled_message,
38    StudentClearanceManageFormPage,
39    StudentBaseManageFormPage, StudentFilesUploadPage,
40    ExportPDFClearanceSlipPage, StudentsContainerPage,
41    StudentsContainerManagePage, StudentBaseDisplayFormPage,
42    StudentClearanceDisplayFormPage, StudentPersonalDisplayFormPage,
43    StudyCourseDisplayFormPage, StudyLevelDisplayFormPage,
44    CourseTicketDisplayFormPage, OnlinePaymentDisplayFormPage,
45    AccommodationManageFormPage, BedTicketDisplayFormPage,
46    StudentClearanceEditFormPage, StudentPersonalEditFormPage,
47    PaymentsManageFormPage, StudyCourseTranscriptPage)
48from waeup.kofa.students.interfaces import (
49    IStudentsContainer, IStudent, IStudentStudyCourse, IStudentAccommodation,
50    IStudentStudyLevel, ICourseTicket, IStudentOnlinePayment, IBedTicket,
51    IStudentPaymentsContainer, IStudentsUtils
52    )
53from waeup.kofa.utils.helpers import get_fileformat
54
55grok.context(IKofaObject) # Make IKofaObject the default context
56grok.templatedir('browser_templates')
57
58ALLOWED_FILE_EXTENSIONS = ('jpg', 'png', 'pdf', 'tif')
59
60class StudentManageSidebar(grok.ViewletManager):
61    grok.name('left_studentmanage')
62
63class StudentManageLink(grok.Viewlet):
64    """A link displayed in the student box which shows up for StudentNavigation
65    objects.
66
67    """
68    grok.baseclass()
69    grok.viewletmanager(StudentManageSidebar)
70    grok.context(IKofaObject)
71    grok.view(Interface)
72    grok.order(5)
73    grok.require('waeup.viewStudent')
74
75    link = 'index'
76    text = _(u'Base Data')
77
78    def render(self):
79        url = self.view.url(self.context.student, self.link)
80        # Here we know that the cookie has been set
81        lang = self.request.cookies.get('kofa.language')
82        text = translate(self.text, 'waeup.kofa',
83            target_language=lang)
84        if not self.link:
85            return ''
86        return u'<li><a href="%s">%s</a></li>' % (
87                url, text)
88
89class StudentManageApplicationLink(StudentManageLink):
90    grok.order(1)
91    link = 'application_slip'
92    text = _(u'Application Slip')
93
94    def render(self):
95        slip = getUtility(IExtFileStore).getFileByContext(
96            self.context.student, attr=self.link)
97        if slip:
98            lang = self.request.cookies.get('kofa.language')
99            text = translate(self.text, 'waeup.kofa',
100                target_language=lang)
101            url = self.view.url(self.context.student,self.link)
102            return u'<li><a href="%s">%s</a></li>' % (
103                    url, text)
104        return ''
105
106class StudentManageBaseLink(StudentManageLink):
107    grok.order(2)
108    link = 'index'
109    text = _(u'Base Data')
110
111class StudentManageClearanceLink(StudentManageLink):
112    grok.order(3)
113    grok.name('studentmanageclearancelink')
114    link = 'view_clearance'
115    text = _(u'Clearance Data')
116
117class StudentManagePersonalLink(StudentManageLink):
118    grok.order(4)
119    grok.name('studentmanagepersonallink')
120    link = 'view_personal'
121    text = _(u'Personal Data')
122
123class StudentManageStudyCourseLink(StudentManageLink):
124    grok.order(5)
125    link = 'studycourse'
126    text = _(u'Study Course')
127
128class StudentManagePaymentsLink(StudentManageLink):
129    grok.order(6)
130    grok.require('waeup.viewStudent')
131    link = 'payments'
132    text = _(u'Payments')
133
134class StudentManageAccommodationLink(StudentManageLink):
135    grok.order(7)
136    grok.name('studentmanageaccommodationlink')
137    grok.require('waeup.handleAccommodation')
138    link = 'accommodation'
139    text = _(u'Accommodation')
140
141class StudentManageHistoryLink(StudentManageLink):
142    grok.order(8)
143    link = 'history'
144    text = _(u'History')
145
146
147class StudentsContainerManageActionButton(ManageActionButton):
148    grok.order(1)
149    grok.context(IStudentsContainer)
150    grok.view(StudentsContainerPage)
151    grok.require('waeup.manageStudent')
152    text = _('Manage student section')
153
154class StudentsContainerAddActionButton(AddActionButton):
155    grok.order(1)
156    grok.context(IStudentsContainer)
157    grok.view(StudentsContainerManagePage)
158    grok.require('waeup.manageStudent')
159    text = _('Add student')
160    target = 'addstudent'
161
162class ContactActionButton(ManageActionButton):
163    grok.order(5)
164    grok.context(IStudent)
165    grok.view(StudentBaseDisplayFormPage)
166    grok.require('waeup.manageStudent')
167    icon = 'actionicon_mail.png'
168    text = _('Send email')
169    target = 'contactstudent'
170
171class StudentBaseManageActionButton(ManageActionButton):
172    grok.order(1)
173    grok.context(IStudent)
174    grok.view(StudentBaseDisplayFormPage)
175    grok.require('waeup.manageStudent')
176    text = _('Manage')
177    target = 'manage_base'
178
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
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
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
206class StudentTransferButton(ManageActionButton):
207    grok.order(6)
208    grok.context(IStudent)
209    grok.view(StudentBaseDisplayFormPage)
210    grok.require('waeup.manageStudent')
211    text = _('Transfer student')
212    target = 'transfer'
213    icon = 'actionicon_redo.png'
214
215class StudentDeactivateActionButton(ManageActionButton):
216    grok.order(7)
217    grok.context(IStudent)
218    grok.view(StudentBaseDisplayFormPage)
219    grok.require('waeup.manageStudent')
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
230    @property
231    def onclick(self):
232        return "return window.confirm(%s);" % _(
233            "'A history message will be added. Are you sure?'")
234
235class StudentActivateActionButton(ManageActionButton):
236    grok.order(7)
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
250    @property
251    def onclick(self):
252        return "return window.confirm(%s);" % _(
253            "'A history message will be added. Are you sure?'")
254
255class StudentClearanceManageActionButton(ManageActionButton):
256    grok.order(1)
257    grok.context(IStudent)
258    grok.view(StudentClearanceDisplayFormPage)
259    grok.require('waeup.manageStudent')
260    text = _('Manage')
261    target = 'manage_clearance'
262
263class StudentClearActionButton(ManageActionButton):
264    grok.order(2)
265    grok.context(IStudent)
266    grok.view(StudentClearanceDisplayFormPage)
267    grok.require('waeup.clearStudent')
268    text = _('Clear student')
269    target = 'clear'
270    icon = 'actionicon_accept.png'
271
272    @property
273    def target_url(self):
274        if clearance_disabled_message(self.context):
275            return ''
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')
285    text = _('Reject clearance')
286    target = 'reject_clearance'
287    icon = 'actionicon_reject.png'
288
289    @property
290    def target_url(self):
291        if clearance_disabled_message(self.context):
292            return ''
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'
303    text = _('Download clearance slip')
304    target = 'clearance_slip.pdf'
305
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
324class StudentPersonalManageActionButton(ManageActionButton):
325    grok.order(1)
326    grok.context(IStudent)
327    grok.view(StudentPersonalDisplayFormPage)
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')
337    text = _('Edit')
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')
345    text = _('Manage')
346    target = 'manage'
347
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
354class StudyCourseTranscriptActionButton(ManageActionButton):
355    grok.order(2)
356    grok.context(IStudentStudyCourse)
357    grok.view(StudyCourseDisplayFormPage)
358    grok.require('waeup.viewTranscript')
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)
373    grok.require('waeup.viewTranscript')
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
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
399class StudyLevelManageActionButton(ManageActionButton):
400    grok.order(1)
401    grok.context(IStudentStudyLevel)
402    grok.view(StudyLevelDisplayFormPage)
403    grok.require('waeup.manageStudent')
404    text = _('Manage')
405    target = 'manage'
406
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
414class StudentValidateCoursesActionButton(ManageActionButton):
415    grok.order(3)
416    grok.context(IStudentStudyLevel)
417    grok.view(StudyLevelDisplayFormPage)
418    grok.require('waeup.validateStudent')
419    text = _('Validate courses')
420    target = 'validate_courses'
421    icon = 'actionicon_accept.png'
422
423    @property
424    def target_url(self):
425        is_current = self.context.__parent__.is_current
426        if self.context.student.state != REGISTERED or \
427            str(self.context.__parent__.current_level) != self.context.__name__ or\
428            not is_current:
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')
437    text = _('Reject courses')
438    target = 'reject_courses'
439    icon = 'actionicon_reject.png'
440
441    @property
442    def target_url(self):
443        is_current = self.context.__parent__.is_current
444        if self.context.student.state not in (VALIDATED, REGISTERED) or \
445            str(self.context.__parent__.current_level) != self.context.__name__ or\
446            not is_current:
447            return ''
448        return self.view.url(self.view.context, self.target)
449
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')
457    target = 'course_registration_slip.pdf'
458
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
466class CourseTicketManageActionButton(ManageActionButton):
467    grok.order(1)
468    grok.context(ICourseTicket)
469    grok.view(CourseTicketDisplayFormPage)
470    grok.require('waeup.manageStudent')
471    text = _('Manage')
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):
483    grok.order(9) # This button should always be the last one.
484    grok.context(IStudentOnlinePayment)
485    grok.view(OnlinePaymentDisplayFormPage)
486    grok.require('waeup.viewStudent')
487    icon = 'actionicon_pdf.png'
488    text = _('Download payment slip')
489    target = 'payment_slip.pdf'
490
491    @property
492    def target_url(self):
493        #if self.context.p_state != 'paid':
494        #    return ''
495        return self.view.url(self.view.context, self.target)
496
497class ApprovePaymentActionButton(ManageActionButton):
498    grok.order(8)
499    grok.context(IStudentOnlinePayment)
500    grok.view(OnlinePaymentDisplayFormPage)
501    grok.require('waeup.managePortal')
502    icon = 'actionicon_accept.png'
503    text = _('Approve payment')
504    target = 'approve'
505
506    @property
507    def target_url(self):
508        if self.context.p_state == 'paid':
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'
518    text = _('Book accommodation')
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'
527    text = _('Download bed allocation slip')
528    target = 'bed_allocation_slip.pdf'
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'
536    text = _('Relocate student')
537    target = 'relocate'
538
539class StudentBaseActionButton(ManageActionButton):
540    grok.order(1)
541    grok.context(IStudent)
542    grok.view(StudentBaseDisplayFormPage)
543    grok.require('waeup.handleStudent')
544    text = _('Edit')
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'
553    text = _('Change password')
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'
562    text = _('Change portrait')
563    target = 'change_portrait'
564
565    @property
566    def target_url(self):
567        PWCHANGE_STATES = getUtility(IStudentsUtils).PWCHANGE_STATES
568        if self.context.state not in PWCHANGE_STATES:
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'
578    text = _('Start clearance')
579    target = 'start_clearance'
580
581    @property
582    def target_url(self):
583        if self.context.state != ADMITTED:
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')
592    text = _('Edit')
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
601class StartSessionActionButton(ManageActionButton):
602    grok.order(1)
603    grok.context(IStudentStudyCourse)
604    grok.view(StudyCourseDisplayFormPage)
605    grok.require('waeup.handleStudent')
606    icon = 'actionicon_start.gif'
607    text = _('Start new session')
608    target = 'start_session'
609
610    @property
611    def target_url(self):
612        if self.context.next_session_allowed and self.context.is_current:
613            return self.view.url(self.view.context, self.target)
614        return False
615
616class AddStudyLevelActionButton(AddActionButton):
617    grok.order(1)
618    grok.context(IStudentStudyCourse)
619    grok.view(StudyCourseDisplayFormPage)
620    grok.require('waeup.handleStudent')
621    text = _('Add course list')
622    target = 'add'
623
624    @property
625    def target_url(self):
626        student = self.view.context.student
627        condition1 = student.state != PAID
628        condition2 = str(student['studycourse'].current_level) in \
629            self.view.context.keys()
630        condition3 = not self.context.is_current
631        if condition1 or condition2 or condition3:
632            return ''
633        return self.view.url(self.view.context, self.target)
634
635class StudyLevelEditActionButton(ManageActionButton):
636    grok.order(2)
637    grok.context(IStudentStudyLevel)
638    grok.view(StudyLevelDisplayFormPage)
639    grok.require('waeup.editStudyLevel')
640    text = _('Edit course list')
641    target = 'edit'
642
643    @property
644    def target_url(self):
645        student = self.view.context.student
646        condition1 = student.state == PAID
647        condition2 = self.view.context.is_current_level
648        is_current = self.context.__parent__.is_current
649        if condition1 and condition2 and is_current:
650            return self.view.url(self.view.context, self.target)
651        return ''
652
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')
666    grok.name('addpreviouspaymentactionbutton')
667    text = _('Add previous session payment ticket')
668    target = 'addpp'
669
670    @property
671    def target_url(self):
672        student = self.view.context.student
673        if student.before_payment or not self.target:
674            return ''
675        return self.view.url(self.view.context, self.target)
676
677class AddBalancePaymentActionButton(AddActionButton):
678    grok.order(3)
679    grok.context(IStudentPaymentsContainer)
680    grok.view(PaymentsManageFormPage)
681    grok.require('waeup.manageStudent')
682    grok.name('addbalancepaymentactionbutton')
683    text = _('Add balance payment ticket')
684    target = 'addbp'
685
686    @property
687    def target_url(self):
688        if not self.target:
689            return ''
690        return self.view.url(self.view.context, self.target)
691
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
707class ProcessTranscriptRequestActionButton(ManageActionButton):
708    grok.order(9)
709    grok.context(IStudent)
710    grok.view(StudentBaseDisplayFormPage)
711    grok.require('waeup.viewTranscript')
712    text = _('Manage transcript request')
713    target = 'process_transcript_request'
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
722class StudentsTab(PrimaryNavTab):
723    """Students tab in primary navigation.
724    """
725
726    grok.context(IKofaObject)
727    grok.order(4)
728    grok.require('waeup.viewStudentsTab')
729    grok.name('studentstab')
730
731    pnav = 4
732    tab_title = _(u'Students')
733
734    @property
735    def link_target(self):
736        return self.view.application_url('students')
737
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()
747    grok.viewletmanager(PrimaryStudentNavManager)
748    template = default_primary_nav_template
749    grok.order(1)
750    grok.require('waeup.Authenticated')
751    pnav = 0
752    tab_title = u'Some Text'
753
754    @property
755    def link_target(self):
756        return self.view.application_url()
757
758    @property
759    def active(self):
760        view_pnav = getattr(self.view, 'pnav', 0)
761        if view_pnav == self.pnav:
762            return 'active'
763        return ''
764
765class MyStudentDataTab(PrimaryStudentNavTab):
766    """MyData dropdown tab in primary navigation.
767    """
768    grok.order(3)
769    grok.require('waeup.viewMyStudentDataTab')
770    grok.template('mydatadropdowntabs')
771    pnav = 4
772    tab_title = _(u'My Data')
773
774    @property
775    def active(self):
776        view_pnav = getattr(self.view, 'pnav', 0)
777        if view_pnav == self.pnav:
778            return 'active dropdown'
779        return 'dropdown'
780
781    @property
782    def targets(self):
783        student = grok.getSite()['students'][self.request.principal.id]
784        student_url = self.view.url(student)
785        app_slip = getUtility(IExtFileStore).getFileByContext(
786            student, 'application_slip')
787        targets = []
788        if app_slip:
789            targets = [{'url':student_url + '/application_slip',
790                        'title':_('Application Slip')},]
791        targets += [
792            {'url':student_url, 'title':'Base Data'},
793            {'url':student_url + '/view_clearance',
794             'title':_('Clearance Data')},
795            {'url':student_url + '/view_personal', 'title':_('Personal Data')},
796            {'url':student_url + '/studycourse', 'title':_('Study Course')},
797            {'url':student_url + '/payments', 'title':_('Payments')},
798            {'url':student_url + '/accommodation',
799             'title':_('Accommodation Data')},
800            {'url':student_url + '/history', 'title':_('History')},
801            ]
802        return targets
803
804def handle_file_delete(context, view, download_name):
805    """Handle deletion of student file.
806
807    """
808    store = getUtility(IExtFileStore)
809    store.deleteFileByContext(context, attr=download_name)
810    context.writeLogMessage(view, 'deleted: %s' % download_name)
811    view.flash(_('${a} deleted.', mapping = {'a':download_name}))
812    return
813
814def handle_file_upload(upload, context, view, max_size, download_name=None):
815    """Handle upload of student file.
816
817    Returns `True` in case of success or `False`.
818
819    Please note that file pointer passed in (`upload`) most probably
820    points to end of file when leaving this function.
821    """
822    # Check some file requirements first
823    size = file_size(upload)
824    if size > max_size:
825        view.flash(_('Uploaded file is too big.'))
826        return False
827    upload.seek(0) # file pointer moved when determining size
828    file_format = get_fileformat(None, upload.read(512))
829    upload.seek(0) # same here
830    if file_format is None:
831        view.flash(_('Could not determine file type.'))
832        return False
833    basename, expected_ext = os.path.splitext(download_name)
834    if expected_ext:
835        if '.' + file_format != expected_ext:
836            view.flash(_('${a} file extension expected.',
837                mapping = {'a':expected_ext[1:]}))
838            return False
839    else:
840        if not file_format in ALLOWED_FILE_EXTENSIONS:
841            view.flash(
842                _('Only the following extensions are allowed: ${a}',
843                mapping = {'a':', '.join(ALLOWED_FILE_EXTENSIONS)}))
844            return False
845        download_name += '.' + file_format
846    store = getUtility(IExtFileStore)
847    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
848    store.createFile(file_id, upload)
849    context.writeLogMessage(view, 'uploaded: %s (%s)' % (
850        download_name,upload.filename))
851    view.flash(_('File ${a} uploaded.', mapping = {'a':download_name}))
852    return True
853
854class FileManager(grok.ViewletManager):
855    """Viewlet manager for uploading files, preferably scanned images.
856    """
857    grok.name('files')
858
859class FileDisplay(grok.Viewlet):
860    """Base file display viewlet.
861    """
862    grok.baseclass()
863    grok.context(IStudent)
864    grok.viewletmanager(FileManager)
865    grok.view(StudentClearanceDisplayFormPage)
866    template = default_filedisplay_template
867    grok.order(1)
868    grok.require('waeup.viewStudent')
869    label = _(u'File')
870    title = _(u'Scan')
871    download_name = u'filename.jpg'
872
873    @property
874    def file_exists(self):
875        image = getUtility(IExtFileStore).getFileByContext(
876            self.context, attr=self.download_name)
877        if image:
878            return True
879        else:
880            return False
881
882class FileUpload(FileDisplay):
883    """Base upload viewlet.
884    """
885    grok.baseclass()
886    grok.context(IStudent)
887    grok.viewletmanager(FileManager)
888    grok.view(StudentClearanceManageFormPage)
889    template = default_fileupload_template
890    grok.require('waeup.uploadStudentFile')
891    tab_redirect = '?tab2'
892    mus = 1024 * 150
893    upload_button =_('Upload new file')
894    delete_button = _('Delete attachment')
895
896    @property
897    def show_viewlet(self):
898        students_utils = getUtility(IStudentsUtils)
899        if self.__name__ in students_utils.SKIP_UPLOAD_VIEWLETS:
900            return False
901        return True
902
903    @property
904    def input_name(self):
905        return "%s" % self.__name__
906
907    def update(self):
908        self.max_upload_size = string_from_bytes(self.mus)
909        delete_button = self.request.form.get(
910            'delete_%s' % self.input_name, None)
911        upload_button = self.request.form.get(
912            'upload_%s' % self.input_name, None)
913        if delete_button:
914            handle_file_delete(
915                context=self.context, view=self.view,
916                download_name=self.download_name)
917            self.view.redirect(
918                self.view.url(
919                    self.context, self.view.__name__) + self.tab_redirect)
920            return
921        if upload_button:
922            upload = self.request.form.get(self.input_name, None)
923            if upload:
924                # We got a fresh upload
925                handle_file_upload(upload,
926                    self.context, self.view, self.mus, self.download_name)
927                self.view.redirect(
928                    self.view.url(
929                        self.context, self.view.__name__) + self.tab_redirect)
930            else:
931                self.view.flash(_('No local file selected.'))
932                self.view.redirect(
933                    self.view.url(
934                        self.context, self.view.__name__) + self.tab_redirect)
935        return
936
937class PassportDisplay(FileDisplay):
938    """Passport display viewlet.
939    """
940    grok.order(1)
941    grok.context(IStudent)
942    grok.view(StudentBaseDisplayFormPage)
943    grok.require('waeup.viewStudent')
944    grok.template('imagedisplay')
945    label = _(u'Passport Picture')
946    download_name = u'passport.jpg'
947
948class PassportUploadManage(FileUpload):
949    """Passport upload viewlet for officers.
950    """
951    grok.order(1)
952    grok.context(IStudent)
953    grok.view(StudentBaseManageFormPage)
954    grok.require('waeup.manageStudent')
955    grok.template('imageupload')
956    label = _(u'Passport Picture (jpg only)')
957    mus = 1024 * 50
958    download_name = u'passport.jpg'
959    tab_redirect = '?tab2'
960
961class PassportUploadEdit(PassportUploadManage):
962    """Passport upload viewlet for students.
963    """
964    grok.view(StudentFilesUploadPage)
965    grok.require('waeup.uploadStudentFile')
966
967class BirthCertificateDisplay(FileDisplay):
968    """Birth Certificate display viewlet.
969    """
970    grok.order(1)
971    label = _(u'Birth Certificate')
972    title = _(u'Birth Certificate Scan')
973    download_name = u'birth_certificate'
974
975class BirthCertificateSlip(BirthCertificateDisplay):
976    grok.view(ExportPDFClearanceSlipPage)
977
978class BirthCertificateUpload(FileUpload):
979    """Birth Certificate upload viewlet.
980    """
981    grok.order(1)
982    label = _(u'Birth Certificate')
983    title = _(u'Birth Certificate Scan')
984    mus = 1024 * 150
985    download_name = u'birth_certificate'
986    tab_redirect = '?tab2'
987
988class Image(grok.View):
989    """Renders images for students.
990    """
991    grok.baseclass()
992    grok.name('none.jpg')
993    grok.context(IStudent)
994    grok.require('waeup.viewStudent')
995    download_name = u'none.jpg'
996
997    def render(self):
998        # A filename chooser turns a context into a filename suitable
999        # for file storage.
1000        image = getUtility(IExtFileStore).getFileByContext(
1001            self.context, attr=self.download_name)
1002        if image is None:
1003            # show placeholder image
1004            self.response.setHeader('Content-Type', 'image/jpeg')
1005            return open(DEFAULT_IMAGE_PATH, 'rb').read()
1006        dummy,ext = os.path.splitext(image.name)
1007        if ext == '.jpg':
1008            self.response.setHeader('Content-Type', 'image/jpeg')
1009        elif ext == '.png':
1010            self.response.setHeader('Content-Type', 'image/png')
1011        elif ext == '.pdf':
1012            self.response.setHeader('Content-Type', 'application/pdf')
1013        elif ext == '.tif':
1014            self.response.setHeader('Content-Type', 'image/tiff')
1015        return image
1016
1017class Passport(Image):
1018    """Renders jpeg passport picture.
1019    """
1020    grok.name('passport.jpg')
1021    download_name = u'passport.jpg'
1022    grok.context(IStudent)
1023
1024class ApplicationSlipImage(Image):
1025    """Renders application slip scan.
1026    """
1027    grok.name('application_slip')
1028    download_name = u'application_slip'
1029
1030class BirthCertificateImage(Image):
1031    """Renders birth certificate scan.
1032    """
1033    grok.name('birth_certificate')
1034    download_name = u'birth_certificate'
Note: See TracBrowser for help on using the repository browser.