source: main/waeup.sirp/trunk/src/waeup/sirp/students/viewlets.py @ 7257

Last change on this file since 7257 was 7243, checked in by Henrik Bettermann, 13 years ago

Use only one primarynavtab.pt pagetemplate and render list item only if link_target is provided.

Provide link_target of EnquiriesTab? and ApplicantsAnonTab? only if principal id is zope.anybody.

  • Property svn:keywords set to Id
File size: 13.5 KB
Line 
1## $Id: viewlets.py 7243 2011-12-01 10:11:59Z 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 waeup.sirp.interfaces import (
23    IWAeUPObject, IExtFileStore, IFileStoreNameChooser)
24from waeup.sirp.utils.helpers import string_from_bytes, file_size
25from waeup.sirp.browser import DEFAULT_IMAGE_PATH
26from waeup.sirp.browser.viewlets import PrimaryNavTab
27from waeup.sirp.browser.layout import default_primary_nav_template
28from waeup.sirp.students.browser import (
29    StudentClearanceDisplayFormPage, StudentClearanceManageFormPage,
30    write_log_message, StudentBaseManageFormPage, StudentBaseDisplayFormPage,
31    StudentFilesUploadPage)
32from waeup.sirp.students.interfaces import IStudent, IStudentClearance
33
34grok.context(IWAeUPObject) # Make IWAeUPObject the default context
35grok.templatedir('browser_templates')
36
37ALLOWED_FILE_EXTENSIONS = ('jpg', 'png', 'pdf', 'tif')
38
39class StudentManageSidebar(grok.ViewletManager):
40    grok.name('left_studentmanage')
41
42class StudentManageLink(grok.Viewlet):
43    """A link displayed in the student box which shows up for StudentNavigation
44    objects.
45
46    """
47    grok.baseclass()
48    grok.viewletmanager(StudentManageSidebar)
49    grok.context(IWAeUPObject)
50    grok.view(Interface)
51    grok.order(5)
52    grok.require('waeup.viewStudent')
53
54    link = 'index'
55    text = u'Base Data'
56
57    def render(self):
58        url = self.view.url(self.context.getStudent(), self.link)
59        return u'<div class="portlet"><a href="%s">%s</a></div>' % (
60                url, self.text)
61
62class StudentManageBaseLink(StudentManageLink):
63    grok.order(1)
64    link = 'index'
65    text = u'Base Data'
66
67class StudentManageClearanceLink(StudentManageLink):
68    grok.order(2)
69    link = 'view_clearance'
70    text = u'Clearance Data'
71
72class StudentManagePersonalLink(StudentManageLink):
73    grok.order(2)
74    link = 'view_personal'
75    text = u'Personal Data'
76
77class StudentManageStudyCourseLink(StudentManageLink):
78    grok.order(3)
79    link = 'studycourse'
80    text = u'Study Course'
81
82class StudentManagePaymentsLink(StudentManageLink):
83    grok.order(4)
84    grok.require('waeup.payStudent')
85    link = 'payments'
86    text = u'Payments'
87
88class StudentManageAccommodationLink(StudentManageLink):
89    grok.order(5)
90    grok.require('waeup.handleAccommodation')
91    link = 'accommodation'
92    text = u'Accommodation Data'
93
94class StudentManageHistoryLink(StudentManageLink):
95    grok.order(6)
96    link = 'history'
97    text = u'History'
98
99
100class StudentMenu(grok.ViewletManager):
101    grok.name('top_student')
102
103class StudentLink(grok.Viewlet):
104    """A link displayed in the student box which shows up for StudentNavigation
105    objects.
106
107    """
108    grok.baseclass()
109    grok.viewletmanager(StudentMenu)
110    grok.context(IWAeUPObject)
111    grok.view(Interface)
112    grok.order(5)
113    grok.require('waeup.viewStudent')
114    template = grok.PageTemplateFile('browser_templates/plainactionbutton.pt')
115
116    link = 'index'
117    text = u'Base Data'
118
119    @property
120    def target_url(self):
121        """Get a URL to the target...
122        """
123        return self.view.url(self.context.getStudent(), self.link)
124
125class StudentBaseLink(StudentLink):
126    grok.order(1)
127    link = 'index'
128    text = u'Base Data'
129
130class StudentClearanceLink(StudentLink):
131    grok.order(2)
132    link = 'view_clearance'
133    text = u'Clearance Data'
134
135class StudentPersonalLink(StudentLink):
136    grok.order(2)
137    link = 'view_personal'
138    text = u'Personal Data'
139
140class StudentStudyCourseLink(StudentLink):
141    grok.order(3)
142    link = 'studycourse'
143    text = u'Study Course'
144
145class StudentPaymentsLink(StudentLink):
146    grok.order(4)
147    link = 'payments'
148    text = u'Payments'
149
150class StudentAccommodationLink(StudentLink):
151    grok.order(5)
152    link = 'accommodation'
153    text = u'Accommodation'
154
155class StudentHistoryLink(StudentLink):
156    grok.order(6)
157    link = 'history'
158    text = u'History'
159
160class StudentsTab(PrimaryNavTab):
161    """Students tab in primary navigation.
162    """
163
164    grok.context(IWAeUPObject)
165    grok.order(4)
166    grok.require('waeup.viewStudentsTab')
167
168    pnav = 4
169    tab_title = u'Students'
170
171    @property
172    def link_target(self):
173        return self.view.application_url('students')
174
175class PrimaryStudentNavManager(grok.ViewletManager):
176    """Viewlet manager for the primary navigation tab.
177    """
178    grok.name('primary_nav_student')
179
180class PrimaryStudentNavTab(grok.Viewlet):
181    """Base for primary student nav tabs.
182    """
183    grok.baseclass()
184    grok.viewletmanager(PrimaryStudentNavManager)
185    template = default_primary_nav_template
186    grok.order(1)
187    grok.require('waeup.Authenticated')
188    pnav = 0
189    tab_title = u'Some Text'
190
191    @property
192    def link_target(self):
193        return self.view.application_url()
194
195    @property
196    def active(self):
197        view_pnav = getattr(self.view, 'pnav', 0)
198        if view_pnav == self.pnav:
199            return 'active'
200        return ''
201
202class MyStudentDataTab(PrimaryStudentNavTab):
203    """MyData-tab in primary navigation.
204    """
205    grok.order(3)
206    grok.require('waeup.viewMyStudentDataTab')
207    pnav = 4
208    tab_title = u'My Data'
209
210    @property
211    def link_target(self):
212        rel_link = '/students/%s' % self.request.principal.id
213        return self.view.application_url() + rel_link
214
215def handle_file_delete(context, view, download_name):
216    """Handle deletion of student file.
217
218    """
219    store = getUtility(IExtFileStore)
220    store.deleteFileByContext(context, attr=download_name)
221    write_log_message(view, 'deleted: %s' % download_name)
222    view.flash('%s deleted.' % download_name)
223    return
224
225def handle_file_upload(upload, context, view, max_size, download_name=None):
226    """Handle upload of student file.
227
228    Returns `True` in case of success or `False`.
229
230    Please note that file pointer passed in (`upload`) most probably
231    points to end of file when leaving this function.
232    """
233    # Check some file requirements first
234    if upload.filename.count('.') == 0:
235        view.flash('File name has no extension.')
236        return False
237    if upload.filename.count('.') > 1:
238        view.flash('File name contains more than one dot.')
239        return False
240    basename, expected_ext = os.path.splitext(download_name)
241    dummy, ext = os.path.splitext(upload.filename)
242    ext.lower()
243    if expected_ext:
244        if ext != expected_ext:
245            view.flash('%s file extension expected.' %
246                expected_ext.replace('.',''))
247            return False
248    else:
249        if not ext.replace('.','') in ALLOWED_FILE_EXTENSIONS:
250            view.flash(
251                'Only the following extension are allowed: %s' %
252                ', '.join(ALLOWED_FILE_EXTENSIONS))
253            return False
254        download_name += ext
255    size = file_size(upload)
256    if size > max_size:
257        view.flash('Uploaded file is too big.')
258        return False
259    upload.seek(0) # file pointer moved when determining size
260    store = getUtility(IExtFileStore)
261    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
262    store.createFile(file_id, upload)
263    write_log_message(view, 'uploaded: %s (%s)' % (download_name,upload.filename))
264    view.flash('File %s uploaded.' % download_name)
265    return True
266
267class FileManager(grok.ViewletManager):
268    """Viewlet manager for uploading files, preferably scanned images.
269    """
270    grok.name('files')
271
272class FileDisplay(grok.Viewlet):
273    """Base file display viewlet.
274    """
275    grok.baseclass()
276    grok.context(IStudentClearance)
277    grok.viewletmanager(FileManager)
278    grok.view(StudentClearanceDisplayFormPage)
279    grok.template('filedisplay')
280    grok.order(1)
281    grok.require('waeup.viewStudent')
282    label = u'File:'
283    title = u'Scan'
284    download_name = u'filename.jpg'
285
286    @property
287    def file_exists(self):
288        image = getUtility(IExtFileStore).getFileByContext(
289            self.context, attr=self.download_name)
290        if image:
291            return True
292        else:
293            return False
294
295class FileUpload(FileDisplay):
296    """Base upload viewlet.
297    """
298    grok.baseclass()
299    grok.context(IStudentClearance)
300    grok.viewletmanager(FileManager)
301    grok.view(StudentClearanceManageFormPage)
302    grok.template('fileupload')
303    grok.require('waeup.uploadStudentFile')
304    tab_redirect = ''
305    mus = 1024 * 150
306
307    @property
308    def input_name(self):
309        return "%s" % self.__name__
310
311    def update(self):
312        self.max_upload_size = string_from_bytes(self.mus)
313        delete_button = self.request.form.get(
314            'delete_%s' % self.input_name, None)
315        upload_button = self.request.form.get(
316            'upload_%s' % self.input_name, None)
317        if delete_button:
318            handle_file_delete(
319                context=self.context, view=self.view,
320                download_name=self.download_name)
321            self.view.redirect(
322                self.view.url(
323                    self.context, self.view.__name__) + self.tab_redirect)
324            return
325        if upload_button:
326            upload = self.request.form.get(self.input_name, None)
327            if upload:
328                # We got a fresh upload
329                handle_file_upload(upload,
330                    self.context, self.view, self.mus, self.download_name)
331                self.view.redirect(
332                    self.view.url(
333                        self.context, self.view.__name__) + self.tab_redirect)
334            else:
335                self.view.flash('No local file selected.')
336                self.view.redirect(
337                    self.view.url(
338                        self.context, self.view.__name__) + self.tab_redirect)
339        return
340
341class PassportDisplay(FileDisplay):
342    """Passport display viewlet.
343    """
344    grok.order(1)
345    grok.context(IStudent)
346    grok.view(StudentBaseDisplayFormPage)
347    grok.require('waeup.viewStudent')
348    grok.template('imagedisplay')
349    label = u'Passport Picture:'
350    download_name = u'passport.jpg'
351
352class PassportUploadManage(FileUpload):
353    """Passport upload viewlet for officers.
354    """
355    grok.order(1)
356    grok.context(IStudent)
357    grok.view(StudentBaseManageFormPage)
358    grok.require('waeup.manageStudent')
359    grok.template('imageupload')
360    label = u'Passport Picture (jpg only):'
361    mus = 1024 * 50
362    download_name = u'passport.jpg'
363    tab_redirect = '#tab-2'
364
365class PassportUploadEdit(PassportUploadManage):
366    """Passport upload viewlet for students.
367    """
368    grok.view(StudentFilesUploadPage)
369    grok.require('waeup.uploadStudentFile')
370
371class BirthCertificateDisplay(FileDisplay):
372    """Birth Certificate display viewlet.
373    """
374    grok.order(1)
375    label = u'Birth Certificate:'
376    title = u'Birth Certificate Scan'
377    download_name = u'birth_certificate'
378
379class BirthCertificateUpload(FileUpload):
380    """Birth Certificate upload viewlet.
381    """
382    grok.order(1)
383    label = u'Birth Certificate:'
384    title = u'Birth Certificate Scan'
385    mus = 1024 * 150
386    download_name = u'birth_certificate'
387    tab_redirect = '#tab-2'
388
389class AcceptanceLetterDisplay(FileDisplay):
390    """Acceptance Letter display viewlet.
391    """
392    grok.order(1)
393    label = u'Acceptance Letter:'
394    title = u'Acceptance Letter Scan'
395    download_name = u'acceptance_letter'
396
397class AcceptanceLetterUpload(FileUpload):
398    """AcceptanceLetter upload viewlet.
399    """
400    grok.order(2)
401    label = u'Acceptance Letter:'
402    title = u'Acceptance Letter Scan'
403    mus = 1024 * 150
404    download_name = u'acceptance_letter'
405    tab_redirect = '#tab-2'
406
407class Image(grok.View):
408    """Renders jpeg images for students.
409    """
410    grok.baseclass()
411    grok.name('none.jpg')
412    grok.context(IStudentClearance)
413    grok.require('waeup.viewStudent')
414    download_name = u'none.jpg'
415
416    def render(self):
417        # A filename chooser turns a context into a filename suitable
418        # for file storage.
419        image = getUtility(IExtFileStore).getFileByContext(
420            self.context, attr=self.download_name)
421        if image is None:
422            # show placeholder image
423            self.response.setHeader('Content-Type', 'image/jpeg')
424            return open(DEFAULT_IMAGE_PATH, 'rb').read()
425        dummy,ext = os.path.splitext(image.name)
426        if ext == '.jpg':
427            self.response.setHeader('Content-Type', 'image/jpeg')
428        elif ext == '.png':
429            self.response.setHeader('Content-Type', 'image/png')
430        elif ext == '.pdf':
431            self.response.setHeader('Content-Type', 'application/pdf')
432        elif ext == '.tif':
433            self.response.setHeader('Content-Type', 'image/tiff')
434        return image
435
436class Passport(Image):
437    """Renders jpeg passport picture.
438    """
439    grok.name('passport.jpg')
440    download_name = u'passport.jpg'
441    grok.context(IStudent)
442
443class BirthCertificateImage(Image):
444    """Renders birth certificate jpeg scan.
445    """
446    grok.name('birth_certificate')
447    download_name = u'birth_certificate'
448
449class AcceptanceLetterImage(Image):
450    """Renders acceptance letter jpeg scan.
451    """
452    grok.name('acceptance_letter')
453    download_name = u'acceptance_letter'
Note: See TracBrowser for help on using the repository browser.