Skip to content

Commit

Permalink
fix(FTM) Homologous output Refs: #31061 (#31072)
Browse files Browse the repository at this point in the history
### Proposed Changes
* This is quite simple. A cache invalidation was needed when passing FTM
params this was causing the output on the contents and the rendered bits
to diverge
* Additionally while updating the FTM karate test I discovered a
discrepancy between the rendered HTML and the contentlet items returned
within the container at the JSON level. A vtl code was used to render
the traditional TM content retrieved by the $dotcontent.pullPerPage view
tool was affecting the rendering logic. The VTL Logic was removed to
allow showing working versions of the content
  • Loading branch information
fabrizzio-dotCMS authored Jan 16, 2025
1 parent cd3e529 commit f07c0ce
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1231,7 +1231,12 @@ protected Contentlet findContentletByIdentifier(final String identifier, final l
throws DotDataException {

final String variant = UtilMethods.isSet(variantId) ? variantId : DEFAULT_VARIANT.name();

// Perhaps we should exclude here contents with only a working version and no live version whatsoever
// To match what we did in the old time machine days
// This logic is tied with a fragment of VTL code in ContainerLoader.java check it out
// Since it basically iterates over the results of this method checks the sysPublishDate and sysExpireDate
// and then adds the contentlet to the container if a live version is found and the dates are correct
// But for the new time machine we allow the user to see the working version dropped on the container
final String query = "SELECT c.*, ci.owner \n"
+ "FROM contentlet c\n"
+ "INNER JOIN identifier i ON i.id = c.identifier\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.dotcms.contenttype.exception.NotFoundInDbException;
import com.dotcms.contenttype.model.type.ContentType;
import com.dotcms.exception.ExceptionUtil;
import com.dotcms.rest.api.v1.page.PageResource;
import com.dotmarketing.beans.ContainerStructure;
import com.dotmarketing.beans.Host;
import com.dotmarketing.business.APILocator;
Expand Down Expand Up @@ -260,52 +261,65 @@ private InputStream buildVelocity(final Container container, final String uuid,
velocityCodeBuilder.append(editWrapperDiv);
velocityCodeBuilder.append("#end");
}
// WARNING: Make no changes to the variable names used here without having checked first its usage
// e.g. ContentletDetail.java uses _show_working_

//Let's find out if the time-machine attribute is set
velocityCodeBuilder.append("#set($_timeMachineOn=false)")
.append("#if($UtilMethods.isSet($request.getSession(false)) && $request.session.getAttribute(\""+PageResource.TM_DATE+"\"))")
.append("#set($_timeMachineOn=true)")
.append("#set($_tmdate=$date.toDate($webapi.parseLong($request.session.getAttribute(\""+PageResource.TM_DATE+"\"))))")
.append("#end")
.append("#if($request.getAttribute(\""+PageResource.TM_DATE+"\"))")
.append("#set($_timeMachineOn=true)")
.append("#set($_tmdate=$date.toDate($webapi.parseLong($request.getAttribute(\""+PageResource.TM_DATE+"\"))))")
.append("#end");

// FOR LOOP

velocityCodeBuilder.append("#foreach ($contentletId in $CONTENTLETS )");

velocityCodeBuilder.append("#set($dotContentMap=$dotcontent.load($contentletId))");
velocityCodeBuilder.append("#set($_show_working_=false)");

//Time-machine block begin
velocityCodeBuilder.append("#if($UtilMethods.isSet($request.getSession(false)) && $request.session.getAttribute(\"tm_date\"))");

velocityCodeBuilder.append("#set($_tmdate=$date.toDate($webapi.parseLong($request.session.getAttribute(\"tm_date\"))))");
velocityCodeBuilder.append("#set($_ident=$webapi.findIdentifierById($contentletId))");
// if the content has expired we rewrite the identifier so it isn't loaded
velocityCodeBuilder.append("#if($UtilMethods.isSet($_ident.sysExpireDate) && $_tmdate.after($_ident.sysExpireDate))");
velocityCodeBuilder.append("#set($contentletId='')");
velocityCodeBuilder
.append("#foreach ($contentletId in $CONTENTLETS )")
.append("#set($dotContentMap=$dotcontent.load($contentletId))")
.append("#set($_show_working_=false)");

//Time-machine block begin
velocityCodeBuilder.append("#if($_timeMachineOn) ");

velocityCodeBuilder
.append("#set($_ident=$webapi.findIdentifierById($contentletId))");

// if the content has expired we rewrite the identifier, so it isn't loaded
velocityCodeBuilder
.append("#if($UtilMethods.isSet($_ident.sysExpireDate) && $_tmdate.after($_ident.sysExpireDate))")
.append("#set($contentletId='')")
.append("#end");

// if the content should be published then force to show the working version
velocityCodeBuilder
.append("#if($UtilMethods.isSet($_ident.sysPublishDate) && ($_tmdate.equals($_ident.sysPublishDate) || $_tmdate.after($_ident.sysPublishDate)))")
.append("#set($_show_working_=true)")
.append("#end");

velocityCodeBuilder.append("#if(!$UtilMethods.isSet($user)) ")
.append("#set($user = $cmsuser.getLoggedInUser($request)) ")
.append("#end");
//end of time-machine block
velocityCodeBuilder.append("#end");

// if the content should be published then force to show the working version
velocityCodeBuilder.append("#if($UtilMethods.isSet($_ident.sysPublishDate) && ($_tmdate.equals($_ident.sysPublishDate) || $_tmdate.after($_ident.sysPublishDate)))");
velocityCodeBuilder.append("#set($_show_working_=true)");
velocityCodeBuilder.append("#end");

velocityCodeBuilder.append("#if(! $webapi.contentHasLiveVersion($contentletId) && ! $_show_working_)")
.append("#set($contentletId='')") // working contentlet still not published
.append("#end");

velocityCodeBuilder.append("#if(!$UtilMethods.isSet($user)) ")
.append("#set($user = $cmsuser.getLoggedInUser($request)) ")
.append("#end");
//end of time-machine block
velocityCodeBuilder.append("#end");

velocityCodeBuilder.append("#set($CONTENT_INODE = '')");
velocityCodeBuilder.append("#set($CONTENT_BASE_TYPE = '')");
velocityCodeBuilder.append("#set($CONTENT_LANGUAGE = '')");
velocityCodeBuilder.append("#set($ContentletTitle = '')");
velocityCodeBuilder.append("#set($CONTENT_TYPE_ID = '')");
velocityCodeBuilder.append("#set($CONTENT_TYPE = '')");
velocityCodeBuilder.append("#set($CONTENT_VARIANT = '')");
velocityCodeBuilder.append("#set($ON_NUMBER_OF_PAGES = '')");

// read in the content
velocityCodeBuilder.append("#if($contentletId != '')");
velocityCodeBuilder.append("#contentDetail($contentletId)");
velocityCodeBuilder.append("#end");
velocityCodeBuilder
.append("#set($CONTENT_INODE = '')")
.append("#set($CONTENT_BASE_TYPE = '')")
.append("#set($CONTENT_LANGUAGE = '')")
.append("#set($ContentletTitle = '')")
.append("#set($CONTENT_TYPE_ID = '')")
.append("#set($CONTENT_TYPE = '')")
.append("#set($CONTENT_VARIANT = '')")
.append("#set($ON_NUMBER_OF_PAGES = '')");

// read in the content
velocityCodeBuilder
.append("#if($contentletId != '')")
.append("#contentDetail($contentletId)")
.append("#end");

velocityCodeBuilder.append("#set($HAVE_A_VERSION=($CONTENT_INODE != ''))");

Expand Down Expand Up @@ -354,13 +368,13 @@ private InputStream buildVelocity(final Container container, final String uuid,

for (int i = 0; i < containerContentTypeList.size(); i++) {
ContainerStructure cs = containerContentTypeList.get(i);
String ifelse = (i == 0) ? "if" : "elseif";
velocityCodeBuilder.append("#").append(ifelse)
String ifElse = (i == 0) ? "if" : "elseif";
velocityCodeBuilder.append("#").append(ifElse)
.append("($ContentletStructure ==\"")
.append(cs.getStructureId()).append("\")");
velocityCodeBuilder.append(cs.getCode());
}
if (containerContentTypeList.size() > 0) {
if (!containerContentTypeList.isEmpty()) {
velocityCodeBuilder.append("#end");
}

Expand All @@ -375,11 +389,11 @@ private InputStream buildVelocity(final Container container, final String uuid,
velocityCodeBuilder.append("#end");

// end content dot-data-content
if (mode == PageMode.EDIT_MODE) {
velocityCodeBuilder.append("</div>");
}
if (mode == PageMode.EDIT_MODE) {
velocityCodeBuilder.append("</div>");
}

velocityCodeBuilder.append("#set($dotContentMap='')");
velocityCodeBuilder.append("#set($dotContentMap='')");
// ##End of foreach loop
velocityCodeBuilder.append("#end");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.dotcms.contenttype.model.field.TimeField;
import com.dotcms.contenttype.model.type.BaseContentType;
import com.dotcms.contenttype.model.type.ContentType;
import static com.dotcms.util.FunctionUtils.getOrDefault;
import com.dotcms.util.JsonUtil;
import com.dotcms.variant.business.web.VariantWebAPI.RenderContext;
import com.dotmarketing.business.APILocator;
Expand All @@ -42,8 +43,6 @@
import com.liferay.portal.model.User;
import com.liferay.util.FileUtil;
import io.vavr.control.Try;
import org.apache.velocity.exception.ResourceNotFoundException;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
Expand All @@ -53,6 +52,7 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.apache.velocity.exception.ResourceNotFoundException;

/**
* Provides the Velocity Engine with the objects that are or can be used when rendering content.
Expand Down Expand Up @@ -634,36 +634,35 @@ public void invalidate(Structure structure) throws DotDataException, DotSecurity
public InputStream writeObject(final VelocityResourceKey key)
throws DotStateException, DotDataException, DotSecurityException {

long language = Long.valueOf(key.language);
final long language = Long.parseLong(key.language);
final RenderContext renderContext = WebAPILocator.getVariantWebAPI()
.getRenderContext(language, key.id1, key.mode, APILocator.systemUser());

Optional<ContentletVersionInfo> info = APILocator.getVersionableAPI().getContentletVersionInfo(key.id1,
renderContext.getCurrentLanguageId(), renderContext.getCurrentVariantKey());

Contentlet contentlet = (key.mode.showLive)
? APILocator.getContentletAPI().find(info.get().getLiveInode(),
APILocator.systemUser(), false)
: APILocator.getContentletAPI().find(info.get().getWorkingInode(),
if(info.isEmpty()){
throw new ResourceNotFoundException("cannot find content version info for key: " + key);
}

final ContentletVersionInfo contentletVersionInfo = info.get();
final String inode = (key.mode.showLive)
? contentletVersionInfo.getLiveInode()
: contentletVersionInfo.getWorkingInode();

final Contentlet contentlet =
APILocator.getContentletAPI().find(inode,
APILocator.systemUser(), false);

Logger.debug(this, "DotResourceLoader:\tWriting out contentlet inode = " + contentlet.getInode());
final String liveWorkingLabel = getOrDefault(key.mode.showLive,()->"live",()->"working");

Logger.debug(this, String.format("DotResourceLoader:\tWriting out contentlet \"%s\" inode = %s", liveWorkingLabel, inode));
if (null == contentlet) {
throw new ResourceNotFoundException("cannot find content for: " + key);
}
return buildVelocity(contentlet, key.mode, key.path);
}

private boolean shouldCheckForVersionInfoInDefaultLanguage(long language) {
return language != defaultLang && APILocator.getLanguageAPI()
.canDefaultContentToDefaultLanguage();
}

private boolean isLiveVersionNotAvailable(VelocityResourceKey key, ContentletVersionInfo info) {
return info == null || key.mode.showLive && !UtilMethods.isSet(info.getLiveInode());
}


@Override
public void invalidate(Object obj, PageMode mode) {
Contentlet asset = (Contentlet) obj;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ private List<ContainerRaw> populateContainers() throws DotDataException, DotSecu

final HttpServletRequest request = HttpServletRequestThreadLocal.INSTANCE.getRequest();
final Date timeMachineDate = timeMachineDate(request).orElseGet(()->null);
if(null != timeMachineDate){
Logger.debug(this, "Time Machine date found cache must be evicted: " + timeMachineDate);
// for future time machine we need to invalidate the cache for there can be precalculated content
// that was loaded before without using time machine date see https://github.com/dotCMS/core/issues/31061
new PageLoader().invalidate(htmlPage, mode);
}
final boolean live = this.isLive(request);
final String currentVariantId = WebAPILocator.getVariantWebAPI().currentVariantId();
final Table<String, String, Set<PersonalizedContentlet>> pageContents = this.multiTreeAPI
Expand Down Expand Up @@ -412,7 +418,8 @@ private void addRelationships(final Contentlet contentlet) {
}

private Contentlet getContentletByVariantFallback(final String currentVariantId,
final PersonalizedContentlet personalizedContentlet, final Date timeMachineDate) {
final PersonalizedContentlet personalizedContentlet, final Date timeMachineDate)
throws DotSecurityException {

final Contentlet contentlet = this.getContentlet(personalizedContentlet, currentVariantId, timeMachineDate);

Expand Down Expand Up @@ -539,7 +546,7 @@ private boolean needParseContainerPrefix(final Container container, final String
* Personalized Contentlet object.
*/
private Contentlet getContentlet(final PersonalizedContentlet personalizedContentlet,
final String variantName, final Date timeMachineDate) {
final String variantName, final Date timeMachineDate) throws DotSecurityException {

try {
return Config.getBooleanProperty("DEFAULT_CONTENT_TO_DEFAULT_LANGUAGE", false) ?
Expand All @@ -551,7 +558,7 @@ private Contentlet getContentlet(final PersonalizedContentlet personalizedConten
// Page that is holding it without any problems
return limitedUserPermissionFallback(personalizedContentlet.getContentletId());
}
throw new DotStateException(se);
throw se;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public ContentUtils getInstance()
*/
public static Contentlet find(final String inodeOrIdentifier, final User user, final boolean EDIT_OR_PREVIEW_MODE, final long sessionLang){
final Optional<String> timeMachineDate = TimeMachineUtil.getTimeMachineDate();
return find(inodeOrIdentifier,user,timeMachineDate.orElse(null),EDIT_OR_PREVIEW_MODE, sessionLang);
return find(inodeOrIdentifier, user, timeMachineDate.orElse(null), EDIT_OR_PREVIEW_MODE, sessionLang);
}

private static Contentlet fixRecurringDates(Contentlet contentlet, String[] recDates) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ private void setUpTimeMachineIfPresent(final PageRenderParams renderParams) {
session.setAttribute(TM_DATE, timeMachineEpochMillis);
session.setAttribute(TM_LANG, renderParams.languageId());
session.setAttribute(DOT_CACHE, "refresh");
session.setAttribute(TM_HOST, host.get());
} else {
request.setAttribute(TM_DATE, timeMachineEpochMillis);
request.setAttribute(TM_LANG, renderParams.languageId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,11 @@ public PageView build(final boolean rendered, final PageMode mode) throws DotDat
// (unless host is specified in the dotParse) github 14624
final RenderParams params=new RenderParams(user,language, site, mode);
request.setAttribute(RenderParams.RENDER_PARAMS_ATTRIBUTE, params);
final User systemUser = APILocator.getUserAPI().getSystemUser();
final boolean canEditTemplate = this.permissionAPI.doesUserHavePermission(template, PermissionLevel.EDIT.getType(), user);
final boolean canCreateTemplates = layoutAPI.doesUserHaveAccessToPortlet("templates", user);

final PageRenderUtil pageRenderUtil = new PageRenderUtil(
this.htmlPageAsset, systemUser, mode, language.getId(), this.site);
this.htmlPageAsset, user, mode, language.getId(), this.site);

final Optional<Contentlet> urlContentletOpt = this.findUrlContentlet (request);

Expand Down
Loading

0 comments on commit f07c0ce

Please sign in to comment.