Skip to content

Commit

Permalink
#23181 include in 23.01.8
Browse files Browse the repository at this point in the history
  • Loading branch information
erickgonzalez committed Oct 30, 2023
1 parent f7fc4d5 commit 512f1d8
Show file tree
Hide file tree
Showing 7 changed files with 341 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
package com.dotcms.rest.api.v1.template;

import com.dotcms.datagen.HTMLPageDataGen;
import com.dotcms.datagen.SiteDataGen;
import com.dotcms.datagen.TemplateDataGen;
import com.dotcms.datagen.TestUserUtils;
import com.dotcms.datagen.UserDataGen;
import com.dotcms.contenttype.model.field.Field;
import com.dotcms.contenttype.model.field.TextField;
import com.dotcms.contenttype.model.type.ContentType;
import com.dotcms.datagen.*;
import com.dotcms.mock.request.MockAttributeRequest;
import com.dotcms.mock.request.MockHeaderRequest;
import com.dotcms.mock.request.MockHttpRequestIntegrationTest;
import com.dotcms.mock.request.MockSessionRequest;
import com.dotcms.mock.response.MockHttpResponse;
import com.dotcms.rendering.velocity.viewtools.DotTemplateTool;
import com.dotcms.rest.ResponseEntityView;
import com.dotcms.rest.api.BulkResultView;
import com.dotcms.util.IntegrationTestInitService;
import com.dotmarketing.beans.Host;
import com.dotmarketing.beans.MultiTree;
import com.dotmarketing.beans.Permission;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.PermissionAPI;
import com.dotmarketing.exception.DoesNotExistException;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotSecurityException;
import com.dotmarketing.portlets.containers.model.Container;
import com.dotmarketing.portlets.contentlet.model.Contentlet;
import com.dotmarketing.portlets.htmlpageasset.business.render.PageContext;
import com.dotmarketing.portlets.htmlpageasset.model.HTMLPageAsset;
import com.dotmarketing.portlets.languagesmanager.model.Language;
import com.dotmarketing.portlets.templates.design.bean.TemplateLayout;
import com.dotmarketing.portlets.templates.model.Template;
import com.dotmarketing.util.PageMode;
import com.dotmarketing.util.PaginatedArrayList;
import com.dotmarketing.util.UUIDGenerator;
import com.dotmarketing.util.WebKeys;
Expand All @@ -32,12 +39,17 @@
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class TemplateResourceTest {

static TemplateResource resource;
Expand Down Expand Up @@ -1087,4 +1099,148 @@ public void test_listTemplate_limitedUserNoREADPermissionsOverOneTemplate()
paginatedArrayList = PaginatedArrayList.class.cast(responseEntityView.getEntity());
Assert.assertEquals(1, this.removeSystemTemplate(paginatedArrayList).size());
}

/**
* Method to test: {@link com.dotmarketing.portlets.htmlpageasset.business.render.HTMLPageAssetRenderedAPIImpl#getPageHtml(PageContext, HttpServletRequest, HttpServletResponse)}
* When: You have a Page that:
* - it is using a Template that hava a wrong Container UUID like 1562770692396
* - it has Contentlet into it.
*
* And the Template is changed
*
* Should: Keep render the Contentlet that is inside the page.
*
* @throws DotDataException
* @throws DotSecurityException
* @throws InterruptedException
*/
@Test
public void legacyUUIDTemplate() throws DotDataException, DotSecurityException, InterruptedException {
final Language defaultLanguage = APILocator.getLanguageAPI().getDefaultLanguage();
final String uuid = "1562770692396";

final String legacyDrawBody = "<div id=\"resp-template\" name=\"globalContainer\">"
+ "<div id=\"hd-template\">"
+ "<h1>Header</h1>"
+ "</div>"
+ "<div id=\"bd-template\">"
+ "<div id=\"yui-main-template\">"
+ "<div class=\"yui-b-template\" id=\"splitBody0\">"
+ "<div class=\"addContainerSpan\">"
+ "<a href=\"javascript: showAddContainerDialog('splitBody0');\" title=\"Add Container\">"
+ "<span class=\"plusBlueIcon\"></span>"
+ "Add Container"
+ "</a>"
+ "</div>"
+ "<span class=\"titleContainerSpan\" id=\"splitBody0_span_69b3d24d-7e80-4be6-b04a-d352d16493ee_1562770692396\" title=\"container_69b3d24d-7e80-4be6-b04a-d352d16493ee\">"
+ "<div class=\"removeDiv\">"
+ "<a href=\"javascript: removeDrawedContainer('splitBody0','69b3d24d-7e80-4be6-b04a-d352d16493ee','1562770692396');\" title=\"Remove Container\">"
+ "<span class=\"minusIcon\"></span>Remove Container"
+ "</a>"
+ "</div>"
+ "<div class=\"clear\"></div>"
+ "<h2>Container: Default</h2>"
+ "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris "
+ "nisi ut aliquip ex ea commodo consequat."
+ "</p>"
+ "</span>"
+ "<div style=\"display: none;\" title=\"container_69b3d24d-7e80-4be6-b04a-d352d16493ee\" id=\"splitBody0_div_69b3d24d-7e80-4be6-b04a-d352d16493ee_1562770692396\">"
+ "#parseContainer('%s','%s')\n"
+ "</div>"
+ "</div>"
+ "</div>"
+ "</div>"
+ "<div id=\"ft-template\"><h1>Footer</h1></div>"
+ "</div>";

final String legacyBody = "#parseContainer('%s', '%s')";

final Field field = new FieldDataGen().type(TextField.class).next();
final ContentType contentType = new ContentTypeDataGen().field(field).nextPersisted();
final Container container = new ContainerDataGen()
.withContentType(contentType, "${" + field.variable() + "}")
.nextPersisted();

final String legacyDrawBodyFormatted = String.format(legacyDrawBody, container.getIdentifier(), uuid);

final Contentlet contentlet = new ContentletDataGen(contentType)
.setProperty(field.variable(), "Testing")
.languageId(defaultLanguage.getId())
.nextPersisted();

final Contentlet theme = new ThemeDataGen().nextPersisted();
final Template template = new TemplateDataGen()
.drawedBody(legacyDrawBodyFormatted)
.body(String.format(legacyBody, container.getIdentifier(), uuid))
.theme(theme)
.nextPersisted();

final TemplateResource templateResource = new TemplateResource();

final Host site = new SiteDataGen().nextPersisted();

final HTMLPageAsset htmlPageAsset = new HTMLPageDataGen(site, template)
.languageId(defaultLanguage.getId())
.nextPersisted();

final MultiTree multiTree = new MultiTreeDataGen()
.setPage(htmlPageAsset)
.setContainer(container)
.setContentlet(contentlet)
.setInstanceID( uuid)
.setTreeOrder(0)
.nextPersisted();

final HttpSession mockHttpSession = mock(HttpSession.class);
final HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getParameter("host_id")).thenReturn(site.getIdentifier());
when(request.getAttribute(com.liferay.portal.util.WebKeys.USER)).thenReturn(APILocator.systemUser());
when(request.getSession()).thenReturn(mockHttpSession);

final TemplateHelper templateHelper = new TemplateHelper();
final TemplateView templateView = templateHelper.toTemplateView(template,
APILocator.systemUser());

final HttpServletResponse response = mock(HttpServletResponse.class);
final TemplateForm templateForm = new TemplateForm.Builder()
.siteId(site.getIdentifier())
.identifier(template.getIdentifier())
.inode(template.getInode())
.layout(templateView.getLayout())
.title(template.getTitle())
.build();

final PageContext pageContext = new PageContext(APILocator.systemUser(),
htmlPageAsset.getPageUrl(), PageMode.PREVIEW_MODE, htmlPageAsset);

final String pageHtml_1 = APILocator.getHTMLPageAssetRenderedAPI()
.getPageHtml(pageContext, request, response);

assertTrue(pageHtml_1.contains("<div>Testing</div>"));

final Template templateFromDaBaseBeforeUpdate = APILocator.getTemplateAPI()
.findWorkingTemplate(template.getIdentifier(), APILocator.systemUser(), false);

final TemplateLayout templateLayoutBeforeUpdate = DotTemplateTool.getTemplateLayout(
templateFromDaBaseBeforeUpdate.getDrawedBody());
assertTrue(templateLayoutBeforeUpdate.existsContainer(container, uuid));

templateResource.save(request, response, templateForm);

Thread.sleep(3000);

final Template templateFromDaBaseAfterUpdate = APILocator.getTemplateAPI()
.findWorkingTemplate(template.getIdentifier(), APILocator.systemUser(), false);

final TemplateLayout templateLayoutAfterUpdate = DotTemplateTool.getTemplateLayout(
templateFromDaBaseAfterUpdate.getDrawedBody());
assertTrue(templateLayoutAfterUpdate.existsContainer(container, "1"));

final String pageHtml_2 = APILocator.getHTMLPageAssetRenderedAPI()
.getPageHtml(pageContext, request, response);
assertTrue(pageHtml_2.contains("<div>Testing</div>"));


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ public TemplateLayout toTemplateLayout(final TemplateLayoutView templateLayoutVi
TemplateLayout layout = null;

if (null != templateLayoutView) {
//update UUID for the containers
templateLayoutView.updateUUIDOfContainers();

layout = new TemplateLayout();
layout.setBody(this.toBody(templateLayoutView.getBody()));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.dotcms.rest.api.v1.template;

import com.dotmarketing.util.UtilMethods;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.Map;
import com.dotmarketing.portlets.templates.design.bean.ContainerUUID;

import java.util.*;
import java.util.stream.Collectors;

public class TemplateLayoutView {

Expand Down Expand Up @@ -61,28 +64,122 @@ public SidebarView getSidebar() {
*
* TemplateLayoutView with the updated UUID for each container.
*/
protected void updateUUIDOfContainers(){
protected ContainerUUIDChanges updateUUIDOfContainers(){
final ContainerUUIDChanges containerUUIDChanged = new ContainerUUIDChanges();
final Map<String,Integer> UUIDByContainermap = new HashMap<>();
this.getBody().getRows().forEach(
row -> row.getColumns().stream().forEach(
column -> column.getContainers().stream().forEach(
containerUUID -> {
final String containerID = containerUUID.getIdentifier();
int value = UUIDByContainermap.getOrDefault(containerID,0);
UUIDByContainermap.put(containerID,++value);
containerUUID.setUuid(UUIDByContainermap.get(containerID).toString());
final String[] uuidValues = setNewUUID(UUIDByContainermap,
containerUUID);
containerUUIDChanged.change(containerUUID.getIdentifier(), uuidValues[0], uuidValues[1]);
}
)));

if(this.getSidebar()!=null) {
this.getSidebar().getContainers().stream().forEach(
containerUUID -> {
final String containerID = containerUUID.getIdentifier();
int value = UUIDByContainermap.getOrDefault(containerID, 0);
UUIDByContainermap.put(containerID, ++value);
containerUUID.setUuid(UUIDByContainermap.get(containerID).toString());
final String[] uuidValues = setNewUUID(UUIDByContainermap, containerUUID);
containerUUIDChanged.change(containerUUID.getIdentifier(), uuidValues[0], uuidValues[1]);
}
);
}
return containerUUIDChanged;
}

private static String[] setNewUUID(final Map<String, Integer> UUIDByContainermap,
final ContainerUUID containerUUID) {
final String oldValue = containerUUID.getUUID();
final String containerID = containerUUID.getIdentifier();
int value = UUIDByContainermap.getOrDefault(containerID,0);
final int newValue = value + 1;
UUIDByContainermap.put(containerID, newValue);
containerUUID.setUuid(UUIDByContainermap.get(containerID).toString());

return new String[]{oldValue, String.valueOf(newValue)};
}


/**
* Represent a set of UUID change when a Template's Layout is updated
*
*/
public static class ContainerUUIDChanges {
final Map<String, Map<String, String>> changes = new HashMap();
final Map<String, Collection<String>> newValues = new HashMap<>();
public void change(final String containerId, final String oldValue, final String newValue) {
if (ContainerUUID.UUID_DEFAULT_VALUE.equals(oldValue)) {
final Collection<String> containerNewValues = newValues.getOrDefault(containerId,
new HashSet<>());
containerNewValues.add(newValue);
newValues.put(containerId, containerNewValues);
} else if (!oldValue.equals(newValue)) {
final Map<String, String> containerChanges = changes.getOrDefault(containerId,
new HashMap<String, String>());
containerChanges.put(oldValue, newValue);
changes.put(containerId, containerChanges);
}
}

/**
* Return all the UUID that was lost in the Template's Layout update, for Example, if
* we have a Template with a Layout equals to:
*
* <code>
* {
* rows: [
* columns: [
* containers: [
* {
* id: "...",
* uuid: "109839"
* }
* ]
* ]
* ]
* }
* </code>
*
* The UUID equals to 109839 is not valid for this reason if the Layout is updated this UUID
* is changed by 1, and then the 109839 is lost.
*
* @return
*/
public Collection<ContainerUUIDChanged> lostUUIDValues(){
final List<ContainerUUIDChanged> result = new ArrayList<>();

for (final String containerId : changes.keySet()) {
final Map<String, String> containerChanges = changes.get(containerId);
final Collection<String> newValuesChanged = containerChanges.values();
final Collection<String> containerNewValues = newValues.get(containerId);

final List<ContainerUUIDChanged> partialResult = containerChanges.entrySet().stream()
.filter(entry -> !newValuesChanged.contains(entry.getKey()))
.filter(entry -> !UtilMethods.isSet(containerNewValues) || !containerNewValues.contains(entry.getKey()))
.map(entry -> new ContainerUUIDChanged(containerId, entry.getKey(),
entry.getValue()))
.collect(Collectors.toList());

result.addAll(partialResult);
}

return result;
}
}

/**
* Represent a Change in just one UUID into the Template's Layout
*/
public static class ContainerUUIDChanged {
final String containerId;
final String newValue;
final String oldValue;

public ContainerUUIDChanged(final String containerId, final String oldValue, final String newValue) {
this.newValue = newValue;
this.oldValue = oldValue;
this.containerId = containerId;
}
}
}
Loading

0 comments on commit 512f1d8

Please sign in to comment.