categories groovy merge System Administrator Jahia 7.3 Jahia 8

How to merge 2 categories

Question

What is the way to merge 2 categories?
 

Answer

Imagine that we have 2 categories catA and catB

If you want to merge catA with catB, then you simply need to get the list of nodes with a reference to catA, then remove this reference and set it to catB

Here could be a script to handle it from the groovy console. Before running it, you need to set the categoryFrom and the categoryTo variables with the current category path you want to work with.

Also set the doIt to true to apply the changes. 

import org.jahia.api.Constants
import org.jahia.services.content.*

import javax.jcr.NodeIterator
import javax.jcr.PathNotFoundException
import javax.jcr.RepositoryException
import javax.jcr.query.Query

def logger = log;

String categoryFrom = "/sites/systemsite/categories/category-a";
String categoryTo = "/sites/systemsite/categories/category-b";

boolean doIt = false;

Set<String> nodesToAutoPublish = new HashSet<String>();
Set<String> nodesToManuallyPublish = new HashSet<String>();

JCRTemplate.getInstance().doExecuteWithSystemSession(null, Constants.EDIT_WORKSPACE, null, new JCRCallback() {
    @Override
    Object doInJCR(JCRSessionWrapper session) throws RepositoryException {
        JCRNodeWrapper fromCategoryNode = null;
        try {
            fromCategoryNode = session.getNode(categoryFrom);
        } catch (javax.jcr.PathNotFoundException e) {
        }
        JCRNodeWrapper toCategoryNode = null;
        try {
            toCategoryNode = session.getNode(categoryTo);
        } catch (javax.jcr.PathNotFoundException e) {
        }


        if (fromCategoryNode != null && toCategoryNode != null) {
            String categoryFromUUID = fromCategoryNode.getIdentifier();
            String categoryToUUID = toCategoryNode.getIdentifier();

            def q = "SELECT * FROM [jmix:categorized] where [j:defaultCategory]='" + categoryFromUUID + "'";

            NodeIterator iterator = session.getWorkspace().getQueryManager().createQuery(q, Query.JCR_SQL2).execute().getNodes();
            while (iterator.hasNext()) {
                final JCRNodeWrapper node = (JCRNodeWrapper) iterator.nextNode();
                logger.info("Found category (" + fromCategoryNode.getDisplayableName() + ") on node " + node.getPath());
                boolean toCategoryAlreadySet = false;

                try {
                    if (! hasPendingModification(node)) {
                        nodesToAutoPublish.add(node.getIdentifier());
                    } else {
                        nodesToManuallyPublish.add(node.getIdentifier());
                    }

                    JCRPropertyWrapper categoryProp = node.getProperty("j:defaultCategory");

                    JCRValueWrapper valueToRemove = null;
                    JCRValueWrapper[] categoryValues = categoryProp.getValues()
                    for (JCRValueWrapper categoryValue : categoryValues) {
                        if (categoryValue.getString().equals(categoryToUUID)) {
                            toCategoryAlreadySet = true;
                        }
                        if (categoryValue.getString().equals(categoryFromUUID)) {
                            valueToRemove = categoryValue;
                        }
                    }
                    try {
                        categoryProp.removeValue(valueToRemove);
                        logger.info("    Remove category " + valueToRemove.getString() + " (" + fromCategoryNode.getDisplayableName() + ") on " + node.getPath());
                    } catch (javax.jcr.ValueFormatException e) {
                        logger.info("    Error when trying to rempve category " + categoryFromUUID + " (" + fromCategoryNode.getDisplayableName() + ") on " + node.getPath() + " " + e.getMessage());
                    }
                    if (! toCategoryAlreadySet ) {
                        try {
                            categoryProp.addValue(toCategoryNode);
                            logger.info("    Set category " + categoryToUUID + " (" + toCategoryNode.getDisplayableName() + ") on " + node.getPath());
                        } catch (javax.jcr.ValueFormatException e) {
                            logger.info("    Error when trying to set category " + categoryToUUID + " (" + toCategoryNode.getDisplayableName() + ") on " + node.getPath() + " " + e.getMessage());
                        }
                    }
                    node.setProperty("j:defaultCategory", categoryProp.getValues());
                    if (doIt) {
                        node.saveSession();
                    }
                } catch (PathNotFoundException e) {
                }


            }

        }
        if (CollectionUtils.isNotEmpty(nodesToAutoPublish)) {
            if (doIt) {
                JCRPublicationService.getInstance().publish(nodesToAutoPublish.asList(), Constants.EDIT_WORKSPACE, Constants.LIVE_WORKSPACE, null);
            };
            logger.info("");
            logger.info("Nodes which where republished:")
            for (String identifier : nodesToAutoPublish) {
                logger.warn("   " + session.getNodeByIdentifier(identifier).getPath());
            }
        }
        if (CollectionUtils.isNotEmpty(nodesToManuallyPublish)) {
            logger.info("");
            logger.info("Nodes to publish manually:")
            for (String identifier : nodesToManuallyPublish) {
                logger.warn("   " + session.getNodeByIdentifier(identifier).getPath());
            }
        }
        if (doIt) {
            session.save();
        }

        return null;
    }
});

private boolean hasPendingModifications(JCRNodeWrapper node) {
    if (!node.hasProperty("j:lastPublished")) return true
    if (!node.hasProperty("j:published") || !node.getProperty("j:published").getBoolean()) return true
    java.util.Calendar lastModified = node.getProperty("jcr:lastModified").getDate()
    java.util.Calendar lastPublished = node.getProperty("j:lastPublished").getDate()
    return lastModified > lastPublished
}