1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # Copyright (C) 2005-2007 Benoît PIN <benoit.pin@ensmp.fr> #
6 # This program is free software; you can redistribute it and/or #
7 # modify it under the terms of the GNU General Public License #
8 # as published by the Free Software Foundation; either version 2 #
9 # of the License, or (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program; if not, write to the Free Software #
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
19 #######################################################################################
20 """ This module implements a portal-managed File class that's inherits of CMFDefault
21 File. If exists, portal_transforms is called to extract text content, and publish
28 from Globals
import InitializeClass
29 from AccessControl
import ClassSecurityInfo
31 from zope
.component
.factory
import Factory
33 from Products
.CMFDefault
.File
import File
as CMFFile
34 from Products
.Photo
.blobbases
import File
as BlobFile
35 from Products
.CMFDefault
.DublinCore
import DefaultDublinCoreImpl
36 from Products
.CMFCore
.permissions
import View
, ModifyPortalContent
37 from Products
.CMFCore
.utils
import getToolByName
38 from hexagonit
.swfheader
import parse
as parseswf
40 class File(BlobFile
, CMFFile
) :
41 #class File(CMFFile) :
42 """ file class with portal_transforms support """
44 security
= ClassSecurityInfo()
46 _properties
= CMFFile
._properties
+ ({'id':'orig_name', 'type':'string', 'mode':'w', 'label':"Original Name"},)
59 , expiration_date
=None
64 BlobFile
.__init
__(self
, id, title
, file, content_type
=content_type
, precondition
=precondition
)
66 #delattr(self, '__name__')
68 # If no file format has been passed in, rely on what OFS.Image.File
69 # detected. Unlike Images, which have code to try and pick the content
70 # type out of the binary data, File objects only provide the correct
71 # type if a "hint" in the form of a filename extension is given.
73 format
= self
.content_type
75 DefaultDublinCoreImpl
.__init
__( self
, title
, subject
, description
76 , contributors
, effective_date
, expiration_date
77 , format
, language
, rights
)
80 def __getattr__(self
, name
) :
81 try : return CMFFile
.__getattr
__(self
, name
)
83 selfAttrs
= self
.__dict
__
84 if selfAttrs
.has_key('_v_transform_cache') :
85 cache
= selfAttrs
['_v_transform_cache']
86 cacheTuple
= cache
.get('text_html', None) # (time, value)
88 cacheData
= cacheTuple
[1]
90 subObDict
= cacheData
.getSubObjects()
91 if subObDict
.has_key(name
) :
92 fileOb
= OFS
.Image
.File(name
, name
, subObDict
[name
])
95 raise AttributeError, name
97 def manage_upload(self
,file='',REQUEST
=None):
98 ret
= super(File
, self
).manage_upload(file=file, REQUEST
=REQUEST
)
100 orig_name
= OFS
.Image
.cookId('', '', file)[0]
102 self
.orig_name
= orig_name
104 print self
.absolute_url(), self
.Format()
105 if self
.Format() == 'application/x-shockwave-flash' :
108 swfmetadata
= parseswf(file)
110 swfmetadata
= {'width':600, 'height':600}
112 for name
in ('width', 'height') :
113 value
= swfmetadata
[name
]
114 if self
.hasProperty(name
) :
115 self
._updateProperty
(name
, value
)
117 self
.manage_addProperty(name
, value
, 'int')
123 security
.declareProtected(ModifyPortalContent
, 'edit')
124 def edit(self
, precondition
='', file=''):
125 orig_name
= OFS
.Image
.cookId('', '', file)[0]
127 self
.orig_name
= orig_name
128 CMFFile
.edit(self
, precondition
=precondition
, file=file)
129 if hasattr(self
, '_v_transform_cache') :
130 del self
._v
_transform
_cache
133 security
.declareProtected(View
, 'SearchableText')
134 def SearchableText(self
) :
135 """ Return full text"""
136 baseSearchableText
= CMFFile
.SearchableText(self
)
137 transformTool
= getToolByName(self
, 'portal_transforms', default
=None)
138 if transformTool
is None :
139 return baseSearchableText
141 f
= self
.bdata
.open()
143 datastream_text
= transformTool
.convertTo('text/plain',
145 mimetype
= self
.content_type
149 if datastream_text
is not None :
150 full_text
= datastream_text
.getData()
152 return baseSearchableText
+ full_text
154 security
.declareProtected(View
, 'preview')
156 """Return HTML preview if it's possible or empty string """
157 transformTool
= getToolByName(self
, 'portal_transforms', default
= None)
158 if transformTool
is None :
161 filename
= self
.getId().replace(' ', '_')
162 f
= self
.bdata
.open()
164 datastream
= transformTool
.convertTo('text/html',
167 mimetype
= self
.content_type
,
170 if datastream
is not None : return datastream
.getData()
173 security
.declareProtected(View
, 'download')
174 def download(self
, REQUEST
, RESPONSE
):
175 """Download this item.
177 Calls OFS.Image.File.index_html to perform the actual transfer after
178 first setting Content-Disposition to suggest a filename.
180 This method is deprecated, use the URL of this object itself. Because
181 the default view of a File object is to download, rather than view,
182 this method is obsolete. Also note that certain browsers do not deal
183 well with a Content-Disposition header.
187 RESPONSE
.setHeader('Content-Disposition',
188 'attachment; filename=%s' % (self
.orig_name
or self
.getId()))
189 return OFS
.Image
.File
.index_html(self
, REQUEST
, RESPONSE
)
191 security
.declarePublic('getIcon')
192 def getIcon(self
, relative_to_portal
=0):
193 """ return icon corresponding to mime-type
195 regTool
= getToolByName(self
, 'mimetypes_registry', default
=None)
197 f
= self
.bdata
.open()
198 mime
= regTool(f
, mimetype
=self
.content_type
)[2]
200 return mime
.icon_path
202 return CMFFile
.getIcon(self
, relative_to_portal
=relative_to_portal
)
205 InitializeClass(File
)
206 FileFactory
= Factory(File
)
209 def addFile( dispatcher
218 , effective_date
=None
219 , expiration_date
=None
228 # cookId sets the id and title if they are not explicity specified
229 id, title
= OFS
.Image
.cookId(id, title
, file)
231 container
= dispatcher
.Destination()
233 # Instantiate the object and set its description.
234 fobj
= File( id, title
=title
, file='', content_type
=content_type
,
235 precondition
=precondition
, subject
=subject
, description
=description
,
236 contributors
=contributors
, effective_date
=effective_date
,
237 expiration_date
=expiration_date
, format
=format
,
238 language
=language
, rights
=rights
241 # Add the File instance to self
242 container
._setObject
(id, fobj
)
244 # 'Upload' the file. This is done now rather than in the
245 # constructor because the object is now in the ZODB and
246 # can span ZODB objects.
247 container
._getOb
(id).manage_upload(file)