[Zope3-checkins] SVN: Zope3/branches/isarsprint-dav-work/src/zope/app/dav/ First cut at PROPPATCH code; based on PROPFIND code, no actual property

Martijn Pieters mj at zopatista.com
Sun Oct 10 06:28:52 EDT 2004


Log message for revision 27883:
  First cut at PROPPATCH code; based on PROPFIND code, no actual property
  patching functionality implemented yet.
  


Changed:
  U   Zope3/branches/isarsprint-dav-work/src/zope/app/dav/configure.zcml
  A   Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py
  A   Zope3/branches/isarsprint-dav-work/src/zope/app/dav/tests/test_proppatch.py


-=-
Modified: Zope3/branches/isarsprint-dav-work/src/zope/app/dav/configure.zcml
===================================================================
--- Zope3/branches/isarsprint-dav-work/src/zope/app/dav/configure.zcml	2004-10-10 10:23:51 UTC (rev 27882)
+++ Zope3/branches/isarsprint-dav-work/src/zope/app/dav/configure.zcml	2004-10-10 10:28:52 UTC (rev 27883)
@@ -11,6 +11,14 @@
       allowed_attributes="PROPFIND setDepth getDepth" />
   
   <view
+      for="*"
+      name="PROPPATCH"
+      type="zope.publisher.interfaces.http.IHTTPRequest"
+      factory=".proppatch.PROPPATCH"
+      permission="zope.ManageContent"
+      allowed_attributes="PROPPATCH" />
+  
+  <view
       for="zope.app.http.interfaces.INullResource"
       name="MKCOL"
       type="zope.publisher.interfaces.http.IHTTPRequest"

Added: Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py
===================================================================
--- Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py	2004-10-10 10:23:51 UTC (rev 27882)
+++ Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py	2004-10-10 10:28:52 UTC (rev 27883)
@@ -0,0 +1,68 @@
+##############################################################################
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+##############################################################################
+"""WebDAV method PROPPATCH
+
+$Id: propfind.py 27237 2004-08-23 23:42:11Z jim $
+"""
+__docformat__ = 'restructuredtext'
+
+from xml.dom import minidom
+
+from zope.app import zapi
+from zope.app.container.interfaces import IReadContainer
+
+class PROPPATCH(object):
+    """PROPPATCH handler for all objects"""
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+        ct = request.getHeader('content-type', 'text/xml')
+        if ';' in ct:
+            parts = ct.split(';', 1)
+            self.content_type = parts[0].strip().lower()
+            self.content_type_params = parts[1].strip()
+        else:
+            self.content_type = ct.lower()
+            self.content_type_params = None
+        self.default_ns = 'DAV:'
+
+    def PROPPATCH(self):
+        request = self.request
+        resource_url = str(zapi.getView(self.context, 'absolute_url', request))
+        if IReadContainer.providedBy(self.context):
+            resource_url = resource_url + '/'
+        data = request.bodyFile
+        data.seek(0)
+        response = ''
+        body = ''
+
+        if self.content_type not in ['text/xml', 'application/xml']:
+            request.response.setStatus(400)
+            return body
+
+        xmldoc = minidom.parse(data)
+        response = minidom.Document()
+        ms = response.createElement('multistatus')
+        ms.setAttribute('xmlns', self.default_ns)
+        response.appendChild(ms)
+        re = response.createElement('response')
+        ms.appendChild(re)
+        href = response.createElement('href')
+        re.appendChild(href)
+        r_url = response.createTextNode(resource_url)
+        href.appendChild(r_url)
+
+        body = response.toxml().encode('utf-8')
+        request.response.setBody(body)
+        request.response.setStatus(207)
+        return body

Added: Zope3/branches/isarsprint-dav-work/src/zope/app/dav/tests/test_proppatch.py
===================================================================
--- Zope3/branches/isarsprint-dav-work/src/zope/app/dav/tests/test_proppatch.py	2004-10-10 10:23:51 UTC (rev 27882)
+++ Zope3/branches/isarsprint-dav-work/src/zope/app/dav/tests/test_proppatch.py	2004-10-10 10:28:52 UTC (rev 27883)
@@ -0,0 +1,165 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test the dav PROPPATCH interactions.
+
+$Id: test_directives.py 27844 2004-10-09 15:37:29Z mj $
+"""
+__docformat__ = 'restructuredtext'
+
+import unittest
+from StringIO import StringIO
+
+from zope.interface import Interface, implements, directlyProvides
+from zope.publisher.interfaces.http import IHTTPRequest
+	
+from zope.app import zapi
+from zope.app.tests import ztapi
+
+from zope.app.traversing.api import traverse
+from zope.publisher.browser import TestRequest
+from zope.app.site.tests.placefulsetup import PlacefulSetup
+from zope.app.traversing.browser import AbsoluteURL
+from zope.app.dublincore.interfaces import IZopeDublinCore
+from zope.app.dublincore.annotatableadapter import ZDCAnnotatableAdapter
+from zope.app.annotation.interfaces import IAnnotatable, IAnnotations
+from zope.app.annotation.attribute import AttributeAnnotations
+
+import zope.app.dav.tests
+from zope.app.dav.tests.unitfixtures import File, Folder, FooZPT
+
+from zope.app.dav import proppatch
+from zope.app.dav.interfaces import IDAVSchema
+from zope.app.dav.interfaces import IDAVNamespace
+
+def _createRequest(body=None, headers=None, skip_headers=None,
+                   namespaces=(('Z', 'http://www.w3.com/standards/z39.50/'),),
+                   set=('<Z:authors>\n<Z:Author>Jim Whitehead</Z:Author>\n',
+                        '<Z:Author>Roy Fielding</Z:Author>\n</Z:authors>'),
+                   remove=('<D:prop><Z:Copyright-Owner/></D:prop>\n')):
+    if body is None:
+        setProps = removeProps = ''
+        if set:
+            setProps = '<set><prop>\n%s\n</prop></set>\n' % (''.join(set))
+        if remove:
+            removeProps = '<remove><prop>\n%s\n</prop></remove>\n' % (
+                ''.join(remove))
+            
+        body = '''<?xml version="1.0"  ?>
+
+        <propertyupdate xmlns="DAV:"
+                        xmlns:Z="http://www.w3.com/standards/z39.50/">
+        %s
+        </propertyupdate>
+        ''' % (setProps + removeProps)
+
+    _environ = {'CONTENT_TYPE': 'text/xml',
+                'CONTENT_LENGTH': str(len(body))}
+
+    if headers is not None:
+        for key, value in headers.items():
+            _environ[key.upper().replace("-", "_")] = value
+
+    if skip_headers is not None:
+        for key in skip_headers:
+            if _environ.has_key(key.upper()):
+                del _environ[key.upper()]
+
+    request = TestRequest(StringIO(body), StringIO(), _environ)
+    return request
+
+class PropFindTests(PlacefulSetup, unittest.TestCase):
+
+    def setUp(self):
+        PlacefulSetup.setUp(self)
+        PlacefulSetup.buildFolders(self)
+        root = self.rootFolder
+        zpt = FooZPT()
+        self.content = "some content\n for testing"
+        file = File('spam', 'text/plain', self.content)
+        folder = Folder('bla')
+        root['file'] = file
+        root['zpt'] = zpt
+        root['folder'] = folder
+        self.zpt = traverse(root, 'zpt')
+        self.file = traverse(root, 'file')
+        ztapi.provideView(None, IHTTPRequest, Interface,
+                          'absolute_url', AbsoluteURL)
+        ztapi.provideView(None, IHTTPRequest, Interface,
+                          'PROPPATCH', proppatch.PROPPATCH)
+        ztapi.provideAdapter(IAnnotatable, IAnnotations, AttributeAnnotations)
+        ztapi.provideAdapter(IAnnotatable, IZopeDublinCore,
+                             ZDCAnnotatableAdapter)
+        utils = zapi.getGlobalService('Utilities')
+        directlyProvides(IDAVSchema, IDAVNamespace)
+        utils.provideUtility(IDAVNamespace, IDAVSchema, 'DAV:')
+        directlyProvides(IZopeDublinCore, IDAVNamespace)
+        utils.provideUtility(IDAVNamespace, IZopeDublinCore,
+                             'http://www.purl.org/dc/1.1')
+
+    def test_contenttype1(self):
+        file = self.file
+        request = _createRequest(headers={'Content-type':'text/xml'})
+        ppatch = proppatch.PROPPATCH(file, request)
+        ppatch.PROPPATCH()
+        # Check HTTP Response
+        self.assertEqual(request.response.getStatus(), 207)
+
+    def test_contenttype2(self):
+        file = self.file
+        request = _createRequest(headers={'Content-type':'application/xml'})
+
+        ppatch = proppatch.PROPPATCH(file, request)
+        ppatch.PROPPATCH()
+        # Check HTTP Response
+        self.assertEqual(request.response.getStatus(), 207)
+
+    def test_contenttype3(self):
+        # Check for an appropriate response when the content-type has
+        # parameters, and that the major/minor parts are treated in a
+        # case-insensitive way.
+        file = self.file
+        request = _createRequest(headers={'Content-type':
+                                          'TEXT/XML; charset="utf-8"'})
+        ppatch = proppatch.PROPPATCH(file, request)
+        ppatch.PROPPATCH()
+        # Check HTTP Response
+        self.assertEqual(request.response.getStatus(), 207)
+
+    def test_bad_contenttype(self):
+        file = self.file
+        request = _createRequest(headers={'Content-type':'text/foo'})
+
+        ppatch = proppatch.PROPPATCH(file, request)
+        ppatch.PROPPATCH()
+        # Check HTTP Response
+        self.assertEqual(request.response.getStatus(), 400)
+
+    def test_no_contenttype(self):
+        file = self.file
+        request = _createRequest(skip_headers=('content-type'))
+
+        ppatch = proppatch.PROPPATCH(file, request)
+        ppatch.PROPPATCH()
+        # Check HTTP Response
+        self.assertEqual(request.response.getStatus(), 207)
+        self.assertEqual(ppatch.content_type, 'text/xml')
+
+    
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(PropFindTests),
+        ))
+
+if __name__ == '__main__':
+    unittest.main()



More information about the Zope3-Checkins mailing list