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 """ file class with portal_transforms support """
43 security
= ClassSecurityInfo()
45 _properties
= CMFFile
._properties
+ ({'id':'orig_name', 'type':'string', 'mode':'w', 'label':"Original Name"},)
58 , expiration_date
=None
65 format
= self
.content_type
or 'application/octet-stream'
67 DefaultDublinCoreImpl
.__init
__( self
, title
, subject
, description
68 , contributors
, effective_date
, expiration_date
69 , format
, language
, rights
)
70 BlobFile
.__init
__(self
, id, title
, file, content_type
=content_type
, precondition
=precondition
)
73 def __getattr__(self
, name
) :
74 try : return CMFFile
.__getattr
__(self
, name
)
76 selfAttrs
= self
.__dict
__
77 if selfAttrs
.has_key('_v_transform_cache') :
78 cache
= selfAttrs
['_v_transform_cache']
79 cacheTuple
= cache
.get('text_html', None) # (time, value)
81 cacheData
= cacheTuple
[1]
83 subObDict
= cacheData
.getSubObjects()
84 if subObDict
.has_key(name
) :
85 fileOb
= OFS
.Image
.File(name
, name
, subObDict
[name
])
88 raise AttributeError, name
90 def manage_upload(self
,file='',REQUEST
=None):
91 ret
= super(File
, self
).manage_upload(file=file, REQUEST
=REQUEST
)
93 orig_name
= OFS
.Image
.cookId('', '', file)[0]
95 self
.orig_name
= orig_name
97 if self
.Format() == 'application/x-shockwave-flash' :
100 swfmetadata
= parseswf(file)
102 swfmetadata
= {'width':600, 'height':600}
104 for name
in ('width', 'height') :
105 value
= swfmetadata
[name
]
106 if self
.hasProperty(name
) :
107 self
._updateProperty
(name
, value
)
109 self
.manage_addProperty(name
, value
, 'int')
115 security
.declareProtected(ModifyPortalContent
, 'edit')
116 def edit(self
, precondition
='', file=''):
117 orig_name
= OFS
.Image
.cookId('', '', file)[0]
119 self
.orig_name
= orig_name
120 CMFFile
.edit(self
, precondition
=precondition
, file=file)
121 if hasattr(self
, '_v_transform_cache') :
122 del self
._v
_transform
_cache
125 security
.declareProtected(View
, 'SearchableText')
126 def SearchableText(self
) :
127 """ Return full text"""
128 baseSearchableText
= CMFFile
.SearchableText(self
)
129 transformTool
= getToolByName(self
, 'portal_transforms', default
=None)
130 if transformTool
is None :
131 return baseSearchableText
133 f
= self
.bdata
.open()
135 datastream_text
= transformTool
.convertTo('text/plain',
137 mimetype
= self
.content_type
141 if datastream_text
is not None :
142 full_text
= datastream_text
.getData()
144 return baseSearchableText
+ full_text
146 security
.declareProtected(View
, 'preview')
148 """Return HTML preview if it's possible or empty string """
149 transformTool
= getToolByName(self
, 'portal_transforms', default
= None)
150 if transformTool
is None :
153 filename
= self
.getId().replace(' ', '_')
154 f
= self
.bdata
.open()
156 datastream
= transformTool
.convertTo('text/html',
159 mimetype
= self
.content_type
,
162 if datastream
is not None : return datastream
.getData()
165 security
.declareProtected(View
, 'download')
166 def download(self
, REQUEST
, RESPONSE
):
167 """Download this item.
169 Calls OFS.Image.File.index_html to perform the actual transfer after
170 first setting Content-Disposition to suggest a filename.
172 This method is deprecated, use the URL of this object itself. Because
173 the default view of a File object is to download, rather than view,
174 this method is obsolete. Also note that certain browsers do not deal
175 well with a Content-Disposition header.
179 RESPONSE
.setHeader('Content-Disposition',
180 'attachment; filename=%s' % (self
.orig_name
or self
.getId()))
181 return OFS
.Image
.File
.index_html(self
, REQUEST
, RESPONSE
)
183 security
.declarePublic('getIcon')
184 def getIcon(self
, relative_to_portal
=0):
185 """ return icon corresponding to mime-type
187 regTool
= getToolByName(self
, 'mimetypes_registry', default
=None)
189 f
= self
.bdata
.open()
190 mime
= regTool(f
, mimetype
=self
.content_type
)[2]
192 return mime
.icon_path
194 return CMFFile
.getIcon(self
, relative_to_portal
=relative_to_portal
)
197 InitializeClass(File
)
198 FileFactory
= Factory(File
)
201 def addFile( dispatcher
210 , effective_date
=None
211 , expiration_date
=None
220 # cookId sets the id and title if they are not explicity specified
221 id, title
= OFS
.Image
.cookId(id, title
, file)
223 container
= dispatcher
.Destination()
225 # Instantiate the object and set its description.
226 fobj
= File( id, title
=title
, file='', content_type
=content_type
,
227 precondition
=precondition
, subject
=subject
, description
=description
,
228 contributors
=contributors
, effective_date
=effective_date
,
229 expiration_date
=expiration_date
, format
=format
,
230 language
=language
, rights
=rights
233 # Add the File instance to self
234 container
._setObject
(id, fobj
)
236 # 'Upload' the file. This is done now rather than in the
237 # constructor because the object is now in the ZODB and
238 # can span ZODB objects.
239 container
._getOb
(id).manage_upload(file)