コード例 #1
0
class NamedBlobFile(Persistent):
    """A file stored in a ZODB BLOB, with a filename"""

    filename = FieldProperty(INamedFile['filename'])

    def __init__(self, data='', contentType='', filename=None):
        if (
            filename is not None and
            contentType in ('', 'application/octet-stream')
        ):
            contentType = get_contenttype(filename=filename)
        self.contentType = contentType
        self._blob = Blob()
        f = self._blob.open('w')
        f.write('')
        f.close()
        self._setData(data)
        self.filename = filename

    def open(self, mode='r'):
        if mode != 'r' and 'size' in self.__dict__:
            del self.__dict__['size']
        return self._blob.open(mode)

    def openDetached(self):
        return open(self._blob.committed(), 'rb')

    def _setData(self, data):
        if 'size' in self.__dict__:
            del self.__dict__['size']
        # Search for a storable that is able to store the data
        dottedName = '.'.join((data.__class__.__module__,
                               data.__class__.__name__))
        log.debug('Storage selected for data: %s', dottedName)
        storable = getUtility(IStorage, name=dottedName)
        storable.store(data, self._blob)

    def _getData(self):
        fp = self._blob.open('r')
        data = fp.read()
        fp.close()
        return data

    _data = property(_getData, _setData)
    data = property(_getData, _setData)

    @property
    def size(self):
        if 'size' in self.__dict__:
            return self.__dict__['size']
        reader = self._blob.open()
        reader.seek(0, 2)
        size = int(reader.tell())
        reader.close()
        self.__dict__['size'] = size
        return size

    def getSize(self):
        return self.size
コード例 #2
0
ファイル: file.py プロジェクト: Thokas/plone.namedfile
class NamedBlobFile(Persistent):
    """A file stored in a ZODB BLOB, with a filename"""

    filename = FieldProperty(INamedFile['filename'])

    def __init__(self, data=b'', contentType='', filename=None):
        if (
            filename is not None and
            contentType in ('', 'application/octet-stream')
        ):
            contentType = get_contenttype(filename=filename)
        self.contentType = contentType
        self._blob = Blob()
        f = self._blob.open('w')
        f.write(b'')
        f.close()
        self._setData(data)
        self.filename = filename

    def open(self, mode='r'):
        if mode != 'r' and 'size' in self.__dict__:
            del self.__dict__['size']
        return self._blob.open(mode)

    def openDetached(self):
        return open(self._blob.committed(), 'rb')

    def _setData(self, data):
        if 'size' in self.__dict__:
            del self.__dict__['size']
        # Search for a storable that is able to store the data
        dottedName = '.'.join((data.__class__.__module__,
                               data.__class__.__name__))
        log.debug('Storage selected for data: %s', dottedName)
        storable = getUtility(IStorage, name=dottedName)
        storable.store(data, self._blob)

    def _getData(self):
        fp = self._blob.open('r')
        data = fp.read()
        fp.close()
        return data

    _data = property(_getData, _setData)
    data = property(_getData, _setData)

    @property
    def size(self):
        if 'size' in self.__dict__:
            return self.__dict__['size']
        with self._blob.open() as reader:
            reader.seek(0, 2)
            size = int(reader.tell())
        self.__dict__['size'] = size
        return size

    def getSize(self):
        return self.size
コード例 #3
0
ファイル: file.py プロジェクト: pigaov10/plone4.3
class NamedBlobFile(Persistent):
    """A file stored in a ZODB BLOB, with a filename"""

    implements(INamedBlobFile)

    filename = FieldProperty(INamedFile["filename"])

    def __init__(self, data="", contentType="", filename=None):
        if filename is not None and contentType in ("", "application/octet-stream"):
            contentType = get_contenttype(filename=filename)
        self.contentType = contentType
        self._blob = Blob()
        f = self._blob.open("w")
        f.write("")
        f.close()
        self._setData(data)
        self.filename = filename

    def open(self, mode="r"):
        if mode != "r" and "size" in self.__dict__:
            del self.__dict__["size"]
        return self._blob.open(mode)

    def openDetached(self):
        return open(self._blob.committed(), "rb")

    def _setData(self, data):
        if "size" in self.__dict__:
            del self.__dict__["size"]
        # Search for a storable that is able to store the data
        dottedName = ".".join((data.__class__.__module__, data.__class__.__name__))
        storable = getUtility(IStorage, name=dottedName)
        storable.store(data, self._blob)

    def _getData(self):
        fp = self._blob.open("r")
        data = fp.read()
        fp.close()
        return data

    _data = property(_getData, _setData)
    data = property(_getData, _setData)

    @property
    def size(self):
        if "size" in self.__dict__:
            return self.__dict__["size"]
        reader = self._blob.open()
        reader.seek(0, 2)
        size = int(reader.tell())
        reader.close()
        self.__dict__["size"] = size
        return size

    def getSize(self):
        return self.size
コード例 #4
0
class File(Persistent):
    """A persistent content component storing binary file data."""

    implements(zope.app.publication.interfaces.IFileContent,
               interfaces.IBlobFile)

    def __init__(self, data='', contentType=''):
        self.contentType = contentType
        self._blob = Blob()
        f = self._blob.open('w')
        f.write('')
        f.close()
        self._setData(data)

    def open(self, mode='r'):
        if mode != 'r' and 'size' in self.__dict__:
            del self.__dict__['size']
        return self._blob.open(mode)

    def openDetached(self):
        return open(self._blob.committed(), 'rb')

    def _setData(self, data):
        if 'size' in self.__dict__:
            del self.__dict__['size']
        # Search for a storable that is able to store the data
        dottedName = ".".join((data.__class__.__module__,
                               data.__class__.__name__))
        storable = zope.component.getUtility(interfaces.IStorage,
                                             name=dottedName)
        storable.store(data, self._blob)

    def _getData(self):
        fp = self._blob.open('r')
        data = fp.read()
        fp.close()
        return data

    _data = property(_getData, _setData)
    data = property(_getData, _setData)

    @property
    def size(self):
        if 'size' in self.__dict__:
            return self.__dict__['size']
        reader = self._blob.open()
        reader.seek(0,2)
        size = int(reader.tell())
        reader.close()
        self.__dict__['size'] = size
        return size

    def getSize(self):
        return self.size
コード例 #5
0
    def test_committed_when_uncommitted(self):
        # An exception is raised if we call committed on a blob that has
        # uncommitted changes:
        blob = Blob()
        with self.assertRaisesRegex(BlobError, "Uncommitted changes"):
            blob.committed()

        with self.assertRaisesRegex(BlobError, "Uncommitted changes"):
            blob.open('c')

        blob = self._make_blob()
        conn = self.database.open()
        root = conn.root()
        root['blob'] = blob
        with self.assertRaisesRegex(BlobError, "Uncommitted changes"):
            blob.committed()

        with self.assertRaisesRegex(BlobError, "Uncommitted changes"):
            blob.open('c')

        transaction.savepoint()
        with self.assertRaisesRegex(BlobError, "Uncommitted changes"):
            blob.committed()
        with self.assertRaisesRegex(BlobError, "Uncommitted changes"):
            blob.open('c')

        transaction.commit()
        self._check_blob_contents(blob, self.DATA1, 'c')
コード例 #6
0
ファイル: __init__.py プロジェクト: domenkozar/substanced
class File(Persistent):

    title = _BLANK

    name = renamer()

    def __init__(self, stream=None, mimetype=None, title=_BLANK):
        """ The constructor of a File object.

        ``stream`` should be a filelike object (an object with a ``read``
        method that takes a size argument) or ``None``.  If stream is
        ``None``, the blob attached to this file object is created empty.

        ``title`` must be a string or Unicode object.

        ``mimetype`` may be any of the following:

        - ``None``, meaning set this file object's mimetype to
          ``application/octet-stream`` (the default).

        - A mimetype string (e.g. ``image/gif``)

        - The constant :attr:`substanced.file.USE_MAGIC`, which will
          derive the mimetype from the stream content (if ``stream`` is also
          supplied) using the ``python-magic`` library.

          .. warning::

             On non-Linux systems, successful use of
             :attr:`substanced.file.USE_MAGIC` requires the installation
             of additional dependencies.  See :ref:`optional_dependencies`.
        """
        self.blob = Blob()
        self.title = title or _BLANK

        # mimetype will be overridden by upload if there's a stream
        if mimetype is USE_MAGIC:
            self.mimetype = "application/octet-stream"
        else:
            self.mimetype = mimetype or "application/octet-stream"

        if stream is not None:
            if mimetype is USE_MAGIC:
                hint = USE_MAGIC
            else:
                hint = None
            self.upload(stream, mimetype_hint=hint)

    def upload(self, stream, mimetype_hint=None):
        """ Replace the current contents of this file's blob with the
        contents of ``stream``.  ``stream`` must be a filelike object (it
        must have a ``read`` method that takes a size argument).

        ``mimetype_hint`` can be any of the following:

        - ``None``, meaning don't reset the current mimetype.  This is the
          default.  If you already know the file's mimetype, and you don't
          want it divined from a filename or stream content, use ``None`` as
          the ``mimetype_hint`` value, and set the ``mimetype`` attribute of
          the file object directly before or after calling this method.

        - A string containing a filename that has an extension; the mimetype
          will be derived from the extension in the filename using the Python
          ``mimetypes`` module, and the result will be set as the mimetype
          attribute of this object.

        - The constant :attr:`pyramid.file.USE_MAGIC`, which will derive
          the mimetype using the ``python-magic`` library based on the
          stream's actual content.  The result will be set as the mimetype
          attribute of this object.

          .. warning::

             On non-Linux systems, successful use of
             :attr:`substanced.file.USE_MAGIC` requires the installation
             of additional dependencies.  See :ref:`optional_dependencies`.
          
        """
        if not stream:
            stream = io.StringIO()
        fp = self.blob.open("w")
        first = True
        use_magic = False
        if mimetype_hint is USE_MAGIC:
            use_magic = True
            if magic is None:  # pragma: no cover
                warnings.warn(
                    "The python-magic library does not have its requisite "
                    "dependencies installed properly, therefore the "
                    '"USE_MAGIC" flag passed to this method has been ignored '
                    '(it has been converted to "None").  The mimetype of '
                    "substanced.file.File objects created may be incorrect as "
                    "a result."
                )
                use_magic = False
                mimetype_hint = None

        if not use_magic:
            if mimetype_hint is not None:
                mimetype, _ = mimetypes.guess_type(mimetype_hint, strict=False)
                if mimetype is None:
                    mimetype = "application/octet-stream"
                self.mimetype = mimetype
        for chunk in chunks(stream):
            if use_magic and first:
                first = False
                m = magic.Magic(mime=True)
                mimetype = m.from_buffer(chunk)
                self.mimetype = u(mimetype)
            fp.write(chunk)
        fp.close()

    def get_response(self, **kw):
        """ Return a WebOb-compatible response object which uses the blob
        content as the stream data and the mimetype of the file as the
        content type.  The ``**kw`` arguments will be passed to the
        ``pyramid.response.FileResponse`` constructor as its keyword
        arguments."""
        if not "content_type" in kw:
            kw["content_type"] = str(self.mimetype)
        path = self.blob.committed()
        response = FileResponse(path, **kw)
        return response

    def get_size(self):
        """ Return the size in bytes of the data in the blob associated with
        the file"""
        return os.stat(self.blob.committed()).st_size

    def get_etag(self):
        """ Return a token identifying the "version" of the file.
        """
        self._p_activate()
        mine = self._p_serial
        blob = self.blob._p_serial
        if blob == z64:
            self.blob._p_activate()
            blob = self.blob._p_serial
        return oid_repr(max(mine, blob))
コード例 #7
0
class File(Persistent):

    title = u''

    def __init__(self, stream=None, mimetype=None, title=u''):
        """ The constructor of a File object.

        ``stream`` should be a filelike object (an object with a ``read``
        method that takes a size argument) or ``None``.  If stream is
        ``None``, the blob attached to this file object is created empty.

        ``title`` must be a string or Unicode object.

        ``mimetype`` may be any of the following:

        - ``None``, meaning set this file object's mimetype to
          ``application/octet-stream`` (the default).

        - A mimetype string (e.g. ``image/gif``)

        - The constant :attr:`substanced.file.USE_MAGIC`, which will
          derive the mimetype from the stream content (if ``stream`` is also
          supplied) using the ``python-magic`` library.

          .. warning::

             On non-Linux systems, successful use of
             :attr:`substanced.file.USE_MAGIC` requires the installation
             of additional dependencies.  See :ref:`optional_dependencies`.
        """
        self.blob = Blob()
        self.mimetype = mimetype or 'application/octet-stream'
        self.title = title or u''
        if stream is not None:
            if mimetype is USE_MAGIC:
                hint = USE_MAGIC
            else:
                hint = None
            self.upload(stream, mimetype_hint=hint)

    def upload(self, stream, mimetype_hint=None):
        """ Replace the current contents of this file's blob with the
        contents of ``stream``.  ``stream`` must be a filelike object (it
        must have a ``read`` method that takes a size argument).

        ``mimetype_hint`` can be any of the following:

        - ``None``, meaning don't reset the current mimetype.  This is the
          default.  If you already know the file's mimetype, and you don't
          want it divined from a filename or stream content, use ``None`` as
          the ``mimetype_hint`` value, and set the ``mimetype`` attribute of
          the file object directly before or after calling this method.

        - A string containing a filename that has an extension; the mimetype
          will be derived from the extension in the filename using the Python
          ``mimetypes`` module, and the result will be set as the mimetype
          attribute of this object.

        - The constant :attr:`pyramid.file.USE_MAGIC`, which will derive
          the mimetype using the ``python-magic`` library based on the
          stream's actual content.  The result will be set as the mimetype
          attribute of this object.

          .. warning::

             On non-Linux systems, successful use of
             :attr:`substanced.file.USE_MAGIC` requires the installation
             of additional dependencies.  See :ref:`optional_dependencies`.
          
        """
        if not stream:
            stream = StringIO.StringIO()
        fp = self.blob.open('w')
        first = True
        use_magic = False
        if mimetype_hint is USE_MAGIC:
            use_magic = True
            if magic is None:  # pragma: no cover
                warnings.warn(
                    'The python-magic library does not have its requisite '
                    'dependencies installed properly, therefore the '
                    '"USE_MAGIC" flag passed to this method has been ignored '
                    '(it has been converted to "None").  The mimetype of '
                    'substanced.file.File objects created may be incorrect as '
                    'a result.')
                use_magic = False
                mimetype_hint = None

        if not use_magic:
            if mimetype_hint is not None:
                mimetype, _ = mimetypes.guess_type(mimetype_hint, strict=False)
                if mimetype is None:
                    mimetype = 'application/octet-stream'
                self.mimetype = mimetype
        for chunk in chunks(stream):
            if use_magic and first:
                first = False
                m = magic.Magic(mime=True)
                mimetype = m.from_buffer(chunk)
                self.mimetype = mimetype
            fp.write(chunk)
        fp.close()

    def get_response(self, **kw):
        """ Return a WebOb-compatible response object which uses the blob
        content as the stream data and the mimetype of the file as the
        content type.  The ``**kw`` arguments will be passed to the
        ``pyramid.response.FileResponse`` constructor as its keyword
        arguments."""
        if not 'content_type' in kw:
            kw['content_type'] = self.mimetype
        path = self.blob.committed()
        response = FileResponse(path, **kw)
        return response

    def get_size(self):
        """ Return the size in bytes of the data in the blob associated with
        the file"""
        return os.stat(self.blob.committed()).st_size
コード例 #8
0
ファイル: NyBlobFile.py プロジェクト: pombredanne/trunk-eggs
class NyBlobFile(Persistent):
    """Naaya container for files stored using ZODB Blob"""

    implements(INyBlobFile)

    def __init__(self, **kwargs):
        kwargs.setdefault('filename', None)
        kwargs.setdefault('content_type', 'application/octet-stream')
        for key, value in kwargs.iteritems():
            setattr(self, key, value)
        self._blob = Blob()

    def open(self):
        return self._blob.open('r')

    def open_iterator(self):
        return filestream_iterator(self._blob.committed(), 'rb')

    def open_write(self):
        return self._blob.open('w')

    def send_data(self, RESPONSE, as_attachment=True, set_filename=True,
                  REQUEST=None):
        """NyBlobFiles can also be served using X-Sendfile.
        In order to do so, you need to set X-NaayaEnableSendfile header
        to "on" by frontend server for each request.

        Lighttpd.conf example (working in proxy mode)::
         server.modules  += ( "mod_setenv" )
         setenv.add-request-header = ( "X-NaayaEnableSendfile" => "on" )
         proxy-core.allow-x-sendfile = "enable"

        """
        RESPONSE.setHeader('Content-Length', self.size)
        RESPONSE.setHeader('Content-Type', self.content_type)
        if as_attachment:
            header_value = "attachment"
            if set_filename:
                utf8_fname = urllib.quote(self.filename)
                header_value += ";filename*=UTF-8''%s" % utf8_fname
            RESPONSE.setHeader('Content-Disposition', header_value)

        # Test for enabling of X-SendFile
        if REQUEST is not None:
            ny_xsendfile = REQUEST.get_header("X-NaayaEnableSendfile")
            if ny_xsendfile is not None and ny_xsendfile=="on":
                RESPONSE.setHeader("X-Sendfile", self._current_filename())
                return "[body should be replaced by front-end server]"

        if hasattr(RESPONSE, '_streaming'):
            return self.open_iterator()
        else:
            return self.open().read()

    def _current_filename(self):
        """ Convenience function that returns blob's filename """
        try:
            return self._blob.committed()
        except BlobError:
            return self._blob._p_blob_uncommitted

    def __repr__(self):
        return '<%(cls)s %(fname)r (%(mime)s, %(size)r bytes)>' % {
            'cls': self.__class__.__name__,
            'fname': self.filename,
            'mime': self.content_type,
            'size': self.size,
        }
コード例 #9
0
ファイル: file.py プロジェクト: Umair/App-Python-SDK
class BlobValue(object):
    """A BlobValue is using a ZODB Blob to store data. It handles both
    the zope.app.file and zope.file features. It can be used as a blob
    attribute, for more complex object. It can also be used as a mixin
    with a Persistent class.
    """
    implements(IBlobFile)

    filename = FieldProperty(IBlobFile['filename'])
    mimeType = FieldProperty(IBlobFile['mimeType'])
    parameters = FieldProperty(IBlobFile['parameters'])

    def __init__(self, data='', contentType='',
                 filename=None, parameters=None):

        if filename:
            filename = clean_filename(filename)
            self.filename = filename

        if not contentType and filename:
            self.mimeType, enc = guess_content_type(name=filename)
        elif not contentType:
            self.mimeType = "application/octet-stream"
        else:
            self.mimeType = contentType

        if parameters is None:
            parameters = {}
        else:
            parameters = dict(parameters)
        self.parameters = parameters

        self._blob = Blob()
        self.data = data

    @property
    def contentType(self):
        return self.mimeType

    def open(self, mode="r"):
        return self._blob.open(mode)

    def openDetached(self):
        return file(self._blob.committed(), 'rb')

    def __len__(self):
        if self._blob == "":
            return 0
        reader = self._blob.open()
        reader.seek(0, 2)
        size = reader.tell()
        reader.close()
        return size

    @property
    def size(self):
        return int(self.__len__())

    @apply
    def data():
        """The blob property using a IFileStorage adapter
        to write down the value.
        """

        def get(self):
            blob = self._blob.open('r')
            data = blob.read()
            blob.close()
            return data

        def set(self, value):
            stored = queryMultiAdapter((self._blob, value), IFileStorage)
            if stored is not True:
                raise StorageError(
                    "An error occured during the blob storage. Check the "
                    "value type (%r). This value should implement IFile, "
                    "IString or IUnicode (see `dolmen.builtins`)."
                    % value.__class__)

        return property(get, set)

    @property
    def physical_path(self):
        try:
            filename = self._blob.committed()
        except BlobError:
            # We retry, the data has now been commited
            # if possible by the ZODB blob.
            try:
                filename = self._blob.committed()
            except BlobError:
                # The retry failed, we return None.
                return None
        return filename
コード例 #10
0
ファイル: data.py プロジェクト: Zojax/zojax.filefield
class File(Persistent):
    """ inspired by zope.file package implementation """
    interface.implements(IFile)

    filename = u'file'
    mimeType = u''
    modified = None
    disablePreview = False
    disablePrint = False

    def __init__(self):
        self._blob = Blob()
        self.data = u''

    @setproperty
    def data(self, data):
        self.size = len(data)
        self.hash = md5.md5(data).hexdigest()
        self.modified = zope.datetime.parseDatetimetz(str(datetime.now()))
        fp = self.open('w')
        fp.write(data)
        fp.close()

    @getproperty
    def data(self):
        try:
            fp = self._blob.open('r')
            data = fp.read()
            fp.close()
            return data
        except POSKeyError:
            print "Found damaged FileField: %s" % (self.filename)
            return False

    @getproperty
    def previewIsAvailable(self):
        """ check record in previewsCatalog,
            returns True or False
        """
        return getUtility(IPreviewsCatalog).check(self)

    @getproperty
    def size(self):
        if 'size' in self.__dict__:
            return self.__dict__['size']
        else:
            reader = self.open()
            if not reader:
                return 0
            try:
                reader.seek(0, 2)
                size = int(reader.tell())
            finally:
                reader.close()
            self.__dict__['size'] = size
            return size

    @setproperty
    def size(self, value):
        self.__dict__['size'] = value

    @Lazy
    def hash(self):
        fp = self._blob.open('r')
        data = fp.read()
        fp.close()
        self.hash = md5.md5(data).hexdigest()
        self._p_changed = True
        return self.hash

    def __len__(self):
        return self.size

    def __nonzero__(self):
        return self.size > 0

    def clear(self):
        self.filename = u''
        self.mimeType = u''
        self.data = u''
        self.disablePreview = u''
        self.disablePrint = u''

        # NOTE: remove record from previewsCatalog
        getUtility(IPreviewsCatalog).remove(self)

    def open(self, mode="r"):
        try:
            if 'w' in mode:
                if 'size' in self.__dict__:
                    del self.__dict__['size']
                self.modified = zope.datetime.parseDatetimetz(
                    str(datetime.now()))
            return self._blob.open(mode)
        except POSKeyError:
            print "Found damaged FileField: %s" % (self.filename)
            return False

    def openPreview(self, mode="r"):
        """ returns openPreview for preview
        """
        preview = getUtility(IPreviewsCatalog).getPreview(self)
        return preview.openPreview(mode)

    def openDetached(self, n=0):
        try:
            return file(self._blob.committed(), 'rb')
        except BlobError:
            if n < 2:
                transaction.commit()
                return self.openDetached(n + 1)

    def openPreviewDetached(self):
        """ returns openPreviewDetached for preview
        """
        preview = getUtility(IPreviewsCatalog).getPreview(self)
        return preview.openPreviewDetached()

    def _show(self, request, filename=None, contentDisposition="inline"):
        response = request.response

        if not self.mimeType:
            response.setHeader('Content-Type', 'application/octet-stream')
        else:
            response.setHeader('Content-Type', self.mimeType)

        response.setHeader('Content-Length', self.size)

        modified = self.modified

        header = request.getHeader('If-Modified-Since', None)

        lmt = long(zope.datetime.time(modified.isoformat()))

        if header is not None:
            header = header.split(';')[0]
            try:
                mod_since = long(zope.datetime.time(header))
            except:
                mod_since = None
            if mod_since is not None:
                if lmt <= mod_since:
                    response.setStatus(304)
                    return ''
        response.setHeader('Last-Modified', zope.datetime.rfc1123_date(lmt))

        if filename is None:
            filename = self.filename

        response.setHeader(
            'Content-Disposition', '%s; filename="%s"' % (
                contentDisposition, filename.encode('utf-8')))

        if not self.size:
            response.setHeader('Content-Type', 'text/plain')
            return ''
        else:
            return self

    def show(self, *kv, **kw):
        res = self._show(*kv, **kw)
        if res != '':
            return DownloadResult(self)
        return res

    def showFly(self, *kv, **kw):
        res = self._show(*kv, **kw)
        if res != '':
            return DownloadResultFly(self)
        return res

    def _showPreview(self, request, filename=None, contentDisposition="inline"):

        # NOTE: previewSize for preview from previewsCatalog
        previewSize = getUtility(IPreviewsCatalog).getPreviewSize(self)

        response = request.response

        response.setHeader('Content-Type', 'application/x-shockwave-flash')

        response.setHeader('Content-Length', previewSize)

        modified = self.modified

        header = request.getHeader('If-Modified-Since', None)

        lmt = long(rfc822.mktime_tz(modified.utctimetuple() + (0,)))

        if header is not None:
            header = header.split(';')[0]
            try:
                mod_since = long(zope.datetime.time(header))
            except:
                mod_since = None
            if mod_since is not None:
                if lmt <= mod_since:
                    response.setStatus(304)
                    return ''
        response.setHeader('Last-Modified', zope.datetime.rfc1123_date(lmt))

        if filename is None:
            filename = self.filename

        response.setHeader(
            'Content-Disposition', '%s; filename="%s"' % (
                contentDisposition, filename.encode('utf-8')))

        if not previewSize:
            response.setHeader('Content-Type', 'text/plain')
            return ''
        else:
            return self

    def showPreview(self, *kv, **kw):
        res = self._showPreview(*kv, **kw)
        if res != '':
            return DownloadPreviewResult(self)
        return res

    def showPreviewFly(self, *kv, **kw):
        res = self._showPreview(*kv, **kw)
        if res != '':
            return DownloadPreviewResultFly(self)
        return res

    def generatePreview(self):
        """ add record to previewsCatalog, generate preview
        """
        getUtility(IPreviewsCatalog).add(self)

    def __deepcopy__(self, memo):
        new = File()
        new.data = self.data
        new.filename = self.filename
        new.mimeType = self.mimeType
        new.disablePreview = self.disablePreview
        new.disablePrint = self.disablePrint
        new.generatePreview()
        return new
コード例 #11
0
class File(Persistent, Contained):
    """Generic file persistent object"""

    title = FieldProperty(IFileInfo['title'])
    description = FieldProperty(IFileInfo['description'])
    filename = FieldProperty(IFileInfo['filename'])
    language = FieldProperty(IFileInfo['language'])

    _size = 0

    def __init__(self, data='', content_type=None, source=None):
        self.content_type = content_type
        self._blob = None
        if data:
            self.data = data
        elif source:
            if os.path.exists(source):
                try:
                    f = open(source, 'rb')  # pylint: disable=invalid-name
                    self.data = f
                finally:
                    f.close()

    def init_blob(self):
        """Initialize internal blob and add reference to it"""
        self.remove_blob_reference()
        self._blob = Blob()

    def add_blob_reference(self, reference=None):
        """Add reference to internal blob"""
        if self._blob is not None:
            references = get_utility(IBlobReferenceManager)
            references.add_reference(
                self._blob, reference if reference is not None else self)

    def remove_blob_reference(self):
        """Remove reference to internal blob

        Blob is deleted if there is no more reference to it.
        """
        if self._blob is not None:
            references = get_utility(IBlobReferenceManager)
            references.drop_reference(self._blob, self)
            self._blob = None

    def get_blob(self, mode='r'):
        """Open current blob in given mode"""
        if self._blob is None:
            return None
        return self._blob.open(mode=mode)

    def get_detached_blob(self):
        """Get a detached blob, which can be used after transaction end"""
        if self._blob is None:
            return None
        return open(self._blob.committed(), 'rb')

    def _get_data(self):
        """Read the whole blob content"""
        f = self.get_blob()  # pylint: disable=invalid-name
        if f is None:
            return None
        try:
            data = f.read()
            return data
        finally:
            f.close()

    def _set_data(self, data):
        """Set blob content"""
        self.init_blob()
        if isinstance(data, str):
            data = data.encode('utf-8')
        elif hasattr(data, 'seek'):
            data.seek(0)
        f = self.get_blob('w')  # pylint: disable=invalid-name
        try:
            if hasattr(data, 'read'):
                self._size = 0
                _data = data.read(BLOCK_SIZE)
                size = len(_data)
                while size > 0:
                    f.write(_data)
                    self._size += size
                    _data = data.read(BLOCK_SIZE)
                    size = len(_data)
            else:
                f.write(data)
                self._size = len(data)
        finally:
            f.close()

    data = property(_get_data, _set_data)

    def get_size(self):
        """Return current blob size"""
        return self._size

    def __enter__(self):
        """Context manager entry point"""
        return self.get_blob(mode='r')

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit point

        We don't close the blob here.
        It's up to the context manager call to close it!
        """

    def __iter__(self):
        """Iterator over blob content to read by chunks"""
        if self._blob is None:
            return
        with self as f:  # pylint: disable=invalid-name
            while True:
                chunk = f.read(BLOCK_SIZE)
                if not chunk:
                    f.close()
                    return
                yield chunk

    def __bool__(self):
        """Non-zero test against blob size"""
        return self._size > 0
コード例 #12
0
class NyBlobFile(Item, Persistent, Cacheable, Implicit):
    """Naaya persistence of file using ZODB blobs"""

    implements(INyBlobFile)
    meta_type = "NyBlobFile"
    security = ClassSecurityInfo()

    def __init__(self, **kwargs):
        super(NyBlobFile, self).__init__(**kwargs)
        kwargs.setdefault('filename', None)
        kwargs.setdefault('content_type', 'application/octet-stream')
        for key, value in kwargs.iteritems():
            setattr(self, key, value)
        self._blob = Blob()

    def is_broken(self):
        filename = self.get_filename()
        if not filename:
            return True
        try:
            os.stat(filename)
            return False
        except (OSError, POSKeyError):
            return True

    def open(self):
        return self._blob.open('r')

    def open_iterator(self):
        return filestream_iterator(self._blob.committed(), 'rb')

    def open_write(self):
        return self._blob.open('w')

    def send_data(self, RESPONSE, as_attachment=True, set_filename=True,
                  REQUEST=None):
        """NyBlobFiles can also be served using X-Sendfile.
        In order to do so, you need to set X-NaayaEnableSendfile header
        to "on" by frontend server for each request.

        Lighttpd.conf example (working in proxy mode)::
         server.modules  += ( "mod_setenv" )
         setenv.add-request-header = ( "X-NaayaEnableSendfile" => "on" )
         proxy-core.allow-x-sendfile = "enable"

        """
        RESPONSE.setHeader('Content-Length', self.size)
        RESPONSE.setHeader('Content-Type', self.content_type)
        if as_attachment:
            header_value = "attachment"
            if set_filename:
                utf8_fname = urllib.quote(self.filename)
                header_value += ";filename*=UTF-8''%s" % utf8_fname
            RESPONSE.setHeader('Content-Disposition', header_value)

        # Test for enabling of X-SendFile
        if REQUEST is not None:
            ny_xsendfile = REQUEST.get_header("X-NaayaEnableSendfile")
            if ny_xsendfile is not None and ny_xsendfile=="on":
                RESPONSE.setHeader("X-Sendfile", self._current_filename())
                return "[body should be replaced by front-end server]"

        if hasattr(RESPONSE, '_streaming'):
            return self.open_iterator()
        else:
            return self.open().read()

    def _current_filename(self):
        """ Convenience function that returns blob's filename """
        try:
            return self._blob.committed()
        except POSKeyError:
            return None
        except BlobError:
            return self._blob._p_blob_uncommitted

    get_filename = _current_filename

    def __repr__(self):
        return '<%(cls)s %(fname)r (%(mime)s, %(size)r bytes)>' % {
            'cls': self.__class__.__name__,
            'fname': self.filename,
            'mime': self.content_type,
            'size': self.size,
        }

    def get_size(self):
        return self.size

    security.declareProtected("View", 'index_html')
    def index_html(self, REQUEST=None, RESPONSE=None, charset='utf-8', disposition='inline'):
        """ make it directly viewable when entering the objects URL """

        if REQUEST is None:
            REQUEST = self.REQUEST

        if RESPONSE is None:
            RESPONSE = REQUEST.RESPONSE

        RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime))
        RESPONSE.setHeader('Content-Type', self.getContentType())
        RESPONSE.setHeader('Accept-Ranges', 'bytes')

        if handleIfModifiedSince(self, REQUEST, RESPONSE):
            return ''

        length = self.get_size()
        RESPONSE.setHeader('Content-Length', length)

        filename = self.getFilename()
        if filename is not None:
            if not isinstance(filename, unicode):
                filename = unicode(filename, charset, errors="ignore")
            filename = IUserPreferredFileNameNormalizer(REQUEST).normalize(
                filename)
            header_value = contentDispositionHeader(
                disposition=disposition,
                filename=filename)
            RESPONSE.setHeader("Content-disposition", header_value)

        request_range = handleRequestRange(self, length, REQUEST, RESPONSE)
        for fr in self._blob.readers:
            self._blob.readers.remove(fr)

        return self.getIterator(**request_range)

    security.declarePrivate('getIterator')
    def getIterator(self, **kw):
        """ return a filestream iterator object from the blob """
        return BlobStreamIterator(self._blob, **kw)

    def getContentType(self):
        return self.content_type

    def getFilename(self):
        return self.filename

    def raw_data(self):
        f = self.open()
        s = f.read()
        f.close()
        for fr in self._blob.readers:
            self._blob.readers.remove(fr)
        return s
コード例 #13
0
class NyBlobFile(Item, Persistent, Cacheable, Implicit):
    """Naaya persistence of file using ZODB blobs"""

    implements(INyBlobFile)
    meta_type = "NyBlobFile"
    security = ClassSecurityInfo()

    def __init__(self, **kwargs):
        super(NyBlobFile, self).__init__(**kwargs)
        kwargs.setdefault('filename', None)
        kwargs.setdefault('content_type', 'application/octet-stream')
        for key, value in kwargs.iteritems():
            setattr(self, key, value)
        self._blob = Blob()

    def is_broken(self):
        filename = self.get_filename()
        if not filename:
            return True
        try:
            os.stat(filename)
            return False
        except (OSError, POSKeyError):
            return True

    def open(self):
        return self._blob.open('r')

    def open_iterator(self):
        return filestream_iterator(self._blob.committed(), 'rb')

    def open_write(self):
        return self._blob.open('w')

    def send_data(self,
                  RESPONSE,
                  as_attachment=True,
                  set_filename=True,
                  REQUEST=None):
        """NyBlobFiles can also be served using X-Sendfile.
        In order to do so, you need to set X-NaayaEnableSendfile header
        to "on" by frontend server for each request.

        Lighttpd.conf example (working in proxy mode)::
         server.modules  += ( "mod_setenv" )
         setenv.add-request-header = ( "X-NaayaEnableSendfile" => "on" )
         proxy-core.allow-x-sendfile = "enable"

        """
        RESPONSE.setHeader('Content-Length', self.size)
        RESPONSE.setHeader('Content-Type', self.content_type)
        if as_attachment:
            header_value = "attachment"
            if set_filename:
                utf8_fname = urllib.quote(self.filename)
                header_value += ";filename*=UTF-8''%s" % utf8_fname
            RESPONSE.setHeader('Content-Disposition', header_value)

        # Test for enabling of X-SendFile
        if REQUEST is not None:
            ny_xsendfile = REQUEST.get_header("X-NaayaEnableSendfile")
            if ny_xsendfile is not None and ny_xsendfile == "on":
                RESPONSE.setHeader("X-Sendfile", self._current_filename())
                return "[body should be replaced by front-end server]"

        if hasattr(RESPONSE, '_streaming'):
            return self.open_iterator()
        else:
            return self.open().read()

    def _current_filename(self):
        """ Convenience function that returns blob's filename """
        try:
            return self._blob.committed()
        except POSKeyError:
            return None
        except BlobError:
            return self._blob._p_blob_uncommitted

    get_filename = _current_filename

    def __repr__(self):
        return '<%(cls)s %(fname)r (%(mime)s, %(size)r bytes)>' % {
            'cls': self.__class__.__name__,
            'fname': self.filename,
            'mime': self.content_type,
            'size': self.size,
        }

    def get_size(self):
        return self.size

    security.declareProtected("View", 'index_html')

    def index_html(self,
                   REQUEST=None,
                   RESPONSE=None,
                   charset='utf-8',
                   disposition='inline'):
        """ make it directly viewable when entering the objects URL """

        if REQUEST is None:
            REQUEST = self.REQUEST

        if RESPONSE is None:
            RESPONSE = REQUEST.RESPONSE

        RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime))
        RESPONSE.setHeader('Content-Type', self.getContentType())
        RESPONSE.setHeader('Accept-Ranges', 'bytes')

        if handleIfModifiedSince(self, REQUEST, RESPONSE):
            return ''

        length = self.get_size()
        RESPONSE.setHeader('Content-Length', length)

        filename = self.getFilename()
        if filename is not None:
            if not isinstance(filename, unicode):
                filename = unicode(filename, charset, errors="ignore")
            filename = IUserPreferredFileNameNormalizer(REQUEST).normalize(
                filename)
            header_value = contentDispositionHeader(disposition=disposition,
                                                    filename=filename)
            RESPONSE.setHeader("Content-disposition", header_value)

        request_range = handleRequestRange(self, length, REQUEST, RESPONSE)
        for fr in self._blob.readers:
            self._blob.readers.remove(fr)

        return self.getIterator(**request_range)

    security.declarePrivate('getIterator')

    def getIterator(self, **kw):
        """ return a filestream iterator object from the blob """
        return BlobStreamIterator(self._blob, **kw)

    def getContentType(self):
        return self.content_type

    def getFilename(self):
        return self.filename

    def raw_data(self):
        f = self.open()
        s = f.read()
        f.close()
        for fr in self._blob.readers:
            self._blob.readers.remove(fr)
        return s
コード例 #14
0
ファイル: configlet.py プロジェクト: Zojax/zojax.filefield
class PreviewRecord(Persistent):
    interface.implements(IPreviewRecord)

    def __init__(self, parent=None):
        self.parent = parent
        self.previewSize = 0
        self._previewBlob = Blob()

    @getproperty
    def previewData(self):
        """ returns preview data """
        fp = self._previewBlob.open('r')
        data = fp.read()
        fp.close()
        return data

    @getproperty
    def previewSize(self):
        if 'previewSize' in self.__dict__:
            return self.__dict__['previewSize']
        else:
            reader = self.openPreview()
            try:
                reader.seek(0,2)
                size = int(reader.tell())
            finally:
                reader.close()
            self.__dict__['previewSize'] = size
            return size

    @setproperty
    def previewSize(self, value):
        self.__dict__['previewSize'] = value

    def openPreview(self, mode="r"):
        try:
            return self._previewBlob.open(mode)
        except AttributeError:
            self._previewBlob = Blob()
            return self._previewBlob.open(mode)

    def openPreviewDetached(self, n=0):
        try:
            return file(self._previewBlob.committed(), 'rb')
        except BlobError:
            if n < 2:
                transaction.commit()
                return self.openPreviewDetached(n + 1)

    def generatePreview(self):
        MAX_VALUE = getUtility(IPreviewsCatalog).maxValue * 1024 * 1024
        size = 0

        if self.parent.size < MAX_VALUE and not self.parent.disablePreview:
            logger.info(
                "Start generating preview for: %s" % self.parent.filename)
            fp = self.openPreview('w')
            ff = self.parent.open()
            try:
                fp.write(api.convert(
                    ff, 'application/x-shockwave-flash', self.parent.mimeType,
                    filename=self.parent.filename))
                size = int(fp.tell())
            except (ConverterException, OSError), e:
                logger.warning(
                    'Error generating preview for %s: %s',
                    self.parent.filename, e)
            except: