source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/files.py @ 11986

Last change on this file since 11986 was 11985, checked in by Henrik Bettermann, 10 years ago

pep8

File size: 8.6 KB
Line 
1## $Id: viewlets.py 11772 2014-07-31 04:38:23Z henrik $
2##
3## Copyright (C) 2014 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##
18
19import os
20import grok
21from zope.component import getUtility
22from zope.interface import Interface
23from waeup.ikoba.interfaces import (
24    IIkobaObject, IExtFileStore, IFileStoreNameChooser)
25from waeup.ikoba.interfaces import MessageFactory as _
26from waeup.ikoba.browser import DEFAULT_IMAGE_PATH
27from waeup.ikoba.utils.helpers import (
28    string_from_bytes, file_size, get_fileformat)
29from waeup.ikoba.browser.layout import (
30    default_filedisplay_template,
31    default_fileupload_template)
32
33from waeup.ikoba.customers.interfaces import ICustomer, ICustomersUtils
34from waeup.ikoba.customers.browser import (
35    CustomerBaseDisplayFormPage, CustomerBaseManageFormPage,
36    CustomerFilesUploadPage)
37
38grok.context(IIkobaObject)  # Make IIkobaObject the default context
39grok.templatedir('browser_templates')
40
41
42def handle_file_delete(context, view, download_name):
43    """Handle deletion of customer file.
44
45    """
46    store = getUtility(IExtFileStore)
47    store.deleteFileByContext(context, attr=download_name)
48    context.writeLogMessage(view, 'deleted: %s' % download_name)
49    view.flash(_('${a} deleted.', mapping={'a': download_name}))
50    return
51
52
53def handle_file_upload(upload, context, view, max_size, download_name=None):
54    """Handle upload of customer file.
55
56    Returns `True` in case of success or `False`.
57
58    Please note that file pointer passed in (`upload`) most probably
59    points to end of file when leaving this function.
60    """
61    # Check some file requirements first
62    size = file_size(upload)
63    if size > max_size:
64        view.flash(_('Uploaded file is too big.'), type="danger")
65        return False
66    upload.seek(0)  # file pointer moved when determining size
67    dummy,ext = os.path.splitext(upload.filename)
68    # fpm files are expected to be fingerprint minutiae, file
69    # format is not yet checked
70    if ext == '.fpm':
71        file_format = 'fpm'
72    else:
73        file_format = get_fileformat(None, upload.read(512))
74        upload.seek(0)  # same here
75    if file_format is None:
76        view.flash(_('Could not determine file type.'), type="danger")
77        return False
78    basename, expected_ext = os.path.splitext(download_name)
79    if expected_ext:
80        if '.' + file_format != expected_ext:
81            view.flash(_('${a} file extension expected.',
82                mapping={'a': expected_ext[1:]}), type="danger")
83            return False
84    else:
85        if not file_format in ALLOWED_FILE_EXTENSIONS:
86            view.flash(
87                _('Only the following extensions are allowed: ${a}',
88                mapping={'a': ', '.join(ALLOWED_FILE_EXTENSIONS)}),
89                type="danger")
90            return False
91        download_name += '.' + file_format
92    store = getUtility(IExtFileStore)
93    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
94    store.createFile(file_id, upload)
95    context.writeLogMessage(view, 'uploaded: %s (%s)' % (
96        download_name,upload.filename))
97    view.flash(_('File ${a} uploaded.', mapping={'a': download_name}))
98    return True
99
100
101class FileManager(grok.ViewletManager):
102    """Viewlet manager for uploading files, preferably scanned images.
103    """
104    grok.name('files')
105
106
107class FileDisplay(grok.Viewlet):
108    """Base file display viewlet.
109    """
110    grok.baseclass()
111    grok.context(ICustomer)
112    grok.viewletmanager(FileManager)
113    grok.view(CustomerBaseDisplayFormPage)
114    template = default_filedisplay_template
115    grok.order(1)
116    grok.require('waeup.viewCustomer')
117    label = _(u'File')
118    title = _(u'Scan')
119    download_name = u'filename.jpg'
120
121    @property
122    def file_exists(self):
123        image = getUtility(IExtFileStore).getFileByContext(
124            self.context, attr=self.download_name)
125        if image:
126            return True
127        else:
128            return False
129
130
131class FileUpload(FileDisplay):
132    """Base upload viewlet.
133    """
134    grok.baseclass()
135    grok.context(ICustomer)
136    grok.viewletmanager(FileManager)
137    grok.view(CustomerBaseManageFormPage)
138    template = default_fileupload_template
139    grok.require('waeup.uploadCustomerFile')
140    tab_redirect = '#tab2-top'
141    mus = 1024 * 150
142    upload_button =_('Upload selected file')
143    delete_button = _('Delete')
144
145    @property
146    def show_viewlet(self):
147        customers_utils = getUtility(ICustomersUtils)
148        if self.__name__ in customers_utils.SKIP_UPLOAD_VIEWLETS:
149            return False
150        return True
151
152    @property
153    def input_name(self):
154        return "%s" % self.__name__
155
156    def update(self):
157        self.max_upload_size = string_from_bytes(self.mus)
158        delete_button = self.request.form.get(
159            'delete_%s' % self.input_name, None)
160        upload_button = self.request.form.get(
161            'upload_%s' % self.input_name, None)
162        if delete_button:
163            handle_file_delete(
164                context=self.context, view=self.view,
165                download_name=self.download_name)
166            self.view.redirect(
167                self.view.url(
168                    self.context, self.view.__name__) + self.tab_redirect)
169            return
170        if upload_button:
171            upload = self.request.form.get(self.input_name, None)
172            if upload:
173                # We got a fresh upload
174                handle_file_upload(upload,
175                    self.context, self.view, self.mus, self.download_name)
176                self.view.redirect(
177                    self.view.url(
178                        self.context, self.view.__name__) + self.tab_redirect)
179            else:
180                self.view.flash(_('No local file selected.'), type="danger")
181                self.view.redirect(
182                    self.view.url(
183                        self.context, self.view.__name__) + self.tab_redirect)
184        return
185
186
187class PassportDisplay(FileDisplay):
188    """Passport display viewlet.
189    """
190    grok.order(1)
191    grok.context(ICustomer)
192    grok.require('waeup.viewCustomer')
193    grok.template('imagedisplay')
194    label = _(u'Passport Picture')
195    download_name = u'passport.jpg'
196
197
198class PassportUploadManage(FileUpload):
199    """Passport upload viewlet for officers.
200    """
201    grok.order(1)
202    grok.context(ICustomer)
203    grok.require('waeup.manageCustomer')
204    grok.template('imageupload')
205    label = _(u'Passport Picture (jpg only)')
206    mus = 1024 * 50
207    download_name = u'passport.jpg'
208    tab_redirect = '#tab2'
209
210
211class PassportUploadEdit(PassportUploadManage):
212    """Passport upload viewlet for customers.
213    """
214    grok.view(CustomerFilesUploadPage)
215    grok.require('waeup.uploadCustomerFile')
216
217
218class Image(grok.View):
219    """Renders images for customers.
220    """
221    grok.baseclass()
222    grok.name('none.jpg')
223    grok.context(ICustomer)
224    grok.require('waeup.viewCustomer')
225    download_name = u'none.jpg'
226
227    def render(self):
228        # A filename chooser turns a context into a filename suitable
229        # for file storage.
230        image = getUtility(IExtFileStore).getFileByContext(
231            self.context, attr=self.download_name)
232        if image is None:
233            # show placeholder image
234            self.response.setHeader('Content-Type', 'image/jpeg')
235            return open(DEFAULT_IMAGE_PATH, 'rb').read()
236        dummy,ext = os.path.splitext(image.name)
237        if ext == '.jpg':
238            self.response.setHeader('Content-Type', 'image/jpeg')
239        elif ext == '.fpm':
240            self.response.setHeader('Content-Type', 'application/binary')
241        elif ext == '.png':
242            self.response.setHeader('Content-Type', 'image/png')
243        elif ext == '.pdf':
244            self.response.setHeader('Content-Type', 'application/pdf')
245        elif ext == '.tif':
246            self.response.setHeader('Content-Type', 'image/tiff')
247        return image
248
249
250class Passport(Image):
251    """Renders jpeg passport picture.
252    """
253    grok.name('passport.jpg')
254    download_name = u'passport.jpg'
255    grok.context(ICustomer)
Note: See TracBrowser for help on using the repository browser.