[Zope-Checkins] SVN: Zope/trunk/ Collector #2298: webdav.Resource.COPY and webdav.Resource.MOVE did

Stefan H. Holek stefan at epy.co.at
Sat Mar 24 10:08:07 EDT 2007


Log message for revision 73499:
  Collector #2298: webdav.Resource.COPY and webdav.Resource.MOVE did
  not send the expected copy/move events.
  
  Note: Tests live in OFS.tests.
  

Changed:
  U   Zope/trunk/doc/CHANGES.txt
  A   Zope/trunk/lib/python/OFS/tests/events.zcml
  A   Zope/trunk/lib/python/OFS/tests/testCopySupportEvents.py
  U   Zope/trunk/lib/python/OFS/tests/testCopySupportHooks.py
  U   Zope/trunk/lib/python/webdav/Resource.py

-=-
Modified: Zope/trunk/doc/CHANGES.txt
===================================================================
--- Zope/trunk/doc/CHANGES.txt	2007-03-24 13:55:36 UTC (rev 73498)
+++ Zope/trunk/doc/CHANGES.txt	2007-03-24 14:08:05 UTC (rev 73499)
@@ -88,6 +88,9 @@
 
     Bugs Fixed
 
+      - Collector #2298: webdav.Resource.COPY and webdav.Resource.MOVE did
+        not send the expected copy/move events.
+
       - Collector #2296: Fixed import of ZClass products, broken by removal
         of BBB support for pasting objects whose meta_type info was
         permission-free.

Added: Zope/trunk/lib/python/OFS/tests/events.zcml
===================================================================
--- Zope/trunk/lib/python/OFS/tests/events.zcml	2007-03-24 13:55:36 UTC (rev 73498)
+++ Zope/trunk/lib/python/OFS/tests/events.zcml	2007-03-24 14:08:05 UTC (rev 73499)
@@ -0,0 +1,112 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    i18n_domain="extfile">
+
+  <!-- Item -->
+
+  <subscriber
+    handler=".testCopySupportEvents.objectAddedEvent"
+    for=".testCopySupportEvents.ITestItem
+         zope.app.container.interfaces.IObjectAddedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectCopiedEvent"
+    for=".testCopySupportEvents.ITestItem
+         zope.lifecycleevent.interfaces.IObjectCopiedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectMovedEvent"
+    for=".testCopySupportEvents.ITestItem
+         zope.app.container.interfaces.IObjectMovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectRemovedEvent"
+    for=".testCopySupportEvents.ITestItem
+         zope.app.container.interfaces.IObjectRemovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectWillBeAddedEvent"
+    for=".testCopySupportEvents.ITestItem
+         OFS.interfaces.IObjectWillBeAddedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectWillBeMovedEvent"
+    for=".testCopySupportEvents.ITestItem
+         OFS.interfaces.IObjectWillBeMovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectWillBeRemovedEvent"
+    for=".testCopySupportEvents.ITestItem
+         OFS.interfaces.IObjectWillBeRemovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectClonedEvent"
+    for=".testCopySupportEvents.ITestItem
+         OFS.interfaces.IObjectClonedEvent"
+    />
+
+  <!-- Folder -->
+
+  <subscriber
+    handler=".testCopySupportEvents.objectAddedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         zope.app.container.interfaces.IObjectAddedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectCopiedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         zope.lifecycleevent.interfaces.IObjectCopiedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectMovedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         zope.app.container.interfaces.IObjectMovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectRemovedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         zope.app.container.interfaces.IObjectRemovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.containerModifiedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         zope.app.container.interfaces.IContainerModifiedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectWillBeAddedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         OFS.interfaces.IObjectWillBeAddedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectWillBeMovedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         OFS.interfaces.IObjectWillBeMovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectWillBeRemovedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         OFS.interfaces.IObjectWillBeRemovedEvent"
+    />
+
+  <subscriber
+    handler=".testCopySupportEvents.objectClonedEvent"
+    for=".testCopySupportEvents.ITestFolder
+         OFS.interfaces.IObjectClonedEvent"
+    />
+
+</configure>
+


Property changes on: Zope/trunk/lib/python/OFS/tests/events.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: Zope/trunk/lib/python/OFS/tests/testCopySupportEvents.py
===================================================================
--- Zope/trunk/lib/python/OFS/tests/testCopySupportEvents.py	2007-03-24 13:55:36 UTC (rev 73498)
+++ Zope/trunk/lib/python/OFS/tests/testCopySupportEvents.py	2007-03-24 14:08:05 UTC (rev 73499)
@@ -0,0 +1,366 @@
+import unittest
+import Testing
+import Zope2
+Zope2.startup()
+
+import os
+import transaction
+
+from Testing.makerequest import makerequest
+
+from AccessControl.SecurityManagement import newSecurityManager
+from AccessControl.SecurityManagement import noSecurityManager
+
+from OFS.SimpleItem import SimpleItem
+from OFS.Folder import Folder
+
+from zope import interface
+from zope.app.container.interfaces import IObjectAddedEvent
+from zope.app.container.interfaces import IObjectRemovedEvent
+from OFS.interfaces import IObjectWillBeAddedEvent
+from OFS.interfaces import IObjectWillBeRemovedEvent
+
+from zope.testing import cleanup
+from Products.Five import zcml
+from Globals import package_home
+
+
+class EventLogger(object):
+    def __init__(self):
+        self.reset()
+    def reset(self):
+        self._called = []
+    def trace(self, ob, event):
+        self._called.append((ob.getId(), event))
+    def called(self):
+        return self._called
+
+eventlog = EventLogger()
+
+
+class ITestItem(interface.Interface):
+    pass
+
+class TestItem(SimpleItem):
+    interface.implements(ITestItem)
+    def __init__(self, id):
+        self.id = id
+
+
+class ITestFolder(interface.Interface):
+    pass
+
+class TestFolder(Folder):
+    interface.implements(ITestFolder)
+    def __init__(self, id):
+        self.id = id
+    def _verifyObjectPaste(self, object, validate_src=1):
+        pass # Always allow
+
+
+# See events.zcml
+
+def objectAddedEvent(ob, event):
+    eventlog.trace(ob, 'ObjectAddedEvent')
+
+def objectCopiedEvent(ob, event):
+    eventlog.trace(ob, 'ObjectCopiedEvent')
+
+def objectMovedEvent(ob, event):
+    if IObjectAddedEvent.providedBy(event):
+        return
+    if IObjectRemovedEvent.providedBy(event):
+        return
+    eventlog.trace(ob, 'ObjectMovedEvent')
+
+def objectRemovedEvent(ob, event):
+    eventlog.trace(ob, 'ObjectRemovedEvent')
+
+def containerModifiedEvent(ob, event):
+    eventlog.trace(ob, 'ContainerModifiedEvent')
+
+def objectWillBeAddedEvent(ob, event):
+    eventlog.trace(ob, 'ObjectWillBeAddedEvent')
+
+def objectWillBeMovedEvent(ob, event):
+    if IObjectWillBeAddedEvent.providedBy(event):
+        return
+    if IObjectWillBeRemovedEvent.providedBy(event):
+        return
+    eventlog.trace(ob, 'ObjectWillBeMovedEvent')
+
+def objectWillBeRemovedEvent(ob, event):
+    eventlog.trace(ob, 'ObjectWillBeRemovedEvent')
+
+def objectClonedEvent(ob, event):
+    eventlog.trace(ob, 'ObjectClonedEvent')
+
+
+class EventLayer:
+
+    @classmethod
+    def setUp(cls):
+        cleanup.cleanUp()
+        zcml._initialized = 0
+        zcml.load_site()
+        import OFS.tests
+        file = os.path.join(package_home(globals()), 'events.zcml')
+        zcml.load_config(file, package=OFS.tests)
+
+    @classmethod
+    def tearDown(cls):
+        cleanup.cleanUp()
+        zcml._initialized = 0
+
+
+class EventTest(unittest.TestCase):
+
+    layer = EventLayer
+
+    def setUp(self):
+        self.app = makerequest(Zope2.app())
+        try:
+            uf = self.app.acl_users
+            uf._doAddUser('manager', 'secret', ['Manager'], [])
+            user = uf.getUserById('manager').__of__(uf)
+            newSecurityManager(None, user)
+        except:
+            self.tearDown()
+            raise
+
+    def tearDown(self):
+        noSecurityManager()
+        transaction.abort()
+        self.app._p_jar.close()
+
+
+class TestCopySupport(EventTest):
+    '''Tests the order in which events are fired'''
+
+    def setUp(self):
+        EventTest.setUp(self)
+        # A folder that does not verify pastes
+        self.app._setObject('folder', TestFolder('folder'))
+        self.folder = getattr(self.app, 'folder')
+        # The subfolder we are going to copy/move to
+        self.folder._setObject('subfolder', TestFolder('subfolder'))
+        self.subfolder = getattr(self.folder, 'subfolder')
+        # The document we are going to copy/move
+        self.folder._setObject('mydoc', TestItem('mydoc'))
+        # Need _p_jars
+        transaction.savepoint(1)
+        # Reset event log
+        eventlog.reset()
+
+    def test_1_Clone(self):
+        # Test clone
+        self.subfolder.manage_clone(self.folder.mydoc, 'mydoc')
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectCopiedEvent'),
+             ('mydoc', 'ObjectWillBeAddedEvent'),
+             ('mydoc', 'ObjectAddedEvent'),
+             ('subfolder', 'ContainerModifiedEvent'),
+             ('mydoc', 'ObjectClonedEvent')]
+        )
+
+    def test_2_CopyPaste(self):
+        # Test copy/paste
+        cb = self.folder.manage_copyObjects(['mydoc'])
+        self.subfolder.manage_pasteObjects(cb)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectCopiedEvent'),
+             ('mydoc', 'ObjectWillBeAddedEvent'),
+             ('mydoc', 'ObjectAddedEvent'),
+             ('subfolder', 'ContainerModifiedEvent'),
+             ('mydoc', 'ObjectClonedEvent')]
+        )
+
+    def test_3_CutPaste(self):
+        # Test cut/paste
+        cb = self.folder.manage_cutObjects(['mydoc'])
+        self.subfolder.manage_pasteObjects(cb)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeMovedEvent'),
+             ('mydoc', 'ObjectMovedEvent'),
+             ('folder', 'ContainerModifiedEvent'),
+             ('subfolder', 'ContainerModifiedEvent')]
+        )
+
+    def test_4_Rename(self):
+        # Test rename
+        self.folder.manage_renameObject('mydoc', 'yourdoc')
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeMovedEvent'),
+             ('yourdoc', 'ObjectMovedEvent'),
+             ('folder', 'ContainerModifiedEvent')]
+        )
+
+    def test_5_COPY(self):
+        # Test webdav COPY
+        req = self.app.REQUEST
+        req.environ['HTTP_DEPTH'] = 'infinity'
+        req.environ['HTTP_DESTINATION'] = '%s/subfolder/mydoc' % self.folder.absolute_url()
+        self.folder.mydoc.COPY(req, req.RESPONSE)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectCopiedEvent'),
+             ('mydoc', 'ObjectWillBeAddedEvent'),
+             ('mydoc', 'ObjectAddedEvent'),
+             ('subfolder', 'ContainerModifiedEvent'),
+             ('mydoc', 'ObjectClonedEvent')]
+        )
+
+    def test_6_MOVE(self):
+        # Test webdav MOVE
+        req = self.app.REQUEST
+        req.environ['HTTP_DEPTH'] = 'infinity'
+        req.environ['HTTP_DESTINATION'] = '%s/subfolder/mydoc' % self.folder.absolute_url()
+        self.folder.mydoc.MOVE(req, req.RESPONSE)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeMovedEvent'),
+             ('mydoc', 'ObjectMovedEvent'),
+             ('folder', 'ContainerModifiedEvent'),
+             ('subfolder', 'ContainerModifiedEvent')]
+        )
+
+    def test_7_DELETE(self):
+        # Test webdav DELETE
+        req = self.app.REQUEST
+        req['URL'] = '%s/mydoc' % self.folder.absolute_url()
+        self.folder.mydoc.DELETE(req, req.RESPONSE)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeRemovedEvent'),
+             ('mydoc', 'ObjectRemovedEvent'),
+             ('folder', 'ContainerModifiedEvent')]
+        )
+
+
+class TestCopySupportSublocation(EventTest):
+    '''Tests the order in which events are fired'''
+
+    def setUp(self):
+        EventTest.setUp(self)
+        # A folder that does not verify pastes
+        self.app._setObject('folder', TestFolder('folder'))
+        self.folder = getattr(self.app, 'folder')
+        # The subfolder we are going to copy/move to
+        self.folder._setObject('subfolder', TestFolder('subfolder'))
+        self.subfolder = getattr(self.folder, 'subfolder')
+        # The folder we are going to copy/move
+        self.folder._setObject('myfolder', TestFolder('myfolder'))
+        self.myfolder = getattr(self.folder, 'myfolder')
+        # The "sublocation" inside our folder we are going to watch
+        self.myfolder._setObject('mydoc', TestItem('mydoc'))
+        # Need _p_jars
+        transaction.savepoint(1)
+        # Reset event log
+        eventlog.reset()
+
+    def test_1_Clone(self):
+        # Test clone
+        self.subfolder.manage_clone(self.folder.myfolder, 'myfolder')
+        self.assertEqual(eventlog.called(),
+            [#('mydoc', 'ObjectCopiedEvent'),
+             ('myfolder', 'ObjectCopiedEvent'),
+             ('mydoc', 'ObjectWillBeAddedEvent'),
+             ('myfolder', 'ObjectWillBeAddedEvent'),
+             ('mydoc', 'ObjectAddedEvent'),
+             ('myfolder', 'ObjectAddedEvent'),
+             ('subfolder', 'ContainerModifiedEvent'),
+             ('mydoc', 'ObjectClonedEvent'),
+             ('myfolder', 'ObjectClonedEvent')]
+        )
+
+    def test_2_CopyPaste(self):
+        # Test copy/paste
+        cb = self.folder.manage_copyObjects(['myfolder'])
+        self.subfolder.manage_pasteObjects(cb)
+        self.assertEqual(eventlog.called(),
+            [#('mydoc', 'ObjectCopiedEvent'),
+             ('myfolder', 'ObjectCopiedEvent'),
+             ('mydoc', 'ObjectWillBeAddedEvent'),
+             ('myfolder', 'ObjectWillBeAddedEvent'),
+             ('mydoc', 'ObjectAddedEvent'),
+             ('myfolder', 'ObjectAddedEvent'),
+             ('subfolder', 'ContainerModifiedEvent'),
+             ('mydoc', 'ObjectClonedEvent'),
+             ('myfolder', 'ObjectClonedEvent')]
+        )
+
+    def test_3_CutPaste(self):
+        # Test cut/paste
+        cb = self.folder.manage_cutObjects(['myfolder'])
+        self.subfolder.manage_pasteObjects(cb)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeMovedEvent'),
+             ('myfolder', 'ObjectWillBeMovedEvent'),
+             ('mydoc', 'ObjectMovedEvent'),
+             ('myfolder', 'ObjectMovedEvent'),
+             ('folder', 'ContainerModifiedEvent'),
+             ('subfolder', 'ContainerModifiedEvent')]
+        )
+
+    def test_4_Rename(self):
+        # Test rename
+        self.folder.manage_renameObject('myfolder', 'yourfolder')
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeMovedEvent'),
+             ('myfolder', 'ObjectWillBeMovedEvent'),
+             ('mydoc', 'ObjectMovedEvent'),
+             ('yourfolder', 'ObjectMovedEvent'),
+             ('folder', 'ContainerModifiedEvent')]
+        )
+
+    def test_5_COPY(self):
+        # Test webdav COPY
+        req = self.app.REQUEST
+        req.environ['HTTP_DEPTH'] = 'infinity'
+        req.environ['HTTP_DESTINATION'] = '%s/subfolder/myfolder' % self.folder.absolute_url()
+        self.folder.myfolder.COPY(req, req.RESPONSE)
+        self.assertEqual(eventlog.called(),
+            [#('mydoc', 'ObjectCopiedEvent'),
+             ('myfolder', 'ObjectCopiedEvent'),
+             ('mydoc', 'ObjectWillBeAddedEvent'),
+             ('myfolder', 'ObjectWillBeAddedEvent'),
+             ('mydoc', 'ObjectAddedEvent'),
+             ('myfolder', 'ObjectAddedEvent'),
+             ('subfolder', 'ContainerModifiedEvent'),
+             ('mydoc', 'ObjectClonedEvent'),
+             ('myfolder', 'ObjectClonedEvent')]
+        )
+
+    def test_6_MOVE(self):
+        # Test webdav MOVE
+        req = self.app.REQUEST
+        req.environ['HTTP_DEPTH'] = 'infinity'
+        req.environ['HTTP_DESTINATION'] = '%s/subfolder/myfolder' % self.folder.absolute_url()
+        self.folder.myfolder.MOVE(req, req.RESPONSE)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeMovedEvent'),
+             ('myfolder', 'ObjectWillBeMovedEvent'),
+             ('mydoc', 'ObjectMovedEvent'),
+             ('myfolder', 'ObjectMovedEvent'),
+             ('folder', 'ContainerModifiedEvent'),
+             ('subfolder', 'ContainerModifiedEvent')]
+        )
+
+    def test_7_DELETE(self):
+        # Test webdav DELETE
+        req = self.app.REQUEST
+        req['URL'] = '%s/myfolder' % self.folder.absolute_url()
+        self.folder.myfolder.DELETE(req, req.RESPONSE)
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'ObjectWillBeRemovedEvent'),
+             ('myfolder', 'ObjectWillBeRemovedEvent'),
+             ('mydoc', 'ObjectRemovedEvent'),
+             ('myfolder', 'ObjectRemovedEvent'),
+             ('folder', 'ContainerModifiedEvent')]
+        )
+
+
+def test_suite():
+    from unittest import TestSuite, makeSuite
+    suite = TestSuite()
+    suite.addTest(makeSuite(TestCopySupport))
+    suite.addTest(makeSuite(TestCopySupportSublocation))
+    return suite
+


Property changes on: Zope/trunk/lib/python/OFS/tests/testCopySupportEvents.py
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: Zope/trunk/lib/python/OFS/tests/testCopySupportHooks.py
===================================================================
--- Zope/trunk/lib/python/OFS/tests/testCopySupportHooks.py	2007-03-24 13:55:36 UTC (rev 73498)
+++ Zope/trunk/lib/python/OFS/tests/testCopySupportHooks.py	2007-03-24 14:08:05 UTC (rev 73499)
@@ -14,70 +14,49 @@
 from OFS.Folder import Folder
 
 
-class HookCounter:
-    '''Logs calls to old-school hooks'''
-
+class EventLogger(object):
     def __init__(self):
         self.reset()
-
     def reset(self):
-        self.count = 0
-        self.afterAdd = [0]
-        self.afterClone = [0]
-        self.beforeDelete = [0]
+        self._called = []
+    def trace(self, ob, event):
+        self._called.append((ob.getId(), event))
+    def called(self):
+        return self._called
 
-    def manage_afterAdd(self, item, container):
-        self.count = self.count + 1
-        self.afterAdd.append(self.count)
+eventlog = EventLogger()
 
-    def manage_afterClone(self, item):
-        self.count = self.count + 1
-        self.afterClone.append(self.count)
 
-    def manage_beforeDelete(self, item, container):
-        self.count = self.count + 1
-        self.beforeDelete.append(self.count)
-
-    def order(self):
-        return self.afterAdd[-1], self.afterClone[-1], self.beforeDelete[-1]
-
-
-class TestItem(HookCounter, SimpleItem):
-
+class TestItem(SimpleItem):
     def __init__(self, id):
-        HookCounter.__init__(self)
         self.id = id
+    def manage_afterAdd(self, item, container):
+        eventlog.trace(self, 'manage_afterAdd')
+    def manage_afterClone(self, item):
+        eventlog.trace(self, 'manage_afterClone')
+    def manage_beforeDelete(self, item, container):
+        eventlog.trace(self, 'manage_beforeDelete')
 
 
-class TestFolder(HookCounter, Folder):
-
+class TestFolder(Folder):
     def __init__(self, id):
-        HookCounter.__init__(self)
         self.id = id
-
     def _verifyObjectPaste(self, object, validate_src=1):
-        # Don't verify pastes as our test objects don't have
-        # factory methods registered.
-        pass
-
+        pass # Always allow
     def manage_afterAdd(self, item, container):
-        HookCounter.manage_afterAdd(self, item, container)
+        eventlog.trace(self, 'manage_afterAdd')
         Folder.manage_afterAdd(self, item, container)
-
     def manage_afterClone(self, item):
-        HookCounter.manage_afterClone(self, item)
+        eventlog.trace(self, 'manage_afterClone')
         Folder.manage_afterClone(self, item)
-
     def manage_beforeDelete(self, item, container):
-        HookCounter.manage_beforeDelete(self, item, container)
+        eventlog.trace(self, 'manage_beforeDelete')
         Folder.manage_beforeDelete(self, item, container)
 
 
-try:
-    from Products.Five.eventconfigure import setDeprecatedManageAddDelete
-    setDeprecatedManageAddDelete(HookCounter)
-except ImportError:
-    pass
+from Products.Five.eventconfigure import setDeprecatedManageAddDelete
+setDeprecatedManageAddDelete(TestItem)
+setDeprecatedManageAddDelete(TestFolder)
 
 
 class HookTest(unittest.TestCase):
@@ -100,44 +79,56 @@
 
 
 class TestCopySupport(HookTest):
-    '''Tests the order in which the add/clone/del hooks are called'''
+    '''Tests the order in which add/clone/del hooks are called'''
 
     def setUp(self):
         HookTest.setUp(self)
-        # A folder
+        # A folder that does not verify pastes
         self.app._setObject('folder', TestFolder('folder'))
-        self.folder = self.app['folder']
-        # A subfolder we are going to copy/move to
+        self.folder = getattr(self.app, 'folder')
+        # The subfolder we are going to copy/move to
         self.folder._setObject('subfolder', TestFolder('subfolder'))
-        self.subfolder = self.folder['subfolder']
-        # A document we are going to copy/move
+        self.subfolder = getattr(self.folder, 'subfolder')
+        # The document we are going to copy/move
         self.folder._setObject('mydoc', TestItem('mydoc'))
-        # Must have _p_jars
+        # Need _p_jars
         transaction.savepoint(1)
-        # Reset counters
-        self.folder.mydoc.reset()
+        # Reset event log
+        eventlog.reset()
 
     def test_1_Clone(self):
         # Test clone
-        self.subfolder.manage_clone(self.folder.mydoc, 'yourdoc')
-        self.assertEqual(self.subfolder.yourdoc.order(), (1, 2, 0)) # add, clone
+        self.subfolder.manage_clone(self.folder.mydoc, 'mydoc')
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterClone')]
+        )
 
     def test_2_CopyPaste(self):
         # Test copy/paste
         cb = self.folder.manage_copyObjects(['mydoc'])
         self.subfolder.manage_pasteObjects(cb)
-        self.assertEqual(self.subfolder.mydoc.order(), (1, 2, 0))   # add, clone
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterClone')]
+        )
 
     def test_3_CutPaste(self):
         # Test cut/paste
         cb = self.folder.manage_cutObjects(['mydoc'])
         self.subfolder.manage_pasteObjects(cb)
-        self.assertEqual(self.subfolder.mydoc.order(), (2, 0, 1))   # del, add
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete'),
+             ('mydoc', 'manage_afterAdd')]
+        )
 
     def test_4_Rename(self):
         # Test rename
         self.folder.manage_renameObject('mydoc', 'yourdoc')
-        self.assertEqual(self.folder.yourdoc.order(), (2, 0, 1))    # del, add
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete'),
+             ('yourdoc', 'manage_afterAdd')]
+        )
 
     def test_5_COPY(self):
         # Test webdav COPY
@@ -145,123 +136,136 @@
         req.environ['HTTP_DEPTH'] = 'infinity'
         req.environ['HTTP_DESTINATION'] = '%s/subfolder/mydoc' % self.folder.absolute_url()
         self.folder.mydoc.COPY(req, req.RESPONSE)
-        self.assertEqual(req.RESPONSE.getStatus(), 201)
-        self.assertEqual(self.subfolder.mydoc.order(), (1, 2, 0))   # add, clone
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterClone')]
+        )
 
     def test_6_MOVE(self):
         # Test webdav MOVE
         req = self.app.REQUEST
         req.environ['HTTP_DEPTH'] = 'infinity'
         req.environ['HTTP_DESTINATION'] = '%s/subfolder/mydoc' % self.folder.absolute_url()
-        old = self.folder.mydoc
         self.folder.mydoc.MOVE(req, req.RESPONSE)
-        self.assertEqual(req.RESPONSE.getStatus(), 201)
-        self.assertEqual(old.order(), (0, 0, 1))                    # del
-        self.assertEqual(self.subfolder.mydoc.order(), (1, 0, 0))   # add
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete'),
+             ('mydoc', 'manage_afterAdd')]
+        )
 
     def test_7_DELETE(self):
         # Test webdav DELETE
         req = self.app.REQUEST
         req['URL'] = '%s/mydoc' % self.folder.absolute_url()
-        old = self.folder.mydoc
         self.folder.mydoc.DELETE(req, req.RESPONSE)
-        self.assertEqual(req.RESPONSE.getStatus(), 204)
-        self.assertEqual(old.order(), (0, 0, 1))                    # del
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete')]
+        )
 
 
 class TestCopySupportSublocation(HookTest):
-    '''Tests the order in which the add/clone/del hooks are called'''
+    '''Tests the order in which add/clone/del hooks are called'''
 
     def setUp(self):
         HookTest.setUp(self)
-        # A folder
+        # A folder that does not verify pastes
         self.app._setObject('folder', TestFolder('folder'))
-        self.folder = self.app['folder']
-        # A subfolder we are going to copy/move to
+        self.folder = getattr(self.app, 'folder')
+        # The subfolder we are going to copy/move to
         self.folder._setObject('subfolder', TestFolder('subfolder'))
-        self.subfolder = self.folder['subfolder']
-        # A folderish object we are going to copy/move
+        self.subfolder = getattr(self.folder, 'subfolder')
+        # The folder we are going to copy/move
         self.folder._setObject('myfolder', TestFolder('myfolder'))
-        self.myfolder = self.folder['myfolder']
-        # A "sublocation" inside myfolder we are going to watch
+        self.myfolder = getattr(self.folder, 'myfolder')
+        # The "sublocation" inside our folder we are going to watch
         self.myfolder._setObject('mydoc', TestItem('mydoc'))
-        # Must have _p_jars
+        # Need _p_jars
         transaction.savepoint(1)
-        # Reset counters
-        self.myfolder.reset()
-        self.myfolder.mydoc.reset()
+        # Reset event log
+        eventlog.reset()
 
     def test_1_Clone(self):
         # Test clone
-        self.subfolder.manage_clone(self.folder.myfolder, 'yourfolder')
-        self.assertEqual(self.subfolder.yourfolder.order(), (1, 2, 0))          # add, clone
-        self.assertEqual(self.subfolder.yourfolder.mydoc.order(), (1, 2, 0))    # add, clone
+        self.subfolder.manage_clone(self.folder.myfolder, 'myfolder')
+        self.assertEqual(eventlog.called(),
+            [('myfolder', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterAdd'),
+             ('myfolder', 'manage_afterClone'),
+             ('mydoc', 'manage_afterClone')]
+        )
 
     def test_2_CopyPaste(self):
         # Test copy/paste
         cb = self.folder.manage_copyObjects(['myfolder'])
         self.subfolder.manage_pasteObjects(cb)
-        self.assertEqual(self.subfolder.myfolder.order(), (1, 2, 0))            # add, clone
-        self.assertEqual(self.subfolder.myfolder.mydoc.order(), (1, 2, 0))      # add, clone
+        self.assertEqual(eventlog.called(),
+            [('myfolder', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterAdd'),
+             ('myfolder', 'manage_afterClone'),
+             ('mydoc', 'manage_afterClone')]
+        )
 
     def test_3_CutPaste(self):
         # Test cut/paste
         cb = self.folder.manage_cutObjects(['myfolder'])
         self.subfolder.manage_pasteObjects(cb)
-        self.assertEqual(self.subfolder.myfolder.order(), (2, 0, 1))            # del, add
-        self.assertEqual(self.subfolder.myfolder.mydoc.order(), (2, 0, 1))      # del, add
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete'),
+             ('myfolder', 'manage_beforeDelete'),
+             ('myfolder', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterAdd')]
+        )
 
     def test_4_Rename(self):
         # Test rename
         self.folder.manage_renameObject('myfolder', 'yourfolder')
-        self.assertEqual(self.folder.yourfolder.order(), (2, 0, 1))             # del, add
-        self.assertEqual(self.folder.yourfolder.mydoc.order(), (2, 0, 1))       # del, add
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete'),
+             ('myfolder', 'manage_beforeDelete'),
+             ('yourfolder', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterAdd')]
+        )
 
     def test_5_COPY(self):
         # Test webdav COPY
-        #
-        # See http://www.zope.org/Collectors/Zope/2169
-        #
         req = self.app.REQUEST
         req.environ['HTTP_DEPTH'] = 'infinity'
-        req.environ['HTTP_DESTINATION'] = '%s/subfolder/yourfolder' % self.folder.absolute_url()
+        req.environ['HTTP_DESTINATION'] = '%s/subfolder/myfolder' % self.folder.absolute_url()
         self.folder.myfolder.COPY(req, req.RESPONSE)
-        self.assertEqual(req.RESPONSE.getStatus(), 201)
-        self.assertEqual(self.subfolder.yourfolder.order(), (1, 2, 0))          # add, clone
-        self.assertEqual(self.subfolder.yourfolder.mydoc.order(), (1, 2, 0))    # add, clone
+        self.assertEqual(eventlog.called(),
+            [('myfolder', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterAdd'),
+             ('myfolder', 'manage_afterClone'),
+             ('mydoc', 'manage_afterClone')]
+        )
 
     def test_6_MOVE(self):
         # Test webdav MOVE
         req = self.app.REQUEST
         req.environ['HTTP_DEPTH'] = 'infinity'
-        req.environ['HTTP_DESTINATION'] = '%s/subfolder/yourfolder' % self.folder.absolute_url()
-        oldfolder = self.folder.myfolder
-        olddoc = self.folder.myfolder.mydoc
+        req.environ['HTTP_DESTINATION'] = '%s/subfolder/myfolder' % self.folder.absolute_url()
         self.folder.myfolder.MOVE(req, req.RESPONSE)
-        self.assertEqual(req.RESPONSE.getStatus(), 201)
-        self.assertEqual(oldfolder.order(), (0, 0, 1))                          # del
-        self.assertEqual(self.subfolder.yourfolder.order(), (1, 0, 0))          # add
-        self.assertEqual(olddoc.order(), (0, 0, 1))                             # del
-        self.assertEqual(self.subfolder.yourfolder.mydoc.order(), (1, 0, 0))    # add
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete'),
+             ('myfolder', 'manage_beforeDelete'),
+             ('myfolder', 'manage_afterAdd'),
+             ('mydoc', 'manage_afterAdd')]
+        )
 
     def test_7_DELETE(self):
         # Test webdav DELETE
         req = self.app.REQUEST
         req['URL'] = '%s/myfolder' % self.folder.absolute_url()
-        oldfolder = self.folder.myfolder
-        olddoc = self.folder.myfolder.mydoc
         self.folder.myfolder.DELETE(req, req.RESPONSE)
-        self.assertEqual(req.RESPONSE.getStatus(), 204)
-        self.assertEqual(oldfolder.order(), (0, 0, 1))                          # del
-        self.assertEqual(olddoc.order(), (0, 0, 1))                             # del
+        self.assertEqual(eventlog.called(),
+            [('mydoc', 'manage_beforeDelete'),
+             ('myfolder', 'manage_beforeDelete')]
+        )
 
 
 def test_suite():
-    suite = unittest.TestSuite()
-    suite.addTest(unittest.makeSuite(TestCopySupport))
-    suite.addTest(unittest.makeSuite(TestCopySupportSublocation))
+    from unittest import TestSuite, makeSuite
+    suite = TestSuite()
+    suite.addTest(makeSuite(TestCopySupport))
+    suite.addTest(makeSuite(TestCopySupportSublocation))
     return suite
 
-if __name__ == '__main__':
-    unittest.main(defaultTest='test_suite')
-

Modified: Zope/trunk/lib/python/webdav/Resource.py
===================================================================
--- Zope/trunk/lib/python/webdav/Resource.py	2007-03-24 13:55:36 UTC (rev 73498)
+++ Zope/trunk/lib/python/webdav/Resource.py	2007-03-24 14:08:05 UTC (rev 73499)
@@ -17,6 +17,7 @@
 
 import mimetypes
 import sys
+import warnings
 from urllib import unquote
 
 import ExtensionClass
@@ -29,7 +30,7 @@
 from AccessControl.Permissions import webdav_lock_items
 from AccessControl.Permissions import webdav_unlock_items
 from AccessControl.Permissions import webdav_access
-from Acquisition import aq_base
+from Acquisition import aq_base, aq_inner, aq_parent
 from zExceptions import BadRequest, MethodNotAllowed
 from zExceptions import Unauthorized, Forbidden, NotFound
 from zope.interface import implements
@@ -46,7 +47,11 @@
 from WriteLockInterface import WriteLockInterface
 
 from zope.event import notify
+from zope.lifecycleevent import ObjectCopiedEvent
+from zope.app.container.contained import ObjectMovedEvent
+from zope.app.container.contained import notifyContainerModified
 from OFS.event import ObjectClonedEvent
+from OFS.event import ObjectWillBeMovedEvent
 import OFS.subscribers
 
 
@@ -230,7 +235,7 @@
         ifhdr = REQUEST.get_header('If', '')
         url = urlfix(REQUEST['URL'], 'DELETE')
         name = unquote(filter(None, url.split( '/')[-1]))
-        parent = self.aq_parent
+        parent = aq_parent(aq_inner(self))
         # Lock checking
         if Lockable.wl_isLocked(self):
             if ifhdr:
@@ -396,10 +401,14 @@
         if depth=='0' and isDavCollection(ob):
             for id in ob.objectIds():
                 ob._delObject(id)
+
+        notify(ObjectCopiedEvent(ob, self))
+
         if existing:
             object=getattr(parent, name)
             self.dav__validate(object, 'DELETE', REQUEST)
             parent._delObject(name)
+
         parent._setObject(name, ob)
         ob = parent._getOb(name)
         ob._postCopy(parent, op=0)
@@ -505,20 +514,52 @@
                 raise PreconditionFailed, 'Source is locked and no '\
                       'condition was passed in.'
 
+        orig_container = aq_parent(aq_inner(self))
+        orig_id = self.getId()
+
+        self._notifyOfCopyTo(parent, op=1)
+
+        notify(ObjectWillBeMovedEvent(self, orig_container, orig_id,
+                                      parent, name))
+
         # try to make ownership explicit so that it gets carried
         # along to the new location if needed.
         self.manage_changeOwnershipType(explicit=1)
 
-        self._notifyOfCopyTo(parent, op=1)
-        ob = aq_base(self._getCopy(parent))
-        self.aq_parent._delObject(absattr(self.id))
+        ob = self._getCopy(parent)
         ob._setId(name)
+
+        try:
+            orig_container._delObject(orig_id, suppress_events=True)
+        except TypeError:
+            # BBB: removed in Zope 2.11
+            orig_container._delObject(orig_id)
+            warnings.warn(
+                "%s._delObject without suppress_events is deprecated "
+                "and will be removed in Zope 2.11." %
+                orig_container.__class__.__name__, DeprecationWarning)
+
         if existing:
             object=getattr(parent, name)
             self.dav__validate(object, 'DELETE', REQUEST)
             parent._delObject(name)
-        parent._setObject(name, ob)
+
+        try:
+            parent._setObject(name, ob, set_owner=0, suppress_events=True)
+        except TypeError:
+            # BBB: removed in Zope 2.11
+            parent._setObject(name, ob, set_owner=0)
+            warnings.warn(
+                "%s._setObject without suppress_events is deprecated "
+                "and will be removed in Zope 2.11." %
+                parent.__class__.__name__, DeprecationWarning)
         ob = parent._getOb(name)
+
+        notify(ObjectMovedEvent(ob, orig_container, orig_id, parent, name))
+        notifyContainerModified(orig_container)
+        if aq_base(orig_container) is not aq_base(parent):
+            notifyContainerModified(parent)
+
         ob._postCopy(parent, op=1)
 
         # try to make ownership implicit if possible



More information about the Zope-Checkins mailing list