c0e37c75d251d2a36b1d669dd87d1b481074e8b1
[Plinn.git] / File.py
1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # Copyright (C) 2005-2007 BenoƮt PIN <benoit.pin@ensmp.fr> #
5 # #
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. #
10 # #
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. #
15 # #
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
22 attachments.
23
24 $Id: File.py 1549 2010-02-04 13:04:22Z pin $
25 $URL: http://svn.cri.ensmp.fr/svn/Plinn/branches/CMF-2.1/File.py $
26 """
27
28 from Globals import InitializeClass
29 from AccessControl import ClassSecurityInfo
30 import OFS
31 from zope.component.factory import Factory
32
33 from Products.CMFDefault.File import File as BaseFile
34 from Products.CMFCore.permissions import View, ModifyPortalContent
35 from Products.CMFCore.utils import getToolByName
36 from swfheader import parse as parseswf
37
38 class File(BaseFile) :
39 """ file class with portal_transforms support """
40
41 security = ClassSecurityInfo()
42
43 _properties = BaseFile._properties + ({'id':'orig_name', 'type':'string', 'mode':'w', 'label':"Original Name"},)
44 orig_name = ''
45
46
47 def __getattr__(self, name) :
48 try : return BaseFile.__getattr__(self, name)
49 except :
50 selfAttrs = self.__dict__
51 if selfAttrs.has_key('_v_transform_cache') :
52 cache = selfAttrs['_v_transform_cache']
53 cacheTuple = cache.get('text_html', None) # (time, value)
54 if cacheTuple :
55 cacheData = cacheTuple[1]
56
57 subObDict = cacheData.getSubObjects()
58 if subObDict.has_key(name) :
59 fileOb = OFS.Image.File(name, name, subObDict[name])
60 return fileOb
61
62 raise AttributeError, name
63
64 def manage_upload(self,file='',REQUEST=None):
65 ret = super(File, self).manage_upload(file=file, REQUEST=REQUEST)
66
67 orig_name = OFS.Image.cookId('', '', file)[0]
68 if orig_name :
69 self.orig_name = orig_name
70
71 print self.absolute_url(), self.Format()
72 if self.Format() == 'application/x-shockwave-flash' :
73 if file :
74 try :
75 swfmetadata = parseswf(file)
76 except IOError :
77 swfmetadata = {'width':600, 'height':600}
78
79 for name in ('width', 'height') :
80 value = swfmetadata[name]
81 if self.hasProperty(name) :
82 self._updateProperty(name, value)
83 else :
84 self.manage_addProperty(name, value, 'int')
85 self.reindexObject()
86 return ret
87
88
89
90 security.declareProtected(ModifyPortalContent, 'edit')
91 def edit(self, precondition='', file=''):
92 orig_name = OFS.Image.cookId('', '', file)[0]
93 if orig_name :
94 self.orig_name = orig_name
95 BaseFile.edit(self, precondition=precondition, file=file)
96 if hasattr(self, '_v_transform_cache') :
97 del self._v_transform_cache
98
99
100 security.declareProtected(View, 'SearchableText')
101 def SearchableText(self) :
102 """ Return full text"""
103 baseSearchableText = BaseFile.SearchableText(self)
104 transformTool = getToolByName(self, 'portal_transforms', default=None)
105 if transformTool is None :
106 return baseSearchableText
107 else :
108 datastream_text = transformTool.convertTo('text/plain',
109 str(self.data),
110 mimetype = self.content_type
111 )
112 full_text = ''
113 if datastream_text is not None :
114 full_text = datastream_text.getData()
115
116 return baseSearchableText + full_text
117
118 security.declareProtected(View, 'preview')
119 def preview(self) :
120 """Return HTML preview if it's possible or empty string """
121 transformTool = getToolByName(self, 'portal_transforms', default = None)
122 if transformTool is None :
123 return ''
124 else :
125 filename = self.getId().replace(' ', '_')
126 datastream = transformTool.convertTo('text/html',
127 str(self.data),
128 object=self,
129 mimetype = self.content_type,
130 filename = filename)
131
132 if datastream is not None : return datastream.getData()
133 else : return ''
134
135 security.declareProtected(View, 'download')
136 def download(self, REQUEST, RESPONSE):
137 """Download this item.
138
139 Calls OFS.Image.File.index_html to perform the actual transfer after
140 first setting Content-Disposition to suggest a filename.
141
142 This method is deprecated, use the URL of this object itself. Because
143 the default view of a File object is to download, rather than view,
144 this method is obsolete. Also note that certain browsers do not deal
145 well with a Content-Disposition header.
146
147 """
148
149 RESPONSE.setHeader('Content-Disposition',
150 'attachment; filename=%s' % (self.orig_name or self.getId()))
151 return OFS.Image.File.index_html(self, REQUEST, RESPONSE)
152
153 security.declarePublic('getIcon')
154 def getIcon(self, relative_to_portal=0):
155 """ return icon corresponding to mime-type
156 """
157 regTool = getToolByName(self, 'mimetypes_registry', default=None)
158 if regTool :
159 mime = regTool(str(self.data), mimetype=self.content_type)[2]
160 return mime.icon_path
161 else :
162 return BaseFile.getIcon(self, relative_to_portal=relative_to_portal)
163
164
165 InitializeClass(File)
166 FileFactory = Factory(File)
167
168
169 def addFile( dispatcher
170 , id
171 , title=''
172 , file=''
173 , content_type=''
174 , precondition=''
175 , subject=()
176 , description=''
177 , contributors=()
178 , effective_date=None
179 , expiration_date=None
180 , format='text/html'
181 , language=''
182 , rights=''
183 ):
184 """
185 Add a File
186 """
187
188 # cookId sets the id and title if they are not explicity specified
189 id, title = OFS.Image.cookId(id, title, file)
190
191 container = dispatcher.Destination()
192
193 # Instantiate the object and set its description.
194 fobj = File( id, title=title, file='', content_type=content_type,
195 precondition=precondition, subject=subject, description=description,
196 contributors=contributors, effective_date=effective_date,
197 expiration_date=expiration_date, format=format,
198 language=language, rights=rights
199 )
200
201 # Add the File instance to self
202 container._setObject(id, fobj)
203
204 # 'Upload' the file. This is done now rather than in the
205 # constructor because the object is now in the ZODB and
206 # can span ZODB objects.
207 container._getOb(id).manage_upload(file)