From 5c7d50d5a0ce0c2bc8024979de3365fdfc275095 Mon Sep 17 00:00:00 2001 From: Julien Muchembled <jm@nexedi.com> Date: Tue, 9 Aug 2011 17:59:11 +0200 Subject: [PATCH] Fix webdav support when used to upload embedded files Also cleanup and optimize PUT & ContributionTool This reverts commit eaf12293bd10dd81d0a9bc120467207bc2b33ba1. --- .../interactions/Document_PUT.xml | 94 ------------------- .../Document_setFilenameAndContentType.xml | 75 --------------- bt5/erp5_base/bt/revision | 2 +- product/ERP5/Tool/ContributionTool.py | 57 ++++++----- product/ERP5Type/Core/Folder.py | 5 +- product/ERP5Type/WebDAVSupport.py | 78 ++++++++------- 6 files changed, 76 insertions(+), 235 deletions(-) delete mode 100644 bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/interactions/Document_PUT.xml delete mode 100644 bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/scripts/Document_setFilenameAndContentType.xml diff --git a/bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/interactions/Document_PUT.xml b/bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/interactions/Document_PUT.xml deleted file mode 100644 index 697ae52b97..0000000000 --- a/bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/interactions/Document_PUT.xml +++ /dev/null @@ -1,94 +0,0 @@ -<?xml version="1.0"?> -<ZopeData> - <record id="1" aka="AAAAAAAAAAE="> - <pickle> - <global name="InteractionDefinition" module="Products.ERP5.Interaction"/> - </pickle> - <pickle> - <dictionary> - <item> - <key> <string>actbox_category</string> </key> - <value> <string>workflow</string> </value> - </item> - <item> - <key> <string>actbox_name</string> </key> - <value> <string></string> </value> - </item> - <item> - <key> <string>actbox_url</string> </key> - <value> <string></string> </value> - </item> - <item> - <key> <string>activate_script_name</string> </key> - <value> - <tuple/> - </value> - </item> - <item> - <key> <string>after_script_name</string> </key> - <value> - <list> - <string>Document_setFilenameAndContentType</string> - </list> - </value> - </item> - <item> - <key> <string>before_commit_script_name</string> </key> - <value> - <tuple/> - </value> - </item> - <item> - <key> <string>description</string> </key> - <value> <string></string> </value> - </item> - <item> - <key> <string>guard</string> </key> - <value> - <none/> - </value> - </item> - <item> - <key> <string>id</string> </key> - <value> <string>Document_PUT</string> </value> - </item> - <item> - <key> <string>method_id</string> </key> - <value> - <list> - <string>PUT</string> - </list> - </value> - </item> - <item> - <key> <string>once_per_transaction</string> </key> - <value> <int>0</int> </value> - </item> - <item> - <key> <string>portal_type_filter</string> </key> - <value> - <none/> - </value> - </item> - <item> - <key> <string>script_name</string> </key> - <value> - <tuple/> - </value> - </item> - <item> - <key> <string>temporary_document_disallowed</string> </key> - <value> <int>0</int> </value> - </item> - <item> - <key> <string>title</string> </key> - <value> <string></string> </value> - </item> - <item> - <key> <string>trigger_type</string> </key> - <value> <int>2</int> </value> - </item> - </dictionary> - </pickle> - </record> -</ZopeData> diff --git a/bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/scripts/Document_setFilenameAndContentType.xml b/bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/scripts/Document_setFilenameAndContentType.xml deleted file mode 100644 index 8013cb9348..0000000000 --- a/bt5/erp5_base/WorkflowTemplateItem/portal_workflow/document_conversion_interaction_workflow/scripts/Document_setFilenameAndContentType.xml +++ /dev/null @@ -1,75 +0,0 @@ -<?xml version="1.0"?> -<ZopeData> - <record id="1" aka="AAAAAAAAAAE="> - <pickle> - <global name="PythonScript" module="Products.PythonScripts.PythonScript"/> - </pickle> - <pickle> - <dictionary> - <item> - <key> <string>Script_magic</string> </key> - <value> <int>3</int> </value> - </item> - <item> - <key> <string>_bind_names</string> </key> - <value> - <object> - <klass> - <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> - </klass> - <tuple/> - <state> - <dictionary> - <item> - <key> <string>_asgns</string> </key> - <value> - <dictionary> - <item> - <key> <string>name_container</string> </key> - <value> <string>container</string> </value> - </item> - <item> - <key> <string>name_context</string> </key> - <value> <string>context</string> </value> - </item> - <item> - <key> <string>name_m_self</string> </key> - <value> <string>script</string> </value> - </item> - <item> - <key> <string>name_subpath</string> </key> - <value> <string>traverse_subpath</string> </value> - </item> - </dictionary> - </value> - </item> - </dictionary> - </state> - </object> - </value> - </item> - <item> - <key> <string>_body</string> </key> - <value> <string>document = state_change[\'object\']\n -portal = document.getPortalObject()\n -\n -filename = document.getId()\n -document.setFilename(filename)\n -content_type = portal.mimetypes_registry.lookupExtension(filename)\n -\n -if content_type is not None:\n - document.setContentType(str(content_type))\n -</string> </value> - </item> - <item> - <key> <string>_params</string> </key> - <value> <string>state_change</string> </value> - </item> - <item> - <key> <string>id</string> </key> - <value> <string>Document_setFilenameAndContentType</string> </value> - </item> - </dictionary> - </pickle> - </record> -</ZopeData> diff --git a/bt5/erp5_base/bt/revision b/bt5/erp5_base/bt/revision index 40b9b19206..b7e8805f4f 100644 --- a/bt5/erp5_base/bt/revision +++ b/bt5/erp5_base/bt/revision @@ -1 +1 @@ -990 \ No newline at end of file +991 \ No newline at end of file diff --git a/product/ERP5/Tool/ContributionTool.py b/product/ERP5/Tool/ContributionTool.py index 464e243f2e..3279aaddfe 100644 --- a/product/ERP5/Tool/ContributionTool.py +++ b/product/ERP5/Tool/ContributionTool.py @@ -151,7 +151,6 @@ class ContributionTool(BaseTool): kw['filename'] = kw['file_name'] del(kw['file_name']) filename = kw.get('filename', None) - portal_type = kw.get('portal_type') temp_object = kw.get('temp_object', False) document = None @@ -161,42 +160,55 @@ class ContributionTool(BaseTool): # Container may disappear, be smoother by passing default value container = portal.restrictedTraverse(container_path, None) # Try to find the filename - content_type = None if not url: # check if file was provided file_object = kw.get('file') if file_object is not None: if not filename: - filename = file_object.filename + filename = getattr(file_object, 'filename', None) else: # some channels supply data and file-name separately # this is the case for example for email ingestion # in this case, we build a file wrapper for it - data = kw.get('data') - if data is not None and filename: + try: + data = kw.pop('data') + except KeyError: + raise ValueError('data must be provided') + if data is not None: file_object = cStringIO.StringIO() file_object.write(data) file_object.seek(0) kw['file'] = file_object - del kw['data'] - else: - raise TypeError, 'data and filename must be provided' + content_type = kw.pop('content_type', None) else: file_object, filename, content_type = self._openURL(url) - if content_type: - kw['content_type'] = content_type + content_type = kw.pop('content_type', None) or content_type kw['file'] = file_object + if not filename: + raise ValueError('filename must be provided') + if not content_type: # fallback to a default content_type according provided # filename content_type = self.guessMimeTypeFromFilename(filename) + if content_type: + kw['content_type'] = content_type + + portal_type = kw.pop('portal_type', None) + if not portal_type: + if container is None or container.isModuleType(): + # Guess it with help of portal_contribution_registry + portal_type = portal.portal_contribution_registry.findPortalTypeName( + filename=filename, content_type=content_type) + else: + portal_type = 'Embedded File' - if portal_type and container is not None: + if container is not None: # Simplify things here and return a document immediately # XXX Nicolas: This will break support of WebDAV # if _setObject is not called - document = container.newContent(id=document_id, **kw) + document = container.newContent(document_id, portal_type, **kw) if discover_metadata: document.activate(after_path_and_method_id=(document.getPath(), ('convertToBaseFormat', 'Document_tryToConvertToBaseFormat')))\ @@ -206,24 +218,14 @@ class ContributionTool(BaseTool): return document # If the portal_type was provided, we can go faster - if portal_type and container is None: + if portal_type: # We know the portal_type, let us find the default module # and use it as container try: container = portal.getDefaultModule(portal_type) except ValueError: - container = None - - # From here, there is no hope unless a file was provided - if file_object is None: - raise ValueError, "No data provided" - + pass - if portal_type is None: - # Guess it with help of portal_contribution_registry - registry = portal.portal_contribution_registry - portal_type = registry.findPortalTypeName(filename=filename, - content_type=content_type) # # Check if same file is already exists. if it exists, then update it. # @@ -247,12 +249,9 @@ class ContributionTool(BaseTool): # Temp objects use the standard newContent from Folder if temp_object: # For temp_object creation, use the standard method - kw['portal_type'] = portal_type - return BaseTool.newContent(self, **kw) + return BaseTool.newContent(self, portal_type=portal_type, **kw) # Then put the file inside ourselves for a short while - if container_path is not None: - container = self.getPortalObject().restrictedTraverse(container_path) document = self._setObject(document_id, None, portal_type=portal_type, user_login=user_login, container=container, discover_metadata=discover_metadata, @@ -270,7 +269,7 @@ class ContributionTool(BaseTool): # Allow reindexing, reindex it and return the document try: - delattr(document, 'isIndexable') + del document.isIndexable except AttributeError: # Document does not have such attribute pass diff --git a/product/ERP5Type/Core/Folder.py b/product/ERP5Type/Core/Folder.py index 87bbfb3322..be948ae124 100644 --- a/product/ERP5Type/Core/Folder.py +++ b/product/ERP5Type/Core/Folder.py @@ -44,7 +44,6 @@ from Products.ERP5Type.CopySupport import CopyContainer from Products.ERP5Type import PropertySheet from Products.ERP5Type.XMLExportImport import Folder_asXML from Products.ERP5Type.Utils import sortValueList -from Products.ERP5Type.WebDAVSupport import Folder as WebDAVFolder from Products.ERP5Type import Permissions try: @@ -454,7 +453,7 @@ BTREE_HANDLER = 1 HBTREE_HANDLER = 2 -class Folder(CopyContainer, CMFBTreeFolder, CMFHBTreeFolder, Base, FolderMixIn, WebDAVFolder): +class Folder(CopyContainer, CMFBTreeFolder, CMFHBTreeFolder, Base, FolderMixIn): """ A Folder is a subclass of Base but not of XMLObject. Folders are not considered as documents and are therefore @@ -518,7 +517,7 @@ class Folder(CopyContainer, CMFBTreeFolder, CMFHBTreeFolder, Base, FolderMixIn, Title = Base.Title _setPropValue = Base._setPropValue _propertyMap = Base._propertyMap # are there any others XXX ? - PUT_factory = WebDAVFolder.PUT_factory + PUT_factory = None # XXX Prevent inheritance from PortalFolderBase description = None diff --git a/product/ERP5Type/WebDAVSupport.py b/product/ERP5Type/WebDAVSupport.py index c0f3701827..bbe983319b 100644 --- a/product/ERP5Type/WebDAVSupport.py +++ b/product/ERP5Type/WebDAVSupport.py @@ -200,36 +200,48 @@ class TextContent: """ Used for FTP and apparently the ZMI now too """ return len(self.manage_FTPget()) - -class Folder: - """ - Taken from CMFCore.PortalFolder - """ - def PUT_factory( self, name, typ, body ): - """ Factory for PUT requests to objects which do not yet exist. - - Used by NullResource.PUT. - - Returns -- Bare and empty object of the appropriate type (or None, if - we don't know what to do) - """ - portal = self.getPortalObject() - registry = portal.portal_contribution_registry - portal_type = registry.findPortalTypeName(filename=name, - content_type=typ) - if portal_type is None: - return None - - # The code bellow is inspired from ERP5Type.Core.Folder.newContent - pt = self._getTypesTool() - myType = pt.getTypeInfo(self) - if myType is not None and not myType.allowType( portal_type ) and \ - 'portal_contributions' not in self.getPhysicalPath(): - raise ValueError('Disallowed subobject type: %s' % portal_type) - container = portal.getDefaultModule(portal_type) - pt.constructContent(type_name=portal_type, - container=container, - id=name) - - document = container._getOb(name) - return document +from webdav.common import Locked, PreconditionFailed +from webdav.interfaces import IWriteLock +from webdav.NullResource import NullResource +from zope.contenttype import guess_content_type +NullResource_PUT = NullResource.PUT + +def PUT(self, REQUEST, RESPONSE): + """Create a new non-collection resource. + """ + if getattr(self.__parent__, 'PUT_factory', None) is not None: # BBB + return NullResource_PUT(self, REQUEST, RESPONSE) + + self.dav__init(REQUEST, RESPONSE) + + name = self.__name__ + parent = self.__parent__ + + ifhdr = REQUEST.get_header('If', '') + if IWriteLock.providedBy(parent) and parent.wl_isLocked(): + if ifhdr: + parent.dav__simpleifhandler(REQUEST, RESPONSE, col=1) + else: + # There was no If header at all, and our parent is locked, + # so we fail here + raise Locked + elif ifhdr: + # There was an If header, but the parent is not locked + raise PreconditionFailed + + # <ERP5> + # XXX: Do we really want to force 'id' + # when PUT is called on Contribution Tool ? + kw = {'id': name, 'data': None, 'filename': name} + contribution_tool = parent.getPortalObject().portal_contributions + if aq_base(contribution_tool) is not aq_base(parent): + kw.update(container=parent, discover_metadata=False) + ob = contribution_tool.newContent(**kw) + # </ERP5> + + ob.PUT(REQUEST, RESPONSE) + RESPONSE.setStatus(201) + RESPONSE.setBody('') + return RESPONSE + +NullResource.PUT = PUT -- 2.30.9