source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/fileviewlets.py @ 12193

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

Add PDFDocumentSlipPage and related components.

  • Property svn:keywords set to Id
File size: 10.9 KB
RevLine 
[12035]1## $Id: fileviewlets.py 12062 2014-11-26 13:03:56Z henrik $
[11971]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
[11972]27from waeup.ikoba.utils.helpers import (
28    string_from_bytes, file_size, get_fileformat)
[11971]29from waeup.ikoba.browser.layout import (
30    default_filedisplay_template,
31    default_fileupload_template)
32
[12035]33from waeup.ikoba.customers.interfaces import (
[12057]34    ICustomer, ICustomersUtils)
35
36from waeup.ikoba.customers.documents import (
37    CustomerSampleDocument, CustomerPDFDocument
38    )
[11971]39from waeup.ikoba.customers.browser import (
40    CustomerBaseDisplayFormPage, CustomerBaseManageFormPage,
[12035]41    CustomerFilesUploadPage,
[12050]42    DocumentDisplayFormPage, DocumentManageFormPage, DocumentEditFormPage,
[12062]43    PDFDocumentSlipPage,)
[11971]44
[11985]45grok.context(IIkobaObject)  # Make IIkobaObject the default context
[11971]46grok.templatedir('browser_templates')
47
[11987]48ALLOWED_FILE_EXTENSIONS = ('jpg', 'png', 'pdf', 'tif', 'fpm')
[11985]49
[11987]50
[11971]51def handle_file_delete(context, view, download_name):
52    """Handle deletion of customer file.
53
54    """
55    store = getUtility(IExtFileStore)
56    store.deleteFileByContext(context, attr=download_name)
57    context.writeLogMessage(view, 'deleted: %s' % download_name)
[11985]58    view.flash(_('${a} deleted.', mapping={'a': download_name}))
[11971]59    return
60
[11985]61
[11971]62def handle_file_upload(upload, context, view, max_size, download_name=None):
63    """Handle upload of customer file.
64
65    Returns `True` in case of success or `False`.
66
67    Please note that file pointer passed in (`upload`) most probably
68    points to end of file when leaving this function.
69    """
70    # Check some file requirements first
71    size = file_size(upload)
72    if size > max_size:
73        view.flash(_('Uploaded file is too big.'), type="danger")
74        return False
[11985]75    upload.seek(0)  # file pointer moved when determining size
[11971]76    dummy,ext = os.path.splitext(upload.filename)
77    # fpm files are expected to be fingerprint minutiae, file
78    # format is not yet checked
79    if ext == '.fpm':
80        file_format = 'fpm'
81    else:
82        file_format = get_fileformat(None, upload.read(512))
[11985]83        upload.seek(0)  # same here
[11971]84    if file_format is None:
85        view.flash(_('Could not determine file type.'), type="danger")
86        return False
87    basename, expected_ext = os.path.splitext(download_name)
88    if expected_ext:
89        if '.' + file_format != expected_ext:
90            view.flash(_('${a} file extension expected.',
[11985]91                mapping={'a': expected_ext[1:]}), type="danger")
[11971]92            return False
93    else:
94        if not file_format in ALLOWED_FILE_EXTENSIONS:
95            view.flash(
96                _('Only the following extensions are allowed: ${a}',
[11985]97                mapping={'a': ', '.join(ALLOWED_FILE_EXTENSIONS)}),
[11971]98                type="danger")
99            return False
100        download_name += '.' + file_format
101    store = getUtility(IExtFileStore)
102    file_id = IFileStoreNameChooser(context).chooseName(attr=download_name)
103    store.createFile(file_id, upload)
104    context.writeLogMessage(view, 'uploaded: %s (%s)' % (
105        download_name,upload.filename))
[11985]106    view.flash(_('File ${a} uploaded.', mapping={'a': download_name}))
[11971]107    return True
108
[11985]109
[11971]110class FileManager(grok.ViewletManager):
111    """Viewlet manager for uploading files, preferably scanned images.
112    """
113    grok.name('files')
114
[11985]115
[11971]116class FileDisplay(grok.Viewlet):
117    """Base file display viewlet.
118    """
119    grok.baseclass()
120    grok.viewletmanager(FileManager)
121    template = default_filedisplay_template
122    grok.order(1)
123    label = _(u'File')
124    title = _(u'Scan')
125    download_name = u'filename.jpg'
126
127    @property
128    def file_exists(self):
129        image = getUtility(IExtFileStore).getFileByContext(
130            self.context, attr=self.download_name)
131        if image:
132            return True
133        else:
134            return False
135
[11985]136
[11971]137class FileUpload(FileDisplay):
138    """Base upload viewlet.
139    """
140    grok.baseclass()
141    grok.viewletmanager(FileManager)
142    template = default_fileupload_template
143    tab_redirect = '#tab2-top'
144    mus = 1024 * 150
145    upload_button =_('Upload selected file')
146    delete_button = _('Delete')
147
148    @property
149    def show_viewlet(self):
150        customers_utils = getUtility(ICustomersUtils)
151        if self.__name__ in customers_utils.SKIP_UPLOAD_VIEWLETS:
152            return False
153        return True
154
155    @property
156    def input_name(self):
157        return "%s" % self.__name__
158
159    def update(self):
160        self.max_upload_size = string_from_bytes(self.mus)
161        delete_button = self.request.form.get(
162            'delete_%s' % self.input_name, None)
163        upload_button = self.request.form.get(
164            'upload_%s' % self.input_name, None)
165        if delete_button:
166            handle_file_delete(
167                context=self.context, view=self.view,
168                download_name=self.download_name)
169            self.view.redirect(
170                self.view.url(
171                    self.context, self.view.__name__) + self.tab_redirect)
172            return
173        if upload_button:
174            upload = self.request.form.get(self.input_name, None)
175            if upload:
176                # We got a fresh upload
177                handle_file_upload(upload,
178                    self.context, self.view, self.mus, self.download_name)
179                self.view.redirect(
180                    self.view.url(
181                        self.context, self.view.__name__) + self.tab_redirect)
182            else:
183                self.view.flash(_('No local file selected.'), type="danger")
184                self.view.redirect(
185                    self.view.url(
186                        self.context, self.view.__name__) + self.tab_redirect)
187        return
188
[11985]189
[11988]190class Image(grok.View):
191    """Renders images for customers.
192    """
193    grok.baseclass()
194    grok.name('none.jpg')
195    download_name = u'none.jpg'
196
197    def render(self):
198        # A filename chooser turns a context into a filename suitable
199        # for file storage.
200        image = getUtility(IExtFileStore).getFileByContext(
201            self.context, attr=self.download_name)
202        if image is None:
203            # show placeholder image
204            self.response.setHeader('Content-Type', 'image/jpeg')
205            return open(DEFAULT_IMAGE_PATH, 'rb').read()
206        dummy,ext = os.path.splitext(image.name)
207        if ext == '.jpg':
208            self.response.setHeader('Content-Type', 'image/jpeg')
209        elif ext == '.fpm':
210            self.response.setHeader('Content-Type', 'application/binary')
211        elif ext == '.png':
212            self.response.setHeader('Content-Type', 'image/png')
213        elif ext == '.pdf':
214            self.response.setHeader('Content-Type', 'application/pdf')
215        elif ext == '.tif':
216            self.response.setHeader('Content-Type', 'image/tiff')
217        return image
218
219# File viewlets for customer base page
220
[11971]221class PassportDisplay(FileDisplay):
222    """Passport display viewlet.
223    """
224    grok.order(1)
225    grok.context(ICustomer)
[11987]226    grok.view(CustomerBaseDisplayFormPage)
[11971]227    grok.require('waeup.viewCustomer')
228    grok.template('imagedisplay')
229    label = _(u'Passport Picture')
230    download_name = u'passport.jpg'
231
[11985]232
[12038]233class PassportManageUpload(FileUpload):
[11971]234    """Passport upload viewlet for officers.
235    """
236    grok.order(1)
237    grok.context(ICustomer)
[11987]238    grok.view(CustomerBaseManageFormPage)
[11971]239    grok.require('waeup.manageCustomer')
240    grok.template('imageupload')
241    label = _(u'Passport Picture (jpg only)')
242    mus = 1024 * 50
243    download_name = u'passport.jpg'
244    tab_redirect = '#tab2'
245
[11985]246
[12038]247class PassportEditUpload(PassportManageUpload):
[11971]248    """Passport upload viewlet for customers.
249    """
250    grok.view(CustomerFilesUploadPage)
251    grok.require('waeup.uploadCustomerFile')
252
[11985]253
[11971]254class Passport(Image):
255    """Renders jpeg passport picture.
256    """
257    grok.name('passport.jpg')
258    download_name = u'passport.jpg'
259    grok.context(ICustomer)
[11988]260    grok.require('waeup.viewCustomer')
261
262# File viewlets for customer documents
[12035]263
[12062]264class SampleScanManageUpload(FileUpload):
[12038]265    """Scan upload viewlet for officers.
[12035]266    """
267    grok.order(1)
[12057]268    grok.context(CustomerSampleDocument)
[12035]269    grok.view(DocumentManageFormPage)
270    grok.require('waeup.manageCustomer')
[12057]271    label = _(u'Sample Scan')
272    title = _(u'Sample Scan')
[12035]273    mus = 1024 * 50
[12057]274    download_name = u'sample'
[12035]275    tab_redirect = '#tab2'
276
[12036]277
[12062]278class SampleScanEditUpload(SampleScanManageUpload):
[12038]279    """Scan upload viewlet for customer.
[12036]280    """
281    grok.view(DocumentEditFormPage)
282    grok.require('waeup.handleCustomer')
283
284
[12062]285class SampleScanDisplay(FileDisplay):
[12038]286    """Scan display viewlet.
[12035]287    """
288    grok.order(1)
[12057]289    grok.context(CustomerSampleDocument)
[12035]290    grok.require('waeup.viewCustomer')
291    grok.view(DocumentDisplayFormPage)
[12057]292    label = _(u'Sample Scan')
293    title = _(u'Sample Scan')
294    download_name = u'sample'
[12035]295
[12036]296
[12057]297class SampleScanImage(Image):
[12038]298    """Scan document.
[12035]299    """
[12057]300    grok.name('sample')
301    grok.context(CustomerSampleDocument)
[12035]302    grok.require('waeup.viewCustomer')
[12057]303    download_name = u'sample'
304
[12062]305class SampleScanPDFSlip(SampleScanDisplay):
306    grok.view(PDFDocumentSlipPage)
[12057]307
[12062]308
309class PDFScanManageUpload(FileUpload):
[12057]310    """Scan upload viewlet for officers.
311    """
312    grok.view(DocumentManageFormPage)
313    grok.context(CustomerPDFDocument)
314    grok.require('waeup.manageCustomer')
315    label = _(u'PDF File')
316    title = _(u'PDF File')
317    mus = 1024 * 200
[12058]318    download_name = u'sample.pdf'
[12057]319    tab_redirect = '#tab2'
320
321
[12062]322class PDFScanEditUpload(PDFScanManageUpload):
[12057]323    """Scan upload viewlet for customer.
324    """
325    grok.view(DocumentEditFormPage)
326    grok.require('waeup.handleCustomer')
327
328
[12062]329class PDFScanDisplay(FileDisplay):
[12057]330    """Scan display viewlet.
331    """
332    grok.order(1)
333    grok.context(CustomerPDFDocument)
334    grok.require('waeup.viewCustomer')
335    grok.view(DocumentDisplayFormPage)
336    label = _(u'PDF Scan')
337    title = _(u'PDF Scan')
[12058]338    download_name = u'sample.pdf'
[12057]339
340
341class PDFScanImage(Image):
342    """Scan document.
343    """
[12058]344    grok.name('sample.pdf')
[12057]345    grok.context(CustomerPDFDocument)
346    grok.require('waeup.viewCustomer')
[12058]347    download_name = u'sample.pdf'
[12062]348
349class PDFScanSlip(PDFScanDisplay):
350    grok.view(PDFDocumentSlipPage)
Note: See TracBrowser for help on using the repository browser.