Back to index

plone3  3.1.7
File.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ This module implements a portal-managed File class.  It is based on
00014 Zope's built-in File object, but modifies the behaviour slightly to
00015 make it more Portal-friendly.
00016 
00017 $Id: File.py 77186 2007-06-28 19:06:19Z yuppie $
00018 """
00019 
00020 import OFS.Image
00021 from AccessControl import ClassSecurityInfo
00022 from Globals import InitializeClass
00023 from OFS.Cache import Cacheable
00024 from zope.component.factory import Factory
00025 from zope.interface import implements
00026 
00027 from Products.CMFCore.PortalContent import PortalContent
00028 from Products.CMFCore.utils import _checkConditionalGET
00029 from Products.CMFCore.utils import _OldCacheHeaders
00030 from Products.CMFCore.utils import _setCacheHeaders
00031 from Products.CMFCore.utils import _ViewEmulator
00032 from Products.GenericSetup.interfaces import IDAVAware
00033 
00034 from DublinCore import DefaultDublinCoreImpl
00035 from interfaces import IFile
00036 from interfaces import IMutableFile
00037 from permissions import ModifyPortalContent
00038 from permissions import View
00039 
00040 
00041 def addFile( self
00042            , id
00043            , title=''
00044            , file=''
00045            , content_type=''
00046            , precondition=''
00047            , subject=()
00048            , description=''
00049            , contributors=()
00050            , effective_date=None
00051            , expiration_date=None
00052            , format='text/html'
00053            , language=''
00054            , rights=''
00055            ):
00056     """
00057     Add a File
00058     """
00059 
00060     # cookId sets the id and title if they are not explicity specified
00061     id, title = OFS.Image.cookId(id, title, file)
00062 
00063     self=self.this()
00064 
00065     # Instantiate the object and set its description.
00066     fobj = File( id, title, '', content_type, precondition, subject
00067                , description, contributors, effective_date, expiration_date
00068                , format, language, rights
00069                )
00070 
00071     # Add the File instance to self
00072     self._setObject(id, fobj)
00073 
00074     # 'Upload' the file.  This is done now rather than in the
00075     # constructor because the object is now in the ZODB and
00076     # can span ZODB objects.
00077     self._getOb(id).manage_upload(file)
00078 
00079 
00080 class File(PortalContent, OFS.Image.File, DefaultDublinCoreImpl):
00081 
00082     """A Portal-managed File.
00083     """
00084 
00085     implements(IMutableFile, IFile, IDAVAware)
00086     __implements__ = ( PortalContent.__implements__
00087                      , DefaultDublinCoreImpl.__implements__
00088                      )
00089 
00090     effective_date = expiration_date = None
00091     icon = PortalContent.icon
00092 
00093     manage_options = ( PortalContent.manage_options
00094                      + Cacheable.manage_options
00095                      )
00096 
00097     security = ClassSecurityInfo()
00098 
00099     def __init__( self
00100                 , id
00101                 , title=''
00102                 , file=''
00103                 , content_type=''
00104                 , precondition=''
00105                 , subject=()
00106                 , description=''
00107                 , contributors=()
00108                 , effective_date=None
00109                 , expiration_date=None
00110                 , format=None
00111                 , language='en-US'
00112                 , rights=''
00113                 ):
00114         OFS.Image.File.__init__( self, id, title, file
00115                                , content_type, precondition )
00116         self._setId(id)
00117         delattr(self, '__name__')
00118 
00119         # If no file format has been passed in, rely on what OFS.Image.File
00120         # detected. Unlike Images, which have code to try and pick the content
00121         # type out of the binary data, File objects only provide the correct
00122         # type if a "hint" in the form of a filename extension is given.
00123         if format is None:
00124             format = self.content_type 
00125 
00126         DefaultDublinCoreImpl.__init__( self, title, subject, description
00127                                , contributors, effective_date, expiration_date
00128                                , format, language, rights )
00129 
00130     # For old instances where bases had OFS.Image.File first,
00131     # the id was actually stored in __name__.
00132     # getId() will do the correct thing here, as id() is callable
00133     def id(self):
00134         return self.__name__
00135 
00136     security.declareProtected(View, 'SearchableText')
00137     def SearchableText(self):
00138         """
00139         SeachableText is used for full text seraches of a portal.  It
00140         should return a concatenation of all useful text.
00141         """
00142         return "%s %s" % (self.title, self.description)
00143 
00144     security.declarePrivate('_isNotEmpty')
00145     def _isNotEmpty(self, file):
00146         """ Do various checks on 'file' to try to determine non emptiness. """
00147         if not file:
00148             return 0                    # Catches None, Missing.Value, ''
00149         elif file and (type(file) is type('')):
00150             return 1
00151         elif getattr(file, 'filename', None):
00152             return 1
00153         elif not hasattr(file, 'read'):
00154             return 0
00155         else:
00156             file.seek(0,2)              # 0 bytes back from end of file
00157             t = file.tell()             # Report the location
00158             file.seek(0)                # and return pointer back to 0
00159             if t: return 1
00160             else: return 0
00161 
00162     security.declarePrivate('_edit')
00163     def _edit(self, precondition='', file=''):
00164         """ Perform changes for user """
00165         if precondition: self.precondition = precondition
00166         elif self.precondition: del self.precondition
00167 
00168         if self._isNotEmpty(file):
00169             self.manage_upload(file)
00170 
00171     security.declareProtected(ModifyPortalContent, 'edit')
00172     def edit(self, precondition='', file=''):
00173         """ Update and reindex. """
00174         self._edit( precondition, file )
00175         self.reindexObject()
00176 
00177     security.declareProtected(View, 'index_html')
00178     def index_html(self, REQUEST, RESPONSE):
00179         """
00180         The default view of the contents of a File or Image.
00181 
00182         Returns the contents of the file or image.  Also, sets the
00183         Content-Type HTTP header to the objects content type.
00184         """
00185         view = _ViewEmulator().__of__(self)
00186 
00187         # If we have a conditional get, set status 304 and return
00188         # no content 
00189         if _checkConditionalGET(view, extra_context={}):
00190             return ''
00191 
00192         RESPONSE.setHeader('Content-Type', self.content_type)
00193 
00194         # old-style If-Modified-Since header handling.
00195         if self._setOldCacheHeaders():
00196             # Make sure the CachingPolicyManager gets a go as well
00197             _setCacheHeaders(view, extra_context={})
00198             return ''
00199 
00200         rendered = OFS.Image.File.index_html(self, REQUEST, RESPONSE)
00201 
00202         # There are 2 Cache Managers which can be in play....
00203         # need to decide which to use to determine where the cache headers
00204         # are decided on.
00205         if self.ZCacheable_getManager() is not None:
00206             self.ZCacheable_set(None)
00207         else:
00208             _setCacheHeaders(view, extra_context={})
00209 
00210         return rendered
00211 
00212     def _setOldCacheHeaders(self):
00213         # return False to disable this simple caching behaviour
00214         return _OldCacheHeaders(self) 
00215 
00216     security.declareProtected(View, 'download')
00217     def download(self, REQUEST, RESPONSE):
00218         """Download this item.
00219 
00220         Calls OFS.Image.File.index_html to perform the actual transfer after
00221         first setting Content-Disposition to suggest a filename.
00222 
00223         This method is deprecated, use the URL of this object itself. Because
00224         the default view of a File object is to download, rather than view,
00225         this method is obsolete. Also note that certain browsers do not deal
00226         well with a Content-Disposition header.
00227 
00228         """
00229 
00230         RESPONSE.setHeader('Content-Disposition',
00231                            'attachment; filename=%s' % self.getId())
00232         return self.index_html(self, REQUEST, RESPONSE)
00233 
00234     security.declareProtected(View, 'Format')
00235     def Format(self):
00236         """ Dublin Core element - resource format """
00237         return self.content_type
00238 
00239     security.declareProtected(ModifyPortalContent, 'setFormat')
00240     def setFormat(self, format):
00241         """ Dublin Core element - resource format """
00242         self.manage_changeProperties(content_type=format)
00243 
00244     security.declareProtected(ModifyPortalContent, 'PUT')
00245     def PUT(self, REQUEST, RESPONSE):
00246         """ Handle HTTP (and presumably FTP?) PUT requests """
00247         OFS.Image.File.PUT( self, REQUEST, RESPONSE )
00248         self.reindexObject()
00249 
00250 InitializeClass(File)
00251 
00252 FileFactory = Factory(File)