[Zope3-checkins]
SVN: Zope3/branches/isarsprint-dav-work/src/zope/app/dav/
Full PROPPATCH support working;
now registered namespaces are supported too.
Martijn Pieters
mj at zopatista.com
Thu Oct 14 09:48:54 EDT 2004
Log message for revision 28184:
Full PROPPATCH support working; now registered namespaces are supported too.
Changed:
U Zope3/branches/isarsprint-dav-work/src/zope/app/dav/opaquenamespaces.py
U Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py
U Zope3/branches/isarsprint-dav-work/src/zope/app/dav/tests/test_proppatch.py
-=-
Modified: Zope3/branches/isarsprint-dav-work/src/zope/app/dav/opaquenamespaces.py
===================================================================
--- Zope3/branches/isarsprint-dav-work/src/zope/app/dav/opaquenamespaces.py 2004-10-14 13:47:41 UTC (rev 28183)
+++ Zope3/branches/isarsprint-dav-work/src/zope/app/dav/opaquenamespaces.py 2004-10-14 13:48:53 UTC (rev 28184)
@@ -108,6 +108,7 @@
#
# Convenience methods; storing and retrieving properties through WebDAV
+ # It may be better to use specialised IDAWWidget implementatins for this.
#
def renderProperty(self, ns, nsprefix, prop, propel):
"""Render a property as DOM elements"""
Modified: Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py
===================================================================
--- Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py 2004-10-14 13:47:41 UTC (rev 28183)
+++ Zope3/branches/isarsprint-dav-work/src/zope/app/dav/proppatch.py 2004-10-14 13:48:53 UTC (rev 28184)
@@ -19,11 +19,12 @@
import transaction
from zope.app import zapi
-from zope.schema import getFieldNamesInOrder
+from zope.schema import getFieldNamesInOrder, getFields
from zope.app.container.interfaces import IReadContainer
from zope.publisher.http import status_reasons
+from zope.app.form.utility import setUpWidget, no_value
-from interfaces import IDAVNamespace
+from interfaces import IDAVNamespace, IDAVWidget
from opaquenamespaces import IDAVOpaqueNamespaces
class PROPPATCH(object):
@@ -156,10 +157,32 @@
props.append(prop.localName)
return 200
return 403
-
- # XXX: Deal with registered ns interfaces here
- return 403
+
+ if not prop.localName in self.avail_props[ns]:
+ return 403 # Cannot add propeties to a registered schema
+
+ fields = getFields(iface)
+ field = fields[prop.localName]
+ if field.readonly:
+ return 409 # RFC 2518 specifies 409 for readonly props
+
+ value = field.get(iface(self.context))
+ if value is field.missing_value:
+ value = no_value
+ setUpWidget(self, prop.localName, field, IDAVWidget,
+ value=value, ignoreStickyValues=True)
+
+ widget = getattr(self, prop.localName + '_widget')
+ widget.setRenderedValue(prop)
+ if not widget.hasValidInput():
+ return 409 # Didn't match the widget validation
+
+ if widget.applyChanges(iface(self.context)):
+ return 200
+
+ return 422 # Field didn't accept the value
+
def _handleRemove(self, prop):
ns = prop.namespaceURI
if not prop.localName in self.avail_props.get(ns, []):
@@ -171,6 +194,20 @@
return 200
self.oprops.removeProperty(ns, prop.localName)
return 200
-
- # XXX: Deal with registered ns interfaces here
- return 403
+
+ # Registered interfaces
+ fields = getFields(iface)
+ field = fields[prop.localName]
+ if field.readonly:
+ return 409 # RFC 2518 specifies 409 for readonly props
+
+ if field.required:
+ if field.default is None:
+ return 409 # Clearing a required property is a conflict
+ # Reset the field to the default if a value is required
+ field.set(iface(self.context), field.default)
+ return 200
+
+ # Reset the field to it's defined missing_value
+ field.set(iface(self.context), field.missing_value)
+ return 200
Modified: 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-14 13:47:41 UTC (rev 28183)
+++ Zope3/branches/isarsprint-dav-work/src/zope/app/dav/tests/test_proppatch.py 2004-10-14 13:48:53 UTC (rev 28184)
@@ -20,7 +20,10 @@
import unittest
from StringIO import StringIO
+import transaction
+
from zope.interface import Interface, implements, directlyProvides
+from zope.schema import Text
from zope.publisher.interfaces.http import IHTTPRequest
from zope.publisher.http import status_reasons
from zope.pagetemplate.tests.util import normalize_xml
@@ -35,8 +38,10 @@
from zope.app.traversing.browser import AbsoluteURL
from zope.app.dublincore.interfaces import IZopeDublinCore
from zope.app.dublincore.annotatableadapter import ZDCAnnotatableAdapter
+from zope.app.dublincore.zopedublincore import ScalarProperty
from zope.app.annotation.interfaces import IAnnotatable, IAnnotations
from zope.app.annotation.attribute import AttributeAnnotations
+from zope.schema.interfaces import IText, ISequence
import zope.app.dav.tests
from zope.app.dav.tests.unitfixtures import File, Folder, FooZPT
@@ -44,6 +49,8 @@
from zope.app.dav import proppatch
from zope.app.dav.interfaces import IDAVSchema
from zope.app.dav.interfaces import IDAVNamespace
+from zope.app.dav.interfaces import IDAVWidget
+from zope.app.dav.widget import TextDAVWidget, SequenceDAVWidget
from zope.app.dav.opaquenamespaces import DAVOpaqueNamespacesAdapter
from zope.app.dav.opaquenamespaces import IDAVOpaqueNamespaces
@@ -86,6 +93,44 @@
request = TestRequest(StringIO(body), StringIO(), _environ)
return request
+
+class ITestSchema(Interface):
+ requiredNoDefault = Text(required=True, default=None)
+ requiredDefault = Text(required=True, default=u'Default Value')
+ unusualMissingValue = Text(required=False, missing_value=u'Missing Value')
+ constrained = Text(required=False, min_length=5)
+
+EmptyTestValue = object()
+TestKey = 'zope.app.dav.tests.test_proppatch'
+TestURI = 'uri://proppatch_tests'
+
+class TestSchemaAdapter(object):
+ implements(ITestSchema)
+ __used_for__ = IAnnotatable
+ annotations = None
+
+ def __init__(self, context):
+ annotations = IAnnotations(context)
+ data = annotations.get(TestKey)
+ if data is None:
+ self.annotations = annotations
+ data = {u'requiredNoDefault': (EmptyTestValue,),
+ u'requiredDefault': (EmptyTestValue,),
+ u'unusualMissingValue': (EmptyTestValue,),
+ u'constrained': (EmptyTestValue,)}
+ self._mapping = data
+
+ def _changed(self):
+ if self.annotations is not None:
+ self.annotations[TestKey] = self._mapping
+ self.annotations = None
+
+ requiredNoDefault = ScalarProperty(u'requiredNoDefault')
+ requiredDefault = ScalarProperty(u'requiredDefault')
+ unusualMissingValue = ScalarProperty(u'unusualMissingValue')
+ constrained = ScalarProperty(u'constrained')
+
+
class PropFindTests(PlacefulSetup, unittest.TestCase):
def setUp(self):
@@ -105,17 +150,22 @@
'absolute_url', AbsoluteURL)
ztapi.provideView(None, IHTTPRequest, Interface,
'PROPPATCH', proppatch.PROPPATCH)
+ ztapi.browserViewProviding(IText, TextDAVWidget, IDAVWidget)
+ ztapi.browserViewProviding(ISequence, SequenceDAVWidget, IDAVWidget)
ztapi.provideAdapter(IAnnotatable, IAnnotations, AttributeAnnotations)
ztapi.provideAdapter(IAnnotatable, IZopeDublinCore,
ZDCAnnotatableAdapter)
ztapi.provideAdapter(IAnnotatable, IDAVOpaqueNamespaces,
DAVOpaqueNamespacesAdapter)
+ ztapi.provideAdapter(IAnnotatable, ITestSchema, TestSchemaAdapter)
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')
+ directlyProvides(ITestSchema, IDAVNamespace)
+ utils.provideUtility(IDAVNamespace, ITestSchema, TestURI)
self.db = DB()
self.conn = self.db.open()
root = self.conn.root()
@@ -296,20 +346,90 @@
{u'uri://foo': {u'bar': '<bar>spam</bar>'}})
def test_proppatch_failure(self):
- # XXX: This relies on the fact that only opaque properties can be set
- # for now. As soon as registered interfaces support is implemented,
- # this test will need to be rewritten.
expect = self._makePropstat(
('uri://foo',), '<bar xmlns="a0"/>', 424)
expect += self._makePropstat(
- ('http://www.purl.org/dc/1.1',), '<title xmlns="a0"/>', 403)
+ ('http://www.purl.org/dc/1.1',), '<nonesuch xmlns="a0"/>', 403)
self._checkProppatch(self.zpt,
ns=(('foo', 'uri://foo'), ('DC', 'http://www.purl.org/dc/1.1')),
- set=('<foo:bar>spam</foo:bar>', '<DC:title>Test</DC:title>'),
+ set=('<foo:bar>spam</foo:bar>', '<DC:nonesuch>Test</DC:nonesuch>'),
expect=expect)
self._assertOPropsEqual(self.zpt, {})
+
+ def test_nonexistent_dc(self):
+ expect = self._makePropstat(
+ ('http://www.purl.org/dc/1.1',), '<nonesuch xmlns="a0"/>', 403)
+ self._checkProppatch(self.zpt,
+ ns=(('DC', 'http://www.purl.org/dc/1.1'),),
+ set=('<DC:nonesuch>Test</DC:nonesuch>',), expect=expect)
+
+ def test_set_readonly(self):
+ expect = self._makePropstat((), '<getcontentlength/>', 409)
+ self._checkProppatch(self.zpt,
+ set=('<getcontentlength>Test</getcontentlength>',), expect=expect)
+
+ def test_remove_readonly(self):
+ expect = self._makePropstat((), '<getcontentlength/>', 409)
+ self._checkProppatch(self.zpt, rm=('<getcontentlength/>',),
+ expect=expect)
-
+ def test_remove_required_no_default(self):
+ testprops = ITestSchema(self.zpt)
+ testprops.requiredNoDefault = u'foo'
+ transaction.commit()
+ expect = self._makePropstat((TestURI,),
+ '<requiredNoDefault xmlns="a0"/>', 409)
+ self._checkProppatch(self.zpt,
+ ns=(('tst', TestURI),), rm=('<tst:requiredNoDefault/>',),
+ expect=expect)
+ self.assertEqual(ITestSchema(self.zpt).requiredNoDefault, u'foo')
+
+ def test_remove_required_default(self):
+ testprops = ITestSchema(self.zpt)
+ testprops.requiredDefault = u'foo'
+ transaction.commit()
+ expect = self._makePropstat((TestURI,),
+ '<requiredDefault xmlns="a0"/>', 200)
+ self._checkProppatch(self.zpt,
+ ns=(('tst', TestURI),), rm=('<tst:requiredDefault/>',),
+ expect=expect)
+ self.assertEqual(testprops.requiredDefault, u'Default Value')
+
+ def test_remove_required_missing_value(self):
+ testprops = ITestSchema(self.zpt)
+ testprops.unusualMissingValue = u'foo'
+ transaction.commit()
+ expect = self._makePropstat((TestURI,),
+ '<unusualMissingValue xmlns="a0"/>', 200)
+ self._checkProppatch(self.zpt,
+ ns=(('tst', TestURI),), rm=('<tst:unusualMissingValue/>',),
+ expect=expect)
+ self.assertEqual(testprops.unusualMissingValue, u'Missing Value')
+
+ def test_set_dctitle(self):
+ dc = IZopeDublinCore(self.zpt)
+ dc.title = u'Test Title'
+ transaction.commit()
+ expect = self._makePropstat(('http://www.purl.org/dc/1.1',),
+ '<title xmlns="a0"/>', 200)
+ self._checkProppatch(self.zpt,
+ ns=(('DC', 'http://www.purl.org/dc/1.1'),),
+ set=('<DC:title>Foo Bar</DC:title>',),
+ expect=expect)
+ self.assertEqual(dc.title, u'Foo Bar')
+
+ def test_set_dcsubjects(self):
+ dc = IZopeDublinCore(self.zpt)
+ dc.subjects = (u'Bla', u'Ble', u'Bli')
+ transaction.commit()
+ expect = self._makePropstat(('http://www.purl.org/dc/1.1',),
+ '<subjects xmlns="a0"/>', 200)
+ self._checkProppatch(self.zpt,
+ ns=(('DC', 'http://www.purl.org/dc/1.1'),),
+ set=('<DC:subjects>Foo, Bar</DC:subjects>',),
+ expect=expect)
+ self.assertEqual(dc.subjects, (u'Foo', u'Bar'))
+
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(PropFindTests),
More information about the Zope3-Checkins
mailing list