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

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

StudentsOfficers? are not allowed to view the accommodation and payments containers of students. We therefore use the dedicated permissions waeup.handleAccommodation and waeup.payStudent.

Add role waeup.ACManager with permission waeup.manageACBatches which has already been uses in accesscodes.

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