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

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

For customization we need to name the tab viewlets.

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