Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/65.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fire ``IContainerModifiedEvent`` from ``orderObjects`` in both ``DefaultOrdering`` and ``PartialOrdering``. Every other ordering mutation goes through ``moveObjectsByDelta``, which notifies, so ``orderObjects`` was the only reordering that subscribers could not observe. @kunalKumar-13
5 changes: 5 additions & 0 deletions src/plone/folder/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ def keyfn(obj_id):
order.sort(key=keyfn, reverse=bool(reverse))
for n, obj_id in enumerate(order):
pos[obj_id] = n
# The order annotation was mutated, so subscribers have to hear about
# it -- every other ordering mutation goes through moveObjectsByDelta,
# which notifies. Without this, orderObjects is the one way to reorder
# a folder that nothing outside can observe.
notifyContainerModified(self.context)
return -1

def getObjectPosition(self, obj_id):
Expand Down
1 change: 1 addition & 0 deletions src/plone/folder/partial.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def keyfn(id):

self.order = sorted(self.order, key=keyfn, reverse=bool(reverse))
self.context._p_changed = True # the order was changed
notifyContainerModified(self.context)
return -1

def getObjectPosition(self, id):
Expand Down
44 changes: 44 additions & 0 deletions src/plone/folder/tests/test_ordersupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,33 @@
from plone.folder.testing import PLONEFOLDER_FUNCTIONAL_TESTING
from plone.folder.testing import PLONEFOLDER_INTEGRATION_TESTING
from plone.folder.tests.utils import DummyObject
from zope.container.interfaces import IContainerModifiedEvent

import transaction
import unittest
import zope.event


class _collect_container_modified:
"""Collect IContainerModifiedEvent notifications raised inside the block.

Subscribes at the `zope.event` level so the test does not depend on
anything being registered in the component registry.
"""

def __init__(self):
self.events = []

def _handle(self, event):
if IContainerModifiedEvent.providedBy(event):
self.events.append(event)

def __enter__(self):
zope.event.subscribers.append(self._handle)
return self

def __exit__(self, *exc):
zope.event.subscribers.remove(self._handle)


class TestFolder(OrderedBTreeFolderBase, Traversable):
Expand Down Expand Up @@ -333,6 +357,26 @@ def testOrderObjectsOnlyReverse(self):
self.assertEqual(self.folder.getObjectPosition("bar"), 1)
self.assertEqual(self.folder.getObjectPosition("foo"), 2)

def testOrderObjectsNotifiesContainerModified(self):
# Every other ordering mutation goes through moveObjectsByDelta, which
# notifies. orderObjects must not be the one that stays silent.
with _collect_container_modified() as collected:
self.folder.orderObjects("id")
self.assertEqual(len(collected.events), 1)
self.assertIs(collected.events[0].object, self.folder)

def testOrderObjectsOnlyReverseNotifiesContainerModified(self):
with _collect_container_modified() as collected:
self.folder.orderObjects(reverse=True)
self.assertEqual(len(collected.events), 1)

def testOrderObjectsWithoutWorkDoesNotNotify(self):
# No key and no reverse is a no-op that returns early; nothing was
# reordered, so nothing should be announced.
with _collect_container_modified() as collected:
self.assertEqual(self.folder.orderObjects(), -1)
self.assertEqual(collected.events, [])

def testSubsetIds(self):
self.folder.moveObjectsByDelta(["baz"], -1, ["foo", "bar", "baz"])
self.assertEqual(self.folder.getObjectPosition("foo"), 0)
Expand Down
39 changes: 39 additions & 0 deletions src/plone/folder/tests/test_partialordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,29 @@
from plone.folder.tests.utils import Chaoticle
from plone.folder.tests.utils import Orderable
from transaction import savepoint
from zope.container.interfaces import IContainerModifiedEvent
from zope.interface import implementer

import unittest
import zope.event


class _collect_container_modified:
"""Collect IContainerModifiedEvent notifications raised inside the block."""

def __init__(self):
self.events = []

def _handle(self, event):
if IContainerModifiedEvent.providedBy(event):
self.events.append(event)

def __enter__(self):
zope.event.subscribers.append(self._handle)
return self

def __exit__(self, *exc):
zope.event.subscribers.remove(self._handle)


class PartialOrderingTests(unittest.TestCase):
Expand Down Expand Up @@ -188,6 +208,25 @@ def testMoveObjectToPosition(self):
),
)

def testOrderObjectsNotifiesContainerModified(self):
container, ordering = self.create()
with _collect_container_modified() as collected:
ordering.orderObjects("id")
self.assertEqual(len(collected.events), 1)
self.assertIs(collected.events[0].object, container)

def testOrderObjectsOnlyReverseNotifiesContainerModified(self):
container, ordering = self.create()
with _collect_container_modified() as collected:
ordering.orderObjects(reverse=True)
self.assertEqual(len(collected.events), 1)

def testOrderObjectsWithoutWorkDoesNotNotify(self):
container, ordering = self.create()
with _collect_container_modified() as collected:
self.assertEqual(ordering.orderObjects(), -1)
self.assertEqual(collected.events, [])

def testOrderObjects(self):
self.runTableTests(
"orderObjects",
Expand Down