Goal
A sample workflow with dialog participant step for selecting destination folder from a list of options in dropdown. Subfolders under a specific root folder eg. /content/dam are shown in the dropdown
Demo | Package Install | Github
Dialog Path in Participant Step
Dialog in CRX
Dialog in Complete Work Item
Solution
1) Create a datasource /apps/eaem-content-copy-dialog-pariticipant-step/dialogs/folders-ds/folders-ds.jsp for showing the folders in dropdown. Here the root folder was set to /content/dam, but the logic can be adjusted to return a folder list based on usecase
<%@include file="/libs/granite/ui/global.jsp"%> <%@ page import="com.adobe.granite.ui.components.ds.DataSource" %> <%@ page import="com.adobe.granite.ui.components.ds.ValueMapResource" %> <%@ page import="org.apache.sling.api.wrappers.ValueMapDecorator" %> <%@ page import="com.adobe.granite.ui.components.ds.SimpleDataSource" %> <%@ page import="org.apache.commons.collections.iterators.TransformIterator" %> <%@ page import="org.apache.commons.collections.Transformer" %> <%@ page import="org.apache.sling.api.resource.*" %> <%@ page import="java.util.*" %> <% String ROOT_PATH = "/content/dam"; final ResourceResolver resolver = resourceResolver; Resource rootPath = resolver.getResource(ROOT_PATH); List<Resource> qualifiedParents = new ArrayList<Resource>(); rootPath.listChildren().forEachRemaining(r -> { if(r.getName().equals("jcr:content")){ return; } qualifiedParents.add(r); }); DataSource ds = new SimpleDataSource(new TransformIterator(qualifiedParents.iterator(), new Transformer() { public Object transform(Object o) { Resource resource = (Resource) o; ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>()), tvm = resource.getValueMap(); vm.put("value", resource.getPath()); vm.put("text", tvm.get("jcr:content/jcr:title", tvm.get("jcr:title", resource.getName()))); return new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm); } })); request.setAttribute(DataSource.class.getName(), ds); %>
2) Create the dialog /apps/eaem-content-copy-dialog-pariticipant-step/dialogs/content-copy-dialog to show in Inbox console work item Complete Workflow Item
<?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="nt:unstructured" jcr:title="Experience AEM Content Copy" sling:resourceType="cq/gui/components/authoring/dialog"> <content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container"> <items jcr:primaryType="nt:unstructured"> <parent jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldDescription="Select Parent Folder" fieldLabel="Parent Folder" name="parentFolder"> <datasource jcr:primaryType="nt:unstructured" sling:resourceType="/apps/eaem-content-copy-dialog-pariticipant-step/dialogs/folders-ds" addNone="{Boolean}true"/> </parent> </items> </column> </items> </content> </jcr:root>
3) Add the dialog path in Dialog Participant Step of workflow model e.g. /conf/global/settings/workflow/models/experience-aem-content-copy
4) Create a process step e.g. apps.experienceaem.assets.ContentCopyTask to read the parent folder path set in parentFolder of previous step (dialog drop down)
package apps.experienceaem.assets; import com.adobe.granite.workflow.PayloadMap; import com.day.cq.commons.jcr.JcrUtil; import com.day.cq.dam.api.Asset; import com.day.cq.dam.commons.util.DamUtil; import com.day.cq.workflow.metadata.MetaDataMap; import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.resource.*; import com.day.cq.workflow.WorkflowException; import com.day.cq.workflow.WorkflowSession; import com.day.cq.workflow.exec.WorkItem; import com.day.cq.workflow.exec.WorkflowProcess; import org.apache.sling.jcr.resource.api.JcrResourceConstants; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.Node; import javax.jcr.Session; import java.util.Collections; import java.util.Date; import java.util.Iterator; @Component( immediate = true, service = {WorkflowProcess.class}, property = { "process.label = Experience AEM Content Copy Task" } ) public class ContentCopyTask implements WorkflowProcess { protected final Logger log = LoggerFactory.getLogger(this.getClass()); private static final String DIALOG_PARTICIPANT_NODE_ID = "node1"; private static final String DESTINATION_PATH = "parentFolder"; @Reference private ResourceResolverFactory resolverFactory; @Override public void execute(WorkItem item, WorkflowSession wfSession, MetaDataMap args) throws WorkflowException { try { Session session = wfSession.getSession(); ResourceResolver resolver = getResourceResolver(session); Asset payload = getAssetFromPayload(item, resolver); if(payload == null){ log.error("Empty payload, nothing to copy"); return; } String destinationPath = getDestinationPathForCopy(item, resolver); if(StringUtils.isEmpty(destinationPath)){ log.error("Destination path empty for copyign content - " + payload.getPath()); return; } Node copiedPath = JcrUtil.copy(payload.adaptTo(Node.class), resolver.getResource(destinationPath).adaptTo(Node.class), null); log.debug("Copied Path - " + copiedPath); session.save(); } catch (Exception e) { log.error("Failed to copy content", e); } } private String getDestinationPathForCopy(WorkItem item, ResourceResolver resolver) throws Exception{ String wfHistoryPath = item.getWorkflow().getId() + "/history"; Iterator<Resource> historyItr = resolver.getResource(wfHistoryPath).listChildren(); ValueMap metaVM = null; Resource resource, itemResource; String nodeId, destinationPath = ""; while(historyItr.hasNext()){ resource = historyItr.next(); itemResource = resource.getChild("workItem"); nodeId = itemResource.getValueMap().get("nodeId", ""); if(!nodeId.equals(DIALOG_PARTICIPANT_NODE_ID)){ continue; } metaVM = itemResource.getChild("metaData").getValueMap(); destinationPath = metaVM.get(DESTINATION_PATH, ""); break; } return destinationPath; } public Asset getAssetFromPayload(final WorkItem item, final ResourceResolver resolver) throws Exception{ Asset asset = null; if (!item.getWorkflowData().getPayloadType().equals(PayloadMap.TYPE_JCR_PATH)) { return null; } final String path = item.getWorkflowData().getPayload().toString(); final Resource resource = resolver.getResource(path); if (null != resource) { asset = DamUtil.resolveToAsset(resource); } else { log.error("getAssetFromPayload: asset [{}] in payload of workflow [{}] does not exist.", path, item.getWorkflow().getId()); } return asset; } private ResourceResolver getResourceResolver(final Session session) throws LoginException { return resolverFactory.getResourceResolver( Collections.<String, Object> singletonMap(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, session)); } }
No comments:
Post a Comment