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 _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org http://mail.zope.org/mailman/listinfo/zope-checkins