[CMF-checkins] SVN: CMF/trunk/CMFUid/ - Forward-port CMFUid changes from the 2.1-branch:

Jens Vagelpohl jens at dataflake.org
Mon Apr 2 04:31:27 EDT 2007


Log message for revision 73977:
  - Forward-port CMFUid changes from the 2.1-branch:
  
      - CMFUid.UniqueIdAnnotationTool: Annotation handling has been switched
        from triggering it through old-style manage_*-methods to using
        events. UID assigning behavior has been made more flexible. Please
        review CMFUid/README.txt for information about the current
        behavior and the new features.
        (http://www.zope.org/Collectors/CMF/474)
  

Changed:
  U   CMF/trunk/CMFUid/README.txt
  U   CMF/trunk/CMFUid/UniqueIdAnnotationTool.py
  U   CMF/trunk/CMFUid/configure.zcml
  A   CMF/trunk/CMFUid/event.zcml
  U   CMF/trunk/CMFUid/interfaces.py
  A   CMF/trunk/CMFUid/profiles/default/catalog.xml
  U   CMF/trunk/CMFUid/profiles/default/componentregistry.xml
  A   CMF/trunk/CMFUid/testing.py
  U   CMF/trunk/CMFUid/tests/test_uidannotation.py

-=-
Modified: CMF/trunk/CMFUid/README.txt
===================================================================
--- CMF/trunk/CMFUid/README.txt	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/README.txt	2007-04-02 08:31:27 UTC (rev 73977)
@@ -15,7 +15,8 @@
         
             The 'portal_uidgenerator' tools responsibility is to generate 
             unique ids. The 'portal_uidannotation' tool is responsible to 
-            attach unique ids to a content object. The 'portal_uidhandler' 
+            attach unique ids to a content object, and enforce rules about
+            what happens on object move/create/delete. The 'portal_uidhandler' 
             manages registering and accessing unique ids. 
             
             This design was chosen to allow users replacing only parts of
@@ -40,7 +41,14 @@
         
         The current implementation of get/queryBrain and get/queryObject 
         do not return invisible objects (and brains of invisible objects).
+        By invisible objects, we mean objects that would be filtered out
+        by portal_catalog.searchResults due to expiry/effective date and/or
+        user roles.
         
+        It is often necessary to avoid this filtering in an application.
+        To do this, use the unrestrictedGet/QueryBrain and
+        unrestrictedGet/QueryObject as this will avoid 'None' results.
+
         Have a look at the interfaces.
         
         CMFUid's functionality is used by CMFDefault's favorite content type 
@@ -50,3 +58,43 @@
         See 'CMFDefault.Favorite.Favorite'.
     
     gregweb/2004-08-05
+
+UPDATE 2007-03-30
+=================
+
+The annotation code has been updated to use events for assigning/removing 
+uids.  The settings for this live in the portal_uidannotation tool.
+
+The default behaviour is:
+
+ - uids are NOT assigned when an object is created
+   (it is assumed that other code is responsible for this)
+
+ - when an object is moved, a UID is not changed
+
+ - when an object is imported, any EXISTING UID is removed
+   (this can be controlled via the 'remove_on_add' property)
+
+ - when an object is copied, any EXISTING UID is removed
+   (this can be controlled via the 'remove_on_clone' property)
+
+A more natural behaviour is for UIDs to be assigned automatically on 
+creation.  To enable this feature:
+
+ - tick the 'assign UIDs on add' tickbox
+   (uids will now be assigned when content is added or imported and any
+   EXISTING uid will be replaced)
+
+ - tick the 'assign UIDs on copy' tickbox
+   (objects will get a NEW uid when they are copied which will replace 
+   any EXISTING uid)
+
+In order to preserve the original behaviour of the tool, automatic 
+assignment of uids is NOT enabled by default - it must be turned on in 
+the uidannotation tool.
+
+The behaviour is hooked in based on object creating/deletion/move events
+for any IContentish objects.  The event handlers live in the 
+UniqueIdAnnotation tool.
+
+

Modified: CMF/trunk/CMFUid/UniqueIdAnnotationTool.py
===================================================================
--- CMF/trunk/CMFUid/UniqueIdAnnotationTool.py	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/UniqueIdAnnotationTool.py	2007-04-02 08:31:27 UTC (rev 73977)
@@ -24,16 +24,20 @@
 from Globals import Persistent
 from OFS.PropertyManager import PropertyManager
 from OFS.SimpleItem import SimpleItem
-from zope.component import getUtility
+from zope.component import queryUtility
 from zope.interface import implements
 
 from Products.CMFCore.ActionProviderBase import ActionProviderBase
 from Products.CMFCore.utils import registerToolInterface
 from Products.CMFCore.utils import UniqueObject
 
+from Products.CMFUid.interfaces import IUniqueIdHandler
 from Products.CMFUid.interfaces import IUniqueIdAnnotation
 from Products.CMFUid.interfaces import IUniqueIdAnnotationManagement
+from Products.CMFUid.interfaces import UniqueIdError
 
+from OFS.interfaces import IObjectClonedEvent
+from zope.app.container.interfaces import IObjectAddedEvent
 
 class UniqueIdAnnotation(Persistent, Implicit):
 
@@ -64,50 +68,47 @@
         """
         self._uid = uid
 
-    def manage_afterClone(self, item):
-        """See IUniqueIdAnnotation.
-        """
-        # Duplicated unique ids on the copied object have to be avoided.
-        # the uid object may already be removed by the 'manage_afterAdd'.
-        # To be independent of the implementation of 'manage_afterAdd'
-        # the unique id object probably gets removed another time.
-        anno_tool = getUtility(IUniqueIdAnnotationManagement)
-        if anno_tool.remove_on_clone:
-            try:
-                delattr( aq_parent( aq_inner(self) ), self.id )
-            except (KeyError, AttributeError):
-                pass
+InitializeClass(UniqueIdAnnotation)
 
-    def manage_beforeDelete(self, item, container):
-        """See IUniqueIdAnnotation.
-        """
-        # This helps in distinguishing renaming from copying/adding and
-        # importing in 'manage_afterAdd' (see below)
-        anno_tool = getUtility(IUniqueIdAnnotationManagement)
-        if anno_tool.remove_on_add:
-            self._cmf_uid_is_rename = True
+def handleUidAnnotationEvent(ob, event):
+    """ Event subscriber for (IUniqueIdAnnotation, IObjectEvent) events
+    """
 
-    def manage_afterAdd(self, item, container):
-        """See IUniqueIdAnnotation.
-        """
-        # 'is_rename' is set if deletion was caused by a rename/move.
-        # The unique id is deleted only if the call is not part of
-        # a rename operation.
-        # This way I the unique id gets deleted on imports.
-        _is_rename = getattr(aq_base(self), '_cmf_uid_is_rename', None)
-        anno_tool = getUtility(IUniqueIdAnnotationManagement)
-        if anno_tool.remove_on_add and anno_tool.remove_on_clone \
-           and not _is_rename:
-            try:
-                delattr( aq_parent( aq_inner(self) ), self.id )
-            except (KeyError, AttributeError):
-                pass
-        if _is_rename is not None:
-            del self._cmf_uid_is_rename
+    if IObjectAddedEvent.providedBy(event):
+        if event.newParent is not None:
+            anno_tool = queryUtility(IUniqueIdAnnotationManagement)
+            uid_handler = queryUtility(IUniqueIdHandler)
+            if anno_tool is not None:
+                remove_on_add = anno_tool.getProperty('remove_on_add',False)
+                remove_on_clone = anno_tool.getProperty('remove_on_clone',False)
+                assign_on_add = anno_tool.getProperty('assign_on_add',False)
 
-InitializeClass(UniqueIdAnnotation)
-
-
+                if (remove_on_add and remove_on_clone) or assign_on_add:
+                    try:
+                        uid_handler.unregister(ob)
+                    except UniqueIdError:
+                        # did not have one
+                        pass
+                if assign_on_add:
+                    # assign new uid
+                    uid_handler.register(ob)
+                 
+    elif IObjectClonedEvent.providedBy(event):
+        anno_tool = queryUtility(IUniqueIdAnnotationManagement)
+        uid_handler = queryUtility(IUniqueIdHandler)
+        if anno_tool is not None:
+            remove_on_clone = anno_tool.getProperty('remove_on_clone', False)
+            assign_on_clone = anno_tool.getProperty('assign_on_clone', False)
+            if remove_on_clone or assign_on_clone:
+                try:
+                    uid_handler.unregister(ob)
+                except UniqueIdError:
+                    # did not have one
+                    pass
+            if assign_on_clone:
+                # assign new uid
+                uid_handler.register(ob)
+        
 class UniqueIdAnnotationTool(UniqueObject, SimpleItem, PropertyManager,
                              ActionProviderBase):
 
@@ -129,11 +130,17 @@
 
     remove_on_add = True
     remove_on_clone = True
+    assign_on_add = False
+    assign_on_clone = False
     _properties = (
     {'id': 'remove_on_add', 'type': 'boolean', 'mode': 'w',
      'label': "Remove the objects unique id on add (and import)"},
     {'id': 'remove_on_clone', 'type': 'boolean', 'mode': 'w',
      'label': 'Remove the objects unique id on clone (CAUTION !!!)'},
+    {'id': 'assign_on_add', 'type': 'boolean', 'mode': 'w',
+     'label': "Assign a unique ID when an object is added"},
+    {'id': 'assign_on_clone', 'type': 'boolean', 'mode': 'w',
+     'label': "Assign a unique ID when an object is cloned"},
     )
 
     security.declarePrivate('__call__')

Modified: CMF/trunk/CMFUid/configure.zcml
===================================================================
--- CMF/trunk/CMFUid/configure.zcml	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/configure.zcml	2007-04-02 08:31:27 UTC (rev 73977)
@@ -3,6 +3,8 @@
     xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
     i18n_domain="cmf_default">
 
+  <include file="event.zcml" />
+
   <!-- profiles -->
 
   <genericsetup:registerProfile

Added: CMF/trunk/CMFUid/event.zcml
===================================================================
--- CMF/trunk/CMFUid/event.zcml	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/event.zcml	2007-04-02 08:31:27 UTC (rev 73977)
@@ -0,0 +1,10 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope">
+
+  <subscriber
+      for="Products.CMFCore.interfaces.IContentish
+           zope.component.interfaces.IObjectEvent"
+      handler=".UniqueIdAnnotationTool.handleUidAnnotationEvent"
+      />
+
+</configure>


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

Modified: CMF/trunk/CMFUid/interfaces.py
===================================================================
--- CMF/trunk/CMFUid/interfaces.py	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/interfaces.py	2007-04-02 08:31:27 UTC (rev 73977)
@@ -60,7 +60,7 @@
         """
 
 
-class IUniqueIdAnnotation(ICallableOpaqueItem, ICallableOpaqueItemEvents):
+class IUniqueIdAnnotation(ICallableOpaqueItem):
 
     """Opaque unique id item handling adding, copying, and deletion events.
     """

Added: CMF/trunk/CMFUid/profiles/default/catalog.xml
===================================================================
--- CMF/trunk/CMFUid/profiles/default/catalog.xml	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/profiles/default/catalog.xml	2007-04-02 08:31:27 UTC (rev 73977)
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<object name="portal_catalog" meta_type="CMF Catalog">
+ <index name="cmf_uid" meta_type="FieldIndex">
+  <indexed_attr value="cmf_uid"/>
+ </index>
+ <column value="cmf_uid"/>
+</object>


Property changes on: CMF/trunk/CMFUid/profiles/default/catalog.xml
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: CMF/trunk/CMFUid/profiles/default/componentregistry.xml
===================================================================
--- CMF/trunk/CMFUid/profiles/default/componentregistry.xml	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/profiles/default/componentregistry.xml	2007-04-02 08:31:27 UTC (rev 73977)
@@ -3,13 +3,13 @@
  <adapters/>
  <utilities>
   <utility
-     interface="Products.CMFUid.interfaces.IUniqueIdAnnotationManagement"
-     object="/portal_uidannotation"/>
-  <utility
      interface="Products.CMFUid.interfaces.IUniqueIdGenerator"
      object="/portal_uidgenerator"/>
   <utility
      interface="Products.CMFUid.interfaces.IUniqueIdHandler"
      object="/portal_uidhandler"/>
+  <utility
+     interface="Products.CMFUid.interfaces.IUniqueIdAnnotationManagement"
+     object="/portal_uidannotation"/>
  </utilities>
 </componentregistry>

Added: CMF/trunk/CMFUid/testing.py
===================================================================
--- CMF/trunk/CMFUid/testing.py	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/testing.py	2007-04-02 08:31:27 UTC (rev 73977)
@@ -0,0 +1,19 @@
+from zope.app.component.hooks import setHooks
+from zope.testing.cleanup import cleanUp
+from Products.Five import zcml
+
+class UidEventZCMLLayer:
+
+    @classmethod
+    def testSetUp(cls):
+        import Products
+
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('event.zcml', Products.Five)
+        zcml.load_config('event.zcml', Products.CMFUid)
+        setHooks()
+
+    @classmethod
+    def testTearDown(cls):
+        cleanUp()
+


Property changes on: CMF/trunk/CMFUid/testing.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: CMF/trunk/CMFUid/tests/test_uidannotation.py
===================================================================
--- CMF/trunk/CMFUid/tests/test_uidannotation.py	2007-04-02 08:30:04 UTC (rev 73976)
+++ CMF/trunk/CMFUid/tests/test_uidannotation.py	2007-04-02 08:31:27 UTC (rev 73977)
@@ -18,25 +18,55 @@
 import unittest
 import Testing
 
-from OFS.event import ObjectClonedEvent
+from Acquisition import Implicit
 
-from zope.app.container.contained import ObjectAddedEvent
 from zope.component import getSiteManager
-from zope.event import notify
+from zope.component import getUtility
 from zope.interface.verify import verifyClass
+from zope.interface import implements
 
 from Products.CMFCore.PortalFolder import PortalFolder
-from Products.CMFCore.testing import EventZCMLLayer
+from Products.CMFUid.testing import UidEventZCMLLayer
 from Products.CMFCore.tests.base.dummy import DummyContent
 from Products.CMFCore.tests.base.testcase import SecurityTest
 from Products.CMFUid.interfaces import IUniqueIdAnnotationManagement
+from Products.CMFUid.interfaces import IUniqueIdHandler
+from Products.CMFUid.interfaces import UniqueIdError
 
+from Products.CMFCore.tests.test_PortalFolder import _AllowedUser
+from Products.CMFCore.tests.test_PortalFolder import _SensitiveSecurityPolicy
+from AccessControl.SecurityManagement import newSecurityManager
+from Products.CMFCore.tests.test_CMFCatalogAware import TheClass
+from Products.CMFCore.tests.test_CMFCatalogAware import SimpleFolder
+
+import transaction
+
 UID_ATTRNAME = 'cmf_uid'
 
+class DummyUniqueIdHandlerTool(Implicit):
 
+    implements(IUniqueIdHandler)
+
+    def __init__(self):
+        self.counter = 0
+
+    def register(self, ob):
+
+        uid_assigner = getUtility(IUniqueIdAnnotationManagement)
+        annotation = uid_assigner(ob, UID_ATTRNAME)
+        annotation.setUid( self.counter )
+        self.counter += 1
+
+    def unregister(self, ob):
+
+        try:
+           delattr(ob, UID_ATTRNAME)
+        except AttributeError:
+           raise UniqueIdError
+
 class UniqueIdAnnotationToolTests(SecurityTest):
 
-    layer = EventZCMLLayer
+    layer = UidEventZCMLLayer
 
     def _getTargetClass(self):
         from Products.CMFUid.UniqueIdAnnotationTool \
@@ -47,13 +77,44 @@
     def setUp(self):
         SecurityTest.setUp(self)
         self.root._setObject('portal_uidannotation', self._getTargetClass()())
-        self.root._setObject('dummy', DummyContent(id='dummy'))
+        self.root._setObject('portal_uidhandler', DummyUniqueIdHandlerTool())
 
         sm = getSiteManager()
         sm.registerUtility( self.root.portal_uidannotation
                           , IUniqueIdAnnotationManagement
                           )
+        sm.registerUtility( self.root.portal_uidhandler
+                          , IUniqueIdHandler)
 
+        self.root._setObject('dummy', DummyContent(id='dummy'))
+        self.root._setObject('site', SimpleFolder('site'))
+
+        transaction.savepoint(optimistic=True)
+
+    def _initPolicyAndUser( self
+                          , a_lambda=None
+                          , v_lambda=None
+                          , c_lambda=None
+                          ):
+        from AccessControl import SecurityManager
+
+        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.app.acl_users))
+
     def test_interfaces(self):
         from Products.CMFUid.interfaces import IUniqueIdAnnotation
         from Products.CMFUid.interfaces import IUniqueIdAnnotationManagement
@@ -84,70 +145,139 @@
     #   obj.manage_afterAdd(obj_at_target, obj_at_target, target_folder)
     #   obj.manage_afterClone(obj_at_target, obj_at_target)
 
+    def test_simulateItemAddAssigningUid(self):
+        # an annotated object is set in place
+        dummy = DummyContent(id='dummycontent')
+        self.root.portal_uidannotation.assign_on_add = True
+        self.root._setObject('dummycontent', dummy)
+
+        annotation = getattr(dummy, UID_ATTRNAME, None)
+
+        self.failUnless(annotation is not None)
+    
     def test_simulateItemAddRemovingUid(self):
-        dummy = self.root.dummy
+        # an annotated object is set in place
+        dummy = DummyContent(id='dummycontent')
         annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+        self.root._setObject('dummycontent', dummy)
 
-        annotation.__of__(dummy).manage_afterAdd(dummy, None)
         self.assertRaises(AttributeError, getattr, dummy, UID_ATTRNAME)
 
+    def test_simulateItemAddAssignsNewUid(self):
+        # an annotated object is set in place
+        dummy = DummyContent(id='dummycontent')
+        annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+        self.root.portal_uidannotation.assign_on_add = True
+        self.root._setObject('dummycontent', dummy)
+
+        self.failIf( getattr(dummy, UID_ATTRNAME)()==annotation() )
+
     def test_simulateItemAddDoesNotTouchUid(self):
-        dummy = self.root.dummy
+        # an annotated object is set in place
+        dummy = DummyContent(id='dummycontent')
         annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+        self.root.portal_uidannotation.remove_on_add = False
+        self.root._setObject('dummycontent', dummy)
 
-        self.root.portal_uidannotation.remove_on_add = False
-        annotation.__of__(dummy).manage_afterAdd(dummy, None)
         self.assertEqual(getattr(dummy, UID_ATTRNAME), annotation)
 
     def test_simulateItemRename(self):
-        dummy = self.root.dummy
+        # an object is set in place, annotated and then renamed
+        self._initPolicyAndUser() # allow copy/paste operations
+        dummy = TheClass('dummy')
+        site = self.root.site
+        site._setObject('dummy', dummy)
         annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
 
-        annotation.__of__(dummy).manage_beforeDelete(dummy, None)
-        annotation.__of__(dummy).manage_afterAdd(dummy, None)
-        self.assertEqual(getattr(dummy, UID_ATTRNAME), annotation)
+        transaction.savepoint(optimistic=True)
 
+        site.manage_renameObject(id='dummy', new_id='dummy2')
+        new_annotation = getattr(site.dummy2, UID_ATTRNAME)
+        self.assertEqual(annotation(), new_annotation())
+
     def test_simulateItemCloneRemovingUid1(self):
-        dummy = self.root.dummy
+        # an object is set in place, annotated and then copied
+        self._initPolicyAndUser() # allow copy/paste operations
+        dummy = TheClass('dummy')
+        site = self.root.site
+        site._setObject('dummy', dummy)
         annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+        self.root._setObject('folder1', SimpleFolder('folder1'))
 
-        annotation.__of__(dummy).manage_afterAdd(dummy, None)
-        annotation.__of__(dummy).manage_afterClone(dummy)
-        self.assertRaises(AttributeError, getattr, dummy, UID_ATTRNAME)
+        transaction.savepoint(optimistic=True)
+        cookie = site.manage_copyObjects(ids=['dummy'])
+        self.root.folder1.manage_pasteObjects( cookie )
 
+        self.assertRaises(AttributeError, getattr, self.root.folder1.dummy, UID_ATTRNAME)
+
     def test_simulateItemCloneRemovingUid2(self):
-        dummy = self.root.dummy
+        # an object is set in place, annotated and then copied
+        self._initPolicyAndUser() # allow copy/paste operations
+        dummy = TheClass('dummy')
+        site = self.root.site
+        site._setObject('dummy', dummy)
         annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
-
         self.root.portal_uidannotation.remove_on_add = False
-        annotation.__of__(dummy).manage_afterAdd(dummy, None)
-        annotation.__of__(dummy).manage_afterClone(dummy)
-        self.assertRaises(AttributeError, getattr, dummy, UID_ATTRNAME)
+        self.root._setObject('folder1', SimpleFolder('folder1'))
 
+        transaction.savepoint(optimistic=True)
+        cookie = site.manage_copyObjects(ids=['dummy'])
+        self.root.folder1.manage_pasteObjects( cookie )
+
+        self.assertRaises(AttributeError, getattr, self.root.folder1.dummy, UID_ATTRNAME)
+
     def test_simulateItemCloneDoesNotTouchUid(self):
-        dummy = self.root.dummy
+        # an object is set in place, annotated, and then copied
+        self._initPolicyAndUser() # allow copy/paste operations
+        dummy = TheClass('dummy')
+        site = self.root.site
+        site._setObject('dummy', dummy)
         annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
-
         self.root.portal_uidannotation.remove_on_clone = False
-        annotation.__of__(dummy).manage_afterAdd(dummy, None)
-        annotation.__of__(dummy).manage_afterClone(dummy)
-        self.assertEqual(getattr(dummy, UID_ATTRNAME), annotation)
+        self.root._setObject('folder1', SimpleFolder('folder1'))
 
+        transaction.savepoint(optimistic=True)
+        cookie = site.manage_copyObjects(ids=['dummy'])
+        self.root.folder1.manage_pasteObjects( cookie )
+        new_annotation = getattr(self.root.folder1.dummy, UID_ATTRNAME)
+
+        self.assertEqual(annotation(), new_annotation() )
+
+    def test_simulateItemCloneAssignsNewUid(self):
+        # an object is set in place, annotated, and then copied
+        self._initPolicyAndUser() # allow copy/paste operations
+        dummy = TheClass('dummy')
+        site = self.root.site
+        site._setObject('dummy', dummy)
+        annotation = self.root.portal_uidannotation(dummy, UID_ATTRNAME)
+        self.root.portal_uidannotation.assign_on_clone = True
+        self.root._setObject('folder1', SimpleFolder('folder1'))
+
+        transaction.savepoint(optimistic=True)
+        cookie = site.manage_copyObjects(ids=['dummy'])
+        self.root.folder1.manage_pasteObjects( cookie )
+        new_annotation = getattr(self.root.folder1.dummy, UID_ATTRNAME)
+
+        self.failIf( annotation() == new_annotation() )
+
     def test_simulateNestedFolderCloneRemovingUid1(self):
-        self.root._setObject( 'foo', PortalFolder(id='foo') )
-        foo = self.root.foo
-        foo._setObject( 'sub1', PortalFolder(id='sub1') )
-        foo.sub1._setObject( 'sub2', PortalFolder(id='sub2') )
+        self.root.site._setObject( 'foo', SimpleFolder(id='foo') )
+        self.root.site._setObject( 'foo2', SimpleFolder(id='foo2') )
+        foo = self.root.site.foo
+        foo._setObject( 'sub1', SimpleFolder(id='sub1') )
+        foo.sub1._setObject( 'sub2', SimpleFolder(id='sub2') )
         foo.sub1.sub2._setObject( 'baz', DummyContent(id='baz', catalog=1) )
         baz = foo.sub1.sub2.baz
         annotation = self.root.portal_uidannotation(baz, UID_ATTRNAME)
         self.assertEqual( getattr(baz, UID_ATTRNAME), annotation )
 
-        notify(ObjectAddedEvent(foo, foo))
-        notify(ObjectClonedEvent(foo))
-        self.assertRaises(AttributeError, getattr, baz, UID_ATTRNAME)
+        transaction.savepoint(optimistic=True)
+        cookie = self.root.site.manage_copyObjects(ids='foo')
+        self.root.site.foo2.manage_pasteObjects(cookie)
 
+        self.assertRaises(AttributeError, getattr, self.root.site.foo2.foo.sub1.sub2.baz, UID_ATTRNAME)
 
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite(UniqueIdAnnotationToolTests),



More information about the CMF-checkins mailing list