[Checkins] SVN: zope.webdav/trunk/src/zope/webdav/ Emit an ObjectModifiedEvent on successfully modifying a property with

Michael Kerrin michael.kerrin at openapp.biz
Mon Feb 19 17:03:25 EST 2007


Log message for revision 72694:
  Emit an ObjectModifiedEvent on successfully modifying a property with 
  the proppatch method.
  

Changed:
  U   zope.webdav/trunk/src/zope/webdav/ftests/test_proppatch.py
  U   zope.webdav/trunk/src/zope/webdav/proppatch.py
  U   zope.webdav/trunk/src/zope/webdav/tests/test_proppatch.py

-=-
Modified: zope.webdav/trunk/src/zope/webdav/ftests/test_proppatch.py
===================================================================
--- zope.webdav/trunk/src/zope/webdav/ftests/test_proppatch.py	2007-02-19 21:16:17 UTC (rev 72693)
+++ zope.webdav/trunk/src/zope/webdav/ftests/test_proppatch.py	2007-02-19 22:03:24 UTC (rev 72694)
@@ -39,7 +39,7 @@
         self.assert_(
             "All PROPPATCH requests needs a XML body" in response.getBody())
 
-    def test_invalidxml(self):
+    def test_invalidxml_nopropertyupdate_elem(self):
         body = """<?xml version="1.0" encoding="utf-8" ?>
 <D:propfind xmlns:D="DAV:">
   <D:prop />
@@ -55,7 +55,7 @@
         self.assertEqual(response.getBody(), "")
 
     def test_setdisplayname_unauthorized(self):
-        file = self.addResource("/r", "some content", title = u"Test Resource")
+        self.addResource("/r", "some content", title = u"Test Resource")
         body = """<?xml version="1.0" encoding="utf-8" ?>
 <D:propertyupdate xmlns:D="DAV:" xmlns="DAV:">
   <D:set><D:prop>
@@ -77,7 +77,7 @@
 
     def test_setdisplayname(self):
         set_properties = "<D:displayname>Test File</D:displayname>"
-        file = self.addResource("/r", "some content", title = u"Test Resource")
+        self.addResource("/r", "some content", title = u"Test Resource")
 
         httpresponse, xmlbody = self.checkProppatch(
             "/r", basic = "mgr:mgrpw", set_properties = set_properties)
@@ -93,8 +93,7 @@
 
     def test_readonly_property(self):
         set_properties = "<D:getcontentlength>10</D:getcontentlength>"
-        file = self.addResource("/r", "some file content",
-                                title = u"Test Resource")
+        self.addResource("/r", "some file content", title = u"Test Resource")
 
         httpresponse, xmlbody = self.checkProppatch(
             "/r", basic = "mgr:mgrpw", set_properties = set_properties)
@@ -109,25 +108,6 @@
         self.assertMSPropertyValue(response, "{DAV:}getcontentlength",
                                    status = 403)
 
-##     def test_property_notfound(self):
-##         set_properties = """
-##         <E:notfound xmlns:E="example:">Not Existent Prop</E:notfound>
-##         """
-##         file = self.addFile("/testfile", "some file content", "text/plain")
-
-##         httpresponse, xmlbody = self.checkProppatch(
-##             "/testfile", basic = "mgr:mgrpw", set_properties = set_properties)
-
-##         responses = xmlbody.findall("{DAV:}response")
-##         self.assertEqual(len(responses), 1)
-##         response = responses[0]
-##         hrefs = response.findall("{DAV:}href")
-##         self.assertEqual(len(hrefs), 1)
-##         self.assertEqual(hrefs[0].text, "http://localhost/testfile")
-
-##         self.assertMSPropertyValue(response, "{example:}notfound",
-##                                    status = 404)
-
     def test_badinput(self):
         set_properties = """
         <E:exampleintprop xmlns:E="DAVtest:">BAD INT</E:exampleintprop>
@@ -226,7 +206,7 @@
     def test_unicode_title(self):
         teststr = u"copyright \xa9 me"
         set_properties = "<D:displayname>%s</D:displayname>" % teststr
-        file = self.addResource("/r", "some content", title = u"Test Resource")
+        self.addResource("/r", "some content", title = u"Test Resource")
 
         httpresponse, xmlbody = self.checkProppatch(
             "/r", basic = "mgr:mgrpw", set_properties = set_properties)
@@ -296,8 +276,8 @@
 
     def test_setting_unicode_title(self):
         teststr = u"copyright \xa9 me"
-        file = self.addResource(u"/" + teststr, "some file content",
-                                title = u"Old title")
+        self.addResource(u"/" + teststr, "some file content",
+                         title = u"Old title")
 
         httpresponse, xmlbody = self.checkProppatch(
             "/" + teststr.encode("utf-8"), basic = "mgr:mgrpw",

Modified: zope.webdav/trunk/src/zope/webdav/proppatch.py
===================================================================
--- zope.webdav/trunk/src/zope/webdav/proppatch.py	2007-02-19 21:16:17 UTC (rev 72693)
+++ zope.webdav/trunk/src/zope/webdav/proppatch.py	2007-02-19 22:03:24 UTC (rev 72694)
@@ -20,8 +20,10 @@
 """
 __docformat__ = 'restructuredtext'
 
+import zope.event
 from zope import interface
 from zope import component
+from zope.lifecycleevent import ObjectModifiedEvent
 
 import zope.webdav.utils
 import zope.webdav.interfaces
@@ -54,13 +56,13 @@
 
         etree = component.getUtility(IEtree)
 
-        # isError - an error occurred during the processing of the request.
-        isError = False
         # propErrors - list of (property tag, error). error is None if no
         #              error occurred in setting / removing the property.
         propErrors = []
         # properties - list of all the properties that we handled correctly.
         properties = []
+        # changed - boolean indicating whether any content changed or not.
+        changed = False
         for update in xmldata:
             if update.tag not in ("{DAV:}set", "{DAV:}remove"):
                 continue
@@ -74,21 +76,20 @@
             for prop in props:
                 try:
                     if update.tag == "{DAV:}set":
-                        self.handleSet(prop)
-                    else:
-                        self.handleRemove(prop)
+                        changed |= self.handleSet(prop)
+                    else: # update.tag == "{DAV:}remove"
+                        changed |= self.handleRemove(prop)
                 except Unauthorized:
                     # If the use doesn't have the correct permission to modify
                     # a property then we need to re-raise the Unauthorized
                     # exception in order to ask the user to log in.
                     raise
                 except Exception, error:
-                    isError = True
                     propErrors.append((prop.tag, error))
                 else:
                     properties.append(prop.tag)
 
-        if isError:
+        if propErrors:
             errors = zope.webdav.interfaces.WebDAVPropstatErrors(self.context)
 
             for prop, error in propErrors:
@@ -100,6 +101,9 @@
 
             raise errors # this kills the current transaction.
 
+        if changed:
+            zope.event.notify(ObjectModifiedEvent(self.context))
+
         url = zope.webdav.utils.getObjectURL(self.context, self.request)
         response = zope.webdav.utils.Response(url)
         propstat = response.getPropstat(200)
@@ -133,6 +137,8 @@
 
         if field.get(adapter) != value:
             field.set(adapter, value)
+            return True
+        return False
 
     def handleRemove(self, prop):
         davprop = component.queryUtility(
@@ -151,3 +157,5 @@
                 self.context, prop.tag, message = u"property doesn't exist")
 
         deadproperties.removeProperty(prop.tag)
+
+        return True

Modified: zope.webdav/trunk/src/zope/webdav/tests/test_proppatch.py
===================================================================
--- zope.webdav/trunk/src/zope/webdav/tests/test_proppatch.py	2007-02-19 21:16:17 UTC (rev 72693)
+++ zope.webdav/trunk/src/zope/webdav/tests/test_proppatch.py	2007-02-19 22:03:24 UTC (rev 72694)
@@ -22,12 +22,14 @@
 import unittest
 from cStringIO import StringIO
 
+from zope import event
 from zope import interface
 from zope import component
 from zope import schema
 import zope.schema.interfaces
 from zope.traversing.browser.interfaces import IAbsoluteURL
 from zope.security.interfaces import Unauthorized
+from zope.lifecycleevent.interfaces import IObjectModifiedEvent
 
 import zope.webdav.proppatch
 import zope.webdav.publisher
@@ -98,8 +100,6 @@
             path += "/" + self.context.__name__
         elif IResource.providedBy(self.context):
             path += "/resource"
-##         elif ICollection.providedBy(self.context):
-##             path += "/collection"
         else:
             raise ValueError("unknown context type")
 
@@ -118,9 +118,11 @@
 
     def handleSet(self, prop):
         self.setprops.append(prop.tag)
+        return True
 
     def handleRemove(self, prop):
         self.removeprops.append(prop.tag)
+        return True
 
 
 class PROPPATCHXmlParsing(unittest.TestCase):
@@ -340,11 +342,6 @@
     exampletextprop = schema.Text(
         title = u"Example Text Property")
 
-class IExtraPropertyStorage(interface.Interface):
-
-    extratextprop = schema.Text(
-        title = u"Property with no storage")
-
 class IUnauthorizedPropertyStorage(interface.Interface):
 
     unauthprop = schema.TextLine(
@@ -354,8 +351,6 @@
     "{DAVtest:}exampleintprop", IExamplePropertyStorage)
 exampleTextProperty = zope.webdav.properties.DAVProperty(
     "{DAVtest:}exampletextprop", IExamplePropertyStorage)
-extraTextProperty = zope.webdav.properties.DAVProperty(
-    "{DAVtest:}extratextprop", IExtraPropertyStorage)
 unauthProperty = zope.webdav.properties.DAVProperty(
     "{DAVtest:}unauthprop", IUnauthorizedPropertyStorage)
 unauthProperty.restricted = True
@@ -397,6 +392,9 @@
 
 class PROPPATCHHandlePropertyModification(unittest.TestCase):
 
+    def eventLog(self, event):
+        self.events.append(event)
+
     def setUp(self):
         etreeSetup()
 
@@ -409,9 +407,6 @@
                             name = "{DAVtest:}exampletextprop",
                             provided = zope.webdav.interfaces.IDAVProperty)
         exampleTextProperty.field.readonly = False
-        gsm.registerUtility(extraTextProperty,
-                            name = "{DAVtest:}extratextprop",
-                            provided = zope.webdav.interfaces.IDAVProperty)
         gsm.registerUtility(unauthProperty, name = "{DAVtest:}unauthprop")
 
         gsm.registerAdapter(ExamplePropertyStorage,
@@ -421,10 +416,19 @@
                             (IResource, zope.webdav.interfaces.IWebDAVRequest),
                             provided = IUnauthorizedPropertyStorage)
 
+        gsm.registerAdapter(zope.webdav.widgets.IntDAVInputWidget,
+                            (zope.schema.interfaces.IInt,
+                             zope.webdav.interfaces.IWebDAVRequest))
         gsm.registerAdapter(zope.webdav.widgets.TextDAVInputWidget,
                             (zope.schema.interfaces.IText,
                              zope.webdav.interfaces.IWebDAVRequest))
 
+        gsm.registerAdapter(DummyResourceURL,
+                            (IResource, zope.webdav.interfaces.IWebDAVRequest))
+
+        self.events = []
+        zope.event.subscribers.append(self.eventLog)
+
     def tearDown(self):
         etreeTearDown()
 
@@ -436,9 +440,6 @@
         gsm.unregisterUtility(exampleTextProperty,
                               name = "{DAVtest:}exampletextprop",
                               provided = zope.webdav.interfaces.IDAVProperty)
-        gsm.unregisterUtility(extraTextProperty,
-                              name = "{DAVtest:}extratextprop",
-                              provided = zope.webdav.interfaces.IDAVProperty)
         gsm.unregisterUtility(unauthProperty, name = "{DAVtest:}unauthprop")
 
         gsm.unregisterAdapter(ExamplePropertyStorage,
@@ -450,10 +451,20 @@
                                zope.webdav.interfaces.IWebDAVRequest),
                               provided = IUnauthorizedPropertyStorage)
 
+        gsm.unregisterAdapter(zope.webdav.widgets.IntDAVInputWidget,
+                              (zope.schema.interfaces.IInt,
+                               zope.webdav.interfaces.IWebDAVRequest))
         gsm.unregisterAdapter(zope.webdav.widgets.TextDAVInputWidget,
                               (zope.schema.interfaces.IText,
                                zope.webdav.interfaces.IWebDAVRequest))
 
+        gsm.unregisterAdapter(DummyResourceURL,
+                              (IResource,
+                               zope.webdav.interfaces.IWebDAVRequest))
+
+        self.events = []
+        zope.event.subscribers.remove(self.eventLog)
+
     def test_handleSetProperty(self):
         etree = component.getUtility(IEtree)
         propel = etree.Element("{DAVtest:}exampletextprop")
@@ -464,10 +475,22 @@
         resource = Resource("Text Prop", 10)
 
         propp = zope.webdav.proppatch.PROPPATCH(resource, request)
-        propp.handleSet(propel)
-
+        self.assertEqual(propp.handleSet(propel), True)
         self.assertEqual(resource.text, "Example Text Prop")
 
+    def test_handleSetProperty_samevalue(self):
+        etree = component.getUtility(IEtree)
+        propel = etree.Element("{DAVtest:}exampletextprop")
+        propel.text = "Text Prop"
+
+        request = TestRequest(
+            set_properties = """<Dt:exampletextprop xmlns:Dt="DAVtest:">Text Prop</Dt:exampletextprop>""")
+        resource = Resource("Text Prop", 10)
+
+        propp = zope.webdav.proppatch.PROPPATCH(resource, request)
+        self.assertEqual(propp.handleSet(propel), False)
+        self.assertEqual(resource.text, "Text Prop")
+
     def test_handleSet_forbidden_property(self):
         etree = component.getUtility(IEtree)
         propel = etree.Element("{DAVtest:}exampletextprop")
@@ -538,7 +561,48 @@
                           propp.handleRemove,
                           propel)
 
+    def test_event_onsetProperty(self):
+        request = TestRequest(
+            set_properties = """<Dt:exampletextprop xmlns:Dt="DAVtest:">Example Text Prop</Dt:exampletextprop>""")
+        resource = Resource("Text Prop", 10)
 
+        propp = zope.webdav.proppatch.PROPPATCH(resource, request)
+        propp.PROPPATCH()
+
+        self.assertEqual(resource.text, "Example Text Prop") # property modified
+        self.assertEqual(len(self.events), 1)
+        self.assert_(IObjectModifiedEvent.providedBy(self.events[0]))
+        self.assertEqual(self.events[0].object, resource)
+
+    def test_event_onsetProperty_sameValue(self):
+        request = TestRequest(
+            set_properties = """<Dt:exampletextprop xmlns:Dt="DAVtest:">Text Prop</Dt:exampletextprop>""")
+        resource = Resource("Text Prop", 10)
+
+        propp = zope.webdav.proppatch.PROPPATCH(resource, request)
+        propp.PROPPATCH()
+
+        self.assertEqual(resource.text, "Text Prop")
+        self.assertEqual(len(self.events), 0)
+
+    def test_event_multipleProperty(self):
+        request = TestRequest(
+            set_properties = """
+<Dt:exampletextprop xmlns:Dt="DAVtest:">Text Prop</Dt:exampletextprop>
+<Dt:exampleintprop xmlns:Dt="DAVtest:">14</Dt:exampleintprop>
+""")
+        resource = Resource("Text Prop", 10)
+
+        propp = zope.webdav.proppatch.PROPPATCH(resource, request)
+        propp.PROPPATCH()
+
+        self.assertEqual(resource.text, "Text Prop")
+        self.assertEqual(resource.intprop, 14)
+        self.assertEqual(len(self.events), 1)
+        self.assertEqual(IObjectModifiedEvent.providedBy(self.events[0]), True)
+        self.assertEqual(self.events[0].object, resource)
+
+
 class DEADProperties(object):
     interface.implements(zope.webdav.interfaces.IOpaquePropertyStorage)
 
@@ -564,6 +628,9 @@
 
 class PROPPATCHHandlePropertyRemoveDead(unittest.TestCase):
 
+    def eventLog(self, event):
+        self.events.append(event)
+
     def setUp(self):
         etreeSetup()
 
@@ -571,6 +638,12 @@
 
         gsm.registerAdapter(DEADProperties, (IResource,))
 
+        gsm.registerAdapter(DummyResourceURL,
+                            (IResource, zope.webdav.interfaces.IWebDAVRequest))
+
+        self.events = []
+        zope.event.subscribers.append(self.eventLog)
+
     def tearDown(self):
         etreeTearDown()
 
@@ -578,6 +651,13 @@
 
         gsm.unregisterAdapter(DEADProperties, (IResource,))
 
+        gsm.unregisterAdapter(DummyResourceURL,
+                              (IResource,
+                               zope.webdav.interfaces.IWebDAVRequest))
+
+        self.events = []
+        zope.event.subscribers.remove(self.eventLog)
+
     def test_remove_no_storage(self):
         etree = component.getUtility(IEtree)
         propel = etree.Element("{example:}exampledeadprop")
@@ -605,6 +685,7 @@
         self.assertRaises(zope.webdav.interfaces.ConflictError,
                           propp.handleRemove,
                           propel)
+        self.assertEqual(self.events, [])
 
     def test_remove_prop(self):
         etree = component.getUtility(IEtree)
@@ -624,11 +705,29 @@
 
         propp = zope.webdav.proppatch.PROPPATCH(resource, request)
 
-        propp.handleRemove(propel)
+        self.assertEqual(propp.handleRemove(propel), True)
+        self.assertEqual(deadprops.hasProperty(testprop), False)
 
+    def test_event_on_remove_property(self):
+        request = TestRequest(
+            remove_properties = """<Dt:exampledeadprop xmlns:Dt="example:">Example Text Prop</Dt:exampledeadprop>""")
+
+        testprop = "{example:}exampledeadprop"
+
+        resource = Resource("Text Prop", 10)
+        deadprops = DEADProperties(resource)
+        deadprops.setProperty(testprop, "Example Text Prop")
+
+        propp = zope.webdav.proppatch.PROPPATCH(resource, request)
+        propp.PROPPATCH()
+
         self.assertEqual(deadprops.hasProperty(testprop), False)
 
+        self.assertEqual(len(self.events), 1)
+        self.assertEqual(IObjectModifiedEvent.providedBy(self.events[0]), True)
+        self.assertEqual(self.events[0].object, resource)
 
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite(PROPPATCHXmlParsing),



More information about the Checkins mailing list