diff --git a/castle/cms/browser/content/fc.py b/castle/cms/browser/content/fc.py
index 78b763946..b622b397f 100644
--- a/castle/cms/browser/content/fc.py
+++ b/castle/cms/browser/content/fc.py
@@ -32,6 +32,12 @@
from zope.event import notify
from zope.interface import implementer
from zope.lifecycleevent import ObjectModifiedEvent
+from zope.component.hooks import getSite
+from plone.app.contenttypes.interfaces import IDocument
+from zope.annotation.interfaces import IAnnotations
+from persistent.mapping import PersistentMapping
+from plone.namedfile.file import NamedBlobImage
+from ZODB.POSException import POSKeyError
from re import sub
from plone.app.content.browser.vocabulary import (
@@ -190,6 +196,50 @@ def __call__(self):
except CopyError:
return self.copy_error()
+ # XXX: Experimental code block
+ # Can be removed in lieu of installing "experimental.gracefulblobmissing" package,
+ # which ignores missing blob errors
+
+ site = getSite()
+ for path in paste_data.get('paths'):
+ print(path)
+
+ try:
+ obj = site.restrictedTraverse(path.strip('/'), None)
+ print(obj)
+ if obj is None:
+ logger.error("Object not found: '{}'".format(path))
+ return
+ except Exception as e:
+ logger.error("Error retrieving object: {}".format(e))
+ return
+
+ if IDocument.providedBy(obj):
+ annotations = IAnnotations(obj)
+
+ # The ANNOTATIONS_KEY_PREFIX ignores tiles with images/blobs
+ for key in annotations.keys():
+ data = annotations[key]
+
+ # PersistentMapping tiles contain the blobs we want
+ if isinstance(data, PersistentMapping):
+ for item in data.values():
+ if isinstance(item, dict) and isinstance(item.get('data'), NamedBlobImage):
+ blobfile = item.get('data')
+ blob = blobfile._blob
+ try:
+ # Check blob, opening may not be best approach
+ f = blob.open('r')
+ f.close()
+ except POSKeyError:
+ # Broken blob reference
+ # XXX: Call save() on blob or reassign to generic fallback blob
+ path_on_disk = blob._p_blob_committed
+ pass
+
+ # XXX: end of block
+
+
tasks.paste_items.delay(
self.request.form['folder'], paste_data['op'],
paste_data['mdatas'])
diff --git a/castle/cms/profiles/3017/registry/resources.xml b/castle/cms/profiles/3017/registry/resources.xml
new file mode 100644
index 000000000..e3fc35ffa
--- /dev/null
+++ b/castle/cms/profiles/3017/registry/resources.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ 2024-09-24 00:00:00
+
+
+
+ 2024-09-24 00:00:00
+
+
+
diff --git a/castle/cms/profiles/default/metadata.xml b/castle/cms/profiles/default/metadata.xml
index 246079d28..6ce391ae7 100644
--- a/castle/cms/profiles/default/metadata.xml
+++ b/castle/cms/profiles/default/metadata.xml
@@ -1,6 +1,6 @@
- 3016
+ 3017
profile-plone.app.querystring:default
profile-plone.app.mosaic:default
diff --git a/castle/cms/upgrades.zcml b/castle/cms/upgrades.zcml
index 435d45676..5813bbfd0 100644
--- a/castle/cms/upgrades.zcml
+++ b/castle/cms/upgrades.zcml
@@ -261,4 +261,20 @@
profile="castle.cms:default"
/>
+
+
+
diff --git a/castle/cms/upgrades/__init__.py b/castle/cms/upgrades/__init__.py
index 225cbd95a..885924cca 100644
--- a/castle/cms/upgrades/__init__.py
+++ b/castle/cms/upgrades/__init__.py
@@ -141,3 +141,4 @@ def upgrade_3011(site, logger=CASTLE_LOGGER):
upgrade_3014 = default_upgrade_factory('3014')
upgrade_3015 = default_upgrade_factory('3015')
upgrade_3016 = default_upgrade_factory('3016')
+upgrade_3017 = default_upgrade_factory('3017')
diff --git a/travis.cfg b/travis.cfg
index 51312737e..b36c0f147 100644
--- a/travis.cfg
+++ b/travis.cfg
@@ -38,6 +38,7 @@ eggs +=
Pillow
Products.PloneKeywordManager
plone.app.robotframework
+ experimental.gracefulblobmissing
zcml =
castle.cms-overrides
diff --git a/versions.cfg b/versions.cfg
index 104499b8f..a3ef5d589 100644
--- a/versions.cfg
+++ b/versions.cfg
@@ -57,6 +57,7 @@ z3c.jbot = 0.7.2
castle.theme = 1.0.6
Products.PloneKeywordManager = 2.2.1
wildcard.hps = 1.4.0
+experimental.gracefulblobmissing = 2.0
# dependency pins