From 3e02f1c8189da8034d70c84393efd380773e6cec Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 26 Aug 2022 17:52:41 -0500 Subject: [PATCH 01/22] #22857 initial draft and ideas --- .../transform/ContentletTransformer.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 5a6c418beb17..896dfc593d4d 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -1,7 +1,9 @@ package com.dotmarketing.portlets.contentlet.transform; import com.dotcms.content.business.json.ContentletJsonAPI; +import com.dotcms.content.business.json.ContentletJsonHelper; import com.dotcms.contenttype.model.field.LegacyFieldTypes; +import com.dotcms.contenttype.model.field.StoryBlockField; import com.dotcms.contenttype.model.type.ContentType; import com.dotcms.contenttype.model.type.FileAssetContentType; import com.dotcms.contenttype.transform.field.LegacyFieldTransformer; @@ -9,7 +11,9 @@ import com.dotcms.util.transform.DBTransformer; import com.dotmarketing.beans.Host; import com.dotmarketing.beans.Identifier; +import com.dotmarketing.beans.VersionInfo; import com.dotmarketing.business.APILocator; +import com.dotmarketing.business.ApiProvider; import com.dotmarketing.business.DotStateException; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotRuntimeException; @@ -22,6 +26,7 @@ import com.dotmarketing.util.Config; import com.dotmarketing.util.Logger; import com.dotmarketing.util.UtilMethods; +import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.annotations.VisibleForTesting; import com.liferay.util.StringPool; import io.vavr.Lazy; @@ -29,9 +34,14 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; + +import io.vavr.Tuple; +import io.vavr.Tuple2; +import io.vavr.control.Try; import org.jetbrains.annotations.NotNull; /** @@ -109,6 +119,8 @@ private static Contentlet transform(final Map map) { if(!hasJsonFields) { populateFields(contentlet, map); } + + refreshBlockEditorReferences(contentlet); populateWysiwyg(map, contentlet); populateFolderAndHost(contentlet, contentletId, contentTypeId); } catch (final Exception e) { @@ -123,6 +135,96 @@ private static Contentlet transform(final Map map) { return contentlet; } + /** + * In the case the content type has block editor fields, the dotContentlet references must be merge with the new references + * @param contentlet + */ + private static void refreshBlockEditorReferences(final Contentlet contentlet) { + + final List fields = contentlet.getContentType().fields(); + for (final com.dotcms.contenttype.model.field.Field field : fields) { + + if (field instanceof StoryBlockField) { + + final Object blockEditorValue = contentlet.get(field.variable()); + refreshBlockEditorValueReferences(blockEditorValue); + } + } + } + + private static void refreshBlockEditorValueReferences(final Object blockEditorValue) { + + try { + + final LinkedHashMap blockEditorMap = ContentletJsonHelper.INSTANCE.get().objectMapper() + .readValue(Try.of(()->blockEditorValue.toString()) + .getOrElse(""), LinkedHashMap.class); + final Map contentMap = (Map) blockEditorMap.get("content"); + if (null != contentMap) { + + if ("dotContent".equals(contentMap.get("type"))) { + + final Map attrsMap = (Map) blockEditorMap.get("attrs"); + if (null != attrsMap) { + + final Map dataMap = (Map) blockEditorMap.get("data"); + if (null != dataMap) { + + final String identifier = (String)dataMap.get("identifier"); + final String inode = (String)dataMap.get("inode"); + if (null != identifier && null != inode) { + + final VersionInfo versionInfo = APILocator.getVersionableAPI().getVersionInfo(identifier); + if (null != versionInfo && + !(inode.equals(versionInfo.getWorkingInode()) || inode.equals(versionInfo.getLiveInode()))) { + + // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh + refreshBlockEditorDataMap(dataMap, versionInfo) + } + } + } + } + } + } + } catch (final Exception e) { + Logger.debug(ContentletTransformer.class, e.getMessage()); + } + } + + private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo) { + // todo: not sure which inode should use to refresh the reference + final Contentlet contentlet = null; /// todo: find contentlet by + dataMap.put("hostName", contentlet.getHost()); + /* "modDate": "2022-08-26 21:22:25.46", + "publishDate": "2022-08-26 21:22:25.46", + "language": "en-US", + "title": "Test1", + "body": "

Test1

", + "contentTypeIcon": "wysiwyg", + "baseType": "CONTENT", + "inode": "0f653922-1f80-412c-9034-004c5322f871", + "archived": false, + "host": "48190c8c-42c4-46af-8d1a-0cd5db894797", + "working": true, + "locked": false, + "stInode": "2a3e91e4-fbbf-4876-8c5b-2233c1739b05", + "contentType": "webPageContent", + "live": true, + "owner": "dotcms.org.1", + "identifier": "b05b967bc49ccd34bf87ecb2603aaf97", + "languageId": 1, + "__icon__": "contentIcon", + "url": "/content.0f653922-1f80-412c-9034-004c5322f871", + "titleImage": "TITLE_IMAGE_NOT_FOUND", + "modUserName": "Admin User", + "hasLiveVersion": true, + "folder": "SYSTEM_FOLDER", + "hasTitleImage": false, + "sortOrder": 0, + "modUser": "dotcms.org.1"*/ + } + + private static void populateFolderAndHost(final Contentlet contentlet, final String contentletId, final String contentTypeId) throws DotDataException, DotSecurityException { if (UtilMethods.isSet(contentlet.getIdentifier())) { From e6627624afc4018a4a6f4528ce61b9aed77831f4 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 26 Aug 2022 18:02:13 -0500 Subject: [PATCH 02/22] #22857 initial draft and ideas --- .../transform/ContentletTransformer.java | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 896dfc593d4d..76d8b3549575 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -37,6 +37,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.StringTokenizer; import io.vavr.Tuple; @@ -179,7 +180,7 @@ private static void refreshBlockEditorValueReferences(final Object blockEditorVa !(inode.equals(versionInfo.getWorkingInode()) || inode.equals(versionInfo.getLiveInode()))) { // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh - refreshBlockEditorDataMap(dataMap, versionInfo) + refreshBlockEditorDataMap(dataMap, versionInfo, Collections.emptySet()); } } } @@ -191,37 +192,22 @@ private static void refreshBlockEditorValueReferences(final Object blockEditorVa } } - private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo) { + private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo, final Set skipFieldSet) throws DotDataException, DotSecurityException { // todo: not sure which inode should use to refresh the reference - final Contentlet contentlet = null; /// todo: find contentlet by - dataMap.put("hostName", contentlet.getHost()); - /* "modDate": "2022-08-26 21:22:25.46", - "publishDate": "2022-08-26 21:22:25.46", - "language": "en-US", - "title": "Test1", - "body": "

Test1

", - "contentTypeIcon": "wysiwyg", - "baseType": "CONTENT", - "inode": "0f653922-1f80-412c-9034-004c5322f871", - "archived": false, - "host": "48190c8c-42c4-46af-8d1a-0cd5db894797", - "working": true, - "locked": false, - "stInode": "2a3e91e4-fbbf-4876-8c5b-2233c1739b05", - "contentType": "webPageContent", - "live": true, - "owner": "dotcms.org.1", - "identifier": "b05b967bc49ccd34bf87ecb2603aaf97", - "languageId": 1, - "__icon__": "contentIcon", - "url": "/content.0f653922-1f80-412c-9034-004c5322f871", - "titleImage": "TITLE_IMAGE_NOT_FOUND", - "modUserName": "Admin User", - "hasLiveVersion": true, - "folder": "SYSTEM_FOLDER", - "hasTitleImage": false, - "sortOrder": 0, - "modUser": "dotcms.org.1"*/ + final Contentlet contentlet = APILocator.getContentletAPI().find( + versionInfo.getWorkingInode(), APILocator.systemUser(), false); /// todo: find contentlet by working or live + final Set contenteFieldNames = dataMap.keySet(); + for (Object contentFieldName : contenteFieldNames) { + + if (!skipFieldSet.contains(contentFieldName)) { // if it is not a field already edit by the client + + final Object value = contentlet.get(contentFieldName.toString()); + if (null != value) { + + dataMap.put(contentFieldName, value); + } + } + } } From 70a2df687167cc6a1e991b4bc5c962ebd3f2684a Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 26 Aug 2022 18:10:44 -0500 Subject: [PATCH 03/22] #22857 initial draft and ideas --- .../transform/ContentletTransformer.java | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 76d8b3549575..bd04d9c6c26c 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -153,43 +153,60 @@ private static void refreshBlockEditorReferences(final Contentlet contentlet) { } } - private static void refreshBlockEditorValueReferences(final Object blockEditorValue) { + private static Tuple2 refreshBlockEditorValueReferences(final Object blockEditorValue) { + boolean refreshed = false; try { final LinkedHashMap blockEditorMap = ContentletJsonHelper.INSTANCE.get().objectMapper() .readValue(Try.of(()->blockEditorValue.toString()) .getOrElse(""), LinkedHashMap.class); - final Map contentMap = (Map) blockEditorMap.get("content"); - if (null != contentMap) { + final List contentsMap = (List) blockEditorMap.get("content"); - if ("dotContent".equals(contentMap.get("type"))) { + for (final Object contentMapObject : contentsMap) { - final Map attrsMap = (Map) blockEditorMap.get("attrs"); - if (null != attrsMap) { + final Map contentMap = (Map) contentMapObject; + if (null != contentMap) { - final Map dataMap = (Map) blockEditorMap.get("data"); - if (null != dataMap) { + if ("dotContent".equals(contentMap.get("type"))) { - final String identifier = (String)dataMap.get("identifier"); - final String inode = (String)dataMap.get("inode"); - if (null != identifier && null != inode) { + final Map attrsMap = (Map) contentMap.get("attrs"); + if (null != attrsMap) { - final VersionInfo versionInfo = APILocator.getVersionableAPI().getVersionInfo(identifier); - if (null != versionInfo && - !(inode.equals(versionInfo.getWorkingInode()) || inode.equals(versionInfo.getLiveInode()))) { + final Map dataMap = (Map) attrsMap.get("data"); + if (null != dataMap) { - // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh - refreshBlockEditorDataMap(dataMap, versionInfo, Collections.emptySet()); + final String identifier = (String) dataMap.get("identifier"); + final String inode = (String) dataMap.get("inode"); + if (null != identifier && null != inode) { + + final VersionInfo versionInfo = APILocator.getVersionableAPI().getVersionInfo(identifier); + if (null != versionInfo && + !(inode.equals(versionInfo.getWorkingInode()) || inode.equals(versionInfo.getLiveInode()))) { + + refreshed = true; + // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh + refreshBlockEditorDataMap(dataMap, versionInfo, Collections.emptySet()); + } } } } } } } + + if (refreshed) { + + final String blockEditJsonValueString = ContentletJsonHelper.INSTANCE.get().objectMapper() + .writeValueAsString(blockEditorMap); + + return Tuple.of(true, blockEditJsonValueString); // has changed and the now json is returned + } } catch (final Exception e) { Logger.debug(ContentletTransformer.class, e.getMessage()); } + + return Tuple.of(false, blockEditorValue); // return the original value and says didn't change } private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo, final Set skipFieldSet) throws DotDataException, DotSecurityException { From 699d6ea5d54fa551b242ac5336fc1ddce1634320 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 26 Aug 2022 18:12:12 -0500 Subject: [PATCH 04/22] #22857 initial draft and ideas --- .../contentlet/transform/ContentletTransformer.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index bd04d9c6c26c..066786689766 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -148,7 +148,11 @@ private static void refreshBlockEditorReferences(final Contentlet contentlet) { if (field instanceof StoryBlockField) { final Object blockEditorValue = contentlet.get(field.variable()); - refreshBlockEditorValueReferences(blockEditorValue); + final Tuple2 resultOfRefresh = refreshBlockEditorValueReferences(blockEditorValue); + if (resultOfRefresh._1()) { + + contentlet.setProperty(field.variable(), resultOfRefresh._2()); + } } } } From cbf6f2f067e85fa30e1a20de29a04d58c701544c Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 26 Aug 2022 18:14:23 -0500 Subject: [PATCH 05/22] #22857 initial draft and ideas --- .../portlets/contentlet/transform/ContentletTransformer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 066786689766..bbacef5c349d 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -149,7 +149,7 @@ private static void refreshBlockEditorReferences(final Contentlet contentlet) { final Object blockEditorValue = contentlet.get(field.variable()); final Tuple2 resultOfRefresh = refreshBlockEditorValueReferences(blockEditorValue); - if (resultOfRefresh._1()) { + if (resultOfRefresh._1()) { // the block editor value has changed and has to be override contentlet.setProperty(field.variable(), resultOfRefresh._2()); } @@ -210,7 +210,7 @@ private static Tuple2 refreshBlockEditorValueReferences(final O Logger.debug(ContentletTransformer.class, e.getMessage()); } - return Tuple.of(false, blockEditorValue); // return the original value and says didn't change + return Tuple.of(false, blockEditorValue); // return the original value and value didn't change } private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo, final Set skipFieldSet) throws DotDataException, DotSecurityException { From c68edba1bedc0096ff0b2296735c307f8baaba94 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 26 Aug 2022 18:16:22 -0500 Subject: [PATCH 06/22] #22857 initial draft and ideas --- .../portlets/contentlet/transform/ContentletTransformer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index bbacef5c349d..9aac26a59334 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -217,8 +217,8 @@ private static void refreshBlockEditorDataMap(final Map dataMap, final VersionIn // todo: not sure which inode should use to refresh the reference final Contentlet contentlet = APILocator.getContentletAPI().find( versionInfo.getWorkingInode(), APILocator.systemUser(), false); /// todo: find contentlet by working or live - final Set contenteFieldNames = dataMap.keySet(); - for (Object contentFieldName : contenteFieldNames) { + final Set contentFieldNames = dataMap.keySet(); + for (Object contentFieldName : contentFieldNames) { if (!skipFieldSet.contains(contentFieldName)) { // if it is not a field already edit by the client From 938b2edb4756ccad3f43873f5a11fa301af5701f Mon Sep 17 00:00:00 2001 From: jdotcms Date: Mon, 29 Aug 2022 17:33:30 -0500 Subject: [PATCH 07/22] #22857 final changes --- .../transform/ContentletTransformer.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 9aac26a59334..5f1f2557f910 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -190,7 +190,7 @@ private static Tuple2 refreshBlockEditorValueReferences(final O refreshed = true; // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh - refreshBlockEditorDataMap(dataMap, versionInfo, Collections.emptySet()); + refreshBlockEditorDataMap(dataMap, versionInfo); } } } @@ -213,20 +213,17 @@ private static Tuple2 refreshBlockEditorValueReferences(final O return Tuple.of(false, blockEditorValue); // return the original value and value didn't change } - private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo, final Set skipFieldSet) throws DotDataException, DotSecurityException { - // todo: not sure which inode should use to refresh the reference + private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo) throws DotDataException, DotSecurityException { + final Contentlet contentlet = APILocator.getContentletAPI().find( - versionInfo.getWorkingInode(), APILocator.systemUser(), false); /// todo: find contentlet by working or live + versionInfo.getLiveInode(), APILocator.systemUser(), false); final Set contentFieldNames = dataMap.keySet(); for (Object contentFieldName : contentFieldNames) { - if (!skipFieldSet.contains(contentFieldName)) { // if it is not a field already edit by the client - - final Object value = contentlet.get(contentFieldName.toString()); - if (null != value) { + final Object value = contentlet.get(contentFieldName.toString()); + if (null != value) { - dataMap.put(contentFieldName, value); - } + dataMap.put(contentFieldName, value); } } } From 3df7c1b2f85b15698b3bcb8d28632723315d8f8e Mon Sep 17 00:00:00 2001 From: jdotcms Date: Tue, 30 Aug 2022 14:34:22 -0500 Subject: [PATCH 08/22] =?UTF-8?q?=CB=9C#22857=20adding=20the=20story=20blo?= =?UTF-8?q?ck=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contenttype/business/StoryBlockAPI.java | 57 +++++ .../business/StoryBlockAPIImpl.java | 200 ++++++++++++++++++ .../com/dotmarketing/business/APILocator.java | 11 +- .../transform/ContentletTransformer.java | 89 +------- 4 files changed, 268 insertions(+), 89 deletions(-) create mode 100644 dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java create mode 100644 dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java new file mode 100644 index 000000000000..272d8589ae81 --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java @@ -0,0 +1,57 @@ +package com.dotcms.contenttype.business; + +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.google.common.collect.ImmutableSet; +import io.vavr.Tuple2; + +import java.util.List; +import java.util.Set; + +/** + * Api to handle dependencies, references and so for the StoryBlock (content editor) + * @author jsanca + */ +public interface StoryBlockAPI { + + String CONTENT_KEY = "content"; + String TYPE_KEY = "type"; + String ATTRS_KEY = "attrs"; + String DATA_KEY = "data"; + String IDENTIFIER_KEY = "identifier"; + String INODE_KEY = "inode"; + + /** + * Encapsulates the allowed types for contentlets on the story block + */ + Set allowedTypes = new ImmutableSet.Builder().add("dotContent","dotImage").build(); + + /** + * Analyzed all {@link com.dotcms.contenttype.model.field.StoryBlockField} fields, refreshing all contentlet which + * inode is different to the live inode on the system. + * @param contentlet {@link Contentlet} to refresh + * @return Contentlet content refreshed + */ + Contentlet refreshReferences(final Contentlet contentlet); + + /** + * Refresh the story block references for a story block json (The argument storyBlockValue will be converted to string and parse as json) + * @param storyBlockValue Object + * @return Tuple2 boolean if there was something to refresh, the object is the new object refreshed; if not anything to refresh return the same object sent as an argument + */ + Tuple2 refreshStoryBlockValueReferences(final Object storyBlockValue); + + /** + * For each {@link com.dotcms.contenttype.model.field.StoryBlockField} field, retrieve contentlet ids referrer on the + * story block json. + * @param contentlet {@link Contentlet} + * @return List of identifier (empty list if not any contentlet) + */ + List getDependencies (final Contentlet contentlet); + + /** + * Get the dependencies for a story block json /Users/jsanca/gitsources/new-core2/core/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java + * @param storyBlockValue Object + * @return List of contentlets on the story block referrer + */ + List getDependencies (final Object storyBlockValue); +} diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java new file mode 100644 index 000000000000..7e54e3e0588c --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java @@ -0,0 +1,200 @@ +package com.dotcms.contenttype.business; + +import com.dotcms.content.business.json.ContentletJsonHelper; +import com.dotcms.contenttype.model.field.StoryBlockField; +import com.dotmarketing.beans.VersionInfo; +import com.dotmarketing.business.APILocator; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.contentlet.transform.ContentletTransformer; +import com.dotmarketing.util.Logger; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.collect.ImmutableList; +import com.liferay.util.StringPool; +import io.vavr.Tuple; +import io.vavr.Tuple2; +import io.vavr.control.Try; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * default implementation + * @author jsanca + */ +public class StoryBlockAPIImpl implements StoryBlockAPI { + + @Override + public Contentlet refreshReferences(final Contentlet contentlet) { + + if (null != contentlet) { + + contentlet.getContentType().fields(StoryBlockField.class).forEach(field -> { + + final Object storyBlockValue = contentlet.get(field.variable()); + if (null != storyBlockValue) { + + final Tuple2 result = this.refreshStoryBlockValueReferences(storyBlockValue); + if (result._1()) { // the story block value has been changed and has been overridden + + contentlet.setProperty(field.variable(), result._2()); + } + } + }); + } + + return contentlet; + } + @Override + public Tuple2 refreshStoryBlockValueReferences(final Object storyBlockValue) { + + boolean refreshed = false; + try { + + final LinkedHashMap blockEditorMap = this.toMap(storyBlockValue); + + final List contentsMap = (List) blockEditorMap.get(CONTENT_KEY); + + for (final Object contentMapObject : contentsMap) { + + if (null != contentMapObject) { + + final Map contentMap = (Map) contentMapObject; + final Object type = contentMap.get(TYPE_KEY); + if (allowedTypes.contains(type)) { + + refreshed |= refreshStoryBlockMap(contentMap); + } + } + } + + if (refreshed) { + + return Tuple.of(true, toJson(blockEditorMap)); // has changed and the now json is returned + } + } catch (final Exception e) { + + Logger.debug(ContentletTransformer.class, e.getMessage()); + } + + return Tuple.of(false, storyBlockValue); // return the original value and value didn't change + } + + private boolean refreshStoryBlockMap(final Map contentMap) throws DotDataException, DotSecurityException { + + boolean refreshed = false; + final Map attrsMap = (Map) contentMap.get(ATTRS_KEY); + if (null != attrsMap) { + + final Map dataMap = (Map) attrsMap.get(DATA_KEY); + if (null != dataMap) { + + final String identifier = (String) dataMap.get(IDENTIFIER_KEY); + final String inode = (String) dataMap.get(INODE_KEY); + if (null != identifier && null != inode) { + + final VersionInfo versionInfo = APILocator.getVersionableAPI().getVersionInfo(identifier); + if (null != versionInfo && null != versionInfo.getLiveInode() && + !inode.equals(versionInfo.getLiveInode())) { + + // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh + this.refreshBlockEditorDataMap(dataMap, versionInfo); + refreshed = true; + } + } + } + } + + return refreshed; + } + + @Override + public List getDependencies(final Contentlet contentlet) { + + final ImmutableList.Builder contentletIdentifierList = new ImmutableList.Builder<>(); + + contentlet.getContentType().fields(StoryBlockField.class).forEach(field -> { + + contentletIdentifierList.addAll(this.getDependencies(contentlet.get(field.variable()))); + }); + + return contentletIdentifierList.build(); + } + + @Override + public List getDependencies (final Object storyBlockValue) { + + final ImmutableList.Builder contentletIdentifierList = new ImmutableList.Builder<>(); + + try { + + final LinkedHashMap blockEditorMap = this.toMap(storyBlockValue); + final List contentsMap = (List) blockEditorMap.get(CONTENT_KEY); + + for (final Object contentMapObject : contentsMap) { + + if (null != contentMapObject) { + + final Map contentMap = (Map) contentMapObject; + final Object type = contentMap.get(TYPE_KEY); + if (allowedTypes.contains(type)) { + + this.addDependencies(contentletIdentifierList, contentMap); + } + } + } + } catch (final Exception e) { + + Logger.debug(ContentletTransformer.class, e.getMessage()); + } + + return contentletIdentifierList.build(); + } + + private static void addDependencies(final ImmutableList.Builder contentletIdentifierList, + final Map contentMap) { + + final Map attrsMap = (Map) contentMap.get(ATTRS_KEY); + if (null != attrsMap) { + + final Map dataMap = (Map) attrsMap.get(DATA_KEY); + if (null != dataMap) { + + final String identifier = (String) dataMap.get(IDENTIFIER_KEY); + contentletIdentifierList.add(identifier); + } + } + } + + private LinkedHashMap toMap(final Object blockEditorValue) throws JsonProcessingException { + + return ContentletJsonHelper.INSTANCE.get().objectMapper() + .readValue(Try.of(() -> blockEditorValue.toString()) + .getOrElse(StringPool.BLANK), LinkedHashMap.class); + } + + private String toJson (final Object blockEditorMap) throws JsonProcessingException { + + return ContentletJsonHelper.INSTANCE.get().objectMapper() + .writeValueAsString(blockEditorMap); + } + + private void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo) throws DotDataException, DotSecurityException { + + final Contentlet contentlet = APILocator.getContentletAPI().find( + versionInfo.getLiveInode(), APILocator.systemUser(), false); + final Set contentFieldNames = dataMap.keySet(); + for (final Object contentFieldName : contentFieldNames) { + + final Object value = contentlet.get(contentFieldName.toString()); + if (null != value) { + + dataMap.put(contentFieldName, value); + } + } + } +} diff --git a/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java b/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java index 2ceaa68e32f0..0f15b5e1bfa9 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/APILocator.java @@ -28,6 +28,8 @@ import com.dotcms.contenttype.business.DotAssetAPIImpl; import com.dotcms.contenttype.business.FieldAPI; import com.dotcms.contenttype.business.FieldAPIImpl; +import com.dotcms.contenttype.business.StoryBlockAPI; +import com.dotcms.contenttype.business.StoryBlockAPIImpl; import com.dotcms.device.DeviceAPI; import com.dotcms.device.DeviceAPIImpl; import com.dotcms.dotpubsub.DotPubSubProvider; @@ -263,6 +265,10 @@ public static CompanyAPI getCompanyAPI() { return getAPILocatorInstance().getCompanyAPIImpl(); } + public static StoryBlockAPI getStoryBlockAPI() { + return (StoryBlockAPI)getInstance(APIIndex.STORY_BLOCK_API); + } + @VisibleForTesting protected CompanyAPI getCompanyAPIImpl() { return (CompanyAPI) getInstance(APIIndex.COMPANY_API); @@ -1228,7 +1234,9 @@ enum APIIndex CONTENTLET_METADATA_API, DEVICE_API, DETERMINISTIC_IDENTIFIER_API, - CONTENTLET_JSON_API; + CONTENTLET_JSON_API, + + STORY_BLOCK_API; @@ -1315,6 +1323,7 @@ Object create() { case DEVICE_API: return new DeviceAPIImpl(); case DETERMINISTIC_IDENTIFIER_API: return new DeterministicIdentifierAPIImpl(); case CONTENTLET_JSON_API: return new ContentletJsonAPIImpl(); + case STORY_BLOCK_API: return new StoryBlockAPIImpl(); } throw new AssertionError("Unknown API index: " + this); } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 5f1f2557f910..23ee81c75ba9 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -136,96 +136,9 @@ private static Contentlet transform(final Map map) { return contentlet; } - /** - * In the case the content type has block editor fields, the dotContentlet references must be merge with the new references - * @param contentlet - */ private static void refreshBlockEditorReferences(final Contentlet contentlet) { - final List fields = contentlet.getContentType().fields(); - for (final com.dotcms.contenttype.model.field.Field field : fields) { - - if (field instanceof StoryBlockField) { - - final Object blockEditorValue = contentlet.get(field.variable()); - final Tuple2 resultOfRefresh = refreshBlockEditorValueReferences(blockEditorValue); - if (resultOfRefresh._1()) { // the block editor value has changed and has to be override - - contentlet.setProperty(field.variable(), resultOfRefresh._2()); - } - } - } - } - - private static Tuple2 refreshBlockEditorValueReferences(final Object blockEditorValue) { - - boolean refreshed = false; - try { - - final LinkedHashMap blockEditorMap = ContentletJsonHelper.INSTANCE.get().objectMapper() - .readValue(Try.of(()->blockEditorValue.toString()) - .getOrElse(""), LinkedHashMap.class); - final List contentsMap = (List) blockEditorMap.get("content"); - - for (final Object contentMapObject : contentsMap) { - - final Map contentMap = (Map) contentMapObject; - if (null != contentMap) { - - if ("dotContent".equals(contentMap.get("type"))) { - - final Map attrsMap = (Map) contentMap.get("attrs"); - if (null != attrsMap) { - - final Map dataMap = (Map) attrsMap.get("data"); - if (null != dataMap) { - - final String identifier = (String) dataMap.get("identifier"); - final String inode = (String) dataMap.get("inode"); - if (null != identifier && null != inode) { - - final VersionInfo versionInfo = APILocator.getVersionableAPI().getVersionInfo(identifier); - if (null != versionInfo && - !(inode.equals(versionInfo.getWorkingInode()) || inode.equals(versionInfo.getLiveInode()))) { - - refreshed = true; - // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh - refreshBlockEditorDataMap(dataMap, versionInfo); - } - } - } - } - } - } - } - - if (refreshed) { - - final String blockEditJsonValueString = ContentletJsonHelper.INSTANCE.get().objectMapper() - .writeValueAsString(blockEditorMap); - - return Tuple.of(true, blockEditJsonValueString); // has changed and the now json is returned - } - } catch (final Exception e) { - Logger.debug(ContentletTransformer.class, e.getMessage()); - } - - return Tuple.of(false, blockEditorValue); // return the original value and value didn't change - } - - private static void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo) throws DotDataException, DotSecurityException { - - final Contentlet contentlet = APILocator.getContentletAPI().find( - versionInfo.getLiveInode(), APILocator.systemUser(), false); - final Set contentFieldNames = dataMap.keySet(); - for (Object contentFieldName : contentFieldNames) { - - final Object value = contentlet.get(contentFieldName.toString()); - if (null != value) { - - dataMap.put(contentFieldName, value); - } - } + APILocator.getStoryBlockAPI().refreshReferences(contentlet); } From f6943a82d8e867f5c1d93d3bf878e6e259ddaca5 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Tue, 30 Aug 2022 16:24:02 -0500 Subject: [PATCH 09/22] #22857 the refresh happens now even on cached contentlets --- .../business/ESContentFactoryImpl.java | 23 ++++++++++++++++++- .../contenttype/business/StoryBlockAPI.java | 3 ++- .../business/StoryBlockAPIImpl.java | 23 ++++++++++++------- .../business/VersionableAPIImpl.java | 1 + .../transform/ContentletTransformer.java | 14 ++--------- 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java index 0ea2e4176af5..1158443da552 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java @@ -86,6 +86,7 @@ import com.google.common.collect.Lists; import com.google.common.primitives.Ints; import com.liferay.portal.model.User; +import io.vavr.Tuple2; import io.vavr.control.Try; import java.io.Serializable; import java.sql.Connection; @@ -855,7 +856,7 @@ protected Contentlet find(final String inode) throws ElasticsearchException, Dot if (CACHE_404_CONTENTLET.equals(contentlet.getInode())) { return null; } - return contentlet; + return processContentletCache(contentlet); } final Optional dbContentlet = this.findInDb(inode); @@ -870,6 +871,26 @@ protected Contentlet find(final String inode) throws ElasticsearchException, Dot } + /* + * When a contentlet is being cached, may need some process since the value may be invalid. + * One of the things to check would be the contentlet references on the story block, if the contentlet + * has a story block field and contentlets referred in it, the code checks if the contentlets have been + * changed, if so updates the content and stores the json updated again to the contentlet + */ + private Contentlet processContentletCache (final Contentlet contentletCached) { + + final Tuple2 storyBlockRefreshedResult = + APILocator.getStoryBlockAPI().refreshReferences(contentletCached); + + if (storyBlockRefreshedResult._1()) { + + contentletCache.add(storyBlockRefreshedResult._2().getInode(), storyBlockRefreshedResult._2()); + return storyBlockRefreshedResult._2(); + } + + return contentletCached; + } + @Override protected List findAllCurrent() throws DotDataException { throw new DotDataException("findAllCurrent() will blow your stack off, use findAllCurrent(offset, limit)"); diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java index 272d8589ae81..70dfa0a8b99a 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java @@ -19,6 +19,7 @@ public interface StoryBlockAPI { String DATA_KEY = "data"; String IDENTIFIER_KEY = "identifier"; String INODE_KEY = "inode"; + String LANGUAGE_ID_KEY = "languageId"; /** * Encapsulates the allowed types for contentlets on the story block @@ -31,7 +32,7 @@ public interface StoryBlockAPI { * @param contentlet {@link Contentlet} to refresh * @return Contentlet content refreshed */ - Contentlet refreshReferences(final Contentlet contentlet); + Tuple2 refreshReferences(final Contentlet contentlet); /** * Refresh the story block references for a story block json (The argument storyBlockValue will be converted to string and parse as json) diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java index 7e54e3e0588c..dfaa6684d680 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java @@ -2,11 +2,13 @@ import com.dotcms.content.business.json.ContentletJsonHelper; import com.dotcms.contenttype.model.field.StoryBlockField; +import com.dotcms.util.ConversionUtils; import com.dotmarketing.beans.VersionInfo; import com.dotmarketing.business.APILocator; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.contentlet.model.ContentletVersionInfo; import com.dotmarketing.portlets.contentlet.transform.ContentletTransformer; import com.dotmarketing.util.Logger; import com.fasterxml.jackson.core.JsonProcessingException; @@ -15,11 +17,13 @@ import io.vavr.Tuple; import io.vavr.Tuple2; import io.vavr.control.Try; +import org.apache.commons.lang3.mutable.MutableBoolean; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; /** @@ -29,8 +33,9 @@ public class StoryBlockAPIImpl implements StoryBlockAPI { @Override - public Contentlet refreshReferences(final Contentlet contentlet) { + public Tuple2 refreshReferences(final Contentlet contentlet) { + final MutableBoolean refreshed = new MutableBoolean(false); if (null != contentlet) { contentlet.getContentType().fields(StoryBlockField.class).forEach(field -> { @@ -41,13 +46,14 @@ public Contentlet refreshReferences(final Contentlet contentlet) { final Tuple2 result = this.refreshStoryBlockValueReferences(storyBlockValue); if (result._1()) { // the story block value has been changed and has been overridden + refreshed.setTrue(); contentlet.setProperty(field.variable(), result._2()); } } }); } - return contentlet; + return Tuple.of(refreshed.booleanValue(), contentlet); } @Override public Tuple2 refreshStoryBlockValueReferences(final Object storyBlockValue) { @@ -95,14 +101,15 @@ private boolean refreshStoryBlockMap(final Map contentMap) throws DotDataExcepti final String identifier = (String) dataMap.get(IDENTIFIER_KEY); final String inode = (String) dataMap.get(INODE_KEY); + final long languageId = ConversionUtils.toLong(dataMap.get(LANGUAGE_ID_KEY), ()-> APILocator.getLanguageAPI().getDefaultLanguage().getId()); if (null != identifier && null != inode) { - final VersionInfo versionInfo = APILocator.getVersionableAPI().getVersionInfo(identifier); - if (null != versionInfo && null != versionInfo.getLiveInode() && - !inode.equals(versionInfo.getLiveInode())) { + final Optional versionInfo = APILocator.getVersionableAPI().getContentletVersionInfo(identifier, languageId); + if (null != versionInfo && versionInfo.isPresent() && null != versionInfo.get().getLiveInode() && + !inode.equals(versionInfo.get().getLiveInode())) { // the inode stored on the json does not match with any top inode, so the information stored is old and need refresh - this.refreshBlockEditorDataMap(dataMap, versionInfo); + this.refreshBlockEditorDataMap(dataMap, versionInfo.get().getLiveInode()); refreshed = true; } } @@ -183,10 +190,10 @@ private String toJson (final Object blockEditorMap) throws JsonProcessingExcepti .writeValueAsString(blockEditorMap); } - private void refreshBlockEditorDataMap(final Map dataMap, final VersionInfo versionInfo) throws DotDataException, DotSecurityException { + private void refreshBlockEditorDataMap(final Map dataMap, final String liveINode) throws DotDataException, DotSecurityException { final Contentlet contentlet = APILocator.getContentletAPI().find( - versionInfo.getLiveInode(), APILocator.systemUser(), false); + liveINode, APILocator.systemUser(), false); final Set contentFieldNames = dataMap.keySet(); for (final Object contentFieldName : contentFieldNames) { diff --git a/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java b/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java index e22861218e97..504dedb1732f 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java @@ -590,6 +590,7 @@ public void setWorking(final Versionable versionable) throws DotDataException, D } CacheLocator.getIdentifierCache().removeContentletVersionInfoToCache(info.get().getIdentifier(),contentlet.getLanguageId()); + CacheLocator.getIdentifierCache().removeVersionInfoFromCache(info.get().getIdentifier()); } else { final VersionInfo info = versionableFactory.findVersionInfoFromDb(identifier); diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 23ee81c75ba9..1e788b1c9d57 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -1,9 +1,7 @@ package com.dotmarketing.portlets.contentlet.transform; import com.dotcms.content.business.json.ContentletJsonAPI; -import com.dotcms.content.business.json.ContentletJsonHelper; import com.dotcms.contenttype.model.field.LegacyFieldTypes; -import com.dotcms.contenttype.model.field.StoryBlockField; import com.dotcms.contenttype.model.type.ContentType; import com.dotcms.contenttype.model.type.FileAssetContentType; import com.dotcms.contenttype.transform.field.LegacyFieldTransformer; @@ -11,9 +9,7 @@ import com.dotcms.util.transform.DBTransformer; import com.dotmarketing.beans.Host; import com.dotmarketing.beans.Identifier; -import com.dotmarketing.beans.VersionInfo; import com.dotmarketing.business.APILocator; -import com.dotmarketing.business.ApiProvider; import com.dotmarketing.business.DotStateException; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotRuntimeException; @@ -26,7 +22,6 @@ import com.dotmarketing.util.Config; import com.dotmarketing.util.Logger; import com.dotmarketing.util.UtilMethods; -import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.annotations.VisibleForTesting; import com.liferay.util.StringPool; import io.vavr.Lazy; @@ -34,15 +29,10 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.StringTokenizer; -import io.vavr.Tuple; -import io.vavr.Tuple2; -import io.vavr.control.Try; import org.jetbrains.annotations.NotNull; /** @@ -121,7 +111,7 @@ private static Contentlet transform(final Map map) { populateFields(contentlet, map); } - refreshBlockEditorReferences(contentlet); + refreshStoryBlockReferences(contentlet); populateWysiwyg(map, contentlet); populateFolderAndHost(contentlet, contentletId, contentTypeId); } catch (final Exception e) { @@ -136,7 +126,7 @@ private static Contentlet transform(final Map map) { return contentlet; } - private static void refreshBlockEditorReferences(final Contentlet contentlet) { + private static void refreshStoryBlockReferences(final Contentlet contentlet) { APILocator.getStoryBlockAPI().refreshReferences(contentlet); } From b6c60ccc969dc9c84c4c1136fe41b88e30bf758c Mon Sep 17 00:00:00 2001 From: jdotcms Date: Wed, 31 Aug 2022 13:33:10 -0500 Subject: [PATCH 10/22] #22857 adding some minor changes --- .../main/java/com/dotmarketing/business/VersionableAPIImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java b/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java index 504dedb1732f..e22861218e97 100644 --- a/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/business/VersionableAPIImpl.java @@ -590,7 +590,6 @@ public void setWorking(final Versionable versionable) throws DotDataException, D } CacheLocator.getIdentifierCache().removeContentletVersionInfoToCache(info.get().getIdentifier(),contentlet.getLanguageId()); - CacheLocator.getIdentifierCache().removeVersionInfoFromCache(info.get().getIdentifier()); } else { final VersionInfo info = versionableFactory.findVersionInfoFromDb(identifier); From 717a0c3bb3eb35339b05420810fe44df5ea6f9a0 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Wed, 31 Aug 2022 15:56:07 -0500 Subject: [PATCH 11/22] #22857 adding unit test for update references --- .../java/com/dotcms/MainSuite.java | 4 +- .../business/StoryBlockAPITest.java | 189 ++++++++++++++++++ .../contenttype/business/StoryBlockAPI.java | 9 + .../business/StoryBlockAPIImpl.java | 65 +++++- 4 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java diff --git a/dotCMS/src/integration-test/java/com/dotcms/MainSuite.java b/dotCMS/src/integration-test/java/com/dotcms/MainSuite.java index dd76bd16954c..2af65118ff61 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/MainSuite.java +++ b/dotCMS/src/integration-test/java/com/dotcms/MainSuite.java @@ -14,6 +14,7 @@ import com.dotcms.content.model.hydration.MetadataDelegateTest; import com.dotcms.contenttype.business.ContentTypeInitializerTest; import com.dotcms.contenttype.business.DotAssetBaseTypeToContentTypeStrategyImplTest; +import com.dotcms.contenttype.business.StoryBlockAPITest; import com.dotcms.contenttype.test.DotAssetAPITest; import com.dotcms.csspreproc.CSSCacheTest; import com.dotcms.dotpubsub.PostgresPubSubImplTest; @@ -560,7 +561,8 @@ MenuResourceTest.class, AWSS3PublisherTest.class, ContentTypeInitializerTest.class, - PaginatedContentletsIntegrationTest.class + PaginatedContentletsIntegrationTest.class, + StoryBlockAPITest.class }) public class MainSuite { diff --git a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java new file mode 100644 index 000000000000..abe210c2318f --- /dev/null +++ b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java @@ -0,0 +1,189 @@ +package com.dotcms.contenttype.business; + +import com.dotcms.IntegrationTestBase; +import com.dotcms.content.business.json.ContentletJsonHelper; +import com.dotcms.contenttype.model.type.BaseContentType; +import com.dotcms.contenttype.model.type.ContentType; +import com.dotcms.contenttype.model.type.ContentTypeBuilder; +import com.dotcms.contenttype.model.type.FileAssetContentType; +import com.dotcms.datagen.ContentletDataGen; +import com.dotcms.mock.request.FakeHttpRequest; +import com.dotcms.mock.response.BaseResponse; +import com.dotcms.rendering.velocity.viewtools.content.StoryBlockMap; +import com.dotcms.repackage.org.apache.commons.io.FileUtils; +import com.dotcms.util.IntegrationTestInitService; +import com.dotmarketing.beans.Host; +import com.dotmarketing.business.APILocator; +import com.dotmarketing.exception.DotDataException; +import com.dotmarketing.exception.DotSecurityException; +import com.dotmarketing.portlets.contentlet.model.Contentlet; +import com.dotmarketing.portlets.contentlet.model.ContentletDependencies; +import com.dotmarketing.portlets.contentlet.model.IndexPolicy; +import com.dotmarketing.portlets.folders.business.FolderAPI; +import com.dotmarketing.portlets.folders.model.Folder; +import com.dotmarketing.util.Config; +import com.dotmarketing.util.VelocityUtil; +import com.dotmarketing.util.json.JSONException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.liferay.portal.model.User; +import com.liferay.util.StringPool; +import io.vavr.Tuple2; +import io.vavr.control.Try; +import org.apache.velocity.context.Context; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static junit.framework.TestCase.assertEquals; + +public class StoryBlockAPITest extends IntegrationTestBase { + + private static final String JSON = + "{\n" + + " \"type\":\"doc\",\n" + + " \"content\":[\n" + + " {\n" + + " \"type\":\"horizontalRule\"\n" + + " },\n" + + " {\n" + + " \"type\":\"heading\",\n" + + " \"content\":[\n" + + " {\n" + + " \"text\":\"Heading\",\n" + + " \"type\":\"text\"\n" + + " },\n" + + " {\n" + + " \"marks\":[\n" + + " {\n" + + " \"type\":\"italic\"\n" + + " }\n" + + " ],\n" + + " \"text\":\" 1\",\n" + + " \"type\":\"text\"\n" + + " }\n" + + " ],\n" + + " \"attrs\":{\n" + + " \"textAlign\":\"left\",\n" + + " \"level\":1\n" + + " }\n" + + " },\n" + + " {\n" + + " \"type\":\"paragraph\",\n" + + " \"content\":[\n" + + " {\n" + + " \"text\":\"Paragraph\",\n" + + " \"type\":\"text\"\n" + + " },\n" + + " {\n" + + " \"marks\":[\n" + + " {\n" + + " \"type\":\"bold\"\n" + + " }\n" + + " ],\n" + + " \"text\":\" yeah\",\n" + + " \"type\":\"text\"\n" + + " }\n" + + " ],\n" + + " \"attrs\":{\n" + + " \"textAlign\":\"left\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " }"; + + + + @BeforeClass + public static void prepare() throws Exception { + //Setting web app environment + IntegrationTestInitService.getInstance().init(); + } + + @Before + public void before () { + + final Host host = Try.of(()->APILocator.getHostAPI().findDefaultHost( + APILocator.systemUser(), false)).getOrNull(); + final String hostname = null == host? host.getHostname():"dotcms.com"; // fake host + final HttpServletRequest requestProxy = new FakeHttpRequest(hostname, null).request(); + final HttpServletResponse responseProxy = new BaseResponse().response(); + + } + + /** + * Method to test: {@link StoryBlockAPI#refreshStoryBlockValueReferences(Object)} + * Given Scenario: This will create a story block contentlet, adds a rich content and retrieve the json. + * Then, will update the rich content previously added, the story block contentlet should reflect the new rich text changed. + * ExpectedResult: The new json will reflect the rich text changes + * + */ + @Test + public void test_refresh_references() throws DotDataException, DotSecurityException, JsonProcessingException { + + //1) create a rich text contentlet with some initial values + final ContentType contentTypeRichText = APILocator.getContentTypeAPI(APILocator.systemUser()).find("webPageContent"); + final Contentlet richTextContentlet = new ContentletDataGen(contentTypeRichText).setProperty("title","Title1").setProperty("body","Body1").nextPersisted(); + + // 2) add the contentlet to the static story block created previously + final Object newStoryBlockJson = APILocator.getStoryBlockAPI().addContentlet(JSON, richTextContentlet); + + // 3) convert the json to map, to start the test + final Map newStoryBlockMap = ContentletJsonHelper.INSTANCE.get().objectMapper() + .readValue(Try.of(() -> newStoryBlockJson.toString()) + .getOrElse(StringPool.BLANK), LinkedHashMap.class); + + Assert.assertNotNull(newStoryBlockMap); + final List contentList = (List) newStoryBlockMap.get("content"); + final Optional firstContentletMap = contentList.stream() + .filter(content -> "dotContent".equals(Map.class.cast(content).get("type"))).findFirst(); + + Assert.assertTrue(firstContentletMap.isPresent()); + final Map contentletMap = (Map) Map.class.cast(Map.class.cast(firstContentletMap.get()).get(StoryBlockAPI.ATTRS_KEY)).get(StoryBlockAPI.DATA_KEY); + Assert.assertEquals(contentletMap.get("identifier"), richTextContentlet.getIdentifier()); + Assert.assertEquals(contentletMap.get("title"), richTextContentlet.getStringProperty("title")); + Assert.assertEquals(contentletMap.get("body"), richTextContentlet.getStringProperty("body")); + + // 4) checkout/publish the contentlet in order to do new changes + final Contentlet newRichTextContentlet = APILocator.getContentletAPI().checkout(richTextContentlet.getInode(), APILocator.systemUser(), false); + newRichTextContentlet.setProperty("title","Title2"); + newRichTextContentlet.setProperty("body","Body2"); + APILocator.getContentletAPI().publish( + APILocator.getContentletAPI().checkin(newRichTextContentlet, APILocator.systemUser(), false), APILocator.systemUser(), false); + + // 5) ask for refreshing references, the new changes of the rich text contentlet should be reflected on the json + final Tuple2 refreshResult = APILocator.getStoryBlockAPI().refreshStoryBlockValueReferences(newStoryBlockJson); + + // 6) check if the results are ok. + Assert.assertTrue(refreshResult._1()); + Assert.assertNotNull(refreshResult._2()); + final Map refreshedStoryBlockMap = ContentletJsonHelper.INSTANCE.get().objectMapper() + .readValue(Try.of(() -> refreshResult._2().toString()) + .getOrElse(StringPool.BLANK), LinkedHashMap.class); + final List refreshedContentList = (List) refreshedStoryBlockMap.get("content"); + final Optional refreshedfirstContentletMap = refreshedContentList.stream() + .filter(content -> "dotContent".equals(Map.class.cast(content).get("type"))).findFirst(); + + Assert.assertTrue(refreshedfirstContentletMap.isPresent()); + final Map refreshedContentletMap = (Map) Map.class.cast(Map.class.cast(refreshedfirstContentletMap.get()).get(StoryBlockAPI.ATTRS_KEY)).get(StoryBlockAPI.DATA_KEY); + Assert.assertEquals(refreshedContentletMap.get("identifier"), newRichTextContentlet.getIdentifier()); + Assert.assertEquals("Title2", newRichTextContentlet.getStringProperty("title")); + Assert.assertEquals("Body2", newRichTextContentlet.getStringProperty("body")); + + + + } + +} diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java index 70dfa0a8b99a..d2ef01c59393 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java @@ -55,4 +55,13 @@ public interface StoryBlockAPI { * @return List of contentlets on the story block referrer */ List getDependencies (final Object storyBlockValue); + + /** + * Adds a contentlet to the story block value + * @param storyBlockValue {@link Object} + * @param contentlet {@link Contentlet} + * @return Object + */ + Object addContentlet(final Object storyBlockValue, final Contentlet contentlet); + } diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java index dfaa6684d680..11a9c99e1651 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java @@ -1,6 +1,7 @@ package com.dotcms.contenttype.business; import com.dotcms.content.business.json.ContentletJsonHelper; +import com.dotcms.contenttype.model.field.Field; import com.dotcms.contenttype.model.field.StoryBlockField; import com.dotcms.util.ConversionUtils; import com.dotmarketing.beans.VersionInfo; @@ -84,7 +85,7 @@ public Tuple2 refreshStoryBlockValueReferences(final Object st } } catch (final Exception e) { - Logger.debug(ContentletTransformer.class, e.getMessage()); + Logger.debug(StoryBlockAPIImpl.class, e.getMessage()); } return Tuple.of(false, storyBlockValue); // return the original value and value didn't change @@ -156,12 +157,72 @@ public List getDependencies (final Object storyBlockValue) { } } catch (final Exception e) { - Logger.debug(ContentletTransformer.class, e.getMessage()); + Logger.debug(StoryBlockAPIImpl.class, e.getMessage()); } return contentletIdentifierList.build(); } + @Override + public Object addContentlet(final Object storyBlockValue, final Contentlet contentlet) { + + try { + + final Map storyBlockValueMap = toMap(storyBlockValue); + this.addContentlet(storyBlockValueMap, contentlet); + return toJson(storyBlockValueMap); + } catch (JsonProcessingException e) { + + Logger.debug(StoryBlockAPIImpl.class, e.getMessage()); + } + + return storyBlockValue; + } + + private Map addContentlet(final Map storyBlockValueMap, final Contentlet contentlet) { + + if (storyBlockValueMap.containsKey(StoryBlockAPI.CONTENT_KEY)) { + + final List contentList = (List)storyBlockValueMap.get(StoryBlockAPI.CONTENT_KEY); + final Map dataMap = new LinkedHashMap(); + final List fields = contentlet.getContentType().fields(); + + dataMap.put("hostName", contentlet.getHost()); + dataMap.put("modDate", contentlet.getModDate()); + dataMap.put("title", contentlet.getTitle()); + dataMap.put("contentTypeIcon", contentlet.getContentType().icon()); + dataMap.put("baseType", contentlet.getContentType().baseType().getAlternateName()); + dataMap.put("inode", contentlet.getInode()); + dataMap.put("archived", Try.of(()->contentlet.isArchived()).getOrElse(false)); + dataMap.put("working", Try.of(()->contentlet.isWorking()).getOrElse(false)); + dataMap.put("locked", Try.of(()->contentlet.isLocked()).getOrElse(false)); + dataMap.put("stInode", contentlet.getContentType().inode()); + dataMap.put("contentType", contentlet.getContentType().variable()); + dataMap.put("live", Try.of(()->contentlet.isLive()).getOrElse(false)); + dataMap.put("owner", contentlet.getOwner()); + dataMap.put("identifier", contentlet.getIdentifier()); + dataMap.put("languageId", contentlet.getLanguageId()); + dataMap.put("hasLiveVersion", Try.of(()->contentlet.hasLiveVersion()).getOrElse(false)); + dataMap.put("folder", contentlet.getFolder()); + dataMap.put("sortOrder", contentlet.getSortOrder()); + dataMap.put("modUser", contentlet.getModUser()); + + for (final Field field : fields) { + + dataMap.put(field.variable(), contentlet.get(field.variable())); + } + + final Map attrsMap = new LinkedHashMap(); + attrsMap.put(StoryBlockAPI.DATA_KEY, dataMap); + final Map contentMap = new LinkedHashMap(); + contentMap.put(StoryBlockAPI.ATTRS_KEY, attrsMap); + contentMap.put(StoryBlockAPI.TYPE_KEY, "dotContent"); + contentList.add(contentMap); + } + + return storyBlockValueMap; + } + private static void addDependencies(final ImmutableList.Builder contentletIdentifierList, final Map contentMap) { From 20e3c740a0922154483c81136a502bdb1ce006bf Mon Sep 17 00:00:00 2001 From: jdotcms Date: Wed, 31 Aug 2022 16:07:53 -0500 Subject: [PATCH 12/22] #22857 unit test for getDependencies --- .../business/StoryBlockAPITest.java | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java index abe210c2318f..3dc1c6471774 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java @@ -2,34 +2,20 @@ import com.dotcms.IntegrationTestBase; import com.dotcms.content.business.json.ContentletJsonHelper; -import com.dotcms.contenttype.model.type.BaseContentType; import com.dotcms.contenttype.model.type.ContentType; -import com.dotcms.contenttype.model.type.ContentTypeBuilder; -import com.dotcms.contenttype.model.type.FileAssetContentType; import com.dotcms.datagen.ContentletDataGen; import com.dotcms.mock.request.FakeHttpRequest; import com.dotcms.mock.response.BaseResponse; -import com.dotcms.rendering.velocity.viewtools.content.StoryBlockMap; -import com.dotcms.repackage.org.apache.commons.io.FileUtils; import com.dotcms.util.IntegrationTestInitService; import com.dotmarketing.beans.Host; import com.dotmarketing.business.APILocator; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.contentlet.model.Contentlet; -import com.dotmarketing.portlets.contentlet.model.ContentletDependencies; -import com.dotmarketing.portlets.contentlet.model.IndexPolicy; -import com.dotmarketing.portlets.folders.business.FolderAPI; -import com.dotmarketing.portlets.folders.model.Folder; -import com.dotmarketing.util.Config; -import com.dotmarketing.util.VelocityUtil; -import com.dotmarketing.util.json.JSONException; import com.fasterxml.jackson.core.JsonProcessingException; -import com.liferay.portal.model.User; import com.liferay.util.StringPool; import io.vavr.Tuple2; import io.vavr.control.Try; -import org.apache.velocity.context.Context; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; @@ -37,18 +23,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import static junit.framework.TestCase.assertEquals; - +/** + * Test for {@link StoryBlockAPI} + * @author jsanca + */ public class StoryBlockAPITest extends IntegrationTestBase { private static final String JSON = @@ -181,9 +164,39 @@ public void test_refresh_references() throws DotDataException, DotSecurityExcept Assert.assertEquals(refreshedContentletMap.get("identifier"), newRichTextContentlet.getIdentifier()); Assert.assertEquals("Title2", newRichTextContentlet.getStringProperty("title")); Assert.assertEquals("Body2", newRichTextContentlet.getStringProperty("body")); + } + + /** + * Method to test: {@link StoryBlockAPI#getDependencies(Object)} + * Given Scenario: Creates a story block and adds 3 contentlets + * ExpectedResult: The contentlets added should be retrieved + * + */ + @Test + public void test_get_dependencies() throws DotDataException, DotSecurityException, JsonProcessingException { + //1) create a rich text contentlets with some initial values + final ContentType contentTypeRichText = APILocator.getContentTypeAPI(APILocator.systemUser()).find("webPageContent"); + final Contentlet richTextContentlet1 = new ContentletDataGen(contentTypeRichText).setProperty("title","Title1").setProperty("body","Body1").nextPersisted(); + final Contentlet richTextContentlet2 = new ContentletDataGen(contentTypeRichText).setProperty("title","Title1").setProperty("body","Body1").nextPersisted(); + final Contentlet richTextContentlet3 = new ContentletDataGen(contentTypeRichText).setProperty("title","Title1").setProperty("body","Body1").nextPersisted(); + // 2) adds the contentlets to the static story block created previously + final Object newStoryBlockJson1 = APILocator.getStoryBlockAPI().addContentlet(JSON, richTextContentlet1); + final Object newStoryBlockJson2 = APILocator.getStoryBlockAPI().addContentlet(newStoryBlockJson1, richTextContentlet2); + final Object newStoryBlockJson3 = APILocator.getStoryBlockAPI().addContentlet(newStoryBlockJson2, richTextContentlet3); - } + // 3) convert the json to map, to start the test + final Map newStoryBlockMap = ContentletJsonHelper.INSTANCE.get().objectMapper() + .readValue(Try.of(() -> newStoryBlockJson3.toString()) + .getOrElse(StringPool.BLANK), LinkedHashMap.class); + Assert.assertNotNull(newStoryBlockMap); + final List contentletIdList = APILocator.getStoryBlockAPI().getDependencies(newStoryBlockJson3); + Assert.assertNotNull(contentletIdList); + Assert.assertEquals(3, contentletIdList.size()); + Assert.assertTrue(contentletIdList.contains(richTextContentlet1.getIdentifier())); + Assert.assertTrue(contentletIdList.contains(richTextContentlet2.getIdentifier())); + Assert.assertTrue(contentletIdList.contains(richTextContentlet3.getIdentifier())); + } } From ca9d72639bf47514da8f7eda763b4271c097fc5f Mon Sep 17 00:00:00 2001 From: jdotcms Date: Wed, 31 Aug 2022 16:10:14 -0500 Subject: [PATCH 13/22] #22857 unit test for getDependencies --- .../contenttype/business/StoryBlockAPITest.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java index 3dc1c6471774..025cca3d4af4 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java @@ -4,10 +4,7 @@ import com.dotcms.content.business.json.ContentletJsonHelper; import com.dotcms.contenttype.model.type.ContentType; import com.dotcms.datagen.ContentletDataGen; -import com.dotcms.mock.request.FakeHttpRequest; -import com.dotcms.mock.response.BaseResponse; import com.dotcms.util.IntegrationTestInitService; -import com.dotmarketing.beans.Host; import com.dotmarketing.business.APILocator; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; @@ -17,12 +14,9 @@ import io.vavr.Tuple2; import io.vavr.control.Try; import org.junit.Assert; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -95,17 +89,6 @@ public static void prepare() throws Exception { IntegrationTestInitService.getInstance().init(); } - @Before - public void before () { - - final Host host = Try.of(()->APILocator.getHostAPI().findDefaultHost( - APILocator.systemUser(), false)).getOrNull(); - final String hostname = null == host? host.getHostname():"dotcms.com"; // fake host - final HttpServletRequest requestProxy = new FakeHttpRequest(hostname, null).request(); - final HttpServletResponse responseProxy = new BaseResponse().response(); - - } - /** * Method to test: {@link StoryBlockAPI#refreshStoryBlockValueReferences(Object)} * Given Scenario: This will create a story block contentlet, adds a rich content and retrieve the json. From 99d45dee246e27ede85b62f33d8324d1e7dcfa63 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 2 Sep 2022 11:50:26 -0500 Subject: [PATCH 14/22] #22857 adding feedback --- .../business/StoryBlockAPITest.java | 9 ++++--- .../business/ESContentFactoryImpl.java | 10 +++++--- .../contenttype/business/StoryBlockAPI.java | 5 ++-- .../business/StoryBlockAPIImpl.java | 16 ++++++------ .../business/StoryBlockReferenceResult.java | 25 +++++++++++++++++++ 5 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockReferenceResult.java diff --git a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java index 025cca3d4af4..532a71e59c6b 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java @@ -29,6 +29,7 @@ public class StoryBlockAPITest extends IntegrationTestBase { private static final String JSON = + "{\n" + " \"type\":\"doc\",\n" + " \"content\":[\n" + @@ -130,13 +131,13 @@ public void test_refresh_references() throws DotDataException, DotSecurityExcept APILocator.getContentletAPI().checkin(newRichTextContentlet, APILocator.systemUser(), false), APILocator.systemUser(), false); // 5) ask for refreshing references, the new changes of the rich text contentlet should be reflected on the json - final Tuple2 refreshResult = APILocator.getStoryBlockAPI().refreshStoryBlockValueReferences(newStoryBlockJson); + final StoryBlockReferenceResult refreshResult = APILocator.getStoryBlockAPI().refreshStoryBlockValueReferences(newStoryBlockJson); // 6) check if the results are ok. - Assert.assertTrue(refreshResult._1()); - Assert.assertNotNull(refreshResult._2()); + Assert.assertTrue(refreshResult.isRefreshed()); + Assert.assertNotNull(refreshResult.getValue()); final Map refreshedStoryBlockMap = ContentletJsonHelper.INSTANCE.get().objectMapper() - .readValue(Try.of(() -> refreshResult._2().toString()) + .readValue(Try.of(() -> refreshResult.getValue().toString()) .getOrElse(StringPool.BLANK), LinkedHashMap.class); final List refreshedContentList = (List) refreshedStoryBlockMap.get("content"); final Optional refreshedfirstContentletMap = refreshedContentList.stream() diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java index 1158443da552..0dd0e5d7c2f5 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java @@ -16,6 +16,7 @@ import com.dotcms.content.business.json.ContentletJsonHelper; import com.dotcms.content.elasticsearch.ESQueryCache; import com.dotcms.content.elasticsearch.util.RestHighLevelClientProvider; +import com.dotcms.contenttype.business.StoryBlockReferenceResult; import com.dotcms.contenttype.model.field.DataTypes; import com.dotcms.contenttype.model.type.BaseContentType; import com.dotcms.contenttype.model.type.ContentType; @@ -879,13 +880,14 @@ protected Contentlet find(final String inode) throws ElasticsearchException, Dot */ private Contentlet processContentletCache (final Contentlet contentletCached) { - final Tuple2 storyBlockRefreshedResult = + final StoryBlockReferenceResult storyBlockRefreshedResult = APILocator.getStoryBlockAPI().refreshReferences(contentletCached); - if (storyBlockRefreshedResult._1()) { + if (storyBlockRefreshedResult.isRefreshed()) { - contentletCache.add(storyBlockRefreshedResult._2().getInode(), storyBlockRefreshedResult._2()); - return storyBlockRefreshedResult._2(); + final Contentlet refreshedContentlet = (Contentlet) storyBlockRefreshedResult.getValue(); + contentletCache.add(refreshedContentlet.getInode(), refreshedContentlet); + return refreshedContentlet; } return contentletCached; diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java index d2ef01c59393..05cd3e5ba221 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPI.java @@ -2,7 +2,6 @@ import com.dotmarketing.portlets.contentlet.model.Contentlet; import com.google.common.collect.ImmutableSet; -import io.vavr.Tuple2; import java.util.List; import java.util.Set; @@ -32,14 +31,14 @@ public interface StoryBlockAPI { * @param contentlet {@link Contentlet} to refresh * @return Contentlet content refreshed */ - Tuple2 refreshReferences(final Contentlet contentlet); + StoryBlockReferenceResult refreshReferences(final Contentlet contentlet); /** * Refresh the story block references for a story block json (The argument storyBlockValue will be converted to string and parse as json) * @param storyBlockValue Object * @return Tuple2 boolean if there was something to refresh, the object is the new object refreshed; if not anything to refresh return the same object sent as an argument */ - Tuple2 refreshStoryBlockValueReferences(final Object storyBlockValue); + StoryBlockReferenceResult refreshStoryBlockValueReferences(final Object storyBlockValue); /** * For each {@link com.dotcms.contenttype.model.field.StoryBlockField} field, retrieve contentlet ids referrer on the diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java index 11a9c99e1651..032cedf738d0 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java @@ -34,7 +34,7 @@ public class StoryBlockAPIImpl implements StoryBlockAPI { @Override - public Tuple2 refreshReferences(final Contentlet contentlet) { + public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet) { final MutableBoolean refreshed = new MutableBoolean(false); if (null != contentlet) { @@ -44,20 +44,20 @@ public Tuple2 refreshReferences(final Contentlet contentlet final Object storyBlockValue = contentlet.get(field.variable()); if (null != storyBlockValue) { - final Tuple2 result = this.refreshStoryBlockValueReferences(storyBlockValue); - if (result._1()) { // the story block value has been changed and has been overridden + final StoryBlockReferenceResult result = this.refreshStoryBlockValueReferences(storyBlockValue); + if (result.isRefreshed()) { // the story block value has been changed and has been overridden refreshed.setTrue(); - contentlet.setProperty(field.variable(), result._2()); + contentlet.setProperty(field.variable(), result.getValue()); } } }); } - return Tuple.of(refreshed.booleanValue(), contentlet); + return new StoryBlockReferenceResult(refreshed.booleanValue(), contentlet); } @Override - public Tuple2 refreshStoryBlockValueReferences(final Object storyBlockValue) { + public StoryBlockReferenceResult refreshStoryBlockValueReferences(final Object storyBlockValue) { boolean refreshed = false; try { @@ -81,14 +81,14 @@ public Tuple2 refreshStoryBlockValueReferences(final Object st if (refreshed) { - return Tuple.of(true, toJson(blockEditorMap)); // has changed and the now json is returned + return new StoryBlockReferenceResult(true, toJson(blockEditorMap)); // has changed and the now json is returned } } catch (final Exception e) { Logger.debug(StoryBlockAPIImpl.class, e.getMessage()); } - return Tuple.of(false, storyBlockValue); // return the original value and value didn't change + return new StoryBlockReferenceResult(false, storyBlockValue); // return the original value and value didn't change } private boolean refreshStoryBlockMap(final Map contentMap) throws DotDataException, DotSecurityException { diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockReferenceResult.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockReferenceResult.java new file mode 100644 index 000000000000..bd79a139f854 --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockReferenceResult.java @@ -0,0 +1,25 @@ +package com.dotcms.contenttype.business; + +/** + * Result of the refresh references + * - refreshed is true if there were something to refresh + * - value would be the original value (if not refresh) or the value with the refreshed contentlets if something has change + */ +public class StoryBlockReferenceResult { + + private final boolean refreshed; + private final Object value; + + public StoryBlockReferenceResult(final boolean refreshed, final Object value) { + this.refreshed = refreshed; + this.value = value; + } + + public boolean isRefreshed() { + return refreshed; + } + + public Object getValue() { + return value; + } +} From 76ea62414007d734808a965c28e1e353752aa762 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 2 Sep 2022 11:59:05 -0500 Subject: [PATCH 15/22] #22857 adding more feedback --- .../contenttype/business/StoryBlockAPITest.java | 2 +- .../resources/it-dotcms-config-cluster.properties | 5 +++-- .../resources/it-dotmarketing-config.properties | 12 ++++++------ .../resources/postgres-db-config.properties | 8 ++++---- .../contenttype/business/StoryBlockAPIImpl.java | 11 +++++++++-- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java index 532a71e59c6b..4b609be9f5b8 100644 --- a/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java +++ b/dotCMS/src/integration-test/java/com/dotcms/contenttype/business/StoryBlockAPITest.java @@ -29,7 +29,7 @@ public class StoryBlockAPITest extends IntegrationTestBase { private static final String JSON = - + "{\n" + " \"type\":\"doc\",\n" + " \"content\":[\n" + diff --git a/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties b/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties index 40605ac808a8..1f0f188e3f3e 100755 --- a/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties +++ b/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties @@ -101,11 +101,12 @@ ES_AUTH_TLS_CLIENT_CERT=certs/elasticsearch.pem ES_AUTH_TLS_CLIENT_KEY=certs/elasticsearch.key ES_AUTH_TLS_CA_CERT=certs/root-ca.pem -ES_HOSTNAME=elasticsearch +ES_HOSTNAME=localhost +ES_ENDPOINTS=http://localhost:9200 #Set token in case ES_AUTH_TYPE=JWT #ES_AUTH_JWT_TOKEN=eyJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6ImFkbWluIiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3QiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTU2MjExODY1OTA0Mn0.f-t30zgA53Am3w7ueWNFpnhz_5SWiJjKaOT-rNeEp_M ## These lines should be last to allow plugins to override values - touche pas! ## BEGIN PLUGINS -## END PLUGINS \ No newline at end of file +## END PLUGINS diff --git a/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties b/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties index dcfea6199738..6cdf9cc8e21a 100644 --- a/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties +++ b/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties @@ -61,12 +61,12 @@ ASSET_PATH = /assets ## shared folder in unix/linux enviroments we encourage you to use symbolic links ## If this variable is commented the system will work as usual using ## the ASSET_PATH variable as the assets directory inside liferay web root -ASSET_REAL_PATH = /tomcat8/webapps/ROOT/assets +ASSET_REAL_PATH = /Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/assets ## This variable should be used if the dynamic content is to be placed outside of the web application. By the default, the location ## is in dotCMS/dotsecure. If running as war inside an application server, it is important to move this data to a location ## outside of the web application, to prevent data such as the cache and the index from being deleted if the war is redeployed. -DYNAMIC_CONTENT_PATH=/tomcat8/webapps/ROOT/dotsecure +DYNAMIC_CONTENT_PATH=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/dotsecure ## REDIRECT_TO_LOGIN = /dotCMS/login <---- add a redirect to the /portal/401.jsp instead. EMAIL_BACKUPS = /email_backups @@ -809,7 +809,7 @@ CMS_INDEX_PAGE = index mysql_storage_engine_varname=default_storage_engine ## GeoIP2 DB Path Override (absolute path) (defaults to : -GEOIP2_CITY_DATABASE_PATH_OVERRIDE=/tomcat8/webapps/ROOT/WEB-INF/geoip2/GeoLite2-City.mmdb +GEOIP2_CITY_DATABASE_PATH_OVERRIDE=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/WEB-INF/geoip2/GeoLite2-City.mmdb ## Rules engine maximun execution time in ms this property allow to find any rules that ## are running slower than expected, so we can manage the performance of the dotCMS server. @@ -821,10 +821,10 @@ api.system.ruleengine.actionlet.VisitorTagsActionlet.MAX_TAGS=20 #GOOGLE_TRANSLATE_SERVICE_API_KEY=put-your-key-here ## Path to the toolbox.xml file -#TOOLBOX_MANAGER_PATH=/webapps/ROOT/WEB-INF/toolbox.xml +TOOLBOX_MANAGER_PATH=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/WEB-INF/toolbox.xml ## Path to felix folder -felix.base.dir=/tomcat8/webapps/ROOT/WEB-INF/felix +felix.base.dir=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/WEB-INF/felix GDPR_CONSENT_DEFAULT_PROPERTY=true WHITELISTED_HEADERS=User-Agent,Host,Accept-Language,Referer, @@ -843,4 +843,4 @@ api.cors.default.Access-Control-Expose-Headers=* api.cors.graphql.Access-Control-Expose-Headers=Content-Type,Cache-Control APPS_IMPORT_EXPORT_DEFAULT_PASSWORD=WJM9wwu5YjBLAgjUmXgfxhLLCMSJpLyM -dotcms.dev.mode=true \ No newline at end of file +dotcms.dev.mode=true diff --git a/dotCMS/src/integration-test/resources/postgres-db-config.properties b/dotCMS/src/integration-test/resources/postgres-db-config.properties index 901a4221ff5f..b8ed1e21c829 100644 --- a/dotCMS/src/integration-test/resources/postgres-db-config.properties +++ b/dotCMS/src/integration-test/resources/postgres-db-config.properties @@ -1,8 +1,8 @@ #Postgres Connection driverClassName=org.postgresql.Driver -jdbcUrl=jdbc:postgresql://database/dotcms?autosave=conservative -username=postgres -password=postgres +jdbcUrl=jdbc:postgresql://localhost/dotcms?autosave=conservative +username=dotcms +password=dotcms ## Initial wait for a new connection in milliseconds connectionTimeout=3000 ## Pool Min and Max connections @@ -13,4 +13,4 @@ idleTimeout=300000 ## Max lifetime of any connection maxLifetime=120000 ## Log potential leaks after milliseconds -leakDetectionThreshold=60000 \ No newline at end of file +leakDetectionThreshold=60000 diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java index 032cedf738d0..f05396906c73 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java @@ -1,5 +1,6 @@ package com.dotcms.contenttype.business; +import com.dotcms.business.CloseDBIfOpened; import com.dotcms.content.business.json.ContentletJsonHelper; import com.dotcms.contenttype.model.field.Field; import com.dotcms.contenttype.model.field.StoryBlockField; @@ -33,6 +34,7 @@ */ public class StoryBlockAPIImpl implements StoryBlockAPI { + @CloseDBIfOpened @Override public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet) { @@ -56,6 +58,8 @@ public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet) return new StoryBlockReferenceResult(refreshed.booleanValue(), contentlet); } + + @CloseDBIfOpened @Override public StoryBlockReferenceResult refreshStoryBlockValueReferences(final Object storyBlockValue) { @@ -86,6 +90,7 @@ public StoryBlockReferenceResult refreshStoryBlockValueReferences(final Object } catch (final Exception e) { Logger.debug(StoryBlockAPIImpl.class, e.getMessage()); + throw new RuntimeException(e); } return new StoryBlockReferenceResult(false, storyBlockValue); // return the original value and value didn't change @@ -120,6 +125,7 @@ private boolean refreshStoryBlockMap(final Map contentMap) throws DotDataExcepti return refreshed; } + @CloseDBIfOpened @Override public List getDependencies(final Contentlet contentlet) { @@ -133,6 +139,7 @@ public List getDependencies(final Contentlet contentlet) { return contentletIdentifierList.build(); } + @CloseDBIfOpened @Override public List getDependencies (final Object storyBlockValue) { @@ -158,6 +165,7 @@ public List getDependencies (final Object storyBlockValue) { } catch (final Exception e) { Logger.debug(StoryBlockAPIImpl.class, e.getMessage()); + throw new RuntimeException(e); } return contentletIdentifierList.build(); @@ -174,9 +182,8 @@ public Object addContentlet(final Object storyBlockValue, final Contentlet conte } catch (JsonProcessingException e) { Logger.debug(StoryBlockAPIImpl.class, e.getMessage()); + throw new RuntimeException(e); } - - return storyBlockValue; } private Map addContentlet(final Map storyBlockValueMap, final Contentlet contentlet) { From 2adf9bbaf346dbad557ddc6be0fc0287add399b4 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 2 Sep 2022 12:01:09 -0500 Subject: [PATCH 16/22] #22857 adding more feedback --- dotCMS/src/main/java/com/dotcms/storage/model/Metadata.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotCMS/src/main/java/com/dotcms/storage/model/Metadata.java b/dotCMS/src/main/java/com/dotcms/storage/model/Metadata.java index ef076cab71ae..9588834cc8fe 100644 --- a/dotCMS/src/main/java/com/dotcms/storage/model/Metadata.java +++ b/dotCMS/src/main/java/com/dotcms/storage/model/Metadata.java @@ -24,7 +24,7 @@ import java.util.Objects; import java.util.stream.Collectors; - public class Metadata implements Serializable { +public class Metadata implements Serializable { public static final String CUSTOM_PROP_PREFIX = "dot:"; From 24cd314c61b0f4f91e17db6d68586e6c98b53d56 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 2 Sep 2022 12:05:02 -0500 Subject: [PATCH 17/22] #22857 rolling back some config --- .../resources/it-dotcms-config-cluster.properties | 5 ++--- .../resources/it-dotmarketing-config.properties | 12 ++++++------ .../resources/postgres-db-config.properties | 8 ++++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties b/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties index 1f0f188e3f3e..40605ac808a8 100755 --- a/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties +++ b/dotCMS/src/integration-test/resources/it-dotcms-config-cluster.properties @@ -101,12 +101,11 @@ ES_AUTH_TLS_CLIENT_CERT=certs/elasticsearch.pem ES_AUTH_TLS_CLIENT_KEY=certs/elasticsearch.key ES_AUTH_TLS_CA_CERT=certs/root-ca.pem -ES_HOSTNAME=localhost -ES_ENDPOINTS=http://localhost:9200 +ES_HOSTNAME=elasticsearch #Set token in case ES_AUTH_TYPE=JWT #ES_AUTH_JWT_TOKEN=eyJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6ImFkbWluIiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3QiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTU2MjExODY1OTA0Mn0.f-t30zgA53Am3w7ueWNFpnhz_5SWiJjKaOT-rNeEp_M ## These lines should be last to allow plugins to override values - touche pas! ## BEGIN PLUGINS -## END PLUGINS +## END PLUGINS \ No newline at end of file diff --git a/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties b/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties index 6cdf9cc8e21a..dcfea6199738 100644 --- a/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties +++ b/dotCMS/src/integration-test/resources/it-dotmarketing-config.properties @@ -61,12 +61,12 @@ ASSET_PATH = /assets ## shared folder in unix/linux enviroments we encourage you to use symbolic links ## If this variable is commented the system will work as usual using ## the ASSET_PATH variable as the assets directory inside liferay web root -ASSET_REAL_PATH = /Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/assets +ASSET_REAL_PATH = /tomcat8/webapps/ROOT/assets ## This variable should be used if the dynamic content is to be placed outside of the web application. By the default, the location ## is in dotCMS/dotsecure. If running as war inside an application server, it is important to move this data to a location ## outside of the web application, to prevent data such as the cache and the index from being deleted if the war is redeployed. -DYNAMIC_CONTENT_PATH=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/dotsecure +DYNAMIC_CONTENT_PATH=/tomcat8/webapps/ROOT/dotsecure ## REDIRECT_TO_LOGIN = /dotCMS/login <---- add a redirect to the /portal/401.jsp instead. EMAIL_BACKUPS = /email_backups @@ -809,7 +809,7 @@ CMS_INDEX_PAGE = index mysql_storage_engine_varname=default_storage_engine ## GeoIP2 DB Path Override (absolute path) (defaults to : -GEOIP2_CITY_DATABASE_PATH_OVERRIDE=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/WEB-INF/geoip2/GeoLite2-City.mmdb +GEOIP2_CITY_DATABASE_PATH_OVERRIDE=/tomcat8/webapps/ROOT/WEB-INF/geoip2/GeoLite2-City.mmdb ## Rules engine maximun execution time in ms this property allow to find any rules that ## are running slower than expected, so we can manage the performance of the dotCMS server. @@ -821,10 +821,10 @@ api.system.ruleengine.actionlet.VisitorTagsActionlet.MAX_TAGS=20 #GOOGLE_TRANSLATE_SERVICE_API_KEY=put-your-key-here ## Path to the toolbox.xml file -TOOLBOX_MANAGER_PATH=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/WEB-INF/toolbox.xml +#TOOLBOX_MANAGER_PATH=/webapps/ROOT/WEB-INF/toolbox.xml ## Path to felix folder -felix.base.dir=/Users/jsanca/gitsources/new-core2/tomcat9/webapps/ROOT/WEB-INF/felix +felix.base.dir=/tomcat8/webapps/ROOT/WEB-INF/felix GDPR_CONSENT_DEFAULT_PROPERTY=true WHITELISTED_HEADERS=User-Agent,Host,Accept-Language,Referer, @@ -843,4 +843,4 @@ api.cors.default.Access-Control-Expose-Headers=* api.cors.graphql.Access-Control-Expose-Headers=Content-Type,Cache-Control APPS_IMPORT_EXPORT_DEFAULT_PASSWORD=WJM9wwu5YjBLAgjUmXgfxhLLCMSJpLyM -dotcms.dev.mode=true +dotcms.dev.mode=true \ No newline at end of file diff --git a/dotCMS/src/integration-test/resources/postgres-db-config.properties b/dotCMS/src/integration-test/resources/postgres-db-config.properties index b8ed1e21c829..901a4221ff5f 100644 --- a/dotCMS/src/integration-test/resources/postgres-db-config.properties +++ b/dotCMS/src/integration-test/resources/postgres-db-config.properties @@ -1,8 +1,8 @@ #Postgres Connection driverClassName=org.postgresql.Driver -jdbcUrl=jdbc:postgresql://localhost/dotcms?autosave=conservative -username=dotcms -password=dotcms +jdbcUrl=jdbc:postgresql://database/dotcms?autosave=conservative +username=postgres +password=postgres ## Initial wait for a new connection in milliseconds connectionTimeout=3000 ## Pool Min and Max connections @@ -13,4 +13,4 @@ idleTimeout=300000 ## Max lifetime of any connection maxLifetime=120000 ## Log potential leaks after milliseconds -leakDetectionThreshold=60000 +leakDetectionThreshold=60000 \ No newline at end of file From 47b330359de9987fe63bd31898c782c175dcf913 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 2 Sep 2022 12:07:56 -0500 Subject: [PATCH 18/22] #22857 rolling back some config --- .../content/elasticsearch/business/ESContentFactoryImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java index 0dd0e5d7c2f5..26a076c9324e 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java @@ -885,6 +885,7 @@ private Contentlet processContentletCache (final Contentlet contentletCached) { if (storyBlockRefreshedResult.isRefreshed()) { + Logger.debug(this, ()-> "Refreshed story block dependencies for the contentlet: " + contentletCached.getIdentifier()); final Contentlet refreshedContentlet = (Contentlet) storyBlockRefreshedResult.getValue(); contentletCache.add(refreshedContentlet.getInode(), refreshedContentlet); return refreshedContentlet; From 22a08d326f34a2a1b9d7c59de12de1d19e9a8929 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 2 Sep 2022 12:09:53 -0500 Subject: [PATCH 19/22] #22857 adding some logging --- .../contentlet/transform/ContentletTransformer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java index 1e788b1c9d57..f52530d6bfdc 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/transform/ContentletTransformer.java @@ -1,6 +1,7 @@ package com.dotmarketing.portlets.contentlet.transform; import com.dotcms.content.business.json.ContentletJsonAPI; +import com.dotcms.contenttype.business.StoryBlockReferenceResult; import com.dotcms.contenttype.model.field.LegacyFieldTypes; import com.dotcms.contenttype.model.type.ContentType; import com.dotcms.contenttype.model.type.FileAssetContentType; @@ -128,7 +129,11 @@ private static Contentlet transform(final Map map) { private static void refreshStoryBlockReferences(final Contentlet contentlet) { - APILocator.getStoryBlockAPI().refreshReferences(contentlet); + final StoryBlockReferenceResult result = APILocator.getStoryBlockAPI().refreshReferences(contentlet); + if (result.isRefreshed()) { + Logger.debug(ContentletTransformer.class, + ()-> "Refreshed story block dependencies for the contentlet: " + contentlet.getIdentifier()); + } } From 27cf06a4d6ae49fad841a121a236449c70287039 Mon Sep 17 00:00:00 2001 From: Freddy Montes Date: Fri, 9 Sep 2022 13:39:56 -0600 Subject: [PATCH 20/22] Rename var --- .../webapp/html/portlet/ext/contentlet/field/edit_field.jsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotCMS/src/main/webapp/html/portlet/ext/contentlet/field/edit_field.jsp b/dotCMS/src/main/webapp/html/portlet/ext/contentlet/field/edit_field.jsp index a6f215c7e9fb..a84e8de02d9e 100644 --- a/dotCMS/src/main/webapp/html/portlet/ext/contentlet/field/edit_field.jsp +++ b/dotCMS/src/main/webapp/html/portlet/ext/contentlet/field/edit_field.jsp @@ -200,7 +200,7 @@ * If that's the case we set "JSONValue" as null. * Otherwise, we set "JSONValue" equals to "JSONValue". */ - const JSONValue = JSON.stringify(<%=JSONValue%>) !== JSON.stringify({}) ? <%=JSONValue%> : null; + const blockValue = JSON.stringify(<%=JSONValue%>) !== JSON.stringify({}) ? <%=JSONValue%> : null; let content; /** @@ -210,7 +210,7 @@ try { // If JSONValue is an valid Object, we use it as the Block Editor Content. // Otherwise, we try to parse the "textValue". - content = JSONValue || JSON.parse(<%=textValue%>); + content = blockValue || JSON.parse(<%=textValue%>); } catch (error) { content = <%=textValue%>; } From d5435b6af8af454f5f90c5b007303a18fcd7266f Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 9 Sep 2022 16:52:17 -0500 Subject: [PATCH 21/22] #22857 adding a fix for searching by query when need to refresh the block editor dependencies --- .../content/elasticsearch/business/ESContentFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java index 26a076c9324e..c6c998b685dd 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java @@ -1108,7 +1108,7 @@ protected List findContentlets(final List inodes) throws Dot for (String i : inodes) { final Contentlet contentlet = contentletCache.get(i); if (contentlet != null && InodeUtils.isSet(contentlet.getInode())) { - conMap.put(contentlet.getInode(), contentlet); + conMap.put(contentlet.getInode(), processContentletCache(contentlet)); } } From 6e711665a29cf69f53548135694459037100d373 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Thu, 15 Sep 2022 22:23:41 -0500 Subject: [PATCH 22/22] #22857 adding some flag to control when refresh or not --- .../business/ESContentFactoryImpl.java | 18 +++++++++++------- .../business/StoryBlockAPIImpl.java | 4 +++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java index c6c998b685dd..e75f1b778e30 100644 --- a/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java @@ -147,6 +147,7 @@ */ public class ESContentFactoryImpl extends ContentletFactory { + private static final boolean REFRESH_BLOCK_EDITOR_REFERENCES = Config.getBooleanProperty("REFRESH_BLOCK_EDITOR_REFERENCES", true); private static final String[] ES_FIELDS = {"inode", "identifier"}; public static final int ES_TRACK_TOTAL_HITS_DEFAULT = 10000000; public static final String ES_TRACK_TOTAL_HITS = "ES_TRACK_TOTAL_HITS"; @@ -880,15 +881,18 @@ protected Contentlet find(final String inode) throws ElasticsearchException, Dot */ private Contentlet processContentletCache (final Contentlet contentletCached) { - final StoryBlockReferenceResult storyBlockRefreshedResult = - APILocator.getStoryBlockAPI().refreshReferences(contentletCached); + if (REFRESH_BLOCK_EDITOR_REFERENCES) { - if (storyBlockRefreshedResult.isRefreshed()) { + final StoryBlockReferenceResult storyBlockRefreshedResult = + APILocator.getStoryBlockAPI().refreshReferences(contentletCached); - Logger.debug(this, ()-> "Refreshed story block dependencies for the contentlet: " + contentletCached.getIdentifier()); - final Contentlet refreshedContentlet = (Contentlet) storyBlockRefreshedResult.getValue(); - contentletCache.add(refreshedContentlet.getInode(), refreshedContentlet); - return refreshedContentlet; + if (storyBlockRefreshedResult.isRefreshed()) { + + Logger.debug(this, () -> "Refreshed story block dependencies for the contentlet: " + contentletCached.getIdentifier()); + final Contentlet refreshedContentlet = (Contentlet) storyBlockRefreshedResult.getValue(); + contentletCache.add(refreshedContentlet.getInode(), refreshedContentlet); + return refreshedContentlet; + } } return contentletCached; diff --git a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java index f05396906c73..e4098a8e3eb3 100644 --- a/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/contenttype/business/StoryBlockAPIImpl.java @@ -41,7 +41,9 @@ public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet) final MutableBoolean refreshed = new MutableBoolean(false); if (null != contentlet) { - contentlet.getContentType().fields(StoryBlockField.class).forEach(field -> { + // todo: may be we can store a flag such as has story block to avoid the hit to the fields when there is not any block editor + contentlet.getContentType().fields(StoryBlockField.class) // todo, this method filters but creates a new list in memory + .forEach(field -> { final Object storyBlockValue = contentlet.get(field.variable()); if (null != storyBlockValue) {