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 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
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
49 class AttachmentTool( UniqueObject
, SimpleItem
):
50 """ Links attachment objects to contents.
53 id = 'portal_attachment'
54 meta_type
= 'Attachment Tool'
55 manage_options
= SimpleItem
.manage_options
57 security
= ClassSecurityInfo()
59 security
.declarePublic('getAttachmentsFor')
60 def getAttachmentsFor(self
, content
):
61 """getAttachmentsFor returns attachments container of content
63 if getattr( aq_base(content
), 'attachments', None ) is None :
64 self
._createAttachmentContainerFor
(content
)
66 return content
.attachments
68 security
.declarePrivate('_createAttachmentContainerFor')
69 def _createAttachmentContainerFor(self
, content
):
70 """_createAttachmentContainerFor documentation
73 content
.attachments
= AttachmentContainer()
75 security
.declarePublic('uploadAttachmentFor')
76 def uploadAttachmentFor(self
, content
, file, title
='', typeName
='File') :
77 "upload attachment inside content's attachment folder."
79 mtool
= getToolByName(self
, 'portal_membership')
80 if not mtool
.checkPermission(ModifyPortalContent
, content
) :
81 raise AccessControl_Unauthorized
83 utool
= getToolByName(self
, 'portal_url')
84 portal
= utool
.getPortalObject()
86 attachments
= self
.getAttachmentsFor(content
)
87 dummy
, title
= cookId('', title
, file)
88 id = makeValidId(attachments
, title
)
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)
98 raise AccessControl_Unauthorized
100 content
.attachments
._setObject
(id, fileOb
)
101 fileOb
= getattr(content
.attachments
, id)
106 InitializeClass( AttachmentTool
)
109 class AttachmentContainer (Folder
):
111 meta_type
= 'Attachment container'
112 security
= ClassSecurityInfo()
115 self
.id = 'attachments'
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.
124 self
.dav__init(REQUEST
, RESPONSE
)
125 fileName
= unquote(REQUEST
.getHeader('X-File-Name', ''))
126 validId
= makeValidId(self
, fileName
, allow_dup
=True)
128 ifhdr
= REQUEST
.get_header('If', '')
129 if self
.wl_isLocked():
131 self
.dav__simpleifhandler(REQUEST
, RESPONSE
, col
=1)
135 raise PreconditionFailed
137 if int(REQUEST
.get('CONTENT_LENGTH') or 0) > LARGE_FILE_THRESHOLD
:
138 file = REQUEST
['BODYFILE']
139 body
= file.read(LARGE_FILE_THRESHOLD
)
142 body
= REQUEST
.get('BODY', '')
144 typ
=REQUEST
.get_header('content-type', None)
146 typ
, enc
=guess_content_type(validId
, body
)
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
)
156 ob
= File(validId
, fileName
, '')
158 self
._setObject
(validId
, ob
)
162 ob
= self
._getOb
(validId
)
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.
168 self
._verifyObjectPaste
(ob
.__of
__(self
), 0)
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
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()))
180 InitializeClass(AttachmentContainer
)