Skip to content

Commit

Permalink
fix: Issue 28943 storyblock bug (#29008)
Browse files Browse the repository at this point in the history
Previously this fix, when a wyswyg editor contains already information
on the db and makes the migration from wyswyg to block editor.
  • Loading branch information
jdotcms authored Jun 26, 2024
1 parent 09cba8b commit 3b89971
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet)
.forEach(field -> {

final Object storyBlockValue = contentlet.get(field.variable());
if (null != storyBlockValue && JsonUtil.isValidJSON(storyBlockValue.toString())) {
if (null != storyBlockValue) {
final StoryBlockReferenceResult result =
this.refreshStoryBlockValueReferences(storyBlockValue, contentlet.getIdentifier());
if (result.isRefreshed()) {
Expand All @@ -85,40 +85,50 @@ public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet)
@SuppressWarnings("unchecked")
public StoryBlockReferenceResult refreshStoryBlockValueReferences(final Object storyBlockValue, final String parentContentletIdentifier) {
boolean refreshed = false;
if (ThreadUtils.isMethodCallCountEqualThan(this.getClass().getName(),
"refreshStoryBlockValueReferences", MAX_RECURSION_LEVEL)) {
Logger.debug(this, () -> "This method has been called more than " + MAX_RECURSION_LEVEL +
" times in the same thread. This could be a sign of circular reference in the Story Block field. Data will NOT be refreshed.");
return new StoryBlockReferenceResult(false, storyBlockValue);
}
try {
final LinkedHashMap<String, Object> blockEditorMap = this.toMap(storyBlockValue);
final Object contentsMap = blockEditorMap.get(CONTENT_KEY);
if(!UtilMethods.isSet(contentsMap) || !(contentsMap instanceof List)) {
return new StoryBlockReferenceResult(true, storyBlockValue);
if (null != storyBlockValue && JsonUtil.isValidJSON(storyBlockValue.toString())) {
if (ThreadUtils.isMethodCallCountEqualThan(this.getClass().getName(),
"refreshStoryBlockValueReferences", MAX_RECURSION_LEVEL)) {
Logger.debug(this, () -> "This method has been called more than " + MAX_RECURSION_LEVEL +
" times in the same thread. This could be a sign of circular reference in the Story Block field. Data will NOT be refreshed.");
return new StoryBlockReferenceResult(false, storyBlockValue);
}
for (final Map<String, Object> contentMap : (List<Map<String, Object>>) contentsMap) {
if (UtilMethods.isSet(contentMap)) {
final String type = contentMap.get(TYPE_KEY).toString();
if (allowedTypes.contains(type)) { // if somebody adds a story block to itself, we don't want to refresh it

refreshed |= this.refreshStoryBlockMap(contentMap, parentContentletIdentifier);
}
try {
final LinkedHashMap<String, Object> blockEditorMap = this.toMap(storyBlockValue);
final Object contentsMap = blockEditorMap.get(CONTENT_KEY);
if (!UtilMethods.isSet(contentsMap) || !(contentsMap instanceof List)) {
return new StoryBlockReferenceResult(true, storyBlockValue);
}
refreshed = isRefreshed(parentContentletIdentifier, (List<Map<String, Object>>) contentsMap);
if (refreshed) {
return new StoryBlockReferenceResult(true, this.toJson(blockEditorMap));
}
} catch (final Exception e) {
final String errorMsg = String.format("An error occurred when refreshing Story Block Contentlet references in parent Content " +
"'%s': %s", parentContentletIdentifier, ExceptionUtil.getErrorMessage(e));
Logger.warnAndDebug(StoryBlockAPIImpl.class, errorMsg, e);
throw new DotRuntimeException(errorMsg, e);
}
if (refreshed) {
return new StoryBlockReferenceResult(true, this.toJson(blockEditorMap));
}
} catch (final Exception e) {
final String errorMsg = String.format("An error occurred when refreshing Story Block Contentlet references in parent Content " +
"'%s': %s", parentContentletIdentifier, ExceptionUtil.getErrorMessage(e));
Logger.warnAndDebug(StoryBlockAPIImpl.class, errorMsg, e);
throw new DotRuntimeException(errorMsg, e);
}
// Return the original value in case no data was refreshed
return new StoryBlockReferenceResult(false, storyBlockValue);
}

private boolean isRefreshed(final String parentContentletIdentifier,
final List<Map<String, Object>> contentsMap) {

boolean refreshed = false;
for (final Map<String, Object> contentMap : contentsMap) {
if (UtilMethods.isSet(contentMap)) {
final String type = contentMap.get(TYPE_KEY).toString();
if (allowedTypes.contains(type)) { // if somebody adds a story block to itself, we don't want to refresh it

refreshed |= this.refreshStoryBlockMap(contentMap, parentContentletIdentifier);
}
}
}
return refreshed;
}

/**
* Takes the current data map of the referenced Contentlet in the Story Block field and checks whether it matches
* its latest live version or not. If it doesn't, then it means it must be refreshed with the data map from the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Optional;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

Expand Down Expand Up @@ -407,6 +408,21 @@ public void test_get_refreshStoryBlockValueReferences_with_bad_content_value()


}


/**
* Method to test: {@link StoryBlockAPI#refreshStoryBlockValueReferences(Object, String)}
* Given Scenario: Test a story block value that is not a json
* ExpectedResult: Do not throw exception and must return zero dependencies
*/
@Test
public void test_refreshStoryBlockValueReferences_with_json_value() {

final Object newStoryBlockJson1 = "bu bu bu}";

StoryBlockReferenceResult result = APILocator.getStoryBlockAPI().refreshStoryBlockValueReferences(newStoryBlockJson1, "xxx");
assertNotNull(result);
assertFalse(result.isRefreshed());

}

}

0 comments on commit 3b89971

Please sign in to comment.