importPackage(Packages.de.elo.ix.client); //@include lib_Class.js //@include lib_moment.js //@include lib_sol.common.DateUtils.js //@include lib_sol.common.SordUtils.js //@include lib_sol.common.DateUtils.js //@include lib_sol.common.AclUtils.js //@include lib_sol.common.AsyncUtils.js //@include lib_sol.common.UserUtils.js //@include lib_sol.common.Map.js //@include lib_sol.common.ix.DynAdHocFlowUtils.js //@include lib_sol.common.ix.FunctionBase.js var logger = sol.create("sol.Logger", { scope: "sol.common.ix.functions.ChangeUser" }); /** * Changes the user of a workflow node. * * The user will be read from an index field (`fromIndex`), a map field (`fromMap`) or from a workflow map field (`fromWfMap`). * If more then one was defined, the priority is `fromIndex` -> `fromMap` -> `fromWfMap`. * The same rule applies for `defaultFromIndex` -> `defaultFromMap`. The defaultFrom-properties can be used to read a fallback user * from a field, if the user defined in a fromIndex-field was not valid. * If no user was found, the default user will be used. * * The WF-Map Field `CHANGEUSER_CHANGEDUSERBY` is filled depending on which source was used for setting the user if logFallbackMode is true. * "FROMFIELD" -> User defined in a configured `from*-property` was used * "DEFAULTFIELD" -> Fallback-user defined in a configured `defaultFrom*-property` was used * "SUPERVISOR" -> `supervisor-property` was used * "DEFAULT" -> `default-property` was used * "ADMINISTRATOR" -> Administrator was used because none of the other users was valid. * This can be especially useful, if you wish to inform a workflow-form user that he/she only received the form because of a fallback * * The node can be specified by the nodes ID or name. * If booth are defined, the ID will be used. * If `changeCurrentNode` is true, the node with the currentNodeId will be altered. * If neither `nodeId`, nor `nodeName` is specified, the script tries to alter all direct successor person nodes. * * # As workflow node * * - `ObjId` is set based on the element that the workflow is attached to. * - `CurrentNodeId` is set based on the workflow node which executes the script. * * Following configuration should be applied to the comments field. * * { * "defaultUser": "ELO Service", * "nodeId": 7, * "fromIndex": "OWNER", * "userRights": { "r": true } * } * * # Prerequisites * This function modul can only be used in workflow scripts. * * @author PZ, ELO Digital Office GmbH * @version 1.0 * * @eloix * @requires sol.common.SordUtils * @requires sol.common.WfUtils * @requires sol.common.WfMap * @requires sol.common.MapTable * @requires sol.common.ix.FunctionBase * @requires sol.common.ix.DynAdHocFlowUtils */ sol.define("sol.common.ix.functions.ChangeUser", { extend: "sol.common.ix.FunctionBase", requiredConfig: ["wFDiagram", "currentNodeId", "defaultUser"], /** * @cfg {de.elo.ix.client.WFDiagram} wFDiagram (required) * The WFDiagram to which the changes should me applied to */ wFDiagram: undefined, /** * @cfg {Number} currentNodeId (required) * The ID of the current node. * It is used to find the successing person nodes if no ID or name is defined, or to change the user of the node itself, if changeCurrentNode is true */ currentNodeId: undefined, /** * @cfg {String} defaultUser (required) * The user that should be set if none is specified/found */ defaultUser: undefined, /** * @cfg {String} nodeId * Find node to change by node.id */ nodeId: undefined, /** * @cfg {String} nodeName * Find node to change by node.name */ nodeName: undefined, /** * @cfg {String} fromIndex * Read user from a group field */ fromIndex: undefined, /** * @cfg {String} fromMap * Read user from a map field */ fromMap: undefined, /** * @cfg {String} fromWfMap * Read user from a workflow map field */ fromWfMap: undefined, /** * @cfg {String} fromWfMapTable * Read user from workflow map table */ fromWfMapTable: undefined, /** * @cfg {String} defaultFromIndex * Read default user from a group field */ defaultFromIndex: undefined, /** * @cfg {String} defaultFromMap * Read default user from a map field */ defaultFromMap: undefined, /** * @cfg {String} defaultFromWfMap * Read default user from a workflow map field */ defaultFromWfMap: undefined, /** * @cfg {String} defaultFromWfMapTable * Read default user from workflow map table */ defaultFromWfMapTable: undefined, /** * @cfg {String} [previousUserWfMapFieldName=PREVIOUS_USER] * Name of the previous user workflow map field */ /** * @cfg {Boolean} [changeCurrentNode=false] * if true, the user of the current node will be changed, regardless if an ID or name is defined; * of course this will only work on nodes with type = WFNodeC.TYPE_PERSONNODE */ changeCurrentNode: false, /** * @cfg {Integer} [skipNonUserNodes=undefined] * if set to a value > 0, x nodes will be skipped in search for (a) user node(s) * this is useful, if you can't use ChangeUser directly before a user-node but have to put some * other command e.g. ChangeRights inbetween. * Attention: This does not traverse multiple routes. */ skipNonUserNodes: undefined, /** * @cfg {Boolean} [logFallbackMode=false] * Logs the user change fallback mode to the WF-Map Field `CHANGEUSER_CHANGEDUSERBY` */ logFallbackMode: false, /** * @cfg {Object} * Rights that will be added for the node user to the workflow object and it's children * * Example for read access: * * { r: true } */ userRights: undefined, /** * @cfg {Boolean} [supervisor=false] * Sets the supervisor of the given user as node user */ supervisor: false, /** * @cfg {Number} [userDelayDays=0] * The person node might be displayed to the user delayed by this number of days. */ /** * @cfg {Object[]} nodeEscalations Node escalations * @cfg {Object} nodeEscalations.user Node escalation user * @cfg {String} nodeEscalations.user.value Node escalation user name * @cfg {Boolean} [nodeEscalations.user.supervisor=false] Escalate to the users supervisor * @cfg {Number} nodeEscalations.timeLimitMinutes Node escalation minutes * * If no user has been set, the new node user is used. * * Example: * { * "fromWfMapTable": "USER", * "defaultUser": "Administrator", * "nodeEscalations": [{ * "user": { * "supervisor": true * }, * "timeLimitMinutes": 1440 * }] * } */ nodeEscalations: undefined, initialize: function (config) { var me = this; me.$super("sol.common.ix.FunctionBase", "initialize", [config]); }, getUserFromField: function (fromIndex, fromMap, fromWfMap, fromWfMapTable) { var me = this, sord, user, mapItems; if (fromIndex) { sord = ixConnect.ix().checkoutSord(me.wFDiagram.objId, EditInfoC.mbSord, LockC.NO).sord; user = sol.common.SordUtils.getObjKeyValue(sord, fromIndex); } else if (fromMap) { mapItems = ixConnect.ix().checkoutMap(MapDomainC.DOMAIN_SORD, me.wFDiagram.objId, [fromMap], LockC.NO).items; if (mapItems && mapItems.length > 0) { user = mapItems[0].value; } } else if (fromWfMap) { mapItems = ixConnect.ix().checkoutMap(MapDomainC.DOMAIN_WORKFLOW_ACTIVE, me.wFDiagram.id, [fromWfMap], LockC.NO).items; if (mapItems && mapItems.length > 0) { user = mapItems[0].value; // add removing the first item, to enable 'lists' of users, where each call of this function uses the first from the list and disposes it } } else if (fromWfMapTable) { user = sol.common.ix.DynAdHocFlowUtils.shiftUser(me.wFDiagram.id, me.wFDiagram.objId, { userNameKey: fromWfMapTable, previousUserNameKey: me.previousUserWfMapFieldName, currentUserKey: me.currentUserKey }); } return user; }, findNextUserNodes: function (wf, cur, max) { var result = [], nodes, type = WFNodeC.TYPE_PERSONNODE; do { nodes = sol.common.WfUtils.getSuccessorNodes(wf, cur); } while ( max-- && !Array.isArray( // while cur is a nodeId and not an array cur = ( (nodes.length === 1 && (sol.common.WfUtils.getSuccessorNodes(wf, cur, type).length === 0)) // if the found node is a single node but not a user node ? nodes[0].id // set cur to successor node id : result = sol.common.WfUtils.getSuccessorNodes(wf, cur, type) // set nodes (& end the loop) ) ) ); return result; }, /** * Change the node user. */ process: function () { var me = this, user, userNodes, i, node, oldUser, newUser, userExists, changedUserMode = "", wfMap, maxSkipCount, userDelayDateIso; if (me.changeCurrentNode) { userNodes = [sol.common.WfUtils.getNode(me.wFDiagram, me.currentNodeId)]; } else if (me.nodeId) { userNodes = [sol.common.WfUtils.getNode(me.wFDiagram, me.nodeId)]; } else if (me.nodeName) { userNodes = [sol.common.WfUtils.getNodeByName(me.wFDiagram, me.nodeName)]; if (!userNodes || (userNodes.length == 0) || !userNodes[0]) { throw "Node '" + me.nodeName + "' not found"; } } else if (me.skipNonUserNodes) { maxSkipCount = (+me.skipNonUserNodes); if (maxSkipCount >= 0) { userNodes = me.findNextUserNodes(me.wFDiagram, me.currentNodeId, maxSkipCount); } } else { userNodes = sol.common.WfUtils.getSuccessorNodes(me.wFDiagram, me.currentNodeId, WFNodeC.TYPE_PERSONNODE); } user = me.getUserFromField(me.fromIndex, me.fromMap, me.fromWfMap, me.fromWfMapTable); if (sol.common.UserUtils.userExists(user)) { changedUserMode = "FROMFIELD"; } else { user = me.getUserFromField(me.defaultFromIndex, me.defaultFromMap, me.defaultFromWfMap, me.defaultFromWfMapTable); if (sol.common.UserUtils.userExists(user)) { changedUserMode = "DEFAULTFIELD"; } else { user = undefined; } } if (me.supervisor && user) { user = sol.common.UserUtils.getSupervisor(user); if (sol.common.UserUtils.userExists(user)) { changedUserMode = "SUPERVISOR"; } else { user = undefined; } } if (!user) { user = me.defaultUser; if (sol.common.UserUtils.userExists(user)) { changedUserMode = "DEFAULT"; } else { me.logger.warn(["User/Group '{0}' defined in defaultUser-property is not valid!", me.defaultUser]); } } if (userNodes.length == 0) { throw "There aren't any user nodes to change the node user: currentNodeId=" + me.currentNodeId; } for (i = 0; i < userNodes.length; i++) { node = userNodes[i]; if (!node) { me.logger.warn(["userNodes[{0}] is empty", i]); continue; } oldUser = node.userName; newUser = user; userExists = sol.common.UserUtils.userExists(user); if (!userExists) { newUser = 0; changedUserMode = "ADMINISTRATOR"; } sol.common.WfUtils.changeNodeUser(node, newUser, { changeDesignDepartment: true }); sol.common.WfUtils.setNodeEscalations(node, me.nodeEscalations, newUser); if (me.userDelayDays) { userDelayDateIso = sol.common.SordUtils.nowIsoForConnection(ixConnect, { add: { days: me.userDelayDays } }); node.userDelayDateIso = userDelayDateIso; } if (me.userRights && userExists) { sol.common.AclUtils.changeRightsInBackground(me.wFDiagram.objId, { mode: "ADD", users: [user], rights: me.userRights }); } if (me.logFallbackMode) { wfMap = sol.create("sol.common.WfMap", { flowId: me.wFDiagram.id, objId: me.wFDiagram.objId }); wfMap.read(); wfMap.setValue("CHANGEUSER_CHANGEDUSERBY", changedUserMode); wfMap.write(); } me.logger.info(["changed NodeUser from '{0}' to '{1}' using mode '{2}'", oldUser, newUser, changedUserMode]); } } }); /** * @member sol.common.ix.functions.ChangeUser * @static * @inheritdoc sol.common.ix.FunctionBase#onEnterNode */ function onEnterNode(clInfo, userId, wFDiagram, nodeId) { var params, module; logger.enter("onEnterNode_ChangeUser", { flowId: wFDiagram.id, nodeId: nodeId }); sol.common.WfUtils.checkMainAdminWf(wFDiagram); params = sol.common.WfUtils.parseAndCheckParams(wFDiagram, nodeId, "defaultUser"); params.wFDiagram = wFDiagram; params.currentNodeId = nodeId; params.clInfo = clInfo; module = sol.create("sol.common.ix.functions.ChangeUser", params); module.process(); logger.exit("onEnterNode_ChangeUser"); } /** * @member sol.common.ix.functions.ChangeUser * @static * @inheritdoc sol.common.ix.FunctionBase#onExitNode */ function onExitNode(clInfo, userId, wFDiagram, nodeId) { var params, module; logger.enter("onExitNode_ChangeUser", { flowId: wFDiagram.id, nodeId: nodeId }); sol.common.WfUtils.checkMainAdminWf(wFDiagram); params = sol.common.WfUtils.parseAndCheckParams(wFDiagram, nodeId, "defaultUser"); params.wFDiagram = wFDiagram; params.currentNodeId = nodeId; params.clInfo = clInfo; module = sol.create("sol.common.ix.functions.ChangeUser", params); module.process(); logger.exit("onExitNode_ChangeUser"); }