[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