[CMF-checkins] SVN: CMF/trunk/C merged changes from tseaver-catalog_events branch and efge-1.5-five-compatible branch:

Yvo Schubbe y.2006_ at wcm-solutions.de
Fri May 19 03:33:33 EDT 2006


Log message for revision 68181:
  merged changes from tseaver-catalog_events branch and efge-1.5-five-compatible branch:
  - replaced deprecated 'manage_afterAdd', 'manage_afterClone' and 'manage_beforeDelete' hooks

Changed:
  U   CMF/trunk/CHANGES.txt
  U   CMF/trunk/CMFCore/CMFCatalogAware.py
  U   CMF/trunk/CMFCore/configure.zcml
  A   CMF/trunk/CMFCore/event.zcml
  U   CMF/trunk/CMFCore/tests/base/dummy.py
  U   CMF/trunk/CMFCore/tests/base/testcase.py
  U   CMF/trunk/CMFCore/tests/test_CMFCatalogAware.py
  U   CMF/trunk/CMFCore/tests/test_OpaqueItems.py
  U   CMF/trunk/CMFCore/tests/test_PortalContent.py
  U   CMF/trunk/CMFCore/tests/test_PortalFolder.py
  U   CMF/trunk/CMFDefault/DiscussionItem.py
  U   CMF/trunk/CMFDefault/File.py
  U   CMF/trunk/CMFDefault/Image.py
  U   CMF/trunk/CMFDefault/SkinnedFolder.py
  U   CMF/trunk/CMFDefault/tests/test_Discussions.py
  U   CMF/trunk/CMFDefault/tests/test_Image.py
  U   CMF/trunk/CMFDefault/tests/test_Portal.py
  U   CMF/trunk/CMFTopic/tests/test_Topic.py
  U   CMF/trunk/CMFUid/tests/test_uidannotation.py

-=-
Modified: CMF/trunk/CHANGES.txt
===================================================================
--- CMF/trunk/CHANGES.txt	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CHANGES.txt	2006-05-19 07:33:31 UTC (rev 68181)
@@ -10,6 +10,10 @@
 
   Others
 
+    - CMFCatalogAware: Added 'handleObjectEvent' subscriber.
+      This replaces the deprecated 'manage_afterAdd', 'manage_afterClone' and
+      'manage_beforeDelete' hooks.
+
     - setup handlers: Removed support for CMF 1.5 CMFSetup profiles.
 
 CMF 2.0.x

Modified: CMF/trunk/CMFCore/CMFCatalogAware.py
===================================================================
--- CMF/trunk/CMFCore/CMFCatalogAware.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/CMFCatalogAware.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -22,6 +22,10 @@
 from ExtensionClass import Base
 from Globals import DTMLFile
 from Globals import InitializeClass
+from OFS.interfaces import IObjectClonedEvent
+from OFS.interfaces import IObjectWillBeMovedEvent
+from zope.app.container.interfaces import IObjectAddedEvent
+from zope.app.container.interfaces import IObjectMovedEvent
 
 from permissions import AccessContentsInformation
 from permissions import ManagePortal
@@ -34,7 +38,9 @@
 from interfaces.IOpaqueItems \
         import ICallableOpaqueItem as z2ICallableOpaqueItem
 
+
 class CMFCatalogAware(Base):
+
     """Mix-in for notifying portal_catalog and portal_workflow
     """
 
@@ -164,7 +170,7 @@
         # implementing 'ICallableOpaqueItem'.
         self_base = aq_base(self)
         for name in self_base.__dict__.keys():
-            obj = getattr(self_base, name)
+            obj = getattr(self, name)
             if ICallableOpaqueItem.providedBy(obj) \
                     or z2ICallableOpaqueItem.isImplementedBy(obj):
                 items.append((obj.getId(), obj))
@@ -190,22 +196,7 @@
     # Hooks
     # -----
 
-    def manage_afterAdd(self, item, container):
-        """
-            Add self to the catalog.
-            (Called when the object is created or moved.)
-        """
-        self.indexObject()
-        self.__recurse('manage_afterAdd', item, container)
-
-    def manage_afterClone(self, item):
-        """
-            Add self to the workflow.
-            (Called when the object is cloned.)
-        """
-        self.notifyWorkflowCreated()
-        self.__recurse('manage_afterClone', item)
-
+    def _clearLocalRolesAfterClone(self):
         # Make sure owner local role is set after pasting
         # The standard Zope mechanisms take care of executable ownership
         current_user = _getAuthenticatedUser(self)
@@ -214,27 +205,21 @@
             self.manage_delLocalRoles(local_role_holders)
             self.manage_setLocalRoles(current_user.getId(), ['Owner'])
 
-    def manage_beforeDelete(self, item, container):
+    def _recurseOpaques(self, name, container=None):
         """
-            Remove self from the catalog.
-            (Called when the object is deleted or moved.)
+            Recurse in both opaque subobjects.
         """
-        self.__recurse('manage_beforeDelete', item, container)
-        self.unindexObject()
+        for opaque in self.opaqueValues():
+            s = getattr(opaque, '_p_changed', 0)
+            if hasattr(aq_base(opaque), name):
+                if container is None:
+                    getattr(opaque, name)(opaque)
+                else:
+                    getattr(opaque, name)(opaque, container)
+            else:
+                if s is None:
+                    opaque._p_deactivate()
 
-    def __recurse(self, name, *args):
-        """
-            Recurse in both normal and opaque subobjects.
-        """
-        values = self.objectValues()
-        opaque_values = self.opaqueValues()
-        for subobjects in values, opaque_values:
-            for ob in subobjects:
-                s = getattr(ob, '_p_changed', 0)
-                if hasattr(aq_base(ob), name):
-                    getattr(ob, name)(*args)
-                if s is None: ob._p_deactivate()
-
     # ZMI
     # ---
 
@@ -279,3 +264,30 @@
             manage_tabs_message=manage_tabs_message)
 
 InitializeClass(CMFCatalogAware)
+
+
+def handleObjectEvent(ob, event):
+    """ Event subscriber for (IContentish, IObjectEvent) events.
+
+    o XXX:  the nasty '_recurseOpaques' propagates notification to opaque
+            items, which are ignored by the stock ObjectManager propagation.
+    """
+    if IObjectAddedEvent.providedBy(event):
+        if event.newParent is not None:
+            ob.indexObject()
+            ob._recurseOpaques('manage_afterAdd', ob)
+
+    elif IObjectClonedEvent.providedBy(event):
+        ob.notifyWorkflowCreated()
+        ob._clearLocalRolesAfterClone()
+        ob._recurseOpaques('manage_afterClone')
+
+    elif IObjectMovedEvent.providedBy(event):
+        if event.newParent is not None:
+            ob.reindexObject()
+            ob._recurseOpaques('manage_afterAdd', ob)
+
+    elif IObjectWillBeMovedEvent.providedBy(event):
+        if event.oldParent is not None:
+            ob.unindexObject()
+            ob._recurseOpaques('manage_beforeDelete', ob)

Modified: CMF/trunk/CMFCore/configure.zcml
===================================================================
--- CMF/trunk/CMFCore/configure.zcml	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/configure.zcml	2006-05-19 07:33:31 UTC (rev 68181)
@@ -7,6 +7,8 @@
 
   <include package=".exportimport"/>
 
+  <include file="event.zcml"/>
+
   <five:registerClass
       class=".ActionInformation.ActionCategory"
       meta_type="CMF Action Category"
@@ -39,10 +41,4 @@
       global="False"
       />
 
-  <subscriber
-    for=".interfaces.ICookieCrumbler
-         zope.app.event.interfaces.IObjectEvent"
-    handler=".CookieCrumbler.handleCookieCrumblerEvent"
-    />
-
 </configure>

Added: CMF/trunk/CMFCore/event.zcml
===================================================================
--- CMF/trunk/CMFCore/event.zcml	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/event.zcml	2006-05-19 07:33:31 UTC (rev 68181)
@@ -0,0 +1,16 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope">
+
+  <subscriber
+      for=".interfaces.ICookieCrumbler
+           zope.app.event.interfaces.IObjectEvent"
+      handler=".CookieCrumbler.handleCookieCrumblerEvent"
+      />
+
+  <subscriber
+      for=".interfaces.IContentish
+           zope.app.event.interfaces.IObjectEvent"
+      handler=".CMFCatalogAware.handleObjectEvent"
+      />
+
+</configure>


Property changes on: CMF/trunk/CMFCore/event.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: CMF/trunk/CMFCore/tests/base/dummy.py
===================================================================
--- CMF/trunk/CMFCore/tests/base/dummy.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/tests/base/dummy.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -16,14 +16,23 @@
 """
 
 from Acquisition import Implicit, aq_base, aq_inner, aq_parent
+from OFS.event import ObjectWillBeAddedEvent
+from OFS.event import ObjectWillBeRemovedEvent
+from OFS.interfaces import IObjectManager
 from OFS.SimpleItem import Item
+from webdav.common import rfc1123_date
+from zope.app.container.contained import notifyContainerModified
+from zope.app.container.contained import ObjectAddedEvent
+from zope.app.container.contained import ObjectRemovedEvent
+from zope.event import notify
+from zope.interface import implements
 
+from Products.CMFCore.interfaces import IContentish
 from Products.CMFCore.ActionProviderBase import ActionProviderBase
 from Products.CMFCore.PortalContent import PortalContent
+
 from security import OmnipotentUser
 
-from DateTime import DateTime
-from webdav.common import rfc1123_date
 
 class DummyObject(Implicit):
     """
@@ -92,6 +101,8 @@
     """
     A Dummy piece of PortalContent
     """
+    implements(IContentish)
+
     meta_type = 'Dummy'
     portal_type = 'Dummy Content'
     url = 'foo_url'
@@ -107,15 +118,11 @@
         self.catalog = kw.get('catalog',0)
         self.url = kw.get('url',None)
 
-    def manage_afterAdd( self, item, container ):
+    def manage_afterAdd(self, item, container):
         self.after_add_called = 1
-        if self.catalog:
-            PortalContent.manage_afterAdd( self, item, container )
 
-    def manage_beforeDelete( self, item, container ):
+    def manage_beforeDelete(self, item, container):
         self.before_delete_called = 1
-        if self.catalog:
-            PortalContent.manage_beforeDelete( self, item, container )
 
     def absolute_url(self):
        return self.url
@@ -178,9 +185,11 @@
 
 
 class DummyFolder(DummyObject):
+
+    """Dummy Container for testing.
     """
-        Dummy Container for testing
-    """
+    implements(IObjectManager)
+
     def __init__( self, id='dummy', fake_product=0, prefix='' ):
         self._prefix = prefix
         self._id = id
@@ -198,17 +207,23 @@
         return getattr(self, id)
 
     def _setObject(self, id, object):
+        notify(ObjectWillBeAddedEvent(object, self, id))
         self._setOb(id, object)
         object = self._getOb(id)
         if hasattr(aq_base(object), 'manage_afterAdd'):
             object.manage_afterAdd(object, self)
+        notify(ObjectAddedEvent(object, self, id))
+        notifyContainerModified(self)
         return object
 
     def _delObject(self, id):
         object = self._getOb(id)
+        notify(ObjectWillBeRemovedEvent(object, self, id))
         if hasattr(aq_base(object), 'manage_beforeDelete'):
             object.manage_beforeDelete(object, self)
         self._delOb(id)
+        notify(ObjectRemovedEvent(object, self, id))
+        notifyContainerModified(self)
 
     def getPhysicalPath(self):
         p = aq_parent(aq_inner(self))

Modified: CMF/trunk/CMFCore/tests/base/testcase.py
===================================================================
--- CMF/trunk/CMFCore/tests/base/testcase.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/tests/base/testcase.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -11,11 +11,14 @@
 from stat import S_IREAD, S_IWRITE
 from tempfile import mktemp
 
+import Products
 import transaction
 from AccessControl.SecurityManagement import newSecurityManager
 from AccessControl.SecurityManagement import noSecurityManager
 from AccessControl.SecurityManager import setSecurityPolicy
+from Products.Five import zcml
 from Testing.makerequest import makerequest
+from zope.app.testing.placelesssetup import PlacelessSetup
 
 from dummy import DummyFolder
 from security import AnonymousUser
@@ -77,6 +80,7 @@
         root_logger.removeFilter(self)
         self.installed = False
 
+
 class WarningInterceptor:
 
     _old_stderr = None
@@ -126,6 +130,7 @@
         self.REQUEST.close()
         TransactionalTest.tearDown(self)
 
+
 class SecurityTest( TestCase ):
 
     def setUp(self):
@@ -165,6 +170,22 @@
 _prefix = abspath(join(_prefix,'..'))
 
 
+class ContentEventAwareTests(PlacelessSetup):
+
+    """ Mix-in for test case classes which need to get object events handled.
+    """
+    # BBB: replace PlacelessSetup by zope.component.eventtesting.setUp
+    #      and zope.testing.cleanup.cleanUp if we no longer support Zope 2.9
+
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        #   First, set up "stock" OFS event propagation
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('event.zcml', Products.Five)
+        #   Now, register the CMF-specific handler
+        zcml.load_config('event.zcml', Products.CMFCore)
+
+
 class FSDVTest( TestCase, WarningInterceptor ):
     # Base class for FSDV test, creates a fake skin
     # copy that can be edited.
@@ -205,7 +226,6 @@
             mtime2 = stat(thePath)[8]
         self._addedOrRemoved(dir_mtime)
 
-
     def _deleteFile(self,filename):
         try:
             dir_mtime = stat(self.skin_path_name)[8]
@@ -214,7 +234,6 @@
         remove(join(self.skin_path_name, filename))
         self._addedOrRemoved(dir_mtime)
 
-
     def _addedOrRemoved(self, old_mtime):
         # Called after adding/removing a file from self.skin_path_name.
         

Modified: CMF/trunk/CMFCore/tests/test_CMFCatalogAware.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_CMFCatalogAware.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/tests/test_CMFCatalogAware.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -18,13 +18,19 @@
 import unittest
 import Testing
 
+import transaction
 from OFS.Folder import Folder
 from OFS.SimpleItem import SimpleItem
+from zope.interface import implements
 
 from Products.CMFCore.CMFCatalogAware import CMFCatalogAware
 from Products.CMFCore.exceptions import NotFound
+from Products.CMFCore.interfaces import IContentish
+from Products.CMFCore.tests.test_PortalFolder import _AllowedUser
+from Products.CMFCore.tests.test_PortalFolder import _SensitiveSecurityPolicy
 from Products.CMFCore.tests.base.testcase import LogInterceptor
-from Products.CMFCore.WorkflowTool import WorkflowTool
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
+from Products.CMFCore.tests.base.testcase import SecurityTest
 
 CMF_SECURITY_INDEXES = CMFCatalogAware._cmf_security_indexes
 
@@ -84,10 +90,24 @@
             res.append(self.brain_class(ob, obpath))
         return res
 
+
+class DummyWorkflowTool(SimpleItem):
+
+    def __init__(self):
+        self.log = []
+
+    def notifyCreated(self, obj):
+        self.log.append('created %s' % physicalpath(obj))
+
+
 class TheClass(CMFCatalogAware, Folder):
+
+    implements(IContentish)
+
     def __init__(self, id):
         self._setId(id)
         self.notified = False
+
     def notifyModified(self):
         self.notified = True
 
@@ -99,7 +119,7 @@
         self.root.site = SimpleFolder('site')
         self.site = self.root.site
         self.site._setObject('portal_catalog', DummyCatalog())
-        self.site._setObject('portal_workflow', WorkflowTool())
+        self.site._setObject('portal_workflow', DummyWorkflowTool())
         self.site.foo = TheClass('foo')
 
     def tearDown(self):
@@ -193,9 +213,153 @@
 
     # FIXME: more tests needed
 
+
+class CMFCatalogAware_CopySupport_Tests(SecurityTest, ContentEventAwareTests):
+
+    def setUp(self):
+        SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
+
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self)
+
+    def _makeSite(self):
+        import cStringIO
+        from OFS.Application import Application
+        from OFS.tests.testCopySupport import makeConnection
+        from Testing.makerequest import makerequest
+
+        self.connection = makeConnection()
+        try:
+            r = self.connection.root()
+            a = Application()
+            r['Application'] = a
+            self.root = a
+            responseOut = self.responseOut = cStringIO.StringIO()
+            self.app = makerequest(self.root, stdout=responseOut)
+            site = SimpleFolder('site')
+            self.app._setObject('site', site)
+            site = self.app._getOb('site')
+            site._setObject('portal_catalog', DummyCatalog())
+            site._setObject('portal_workflow', DummyWorkflowTool())
+            # Hack, we need a _p_mtime for the file, so we make sure that it
+            # has one. We use a subtransaction, which means we can rollback
+            # later and pretend we didn't touch the ZODB.
+            transaction.savepoint(optimistic=True)
+        except:
+            self.connection.close()
+            raise
+        else:
+            return site
+
+    def _initPolicyAndUser( self
+                          , a_lambda=None
+                          , v_lambda=None
+                          , c_lambda=None
+                          ):
+        from AccessControl import SecurityManager
+        from Products.CMFCore.tests.base.testcase import newSecurityManager
+
+        def _promiscuous( *args, **kw ):
+            return 1
+
+        if a_lambda is None:
+            a_lambda = _promiscuous
+
+        if v_lambda is None:
+            v_lambda = _promiscuous
+
+        if c_lambda is None:
+            c_lambda = _promiscuous
+
+        scp = _SensitiveSecurityPolicy( v_lambda, c_lambda )
+        SecurityManager.setSecurityPolicy( scp )
+        newSecurityManager( None
+                          , _AllowedUser( a_lambda ).__of__( self.root ) )
+
+    def test_object_indexed_after_adding(self):
+
+        site = self._makeSite()
+        bar = TheClass('bar')
+        site._setObject('bar', bar)
+        cat = site.portal_catalog
+        self.assertEquals(cat.log, ["index /site/bar"])
+
+    def test_object_unindexed_after_removing(self):
+
+        site = self._makeSite()
+        bar = TheClass('bar')
+        site._setObject('bar', bar)
+        cat = site.portal_catalog
+        cat.log = []
+        site._delObject('bar')
+        self.assertEquals(cat.log, ["unindex /site/bar"])
+
+    def test_object_indexed_after_copy_and_pasting(self):
+
+        self._initPolicyAndUser() # allow copy/paste operations
+        site = self._makeSite()
+        site.folder1 = SimpleFolder('folder1')
+        folder1 = site.folder1
+        site.folder2 = SimpleFolder('folder2')
+        folder2 = site.folder2
+
+        bar = TheClass('bar')
+        folder1._setObject('bar', bar)
+        cat = site.portal_catalog
+        cat.log = []
+
+        transaction.savepoint(optimistic=True)
+
+        cookie = folder1.manage_copyObjects(ids=['bar'])
+        folder2.manage_pasteObjects(cookie)
+
+        self.assertEquals(cat.log, ["index /site/folder2/bar"])
+
+    def test_object_reindexed_after_cut_and_paste(self):
+
+        self._initPolicyAndUser() # allow copy/paste operations
+        site = self._makeSite()
+        site.folder1 = SimpleFolder('folder1')
+        folder1 = site.folder1
+        site.folder2 = SimpleFolder('folder2')
+        folder2 = site.folder2
+
+        bar = TheClass('bar')
+        folder1._setObject('bar', bar)
+        cat = site.portal_catalog
+        cat.log = []
+
+        transaction.savepoint(optimistic=True)
+
+        cookie = folder1.manage_cutObjects(ids=['bar'])
+        folder2.manage_pasteObjects(cookie)
+
+        self.assertEquals(cat.log, ["unindex /site/folder1/bar",
+                                    "reindex /site/folder2/bar []"])
+
+    def test_object_reindexed_after_moving(self):
+
+        self._initPolicyAndUser() # allow copy/paste operations
+        site = self._makeSite()
+
+        bar = TheClass('bar')
+        site._setObject('bar', bar)
+        cat = site.portal_catalog
+        cat.log = []
+
+        transaction.savepoint(optimistic=True)
+
+        site.manage_renameObject(id='bar', new_id='baz')
+        self.assertEquals(cat.log, ["unindex /site/bar",
+                                    "reindex /site/baz []"])
+
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite(CMFCatalogAwareTests),
+        unittest.makeSuite(CMFCatalogAware_CopySupport_Tests),
         ))
 
 if __name__ == '__main__':

Modified: CMF/trunk/CMFCore/tests/test_OpaqueItems.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_OpaqueItems.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/tests/test_OpaqueItems.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -21,6 +21,7 @@
 
 from Products.CMFCore.interfaces import ICallableOpaqueItem
 from Products.CMFCore.interfaces import ICallableOpaqueItemEvents
+from Products.CMFCore.interfaces import IContentish
 from Products.CMFCore.interfaces.IOpaqueItems \
         import ICallableOpaqueItem as z2ICallableOpaqueItem
 from Products.CMFCore.interfaces.IOpaqueItems \
@@ -28,6 +29,7 @@
 from Products.CMFCore.PortalFolder import PortalFolder
 from Products.CMFCore.tests.base.dummy \
     import DummyContent as OriginalDummyContent
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
 from Products.CMFCore.tests.base.testcase import SecurityTest
 from Products.CMFCore.TypesTool import TypesTool
 
@@ -46,8 +48,10 @@
 
 
 class DummyContent(OriginalDummyContent):
+
     """ A Dummy piece of PortalContent with additional attributes
     """
+    implements(IContentish)
 
     def __init__(self, id='dummy', opaqueItem=None, *args, **kw):
         OriginalDummyContent.__init__(self, id, *args, **kw)
@@ -92,6 +96,7 @@
     def getId(self):
         return self.id
 
+
 class Marker(OpaqueBase):
     """ Opaque item without manage_after/before hookes but marked as callable
     """
@@ -100,6 +105,7 @@
         z2ICallableOpaqueItem,
     )
 
+
 class Hooks(OpaqueBase):
     """ Opaque item with manage_after/before hooks but not marked as callable
     """
@@ -131,10 +137,11 @@
 # Unit Tests
 # -------------------------------------------
 
-class ManageBeforeAfterTests(SecurityTest):
+class ManageBeforeAfterTests(SecurityTest, ContentEventAwareTests):
 
     def setUp(self):
         SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
 
         root = self.root
 
@@ -142,8 +149,10 @@
         root._setObject( 'portal_types', TypesTool() )
 
         # setup portal
-        try: root._delObject('test')
-        except AttributeError: pass
+        try:
+            root._delObject('test')
+        except AttributeError:
+            pass
         root._setObject('test', PortalFolder('test', ''))
         self.test = test = self.root.test
 
@@ -158,11 +167,19 @@
         sub.all_meta_types = extra_meta_types()
 
         # delete items if necessary
-        try: folder._delObject('dummy')
-        except AttributeError: pass
-        try: sub._delObject('dummy')
-        except AttributeError: pass
+        try:
+            folder._delObject('dummy')
+        except AttributeError:
+            pass
+        try:
+            sub._delObject('dummy')
+        except AttributeError:
+            pass
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self)
+
     def test_nonCallableItem(self):
         # no exception should be raised
         folder = self.folder

Modified: CMF/trunk/CMFCore/tests/test_PortalContent.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_PortalContent.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/tests/test_PortalContent.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -23,6 +23,7 @@
 
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyUserFolder
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
 from Products.CMFCore.tests.base.testcase import SecurityRequestTest
 
 
@@ -49,18 +50,23 @@
         verifyClass(IDynamicType, PortalContent)
 
 
-class TestContentCopyPaste(SecurityRequestTest):
+class TestContentCopyPaste(SecurityRequestTest, ContentEventAwareTests):
 
     # Tests related to http://www.zope.org/Collectors/CMF/205
     # Copy/pasting a content item must set ownership to pasting user
 
     def setUp(self):
         SecurityRequestTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
 
         self.root._setObject('site', DummySite('site'))
         self.site = self.root.site
         self.acl_users = self.site._setObject('acl_users', DummyUserFolder())
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityRequestTest.tearDown(self)
+
     def _initContent(self, folder, id):
         from Products.CMFCore.PortalContent import PortalContent
 

Modified: CMF/trunk/CMFCore/tests/test_PortalFolder.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_PortalFolder.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFCore/tests/test_PortalFolder.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -37,6 +37,7 @@
 from Products.CMFCore.tests.base.dummy import DummyFactory
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyUserFolder
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
 from Products.CMFCore.tests.base.testcase import newSecurityManager
 from Products.CMFCore.tests.base.testcase import noSecurityManager
 from Products.CMFCore.tests.base.testcase import SecurityTest
@@ -53,11 +54,12 @@
              'permission': 'View'}]
 
 
-class PortalFolderFactoryTests( SecurityTest ):
+class PortalFolderFactoryTests(SecurityTest, ContentEventAwareTests):
 
-    def setUp( self ):
+    def setUp(self):
         from Products.CMFCore.PortalFolder import PortalFolder
-        SecurityTest.setUp( self )
+        SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
 
         self.root._setObject( 'portal_types', TypesTool() )
         types_tool = self.root.portal_types
@@ -73,6 +75,10 @@
         fti = FTIDATA_DUMMY[0].copy()
         types_tool._setObject( 'Dummy Content', FTI(**fti) )
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self)
+
     def _makeOne( self, id ):
         from Products.CMFCore.PortalFolder import PortalFolder
         return PortalFolder( id ).__of__( self.root )
@@ -111,12 +117,17 @@
                          , type_name='Dummy Content', id='foo' )
 
 
-class PortalFolderTests(SecurityTest):
+class PortalFolderTests(SecurityTest, ContentEventAwareTests):
 
     def setUp(self):
         SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
         self.site = DummySite('site').__of__(self.root)
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self)
+
     def _getTargetClass(self):
         from Products.CMFCore.PortalFolder import PortalFolder
 
@@ -276,7 +287,7 @@
         self.assertEqual( len(ctool), 1 )
 
         foo.reset()
-        test.manage_delObjects( ids=['sub'] )
+        test._delObject('sub')
         self.failIf( foo.after_add_called )
         self.failUnless( foo.before_delete_called )
         self.assertEqual( len(ctool), 0 )
@@ -431,13 +442,18 @@
         self.failIf(test.checkIdAvailable('foo'))
 
 
-class PortalFolderMoveTests(SecurityTest):
+class PortalFolderMoveTests(SecurityTest, ContentEventAwareTests):
 
     def setUp(self):
         SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
         self.root._setObject( 'site', DummySite('site') )
         self.site = self.root.site
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self)
+
     def _makeOne(self, id, *args, **kw):
         from Products.CMFCore.PortalFolder import PortalFolder
 

Modified: CMF/trunk/CMFDefault/DiscussionItem.py
===================================================================
--- CMF/trunk/CMFDefault/DiscussionItem.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFDefault/DiscussionItem.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -210,7 +210,7 @@
         """
         if aq_base(container) is not aq_base(self):
             for obj in self.objectValues():
-                obj.__of__(self).manage_afterAdd(item, container)
+                obj.__of__(self).indexObject()
 
     security.declarePrivate('manage_afterClone')
     def manage_afterClone(self, item):
@@ -219,7 +219,7 @@
             Notify the workflow about the contained items.
         """
         for obj in self.objectValues():
-            obj.__of__(self).manage_afterClone(item)
+            obj.__of__(self).notifyWorkflowCreated()
 
     security.declarePrivate( 'manage_beforeDelete' )
     def manage_beforeDelete(self, item, container):
@@ -228,7 +228,7 @@
         """
         if aq_base(container) is not aq_base(self):
             for obj in self.objectValues():
-                obj.__of__( self ).manage_beforeDelete( item, container )
+                obj.__of__(self).unindexObject()
 
     #
     #   OFS.ObjectManager query interface.

Modified: CMF/trunk/CMFDefault/File.py
===================================================================
--- CMF/trunk/CMFDefault/File.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFDefault/File.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -131,24 +131,6 @@
         """
         return "%s %s" % (self.title, self.description)
 
-    security.declarePrivate('manage_afterAdd')
-    def manage_afterAdd(self, item, container):
-        """Both of my parents have an afterAdd method"""
-        OFS.Image.File.manage_afterAdd(self, item, container)
-        PortalContent.manage_afterAdd(self, item, container)
-
-    security.declarePrivate('manage_afterClone')
-    def manage_afterClone(self, item):
-        """Both of my parents have an afterClone method"""
-        OFS.Image.File.manage_afterClone(self, item)
-        PortalContent.manage_afterClone(self, item)
-
-    security.declarePrivate('manage_beforeDelete')
-    def manage_beforeDelete(self, item, container):
-        """Both of my parents have a beforeDelete method"""
-        PortalContent.manage_beforeDelete(self, item, container)
-        OFS.Image.File.manage_beforeDelete(self, item, container)
-
     security.declarePrivate('_isNotEmpty')
     def _isNotEmpty(self, file):
         """ Do various checks on 'file' to try to determine non emptiness. """

Modified: CMF/trunk/CMFDefault/Image.py
===================================================================
--- CMF/trunk/CMFDefault/Image.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFDefault/Image.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -127,24 +127,6 @@
         """
         return "%s %s" % (self.title, self.description)
 
-    security.declarePrivate('manage_afterAdd')
-    def manage_afterAdd(self, item, container):
-        """Both of my parents have an afterAdd method"""
-        OFS.Image.Image.manage_afterAdd(self, item, container)
-        PortalContent.manage_afterAdd(self, item, container)
-
-    security.declarePrivate('manage_afterClone')
-    def manage_afterClone(self, item):
-        """Both of my parents have an afterClone method"""
-        OFS.Image.Image.manage_afterClone(self, item)
-        PortalContent.manage_afterClone(self, item)
-
-    security.declarePrivate('manage_beforeDelete')
-    def manage_beforeDelete(self, item, container):
-        """Both of my parents have a beforeDelete method"""
-        PortalContent.manage_beforeDelete(self, item, container)
-        OFS.Image.Image.manage_beforeDelete(self, item, container)
-
     security.declarePrivate('_isNotEmpty')
     def _isNotEmpty(self, file):
         """ Do various checks on 'file' to try to determine non emptiness. """

Modified: CMF/trunk/CMFDefault/SkinnedFolder.py
===================================================================
--- CMF/trunk/CMFDefault/SkinnedFolder.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFDefault/SkinnedFolder.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -17,8 +17,10 @@
 
 from AccessControl import ClassSecurityInfo
 from Globals import InitializeClass
+from zope.interface import implements
 
 from Products.CMFCore.CMFCatalogAware import CMFCatalogAware
+from Products.CMFCore.interfaces import IContentish
 from Products.CMFCore.PortalFolder import PortalFolder
 
 from DublinCore import DefaultDublinCoreImpl
@@ -31,6 +33,8 @@
     """ Skinned Folder class. 
     """
 
+    implements(IContentish)
+
     meta_type = 'Skinned Folder'
 
     security = ClassSecurityInfo()

Modified: CMF/trunk/CMFDefault/tests/test_Discussions.py
===================================================================
--- CMF/trunk/CMFDefault/tests/test_Discussions.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFDefault/tests/test_Discussions.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -15,15 +15,14 @@
 $Id$
 """
 
-from unittest import TestCase, TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
 from Products.CMFCore.CatalogTool import CatalogTool
 from Products.CMFCore.tests.base.dummy import DummyContent
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyTool
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
 from Products.CMFCore.tests.base.testcase import SecurityTest
 from Products.CMFCore.tests.base.tidata import FTIDATA_DUMMY
 from Products.CMFCore.tests.base.utils import has_path
@@ -34,7 +33,7 @@
 from Products.CMFDefault.exceptions import DiscussionNotAllowed
 
 
-class DiscussionItemTests(TestCase):
+class DiscussionItemTests(unittest.TestCase):
 
     def test_z2interfaces(self):
         from Interface.Verify import verifyClass
@@ -77,7 +76,7 @@
         verifyClass(IMutableDublinCore, DiscussionItem)
 
 
-class DiscussionItemContainerTests(TestCase):
+class DiscussionItemContainerTests(unittest.TestCase):
 
     def test_z2interfaces(self):
         from Interface.Verify import verifyClass
@@ -95,15 +94,20 @@
         verifyClass(IDiscussable, DiscussionItemContainer)
 
 
-class DiscussionTests( SecurityTest ):
+class DiscussionTests(SecurityTest, ContentEventAwareTests):
 
-    def setUp( self ):
+    def setUp(self):
         SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
         self.site = DummySite('site').__of__(self.root)
         self.site._setObject( 'portal_discussion', DiscussionTool() )
         self.site._setObject( 'portal_membership', DummyTool() )
         self.site._setObject( 'portal_types', TypesTool() )
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self)
+
     def _makeDummyContent(self, id, *args, **kw):
         return self.site._setObject( id, DummyContent(id, *args, **kw) )
 
@@ -299,18 +303,18 @@
         self.assertEqual(len(talkback4.getReplies()), 1)
         self.assertEqual(len(talkback5.getReplies()), 1)
         self.assertEqual(len(talkback6.getReplies()), 0)
-        self.assertEqual(len(ctool), 6)
+        self.assertEqual(len(ctool), 7)
 
         talkback3.deleteReply(id4)
         self.assertEqual(len(talkback.getReplies()), 1)
         self.assertEqual(len(talkback1.getReplies()), 1)
         self.assertEqual(len(talkback2.getReplies()), 1)
         self.assertEqual(len(talkback3.getReplies()), 0)
-        self.assertEqual(len(ctool), 3)
+        self.assertEqual(len(ctool), 4)
 
         talkback.deleteReply(id1)
         self.assertEqual(len(talkback.getReplies()), 0)
-        self.assertEqual(len(ctool), 0)
+        self.assertEqual(len(ctool), 1)
 
     def test_newTalkbackIsWrapped(self):
         test = self._makeDummyContent('test')
@@ -333,11 +337,11 @@
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite( DiscussionItemTests ),
-        makeSuite( DiscussionItemContainerTests ),
-        makeSuite( DiscussionTests ),
+    return unittest.TestSuite((
+        unittest.makeSuite(DiscussionItemTests),
+        unittest.makeSuite(DiscussionItemContainerTests),
+        unittest.makeSuite(DiscussionTests),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/trunk/CMFDefault/tests/test_Image.py
===================================================================
--- CMF/trunk/CMFDefault/tests/test_Image.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFDefault/tests/test_Image.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -25,14 +25,15 @@
 import transaction
 from AccessControl.SecurityManagement import newSecurityManager
 from AccessControl.SecurityManagement import noSecurityManager
-from AccessControl.User import UnrestrictedUser
 from Products.Five import zcml
 from zope.testing.cleanup import cleanUp
 
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyTool
+from Products.CMFCore.tests.base.security import OmnipotentUser
 from Products.CMFCore.tests.base.testcase import _TRAVERSE_ZCML
-from Products.CMFCore.tests.base.testcase import RequestTest
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
+from Products.CMFCore.tests.base.testcase import SecurityRequestTest
 from Products.CMFDefault import tests
 
 from common import ConformsToContent
@@ -102,13 +103,14 @@
         self.assertEqual(image.content_type, 'image/jpeg')
 
 
-class TestImageCopyPaste(RequestTest):
+class TestImageCopyPaste(SecurityRequestTest, ContentEventAwareTests):
 
     # Tests related to http://www.zope.org/Collectors/CMF/176
     # Copy/pasting an image (or file) should reset the object's workflow state.
 
     def setUp(self):
-        RequestTest.setUp(self)
+        SecurityRequestTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
         zcml.load_config('permissions.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.GenericSetup)
@@ -116,10 +118,10 @@
         zcml.load_config('configure.zcml', Products.DCWorkflow)
         zcml.load_string(_TRAVERSE_ZCML)
         try:
-            newSecurityManager(None, UnrestrictedUser('manager', '', ['Manager'], []))
             factory = self.root.manage_addProduct['CMFDefault'].addConfiguredSite
             factory('cmf', 'CMFDefault:default', snapshot=False)
             self.site = self.root.cmf
+            newSecurityManager(None, OmnipotentUser().__of__(self.site))
             self.site.invokeFactory('File', id='file')
             self.site.portal_workflow.doActionFor(self.site.file, 'publish')
             self.site.invokeFactory('Image', id='image')
@@ -134,7 +136,8 @@
 
     def tearDown(self):
         noSecurityManager()
-        RequestTest.tearDown(self)
+        ContentEventAwareTests.tearDown(self)
+        SecurityRequestTest.tearDown(self)
         cleanUp()
 
     def test_File_CopyPasteResetsWorkflowState(self):

Modified: CMF/trunk/CMFDefault/tests/test_Portal.py
===================================================================
--- CMF/trunk/CMFDefault/tests/test_Portal.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFDefault/tests/test_Portal.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -24,10 +24,11 @@
 from zope.testing.cleanup import cleanUp
 
 from Products.CMFCore.tests.base.testcase import _TRAVERSE_ZCML
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
 from Products.CMFCore.tests.base.testcase import SecurityRequestTest
 
 
-class CMFSiteTests(SecurityRequestTest):
+class CMFSiteTests(SecurityRequestTest, ContentEventAwareTests):
 
     def _makeSite( self, id='testsite' ):
 
@@ -48,6 +49,7 @@
 
     def setUp(self):
         SecurityRequestTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
         zcml.load_config('permissions.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.GenericSetup)
@@ -56,6 +58,7 @@
         zcml.load_string(_TRAVERSE_ZCML)
 
     def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
         SecurityRequestTest.tearDown(self)
         cleanUp()
 

Modified: CMF/trunk/CMFTopic/tests/test_Topic.py
===================================================================
--- CMF/trunk/CMFTopic/tests/test_Topic.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFTopic/tests/test_Topic.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -21,6 +21,7 @@
 from Acquisition import Implicit
 
 from Products.CMFCore.tests.base.dummy import DummySite
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
 from Products.CMFCore.tests.base.testcase import SecurityTest
 from Products.CMFCore.TypesTool import FactoryTypeInformation as FTI
 from Products.CMFCore.TypesTool import TypesTool
@@ -118,15 +119,20 @@
         return self._max_items
 
 
-class TestTopic(SecurityTest):
+class TestTopic(SecurityTest, ContentEventAwareTests):
 
     """ Test all the general Topic cases.
     """
 
     def setUp(self):
         SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
         self.site = DummySite('site').__of__(self.root)
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self) 
+
     def _getTargetClass(self):
         from Products.CMFTopic.Topic import Topic
 

Modified: CMF/trunk/CMFUid/tests/test_uidannotation.py
===================================================================
--- CMF/trunk/CMFUid/tests/test_uidannotation.py	2006-05-18 21:58:41 UTC (rev 68180)
+++ CMF/trunk/CMFUid/tests/test_uidannotation.py	2006-05-19 07:33:31 UTC (rev 68181)
@@ -18,15 +18,20 @@
 import unittest
 import Testing
 
+from OFS.event import ObjectClonedEvent
+from zope.app.container.contained import ObjectAddedEvent
+from zope.event import notify
+
 from Products.CMFCore.PortalFolder import PortalFolder
 from Products.CMFCore.tests.base.dummy import DummyContent
+from Products.CMFCore.tests.base.testcase import ContentEventAwareTests
 from Products.CMFCore.tests.base.testcase import SecurityTest
 
 
 UID_ATTRNAME = 'cmf_uid'
 
 
-class UniqueIdAnnotationToolTests(SecurityTest):
+class UniqueIdAnnotationToolTests(ContentEventAwareTests, SecurityTest):
 
     def _getTargetClass(self):
         from Products.CMFUid.UniqueIdAnnotationTool \
@@ -36,9 +41,14 @@
 
     def setUp(self):
         SecurityTest.setUp(self)
+        ContentEventAwareTests.setUp(self)
         self.root._setObject('portal_uidannotation', self._getTargetClass()())
         self.root._setObject('dummy', DummyContent(id='dummy'))
 
+    def tearDown(self):
+        ContentEventAwareTests.tearDown(self)
+        SecurityTest.tearDown(self)
+
     def test_z3interfaces(self):
         from zope.interface.verify import verifyClass
         from Products.CMFUid.interfaces import IUniqueIdAnnotation
@@ -129,8 +139,8 @@
         annotation = self.root.portal_uidannotation(baz, UID_ATTRNAME)
         self.assertEqual( getattr(baz, UID_ATTRNAME), annotation )
 
-        foo.manage_afterAdd(foo, None)
-        foo.manage_afterClone(foo)
+        notify(ObjectAddedEvent(foo, foo))
+        notify(ObjectClonedEvent(foo))
         self.assertRaises(AttributeError, getattr, baz, UID_ATTRNAME)
 
 



More information about the CMF-checkins mailing list