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

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

Backup work in progress.

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