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

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

Localize StudentManageApplicationLink? properly.

  • Property svn:keywords set to Id
File size: 32.8 KB
Line 
13## $Id: viewlets.py 10805 2013-11-28 16:50:50Z 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    text = _('Add previous session payment ticket')
667    target = 'addpp'
668
669    @property
670    def target_url(self):
671        student = self.view.context.student
672        if student.before_payment:
673            return ''
674        return self.view.url(self.view.context, self.target)
675
676class AddBalancePaymentActionButton(AddActionButton):
677    grok.order(3)
678    grok.context(IStudentPaymentsContainer)
679    grok.view(PaymentsManageFormPage)
680    grok.require('waeup.manageStudent')
681    text = _('Add balance payment ticket')
682    target = 'addbp'
683
684    @property
685    def target_url(self):
686        return self.view.url(self.view.context, self.target)
687
688class RequestTranscriptActionButton(ManageActionButton):
689    grok.order(8)
690    grok.context(IStudent)
691    grok.view(StudentBaseDisplayFormPage)
692    grok.require('waeup.handleStudent')
693    text = _('Request transcript')
694    target = 'request_transcript'
695    icon = 'actionicon_transcript.png'
696
697    @property
698    def target_url(self):
699        if self.context.state != GRADUATED:
700            return ''
701        return self.view.url(self.view.context, self.target)
702
703class ProcessTranscriptRequestActionButton(ManageActionButton):
704    grok.order(9)
705    grok.context(IStudent)
706    grok.view(StudentBaseDisplayFormPage)
707    grok.require('waeup.viewTranscript')
708    text = _('Manage transcript request')
709    target = 'process_transcript_request'
710    icon = 'actionicon_transcript.png'
711
712    @property
713    def target_url(self):
714        if self.context.state != TRANSCRIPT:
715            return ''
716        return self.view.url(self.view.context, self.target)
717
718class StudentsTab(PrimaryNavTab):
719    """Students tab in primary navigation.
720    """
721
722    grok.context(IKofaObject)
723    grok.order(4)
724    grok.require('waeup.viewStudentsTab')
725    grok.name('studentstab')
726
727    pnav = 4
728    tab_title = _(u'Students')
729
730    @property
731    def link_target(self):
732        return self.view.application_url('students')
733
734class PrimaryStudentNavManager(grok.ViewletManager):
735    """Viewlet manager for the primary navigation tab.
736    """
737    grok.name('primary_nav_student')
738
739class PrimaryStudentNavTab(grok.Viewlet):
740    """Base for primary student nav tabs.
741    """
742    grok.baseclass()
743    grok.viewletmanager(PrimaryStudentNavManager)
744    template = default_primary_nav_template
745    grok.order(1)
746    grok.require('waeup.Authenticated')
747    pnav = 0
748    tab_title = u'Some Text'
749
750    @property
751    def link_target(self):
752        return self.view.application_url()
753
754    @property
755    def active(self):
756        view_pnav = getattr(self.view, 'pnav', 0)
757        if view_pnav == self.pnav:
758            return 'active'
759        return ''
760
761class MyStudentDataTab(PrimaryStudentNavTab):
762    """MyData dropdown tab in primary navigation.
763    """
764    grok.order(3)
765    grok.require('waeup.viewMyStudentDataTab')
766    grok.template('mydatadropdowntabs')
767    pnav = 4
768    tab_title = _(u'My Data')
769
770    @property
771    def active(self):
772        view_pnav = getattr(self.view, 'pnav', 0)
773        if view_pnav == self.pnav:
774            return 'active dropdown'
775        return 'dropdown'
776
777    @property
778    def targets(self):
779        student = grok.getSite()['students'][self.request.principal.id]
780        student_url = self.view.url(student)
781        app_slip = getUtility(IExtFileStore).getFileByContext(
782            student, 'application_slip')
783        targets = []
784        if app_slip:
785            targets = [{'url':student_url + '/application_slip',
786                        'title':_('Application Slip')},]
787        targets += [
788            {'url':student_url, 'title':'Base Data'},
789            {'url':student_url + '/view_clearance',
790             'title':_('Clearance Data')},
791            {'url':student_url + '/view_personal', 'title':_('Personal Data')},
792            {'url':student_url + '/studycourse', 'title':_('Study Course')},
793            {'url':student_url + '/payments', 'title':_('Payments')},
794            {'url':student_url + '/accommodation',
795             'title':_('Accommodation Data')},
796            {'url':student_url + '/history', 'title':_('History')},
797            ]
798        return targets
799
800def handle_file_delete(context, view, download_name):
801    """Handle deletion of student file.
802
803    """
804    store = getUtility(IExtFileStore)
805    store.deleteFileByContext(context, attr=download_name)
806    context.writeLogMessage(view, 'deleted: %s' % download_name)
807    view.flash(_('${a} deleted.', mapping = {'a':download_name}))
808    return
809
810def handle_file_upload(upload, context, view, max_size, download_name=None):
811    """Handle upload of student file.
812
813    Returns `True` in case of success or `False`.
814
815    Please note that file pointer passed in (`upload`) most probably
816    points to end of file when leaving this function.
817    """
818    # Check some file requirements first
819    size = file_size(upload)
820    if size > max_size:
821        view.flash(_('Uploaded file is too big.'))
822        return False
823    upload.seek(0) # file pointer moved when determining size
824    file_format = get_fileformat(None, upload.read(512))
825    upload.seek(0) # same here
826    if file_format is None:
827        view.flash(_('Could not determine file type.'))
828        return False
829    basename, expected_ext = os.path.splitext(download_name)
830    if expected_ext:
831        if '.' + file_format != expected_ext:
832            view.flash(_('${a} file extension expected.',
833                mapping = {'a':expected_ext[1:]}))
834            return False
835    else:
836        if not file_format in ALLOWED_FILE_EXTENSIONS:
837            view.flash(
838                _('Only the following extensions are allowed: ${a}',
839                mapping = {'a':', '.join(ALLOWED_FILE_EXTENSIONS)}))
840            return False
841        download_name += '.' + file_format
842    store = getUtility(IExtFileStore)
843    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
844    store.createFile(file_id, upload)
845    context.writeLogMessage(view, 'uploaded: %s (%s)' % (
846        download_name,upload.filename))
847    view.flash(_('File ${a} uploaded.', mapping = {'a':download_name}))
848    return True
849
850class FileManager(grok.ViewletManager):
851    """Viewlet manager for uploading files, preferably scanned images.
852    """
853    grok.name('files')
854
855class FileDisplay(grok.Viewlet):
856    """Base file display viewlet.
857    """
858    grok.baseclass()
859    grok.context(IStudent)
860    grok.viewletmanager(FileManager)
861    grok.view(StudentClearanceDisplayFormPage)
862    template = default_filedisplay_template
863    grok.order(1)
864    grok.require('waeup.viewStudent')
865    label = _(u'File')
866    title = _(u'Scan')
867    download_name = u'filename.jpg'
868
869    @property
870    def file_exists(self):
871        image = getUtility(IExtFileStore).getFileByContext(
872            self.context, attr=self.download_name)
873        if image:
874            return True
875        else:
876            return False
877
878class FileUpload(FileDisplay):
879    """Base upload viewlet.
880    """
881    grok.baseclass()
882    grok.context(IStudent)
883    grok.viewletmanager(FileManager)
884    grok.view(StudentClearanceManageFormPage)
885    template = default_fileupload_template
886    grok.require('waeup.uploadStudentFile')
887    tab_redirect = '?tab2'
888    mus = 1024 * 150
889    upload_button =_('Upload new file')
890    delete_button = _('Delete attachment')
891
892    @property
893    def show_viewlet(self):
894        students_utils = getUtility(IStudentsUtils)
895        if self.__name__ in students_utils.SKIP_UPLOAD_VIEWLETS:
896            return False
897        return True
898
899    @property
900    def input_name(self):
901        return "%s" % self.__name__
902
903    def update(self):
904        self.max_upload_size = string_from_bytes(self.mus)
905        delete_button = self.request.form.get(
906            'delete_%s' % self.input_name, None)
907        upload_button = self.request.form.get(
908            'upload_%s' % self.input_name, None)
909        if delete_button:
910            handle_file_delete(
911                context=self.context, view=self.view,
912                download_name=self.download_name)
913            self.view.redirect(
914                self.view.url(
915                    self.context, self.view.__name__) + self.tab_redirect)
916            return
917        if upload_button:
918            upload = self.request.form.get(self.input_name, None)
919            if upload:
920                # We got a fresh upload
921                handle_file_upload(upload,
922                    self.context, self.view, self.mus, self.download_name)
923                self.view.redirect(
924                    self.view.url(
925                        self.context, self.view.__name__) + self.tab_redirect)
926            else:
927                self.view.flash(_('No local file selected.'))
928                self.view.redirect(
929                    self.view.url(
930                        self.context, self.view.__name__) + self.tab_redirect)
931        return
932
933class PassportDisplay(FileDisplay):
934    """Passport display viewlet.
935    """
936    grok.order(1)
937    grok.context(IStudent)
938    grok.view(StudentBaseDisplayFormPage)
939    grok.require('waeup.viewStudent')
940    grok.template('imagedisplay')
941    label = _(u'Passport Picture')
942    download_name = u'passport.jpg'
943
944class PassportUploadManage(FileUpload):
945    """Passport upload viewlet for officers.
946    """
947    grok.order(1)
948    grok.context(IStudent)
949    grok.view(StudentBaseManageFormPage)
950    grok.require('waeup.manageStudent')
951    grok.template('imageupload')
952    label = _(u'Passport Picture (jpg only)')
953    mus = 1024 * 50
954    download_name = u'passport.jpg'
955    tab_redirect = '?tab2'
956
957class PassportUploadEdit(PassportUploadManage):
958    """Passport upload viewlet for students.
959    """
960    grok.view(StudentFilesUploadPage)
961    grok.require('waeup.uploadStudentFile')
962
963class BirthCertificateDisplay(FileDisplay):
964    """Birth Certificate display viewlet.
965    """
966    grok.order(1)
967    label = _(u'Birth Certificate')
968    title = _(u'Birth Certificate Scan')
969    download_name = u'birth_certificate'
970
971class BirthCertificateSlip(BirthCertificateDisplay):
972    grok.view(ExportPDFClearanceSlipPage)
973
974class BirthCertificateUpload(FileUpload):
975    """Birth Certificate upload viewlet.
976    """
977    grok.order(1)
978    label = _(u'Birth Certificate')
979    title = _(u'Birth Certificate Scan')
980    mus = 1024 * 150
981    download_name = u'birth_certificate'
982    tab_redirect = '?tab2'
983
984class Image(grok.View):
985    """Renders images for students.
986    """
987    grok.baseclass()
988    grok.name('none.jpg')
989    grok.context(IStudent)
990    grok.require('waeup.viewStudent')
991    download_name = u'none.jpg'
992
993    def render(self):
994        # A filename chooser turns a context into a filename suitable
995        # for file storage.
996        image = getUtility(IExtFileStore).getFileByContext(
997            self.context, attr=self.download_name)
998        if image is None:
999            # show placeholder image
1000            self.response.setHeader('Content-Type', 'image/jpeg')
1001            return open(DEFAULT_IMAGE_PATH, 'rb').read()
1002        dummy,ext = os.path.splitext(image.name)
1003        if ext == '.jpg':
1004            self.response.setHeader('Content-Type', 'image/jpeg')
1005        elif ext == '.png':
1006            self.response.setHeader('Content-Type', 'image/png')
1007        elif ext == '.pdf':
1008            self.response.setHeader('Content-Type', 'application/pdf')
1009        elif ext == '.tif':
1010            self.response.setHeader('Content-Type', 'image/tiff')
1011        return image
1012
1013class Passport(Image):
1014    """Renders jpeg passport picture.
1015    """
1016    grok.name('passport.jpg')
1017    download_name = u'passport.jpg'
1018    grok.context(IStudent)
1019
1020class ApplicationSlipImage(Image):
1021    """Renders application slip scan.
1022    """
1023    grok.name('application_slip')
1024    download_name = u'application_slip'
1025
1026class BirthCertificateImage(Image):
1027    """Renders birth certificate scan.
1028    """
1029    grok.name('birth_certificate')
1030    download_name = u'birth_certificate'
Note: See TracBrowser for help on using the repository browser.