[Products.Silva][Sylvain Viollon] Make possible to use GhostAsse...

[email protected] Mon, 11 Nov 2013 15:01:54 +0100
Newsgroups gmane.comp.web.zope.silva.cvs
Message-ID <[email protected]>
author:    Sylvain Viollon
date:      Mon Nov 11 15:01:46 2013 +0100
revision:  11878:eb61cd1d2344 in Products.Silva
branch:    2.4
details:   https://hg.infrae.com/Products.Silva?cmd=changeset;node=eb61cd1d2344
modified:  Products/Silva/Ghost/base.py Products/Silva/GhostAsset/content.py Products/Silva/tests/test_ghost_asset.py
added:     
removed:   
log:       Make possible to use GhostAsset as images in the documents if they
	points to an actual image.


diffstat:

 Products/Silva/Ghost/base.py             |  19 +++++++++-----
 Products/Silva/GhostAsset/content.py     |  40 +++++++++++++++++++++++++++++++-
 Products/Silva/tests/test_ghost_asset.py |  37 +++++++++++++++++++++++++++--
 3 files changed, 85 insertions(+), 11 deletions(-)

diffs (190 lines):

diff -r 3068cee1e5c0 -r eb61cd1d2344 Products/Silva/Ghost/base.py
--- a/Products/Silva/Ghost/base.py	Fri Nov 08 17:40:33 2013 +0100
+++ b/Products/Silva/Ghost/base.py	Mon Nov 11 15:01:46 2013 +0100
@@ -20,7 +20,6 @@
 from silva.core.interfaces import IGhostAware, IGhostManager, IPublishable
 from silva.core.references.reference import DeleteSourceReferenceValue
 from silva.core.references.reference import WeakReferenceValue
-from silva.core.references.reference import get_content_id
 from silva.core.references.interfaces import IReferenceService
 from silva.translations import translate as _
 
@@ -176,20 +175,26 @@
             return content.get_short_title_editable()
         return _(u"Ghost target is broken")
 
+    def _get_haunted_factories(self, auto_delete=False):
+        # Give the possibilties to override the selection of reference
+        # factories.
+        if auto_delete:
+            return DeleteSourceReferenceValue
+        return WeakReferenceValue
+
     security.declareProtected(
         SilvaPermissions.ChangeSilvaContent, 'set_haunted')
     def set_haunted(self, content, auto_delete=False):
         """ Set the content as the haunted object
         """
         service = getUtility(IReferenceService)
-        factory = WeakReferenceValue
-        if auto_delete:
-            factory = DeleteSourceReferenceValue
+        factory = self._get_haunted_factories(auto_delete)
         reference = service.get_reference(
             aq_inner(self), name=u"haunted", add=True, factory=factory)
-        if not isinstance(content, int):
-            content = get_content_id(content)
-        reference.set_target_id(content)
+        if isinstance(content, int):
+            reference.set_target_id(content)
+        else:
+            reference.set_target(content)
 
     security.declareProtected(SilvaPermissions.View, 'get_haunted')
     def get_haunted(self):
diff -r 3068cee1e5c0 -r eb61cd1d2344 Products/Silva/GhostAsset/content.py
--- a/Products/Silva/GhostAsset/content.py	Fri Nov 08 17:40:33 2013 +0100
+++ b/Products/Silva/GhostAsset/content.py	Mon Nov 11 15:01:46 2013 +0100
@@ -2,6 +2,7 @@
 # Zope 3
 from five import grok
 from zeam.component import component
+from zope.interface import noLongerProvides, alsoProvides
 
 # Zope 2
 from AccessControl import ClassSecurityInfo
@@ -15,21 +16,58 @@
 
 from silva.core.interfaces import IGhostAsset, IAsset
 from silva.core.interfaces import IAssetPayload, IGhostManager
+from silva.core.interfaces import IImage, IImageIncluable
 from silva.core.interfaces.errors import AssetInvalidTarget
 
+from silva.core.references.reference import get_content_from_id, get_content_id
+from silva.core.references.reference import DeleteSourceReferenceValue
+
+
+class ImageDeleteSourceReferenceValue(DeleteSourceReferenceValue):
+
+    def _check_image(self, target):
+        source = self.source
+        if source is not None:
+            is_image = IImage.providedBy(target)
+            have_image = IImageIncluable.providedBy(source)
+            if is_image and not have_image:
+                alsoProvides(source, IImageIncluable)
+            elif not is_image and have_image:
+                noLongerProvides(source, IImageIncluable)
+
+    def set_target_id(self, target_id):
+        self._check_image(get_content_from_id(target_id))
+        super(ImageDeleteSourceReferenceValue, self).set_target_id(target_id)
+
+    def set_target(self, target):
+        self._check_image(target)
+        super(ImageDeleteSourceReferenceValue, self).set_target_id(
+            get_content_id(target))
+
+
+class ImageWeakReferenceValue(ImageDeleteSourceReferenceValue):
+
+    def cleanup(self):
+        pass
+
 
 class GhostAsset(GhostBase, Asset):
     grok.implements(IGhostAsset)
     security = ClassSecurityInfo()
     meta_type = "Silva Ghost Asset"
 
+    def _get_haunted_factories(self, auto_delete=False):
+        if auto_delete:
+            return ImageDeleteSourceReferenceValue
+        return ImageWeakReferenceValue
+
     security.declareProtected(
         SilvaPermissions.AccessContentsInformation, 'get_filename')
     def get_filename(self):
         asset = self.get_haunted()
         if asset is not None:
             return asset.get_filename()
-        return ''
+        return self.getId()
 
     security.declareProtected(
         SilvaPermissions.AccessContentsInformation, 'get_file_size')
diff -r 3068cee1e5c0 -r eb61cd1d2344 Products/Silva/tests/test_ghost_asset.py
--- a/Products/Silva/tests/test_ghost_asset.py	Fri Nov 08 17:40:33 2013 +0100
+++ b/Products/Silva/tests/test_ghost_asset.py	Mon Nov 11 15:01:46 2013 +0100
@@ -11,7 +11,8 @@
 from zope.interface.verify import verifyObject
 
 from Products.Silva.testing import FunctionalLayer, Transaction
-from silva.core.interfaces import IGhostAsset
+from silva.core.interfaces import IGhostAsset, IImageIncluable
+from silva.core.interfaces.errors import EmptyInvalidTarget
 from silva.core.services.interfaces import IMetadataService
 
 
@@ -26,6 +27,8 @@
             factory = self.root.manage_addProduct['Silva']
             with self.layer.open_fixture('silva.png') as stream:
                 factory.manage_addImage('logo', 'Silva Logo', stream)
+            with self.layer.open_fixture('dark_energy.txt') as stream:
+                factory.manage_addFile('text', 'Text file', stream)
 
         with Transaction():
             metadata = getUtility(IMetadataService).getMetadata(self.root.logo)
@@ -37,8 +40,8 @@
             self.root.logo.get_modification_datetime(),
             DateTime('2010-04-25T12:00:00Z'))
 
-    def test_create_and_access(self):
-        """Create and test a Ghost Asset content type.
+    def test_haunt_image(self):
+        """Create and test a Ghost Asset content type that haunt an image.
         """
         with Transaction():
             factory = self.root.manage_addProduct['Silva']
@@ -52,6 +55,7 @@
         self.assertEqual(ghost.get_haunted(), self.root.logo)
         self.assertEqual(ghost.get_filename(), 'logo.png')
         self.assertEqual(ghost.get_mime_type(), 'image/png')
+        self.assertTrue(IImageIncluable.providedBy(ghost))
         self.assertEqual(
             ghost.get_file_size(),
             self.root.logo.get_file_size())
@@ -62,6 +66,33 @@
             aq_chain(ghost.get_haunted()),
             aq_chain(self.root.logo))
 
+        # Now edit an break the reference.
+        ghost.set_haunted(0)
+        self.assertIsInstance(ghost.get_link_status(), EmptyInvalidTarget)
+        self.assertEqual(ghost.get_haunted(), None)
+        self.assertEqual(ghost.get_filename(), 'ghost')
+        self.assertEqual(ghost.get_file_size(), 0)
+        self.assertEqual(ghost.get_mime_type(), 'application/octet-stream')
+        self.assertFalse(IImageIncluable.providedBy(ghost))
+
+    def test_haunt_file(self):
+        """Create and test a Ghost Asset content type that haunt a
+        file.
+        """
+        with Transaction():
+            factory = self.root.manage_addProduct['Silva']
+            factory.manage_addGhostAsset('ghost', None, haunted=self.root.text)
+
+        self.assertIn('ghost', self.root.objectIds())
+        ghost = self.root._getOb('ghost')
+        self.assertTrue(verifyObject(IGhostAsset, ghost))
+        self.assertIn(ghost, self.root.get_non_publishables())
+        self.assertEqual(ghost.get_link_status(), None)
+        self.assertEqual(ghost.get_haunted(), self.root.text)
+        self.assertEqual(ghost.get_filename(), 'text')
+        self.assertEqual(ghost.get_mime_type(), 'text/plain')
+        self.assertFalse(IImageIncluable.providedBy(ghost))
+
     def test_download(self):
         """create and download a Ghost Asset content type.
         """