importPackage(Packages.java.io); importPackage(Packages.de.elo.ix.client); //@include lib_Class.js //@include lib_sol.common.ObjectUtils.js //@include lib_sol.common.SordUtils.js //@include lib_sol.common.RepoUtils.js //@include lib_sol.common.UserUtils.js //@include lib_sol.common.AsyncUtils.js //@include lib_sol.common.ix.FunctionBase.js //@include lib_sol.common.Template.js var logger = sol.create("sol.Logger", { scope: "sol.common.ix.functions.CopyFolderContents" }); /** * Copies whole folder recursively. * * # As IX function call * * sol.common.IxUtils.execute("RF_sol_function_CopyFolderContents", { * objId: 123, * source: 1233, * copySourceAcl: false, * inheritDestinationAcl: true * }); * * # Node configuration example: * * { * "source": "ARCPATH:/MyTemplates/MyTemplate1" * } * * @author JHR, ELO Digital Office GmbH * @version 1.04.000 * * @eloix * @requires sol.Logger * @requires sol.common.JsonUtils * @requires sol.common.SordUtils * @requires sol.common.RepoUtils * @requires sol.common.AsyncUtils * @requires sol.common.ObjectUtils * @requires sol.common.ix.RfUtils * @requires sol.common.ix.FunctionBase * */ sol.define("sol.common.ix.functions.CopyFolderContents", { extend: "sol.common.ix.FunctionBase", requiredConfig: ["objId", "source"], /** * @cfg {Number} objId (required) * ObjectId of destination folder */ /** * @cfg {Number} source (required) * ObjectId of source folder which content should be copied */ /** * @cfg {Boolean} [copySourceAcl=false] * Copies the ACL of parent element when set */ copySourceAcl: false, /** * @cfg {Boolean} [inheritDestinationAcl=true] * Inherits the ACL of the destination element when set */ inheritDestinationAcl: true, /** * @cfg {Boolean} [copyOnlyWorkversion=true] * Copy only the work version */ copyOnlyWorkversion: true, /** * @cfg {Boolean} [copyOnlyBaseElement=false] * Copy only the base element */ copyOnlyBaseElement: false, /** * @cfg {Boolean} [copyOnlyChildrenElements=false] * Copy only children elements of the base element * This options is currently only supported if function is called in {@link #useQuickCopy} mode */ copyOnlyChildrenElements: false, /** * @cfg {String} [targetMask] * Change the base element mask to another mask finally. When `copyOnlyChildrenElements` is * set to true the mask change will be performed on the already existing target sord object */ targetMask: undefined, /** * @cfg {String} name * If set, the new elements name will set to this, instead of the sources name */ /** * @cfg {Boolean} [useQuickCopy=false] * If `true` the copy process will be executed asynchronous. The first element will be created as fast as possible and the children will be copied in a background job. */ useQuickCopy: false, /** * @cfg {Boolean} [useTemplate=false] * If `true` only `source` prop with a handlebar string will be resolved by a templateSord object * The passed `objId` will be checkout in this case and will act as data provider */ useTemplate: false, /** * @cfg {Boolean} [waitUntilFinished=false] * If `true` the function is waiting until the background copy process is finished * * This property is only working in combination with {@link #useQuickCopy}=`true` * This has the effect that {@link #useQuickCopy} is working sychronously. Use this setting with caution, as this has * an impact on performance */ waitUntilFinished: false, /** * @cfg {Object[]} metadata Only applied if {@link #useQuickCopy} is `true`. * Set additional metadata on the root element after copying the element. * For syntax of the see {@link sol.common.SordUtils#updateSord updateSord}. */ /** * @cfg {Object[]} acl Only applied if {@link #useQuickCopy} is `true`. * @cfg {String} [acl.mode="ADD"] Supported are `SET` and `ADD` * @cfg {Object[]} acl.entries Definition which ACL should be set/added * @cfg {String} acl.entries.userId Either userId or userName has to be defined * @cfg {String} acl.entries.userName Either userId or userName has to be defined. `userName` can be "$CURRENTUSER" to use the current user. * @cfg {String} [acl.entries.type="USER"] Defines if the ACL item is for a user or a group (`USER` or `GROUP`). * @cfg {Object} acl.entries.rights Definition of access * Change access in addition to `copySourceAcl` and `inheritDestinationAcl`. */ /** * @private * @cfg {Number} [sleepTime=200] * The time in ms to recheck, if the process has finished. * For longer running copy processes this value can be increased to reduce the number of polling requests. * Not used when `useQuickCopy = true`. */ initialize: function (config) { var me = this; me.$super("sol.common.ix.FunctionBase", "initialize", [config]); me.sleepTime = (sol.common.ObjectUtils.isNumber(config.sleepTime)) ? config.sleepTime : 200; }, /** * Copies whole folder recursively. * @returns {String} The objId of the copied folder */ process: function () { var me = this, resolvedSource = me.source, ixConn, newObjId; me.checkSource(resolvedSource); ixConn = (me.asAdmin === true) ? ixConnectAdmin : ixConnect; if (!sol.common.RepoUtils.isObjId(me.source)) { // resolve handlebars if necessary me.useTemplate && (resolvedSource = me.resolveTemplate(me.source)); me.checkSource(resolvedSource); me.source = sol.common.RepoUtils.getObjId(resolvedSource, { resolveGuid: true }); } if (!sol.common.RepoUtils.isObjId(me.objId)) { me.objId = sol.common.RepoUtils.getObjId(me.objId, { resolveGuid: true }); } me.logger.info(["CopyFolderContents: source={0}, newParent={1}", me.source, me.objId]); if (me.useQuickCopy === true) { newObjId = me.executeQuickCopy(ixConn); } else { me.logger.debug("Use old synchronous copy process."); newObjId = me.executeBackgroundCopy(ixConn, [me.source], me.objId, me.name, true); } // change mask of the root object if (me.targetMask && newObjId) { me.changeBaseElementMask(newObjId, ixConn); } return newObjId; }, checkSource: function (source) { var str = String(source); if (str.trim() === "") { throw Error("InvalidArgument: 'source' parameter can not be empty"); } }, resolveTemplate: function (source) { var me = this, templateSord = me.provideTemplateSord(); return sol.create("sol.common.Template", { source: source }).apply(templateSord); }, provideTemplateSord: function () { var me = this; return sol.common.SordUtils.getTemplateSord(me.getSord(me.objId)); }, getSord: function (objId) { return sol.common.RepoUtils.getSord(objId); }, /** * @param {objId} newObjId * @param {de.elo.ix.client.IXConnection} ixConnection current ixConnection * @private */ changeBaseElementMask: function (newObjId, ixConnection) { var me = this, rootSord, changedSord; if (sol.common.SordUtils.docMaskExists(me.targetMask)) { me.logger.info(["switch mask of objId={0} to {1}", newObjId, me.targetMask]); rootSord = sol.common.RepoUtils.getSord(newObjId, { sordZ: SordC.mbLean }); changedSord = sol.common.SordUtils.changeMask(rootSord, me.targetMask, ixConnection); ixConnect.ix().checkinSord(changedSord, SordC.mbLean, LockC.NO); } else { me.logger.warn(["mask {1} doesn't exist", me.targetMask]); } }, executeQuickCopy: function (ixConn) { var me = this, sordProperties, detailProperties, srcSord, newSord, newAclItems, currentIxVersion, additionalMapItems, mapItems, blobItems, children, childrenIds; sordProperties = ["name", "desc", "kind", "objKeys", "type", "aclItems"]; detailProperties = ["sortOrder"]; srcSord = ixConn.ix().checkoutSord(me.source, SordC.mbAllIndex, LockC.NO); if (sol.common.SordUtils.isDocument(srcSord)) { me.logger.debug("Use old synchronous copy process for documents."); return me.executeBackgroundCopy(ixConn, [me.source], me.objId, me.name, true); } // when copyOnlyChildrenElements is true then checkout already existing sord object // each option will be ignored regarding the base element if (!me.copyOnlyChildrenElements) { newSord = sol.common.SordUtils.cloneSord(srcSord, { dstParentId: me.objId, memberNames: sordProperties, detailMemberNames: detailProperties, inheritDestinationAcl: me.inheritDestinationAcl, conn: ixConn }); if (me.name) { newSord.name = me.name; } if (me.acl && me.acl.entries && (me.acl.entries.length > 0)) { newAclItems = (me.acl.mode == "SET") ? [] : Array.prototype.slice.call(newSord.aclItems); me.acl.entries.forEach(function (aclEntry) { var accessCode, userId, userName, type; accessCode = sol.common.AclUtils.createAccessCode(aclEntry.rights); userId = (typeof aclEntry.userId !== "undefined") ? aclEntry.userId : ""; userName = (typeof aclEntry.userName !== "undefined") ? aclEntry.userName : ""; type = (aclEntry.type == "GROUP") ? AclItemC.TYPE_GROUP : AclItemC.TYPE_USER; if (userName == "$CURRENTUSER") { userName = String(ixConnect.loginResult.user.name); } newAclItems.push(new AclItem(accessCode, userId, userName, type)); }); newSord.aclItems = newAclItems; } if (me.metadata && (me.metadata.length > 0)) { additionalMapItems = sol.common.SordUtils.updateSord(newSord, me.metadata); } ixConn.ix().checkinSord(newSord, SordC.mbAllIndex, LockC.NO); mapItems = ixConn.ix().checkoutMap(MapDomainC.DOMAIN_SORD, srcSord.id, null, LockC.NO).items || []; if (additionalMapItems) { mapItems = mapItems.concat(additionalMapItems); } if (mapItems.length > 0) { ixConn.ix().checkinMap(MapDomainC.DOMAIN_SORD, newSord.id, newSord.id, mapItems, LockC.NO); } try { currentIxVersion = ixConnect.version; } catch (_) { currentIxVersion = "10.00.000"; } if ((blobItems = ixConn.ix().checkoutMap("formdata", srcSord.id, null, LockC.NO).items || []).length) { if (!sol.common.RepoUtils.checkVersion(currentIxVersion, "11.00.000")) { blobItems = [].slice.call(blobItems).map(me.cloneBlobItem); } ixConn.ix().checkinMap("formdata", newSord.id, newSord.id, blobItems, LockC.NO); } } else { // newSord is here the target sord object // we only need the sord id for the background job newSord = sol.common.RepoUtils.getSord(me.objId, { sordZ: SordC.mbOnlyId, connection: ixConn }); } children = sol.common.RepoUtils.findChildren(srcSord.id, { includeFolders: true, includeDocuments: true, includeReferences: true, sordZ: SordC.mbMin }, ixConn); if (children && (children.length > 0)) { childrenIds = children.map(function (child) { return String(child.id); }); me.copySourceAcl = (me.copySourceAcl !== undefined) ? me.copySourceAcl : false; me.inheritDestinationAcl = (me.inheritDestinationAcl === undefined) ? true : me.inheritDestinationAcl; me.logger.debug(["waitUntilFinished {0}", me.waitUntilFinished]); // client has the ability to decide whether {@link #useQuickCopy} works async or synchronized me.executeBackgroundCopy(ixConn, childrenIds, newSord.id, null, me.waitUntilFinished); } return newSord.id; }, cloneBlobItem: function (item) { var blob, stream; blob = Packages.org.apache.commons.io.IOUtils.toString( stream = item.getBlobValue().getStream(), java.nio.charset.StandardCharsets.UTF_8 ) .getBytes(java.nio.charset.StandardCharsets.UTF_8); stream.close(); return new MapValue(item.key, new FileData("text/plain", blob)); }, executeBackgroundCopy: function (ixConn, startIds, parentId, name, wait) { var me = this, dstObjId = null, navInfo, procInfo, jobState; navInfo = new NavigationInfo(); navInfo.startIDs = startIds; procInfo = new ProcessInfo(); procInfo.desc = "sol.common.ix.functions.CopyFolderContents"; procInfo.errorMode = ProcessInfoC.ERRORMODE_CRITICAL_ONLY; procInfo.procCopyElements = new ProcessCopyElements(); procInfo.procCopyElements.copyOptions = new CopyOptions(); if (me.name) { procInfo.procCopyElements.copyOptions.targetName = name; } if (me.copyOnlyWorkversion) { procInfo.procCopyElements.copyOptions.copyOnlyWorkversion = true; } if (me.copyOnlyBaseElement) { procInfo.procCopyElements.copyOptions.copyOnlyBaseElement = true; } else { procInfo.procCopyElements.copyOptions.copyStructuresAndDocuments = true; } procInfo.procCopyElements.copyOptions.newParentId = parentId; procInfo.procCopyElements.createMapping = wait; // Set permissions if (me.copySourceAcl != me.inheritDestinationAcl) { if (me.copySourceAcl) { procInfo.procCopyElements.copyOptions.keepOriginalPermissions = true; } if (me.inheritDestinationAcl) { procInfo.procCopyElements.copyOptions.takeTargetPermissions = true; } } me.logger.debug(["start copy process: startIds={0}, parentId={1}", startIds, parentId]); jobState = ixConn.ix().processTrees(navInfo, procInfo); if (wait) { me.logger.info(["wait for job: startIds={0}, parentId={1}", startIds, parentId]); jobState = sol.common.AsyncUtils.waitForJob(jobState.getJobGuid(), { connection: ixConn, interval: me.sleepTime }); dstObjId = jobState.procInfo.procCopyElements.copyResult.mapIdsSource2Copy.get(new java.lang.Integer(me.source)); } return dstObjId; } }); /** * @member sol.common.ix.functions.CopyFolderContents * @static * @inheritdoc sol.common.ix.FunctionBase#onEnterNode */ function onEnterNode(clInfo, userId, wFDiagram, nodeId) { var params, module; logger.enter("onEnterNode_sol.common.ix.functions.CopyFolderContents", { flowId: wFDiagram.id, nodeId: nodeId }); sol.common.WfUtils.checkMainAdminWf(wFDiagram); params = sol.common.WfUtils.parseAndCheckParams(wFDiagram, nodeId); params.objId = wFDiagram.objId; module = sol.create("sol.common.ix.functions.CopyFolderContents", params); module.process(); logger.exit("onEnterNode_sol.common.ix.functions.CopyFolderContents"); } /** * @member sol.common.ix.functions.CopyFolderContents * @static * @inheritdoc sol.common.ix.FunctionBase#onExitNode */ function onExitNode(clInfo, userId, wFDiagram, nodeId) { var params, module; logger.enter("onExitNode_sol.common.ix.functions.CopyFolderContents", { flowId: wFDiagram.id, nodeId: nodeId }); sol.common.WfUtils.checkMainAdminWf(wFDiagram); params = sol.common.WfUtils.parseAndCheckParams(wFDiagram, nodeId); params.objId = wFDiagram.objId; module = sol.create("sol.common.ix.functions.CopyFolderContents", params); module.process(); logger.exit("onExitNode_sol.common.ix.functions.CopyFolderContents"); } /** * @member sol.common.ix.functions.CopyFolderContents * @method RF_sol_function_CopyFolderContents * @static * @inheritdoc sol.common.ix.FunctionBase#RF_FunctionName */ function RF_sol_function_CopyFolderContents(iXSEContext, args) { var params, module, objId; logger.enter("RF_sol_function_CopyFolderContents", args); params = sol.common.ix.RfUtils.parseAndCheckParams(iXSEContext, arguments.callee.name, args, "objId", "source", "copySourceAcl", "inheritDestinationAcl"); try { sol.common.ix.RfUtils.checkMainAdminRights(iXSEContext.user, params); } catch (e) { params.asAdmin = false; } module = sol.create("sol.common.ix.functions.CopyFolderContents", params); objId = module.process(); logger.exit("RF_sol_function_CopyFolderContents"); return sol.common.JsonUtils.stringifyAll(objId); }