[Products.Silva][Sylvain Viollon] Update ghost folder code to su...
[email protected] Thu, 14 Nov 2013 15:07:35 +0100
| Newsgroups | gmane.comp.web.zope.silva.cvs |
|---|---|
| Message-ID | <[email protected]> |
author: Sylvain Viollon
date: Thu Nov 14 15:07:31 2013 +0100
revision: 11882:3719ea761135 in Products.Silva
branch: 2.4
details: https://hg.infrae.com/Products.Silva?cmd=changeset;node=3719ea761135
modified: Products/Silva/Folder/management.py Products/Silva/Ghost/content.py Products/Silva/GhostAsset/content.py Products/Silva/GhostFolder/content.py Products/Silva/tests/test_folder_ghoster.py Products/Silva/tests/test_ghost_folder.py
added:
removed:
log: Update ghost folder code to support invalid content.
diffstat:
Products/Silva/Folder/management.py | 7 +++-
Products/Silva/Ghost/content.py | 7 +++-
Products/Silva/GhostAsset/content.py | 7 +++-
Products/Silva/GhostFolder/content.py | 24 +++++++++++---
Products/Silva/tests/test_folder_ghoster.py | 35 +++++++++++++++++++++++
Products/Silva/tests/test_ghost_folder.py | 44 +++++++++++++++++++++-------
6 files changed, 100 insertions(+), 24 deletions(-)
diffs (313 lines):
diff -r d237fdfdfed4 -r 3719ea761135 Products/Silva/Folder/management.py
--- a/Products/Silva/Folder/management.py Tue Nov 12 17:19:36 2013 +0100
+++ b/Products/Silva/Folder/management.py Thu Nov 14 15:07:31 2013 +0100
@@ -26,7 +26,7 @@
from silva.core import conf as silvaconf
from silva.core.interfaces import IContainerManager
from silva.core.interfaces import IAddableContents
-from silva.core.interfaces import IContainer, IAsset
+from silva.core.interfaces import IContainer
from silva.core.interfaces import ContainerError, ContentError
from silva.core.interfaces import ISilvaNameChooser
from silva.translations import translate as _
@@ -239,7 +239,10 @@
result = self.__copy(content, identifier)
else:
identifier = self.__make_id('ghost', content.getId())
- result = factory(identifier)
+ try:
+ result = factory(identifier)
+ except ContentError as result:
+ pass
content = yield result
diff -r d237fdfdfed4 -r 3719ea761135 Products/Silva/Ghost/content.py
--- a/Products/Silva/Ghost/content.py Tue Nov 12 17:19:36 2013 +0100
+++ b/Products/Silva/Ghost/content.py Thu Nov 14 15:07:31 2013 +0100
@@ -17,7 +17,7 @@
from Products.Silva import SilvaPermissions
from silva.core import conf as silvaconf
-from silva.core.interfaces.errors import ContentInvalidTarget
+from silva.core.interfaces.errors import ContentInvalidTarget, ContentError
from silva.core.interfaces import IContent, IGhost, IGhostVersion
from silva.core.interfaces import IPublicationWorkflow, IGhostManager
from silva.translations import translate as _
@@ -103,7 +103,10 @@
assert self.manager.ghost is None
ghost = None
factory = self.manager.container.manage_addProduct['Silva']
- factory.manage_addGhost(self.identifier, None)
+ try:
+ factory.manage_addGhost(self.identifier, None)
+ except ValueError as error:
+ raise ContentError(error[0], content=self.target)
ghost = self.manager.container._getOb(self.identifier)
version = ghost.get_editable()
version.set_haunted(
diff -r d237fdfdfed4 -r 3719ea761135 Products/Silva/GhostAsset/content.py
--- a/Products/Silva/GhostAsset/content.py Tue Nov 12 17:19:36 2013 +0100
+++ b/Products/Silva/GhostAsset/content.py Thu Nov 14 15:07:31 2013 +0100
@@ -23,7 +23,7 @@
from silva.core.interfaces import IAssetPayload, IGhostManager
from silva.core.interfaces import IGhostAsset, IAsset
from silva.core.interfaces import IImage, IImageIncluable
-from silva.core.interfaces.errors import AssetInvalidTarget
+from silva.core.interfaces.errors import AssetInvalidTarget, ContentError
from silva.core.references.reference import DeleteSourceReferenceValue
from silva.core.references.reference import get_content_from_id, get_content_id
from silva.core.views.interfaces import IContentURL
@@ -126,7 +126,10 @@
def create(self, recursive=False):
assert self.manager.ghost is None
factory = self.manager.container.manage_addProduct['Silva']
- factory.manage_addGhostAsset(self.identifier, None)
+ try:
+ factory.manage_addGhostAsset(self.identifier, None)
+ except ValueError as error:
+ raise ContentError(error[0], content=self.target)
ghost = self.manager.container._getOb(self.identifier)
ghost.set_haunted(self.target, auto_delete=self.manager.auto_delete)
self.manager.ghost = ghost
diff -r d237fdfdfed4 -r 3719ea761135 Products/Silva/GhostFolder/content.py
--- a/Products/Silva/GhostFolder/content.py Tue Nov 12 17:19:36 2013 +0100
+++ b/Products/Silva/GhostFolder/content.py Thu Nov 14 15:07:31 2013 +0100
@@ -27,6 +27,7 @@
from silva.core.interfaces import IContainer, IGhostFolder, IGhostManager
from silva.core.interfaces import IPublication
from silva.core.interfaces.errors import ContainerInvalidTarget
+from silva.core.interfaces.errors import ContentError, ContentErrorBundle
from silva.translations import translate as _
@@ -89,6 +90,7 @@
if haunted is None:
return False
stack = self._haunt_diff(haunted, self)
+ errors = []
while stack:
# breadth first search
@@ -105,15 +107,22 @@
if g_id is not None:
g_ob = g_container._getOb(g_id)
- g_ob = get_factory(h_ob)(
- ghost=g_ob,
- container=g_container,
- auto_delete=True,
- auto_publish=True).modify(h_ob, h_id).verify()
+ try:
+ g_ob = get_factory(h_ob)(
+ ghost=g_ob,
+ container=g_container,
+ auto_delete=True,
+ auto_publish=True).modify(h_ob, h_id).verify()
+ except ContentError as error:
+ errors.append(error)
if IContainer.providedBy(h_ob) and g_ob is not None:
stack.extend(self._haunt_diff(h_ob, g_ob))
+ if errors:
+ raise ContentErrorBundle(
+ _(u"Error while synchronizing the Ghost Folder"),
+ content=self, errors=errors)
return True
def _haunt_diff(self, haunted, ghost):
@@ -216,7 +225,10 @@
def create(self, recursive=False):
assert self.manager.ghost is None
factory = self.manager.container.manage_addProduct['Silva']
- factory.manage_addGhostFolder(self.identifier, None)
+ try:
+ factory.manage_addGhostFolder(self.identifier, None)
+ except ValueError as error:
+ raise ContentError(error[0], content=self.target)
ghost = self.manager.container._getOb(self.identifier)
ghost.set_haunted(self.target, auto_delete=self.manager.auto_delete)
if recursive:
diff -r d237fdfdfed4 -r 3719ea761135 Products/Silva/tests/test_folder_ghoster.py
--- a/Products/Silva/tests/test_folder_ghoster.py Tue Nov 12 17:19:36 2013 +0100
+++ b/Products/Silva/tests/test_folder_ghoster.py Thu Nov 14 15:07:31 2013 +0100
@@ -6,10 +6,12 @@
from silva.core.interfaces import IContainerManager, IPublicationWorkflow
from silva.core.interfaces import IGhost, IGhostVersion, IGhostAsset, IGhostFolder
+from silva.core.interfaces.errors import IContentErrorBundle
from zope.interface.verify import verifyObject
from Products.Silva.testing import assertTriggersEvents
from Products.Silva.testing import FunctionalLayer, Transaction
+from Products.Silva.tests.mockers import IMockupNonPublishable
class EditorFolderGhosterTestCase(unittest.TestCase):
@@ -33,6 +35,39 @@
IPublicationWorkflow(self.root.source.data).publish()
+ def test_invalid(self):
+ """Pasting a content as a ghost folder that contains a content
+ with an invalid identifier.
+ """
+ self.root.source.manage_renameObject('folder', 'index')
+ manager = IContainerManager(self.root.target)
+ with assertTriggersEvents('ObjectWillBeAddedEvent',
+ 'ObjectAddedEvent',
+ 'ContainerModifiedEvent'):
+ with manager.ghoster() as ghoster:
+ error = ghoster(self.root.source)
+
+ self.assertTrue(verifyObject(IContentErrorBundle, error))
+ self.assertEqual(error.content, self.root.target.source)
+ self.assertEqual(error.reason, u'Error while synchronizing the Ghost Folder')
+ self.assertEqual(len(error.errors), 1)
+
+ def test_other(self):
+ """Pasting a content that doesn't have a ghost
+ implementation. It should be copied.
+ """
+ factory = self.root.source.manage_addProduct['Silva']
+ factory.manage_addMockupNonPublishable('stuff', 'Stuff')
+ manager = IContainerManager(self.root.target)
+ with assertTriggersEvents('ObjectWillBeAddedEvent',
+ 'ObjectAddedEvent',
+ 'ContainerModifiedEvent'):
+ with manager.ghoster() as ghoster:
+ ghost = ghoster(self.root.source.stuff)
+
+ self.assertTrue(verifyObject(IMockupNonPublishable, ghost))
+ self.assertIn('stuff', self.root.target.objectIds())
+
def test_asset(self):
"""Pasting an asset as a ghost asset.
"""
diff -r d237fdfdfed4 -r 3719ea761135 Products/Silva/tests/test_ghost_folder.py
--- a/Products/Silva/tests/test_ghost_folder.py Tue Nov 12 17:19:36 2013 +0100
+++ b/Products/Silva/tests/test_ghost_folder.py Thu Nov 14 15:07:31 2013 +0100
@@ -15,7 +15,8 @@
from silva.core.interfaces import IContainerManager, IPublicationWorkflow
from silva.core.interfaces import IGhost, IGhostAsset, IGhostVersion
from silva.core.interfaces import IPublication, IFolder, IGhostFolder
-from silva.core.interfaces import errors
+from silva.core.interfaces.errors import EmptyInvalidTarget, CircularInvalidTarget
+from silva.core.interfaces.errors import ContentError, ContainerInvalidTarget
from silva.core.references.interfaces import IReferenceService, IReferenceValue
@@ -46,7 +47,7 @@
factory.manage_addMockupVersionedContent('document', 'Document')
factory.manage_addFolder('folder', 'Folder')
- def test_get_folder(self):
+ def test_ghost_folder(self):
"""Test a Ghost Folder haunting to a Folder.
"""
factory = self.root.target.manage_addProduct['Silva']
@@ -183,7 +184,7 @@
aq_chain(reference.source),
aq_chain(ghost))
- def test_ghost_to_publication(self):
+ def test_convert_to_publication(self):
"""Test convertion of a Ghost Folder to a Publication.
"""
factory = self.root.target.manage_addProduct['Silva']
@@ -222,7 +223,7 @@
self.assertTrue(verifyObject(IGhost, ghost.index))
self.assertTrue(verifyObject(IGhost, ghost.document))
- def test_ghost_to_folder(self):
+ def test_convert_to_folder(self):
"""Test Ghost Folder convertion to a regular Folder.
"""
factory = self.root.target.manage_addProduct['Silva']
@@ -342,22 +343,22 @@
ghost = self.root.target.ghost
self.assertEqual(
ghost.get_link_status(),
- errors.EmptyInvalidTarget())
+ EmptyInvalidTarget())
ghost.set_haunted(self.root.folder.document)
self.assertEqual(
ghost.get_link_status(),
- errors.ContainerInvalidTarget())
+ ContainerInvalidTarget())
ghost.set_haunted(self.root)
self.assertEqual(
ghost.get_link_status(),
- errors.CircularInvalidTarget())
+ CircularInvalidTarget())
ghost.set_haunted(self.root.target.ghost)
self.assertEqual(
ghost.get_link_status(),
- errors.CircularInvalidTarget())
+ CircularInvalidTarget())
ghost.set_haunted(self.root.target.folder)
self.assertEqual(ghost.get_link_status(), None)
@@ -367,12 +368,12 @@
ghost.set_haunted(self.root.target.ghost.folder)
self.assertEqual(
ghost.get_link_status(),
- errors.CircularInvalidTarget())
+ CircularInvalidTarget())
ghost.set_haunted(0)
self.assertEqual(
ghost.get_link_status(),
- errors.EmptyInvalidTarget())
+ EmptyInvalidTarget())
def test_ghost_title(self):
"""Test Ghost Folder title.
@@ -434,6 +435,25 @@
self.assertFalse('folder' in ghost.objectIds())
self.assertTrue('publication' in ghost.objectIds())
+ def test_ghost_haunt_errors(self):
+ """Test modifications: a ghost folder is haunted a folder
+ containing content with invalid identifiers.
+ """
+ factory = self.root.target.manage_addProduct['Silva']
+ factory.manage_addGhostFolder('ghost', None, haunted=self.root.folder)
+
+ ghost = self.root.target.ghost
+ self.root.folder.folder.manage_renameObject('asset', 'cb_asset')
+ with self.assertRaises(ContentError):
+ ghost.haunt()
+
+ self.assertItemsEqual(
+ ghost.objectIds(),
+ ['index', 'document', 'folder', 'publication'])
+ self.assertItemsEqual(
+ ghost.folder.objectIds(),
+ ['document'])
+
def test_ghost_haunt_add_ghosts(self):
"""Test modifications: adding content in the target creates
new ghosts in the ghost folder when the ghost folder is
@@ -801,7 +821,7 @@
self.assertTrue('backup' in self.root.folder.objectIds())
self.assertEqual(
self.root.folder.backup.get_link_status(),
- errors.EmptyInvalidTarget())
+ EmptyInvalidTarget())
self.assertFalse('backup' in ghost.objectIds())
# Ghosting should not change anything
@@ -809,7 +829,7 @@
self.assertIn('backup', self.root.folder.objectIds())
self.assertEqual(
self.root.folder.backup.get_link_status(),
- errors.EmptyInvalidTarget())
+ EmptyInvalidTarget())
self.assertNotIn('backup', ghost.objectIds())