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

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

We need to customize some buttons for the EDP.

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