AEM 65 - Assets Revert to a Version Binary and not Metadata (keeping it current)

Goal


AEM's Revert to this Version, reverts the asset as a whole (both binary and metadata) to selected version, however if you want the binary to be reverted to a specific version but keep metadata current, try the following approach...

Demo | Package Install | Github



Solution


1) Login to CRXDE Lite (http://localhost:4502/crx/de), create folder /apps/eaem-revert-binary-not-metadata

2) Create node /apps/eaem-revert-binary-not-metadata/clientlib of type cq:ClientLibraryFolder, add String property categories with value cq.gui.coral.common.admin.timeline, String[] property dependencies with value lodash

3) Create file (nt:file) /apps/eaem-revert-binary-not-metadata/clientlib/js.txt, add

                        revert-binary-not-metadata.js

4) Create file (nt:file) /apps/eaem-revert-binary-not-metadata/clientlib/revert-binary-not-metadata.js, add the following code (logic injects a hidden field eaem-revert-toversion-file-only into the form posted and filter in next step reads it for taking a backup of metadata before its reverted to another version)

(function($, $document) {
    var EAEM_REVERT_CSS = "eaem-revert-toversion-file-only",
        REVERT_FILE_NOT_METADATA_TITLE = "Revert to this Version (File)",
        REVERT_TO_VERSION_SEL = ".cq-common-admin-timeline-event-button";

    $document.on("click", ".cq-common-admin-timeline-event", addRevertToThisVersionFile);

    function addRevertToThisVersionFile(){
        var $timeLineButton = $(this).find(REVERT_TO_VERSION_SEL);

        if(!_.isEmpty($timeLineButton.next("." + EAEM_REVERT_CSS))){
            return;
        }

        $(getButtonHtml()).insertAfter($timeLineButton).click(revertToVersion);
    }

    function getButtonHtml(){
        return '<button is="coral-button" class="' + EAEM_REVERT_CSS + '" size="M" variant="secondary" style="width:100%; margin-top:.2rem">' +
                    '<coral-button-label>' + REVERT_FILE_NOT_METADATA_TITLE + '</coral-button-label>' +
               '</button>'
    }

    function revertToVersion(event){
        event.preventDefault();

        var $form = $(this).closest("form"),
            $otbRevert = $(this).prev(REVERT_TO_VERSION_SEL);

        $form.append("<input type='hidden' name='" + EAEM_REVERT_CSS + "' value='true'/>");

        $otbRevert.click();
    }
})(jQuery, jQuery(document));


5) Add filter apps.experienceaem.assets.ExperienceAEMVersionFilter for taking backup of metadata before product's logic reverts both binary and metadata. Later, restore metadata from the backup, thereby keeping it current...

package apps.experienceaem.assets;

import com.day.cq.commons.jcr.JcrUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.Session;
import javax.servlet.*;
import java.io.IOException;

@Component(
        service = Filter.class,
        immediate = true,
        name = "Experience AEM Restore file only (not metadata) Filter",
        property = {
                Constants.SERVICE_RANKING + ":Integer=-99",
                "sling.filter.scope=COMPONENT",
                "sling.filter.selectors=version"
        }
)
public class ExperienceAEMVersionFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(ExperienceAEMVersionFilter.class);

    private static String EAEM_REVERT_PARAM = "eaem-revert-toversion-file-only";
    private static String METADATA_BACKUP = "metadata-backup";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        SlingHttpServletRequest slingRequest = (SlingHttpServletRequest)request;

        String assetPath = slingRequest.getParameter("path");

        if(StringUtils.isEmpty(assetPath)){
            chain.doFilter(slingRequest, response);
            return;
        }

        String revertParam = slingRequest.getParameter(EAEM_REVERT_PARAM);

        if(StringUtils.isEmpty(revertParam)){
            chain.doFilter(slingRequest, response);
            return;
        }

        ResourceResolver resolver = slingRequest.getResourceResolver();
        Session session = resolver.adaptTo(Session.class);
        Resource assetResource = resolver.getResource(assetPath);

        if(assetResource == null){
            chain.doFilter(slingRequest, response);
            return;
        }

        String folderPath = assetPath.substring(0, assetPath.lastIndexOf("/"));
        String backupName = assetResource.getName() + "-" + METADATA_BACKUP;
        String backupPath = folderPath + "/" + backupName;

        Resource metadata = assetResource.getChild("jcr:content/metadata");

        if(metadata == null){
            chain.doFilter(slingRequest, response);
            return;
        }

        try{
            if(session.itemExists(backupPath)){
                session.removeItem(backupPath);
            }

            JcrUtil.copy(metadata.adaptTo(Node.class), resolver.getResource(folderPath).adaptTo(Node.class), backupName, true);

            chain.doFilter(slingRequest, response);

            String metadataPath = metadata.getPath();

            session.removeItem(metadataPath);

            session.move(backupPath, metadataPath);

            session.save();
        }catch(Exception e){
            logger.error("Error taking metadata backup - " + assetPath , e);
        }
    }

    @Override
    public void destroy() {
    }
}


No comments:

Post a Comment