//@include lib_Class.js //@include lib_sol.common.SordUtils.js //@include lib_sol.common.RepoUtils.js //@include lib_sol.common.AclUtils.js //@include lib_sol.common.AsyncUtils.js //@include lib_sol.common.SordTypeUtils.js //@include lib_sol.common.IxUtils.js //@include lib_sol.common.TranslateTerms.js //@include lib_sol.common.Template.js //@include lib_sol.common.ix.ActionBase.js var logger = sol.create("sol.Logger", { scope: "sol.common.ix.actions.Standard" }); /** * An generic action to do most common tasks. * * # Prefill metadata * The metadata of an element can be prefilled. There are several possible configurations. * For the configuration the {@link #$metadata} property will be used. * * ## Special properties (always) * * - owner: The owner of the element can be set to the connection user (only used on new elements) * - solType: The field `SOL_TYPE` can be set to a fixed value * * ## Fixed values (always) * The ObjKeys of an element can always be set to fixe values by providing a `key` and a fix `value`. * * ## Copy data from a source element * Planned for future versions * * * @author PZ, ELO Digital Office GmbH * @version 1.04.000 * * @eloix * @requires sol.common.SordUtils * @requires sol.common.RepoUtils * @requires sol.common.AclUtils * @requires sol.common.AsyncUtils * @requires sol.common.SordTypeUtils * @requires sol.common.IxUtils * @requires sol.common.TranslateTerms * @requires sol.common.Template * @requires sol.common.ix.ActionBase */ sol.define("sol.common.ix.actions.Standard", { extend: "sol.common.ix.ActionBase", _SordZ: SordC.mbAllIndex, /** * @cfg {String} $name (optional) The name of the action (returned by {@link #getName}). If not set, the name will be 'sol.common.ix.actions.Standard'. */ /** * @cfg {Object} $new (optional) Definition for creating a new element (see also {@link #objId}). * @cfg {String} $new.name (optional) Handlebars syntax. * @cfg {String} $new.mask (optional) If a new element is created (not from template) this mask will be used. Default will be `DocMaskC.GUID_FOLDER`. * @cfg {String} $new.type (optional) If a new element is created (not from template) this type will be used. * @cfg {Object} $new.target (optional) Default will be 'DEFAULT' mode * @cfg {String} $new.target.mode (optional) Supported are DEFAULT (chaos cabinet), SELECTED ({@link #objId} as target) and FIND (determine target by search) * @cfg {String} $new.target.params (optional) Required, if `mode=FIND` is used (for configuration see {@link sol.common.RepoUtils#getObjIdByIndex}) * @cfg {Object} $new.template (optional) Definition for creating an element by copying a template structure. * @cfg {String} $new.template.objId (optional) Arcpath, objId or GUID of a template. This has priority over '$new.template.base' and '$new.template.name'. * @cfg {String} $new.template.base (optional) The base folder (arcpath, objId or GUID) containing the templates. If used, '$new.template.name' has to be defined. * @cfg {String} $new.template.name (optional) The name of a sub folder (the template) in the base folder. If used, '$new.template.base' has to be defined. */ /** * @cfg {Object} $metadata (optional) Definition of additional metadata * @cfg {String} $metadata.solType (optional) The SOL_TYPE of the object * @cfg {Object} $metadata.owner (optional) * @cfg {Boolean} $metadata.owner.fromConnection (optional) Sets the elements owner to the connection user (only for new elements) * @cfg {Object[]} $metadata.objKeys (optional) Sets the elements ObjKeys * @cfg {String} $metadata.objKeys.key The ObjKeys name * @cfg {String} $metadata.objKeys.value The ObjKeys value */ /** * @cfg {Object} $permissions (optional) * @cfg {String} $permissions.mode (optional) Supported values are "ADD", "SET" and "REMOVE". See {@link sol.common.AclUtils AclUtils} for further documentation and default. * @cfg {Object} $permissions.inherit (optional) If `$new.target.mode=DEFAULT` is used, this parameter will be ignored. * @cfg {Boolean} $permissions.inherit.fromDirectParent (optional) The parent ACL will be used. Has priority over `solutionObjectTypes`. * @cfg {String[]} $permissions.inherit.solutionObjectTypes (optional) Searches in hierarchy for the specified SOL_TYPES and applies those objects ACL. * @cfg {Boolean} [$permissions.copySource=false] (optional) Has only an effect, if a new element is created from a template. The ACL of the template will be copied.Has priority over `fromDirectParent`. */ /** * @cfg {Object} $wf * @cfg {String} $wf.name (optional) Handlebars syntax supported. If not set, the sord name will be used. * @cfg {Object} $wf.template Defines the workflow, which should be started. Either name or key has to be defined. * @cfg {String} $wf.template.name (optional) The name of the workflow template which should be started. This has priority over `$wf.template.key`. * @cfg {String} $wf.template.key (optional) The field to read the name of the workflow template which should be started from. */ /** * @cfg {Object[]} $events (optional) * @cfg {String} $events.id See {@link sol.common.IxUtils#CONST.EVENT_TYPES}. Currently supported: REFRESH, GOTO, DIALOG and FEEDBACK. * @cfg {String} $events.onWfStatus (optional) */ /** * @cfg {String} objId (optional) Start the action on an existing element. If there is a {@link #$new} configuration with `target` set to `mode=SELECTD` this will be used as target. */ //requiredConfig: [], initialize: function (config) { var me = this; me.$super("sol.common.ix.ActionBase", "initialize", [config]); }, getName: function () { var me = this; return me.$name || "sol.common.ix.actions.Standard"; }, /** * */ process: function () { var me = this; me._ctx = {}; // used to carry data me._state = { dirty: false }; // used to track internal state me.initializeElement(); me.editMetadata(); me.saveChanges(); me.applyPermissions(); me.startWorkflow(); me.addEvents(); }, /** * Creates a new element, either from scratch or by copying a template, if {@link #$new} is defined. * If there is no configuration for creating an element, an existing element will be used. * The new `objId` will be saved to the execution context (`_ctx.objId`). * If {@link #$new} is not defined the given objId will be used as _ctx.objId. */ initializeElement: function () { var me = this; if (me.$new && me.$new.template) { // create element from template me._ctx.objId = me.createElementFromTemplate(); me._state.new = true; } else if (me.$new) { // create new element me._sord = me.createElementFromScratch(); me._state.new = true; } else if (me.objId) { // use existing element me._ctx.objId = me.objId; me._state.existing = true; } else { throw "IllegalArgumentException: at least an 'objId' has to be defined"; } }, /** * Applies changes to the elements metadata. */ editMetadata: function () { var me = this, data = []; if (!me._sord && me._ctx.objId && me.$metadata) { me._sord = sol.common.RepoUtils.getSord(me._ctx.objId, { sordZ: me._SordZ }); } if (me._sord && me.$metadata) { if (me.$metadata.owner && (me._state.new === true)) { if (me.$metadata.owner.fromConnection) { data.push({ type: "SORD", key: "ownerId", value: me.user.id }); } } if (me.$metadata.solType) { data.push({ type: "GRP", key: "SOL_TYPE", value: me.$metadata.solType }); } if (me.$metadata.objKeys && (me.$metadata.objKeys.length > 0)) { me.$metadata.objKeys.forEach(function (objKey) { if (objKey.key && objKey.value) { data.push({ type: "GRP", key: objKey.key, value: objKey.value }); } }); } if (me.$metadata.mapItems && (me.$metadata.mapItems.length > 0)) { me.$metadata.mapItems.forEach(function (mapItem) { if (mapItem.key && mapItem.value) { data.push({ type: "MAP", key: mapItem.key, value: mapItem.value }); } }); } if (data.length > 0) { me._mapitems = sol.common.SordUtils.updateSord(me._sord, data); me._state.dirty = true; } } }, /** * Saves the sord changes or the new sord (indicated by the `_dirty` flag) to the database. */ saveChanges: function () { var me = this; if (me._sord && me._state.dirty) { me._ctx.objId = ixConnect.ix().checkinSord(me._sord, me._SordZ, LockC.NO); if (me._mapitems) { ixConnect.ix().checkinMap(MapDomainC.DOMAIN_SORD, me._sord.id, me._sord.id, me._mapitems, LockC.NO); } } me._sord = null; me._mapitems = null; me._state.dirty = false; }, /** * Applies the permissions to the opbject. */ applyPermissions: function () { var me = this, apply = false, params, modeParam, inheritParam; if (!me.$permissions) { return; } // '$permissions.copySource' is used by (and only by) 'createElementFromTemplate' if (me.$permissions.inherit && !me._state.chaos) { // skip if element is in chaos cabinet if (me.$permissions.inherit.fromDirectParent && !me._state.permissionsAlreadyInheritedFromParent) { // skip, if already processed by 'createElementFromTemplate' inheritParam = { fromDirectParent: true }; apply = true; } else if (me.$permissions.inherit.solutionObjectTypes) { inheritParam = { solutionObjectTypes: me.$permissions.inherit.solutionObjectTypes }; apply = true; } } if (me.$permissions.mode && (me.$permissions.mode == "ADD" || me.$permissions.mode == "SET" || me.$permissions.mode == "REMOVE")) { modeParam = me.$permissions.mode; } if (apply) { params = { mode: modeParam, inherit: inheritParam }; me.checkAccessRights(me._ctx.objId); sol.common.AclUtils.changeRightsInBackground(me._ctx.objId, params); } }, startWorkflow: function () { var me = this, wfName, flowId; if (!me.$wf || !me.$wf.template) { throw "IllegalArgumentException: a '$wf.template' has to be defined"; } if (!me.$wf.template.name && !me.$wf.template.key) { throw "IllegalArgumentException: at least '$wf.template.name' or '$wf.template.key' has to be defined"; } wfName = me.createWorkflowName(); if (me.$wf.template.name) { flowId = me.$super("sol.common.ActionBase", "startWorkflow", [me._ctx.objId, me.$wf.template.name, wfName]); } else if (me.$wf.template.key) { flowId = me.startMaskStandardWorkflow(me._ctx.objId, { field: me.$wf.template.key, name: wfName }); } me._ctx.flowId = flowId; }, addEvents: function () { var me = this; if (me.$events && (me.$events.length > 0)) { me.$events.forEach(function (event) { var on, checkout; if (event.onWfStatus && me._ctx.flowId) { on = { type: "WF_STATUS", value: event.onWfStatus, flowId: me._ctx.flowId }; } switch (event.id) { case sol.common.IxUtils.CONST.EVENT_TYPES.REFRESH: me.addRefreshEvent(me._ctx.objId, on); break; case sol.common.IxUtils.CONST.EVENT_TYPES.GOTO: checkout = (event.onWfStatus == "CHECKOUT"); me.addGotoIdEvent(me._ctx.objId, checkout, on); break; case sol.common.IxUtils.CONST.EVENT_TYPES.DIALOG: me.addWfDialogEvent(me._ctx.flowId, { objId: me._ctx.objId, title: me._ctx.wfName || me._ctx.name, dialogId: me.getName() }, on); break; case sol.common.IxUtils.CONST.EVENT_TYPES.FEEDBACK: me.addFeedbackEvent(event.message, null, null, on); break; default: me.logger.warn(["event type {0} is not supported", event.id]); } }); } }, createElementFromTemplate: function () { var me = this, templateId, targetId, copyACL, inheritACL, objId; if (me.$new.template.objId) { templateId = me.$new.template.objId; } else if (me.$new.template.base && me.$new.template.name) { templateId = sol.common.RepoUtils.getObjIdFromRelativePath(me.$new.template.base, "/" + me.$new.template.name); } else { throw "IllegalArgumentException: at least a '$new.template.objId' has to be defined"; } targetId = me.getTargetId(); me._state.fromTemplate = true; me._state.chaos = (targetId === "0"); // force 'copyAcl' if element will be created in chaos cabinet to avoid copy error copyACL = (me._state.chaos || (me.$permissions && (me.$permissions.copySource === true))) ? true : false; inheritACL = (me._state.chaos || (me.$permissions && me.$permissions.inherit && (me.$permissions.inherit.fromDirectParent === false))) ? false : true; if (inheritACL) { me._state.permissionsAlreadyInheritedFromParent = true; } me.checkAccessRights(templateId); if (!me._state.chaos) { me.checkAccessRights(targetId, { r: true, l: true }); } objId = sol.common.IxUtils.execute("RF_sol_function_CopyFolderContents", { objId: targetId, source: templateId, copySourceAcl: copyACL, inheritDestinationAcl: inheritACL, name: me.createElementName(), useQuickCopy: true, acl: { mode: "ADD", entries: [ { userName: "$CURRENTUSER", rights: { r: true, w: true, d: true, e: true, l: true, p: true } } ] } }); return objId; }, createElementFromScratch: function () { var me = this, targetId, mask, sord, type; targetId = me.getTargetId(); mask = me.getMask(); me._state.fromScratch = true; me._state.chaos = (targetId === "0"); if (!me._state.chaos) { me.checkAccessRights(targetId, { r: true, l: true }); } sord = ixConnect.ix().createSord(targetId, mask, EditInfoC.mbSord).sord; sord.name = me.createElementName() || sord.guid; type = me.getType(); if (type) { sord.type = type; } sol.common.SordUtils.addRights(sord, { users: ["$CURRENTUSER"] }); me._state.dirty = true; return sord; }, checkAccessRights: function (objId, rights) { var me = this, hasAccess, rightsStr, msg; rights = rights || { r: true }; hasAccess = sol.common.AclUtils.hasEffectiveRights(objId, { rights: rights }); if (!hasAccess) { rightsStr = ((rights.r === true) ? "R" : "") + ((rights.w === true) ? "W" : "") + ((rights.d === true) ? "D" : "") + ((rights.e === true) ? "E" : "") + ((rights.l === true) ? "L" : "") + ((rights.p === true) ? "P" : ""); msg = "IllegalAccessException: missing permissions (" + rightsStr + ") on '" + objId + "'"; me.logger.warn(msg); throw msg; } }, createElementName: function () { var me = this, sord; if (!me._ctx.name) { if (me._ctx.objId) { sord = sol.common.RepoUtils.getSord(me._ctx.objId, { sordZ: SordC.mbMin }); me._ctx.name = sord.name; } else if (me.$new.name) { me._ctx.name = sol.create("sol.common.Template", { source: me.$new.name }).apply({ date: new Date(), actionId: me.actionId }); } } return me._ctx.name; }, createWorkflowName: function () { var me = this; if (!me._ctx.wfName) { if (me.$wf.name) { me._ctx.wfName = sol.create("sol.common.Template", { source: me.$wf.name }).apply({ date: new Date(), actionId: me.actionId }); } else { me._ctx.wfName = me.createElementName(); } } return me._ctx.wfName; }, getTargetId: function () { var me = this, paramsObj, targetId = null; if (me.$new && me.$new.target) { switch (me.$new.target.mode) { case "SELECTED": targetId = me.objId || "0"; break; case "FIND": paramsObj = JSON.parse(me.$new.target.params); targetId = sol.common.RepoUtils.getObjIdByIndex(paramsObj); break; default: targetId = "0"; break; } } else if (me.$new) { targetId = "0"; } return targetId; }, getMask: function () { var me = this; return (me.$new.mask) ? me.$new.mask : null; }, getType: function () { var me = this, type; try { if (me.$new.type) { type = sol.common.SordTypeUtils.getSordTypeId(me.$new.type); } } catch (ex) { me.logger.warn(["could not determine sord type id for name '{0}'", me.$new.type]); } return (type) ? type : null; } }); /** * @member sol.common.ix.actions.Standard * @method RF_sol_common_action_Standard * @static * @inheritdoc sol.common.ix.ActionBase#RF_FunctionName */ function RF_sol_common_action_Standard(ec, args) { function getTplSord(objId) { try { if (objId) { return sol.common.SordUtils.getTemplateSord(ixConnect.ix().checkoutSord(objId, SordC.mbAllIndex, LockC.NO)).sord; } } catch (ex) { // ignore // this could be due to a 'dynamic' objId, which will be evaluated later } return { id: null }; } logger.enter("RF_sol_common_action_Standard", args); var config, action, result, templatingData; config = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, args); //remove following line as soon as $templating|$sordInTemplating is available in config-app config.$templating = config.$templating || {}; config.$templating.$options = { exposeSord: true, emptyNonRenderedValues: true }; config._$disableParamsTemplating = config._$disableParamsTemplating === undefined || config._$disableParamsTemplating; // Actionbase will skip standard templating based on this property because we take care of templating here templatingData = { objId: config.objId, type: config.$templating.$type, tree: config.$templating.$tree, preconditions: config.$templating.$preconditions }; if (config.$templating.$options.exposeSord) { templatingData.sord = getTplSord(config.objId); } config = sol.common.TemplateUtils.render(config, templatingData, { emptyNonRendered: config.$templating.$options.emptyNonRenderedValues }); if (config._$disableParamsTemplating === true) { config.$templating = undefined; } config.ci = ec.ci; config.user = ec.user; action = sol.create("sol.common.ix.actions.Standard", config); result = action.execute(); logger.exit("RF_sol_common_action_Standard", result); return result; }