[Zope3-checkins]
SVN: Zope3/branches/mkerrin-webdav/src/zope/app/dav/
This is my first implementation of the namespace manager has
Michael Kerrin
michael.kerrin at openapp.biz
Fri Feb 17 07:35:03 EST 2006
Log message for revision 41639:
This is my first implementation of the namespace manager has
proposed at http://www.zope.org/Members/mkerrin/WebDAVProposal
This includes a new way of configuring WebDAV namespaces has
outlined in the proposal.
Hooked up the namespace manager to the PROPFIND method only. The
other DAV methods will follow.
Added new experimental WebDAV request object to handle WebDAV
specific traversal.
This breaks dead properties support and the OPTIONS method but
I will get around to fixing these at a later date.
Changed:
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/DEPENDENCIES.cfg
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/adapter.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/common.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/configure.zcml
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/dav.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_locking.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_propfind.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/interfaces.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/meta.zcml
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/metaconfigure.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/metadirectives.py
A Zope3/branches/mkerrin-webdav/src/zope/app/dav/namespaces.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py
A Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davduplicateproperty.zcml
A Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davnamespace.zcml
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_locking.py
A Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_namespace.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py
A Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/xmldiff.py
U Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py
-=-
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/DEPENDENCIES.cfg
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/DEPENDENCIES.cfg 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/DEPENDENCIES.cfg 2006-02-17 12:35:02 UTC (rev 41639)
@@ -2,6 +2,7 @@
transaction
zope.app
zope.app.locking
+zope.app.copypastemove
zope.component
zope.configuration
zope.interface
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/adapter.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/adapter.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/adapter.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -22,7 +22,8 @@
from zope.interface import Interface, implements
from zope.app import zapi
-from zope.app.dav.interfaces import IDAVSchema, IDAVActiveLock, IDAVLockEntry
+from zope.app.dav.interfaces import IDAVSchema, IActiveLock, ILockEntry, \
+ IDAVLockSchema, IDAVResourceSchema
from zope.app.dublincore.interfaces import IDCTimes
from zope.app.filerepresentation.interfaces import IReadDirectory
from zope.app.size.interfaces import ISized
@@ -30,6 +31,37 @@
from zope.app.locking.interfaces import ILockable
+class DAVLockSchemaAdapter(object):
+ implements(IDAVLockSchema)
+
+ def __init__(self, context):
+ self.context = context
+
+ def supportedlock(self):
+ return ILockEntry(self.context, None)
+ supportedlock = property(supportedlock)
+
+ def lockdiscovery(self):
+ lockable = ILockable(self.context, None)
+ if lockable is None or not lockable.locked():
+ return None
+ return IActiveLock(self.context, None)
+ lockdiscovery = property(lockdiscovery)
+
+
+class DAVResourceAdapter(object):
+ """Defines a standard default resourcetype property value of None.
+
+ This is the only mandatory property defined with the DAV: namespace.
+ """
+ implements(IDAVResourceSchema)
+
+ def __init__(self, context):
+ self.context = context
+
+ resourcetype = None
+
+
class DAVSchemaAdapter(object):
"""An adapter for all content objects that provides the basic DAV
schema/namespace."""
@@ -88,27 +120,25 @@
def getlastmodified(self):
dc = IDCTimes(self.context, None)
- if dc is None or dc.created is None:
+ if dc is None or dc.modified is None:
return None
return dc.modified
getlastmodified = property(getlastmodified)
def supportedlock(self):
- return IDAVLockEntry(self.context, None)
+ return ILockEntry(self.context, None)
supportedlock = property(supportedlock)
def lockdiscovery(self):
lockable = ILockable(self.context, None)
if lockable is None or not lockable.locked():
return None
- return IDAVActiveLock(self.context, None)
+ return IActiveLock(self.context, None)
lockdiscovery = property(lockdiscovery)
- source = None
-
class LockEntry(object):
- implements(IDAVLockEntry)
+ implements(ILockEntry)
def __init__(self, context):
pass
@@ -122,7 +152,7 @@
"""represent a locked object that is the context of this adapter should
be locked otherwise a TypeError is raised
"""
- implements(IDAVActiveLock)
+ implements(IActiveLock)
def __init__(self, context):
self.context = context
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/common.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/common.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/common.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -24,6 +24,7 @@
from zope.security.proxy import removeSecurityProxy
from zope.app import zapi
+from zope import component
from zope.app.container.interfaces import IReadContainer
@@ -155,3 +156,91 @@
if ns_prefix is not None:
el.setAttributeNS(ns, 'xmlns', ns_prefix)
return el
+
+################################################################################
+#
+# WebDAV Request and Request Factory
+#
+################################################################################
+
+from zope.publisher.http import HTTPResponse, HTTPRequest
+from zope.app.publication.http import HTTPPublication
+from zope.app.publication.interfaces import IRequestPublicationFactory
+from interfaces import IWebDAVRequest, IWebDAVRequestFactory
+
+
+class WebDAVResponse(HTTPResponse):
+ """
+ """
+ pass
+
+
+class WebDAVRequest(HTTPRequest):
+ implements(IWebDAVRequest)
+
+ def _createResponse(self):
+ """Create a specific WebDAV response object."""
+ return WebDAVResponse()
+
+
+class WebDAVPublication(HTTPPublication):
+ pass
+
+
+class WebDAVRequestFactory(object):
+ implements(IRequestPublicationFactory)
+
+ def canHandle(self, environment):
+ return True
+
+ def __call__(self):
+ request_class = component.queryUtility(
+ IWebDAVRequestFactory, default = WebDAVRequest)
+ return request_class, WebDAVPublication
+
+################################################################################
+#
+# WebDAV specific traversal. Needed in order to generate null resources.
+#
+################################################################################
+
+from zope.app.http import traversal
+from zope.app.http.put import NullResource
+from zope.publisher.interfaces import NotFound
+from zope.app.http.interfaces import INullResource
+from zope.app.container.interfaces import IContained
+from zope.app.container.contained import Contained
+from persistent import Persistent
+
+
+class LockNullResource(Persistent, Contained):
+ implements(INullResource, IContained)
+
+ def __init__(self, container, name):
+ # container is __parent__
+ # name is __name__
+ pass
+
+ @property
+ def container(self):
+ return self.__parent__
+
+ @property
+ def name(self):
+ return self.__name__
+
+
+class ContainerTraverser(traversal.ContainerTraverser):
+
+ def nullResource(self, request, name):
+ if request.getTraversalStack():
+ raise NotFound(self.context, name, request)
+
+ if request.method == 'MKCOL':
+ return NullResource(self.context, name)
+ elif request.method == 'LOCK':
+ lnr = LockNullResource(self.context, name)
+ self.context[name] = lnr
+ return lnr
+
+ raise NotFound(self.context, name, request)
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/configure.zcml
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/configure.zcml 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/configure.zcml 2006-02-17 12:35:02 UTC (rev 41639)
@@ -2,10 +2,33 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:dav="http://namespaces.zope.org/dav">
+ <publisher
+ name="WEBDAV"
+ factory=".common.WebDAVRequestFactory"
+ methods="PROPFIND PROPPATCH MKCOL LOCK UNLOCK COPY MOVE"
+ priority="30"
+ />
+
+ <content class=".common.LockNullResource">
+ <allow interface="zope.app.http.interfaces.INullResource" />
+ </content>
+
<view
+ for="zope.app.container.interfaces.ISimpleReadContainer"
+ type=".interfaces.IWebDAVRequest"
+ provides="zope.publisher.interfaces.IPublishTraverse"
+ factory=".common.ContainerTraverser"
+ permission="zope.Public"
+ allowed_interface="zope.publisher.interfaces.IPublishTraverse"
+ />
+
+ <!--
+ WebDAV method definitions.
+ -->
+ <view
for="*"
name="PROPFIND"
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
factory=".propfind.PROPFIND"
permission="zope.ManageContent"
allowed_attributes="PROPFIND setDepth getDepth" />
@@ -13,7 +36,7 @@
<view
for="*"
name="PROPPATCH"
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
factory=".proppatch.PROPPATCH"
permission="zope.ManageContent"
allowed_attributes="PROPPATCH" />
@@ -21,7 +44,7 @@
<view
for="zope.app.http.interfaces.INullResource"
name="MKCOL"
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
factory=".mkcol.NullResource"
permission="zope.ManageContent"
allowed_attributes="MKCOL" />
@@ -29,7 +52,7 @@
<view
for="*"
name="MKCOL"
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
factory=".mkcol.MKCOL"
permission="zope.ManageContent"
allowed_attributes="MKCOL" />
@@ -40,7 +63,7 @@
<view
for="zope.interface.Interface"
name="LOCK"
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
factory=".locking.LOCKMethodFactory"
permission="zope.ManageContent"
allowed_attributes="LOCK"
@@ -49,7 +72,7 @@
<view
for="zope.interface.Interface"
name="UNLOCK"
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
factory=".locking.UNLOCKMethodFactory"
permission="zope.ManageContent"
allowed_attributes="UNLOCK"
@@ -68,28 +91,42 @@
<view
for="zope.interface.Interface"
name="COPY"
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
factory=".copy.COPY"
permission="zope.ManageContent"
allowed_attributes="COPY"
/>
<adapter
- provides="zope.app.dav.interfaces.IDAVSchema"
+ for="zope.app.http.interfaces.INullResource"
+ provides="zope.app.dav.interfaces.IDAVLockSchema"
+ permission="zope.Public"
+ factory=".adapter.DAVLockSchemaAdapter"
+ />
+
+ <adapter
for="zope.interface.Interface"
+ provides="zope.app.dav.interfaces.IDAVResourceSchema"
permission="zope.Public"
+ factory=".adapter.DAVResourceAdapter"
+ />
+
+ <adapter
+ provides="zope.app.dav.interfaces.IDAVSchema"
+ for="zope.app.annotation.interfaces.IAnnotatable"
+ permission="zope.Public"
factory=".adapter.DAVSchemaAdapter"
/>
<adapter
- provides="zope.app.dav.interfaces.IDAVActiveLock"
+ provides="zope.app.dav.interfaces.IActiveLock"
for="zope.interface.Interface"
permission="zope.Public"
factory=".adapter.ActiveLock"
/>
<adapter
- provides="zope.app.dav.interfaces.IDAVLockEntry"
+ provides="zope.app.dav.interfaces.ILockEntry"
for="zope.interface.Interface"
permission="zope.Public"
factory=".adapter.LockEntry"
@@ -123,7 +160,7 @@
Define all the DAV widgets.
-->
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.IText"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.TextDAVWidget"
@@ -131,23 +168,31 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
- for="zope.schema.interfaces.IBytes"
+ type=".interfaces.IWebDAVRequest"
+ for="zope.schema.interfaces.ITextLine"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.TextDAVWidget"
permission="zope.Public"
/>
-
+
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.IInt"
provides="zope.app.dav.interfaces.IDAVWidget"
- factory="zope.app.dav.widget.TextDAVWidget"
+ factory="zope.app.dav.widget.IntDAVWidget"
permission="zope.Public"
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
+ for="zope.schema.interfaces.IBytes"
+ provides="zope.app.dav.interfaces.IDAVWidget"
+ factory="zope.app.dav.widget.TextDAVWidget"
+ permission="zope.Public"
+ />
+
+ <view
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.IFloat"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.TextDAVWidget"
@@ -155,7 +200,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.IDatetime"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.DatetimeDAVWidget"
@@ -163,7 +208,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.IDate"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.DateDAVWidget"
@@ -171,7 +216,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.ITuple"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.TupleDAVWidget"
@@ -179,7 +224,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.ISequence"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.SequenceDAVWidget"
@@ -187,7 +232,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.schema.interfaces.IList"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.ListDAVWidget"
@@ -195,7 +240,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.app.dav.fields.IXMLEmptyElementList"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.XMLEmptyElementListDAVWidget"
@@ -203,7 +248,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.app.dav.fields.IDAVXMLSubProperty"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.DAVXMLSubPropertyWidget"
@@ -211,7 +256,7 @@
/>
<view
- type="zope.publisher.interfaces.http.IHTTPRequest"
+ type=".interfaces.IWebDAVRequest"
for="zope.app.dav.fields.DAVOpaqueField"
provides="zope.app.dav.interfaces.IDAVWidget"
factory="zope.app.dav.widget.DAVOpaqueWidget"
@@ -226,4 +271,28 @@
for="DAV:"
interface="zope.app.dav.interfaces.IDAVSchema" />
+ <dav:namespace
+ namespace="http://purl.org/dc/1.1"
+ schemas="zope.app.dublincore.interfaces.IZopeDublinCore"
+ interfaceType=".interfaces.IDCDAVNamespaceType"
+ />
+
+ <dav:namespace
+ namespace="DAV:"
+ interfaceType=".interfaces.IDAVNamespaceType"
+ schemas=".interfaces.IDAVResourceSchema
+ .interfaces.IDAVCreationDate
+ .interfaces.IDAVDisplayName
+ .interfaces.IGETDependentDAVSchema
+ .interfaces.IDAVLockSchema
+ .interfaces.IOptionalDAVSchema
+ ">
+
+ <widget
+ propname="creationdate"
+ class=".widget.ISO8601DateDAVWidget"
+ />
+
+ </dav:namespace>
+
</configure>
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/dav.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/dav.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/dav.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -18,7 +18,10 @@
from persistent import Persistent
import transaction
from zope.interface import implements
-from zope.app.testing.functional import HTTPTestCase
+from zope.app.testing.functional import HTTPTestCase, FunctionalTestSetup
+from zope.publisher.http import HTTPRequest
+from zope.app.publication.http import HTTPPublication
+from zope.app.dav.common import WebDAVRequest, WebDAVPublication
from zope.app.folder import Folder
from zope.app.annotation.interfaces import IAttributeAnnotatable
@@ -53,3 +56,31 @@
page = Page()
page.source = content
self.createObject(path, page)
+
+ def makeRequest(self, path = '', basic = None, form = None, env = {},
+ instream = None):
+ method = env.get('REQUEST_METHOD', '')
+
+ if instream is None:
+ instream = ''
+
+ environment = {"HTTP_HOST": 'localhost',
+ "HTTP_REFERER": 'localhost'}
+ environment.update(env)
+
+ app = FunctionalTestSetup().getApplication()
+ if method in ('PROPFIND', 'PROPPATCH', 'MKCOL', 'LOCK', 'UNLOCK',
+ 'COPY', 'MOVE'):
+ request = app._request(path, instream,
+ environment = environment,
+ basic = basic, form = form,
+ request = WebDAVRequest,
+ publication = WebDAVPublication)
+ else:
+ request = app._request(path, instream,
+ environment=environment,
+ basic=basic, form=form,
+ request=HTTPRequest,
+ publication=HTTPPublication)
+
+ return request
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_locking.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_locking.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_locking.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -23,7 +23,7 @@
from zope.interface import Interface
from zope.app import zapi
-from zope.app.testing import setup, ztapi, functional
+from zope.app.testing import setup, ztapi
from zope.app.locking.interfaces import ILockStorage, ILockable
from zope.app.locking.storage import PersistentLockStorage
from zope.app.locking.adapter import LockingAdapterFactory, LockingPathAdapter
@@ -32,6 +32,7 @@
from zope.app.security.adapter import LocatingTrustedAdapterFactory
+from dav import DAVTestCase
def makeLockBody(data):
body = '''<?xml version="1.0" encoding="utf-8"?>
@@ -44,7 +45,7 @@
return body
-class TestAllowBefore(functional.HTTPTestCase):
+class TestAllowBefore(DAVTestCase):
# Test for the LOCK and UNLOCK in the Allow header. I use both a OPTIONS
# request and a 'FROGS' (undefined) request to test for this. The reason
# for two tests is that I ran into problems getting this to work with the
@@ -108,7 +109,7 @@
class TestLOCK(TestAllowBefore):
def setUp(self):
- functional.HTTPTestCase.setUp(self)
+ super(TestLOCK, self).setUp()
sm = zapi.getSiteManager(self.getRootFolder())
self.storage = storage = PersistentLockStorage()
@@ -126,12 +127,12 @@
del self.storage
def test_allow_options(self):
- super(TestLOCK, self)._test_allow_options(True)
+ self._test_allow_options(True)
def test_allow_publish(self):
## XXX - the LOCK, and UNLOCK methods should show up in the allow header
## for this test but I can't get this work.
- super(TestLOCK, self)._test_allow_publish(True)
+ self._test_allow_publish(True)
def test_lock_file_simple(self):
file = File('some content', 'text/plain')
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_propfind.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_propfind.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/ftests/test_propfind.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -63,15 +63,15 @@
self.verifyPropOK(path='/pt', ns='http://purl.org/dc/1.1',
prop='subjects', expect=expect, basic='mgr:mgrpw')
- def test_opaque(self):
- self.addPage('/pt', u'<span />')
- pt = traverse(self.getRootFolder(), '/pt')
- adapted = IDAVOpaqueNamespaces(pt)
- adapted[u'uri://bar'] = {u'foo': '<foo>spam</foo>'}
- transaction.commit()
- expect = 'spam'
- self.verifyPropOK(path='/pt', ns='uri://bar',
- prop='foo', expect=expect, basic='mgr:mgrpw')
+## def test_opaque(self):
+## self.addPage('/pt', u'<span />')
+## pt = traverse(self.getRootFolder(), '/pt')
+## adapted = IDAVOpaqueNamespaces(pt)
+## adapted[u'uri://bar'] = {u'foo': '<foo>spam</foo>'}
+## transaction.commit()
+## expect = 'spam'
+## self.verifyPropOK(path='/pt', ns='uri://bar',
+## prop='foo', expect=expect, basic='mgr:mgrpw')
def verifyPropOK(self, path, ns, prop, expect, basic):
body = """<?xml version="1.0" ?>
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/interfaces.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/interfaces.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/interfaces.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -17,11 +17,16 @@
"""
__docformat__ = 'restructuredtext'
-from zope.interface import Interface
+from zope.interface import Interface, Attribute
+from zope.interface.interfaces import IInterface
+from zope.interface.common.mapping import IEnumerableMapping
from zope.schema import Int, Text, TextLine, Dict, Datetime, Date, List, Bool
from zope.schema.interfaces import IText, IList
from zope.app.form.interfaces import IWidget
+from zope.publisher.interfaces.http import IHTTPRequest
+from zope.app.publication.interfaces import IRequestFactory
+
from fields import IXMLEmptyElementList, XMLEmptyElementList
from fields import IDAVXMLSubProperty, DAVXMLSubProperty, DAVOpaqueField
@@ -33,6 +38,42 @@
"""
+class IDAVNamespaceType(IInterface):
+ """This interface represents the WebDAV namespace schema defined
+ in RFC2518, RFC3744, ...
+
+ If an **interface** provides this interface type, then all adapters
+ providing the **interfaace** are considered WebDAV data adapters.
+ """
+
+
+class IDCDAVNamespaceType(IInterface):
+ """This interface represents the Dublin Core namespace.
+
+ If an **interface** provides this interface type, then all adapters
+ providing the **interface** are considered data adapters for the
+ DC properties.
+ """
+
+
+class IDAVResourceSchema(Interface):
+ """DAV properties required for Level 1 compliance"""
+
+ resourcetype = XMLEmptyElementList(
+ title = u'''Specifies the nature of the resource''',
+
+ description = u'''\
+ The resourcetype property MUST be
+ defined on all DAV compliant
+ resources. The default value is
+ empty.''',
+
+ readonly = True,
+
+ value_type = TextLine(title = u'resource type')
+ )
+
+
class IDAVCreationDate(Interface):
creationdate = Datetime(title=u'''Records the time and date the resource\
@@ -83,7 +124,7 @@
asserts no policy on ordering.''')
-class IOptionalDAVSchema(IDAVCreationDate, IDAVDisplayName, IDAVSource):
+class IOptionalDAVSchema(IDAVCreationDate, IDAVDisplayName):
"""DAV properties that SHOULD be present but are not required"""
@@ -153,24 +194,7 @@
readonly = True)
-class IDAVResourceSchema(Interface):
- """DAV properties required for Level 1 compliance"""
-
- resourcetype = XMLEmptyElementList(
- title = u'''Specifies the nature of the resource''',
-
- description = u'''\
- The resourcetype property MUST be
- defined on all DAV compliant
- resources. The default value is
- empty.''',
-
- readonly = True,
-
- value_type = TextLine(title = u'resource type')
- )
-
-class IDAVLockEntry(Interface):
+class ILockEntry(Interface):
"""A DAV Sub property of the supportedlock property.
"""
lockscope = XMLEmptyElementList(title = u'''\
@@ -180,8 +204,6 @@
Specifies whether a lock is an exclusive lock, or a
shared lock.''',
- readonly = True,
-
value_type = TextLine(title = u''))
locktype = XMLEmptyElementList(title = u'''\
@@ -192,33 +214,12 @@
this specification only defines one lock type, the
write lock.''',
- readonly = True,
-
value_type = TextLine(title = u''))
-class IDAVActiveLock(Interface):
+class IActiveLock(ILockEntry):
"""A DAV Sub property of the lockdiscovery property.
"""
- lockscope = XMLEmptyElementList(title = u'''\
- Describes the exclusivity of a lock''',
-
- description = u'''\
- Specifies whether a lock is an exclusive lock, or a
- shared lock.''',
-
- value_type = TextLine(title = u''))
-
- locktype = XMLEmptyElementList(title = u'''\
- Describes the access type of the lock''',
-
- description = u'''\
- Specifies the access type of a lock. At present,
- this specification only defines one lock type, the
- write lock.''',
-
- value_type = TextLine(title = u''))
-
depth = Text(title = u'Depth',
description = u'The value of the Depth header.')
@@ -265,7 +266,7 @@
prop_name = 'activelock',
- schema = IDAVActiveLock)
+ schema = IActiveLock)
supportedlock = DAVXMLSubProperty(title = u'''\
To provide a listing of the lock\
@@ -286,7 +287,7 @@
readonly = True,
- schema = IDAVLockEntry,
+ schema = ILockEntry,
prop_name = 'lockentry')
@@ -362,12 +363,18 @@
based on the field constraints.
"""
+ ## this shouldn't be used ???
def setRenderedValue(value):
"""Set the value of the field associated with this widget.
This value must validate to the type expected by the associated field.
"""
+ def setNamespace(ns, ns_prefix):
+ """Set the namespace and the namespace prefix. To be used when rendering
+ this widget.
+ """
+
def setProperty(propel):
"""Parse the DOM element ``propel`` and store the extracted value in
the widget.
@@ -375,8 +382,12 @@
The extracted value must validate against the associated field.
"""
- def renderProperty(ns, ns_prefix):
- """Render a property has a DOM elements.
+ def renderProperty():
+ """Render a property has a Python XML DOM element.
+
+ Use the setNamespace method to set the namespace and namespace prefix
+ to be used when rendering this property if it belongs to a different
+ WebDAV namespace other then the default DAV: namespace.
"""
## def removeProperty(self, ns, prop):
@@ -392,3 +403,100 @@
"""Return True / False wheather the current context and request
matches the the IF HTTP header has specified in RFC 2518
"""
+
+
+################################################################################
+#
+# Namespace Management.
+#
+################################################################################
+class INamespaceManager(Interface):
+ """One instance of this utility exists for each namespace known by the
+ system.
+
+ This utility is used to manage all the properties within a namespace. This
+ includes which properties are defined for an object, accessing these
+ properties, and finding what widgets are used to render these properties.
+ """
+
+ #
+ # Registration methods
+ #
+
+ def registerSchema(schema, restricted_properties = ()):
+ """Register the interface, schema, with the namespace manager. Each
+ field defined in the interface will define a property within the
+ namespace.
+
+ restricted_properties is a list of field names defined in schema
+ which whose corresponding property should not be rendered in
+ response to a PROPFIND request for all properties.
+ """
+
+ def registerWidget(propname, widget):
+ """Register a custom widget for the property named propname.
+
+ The widget is a callable taking the current bound field representing
+ the property named propname and the current request, On being called
+ widget must return an object implementing IDAVWidget.
+ """
+
+ #
+ # namespace management methods
+ #
+
+ def hasProperty(object, propname):
+ """This namespace has a property called propname defined for object.
+ """
+
+ def getProperty(object, propname):
+ """Get the field, propname, for this object, is it exists.
+
+ The returned value will implement zope.schema.interfaces.IField and will
+ be bound to the adapter defining the property propname.
+
+ Raises a TypeError / KeyError exception if the property named propname
+ is not defined for object.
+ """
+
+ def getWidget(object, request, propname, ns_prefix):
+ """Get the WebDAV widget to be used to render / store the property
+ propname.
+
+ The returned value is a WebDAV Widget and so will implement IDAVWidget.
+ By calling the renderProperty and setProperty on this object we will
+ be able to render the value of the property or set a value for this
+ property.
+
+ Raises a KeyError if the property named propname is not defined for
+ object.
+ """
+
+ def getAllPropertyNames(object, restricted = False):
+ """Return a list of all the property names that are defined on object.
+
+ If restricted is True then any defined property for object that is
+ registered has a restricted property is not returned in the generated
+ list of names.
+ """
+
+ def getAllProperties(object, restricted = False):
+ """Return all the properties defined within this namespace for this
+ object.
+
+ If restricted is True then don't return any property that is
+ registered has a restricted property.
+ """
+
+ def isRestrictedProperty(object, propname):
+ """Is the named property a restricted property for this object.
+ """
+
+
+class IWebDAVRequest(IHTTPRequest):
+ """
+ """
+
+
+class IWebDAVRequestFactory(IRequestFactory):
+ """WebDAV request factory."""
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -30,12 +30,14 @@
from zope.app.form.utility import setUpWidget
from zope.app.locking.interfaces import ILockable, ILockStorage, LockingError
from zope.app.container.interfaces import IReadContainer
+from zope.app.http.interfaces import INullResource
-from interfaces import IDAVWidget, IDAVActiveLock, IDAVLockEntry, \
- IDAVLockSchema, IIfHeader
+from interfaces import IDAVWidget, IActiveLock, ILockEntry, \
+ IDAVLockSchema, IIfHeader, IWebDAVRequest
from common import MultiStatus
MAXTIMEOUT = (2L**32)-1
+DEFAULTTIMEOUT = 12 * 60L
_randGen = random.Random(time.time())
@@ -69,10 +71,13 @@
stauts = 422
- at adapter(Interface, IHTTPRequest)
+ at adapter(Interface, IWebDAVRequest)
@implementer(Interface)
def LOCKMethodFactory(context, request):
- lockable = ILockable(context, None)
+ try:
+ lockable = ILockable(context, None)
+ except:
+ return None
if lockable is None:
return None
return LOCK(context, request)
@@ -92,11 +97,10 @@
else:
self.content_type = ct.lower()
self.content_type_params = None
+
self.default_ns = 'DAV:'
self.default_ns_prefix = None
- self.defaulttimeout = 12 * 60L
-
self.errorBody = None
def generateLockToken(self):
@@ -113,12 +117,12 @@
timeoutheader = timeoutheader.strip().lower()
t = str(timeoutheader).split('-')[-1]
if t == 'infinite' or t == 'infinity':
- timeout = self.defaulttimeout
+ timeout = DEFAULTTIMEOUT
else:
timeout = long(t)
if timeout > MAXTIMEOUT:
- timeout = self.defaulttimeout
+ timeout = DEFAULTTIMEOUT
return timeout
@@ -199,14 +203,14 @@
lockinfo['locktoken'] = \
'<locktoken><href>%s</href></locktoken>' % token
- adapted = IDAVActiveLock(object)
+ adapted = IActiveLock(object)
for node in xmldoc.childNodes:
if node.nodeType != node.ELEMENT_NODE:
continue
name = node.localName
- field = IDAVActiveLock[name]
+ field = IActiveLock[name]
setUpWidget(self, name, field, IDAVWidget, value = None,
ignoreStickyValues = False)
@@ -266,7 +270,7 @@
ignoreStickyValues = False)
widget = getattr(self, fieldname + '_widget', None)
assert widget is not None
- el = widget.renderProperty(ns, ns_prefix)
+ el = widget.renderProperty()
prop.appendChild(el)
body = resp.toxml('utf-8')
@@ -283,7 +287,10 @@
@adapter(Interface, IHTTPRequest)
@implementer(Interface)
def UNLOCKMethodFactory(context, request):
- lockable = ILockable(context, None)
+ try:
+ lockable = ILockable(context, None)
+ except:
+ return None
if lockable is None:
return None
return UNLOCK(context, request)
@@ -324,6 +331,8 @@
"lock tokens are not equal")
lockable.unlock()
+ if INullResource.providedBy(object):
+ del object.container[object.name]
# recurise into subfolders if we are a folder.
if IReadContainer.providedBy(object):
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/meta.zcml
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/meta.zcml 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/meta.zcml 2006-02-17 12:35:02 UTC (rev 41639)
@@ -2,11 +2,52 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta">
- <meta:directive
- namespace="http://namespaces.zope.org/dav"
- name="provideInterface"
- schema=".metadirectives.IProvideInterfaceDirective"
- handler=".metaconfigure.interface"
- />
+ <meta:directives namespace="http://namespaces.zope.org/dav">
+ <!--
+ old directive that will disappear later
+ -->
+ <meta:directive
+ name="provideInterface"
+ schema=".metadirectives.IProvideInterfaceDirective"
+ handler=".metaconfigure.interface"
+ />
+
+ <!--
+ new directives
+ -->
+ <meta:complexDirective
+ name="namespace"
+ schema=".metadirectives.INamespaceDirective"
+ handler=".metaconfigure.namespace">
+
+ <meta:subdirective
+ name="widget"
+ schema=".metadirectives.IWidgetSubDirective"
+ />
+
+ </meta:complexDirective>
+
+ <meta:complexDirective
+ name="schemas"
+ schema=".metadirectives.ISchemaDirective"
+ handler=".metaconfigure.schemas">
+
+ <meta:subdirective
+ name="widget"
+ schema=".metadirectives.IWidgetSubDirective"
+ />
+
+ </meta:complexDirective>
+
+ <meta:directive
+ name="widget"
+ schema=".metadirectives.IWidgetDirective"
+ handler=".metaconfigure.widget"
+ />
+
+ </meta:directives>
+
+ <meta:provides feature="webdav" />
+
</configure>
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/metaconfigure.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/metaconfigure.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/metaconfigure.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -17,10 +17,147 @@
"""
__docformat__ = 'restructuredtext'
+from zope import component
+from zope.schema import getFieldNamesInOrder
from zope.app.component.metaconfigure import utility
+from zope.app.component.metaconfigure import adapter
+from zope.app.component.interface import provideInterface
from zope.interface import directlyProvides
from interfaces import IDAVNamespace
+from interfaces import INamespaceManager
+from namespaces import NamespaceManager
+
def interface(_context, for_, interface):
directlyProvides(interface, IDAVNamespace)
utility(_context, IDAVNamespace, interface, name=for_)
+from zope.deprecation import deprecated
+deprecated(interface,
+ 'provideInterface is no more - use namespace, schemas directive')
+
+################################################################################
+#
+# New WebDAV registration.
+#
+################################################################################
+
+def _addWidgetToRegistry(registry, propertyname, class_):
+ registry.registerWidget(propertyname, class_)
+
+
+class namespace(object):
+ def __init__(self, _context, namespace, schemas = [],
+ restricted_properties = [], interfaceType = None):
+ self._context = _context
+ self.namespace = namespace
+ self.schemas = schemas
+ self.restricted_properties = restricted_properties
+ self.interfaceType = interfaceType
+
+ self.widgets = {}
+
+ def widget(self, _context, propname, class_):
+ self.widgets[propname] = class_
+
+ def __call__(self):
+ registry = NamespaceManager(self.namespace, self.schemas,
+ self.restricted_properties,
+ self.interfaceType)
+
+ #
+ # Create a new INamespaceManager Utility
+ #
+ utility(self._context, INamespaceManager, registry,
+ name = self.namespace)
+
+ #
+ # Register all the widgets if they are specified
+ #
+ for prop, widgetclass in self.widgets.items():
+ registry.registerWidget(prop, widgetclass)
+
+ #
+ # Declare all schemas to implement the interfaceType if it is not None
+ #
+ if self.interfaceType is not None:
+ interfaceType = self.interfaceType
+ path = interfaceType.__module__ + '.' + interfaceType.__name__
+
+ self._context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = (path, interfaceType),
+ )
+
+ for schema in self.schemas:
+ self._context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', schema, interfaceType),
+ )
+
+
+class schemas(object):
+ def __init__(self, _context, namespace, schemas,
+ restricted_properties = ()):
+ self._context = _context
+ self.namespace = namespace
+ self.schemas = schemas
+ self.restricted_properties = restricted_properties
+ self.widgets = {}
+
+ def widget(self, _context, propname, class_):
+ self.widgets[propname] = class_
+
+ def callaction(self):
+ registry = component.getUtility(INamespaceManager, self.namespace)
+ #
+ # Register all the schemas
+ #
+ for schema in self.schemas:
+ registry.registerSchema(schema, self.restricted_properties)
+
+ #
+ # Register all the widgets
+ #
+ for prop, widgetclass in self.widgets.items():
+ registry.registerWidget(prop, widgetclass)
+
+ #
+ # Declare all interface to implement interfaceType since we want
+ # these interfaces to show up in the APIDOC tool.
+ #
+ if registry.interfaceType is not None:
+ for schema in self.schemas:
+ provideInterface('', schema, registry.interfaceType)
+
+ def __call__(self):
+ #
+ # Need to make self.schemas hashable for the discriminator to work
+ # correctly - this could be done a lot nicer I am guesing.
+ #
+ discriminator = ('dav:schemas', self.namespace)
+ for schema in self.schemas:
+ discriminator += ('%s.%s' %(schema.__module__, schema.__name__),)
+ self._context.action(
+ discriminator = discriminator,
+ callable = self.callaction,
+ args = (),
+ )
+
+
+def widgetHandler(namespace, propname, class_):
+ registry = component.getUtility(INamespaceManager, namespace)
+ registry.registerWidget(propname, class_)
+
+
+def widget(_context, namespace, propname, class_):
+ #
+ # We can't just ask for the namespace here since it is unlikely to
+ # have being created yet.
+ #
+ _context.action(
+ discriminator = ('dav.namepsacewidget', namespace, propname),
+ callable = widgetHandler,
+ args = (namespace, propname, class_),
+ )
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/metadirectives.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/metadirectives.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/metadirectives.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -19,7 +19,7 @@
from zope.configuration.fields import GlobalInterface
from zope.interface import Interface
-from zope.schema import URI
+from zope.schema import URI, TextLine
class IProvideInterfaceDirective(Interface):
"""This directive assigns a new interface to a component. This interface
@@ -35,3 +35,84 @@
title=u"Interface",
description=u"Specifies an interface/schema for DAV.",
required=True)
+
+#
+# new WebDAV configuration.
+#
+
+from zope.configuration.fields import Tokens
+from zope.configuration.fields import GlobalObject
+from zope.configuration.fields import GlobalInterface
+
+
+class IBaseSchemaDirective(Interface):
+
+ namespace = URI(
+ title = u'Namespace',
+ description = u'Namespace under which this interface will be available'\
+ u' via DAV.',
+ required = True)
+
+ restricted_properties = Tokens(
+ title = u'Restricted Properties',
+ description = u'A list of property names that should not be rendered' \
+ u' has part of the allprop PROPFIND request',
+ required = False,
+ value_type = TextLine())
+
+class ISchemaDirective(IBaseSchemaDirective):
+ """Register a schema for a specified namespace
+ """
+
+ schemas = Tokens(
+ title = u'Schemas',
+ description = u'List of specific schema containing all the' \
+ u' properties to display',
+ required = True,
+ value_type = GlobalInterface())
+
+
+class INamespaceDirective(IBaseSchemaDirective):
+ """Registration new namespace with Zope.
+ """
+
+ schemas = Tokens(
+ title = u'Schemas',
+ description = u'List of specific schema containing all the' \
+ u' properties to display',
+ required = False,
+ value_type = GlobalInterface())
+
+ interfaceType = GlobalInterface(
+ title = u'Interface Type',
+ description = u'',
+ required = False)
+
+
+class IWidgetSubDirective(Interface):
+ """Register Custom WebDAV Widgets for a protocol.
+ """
+
+ propname = TextLine(
+ title = u'Property Name',
+ description = u"""
+ The name of the property / field for which this widget will be used.
+ """,
+ required = True)
+
+ class_ = GlobalObject(
+ title = u'WebDAV Widget Class',
+ description = u'The class that will create the widget',
+ required = True)
+
+
+class IWidgetDirective(IWidgetSubDirective):
+ """Register a custom IDAVWidget widget for a specific property within
+ the given namespace.
+ """
+
+ namespace = URI(
+ title = u'Namespace',
+ description = u'Namespace under which this custom widget will be' \
+ u' available.',
+ required = True)
Added: Zope3/branches/mkerrin-webdav/src/zope/app/dav/namespaces.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/namespaces.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/namespaces.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -0,0 +1,134 @@
+from zope.interface import Interface, implements, Attribute
+from zope import component
+from zope.schema import getFieldNamesInOrder, getFieldNames
+
+from interfaces import IDAVNamespaceType, IDAVWidget
+from interfaces import INamespaceManager
+
+
+class NamespaceManager(object):
+ implements(INamespaceManager)
+
+ def __init__(self, namespace, schemas = [], restricted_properties = [],
+ interfaceType = None):
+ self.namespace = namespace
+ # property name -> schema lookup, schema values should be the
+ # smallest possible schema containing the property.
+ self.properties = {}
+ # a list of property names which should not be listed and rendered
+ # in response to a allprop PROPFIND request.
+ self.restricted_properties = restricted_properties
+ # property name -> widget class to use when rendering a property.
+ self.widgets = {}
+ # optional interface to use with the APIDOC - all schemas will be
+ # declared to implement this interface type. Hence they will show
+ # up in the interface types section of the APIDOC tool.
+ self.interfaceType = interfaceType
+
+ for schema in schemas:
+ self.registerSchema(schema)
+
+ def registerSchema(self, schema, restricted_properties = []):
+ props = {}
+ for baseschema in (schema,) + schema.getBases():
+ for fieldname in getFieldNames(baseschema):
+ if props.has_key(fieldname):
+ oldschema = props[fieldname]
+ if oldschema.isOrExtends(baseschema):
+ pass
+ elif baseschema.isOrExtends(oldschema):
+ props[fieldname] = baseschema
+ else:
+ raise TypeError, "duplicate property in %s" % schema
+ props[fieldname] = baseschema
+
+ for propname in props:
+ if self.properties.has_key(propname):
+ oldschema = self.properties[propname]
+ newschema = props[propname]
+ if oldschema.isOrExtends(newschema):
+ pass
+ elif newschema.isOrExtends(oldschema):
+ self.properties[propname] = newschema
+ else:
+ raise TypeError, "duplicate property %s %s %s" %(
+ propname, schema, oldschema)
+ else:
+ self.properties[propname] = props[propname]
+
+ for propname in restricted_properties:
+ if not self.restricted_properties.has_key(propname):
+ self.restricted_properties.append(propname)
+
+ def registerWidget(self, propname, widget):
+ if not self.properties.has_key(propname):
+ raise TypeError, \
+ "There must exist a property for the widget you are registering"
+ self.widgets[propname] = widget
+
+ def _getAdapter(self, object, propname):
+ schema = self.properties.get(propname, None)
+ if schema is not None:
+ return component.queryAdapter(object, schema, default = None)
+
+ return None
+
+ def hasProperty(self, object, propname):
+ adapter = self._getAdapter(object, propname)
+ if adapter is None:
+ return False
+ return True
+
+ def getProperty(self, object, name):
+ adapter = self._getAdapter(object, name)
+ if adapter is None:
+ raise TypeError, "no property found"
+
+ field = self.properties[name][name]
+ field = field.bind(adapter)
+
+ return field
+
+ def getWidget(self, object, request, name, ns_prefix):
+ adapter = self._getAdapter(object, name)
+ if adapter is None:
+ raise TypeError, "no property found"
+
+ field = self.properties[name][name]
+ field = field.bind(adapter)
+
+ value = field.get(adapter)
+
+ if self.widgets.has_key(name):
+ widget = self.widgets[name](field, request)
+ else:
+ widget = component.getMultiAdapter((field, request), IDAVWidget)
+
+ widget.setRenderedValue(value)
+ widget.setNamespace(self.namespace, ns_prefix)
+
+ return widget
+
+ def getAllPropertyNames(self, object, restricted = False):
+ for propname, schema in self.properties.items():
+ adapter = component.queryAdapter(object, schema, default = None)
+ if adapter is not None and \
+ (restricted is False or \
+ propname not in self.restricted_properties):
+ yield propname
+
+ def getAllProperties(self, object, restricted = False):
+ for propname, schema in self.properties.items():
+ adapter = component.queryAdapter(object, schema, default = None)
+ if adapter is not None:
+ if restricted is False or \
+ propname not in self.restricted_properties:
+ field = schema[propname]
+ field = field.bind(adapter)
+ yield field
+
+ def isRestrictedProperty(self, object, name):
+ if self.hasProperty(object, name):
+ if name in self.restricted_properties:
+ return True
+ return False
Property changes on: Zope3/branches/mkerrin-webdav/src/zope/app/dav/namespaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -21,11 +21,11 @@
from zope.schema import getFieldNamesInOrder, getFields
from zope.publisher.http import status_reasons
-from zope.app import zapi
+from zope import component
from zope.app.container.interfaces import IReadContainer
from zope.app.form.utility import setUpWidget
-from interfaces import IDAVWidget, IDAVNamespace
+from interfaces import IDAVWidget, IDAVNamespace, INamespaceManager
from opaquenamespaces import IDAVOpaqueNamespaces
from common import MultiStatus
@@ -46,18 +46,6 @@
self.content_type_params = None
self.default_ns = 'DAV:'
- self.oprops = IDAVOpaqueNamespaces(self.context, None)
- _avail_props = {}
- # List all *registered* DAV interface namespaces and their properties
- for ns, iface in zapi.getUtilitiesFor(IDAVNamespace):
- _avail_props[ns] = getFieldNamesInOrder(iface)
-
- # List all opaque DAV namespaces and the properties we know of
- if self.oprops:
- for ns, oprops in self.oprops.items():
- _avail_props[ns] = list(oprops.keys())
- self.avail_props = _avail_props
-
self.responsedoc = MultiStatus()
def getDepth(self):
@@ -66,7 +54,7 @@
def setDepth(self, depth):
self._depth = depth.lower()
- def PROPFIND(self, xmldoc = None):
+ def PROPFIND(self):
if self.content_type not in ('text/xml', 'application/xml'):
self.request.response.setStatus(400)
return ''
@@ -74,11 +62,10 @@
self.request.response.setStatus(400)
return ''
- if xmldoc is None:
- try:
- xmldoc = minidom.parse(self.request.bodyStream)
- except expat.ExpatError:
- pass
+ try:
+ xmldoc = minidom.parse(self.request.bodyStream)
+ except expat.ExpatError:
+ xmldoc = None # request body is empty ???
self.handlePropfind(xmldoc)
@@ -97,12 +84,17 @@
propname = xmldoc.getElementsByTagNameNS(
self.default_ns, 'propname')
if propname:
- self._handlePropname(resp)
+ self._renderPropnameResponse(resp)
else:
source = xmldoc.getElementsByTagNameNS(self.default_ns, 'prop')
- self._handlePropvalues(source)
+ if len(source) == 0:
+ self._renderAllProperties(resp)
+ elif len(source) == 1:
+ self._renderSelectedProperties(resp, source[0])
+ else:
+ raise Exception, "something has gone wrong here"
else:
- self._handlePropvalues(None)
+ self._renderAllProperties(resp)
self._depthRecurse(xmldoc)
@@ -122,125 +114,66 @@
responses = subrespdoc.getElementsByTagNameNS(self.default_ns,
'response')
for r in responses:
- ## print "obj: %s, %s" %(zapi.getPath(obj), r.toxml('utf-8'))
self.responsedoc.appendResponse(r)
- def _handleProp(self, source):
- props = {}
- source = source[0]
-
- for node in source.childNodes:
- if node.nodeType != node.ELEMENT_NODE:
- continue
-
- ns = node.namespaceURI
- iface = zapi.queryUtility(IDAVNamespace, ns)
- value = props.get(ns, {'iface': iface, 'props': []})
- value['props'].append(node.localName)
- props[ns] = value
-
- return props
-
- def _handleAllprop(self):
- props = {}
-
- for ns, properties in self.avail_props.items():
- iface = zapi.queryUtility(IDAVNamespace, ns)
- props[ns] = {'iface': iface, 'props': properties}
-
- return props
-
- def _handlePropname(self, resp):
+ def _renderAllProperties(self, response):
count = 0
- for ns, props in self.avail_props.items():
- attr_name = 'a%s' % count
+
+ for namespace, nsmanager in \
+ component.getUtilitiesFor(INamespaceManager):
ns_prefix = None
- if ns is not None and ns != self.default_ns:
+ if namespace != self.default_ns:
+ ns_prefix = 'a%s' % count
count += 1
- ns_prefix = attr_name
- for p in props:
- el = resp.createEmptyElement(ns, ns_prefix, p)
- resp.addPropertyByStatus(ns, ns_prefix, el)
+ for propname in nsmanager.getAllPropertyNames(self.context):
+ widget = nsmanager.getWidget(self.context, self.request,
+ propname, ns_prefix)
+ el = widget.renderProperty()
+ response.addPropertyByStatus(namespace, ns_prefix, el, 200)
- def _handlePropvalues(self, source):
- if not source:
- _props = self._handleAllprop()
- else:
- _props = self._handleProp(source)
-
- self._renderResponse(self.resp, _props)
-
- def _renderResponse(self, re, _props):
+ def _renderSelectedProperties(self, response, source):
count = 0
- # ns - the full namespace for this object.
- for ns, ifaceprops in _props.items():
- attr_name = 'a%s' % count
- ns_prefix = None
- if ns is not None and ns != self.default_ns:
- count += 1
- ns_prefix = attr_name
+ renderedns = {}
- iface = ifaceprops['iface']
- props = ifaceprops['props']
-
- # adapted - the current view through which all properties are
- # reterived this should be moved to using the widget framework.
- if not iface:
- for name in props:
- if self.oprops:
- status = 200
- el = self.oprops.renderProperty(ns, ns_prefix, name)
- if el is None:
- # We can't add a None property in the MultiStatus
- # utility so add an empty property registered has
- # a 404 stats not found property.
- status = 404
- el = re.createEmptyElement(ns, ns_prefix, name)
- re.addPropertyByStatus(ns, ns_prefix, el, status)
- else:
- el = re.createEmptyElement(ns, ns_prefix, name)
- re.addPropertyByStatus(ns, ns_prefix, el, 404)
+ for node in source.childNodes:
+ if node.nodeType != node.ELEMENT_NODE:
continue
- adapted = iface(self.context, None)
- if adapted is None:
- # XXX - maybe these properties are unavailable for a reason.
- # render unavailable properties
- for propname in props:
- el = re.createEmptyElement(ns, ns_prefix, propname)
- re.addPropertyByStatus(ns, ns_prefix, el, 404)
- continue
+ namespace = node.namespaceURI
+ propname = node.localName
+ status = 200
- for propname in props:
- status = 200
- el = None # property DOM fragment
- field = None
+ ns_prefix = None
+ if not renderedns.has_key(namespace) and \
+ namespace != self.default_ns:
+ ns_prefix = 'a%s' % count
+ count += 1
+ elif namespace != self.default_ns:
+ ns_prefix = renderedns[namespace]
- try:
- field = iface[propname]
- except KeyError:
- # A widget wasn't generated for this property
- # because the attribute was missing on the adapted
- # object, which actually means that the adapter
- # didn't fully implement the interface ;(
- el = re.createEmptyElement(ns, ns_prefix, propname)
- status = 404
+ nsmanager = component.queryUtility(INamespaceManager, namespace,
+ default = None)
- re.addPropertyByStatus(ns, ns_prefix, el, status)
- continue
+ if nsmanager is not None:
+ if nsmanager.hasProperty(self.context, propname):
+ widget = nsmanager.getWidget(self.context, self.request,
+ propname, ns_prefix)
+ el = widget.renderProperty()
+ else:
+ el = response.createEmptyElement(namespace, ns_prefix,
+ propname)
+ status = 404
- try:
- setUpWidget(self, propname, field, IDAVWidget,
- value = field.get(adapted),
- ignoreStickyValues = False)
- widget = getattr(self, propname + '_widget', None)
- assert widget is not None
- el = widget.renderProperty(ns, ns_prefix)
- if widget.getErrors():
- status = 500
- except:
- # Internal Server Error - status 500
- el = re.createEmptyElement(ns, ns_prefix, propname)
- status = 500
+ response.addPropertyByStatus(namespace, ns_prefix, el, status)
- re.addPropertyByStatus(ns, ns_prefix, el, status)
+ def _renderPropnameResponse(self, response):
+ count = 0
+ for namespace, manager in component.getUtilitiesFor(INamespaceManager):
+ if namespace != self.default_ns:
+ ns_prefix = 'a%s' % count
+ count += 1
+ else:
+ ns_prefix = None
+ for propname in manager.getAllPropertyNames(self.context):
+ el = response.createEmptyElement(namespace, ns_prefix, propname)
+ response.addPropertyByStatus(namespace, ns_prefix, el, 200)
Added: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davduplicateproperty.zcml
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davduplicateproperty.zcml 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davduplicateproperty.zcml 2006-02-17 12:35:02 UTC (rev 41639)
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:dav="http://namespaces.zope.org/dav">
+
+ <include package="zope.app.dav" file="meta.zcml"/>
+
+ <dav:schemas
+ namespace="http://examplenamespace.org/dav/schema"
+ schemas=".test_namespace.IExampleDuplicateSchema"
+ />
+
+</configure>
Property changes on: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davduplicateproperty.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davnamespace.zcml
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davnamespace.zcml 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davnamespace.zcml 2006-02-17 12:35:02 UTC (rev 41639)
@@ -0,0 +1,26 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:dav="http://namespaces.zope.org/dav">
+
+ <include package="zope.app.dav" file="meta.zcml"/>
+
+ <dav:namespace
+ namespace="http://examplenamespace.org/dav/schema"
+ interfaceType=".test_namespace.IExampleNamespaceType"
+ />
+
+ <dav:schemas
+ namespace="http://examplenamespace.org/dav/schema"
+ schemas=".test_namespace.IExampleSchema"
+ />
+
+ <dav:schemas
+ namespace="http://examplenamespace.org/dav/schema"
+ schemas=".test_namespace.IExampleSchemaExtended"
+ />
+
+ <dav:schemas
+ namespace="http://examplenamespace.org/dav/schema"
+ schemas=".test_namespace.IExampleContactSchema"
+ />
+
+</configure>
Property changes on: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/davnamespace.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_locking.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_locking.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_locking.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -119,7 +119,7 @@
ztapi.provideUtility(ILockStorage, storage)
ztapi.provideUtility(ILockTracker, storage)
- ztapi.provideAdapter(Interface, interfaces.IDAVActiveLock,
+ ztapi.provideAdapter(Interface, interfaces.IActiveLock,
ActiveLock)
ztapi.provideAdapter(Interface, interfaces.IDAVLockSchema,
DAVSchemaAdapter)
Added: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_namespace.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_namespace.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_namespace.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -0,0 +1,269 @@
+##############################################################################
+#
+# Copyright (c) 2004 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 Zope WebDAV namespace registry.
+
+$Id:$
+"""
+import unittest
+from cStringIO import StringIO
+
+from zope.configuration import xmlconfig
+from zope.configuration.config import ConfigurationExecutionError
+from zope.interface.interfaces import IInterface
+from zope.interface.verify import verifyObject
+from zope.interface import Interface, implements
+import zope.app.dav.tests
+from zope.app.component.testing import PlacefulSetup
+
+from zope import component
+from zope.interface.declarations import directlyProvides
+from zope.schema import Int, TextLine
+from zope.schema.interfaces import IInt, ITextLine
+from zope.app.dav.namespaces import NamespaceManager
+from zope.app.dav.interfaces import INamespaceManager, IWebDAVRequest, \
+ IDAVWidget
+from zope.app.dav.common import WebDAVRequest
+from zope.app.dav.widget import IntDAVWidget, TextDAVWidget
+
+namespace = 'http://examplenamespace.org/dav/schema'
+
+#
+# Some Schema's to test for properties.
+#
+
+class IExampleNamespaceType(IInterface):
+ """ """
+
+class IExampleSchema(Interface):
+ """ """
+ age = Int(title = u'Age')
+
+ name = TextLine(title = u'Name')
+
+class IExampleExtendedSchema(IExampleSchema):
+ """ """
+ job = TextLine(title = u'Job Title')
+
+ company = TextLine(title = u'Place of employment')
+
+class IExampleContactSchema(Interface):
+ """ """
+ phoneNo = TextLine(title = u'Phone Number')
+
+class IExampleDuplicateSchema(Interface):
+ """ """
+ age = TextLine(title = u'Duplicate age property')
+
+#
+# Some interfaces and content objects and adapters to test the schemas against.
+#
+
+class IExampleContent(Interface):
+ """Marker interface for content objects...
+ """
+
+
+class IExampleExtendedContent(IExampleContent):
+ """Marker interface for content objects that will have the IExampleExtended
+ properties defined on them.
+ """
+
+
+class IExampleContactContent(Interface):
+ """Marker interface for content objects that have the IExampleContactSchema
+ properties defined on them.
+ """
+
+
+class Content(object):
+ implements(IExampleContent)
+
+ def __init__(self, parent, name):
+ self.__parent__ = parent
+ self.__name__ = name
+
+
+class ExampleAdapter(object):
+ implements(IExampleSchema)
+
+ def __init__(self, context):
+ self.context = context
+
+ @property
+ def age(self):
+ return 15
+
+ @property
+ def name(self):
+ return 'The Other Michael Kerrin'
+
+class ExampleExtendedAdapter(object):
+ implements(IExampleExtendedSchema)
+
+ def __init__(self, context):
+ self.context = context
+
+ @property
+ def age(self):
+ return 10
+
+ @property
+ def name(self):
+ return 'Michael Kerrin'
+
+ @property
+ def job(self):
+ return 'Programmer'
+
+ @property
+ def company(self):
+ return 'OpenApp'
+
+
+class ExampleContactAdapter(object):
+ implements(IExampleContactSchema)
+
+ def __init__(self, context):
+ self.context = context
+
+ @property
+ def phoneNo(self):
+ return '01 1234567'
+
+
+class TestNamespaceDirectives(unittest.TestCase):
+
+ def test_namespace_directives(self):
+ self.assertEqual(
+ component.queryUtility(INamespaceManager, namespace), None)
+ xmlconfig.XMLConfig("davnamespace.zcml", zope.app.dav.tests)()
+ nmanager = component.getUtility(INamespaceManager, namespace)
+ verifyObject(INamespaceManager, nmanager)
+ # quick check to see that schemas work
+ self.assert_(len(nmanager.properties) > 0)
+ # check that we correctly catch duplicate declarations of properties
+ self.assertRaises(ConfigurationExecutionError,
+ xmlconfig.XMLConfig("davduplicateproperty.zcml",
+ zope.app.dav.tests))
+
+
+class TestNamespaceRegistry(unittest.TestCase):
+
+ def setUp(self):
+ davnamespace = NamespaceManager(namespace,
+ schemas = (IExampleSchema,
+ IExampleExtendedSchema,
+ IExampleContactSchema))
+ component.provideUtility(davnamespace, INamespaceManager, namespace)
+
+ # all objects have the properties defined in IExampleSchema defined.
+ component.provideAdapter(ExampleAdapter, (IExampleContent,),
+ IExampleSchema)
+ component.provideAdapter(ExampleExtendedAdapter,
+ (IExampleExtendedContent,),
+ IExampleExtendedSchema)
+ component.provideAdapter(ExampleContactAdapter,
+ (IExampleContactContent,),
+ IExampleContactSchema)
+
+ # setup for widget adapters.
+ component.provideAdapter(IntDAVWidget, (IInt, IWebDAVRequest),
+ IDAVWidget)
+ component.provideAdapter(TextDAVWidget, (ITextLine, IWebDAVRequest),
+ IDAVWidget)
+
+ def test_correct_properties(self):
+ nr = component.getUtility(INamespaceManager, namespace)
+ expected = ['age', 'name', 'job', 'company', 'phoneNo']
+ expected.sort()
+ props = nr.properties.keys()
+ props.sort()
+ self.assertEqual(props, expected)
+
+ def test_correct_schema(self):
+ nr = component.getUtility(INamespaceManager, namespace)
+ ageschema = nr.properties['age']
+ jobschema = nr.properties['job']
+ self.assertEqual(ageschema, IExampleSchema)
+ self.assertEqual(jobschema, IExampleExtendedSchema)
+
+ def test_defined_properties(self):
+ # should be missing the phoneNo since no adapter exists.
+ nr = component.getUtility(INamespaceManager, namespace)
+ context = Content(None, 'contenttype')
+ names = list(nr.getAllPropertyNames(context))
+ names.sort()
+ self.assertEquals(names, ['age', 'name'])
+ # now extend the what the context object implements
+ directlyProvides(context, (IExampleExtendedContent,
+ IExampleContactContent))
+ names = list(nr.getAllPropertyNames(context))
+ names.sort()
+ self.assertEquals(names, ['age', 'company', 'job', 'name', 'phoneNo'])
+
+ def test_properties(self):
+ nr = component.getUtility(INamespaceManager, namespace)
+ context = Content(None, 'contenttype')
+ directlyProvides(context, (IExampleExtendedContent,
+ IExampleContactContent))
+ fields = list(nr.getAllProperties(context))
+
+ names = [field.getName() for field in fields]
+ names.sort()
+ self.assertEquals(names, ['age', 'company', 'job', 'name', 'phoneNo'])
+
+ #
+ # Assert that the adapters found via the namespace manager matches
+ # what we expect.
+ #
+ adapters = {'age': ExampleExtendedAdapter,
+ 'company': ExampleExtendedAdapter,
+ 'job': ExampleExtendedAdapter,
+ 'name': ExampleExtendedAdapter,
+ 'phoneNo': ExampleContactAdapter,
+ }
+ for name in names:
+ field = nr.getProperty(context, name)
+ self.assert_(isinstance(field.context, adapters[field.getName()]))
+
+ def test_widget(self):
+ nr = component.getUtility(INamespaceManager, namespace)
+ context = Content(None, 'contenttype')
+ instream = StringIO('')
+ request = WebDAVRequest(instream, {})
+
+ agewidget = nr.getWidget(context, request, 'age', 'a0')
+ self.assert_(isinstance(agewidget, IntDAVWidget))
+
+ namewidget = nr.getWidget(context, request, 'name', 'a0')
+ xmlel = namewidget.renderProperty()
+ self.assertEqual(xmlel.toxml(),
+ '<name xmlns="a0">The Other Michael Kerrin</name>')
+
+ def test_has_property(self):
+ nr = component.getUtility(INamespaceManager, namespace)
+ context = Content(None, 'contenttype')
+
+ self.assert_(nr.hasProperty(context, 'age'))
+ self.assert_(nr.hasProperty(context, 'job') is False)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestNamespaceRegistry))
+
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest = 'test_suite')
Property changes on: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_namespace.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -25,9 +25,11 @@
from zope.pagetemplate.tests.util import normalize_xml
from zope.schema import getFieldNamesInOrder
-from zope.schema.interfaces import IText, ITextLine, IDatetime, ISequence, IInt
+from zope.schema.interfaces import IText, ITextLine, IDatetime, ISequence, \
+ IList, IInt
-from zope.app import zapi
+from zope import component
+from zope.app.traversing.browser.absoluteurl import absoluteURL
from zope.app.testing import ztapi
from zope.app.traversing.api import traverse
@@ -48,16 +50,18 @@
from zope.app.dav.interfaces import IDAVWidget
from zope.app.dav.interfaces import IXMLEmptyElementList, XMLEmptyElementList
from zope.app.dav.widget import TextDAVWidget, DatetimeDAVWidget, \
- XMLEmptyElementListDAVWidget, SequenceDAVWidget, DAVXMLSubPropertyWidget, \
- DAVOpaqueWidget
+ XMLEmptyElementListDAVWidget, SequenceDAVWidget, ListDAVWidget, \
+ DAVXMLSubPropertyWidget, DAVOpaqueWidget, ISO8601DateDAVWidget
from zope.app.dav.opaquenamespaces import DAVOpaqueNamespacesAdapter
from zope.app.dav.opaquenamespaces import IDAVOpaqueNamespaces
from zope.app.dav.adapter import DAVSchemaAdapter
from zope.app.dav.fields import IDAVXMLSubProperty, IDAVOpaqueField
+from zope.app.dav.interfaces import INamespaceManager
+from zope.app.dav.namespaces import NamespaceManager
from unitfixtures import File, Folder, FooZPT
+import xmldiff
-
def _createRequest(body=None, headers=None, skip_headers=None):
if body is None:
body = '''<?xml version="1.0" encoding="utf-8"?>
@@ -99,8 +103,9 @@
def sizeForDisplay(self):
return 'big'
-class TestPlacefulPROPFIND(PlacefulSetup, TestCase):
+class TestPlacefulPROPFINDBase(PlacefulSetup, TestCase):
+
def setUp(self):
PlacefulSetup.setUp(self)
PlacefulSetup.buildFolders(self)
@@ -124,6 +129,7 @@
ztapi.browserViewProviding(ITextLine, TextDAVWidget, IDAVWidget)
ztapi.browserViewProviding(IDatetime, DatetimeDAVWidget, IDAVWidget)
ztapi.browserViewProviding(ISequence, SequenceDAVWidget, IDAVWidget)
+ ztapi.browserViewProviding(IList, ListDAVWidget, IDAVWidget)
ztapi.browserViewProviding(IXMLEmptyElementList,
XMLEmptyElementListDAVWidget, IDAVWidget)
ztapi.browserViewProviding(IDAVXMLSubProperty, DAVXMLSubPropertyWidget,
@@ -138,13 +144,51 @@
ztapi.provideAdapter(None, IDAVSchema,
DAVSchemaAdapter)
ztapi.provideAdapter(IFile, ISized, FileSized)
- sm = zapi.getGlobalSiteManager()
- directlyProvides(IDAVSchema, IDAVNamespace)
- sm.provideUtility(IDAVNamespace, IDAVSchema, 'DAV:')
- directlyProvides(IZopeDublinCore, IDAVNamespace)
- sm.provideUtility(IDAVNamespace, IZopeDublinCore,
- 'http://www.purl.org/dc/1.1')
+ # new webdav configuration
+ davnamespace = NamespaceManager('DAV:', schemas = (IDAVSchema,))
+ davnamespace.registerWidget('creationdate', ISO8601DateDAVWidget)
+ component.provideUtility(davnamespace, INamespaceManager, 'DAV:')
+
+ dcnamespace = NamespaceManager('http://www.purl.org/dc/1.1',
+ schemas = (IZopeDublinCore,))
+ component.provideUtility(dcnamespace, INamespaceManager,
+ 'http://www.purl.org/dc/1.1')
+
+ def _checkPropfind(self, obj, req, expect, depth='0', resp=None):
+ if req:
+ body = '''<?xml version="1.0" ?>
+ <propfind xmlns="DAV:">%s</propfind>
+ ''' % req
+ else:
+ body = ''
+ request = _createRequest(body=body, headers={
+ 'Content-type': 'text/xml', 'Depth': depth})
+ resource_url = absoluteURL(obj, request)
+ if IReadContainer.providedBy(obj):
+ resource_url += '/'
+ if resp is None:
+ resp = '''<?xml version="1.0" encoding="utf-8"?>
+ <multistatus xmlns="DAV:"><response>
+ <href>%%(resource_url)s</href>
+ <propstat>%s
+ <status>HTTP/1.1 200 OK</status>
+ </propstat></response></multistatus>
+ '''
+ expect = resp % expect
+ expect = expect % {'resource_url': resource_url}
+ pfind = propfind.PROPFIND(obj, request)
+ pfind.PROPFIND()
+ # Check HTTP Response
+ self.assertEqual(request.response.getStatus(), 207)
+ self.assertEqual(pfind.getDepth(), depth)
+ s1 = normalize_xml(request.response.consumeBody())
+ s2 = normalize_xml(expect)
+ xmldiff.compareMultiStatus(self, s1, s2)
+
+
+class TestPlacefulPROPFIND(TestPlacefulPROPFINDBase):
+
def test_contenttype1(self):
file = self.file
request = _createRequest(headers={'Content-type':'text/xml'})
@@ -247,37 +291,6 @@
self.assertEqual(request.response.getStatus(), 400)
self.assertEqual(pfind.getDepth(), 'full')
- def _checkPropfind(self, obj, req, expect, depth='0', resp=None):
- if req:
- body = '''<?xml version="1.0" ?>
- <propfind xmlns="DAV:">%s</propfind>
- ''' % req
- else:
- body = ''
- request = _createRequest(body=body, headers={
- 'Content-type': 'text/xml', 'Depth': depth})
- resource_url = zapi.absoluteURL(obj, request)
- if IReadContainer.providedBy(obj):
- resource_url += '/'
- if resp is None:
- resp = '''<?xml version="1.0" encoding="utf-8"?>
- <multistatus xmlns="DAV:"><response>
- <href>%%(resource_url)s</href>
- <propstat>%s
- <status>HTTP/1.1 200 OK</status>
- </propstat></response></multistatus>
- '''
- expect = resp % expect
- expect = expect % {'resource_url': resource_url}
- pfind = propfind.PROPFIND(obj, request)
- pfind.PROPFIND()
- # Check HTTP Response
- self.assertEqual(request.response.getStatus(), 207)
- self.assertEqual(pfind.getDepth(), depth)
- s1 = normalize_xml(request.response.consumeBody())
- s2 = normalize_xml(expect)
- self.assertEqual(s1, s2)
-
def test_resourcetype(self):
file = self.file
folder = traverse(self.rootFolder, 'folder')
@@ -296,6 +309,38 @@
self._checkPropfind(file, req, expect_file)
self._checkPropfind(folder, req, expect_folder)
+ def test_creationdate(self):
+ root = self.rootFolder
+ file = traverse(root, 'zpt')
+ dc = IZopeDublinCore(file)
+ dc.created = now = datetime.utcnow()
+
+ req = '''<prop>
+ <creationdate/>
+ </prop>
+ '''
+ expect_file = '''<prop>
+ <creationdate>%s</creationdate>
+ </prop>
+ ''' % now.strftime('%Y-%m-%dT%TZ')
+ self._checkPropfind(file, req, expect_file)
+
+ def test_lastmodifieddate(self):
+ root = self.rootFolder
+ file = traverse(root, 'zpt')
+ dc = IZopeDublinCore(file)
+ dc.modified = now = datetime.utcnow()
+
+ req = '''<prop>
+ <getlastmodified/>
+ </prop>
+ '''
+ expect_file = '''<prop>
+ <getlastmodified>%s</getlastmodified>
+ </prop>
+ ''' % now.strftime('%a, %d %b %Y %H:%M:%S +0000')
+ self._checkPropfind(file, req, expect_file)
+
def test_getcontentlength(self):
file = self.file
folder = traverse(self.rootFolder, 'folder')
@@ -353,8 +398,7 @@
dc.created = datetime.utcnow()
req = '''<prop xmlns:DC="http://www.purl.org/dc/1.1">
<DC:created /></prop>'''
- ## the format for the created date below is '%s' dc.created - changing
- ## to the format generated by the new date time dav widget
+
expect = '''<prop xmlns:a0="http://www.purl.org/dc/1.1">
<created xmlns="a0">%s</created></prop>''' % \
dc.created.strftime('%a, %d %b %Y %H:%M:%S %z').rstrip()
@@ -372,39 +416,54 @@
<subjects xmlns="a0">%s</subjects></prop>''' % u', '.join(dc.subjects)
self._checkPropfind(zpt, req, expect)
+ def test_davallprop(self):
+ req = '<allprop/>'
+
+ expect = ''
+ # set at list one value
+ dc = IZopeDublinCore(self.rootFolder)
+ dc.title = u'Root Folder'
+ props = getFieldNamesInOrder(IZopeDublinCore)
+ for p in props:
+ v = getattr(dc, p, '')
+ if not v:
+ v = ''
+ expect += '<%s xmlns="a0">%s</%s>' %(p, v, p)
+ props = getFieldNamesInOrder(IDAVSchema)
+ for p in props:
+ v = ''
+ expect += '<%s>%s</%s>' %(p, v, p)
+ expect = '<prop>%s</prop>' % expect
+ self._checkPropfind(self.rootFolder, req, expect)
+
def test_davpropname(self):
root = self.rootFolder
zpt = traverse(root, 'zpt')
- oprops = IDAVOpaqueNamespaces(zpt)
- oprops[u'http://foo/bar'] = {u'egg': '<egg>spam</egg>'}
req = '''<propname/>'''
expect = ''
props = getFieldNamesInOrder(IZopeDublinCore)
for p in props:
expect += '<%s xmlns="a0"/>' % p
- expect += '<egg xmlns="a1"/>'
props = getFieldNamesInOrder(IDAVSchema)
for p in props:
expect += '<%s/>' % p
expect = '''
- <prop xmlns:a0="http://www.purl.org/dc/1.1" xmlns:a1="http://foo/bar">
+ <prop xmlns:a0="http://www.purl.org/dc/1.1">
%s</prop>''' % expect
self._checkPropfind(zpt, req, expect)
def test_davpropnamefolderdepth0(self):
+ # DC properties are not supported on this folder object.
root = self.rootFolder
folder = traverse(root, 'folder')
req = '''<propname/>'''
expect = ''
- props = getFieldNamesInOrder(IZopeDublinCore)
- for p in props:
- expect += '<%s xmlns="a0"/>' % p
props = getFieldNamesInOrder(IDAVSchema)
for p in props:
expect += '<%s/>' % p
- expect = '''<prop xmlns:a0="http://www.purl.org/dc/1.1">
+ expect = '''<prop>
%s</prop>''' % expect
self._checkPropfind(folder, req, expect)
@@ -414,9 +473,6 @@
req = '''<propname/>'''
props_xml = ''
- props = getFieldNamesInOrder(IZopeDublinCore)
- for p in props:
- props_xml += '<%s xmlns="a0"/>' % p
props = getFieldNamesInOrder(IDAVSchema)
for p in props:
props_xml += '<%s/>' % p
@@ -425,7 +481,7 @@
for p in ('', '1', '2', 'sub1/'):
expect += '''
<response><href>%(path)s</href>
- <propstat><prop xmlns:a0="http://www.purl.org/dc/1.1">
+ <propstat><prop>
%(props_xml)s</prop><status>HTTP/1.1 200 OK</status>
</propstat></response>
''' % {'path': '%(resource_url)s' + p, 'props_xml': props_xml}
@@ -440,19 +496,15 @@
req = '''<propname/>'''
props_xml = ''
- props = getFieldNamesInOrder(IZopeDublinCore)
- for p in props:
- props_xml += '<%s xmlns="a0"/>' % p
props = getFieldNamesInOrder(IDAVSchema)
for p in props:
props_xml += '<%s/>' % p
-
expect = ''
for p in ('', '1', '2', 'sub1/', 'sub1/1', 'sub1/2', 'sub1/sub1/',
'sub1/sub1/last'):
expect += '''
<response><href>%(path)s</href>
- <propstat><prop xmlns:a0="http://www.purl.org/dc/1.1">
+ <propstat><prop>
%(props_xml)s</prop><status>HTTP/1.1 200 OK</status>
</propstat></response>
''' % {'path': '%(resource_url)s' + p, 'props_xml': props_xml}
@@ -461,10 +513,13 @@
<multistatus xmlns="DAV:">%s</multistatus>'''
self._checkPropfind(folder, req, expect, depth='infinity', resp=resp)
+#
+# opaque property support is now broken
+#
+
+class TestPlacefulDeadPropsPROPFIND(PlacefulSetup, TestCase):
+
def test_davemptybodyallpropzptdepth0(self):
- # XXX - this test is failing since the creationdate property is
- # currently not implemented properly.
-
# RFC 2518, Section 8.1: A client may choose not to submit a
# request body. An empty PROPFIND request body MUST be
# treated as a request for the names and values of all
@@ -478,10 +533,7 @@
req = ''
expect = ''
props = getFieldNamesInOrder(IZopeDublinCore)
- ## XXX - The created date below used to take the format defined in this
- ## comment. I need to need the date time specification for both DC and
- ## standard WebDAV.
- ## '%s+00:00' % now}
+ ## XXX - '%s+00:00' % now}
pvalues = {'created': now.strftime('%a, %d %b %Y %H:%M:%S %z').rstrip()}
for p in props:
if pvalues.has_key(p):
@@ -518,7 +570,7 @@
request = _createRequest(body = body,
headers = {'Content-type': 'text/xml',
'Depth': depth})
- resource_url = zapi.absoluteURL(zpt, request)
+ resource_url = absoluteURL(zpt, request)
resp = '''<?xml version="1.0" encoding="utf-8"?>
<multistatus xmlns="DAV:"><response>
<href>%(resource_url)s</href>
@@ -565,9 +617,12 @@
</egg></prop>'''
self._checkPropfind(zpt, req, expect)
+
def test_suite():
return TestSuite((
makeSuite(TestPlacefulPROPFIND),
+ ## XXX - fix deab properties support in zope.app.dav
+ ## makeSuite(TestPlacefulDeadPropsPROPFIND),
))
if __name__ == '__main__':
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -23,7 +23,7 @@
from zope.interface import Interface, implements
from zope.interface.verify import verifyClass
-from zope.schema import Text, Datetime, Date, List, Tuple
+from zope.schema import Text, Datetime, Date, List, Tuple, Int
from zope.schema import ValidationError
from zope.publisher.browser import TestRequest
from zope.testing.doctest import DocTestSuite
@@ -33,12 +33,14 @@
from zope.app.dav.interfaces import IDAVWidget
from zope.app.dav.widget import DAVWidget, TextDAVWidget, DatetimeDAVWidget, \
- DateDAVWidget, XMLEmptyElementListDAVWidget, TupleDAVWidget
+ DateDAVWidget, XMLEmptyElementListDAVWidget, TupleDAVWidget, IntDAVWidget
class DAVWidgetTest(placelesssetup.PlacelessSetup, TestCase):
+ # type of Field we are going to display during this test
_FieldFactory = Text
+ # type of DAV widget we are going to test
_WidgetFactory = DAVWidget
def setUp(self):
@@ -62,6 +64,9 @@
self.failUnless(verifyClass(IDAVWidget, DAVWidget))
def test_widget_input(self):
+ # make sure that the widget can handle an input value recevied via
+ # the setRenderedValue method. This method is only called rendering
+ # a property.
content = self.test_content
self.failIf(self._widget.hasInput())
@@ -71,6 +76,9 @@
self.assertEqual(self._widget.getInputValue(), content)
def _test_widget_bad_input(self, propel):
+ # helper method that tests setting a xml dom fragment that represents
+ # a property. propel should correspond to a correctly formatted
+ # property.
self._widget.setProperty(propel)
self.assert_(self._widget.hasInput())
self.failIf(self._widget.hasValidInput())
@@ -87,12 +95,27 @@
class TextDAVWidgetTest(DAVWidgetTest):
_WidgetFactory = TextDAVWidget
+ _FieldFactory = Text
test_content = u'This is some text content'
+
+class IntDAVWidgetTest(DAVWidgetTest):
+ _WidgetFactory = IntDAVWidget
+ _FieldFactory = Int
+
+ test_content = 10
+
+ def test_widget_bad_input(self):
+ doc = minidom.Document()
+ propel = doc.createElement('foo')
+ propel.appendChild(doc.createTextNode(u'This is NOT an integer'))
+ super(IntDAVWidgetTest, self)._test_widget_bad_input(propel)
+
+
class DatetimeDAVWidgetTest(DAVWidgetTest):
_WidgetFactory = DatetimeDAVWidget
- _FieldFactory = Datetime
+ _FieldFactory = Datetime
test_content = datetime.datetime.fromtimestamp(1131234842)
@@ -150,10 +173,9 @@
class XMLEmptyElementListDAVWidgetTest(DAVWidgetTest):
_WidgetFactory = XMLEmptyElementListDAVWidget
- _FieldFactory = List
+ _FieldFactory = List
test_content = [u'hello', u'there']
- test_bad_contents = [10, u'hello']
class TupleDAVWidgetTest(DAVWidgetTest):
@@ -161,12 +183,12 @@
_FieldFactory = Tuple
test_content = (u'hello', u'there')
- test_bad_contents = [10, u'hello']
def test_suite():
return TestSuite((
makeSuite(TextDAVWidgetTest),
+ makeSuite(IntDAVWidgetTest),
makeSuite(DatetimeDAVWidgetTest),
makeSuite(DateDAVWidgetTest),
makeSuite(XMLEmptyElementListDAVWidgetTest),
Added: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/xmldiff.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/xmldiff.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/xmldiff.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -0,0 +1,108 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""XML differences for use in testing the WebDAV code base
+
+$Id:$
+"""
+__docformat__ = 'restructuredtext'
+
+from xml.dom import minidom
+
+def getTextNode(self, el):
+ value = None
+ for node in el.childNodes:
+ if node.nodeType != node.TEXT_NODE:
+ continue
+ self.assert_(value is None)
+ value = node.nodeValue
+ return value
+
+def convertToDict(self, ms):
+ responses = {}
+
+ for response in ms.childNodes:
+ self.assertEqual(response.localName, 'response')
+
+ hrefel = response.getElementsByTagNameNS('DAV:', 'href')
+ self.assertEqual(len(hrefel), 1)
+ href = getTextNode(self, hrefel[0])
+ self.assert_(responses.has_key(href) is False)
+ propstats = responses[href] = {}
+
+ for propstat in response.getElementsByTagNameNS('DAV:', 'propstat'):
+ statusel = propstat.getElementsByTagNameNS('DAV:', 'status')
+ self.assertEqual(len(statusel), 1)
+ status = getTextNode(self, statusel[0])
+ properties = propstats[status] = {}
+ propel = propstat.getElementsByTagNameNS('DAV:', 'prop')
+ self.assertEqual(len(propel), 1)
+
+ for propertyel in propel[0].childNodes:
+ if propertyel.nodeType != propertyel.ELEMENT_NODE:
+ continue
+ ns = propertyel.namespaceURI
+ propname = propertyel.localName
+ value = propertyel.toxml()
+
+ nsprops = properties.setdefault(ns, {})
+ nsprops[propname] = value
+
+ return responses
+
+def compareMultiStatus(self, status1str, status2str):
+ s1 = minidom.parseString(status1str)
+ s2 = minidom.parseString(status2str)
+
+ ms1 = s1.documentElement
+ ms2 = s2.documentElement
+
+ self.assertEqual(ms1.localName, 'multistatus')
+ self.assertEqual(ms2.localName, 'multistatus')
+
+ resp1 = convertToDict(self, ms1)
+ resp2 = convertToDict(self, ms2)
+
+ self.assertEqual(len(resp1), len(resp2))
+ for href, status1 in resp1.items():
+ self.assert_(resp2.has_key(href),
+ "the expected result is missing a response for the" \
+ " %s object\n" \
+ "'%s' != '%s'" % (href, status1str, status2str))
+ status2 = resp2[href]
+
+ for status, namespaces1 in status1.items():
+ self.assert_(status2.has_key(status))
+ namespaces2 = status2[status]
+
+ self.assertEqual(len(namespaces1), len(namespaces2),
+ "namespace count doesn't match." \
+ "'%s' != '%s'" %(status1str, status2str))
+
+ for namespace, properties1 in namespaces1.items():
+ self.assert_(namespaces2.has_key(namespace),
+ "the namespace %s is missing from the " \
+ " expected result.\n" \
+ "'%s' != '%s'" % (namespace, status1str,
+ status2str))
+ properties2 = namespaces2[namespace]
+
+ self.assertEqual(len(properties1), len(properties2))
+
+ for propname, value1 in properties1.items():
+ self.assert_(properties2.has_key(propname),
+ "the property %s is missing from the " \
+ "expected result" % propname)
+ value2 = properties2[propname]
+
+ self.assertEqual(value1, value2)
Property changes on: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/xmldiff.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py 2006-02-17 11:07:32 UTC (rev 41638)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py 2006-02-17 12:35:02 UTC (rev 41639)
@@ -59,9 +59,10 @@
def getErrors(self):
return self._error
- def setNamespace(self, ns, ns_prefix):
- self.namespace = ns
- self.ns_prefix = ns_prefix
+ def setNamespace(self, namespace, namespace_prefix):
+ if namespace is not None:
+ self.namespace = namespace
+ self.ns_prefix = namespace_prefix
def setRenderedValue(self, value):
# don't use this
@@ -134,13 +135,11 @@
return str(value)
return None
- def renderProperty(self, ns, ns_prefix):
- self.setNamespace(ns, ns_prefix)
+ def renderProperty(self):
+ el = self._xmldoc.createElementNS(self.namespace, self.name)
+ if self.ns_prefix is not None:
+ el.setAttributeNS(self.namespace, 'xmlns', self.ns_prefix)
- el = self._xmldoc.createElementNS(ns, self.name)
- if ns_prefix is not None:
- el.setAttributeNS(ns, 'xmlns', ns_prefix)
-
# this is commented out because it cased some problems with values
# being security proxied when they they are returned from the adapters
## value = self._toDAVValue(self.getInputValue())
@@ -187,7 +186,7 @@
setUpWidget method
>>> widget.setRenderedValue(u'This is some content')
- >>> rendered = widget.renderProperty(None, None)
+ >>> rendered = widget.renderProperty()
>>> rendered #doctest:+ELLIPSIS
<DOM Element: foo at 0x...>
>>> rendered.toxml()
@@ -197,6 +196,41 @@
pass
+class IntDAVWidget(DAVWidget):
+ """
+ Renders a WebDAV property that contains an integer.
+
+ >>> from zope.schema import Int
+ >>> field = Int(__name__ = 'foo', title = u'Foo Title')
+ >>> request = TestRequest()
+ >>> widget = IntDAVWidget(field, request)
+
+ Set up the value stored in the widget. In reality this is done in the
+ setUpWidget method
+
+ >>> widget.setRenderedValue(10)
+ >>> rendered = widget.renderProperty()
+ >>> rendered #doctest:+ELLIPSIS
+ <DOM Element: foo at 0x...>
+ >>> rendered.toxml()
+ '<foo>10</foo>'
+ >>> widget.setProperty(rendered)
+
+ """
+
+ def _setFieldValue(self, value):
+ if not value.childNodes:
+ return self.context.missing_value
+
+ value = value.childNodes[0]
+ try:
+ return int(value.nodeValue)
+ except ValueError, e:
+ raise ConversionError("Invalid int data", e)
+
+ def _toDAVValue(self, value):
+ return str(value)
+
class DatetimeDAVWidget(DAVWidget):
"""Render a WebDAV date property
@@ -211,7 +245,7 @@
>>> from datetime import datetime
>>> date = datetime.utcfromtimestamp(1131233651)
>>> widget.setRenderedValue(date)
- >>> rendered = widget.renderProperty(None, None)
+ >>> rendered = widget.renderProperty()
>>> rendered #doctest:+ELLIPSIS
<DOM Element: foo at ...>
>>> rendered.toxml() # this was '<foo>2005-11-05 23:34:11Z</foo>'
@@ -236,20 +270,20 @@
return value.strftime('%a, %d %b %Y %H:%M:%S %z').rstrip()
-class CreatationDateDAVWidget(DAVWidget):
+class ISO8601DateDAVWidget(DAVWidget):
"""Render a WebDAV date property
>>> from zope.schema import Datetime
>>> field = Datetime(__name__ = 'foo', title = u'Foo Date Title')
>>> request = TestRequest()
- >>> widget = CreatationDateDAVWidget(field, request)
+ >>> widget = ISO8601DateDAVWidget(field, request)
Set the value of the widget to that of the current time.
>>> from datetime import datetime
>>> date = datetime.utcfromtimestamp(1131233651)
>>> widget.setRenderedValue(date)
- >>> rendered = widget.renderProperty(None, None)
+ >>> rendered = widget.renderProperty()
>>> rendered #doctest:+ELLIPSIS
<DOM Element: foo at ...>
>>> rendered.toxml()
@@ -279,7 +313,7 @@
>>> from datetime import datetime
>>> date = datetime.utcfromtimestamp(1131233651)
>>> widget.setRenderedValue(date)
- >>> rendered = widget.renderProperty(None, None)
+ >>> rendered = widget.renderProperty()
>>> rendered #doctest:+ELLIPSIS
<DOM Element: foo at ...>
>>> rendered.toxml() # this was '<foo>2005-11-05 23:34:11Z</foo>'
@@ -337,7 +371,7 @@
>>> request = TestRequest()
>>> widget = XMLEmptyElementListDAVWidget(field, request)
>>> widget.setRenderedValue(['first', 'second'])
- >>> rendered = widget.renderProperty(None, None)
+ >>> rendered = widget.renderProperty()
>>> rendered #doctest:+ELLIPSIS
<DOM Element: foo at ...>
>>> rendered.toxml()
@@ -387,7 +421,7 @@
assert widget is not None
## namespace information is not needed here since we set the
## default namespace on elements
- el = widget.renderProperty(self.namespace, self.ns_prefix)
+ el = widget.renderProperty() # self.namespace, self.ns_prefix)
if pname:
res.appendChild(el)
else:
@@ -398,23 +432,21 @@
class DAVOpaqueWidget(DAVWidget):
- def renderProperty(self, ns, ns_prefix):
- self.setNamespace(ns, ns_prefix)
-
+ def renderProperty(self):
value = self.getInputValue()
if value == self.context.missing_value:
- el = self._xmldoc.createElementNS(ns, self.name)
- if ns_prefix is not None:
- el.setAttributeNS(ns, 'xmlns', ns_prefix)
+ el = self._xmldoc.createElementNS(self.namespace, self.name)
+ if self.ns_prefix is not None:
+ el.setAttributeNS(self.namespace, 'xmlns', self.ns_prefix)
return el
el = minidom.parseString(value)
el = el.documentElement
- if ns_prefix is not None and el.attributes is not None:
+ if self.ns_prefix is not None and el.attributes is not None:
xmlns = el.attributes.getNamedItem('xmlns')
if xmlns is None:
- el.setAttributeNS(ns, 'xmlns', ns_prefix)
+ el.setAttributeNS(self.namespace, 'xmlns', self.ns_prefix)
return el
More information about the Zope3-Checkins
mailing list