1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # © 2007-2014 Benoît Pin <pin@cri.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 """ Portal attachment management tool.
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 zExceptions
import BadRequest
34 from Products
.Photo
import Photo
35 from Products
.CMFCore
.utils
import UniqueObject
, getToolByName
, getUtilityByInterfaceName
36 from Products
.CMFCore
.permissions
import ModifyPortalContent
37 from Products
.CMFCore
.exceptions
import AccessControl_Unauthorized
38 from Products
.Plinn
.utils
import makeValidId
40 from urllib
import unquote
41 from cgi
import escape
42 from ZServer
import LARGE_FILE_THRESHOLD
43 from webdav
.interfaces
import IWriteLock
44 from webdav
.common
import Locked
45 from webdav
.common
import PreconditionFailed
46 from zope
.contenttype
import guess_content_type
50 class AttachmentTool( UniqueObject
, SimpleItem
):
51 """ Links attachment objects to contents.
54 id = 'portal_attachment'
55 meta_type
= 'Attachment Tool'
56 manage_options
= SimpleItem
.manage_options
58 security
= ClassSecurityInfo()
60 security
.declarePublic('getAttachmentsFor')
61 def getAttachmentsFor(self
, content
):
62 """getAttachmentsFor returns attachments container of content
64 if getattr( aq_base(content
), 'attachments', None ) is None :
65 self
._createAttachmentContainerFor
(content
)
67 return content
.attachments
69 security
.declarePrivate('_createAttachmentContainerFor')
70 def _createAttachmentContainerFor(self
, content
):
71 """_createAttachmentContainerFor documentation
74 content
.attachments
= AttachmentContainer()
76 security
.declarePublic('uploadAttachmentFor')
77 def uploadAttachmentFor(self
, content
, file, title
='', typeName
='File') :
78 "upload attachment inside content's attachment folder."
80 mtool
= getToolByName(self
, 'portal_membership')
81 if not mtool
.checkPermission(ModifyPortalContent
, content
) :
82 raise AccessControl_Unauthorized
84 utool
= getToolByName(self
, 'portal_url')
85 portal
= utool
.getPortalObject()
87 attachments
= self
.getAttachmentsFor(content
)
88 dummy
, title
= cookId('', title
, file)
89 id = makeValidId(attachments
, title
)
91 if typeName
== 'Photo':
92 thumbSize
= {'thumb_height' : portal
.getProperty('thumb_size', 192),
93 'thumb_width' : portal
.getProperty('thumb_size', 192)}
94 fileOb
= Photo(id, title
, file, **thumbSize
)
95 elif typeName
== 'File' :
96 fileOb
= File(id, title
, '')
97 fileOb
.manage_upload(file)
99 raise AccessControl_Unauthorized
101 content
.attachments
._setObject
(id, fileOb
)
102 fileOb
= getattr(content
.attachments
, id)
107 InitializeClass( AttachmentTool
)
110 class AttachmentContainer (Folder
):
112 meta_type
= 'Attachment container'
113 security
= ClassSecurityInfo()
116 self
.id = 'attachments'
118 security
.declarePrivate('checkIdAvailable')
119 def checkIdAvailable(self
, id):
128 security
.declareProtected(ModifyPortalContent
, 'put_upload')
129 def put_upload(self
, REQUEST
, RESPONSE
):
130 """ Upload a content thru webdav put method.
131 The default behavior (NullRessource.PUT + PortalFolder.PUT_factory)
132 disallow files names with '_' at the begining.
135 self
.dav__init(REQUEST
, RESPONSE
)
136 fileName
= unquote(REQUEST
.getHeader('X-File-Name', ''))
137 validId
= makeValidId(self
, fileName
, allow_dup
=True)
139 ifhdr
= REQUEST
.get_header('If', '')
140 if self
.wl_isLocked():
142 self
.dav__simpleifhandler(REQUEST
, RESPONSE
, col
=1)
146 raise PreconditionFailed
148 if int(REQUEST
.get('CONTENT_LENGTH') or 0) > LARGE_FILE_THRESHOLD
:
149 file = REQUEST
['BODYFILE']
150 body
= file.read(LARGE_FILE_THRESHOLD
)
153 body
= REQUEST
.get('BODY', '')
155 typ
=REQUEST
.get_header('content-type', None)
157 typ
, enc
=guess_content_type(validId
, body
)
159 if self
.checkIdAvailable(validId
) :
160 if typ
.startswith('image/') :
161 utool
= getUtilityByInterfaceName('Products.CMFCore.interfaces.IURLTool')
162 portal
= utool
.getPortalObject()
163 thumbSize
= {'thumb_height' : portal
.getProperty('thumb_size', 192),
164 'thumb_width' : portal
.getProperty('thumb_size', 192)}
165 ob
= Photo(validId
, fileName
, '', **thumbSize
)
167 ob
= File(validId
, fileName
, '')
169 self
._setObject
(validId
, ob
)
173 ob
= self
._getOb
(validId
)
175 # We call _verifyObjectPaste with verify_src=0, to see if the
176 # user can create this type of object (and we don't need to
177 # check the clipboard.
179 self
._verifyObjectPaste
(ob
.__of
__(self
), 0)
181 sMsg
= 'Unable to create object of class %s in %s: %s' % \
182 (ob
.__class
__, repr(self
), sys
.exc_info()[1],)
183 raise Unauthorized
, sMsg
185 ob
.PUT(REQUEST
, RESPONSE
)
186 RESPONSE
.setStatus(httpRespCode
)
187 RESPONSE
.setHeader('Content-Type', 'text/xml;;charset=utf-8')
188 return '<element id="%s" title="%s"/>' % (ob
.getId(), escape(ob
.title_or_id()))
191 InitializeClass(AttachmentContainer
)