diff --git a/news/56.bugfix b/news/56.bugfix new file mode 100644 index 0000000..db9d10b --- /dev/null +++ b/news/56.bugfix @@ -0,0 +1,2 @@ +Fix importing blocks on the site-root. +[pbauer] diff --git a/src/plone/distribution/exportimport/dist_export.py b/src/plone/distribution/exportimport/dist_export.py index 7f0b30f..23b252f 100644 --- a/src/plone/distribution/exportimport/dist_export.py +++ b/src/plone/distribution/exportimport/dist_export.py @@ -132,7 +132,4 @@ def global_dict_hook(self, item: dict, obj: DexterityContent) -> dict: if item["@type"] == "Plone Site": # To avoid a conflict between @id and id item["@id"] = f"/{item['id']}" - if "blocks" in item: - blocks = item["blocks"] - item["blocks"] = helpers.parse_blocks(blocks) return item diff --git a/src/plone/distribution/exportimport/dist_import.py b/src/plone/distribution/exportimport/dist_import.py index bf84ce6..e29c26e 100644 --- a/src/plone/distribution/exportimport/dist_import.py +++ b/src/plone/distribution/exportimport/dist_import.py @@ -4,11 +4,14 @@ from collective.exportimport.import_content import ImportContent as BaseImportView from pathlib import Path from plone import api +from plone.dexterity.content import DexterityContent +from plone.dexterity.interfaces import IDexterityFTI from plone.distribution import logger from plone.distribution.exportimport import helpers from plone.distribution.exportimport.interfaces import ExportFormat from Products.Five import BrowserView from typing import List +from zope.component import queryUtility class ImportAll(BrowserView): @@ -76,7 +79,7 @@ def __call__( iterator=None, server_directory=False, ): - self.portal_uid = api.content.get_uuid(api.portal.get()) + self.portal = api.portal.get() self.default_language = api.portal.get_registry_record( "plone.default_language", default="en" ) @@ -91,10 +94,33 @@ def __call__( ) def global_dict_hook(self, item: dict) -> dict: - if item["@type"] == "Plone Site": - item["UID"] = self.portal_uid # Fix Language current = item.get("language") if current not in self.languages: item["language"] = self.default_language return item + + def dict_hook_plonesite(self, item: dict) -> dict: + """The Plone Site object exists already so it is updated. + We keep id and UID of the existing object.""" + item["UID"] = api.content.get_uuid(obj=self.portal) + item["@id"] = f"/{self.portal.id}" + item["id"] = self.portal.id + item["title"] = self.portal.title + item["description"] = self.portal.description + return item + + def obj_hook_plonesite(self, obj: DexterityContent, item: dict) -> None: + """IBlocks(obj) does not work yet at this point, so we have to + force the blocks onto the object if Plone Site has the behavior. + """ + fti = queryUtility(IDexterityFTI, name="Plone Site") + if ( + fti + and "volto.blocks" in fti.behaviors + and "blocks" in item + and "blocks_layout" in item + ): + obj.blocks = item["blocks"] + obj.blocks_layout = item["blocks_layout"] + return diff --git a/src/plone/distribution/exportimport/helpers.py b/src/plone/distribution/exportimport/helpers.py index d104e2f..dd63df3 100644 --- a/src/plone/distribution/exportimport/helpers.py +++ b/src/plone/distribution/exportimport/helpers.py @@ -61,49 +61,6 @@ def remove_site_root(item: dict, portal_url: str) -> dict: return json.loads(item_str) -def _fix_image_paths(data: list) -> list: - """Rewrite image urls to use the scale name. - - This is not ideal in terms of performance, but - it 'works' for imported content. - """ - parsed = [] - for info in data: - image_scales = info["image_scales"] - for field in image_scales: - field_data = image_scales[field][0] - field_data["download"] = f"@@images/{field}" - for key, scale in field_data["scales"].items(): - scale["download"] = f"@@images/{field}/{key}" - parsed.append(info) - return parsed - - -def _fix_grid_block(block: dict) -> dict: - """Remove references to computed scales in images.""" - for column in block["columns"]: - for key in ("preview_image", "image"): - image_data = column.get(key) - if not image_data: - continue - column[key] = _fix_image_paths(image_data) - return block - - -BLOCKS_HANDLERS = {"__grid": _fix_grid_block} - - -def parse_blocks(blocks: dict) -> dict: - """Clean up blocks.""" - parsed = {} - for block_uid, block in blocks.items(): - type_ = block.get("@type") - func = BLOCKS_HANDLERS.get(type_, None) - block = func(block) if func else block - parsed[block_uid] = block - return parsed - - def exports_for_distribution(distribution: Distribution) -> List[ExportStep]: """Return a list of available exports for a given distribution.""" _exports = [] diff --git a/tests/api/test_api_site.py b/tests/api/test_api_site.py index ed3a049..65396ac 100644 --- a/tests/api/test_api_site.py +++ b/tests/api/test_api_site.py @@ -31,7 +31,7 @@ class TestApiSite: def test_get_sites(self, app, integration): sites = site_api.get_sites(app) # Integration test creates a Plone Site - assert len(sites) == 3 + assert len(sites) == 2 site = sites[0] assert isinstance(site, PloneSite) @@ -54,11 +54,6 @@ def test_create(self, app, integration, answers, distribution_name): assert isinstance(site, PloneSite) assert site.title == new_site.title - def test_get_creation_report_old_site(self, app, integration): - # An existing site (or older distribution will not have a report) - report = site_api.get_creation_report(app.Plone) - assert report is None - def test_get_creation_report_new_site(self, site): from datetime import datetime from plone.distribution.core import SiteCreationReport diff --git a/tests/exportimport/test_exportimport_helpers.py b/tests/exportimport/test_exportimport_helpers.py index 6120d43..4f03e85 100644 --- a/tests/exportimport/test_exportimport_helpers.py +++ b/tests/exportimport/test_exportimport_helpers.py @@ -68,23 +68,3 @@ def test_remove_site_root_from_image_block(self, integration, export_item): result = func(export_item, self.SITE_ROOT) result_block = self._get_img_block(result) assert result_block["url"].startswith("/") - - def test__fix_grid_block(self, integration, export_item): - func = helpers._fix_grid_block - grid_block = self._get_grid_block(export_item) - src_column = self._get_grid_block_column(grid_block) - src_img_scale = src_column["preview_image"][0]["image_scales"]["image"][0] - assert ( - src_img_scale["download"] - == "@@images/image-2048-4b3f8a97eb42b769ee35ed55a3e962b0.png" - ) - assert ( - src_img_scale["scales"]["great"]["download"] - == "@@images/image-1200-bd0038e8561f6da7a065b2866232fee1.png" - ) - - result = func(grid_block) - result_column = self._get_grid_block_column(result) - result_img_scale = result_column["preview_image"][0]["image_scales"]["image"][0] - assert result_img_scale["download"] == "@@images/image" - assert result_img_scale["scales"]["great"]["download"] == "@@images/image/great" diff --git a/tests/services/test_services_site.py b/tests/services/test_services_site.py index a593e30..fc62a4d 100644 --- a/tests/services/test_services_site.py +++ b/tests/services/test_services_site.py @@ -46,7 +46,7 @@ def test_sites_get_sites(self, app): data = response.json() sites = data["sites"] assert isinstance(sites, list) - assert len(sites) == 3 + assert len(sites) == 2 assert sites[0]["id"] == "plone" assert sites[0]["needs_upgrade"] is False