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

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

Include permission waeup.uploadStudentFile to handle file uploads.

Fix pagetemplate filesuploadpage.pt.

Rearrange fileupload.pt

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