From d3bf97fe71cdcccd645de53152126b8d03422a03 Mon Sep 17 00:00:00 2001 From: Levente Santha Date: Wed, 12 Jul 2023 09:30:12 +0300 Subject: [PATCH] SITES-14361 - List component added to template structure shows wrong images * fixed featured image display for pages in a list * updated unit tests --- .../helper/image/AdaptiveImageHelper.java | 4 +- .../internal/models/v1/ImageImpl.java | 10 ++-- .../internal/models/v3/ListImpl.java | 18 ++++++- .../internal/models/v4/ListImpl.java | 4 +- .../internal/models/v3/ListImplTest.java | 52 +++++++++++++++++++ .../resources/list/v3/exporter-page_7.json | 50 ++++++++++++++++++ .../src/test/resources/list/v3/test-apps.json | 29 +++++++++++ .../src/test/resources/list/v3/test-conf.json | 36 +++++++++++++ .../test/resources/list/v3/test-content.json | 47 +++++++++++++++++ 9 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 bundles/core/src/test/resources/list/v3/exporter-page_7.json create mode 100644 bundles/core/src/test/resources/list/v3/test-conf.json diff --git a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/helper/image/AdaptiveImageHelper.java b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/helper/image/AdaptiveImageHelper.java index 00b6c751f1..a5930e5086 100644 --- a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/helper/image/AdaptiveImageHelper.java +++ b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/helper/image/AdaptiveImageHelper.java @@ -68,7 +68,9 @@ public static Resource getComponentCandidate(@NotNull String suffix, Resource co .map(Page::getTemplate) .map(template -> ResourceUtil.normalize(template.getPath() + suffixPath)) .map(resourceResolver::getResource).orElse(null); - } else { + } + + if (componentCandidate == null) { // image coming from external resource Resource externalImageResource = resourceResolver.getResource(suffixPath); if (externalImageResource != null && externalImageResource.isResourceType(IMAGE_RESOURCE_TYPE)) { diff --git a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ImageImpl.java b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ImageImpl.java index bfbcf8abdf..8a8730aa44 100644 --- a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ImageImpl.java +++ b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ImageImpl.java @@ -253,6 +253,10 @@ protected void initModel() { templateRelativePath = resource.getPath().substring(template.getPath().length()); } else { baseResourcePath = resource.getPath(); + if (resource.getResourceResolver().getResource(resource.getPath()) == null) { + // synthetic merged resource, use the current page path as base path + baseResourcePath = currentPage.getPath(); + } } baseResourcePath = resource.getResourceResolver().map(request, baseResourcePath); if (smartSizesSupported()) { @@ -293,9 +297,9 @@ protected void initModel() { } else { src += extension; } - src += (inTemplate ? Text.escapePath(templateRelativePath) : hasExternalImageResource ? externalImageResourcePath : "") + - (lastModifiedDate > 0 ? ("/" + lastModifiedDate + (StringUtils.isNotBlank(imageName) ? ("/" + imageName) : "")) : "") + - (inTemplate || hasExternalImageResource || lastModifiedDate > 0 ? DOT + extension : ""); + src += inTemplate ? Text.escapePath(templateRelativePath) : hasExternalImageResource ? externalImageResourcePath : ""; + src += lastModifiedDate > 0 ? "/" + lastModifiedDate + (StringUtils.isNotBlank(imageName) ? "/" + imageName : "") : ""; + src += inTemplate || hasExternalImageResource || lastModifiedDate > 0 ? DOT + extension : ""; } if (!isDecorative) { diff --git a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImpl.java b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImpl.java index 7fee90552a..81993427ff 100644 --- a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImpl.java +++ b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImpl.java @@ -17,7 +17,10 @@ import javax.annotation.PostConstruct; +import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.SyntheticResource; import org.apache.sling.models.annotations.Exporter; import org.apache.sling.models.annotations.Model; import org.jetbrains.annotations.NotNull; @@ -50,7 +53,20 @@ public class ListImpl extends com.adobe.cq.wcm.core.components.internal.models.v @Override protected ListItem newPageListItem(@NotNull LinkManager linkManager, @NotNull Page page, String parentId, Component component) { - return new PageListItemImpl(linkManager, page, parentId, component, showDescription, linkItems || displayItemAsTeaser, resource); + Resource listResource = getListResource(); + return new PageListItemImpl(linkManager, page, parentId, component, showDescription, linkItems || displayItemAsTeaser, listResource); + } + + protected Resource getListResource() { + Resource listResource = resource; + String template = currentPage.getProperties().get("cq:template", String.class); + if (StringUtils.isNotBlank(template) && listResource.getPath().startsWith(template)) { + String containingPagePath = currentPage.getPageManager().getContainingPage(listResource).getPath(); + String mergedResourcePath = listResource.getPath().replace(containingPagePath, currentPage.getPath()); + // if the resource comes from the template we need to merge it with the current page + listResource = new SyntheticResource(request.getResourceResolver(), mergedResourcePath, listResource.getResourceType()); + } + return listResource; } /** diff --git a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v4/ListImpl.java b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v4/ListImpl.java index c6b06273a3..b77297a361 100644 --- a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v4/ListImpl.java +++ b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v4/ListImpl.java @@ -34,7 +34,6 @@ import org.apache.sling.models.annotations.Model; import org.jetbrains.annotations.NotNull; -import javax.annotation.PostConstruct; import java.text.Collator; import java.util.Collection; import java.util.Comparator; @@ -51,7 +50,8 @@ public class ListImpl extends com.adobe.cq.wcm.core.components.internal.models.v @Override protected ListItem newPageListItem(@NotNull LinkManager linkManager, @NotNull Page page, String parentId, Component component) { - return new PageListItemImpl(linkManager.get(page).build(), page, parentId, component, showDescription, linkItems || displayItemAsTeaser, resource); + Resource listResource = getListResource(); + return new PageListItemImpl(linkManager.get(page).build(), page, parentId, component, showDescription, linkItems || displayItemAsTeaser, listResource); } @Override diff --git a/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImplTest.java b/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImplTest.java index dd2c81009b..d1055c7bc1 100644 --- a/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImplTest.java +++ b/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v3/ListImplTest.java @@ -17,6 +17,8 @@ import java.util.Collection; +import com.adobe.cq.wcm.core.components.models.Image; +import com.adobe.cq.wcm.core.components.models.Teaser; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ValueMap; import org.junit.jupiter.api.BeforeEach; @@ -36,6 +38,11 @@ public class ListImplTest extends com.adobe.cq.wcm.core.components.internal.models.v1.ListImplTest { private static final String TEST_BASE = "/list/v3"; + protected static final String CONF_ROOT = "/conf"; + protected static final String TEST_CONF_ROOT = "/apps/core/wcm/components"; + + protected static final String LIST_V3_1 = "/content/list/pages/page_7"; + protected static final String LIST_V3_1_TEMPLATE = "/conf/coretest/settings/wcm/templates/template-1/structure/jcr:content/root/list"; @BeforeEach @Override @@ -43,6 +50,7 @@ public void setUp() { testBase = TEST_BASE; internalSetup(); context.load().json(testBase + CoreComponentTestContext.TEST_APPS_JSON, TEST_APPS_ROOT); + context.load().json(testBase + CoreComponentTestContext.TEST_CONF_JSON, CONF_ROOT); } @Test @@ -85,4 +93,48 @@ protected void testListRenderedAsTeaserItems() { Utils.testJSONExport(list, Utils.getTestExporterJSONPath(testBase, LIST_20)); } + + @Test + protected void testChildPageListInTemplateWithFeaturedImageRenderedAsTeaser() { + Utils.enableDataLayer(context, true); + Resource resource = context.resourceResolver().getResource(LIST_V3_1_TEMPLATE); + if (resource == null) { + throw new IllegalStateException("Did you forget to define test resource " + LIST_V3_1_TEMPLATE + "?"); + } + context.currentPage(context.pageManager().getPage(LIST_V3_1)); + context.currentResource(resource); + + List list = context.request().adaptTo(List.class); + + assertEquals(2, list.getListItems().size()); + Collection items = list.getListItems(); + + // The featured image of the page exists: the featured image node of the page is used to render the teaser item + ListItem item0 = (ListItem) items.toArray()[0]; + Resource teaserResource0 = item0.getTeaserResource(); + ValueMap teaserProperties = teaserResource0.getValueMap(); + String linkURL = teaserProperties.get("linkURL", String.class); + String fileReference = teaserProperties.get("fileReference", String.class); + String title = teaserProperties.get("jcr:title", String.class); + assertEquals("/content/list/pages/page_7/jcr:content/root/list", teaserResource0.getPath(), "image resource: path"); + assertEquals("core/wcm/components/teaser/v2/teaser", teaserResource0.getResourceType(), "image resource: resource type"); + assertEquals("/content/list/pages/page_7/page_7_1", linkURL, "image resource: linkURL"); + assertEquals("/content/dam/core/images/Adobe_Systems_logo_and_wordmark.png", fileReference, "image resource: fileReference"); + assertEquals("Page 7.1", title, "image resource: title"); + + // The featured image of the page does not exist: the content node of the page is used to render the teaser item + ListItem item1 = (ListItem) items.toArray()[1]; + Resource teaserResource2 = item1.getTeaserResource(); + assertEquals("/content/list/pages/page_7/jcr:content/root/list", teaserResource2.getPath(), "image resource: path"); + + Utils.testJSONExport(list, Utils.getTestExporterJSONPath(testBase, LIST_V3_1)); + + context.currentResource(teaserResource0); + Teaser teaser = context.request().adaptTo(Teaser.class); + Resource imageResource = teaser.getImageResource(); + + context.currentResource(imageResource); + Image image = context.request().adaptTo(Image.class); + assertEquals("/content/list/pages/page_7.coreimg.png/content/list/pages/page_7/page_7_1/jcr:content/cq:featuredimage.png", image.getSrc()); + } } diff --git a/bundles/core/src/test/resources/list/v3/exporter-page_7.json b/bundles/core/src/test/resources/list/v3/exporter-page_7.json new file mode 100644 index 0000000000..7e5ac75a70 --- /dev/null +++ b/bundles/core/src/test/resources/list/v3/exporter-page_7.json @@ -0,0 +1,50 @@ +{ + "id": "list-dc1f6a2ea5", + "dateFormatString": "yyyy-MM-dd", + "items": [ + { + "id": "list-dc1f6a2ea5-item-b1f4d722d9", + "path": "/content/list/pages/page_7/page_7_1", + "link": { + "valid": true, + "url": "/content/list/pages/page_7/page_7_1.html" + }, + "title": "Page 7.1", + "dataLayer": { + "list-dc1f6a2ea5-item-b1f4d722d9": { + "@type": "core/wcm/components/list/v3/list/item", + "dc:title": "Page 7.1", + "xdm:linkURL": "/content/list/pages/page_7/page_7_1.html" + } + }, + ":type": "cq:PageContent" + }, + { + "id": "list-dc1f6a2ea5-item-e85a27c407", + "path": "/content/list/pages/page_7/page_7_2", + "link": { + "valid": true, + "url": "/content/list/pages/page_7/page_7_2.html" + }, + "title": "Page 7.2", + "dataLayer": { + "list-dc1f6a2ea5-item-e85a27c407": { + "@type": "core/wcm/components/list/v3/list/item", + "dc:title": "Page 7.2", + "xdm:linkURL": "/content/list/pages/page_7/page_7_2.html" + } + }, + ":type": "cq:PageContent" + } + ], + "showDescription": false, + "showModificationDate": false, + "linkItems": false, + "displayItemAsTeaser": true, + "dataLayer": { + "list-dc1f6a2ea5": { + "@type": "core/wcm/components/list/v3/list" + } + }, + ":type": "core/wcm/components/list/v3/list" +} diff --git a/bundles/core/src/test/resources/list/v3/test-apps.json b/bundles/core/src/test/resources/list/v3/test-apps.json index 600c76bee9..3102a24d01 100644 --- a/bundles/core/src/test/resources/list/v3/test-apps.json +++ b/bundles/core/src/test/resources/list/v3/test-apps.json @@ -1,4 +1,18 @@ { + "image": { + "jcr:primaryType": "sling:Folder", + "v2" : { + "jcr:primaryType": "nt:unstructured", + "image" : { + "jcr:primaryType" : "cq:Component", + "jcr:title" : "Image (v2)", + "sling:resourceSuperType": "core/wcm/components/image", + "jcr:description" : "Smart Adaptive Image", + "cq:icon" : "image", + "componentGroup" : ".core-wcm" + } + } + }, "list": { "jcr:primaryType": "sling:Folder", "v3" : { @@ -13,5 +27,20 @@ "componentGroup" : ".core-wcm" } } + }, + "teaser": { + "jcr:primaryType": "sling:Folder", + "v2" : { + "jcr:primaryType": "nt:unstructured", + "teaser" : { + "jcr:primaryType" : "cq:Component", + "jcr:title" : "Teaser (v2)", + "sling:resourceSuperType": "core/wcm/components/teaser", + "jcr:description" : "Teaser Component", + "cq:icon" : "teaser", + "imageDelegate": "core/wcm/components/image/v3/image", + "componentGroup" : ".core-wcm" + } + } } } diff --git a/bundles/core/src/test/resources/list/v3/test-conf.json b/bundles/core/src/test/resources/list/v3/test-conf.json new file mode 100644 index 0000000000..494ee59685 --- /dev/null +++ b/bundles/core/src/test/resources/list/v3/test-conf.json @@ -0,0 +1,36 @@ +{ + "jcr:primaryType": "sling:Folder", + "coretest" : { + "jcr:primaryType": "sling:OrderedFolder", + "jcr:title" : "Core", + "settings" : { + "jcr:primaryType": "sling:Folder", + "wcm" : { + "jcr:primaryType": "cq:Page", + "templates" : { + "jcr:primaryType": "cq:Page", + "template-1" : { + "structure": { + "jcr:primaryType": "cq:Page", + "jcr:content" : { + "jcr:primaryType" : "cq:PageContent", + "jcr:createdBy" : "admin", + "cq:template" : "/conf/coretest/settings/wcm/templates/template-1", + "root" : { + "jcr:primaryType" : "nt:unstructured", + "sling:resourceType": "wcm/foundation/components/responsivegrid", + "list": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "core/wcm/components/list/v3/list", + "listFrom": "children", + "displayItemAsTeaser": "true" + } + } + } + } + } + } + } + } + } +} diff --git a/bundles/core/src/test/resources/list/v3/test-content.json b/bundles/core/src/test/resources/list/v3/test-content.json index c07aa422dc..1d2f0f97da 100644 --- a/bundles/core/src/test/resources/list/v3/test-content.json +++ b/bundles/core/src/test/resources/list/v3/test-content.json @@ -316,6 +316,53 @@ "jcr:title": " ", "cq:lastModified": "2016-09-21T16:12:45.000-07:00" } + }, + "page_7": { + "jcr:primaryType": "cq:Page", + "jcr:content": { + "jcr:primaryType": "cq:PageContent", + "jcr:title": " ", + "cq:template": "/conf/coretest/settings/wcm/templates/template-1" + }, + "page_7_1": { + "jcr:primaryType": "cq:Page", + "jcr:content": { + "jcr:primaryType": "cq:PageContent", + "jcr:title": "Page 7.1", + "cq:featuredimage" : { + "jcr:primaryType" : "nt:unstructured", + "jcr:createdBy" : "admin", + "fileReference" : "/content/dam/core/images/Adobe_Systems_logo_and_wordmark.png" + } + } + }, + "page_7_2": { + "jcr:primaryType": "cq:Page", + "jcr:content": { + "jcr:primaryType": "cq:PageContent", + "jcr:title": "Page 7.2" + } + } + } + } + }, + "dam": { + "jcr:primaryType": "sling:Folder", + "core": { + "jcr:primaryType": "sling:Folder", + "images": { + "jcr:primaryType": "sling:Folder", + "Adobe_Systems_logo_and_wordmark.png": { + "jcr:primaryType": "dam:Asset", + "jcr:content": { + "jcr:primaryType": "dam:AssetContent", + "jcr:title": "Adobe Systems logo and wordmark", + "metadata": { + "jcr:primaryType": "nt:unstructured", + "dc:format": "image/png" + } + } + } } } }