Implémentation de put_upload, reprise de Plinn.Folder.Folder
[Plinn.git] / AttachmentTool.py
1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # © 2007-2014 Benoît Pin <pin@cri.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 """ Portal attachment management tool.
21
22
23
24 """
25
26 from AccessControl import ClassSecurityInfo
27 from Acquisition import aq_base
28 from Globals import InitializeClass
29 from OFS.SimpleItem import SimpleItem
30 from OFS.Folder import Folder
31 from OFS.Image import File, cookId
32 from zExceptions import Unauthorized
33 from Products.Photo import Photo
34 from Products.CMFCore.utils import UniqueObject, getToolByName, getUtilityByInterfaceName
35 from Products.CMFCore.permissions import ModifyPortalContent
36 from Products.CMFCore.exceptions import AccessControl_Unauthorized
37 from Products.Plinn.utils import makeValidId
38
39 from urllib import unquote
40 from cgi import escape
41 from ZServer import LARGE_FILE_THRESHOLD
42 from webdav.interfaces import IWriteLock
43 from webdav.common import Locked
44 from webdav.common import PreconditionFailed
45 from zope.contenttype import guess_content_type
46
47
48
49 class AttachmentTool( UniqueObject, SimpleItem):
50 """ Links attachment objects to contents.
51 """
52
53 id = 'portal_attachment'
54 meta_type = 'Attachment Tool'
55 manage_options = SimpleItem.manage_options
56
57 security = ClassSecurityInfo()
58
59 security.declarePublic('getAttachmentsFor')
60 def getAttachmentsFor(self, content):
61 """getAttachmentsFor returns attachments container of content
62 """
63 if getattr( aq_base(content), 'attachments', None ) is None :
64 self._createAttachmentContainerFor(content)
65
66 return content.attachments
67
68 security.declarePrivate('_createAttachmentContainerFor')
69 def _createAttachmentContainerFor(self, content):
70 """_createAttachmentContainerFor documentation
71 """
72
73 content.attachments = AttachmentContainer()
74
75 security.declarePublic('uploadAttachmentFor')
76 def uploadAttachmentFor(self, content, file, title='', typeName='File') :
77 "upload attachment inside content's attachment folder."
78
79 mtool = getToolByName(self, 'portal_membership')
80 if not mtool.checkPermission(ModifyPortalContent, content) :
81 raise AccessControl_Unauthorized
82
83 utool = getToolByName(self, 'portal_url')
84 portal = utool.getPortalObject()
85
86 attachments = self.getAttachmentsFor(content)
87 dummy, title = cookId('', title, file)
88 id = makeValidId(attachments, title)
89
90 if typeName == 'Photo':
91 thumbSize = {'thumb_height' : portal.getProperty('thumb_size', 192),
92 'thumb_width' : portal.getProperty('thumb_size', 192)}
93 fileOb = Photo(id, title, file, **thumbSize)
94 elif typeName == 'File' :
95 fileOb = File(id, title, '')
96 fileOb.manage_upload(file)
97 else :
98 raise AccessControl_Unauthorized
99
100 content.attachments._setObject(id, fileOb)
101 fileOb = getattr(content.attachments, id)
102 return fileOb
103
104
105
106 InitializeClass( AttachmentTool )
107
108
109 class AttachmentContainer (Folder):
110
111 meta_type = 'Attachment container'
112 security = ClassSecurityInfo()
113
114 def __init__(self):
115 self.id = 'attachments'
116
117 security.declareProtected(ModifyPortalContent, 'put_upload')
118 def put_upload(self, REQUEST, RESPONSE):
119 """ Upload a content thru webdav put method.
120 The default behavior (NullRessource.PUT + PortalFolder.PUT_factory)
121 disallow files names with '_' at the begining.
122 """
123
124 self.dav__init(REQUEST, RESPONSE)
125 fileName = unquote(REQUEST.getHeader('X-File-Name', ''))
126 validId = makeValidId(self, fileName, allow_dup=True)
127
128 ifhdr = REQUEST.get_header('If', '')
129 if self.wl_isLocked():
130 if ifhdr:
131 self.dav__simpleifhandler(REQUEST, RESPONSE, col=1)
132 else:
133 raise Locked
134 elif ifhdr:
135 raise PreconditionFailed
136
137 if int(REQUEST.get('CONTENT_LENGTH') or 0) > LARGE_FILE_THRESHOLD:
138 file = REQUEST['BODYFILE']
139 body = file.read(LARGE_FILE_THRESHOLD)
140 file.seek(0)
141 else:
142 body = REQUEST.get('BODY', '')
143
144 typ=REQUEST.get_header('content-type', None)
145 if typ is None:
146 typ, enc=guess_content_type(validId, body)
147
148 if self.checkIdAvailable(validId) :
149 if typ.startswith('image/') :
150 utool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IURLTool')
151 portal = utool.getPortalObject()
152 thumbSize = {'thumb_height' : portal.getProperty('thumb_size', 192),
153 'thumb_width' : portal.getProperty('thumb_size', 192)}
154 ob = Photo(validId, fileName, '', **thumbSize)
155 else :
156 ob = File(validId, fileName, '')
157
158 self._setObject(validId, ob)
159 httpRespCode = 201
160 else :
161 httpRespCode = 200
162 ob = self._getOb(validId)
163
164 # We call _verifyObjectPaste with verify_src=0, to see if the
165 # user can create this type of object (and we don't need to
166 # check the clipboard.
167 try:
168 self._verifyObjectPaste(ob.__of__(self), 0)
169 except CopyError:
170 sMsg = 'Unable to create object of class %s in %s: %s' % \
171 (ob.__class__, repr(self), sys.exc_info()[1],)
172 raise Unauthorized, sMsg
173
174 ob.PUT(REQUEST, RESPONSE)
175 RESPONSE.setStatus(httpRespCode)
176 RESPONSE.setHeader('Content-Type', 'text/xml;;charset=utf-8')
177 return '<element id="%s" title="%s"/>' % (ob.getId(), escape(ob.title_or_id()))
178
179
180 InitializeClass(AttachmentContainer)