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

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

Reorganize file upload. Each viewlet gets an upload and a delete button and writes its own log message. Thus there is one line per file deletion or file upload in the log file. The save action does no longer upload the files.

It works perfectly in the UI but I have still some problems with the browser test.

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