// PhantomJS doesn't support bind yet Function.prototype.bind = Function.prototype.bind || function (thisp) { var fn = this; return function () { return fn.apply(thisp, arguments); }; }; import Protocols from './protocols.js' import Wizard from './wizard.js' class SmartOrg { /** * Any interaction with the SmartOrg API starts by creating a SmartOrg object. * @example * // If your API is at https://localhost/kirk * var endpoint = "https://localhost"; * var path = "kirk"; * var smartorg = new SmartOrg(endpoint, path); * * @param {string} endpoint The SmartOrg server endpoint * @param {string} path_ The path where the API is accessible */ constructor(endpoint, path_) { this.protocols = new Protocols(endpoint, path_, this); this.wizard = new Wizard(this.protocols); console.info("SmartOrg Javascript API."); console.log("Manhattan Build"); console.log("version 2.2"); this.networkErrorHandler = null; } onNetworkError(callBackFunction) { this.networkErrorHandler = callBackFunction; } /** @typedef {object} UserInfo * @property {string} uid - User ID generated from server */ /** * @external Promise * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise Promise} */ /** * This callback is called when the result is loaded. * * @callback PromiseAuthenticateCallbackSuccess * @param {UserInfo} ret - The result is loaded. */ /** * This callback is called when the result fails to load. * * @callback PromiseAuthenticateCallbackError * @param {Error} err - The error that occurred while loading the result. */ /** Resolves with a {@link PromiseAuthenticateCallbackSuccess}, fails with a {@link PromiseAuthenticateCallbackError} * * @typedef {Promise} PromiseAuthenticate */ /** * Authenticate the user using the credentials provided. * This is the first thing that needs to happen after the SmartOrg object * has been created. * * @param {Object} credentials The credentials with which the user is to be authenticated. * @param {string} credentials.username The username * @param {string} credentials.password The password * @returns {PromiseAuthenticate} A promise to authenticate * * @example * // Let's assume the SmartOrg API is accessible at https://localhost/kirk * var smartorg = new SmartOrg("https://localhost","kirk"); * var username = ...; // get the username from somewhere * var password = ...; // get the password from somewhere * smartorg.authenticate({'username': username, 'password': password}) * .then(function (userInfo) { * console.info("user ID " + userInfo.uid + " logged in"); * }) * .catch(function (err) { * console.error("Error occurred "+err); * }); */ authenticate(credentials) { this.protocols.makeCredentials(credentials); var path_ = this.protocols._getPath('framework/login'); path_ = `${path_}/${credentials.username}`; return this.protocols.apiGet(path_); } /** @typedef {object} Template * @property {string} name - Name of this template * @property {string} hasPlatform - Does this template have a platform capability? * @property {object} [info] - Information about this template * @property {string} [info.Creator] - Name of the creator of this template * @property {string} [info.CreatorLink] - Link to the template creator's website * @property {string} [info.Description] - Description of this template * @property {string} [info.Email] - Email id of template creator */ /** * @external Promise * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise Promise} */ /** * This callback is called when the result is loaded. * * @callback PromiseTemplatesCallbackTemplateSuccess * @param {Template[]} ret - The result is loaded. */ /** * This callback is called when the result fails to load. * * @callback PromiseTemplatesCallbackTemplateError * @param {Error} err - The error that occurred while loading the result. */ /** Resolves with a {@link PromiseTemplatesCallbackTemplateSuccess}, fails with a {@link PromiseTemplatesCallbackTemplateError} * * @typedef {Promise} PromiseTemplates */ /** * Obtain all the templates applicable to a node. * @param {string} nodeID The ID of the node for which templates are to be fetched. * Normally, this would result in all the templates in the system, unless the administrator has restricted * the templates that are visible in the portfolio of which this node is a part. In that case, * only the restricted templates will be returned. * @returns {PromiseTemplates} A promise to provide the list of templates * @example * smartorg.templatesFor(templatesNodeID) * .then(function (ret) { * console.warn(ret); * // ret[0] --> First Template * // ret[0].name --> Name of first template * // ret[0].hasPlatform --> Does this have a platform? * // ret[0].info.Creator --> Optional name of creator of template * // ret[0].info.CreatorLink --> Optional link to creator website * // ret[0].info.Description --> Optional description of template * // ret[0].info.Email --> Optional email id of creator of template * }) * .catch(function (err) { * console.error(err); * }) */ templatesFor(nodeID) { var path_ = this.protocols._getPath('domain/templates'); path_ = `${path_}/${nodeID}`; return this.protocols.apiGet(path_); } /** * Get all templates. Maybe duplicated to templatesFor when node * id is empty. * * @returns {*} */ getAllTemplates() { var path_ = this.protocols._getPath('domain/alltemplates'); path_ = `${path_}`; return this.protocols.apiGet(path_); } /** * @typedef {object} AclGroup * @property {Array<string>} editors - Array of user ids of editors * @property {Array<string>} portfolioAdmins - Array of user ids of portfolio administrators * @property {Array<string>} viewers - Array of user ids of viewers */ /** * @typedef {object} Acl * @property {AclGroup} group - Group Access Control List * @property {string} owner - User ID of owner of portfolio * @property {AclGroup} user - What's this for? */ /** * @typedef {object} Node * @property {string} name - Name of this node * @property {string} _id - ID of this node * @property {string} _rev - Revision number of this node * @property {string} data - A pointer to the data node of the portfolio * @property {string} treeID - The name of the tree to which this node belongs * @property {Array<string>} children - An array of child node IDs under this node * @property {Array<string>} commands - An array of templates that apply to this node. Portfolio nodes tend not to have commands, so this array is likely 0 for such nodes. If there is a template, then only the first item in this array would be populated. This has been kept an array just in case the design evolves to support multiple templates for a node. * @property {boolean} isPlatform - Is the current node a platform node? This is always false for portfolio nodes. * @property {Acl} [acl] - The access control list information for this portfolio. This attribute is only present if the node is a root (portfolio) node. */ /** * @external Promise * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise Promise} */ /** * This callback is called when the result is loaded. * * @callback PromisePortfoliosCallbackSuccess * @param {Node[]} ret - A collection of root (or portfolio) nodes that the user is allowed to access. */ /** * This callback is called when the result fails to load. * * @callback PromisePortfoliosCallbackError * @param {Error} err - The error that occurred while loading portfolios. */ /** Resolves with a {@link PromisePortfoliosCallbackSuccess}, fails with a {@link PromisePortfoliosCallbackError} * * @typedef {Promise} PromisePortfolios */ /** * Fetches all the portfolios available to user, based on access control rules * setup by the administrator. If no rules are set for the user, all * portfolios will be returned. * * @returns {PromisePortfolios} A promise to the portfolios * @example * smartorg.portfolios() * .then(function (portfolios) { * portfolios.map(function (portfolio) { * console.log(portfolio); * }) * }) * .catch(function (err) { * console.error(err); * }) */ portfolios() { var path_ = this.protocols._getPath('template/portfolios'); return this.protocols.apiGet(path_); } /** @typedef {object} Input * @property {string} Key The key of this input * @property {string} Type The type of this input (SCALAR|DISTRIBUTION|TABLE) * @property {string} Units The units of this input * @property {string} Display The display prompt of this input * @property {string} Description The description of this input * @property {string} Constraint The constraint placed on this input (double|integer|year|date|text) * @property {string} Val The value of this input * @property {boolean} Inherited Is this an inherited input (shared variable)? * @property {string} InputType Is this data local to the node or overridden? (LOCAL|OVERRIDE) * @property {number} isLeaf If this node is a leaf, this is set to 1 otherwise 0 * @property {string} CellLink The link to the Excel cell */ /** @typedef {object} MenuItems * @property {string} nodeAttribute - This has identifiers like "r" or "rw" to specify if this node is editable. * @property {string} nodeID - The node for which the inputs have been fetched * @property {Input[]} inputs - The inputs that have been found * @property {string} selectedInputKey - what is this? * @property {string} targetDS - The dataset ID. Why is it called "target"? * @property {string} templateID - The ID of the template associated with this node * @property {string} user - The name of the user who has made the request */ /** * @external Promise * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise Promise} */ /** * This callback is called when the result is loaded. * * @callback PromiseInputsCallbackSuccess * @param {MenuItems} ret - A collection of inputs matching the keys at the node */ /** * This callback is called when the result fails to load. * * @callback PromiseInputsCallbackError * @param {Error} err - The error that occurred while loading inputs. */ /** Resolves with a {@link PromiseInputsCallbackSuccess}, fails with a {@link PromiseInputsCallbackError} * * @typedef {Promise} PromiseInputs */ /** * Given the keys for inputs and a node ID, all the input data * at that node matching the keys are fetched. * * @param {string} nodeID The ID of the node at which the inputs are to be fetched * @param {string} inputKeys A pipe-delimited list of input keys that are to be fetched at the node * @returns {PromiseInputs} A promise to the inputs * @example * nodeID = "012345"; * inputKeys = "marketSize|marketShare|discountRate"; * smartorg.inputsFor(nodeID, inputKeys) * .then(function (inputs) { * inputs.menuItems.map(function (input) { * console.log(input); * }) * }) * .catch(function (err) { * console.error(err); * }) */ inputsFor(nodeID, inputKeys) { var path_ = this.protocols._getPath('template/inputs'); path_ = `${path_}/${nodeID}/${encodeURIComponent(inputKeys)}`; return this.protocols.apiGet(path_); } /** @typedef {object} CompareValueChildData * @property {Array<string>} childLeafNames - A list of names of all children immediately below the selected node * @property {Array<object>} compareValueData - A list of values of all children immediately below the selected node. The values are picked from the template (portfolio or platformPortfolio) based on the *Keys* parameter (an array of output keys) for the COMPARE_VALUE command. * @property {string} nodeName - Name of the selected node */ /** @typedef {object} CompareValueData * @property {object} commandJSON - This has attributes that setup the chart display * @property {CompareValueChildData} highlightedNode - This is the appropriate value data in the node that has been selected * @property {CompareValueChildData} siblingNode - This is the appropriate value data in the sibling node that has been selected. It will be *null* if no sibling has been selected. */ /** @typedef {object} CompareUncOutputData * @property {string} Display - Full display describing the output * @property {string} Units - Units of the output * @property {number} Mean - The mean value of the combined uncertainty bar of this output in the Tornado * @property {string} NodeName - Name of the child * @property {Array<number>} Summary - The low (0), medium (1) and high (2) values of this output based on the combined uncertainty bar in the Tornado. */ /** @typedef {object} CompareUncData * @property {Array<Array<CompareUncOutputData>>} highlightedNode - This is a nested array. First, it has as many elements as there are children. Each element is an array of outputs, one for each Tornado *ValueMetricKey*. * @property {Array<Array<CompareUncOutputData>>} siblingNode - This is a nested array. First, it has as many elements as there are children. Each element is an array of outputs, one for each Tornado *ValueMetricKey*. An empty array is returned if no sibling has been selected. * @property {string} nodeName - Node name of highlighted node * @property {string} shadowNodeName - Node name of sibling node. This is null if no sibling has been selected. */ /** * This callback is called when the result is loaded. * * @callback PromiseActionCallbackSuccess * @param {(CompareValueData|CompareUncData)} ret - An object that differs based on the command that was executed */ /** * This callback is called when the result fails to load. * * @callback PromiseActionCallbackError * @param {Error} err - The error that occurred while loading inputs. */ /** Resolves with a {@link PromiseActionCallbackSuccess}, fails with a {@link PromiseActionCallbackError} * * @typedef {Promise} PromiseActionResults */ /** * Executes action command and fetches the results. This is a general way to access any template menu command. * * @param {string} actionID - The ID for the action specified in the template menu JSON (portfolio or application structure). * @param {string} nodeID - The node for which the action is to be applied * @param {object} packedReportOptions - Report options for this action. * @returns {PromiseActionResults} A promise to the result of running the action * @example * smartorg.actionFor(actionID, nodeID) * .then(function (data) { * console.log(data); // The data object is structured differently for each command * }) * .catch(function (err) { * console.error(err); * }) */ actionFor(actionID, nodeID, packedReportOptions) { var path_ = this.protocols._getPath('template/actionMenu'); path_ = `${path_}/${actionID}/${nodeID}/${packedReportOptions}`; return this.protocols.apiGet(path_); } /** @typedef {object} MenuObject * @property {string} Command - The command to be invoked by this action * @property {string} displayText - The display for this menu item * @property {string} menuID - The unique key for this menu item * @property {string} nodeID - The node ID for from this menu item has been fetched * @property {boolean} isOutput - Is this command an output command? *TABLE_INPUT* and *INPUT_SCREEN* are input commands, and all else are output commands. * @property {number} level - What is this? * @property {object} parameters - These specify what needs to go into the command. They differ based on the command. * @property {string} A - Legacy Javascript code injection. Ignore when writing your applications. */ /** * This callback is called when the result is loaded. * * @callback PromiseActionMenuCallbackSuccess * @param {Object} menu - An object that contains the menu items * @param {Object} menu.menuItems - The menu items for the node * @param {Array<MenuObject>} menu.menuItems.Actions - The menu items under the "Actions" section * @param {Array<MenuObject>} menu.menuItems.Management - The menu items under the "Management" section */ /** * This callback is called when the result fails to load. * * @callback PromiseActionMenuCallbackError * @param {Error} err - The error that occurred while loading inputs. */ /** Resolves with a {@link PromiseActionMenuCallbackSuccess}, fails with a {@link PromiseActionMenuCallbackError} * * @typedef {Promise} PromiseActionMenu */ /** * Fetches the menu (from the appropriate template) that is associated with a node. * * @param {string} nodeID The ID of the node for which a menu is to be fetched * @returns {PromiseActionMenu} A promise to return the action menu for the specified node * @example * smartorg.actionMenuFor(nodeID) * .then(function (menu) { * console.log(menu); * }) * .catch(function (err) { * handleError(err); * }); */ actionMenuFor(nodeID) { var path_ = this.protocols._getPath('template/actionMenu'); path_ = `${path_}/${nodeID}`; return this.protocols.apiGet(path_); } /** * Get share data (Input screen) structure. * * @param nodeID {string} Tree node ID. * @returns {Promise} A promise to return shared data for the * specified node. * @example * smartorg.sharedDataFor(nodeID) * .then(function (menu) { * console.log(menu); * }) * .catch(function (err) { * handleError(err); * }); */ sharedDataFor(nodeID) { var path_ = this.protocols._getPath('template/sharedData'); path_ = `${path_}/${nodeID}`; return this.protocols.apiGet(path_); } /** * @typedef {object} InputKeyValPair * @property {string} Key - the key of the input, eg startYear or discountRate * @property {string} Val - the value of the input eg 0.89 */ /** * Saves inputs * @param {string} nodeID The ID of the node that's inputs are to be saved * @param {Array<InputKeyValPair>} inputs array of inputs to be saved * @returns {string} msg - save status message * @example saved dataset for node 'leafNodeExample' by calling template 'exampleTemplateName' * @example * * //to save inputs for a given node * smartorg.saveInputs(nodeID, inputs) * .then(function (ret) { * console.log(ret); // Need documentation on ret * }) * .catch(function (err) { * handleError(err); * }); */ saveInputs(nodeID, inputs) { var path_ = this.protocols._getPath('domain/template'); var body_ = { nodeID: nodeID, inputs: inputs }; return this.protocols.apiPut(path_, body_); } overrideInput(targetNodeID, sourceNodeID, inputKey) { var path_ = this.protocols._getPath('domain/overrideInput'); var body_ = { 'targetNodeID': targetNodeID, 'sourceNodeID': sourceNodeID, 'inputKey': inputKey }; return this.protocols.apiPut(path_, body_); } deoverrideInput(targetNodeID, inputKey) { var path_ = this.protocols._getPath('domain/deoverrideInput'); var body_ = { targetNodeID: targetNodeID, inputKey: inputKey }; return this.protocols.apiPut(path_, body_); } /** * This callback is called when the Paste Node succeeds * * @callback PromisePasteStatusCallbackSuccess * @param {Number} status - 0=success non-zero=failure * @param {string} message - e.g. 'pasted data' */ /** * This callback is called when the Paste Node fails * * @callback PromisePasteStatusCallbackError * @param {Number} status - http status code, e.g. 500 * @param {string} statusText -http status text, e.g. 'INTERNAL SERVER ERROR' * @param {string} message - e.g. incorrect _id 'ERROR PasteNode Exception ('_id')' */ /** Resolves with a {@link PromisePasteStatusCallbackSuccess}, fails with a {@link PromisePasteStatusCallbackError} * * @typedef {Promise} PromisePasteStatus */ /** * Paste Node * @param {string} targetParentNodeID parent Node ID * @param {string} nodeToPaste Node ID to paste * @returns {PromisePasteStatus} A promise to provide status message of the Paste Node operation. * * @example * // to paste a node under a target parent node * smartorg.pasteNode(targetParentNodeID, nodeToPaste) * .then(function (ret) { * console.warn(ret); * }) *.catch(function (err) { * handleError(err); * }) */ pasteNode(targetParentNodeID, nodeToPaste) { var path_ = this.protocols._getPath('domain/paste'); path_ = `${path_}/${targetParentNodeID}/${nodeToPaste}`; return this.protocols.apiGet(path_); } /** * Set a node (and its children) readonly * @param nodeID * @param includeAllChildren * @returns {string} msg - Made node (and its descendants) readonly * @example * smartorg.makeReadOnly(nodeID, includeAllChildren) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ makeReadOnly(nodeID, includeAllChildren) { var path_ = this.protocols._getPath('domain/readonly'); var attribute = "r"; path_ = `${path_}/${nodeID}/${attribute}/${includeAllChildren}`; return this.protocols.apiPost(path_, {}); } /** * Set a node (and its children) editable * @param nodeID * @param includeAllChildren * @returns {string} msg - Made node (and its descendants) editable * @example * smartorg.makeEditable(nodeID, includeAllChildren) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ makeEditable(nodeID, includeAllChildren) { var path_ = this.protocols._getPath('domain/readonly'); var attribute = "rw"; path_ = `${path_}/${nodeID}/${attribute}/${includeAllChildren}`; return this.protocols.apiPost(path_, {}); } /** * Fetch change log at or under current node. * * @param {string} nodeID - The ID of the node at or under which change log is to be fetched * @returns {Array<changes>} */ changeLog(nodeID) { var path_ = this.protocols._getPath('domain/changes'); path_ = `${path_}/${nodeID}`; return this.protocols.apiPost(path_, {}); } /** * Recalculate entire portfolio * @param treeID * @param recalType * @param startNodeId * @returns {string} msg - tree is recalculated * @example * smartorg.recalculatePortfolio(treeID) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ recalculatePortfolio(treeID, recalType, startNodeId) { var path_ = this.protocols._getPath('domain/recalculate'); path_ = `${path_}/${encodeURIComponent(treeID)}`; var body_ = { recalType: recalType, startNodeId: startNodeId }; return this.protocols.apiPost(path_, body_); } /** * Get the total number of orphan nodes in tree. * * @param treeID {string} Tree id aka root node name. * @returns {*|Promise.<T>|Promise|axios.Promise} * then: number of nodes. */ getOrphanNodesCount(treeID) { var path_ = this.protocols._getPath('domain/tree/analyse/orphan'); path_ = `${path_}/${encodeURIComponent(treeID)}`; return this.protocols.apiGet(path_); } /** * Fix (delete) all orphan nodes in tree. * * @param treeID {string} Tree id aka root node name. * @returns {*|Promise.<T>|Promise|axios.Promise} * then: number of deleted nodes. */ fixOrphanNodesCount(treeID) { var path_ = this.protocols._getPath('domain/tree/analyse/orphan'); path_ = `${path_}/${encodeURIComponent(treeID)}`; return this.protocols.apiDelete(path_); } /** * Get calculation engine version number and log level. * * @return {{}} Promise. * then: {logLevel: "something", versionNumber: "something"} * catch: Error. */ getCalculationEngineInfo() { var path_ = this.protocols._getPath('domain/calcengine/version'); return this.protocols.apiGet(path_); } /** * Fetch lines from bottom of calculation engine log * @param linesFromBottom * @returns {string} msg - fetched lines from bottom of calculation engine log * @example * smartorg.fetchCalculationEngineLog(treeID) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ fetchCalculationEngineLog(linesFromBottom) { var path_ = this.protocols._getPath('domain/fetchCalculationEngineLog'); path_ = `${path_}/${linesFromBottom}`; return this.protocols.apiGet(path_); } /** * Export portfolio * @param nodeID * @returns {string} msg - entire portfolio is exported * @example * smartorg.exportPortfolio(treeID) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ exportPortfolio(nodeID) { var path_ = this.protocols._getPath('domain/exportPortfolio'); path_ = `${path_}/${nodeID}`; return this.protocols.apiPost(path_, {}); } /** * Fetch all exported portfolio paths * @returns {string} exported portfolio path list * @example * smartorg.fetchAllExportedPortfolioPaths(treeID) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ fetchAllExportedPortfolioPaths() { var path_ = this.protocols._getPath('domain/fetchAllExportedPortfolioPaths'); path_ = `${path_}`; return this.protocols.apiGet(path_); } /** * Import portfolio * @param includeData * @param pathToImportFiles64 * @param newTreeName64 * @returns {string} msg - portfolio is imported * @example * smartorg.exportPortfolio(treeID) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ importPortfolio(includeData, pathToImportFiles64, newTreeName64) { var path_ = this.protocols._getPath('domain/importPortfolio'); path_ = `${path_}/${includeData}/${pathToImportFiles64}/${newTreeName64}`; return this.protocols.apiPost(path_, {}); } /** * Create new Portfolio * @param {string} newPortfolioName Name of the new portfolio * @returns {string} msg - create Portfolio status message * @example * smartorg.createPortfolio(newPortfolioName) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ createPortfolio(newPortfolioName) { var path_ = this.protocols._getPath('domain/tree'); path_ = `${path_}/${encodeURIComponent(newPortfolioName)}`; var body_ = {}; return this.protocols.apiPost(path_, body_); } /** * Create new Portfolio from existing portfolio * @param {string} newPortfolioName Name of the new portfolio * @param categoriesConfig * @param acl * @param chosenTemplates * @param chosenGroups * @returns {string} msg - create Portfolio status message * @example * smartorg.createPortfolioFromExisting(newPortfolioName, categoriesConfig, acl) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ createPortfolioFromExisting(newPortfolioName, categoriesConfig, acl, chosenTemplates, chosenGroups) { var path_ = this.protocols._getPath('domain/portfolio'); var body_ = { treeID: newPortfolioName, categoriesConfig: categoriesConfig, acl: acl, chosenTemplates: chosenTemplates, chosenGroups: chosenGroups }; return this.protocols.apiPost(path_, body_); } /** * Create a new Node under an existing portfolio * @param {string} parentNodeID parent node ID * @param {string} newNodeName new Node name * @param {string} templateName template name * @param {string} platformOrLeaf 'platform' or 'leaf' * @returns {string} msg - create Node status message * @example * smartorg.createNode(parentNodeID, newNodeName, templateName, platformOrLeaf) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ createNode(parentNodeID, newNodeName, templateName, platformOrLeaf) { var path_ = this.protocols._getPath('domain/node'); var body_ = { nodeID: parentNodeID, newNodeName: newNodeName, templateName: templateName, platformOrLeaf: platformOrLeaf }; return this.protocols.apiPost(path_, body_); } /** * This callback is called when the node is loaded. * * @callback PromiseNodeCallbackSuccess * @param {Node} node - The node object */ /** * This callback is called when the result fails to load. * * @callback PromiseNodeCallbackError * @param {Error} err - The error that occurred while reading node. */ /** Resolves with a {@link PromiseNodeCallbackSuccess}, fails with a {@link PromiseNodeCallbackError} * * @typedef {Promise} PromiseNodeResults */ /** * Retrieves a node by its ID * @param {string} nodeID The ID of the node to get * @returns {PromiseNodeResults} A promise to return the node * @example * smartorg.nodeBy(nodeID) * .then(function (node) { * console.log(node); * }) * .catch(function (err) { * handleError(err); * }) */ nodeBy(nodeID) { var path_ = this.protocols._getPath('domain/node'); path_ = `${path_}/${nodeID}`; return this.protocols.apiGet(path_); } /** * Edit Node * @param {string} nodeID The ID of the node to edit * @param {string} newNodeName The new node name * @param {string} templateName The template name * @param {Array<string>} children List of children ids. * @returns {axios.Promise} * @example * smartorg.editNode(nodeID, newNodeName, templateName) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) * */ editNode(nodeID, newNodeName, templateName, children) { var path_ = this.protocols._getPath('domain/node'); var body_ = { nodeID: nodeID, newNodeName: newNodeName, templateName: templateName, children: children }; return this.protocols.apiPut(path_, body_); } /** * Delete Node * @param {string} nodeID The ID of the node to delete * @returns {string} msg - delete status message * @example * smartorg.deleteNode(nodeToDeleteID) * .then(function (ret) { * console.warn(ret); * }) * .catch(function (err) { * handleError(err); * }) */ deleteNode(nodeID) { var path_ = this.protocols._getPath('domain/node'); path_ = `${path_}/${nodeID}`; return this.protocols.apiDelete(path_); } /** * Tornado Report * @param {string} nodeID The ID of the node for the Tornado * @returns {*} tornadoData in JSON * @example * smartorg.tornado(nodeID) * .then(function (tornado) { * console.log(tornado); * }) * .catch(function (err) { * handleError(err); * }) */ tornado(nodeID) { var path_ = this.protocols._getPath('template/tornado'); path_ = `${path_}/${nodeID}`; return this.protocols.apiGet(path_); } /** * This callback is called when the treeFor response succeeds * * @callback PromiseTreeCallbackSuccess * @param {Node[]} nodes - tree structure of Nodes */ /** * This callback is called when the treeFor response fails * * @callback PromiseTreeCallbackError * @param {string} message - base64 encoded error message */ /** Resolves with a {@link PromiseTreeCallbackSuccess}, fails with a {@link PromiseTreeCallbackError} * * @typedef {Promise} PromiseTree */ /** * Gets the Tree for a Portfolio * @param {string} portfolioName Portfolio Name * @returns {PromiseTree} A promise representing the Portfolio Tree structure * @example * smartorg.treeFor(treeID) * .then(function (tree) { * console.log(tree); * }) * .catch(function (err) { * handleError(err); * }) */ treeFor(portfolioName) { var path_ = this.protocols._getPath('domain/tree'); path_ = `${path_}/${encodeURIComponent(portfolioName)}`; return this.protocols.apiGet(path_); } /** @typedef {object} CategoryConfig * @property {string} AppliesTo * @property {boolean} IsMultiSelect * @property {string} CategoryName - e.g. Region * @property {array.<string>} CategoryEntries - e.g US, Asia, Europe */ /** * This callback is called when the categoriesConfigFor response succeeds * * @callback CategoryConfigPromiseCallbackSuccess * @param {CategoryConfig[]} categoryConfigs - array of CategoryConfig objectsj */ /** * This callback is called when the categoriesConfigFor response fails * * @callback CategoryConfigPromiseCallbackError * @param {string} message - base64 encoded error message */ /** Resolves with a {@link CategoryConfigPromiseCallbackSuccess}, fails with a {@link CategoryConfigPromiseCallbackSuccess} * * @typedef {Promise} CategoryConfigPromise */ /** * * * @param rootNodeID * @returns {CategoryConfigPromise} * @example * smartorg.categoriesConfigFor(rootNodeID) * .then(function(categoryConfigs) { * // categoryConfigs is an array of categoryConfig * categoryConfigs.forEach(function(categoryConfig) { * console.log(categoryConfig.AppliesTo); * console.log(categoryConfig.IsMultiSelect); * console.log(categoryConfig.CategoryName); //e.g. Region * console.log(categoryConfig.AutoPropagateUp); * * categoryConfig.CategoryEntries.forEach(function(entry) { * console.log("category entry "+ entry); // e.g. US, Asia, Europe * }); * }); * }) * .catch(function(err) { * handleError(err); * }); */ categoriesConfigFor(rootNodeID) { var path_ = this.protocols._getPath('domain/categoryConfig'); path_ = `${path_}/${rootNodeID}`; return this.protocols.apiGet(path_); } /** * This callback is called when the saveCategoryConfig response succeeds * * @callback CategoryConfigSavePromiseCallbackSuccess * @param {string} statusMessage - status of saveCategoryConfig ( new or existing ) */ /** Resolves with a {@link CategoryConfigSavePromiseCallbackSuccess}, fails with a {@link CategoryConfigPromiseCallbackSuccess} * * @typedef {Promise} CategoryConfigSavePromise */ /** * @param rootNodeID * @param {CategoryConfig} categoryConfig new or existing category config object ( not string ) * @returns {CategoryConfigSavePromise} * @example * smartorg.saveCategoryConfig(rootNodeID, categoryConfig) * .then(function(statusMessage) { * console.log(statusMessage); * }) * .catch(function(err) { * handleError(err); * }); */ saveCategoryConfig(rootNodeID, categoryConfig) { var path_ = this.protocols._getPath('domain/categoryConfig'); path_ = `${path_}/${rootNodeID}`; return this.protocols.apiPost(path_, categoryConfig); } /** * Delete a category from config. * * @param rootNodeID * @param categoryName {string} Category name, should be an existing one. * @returns {*} * @example * smartorg.deleteCategoryConfig(rootNodeID, categoryName) * .then(function(statusMessage) { * console.log(statusMessage); * }) * .catch(function(err) { * handleError(err); * }); */ deleteCategoryConfig(rootNodeID, categoryName) { var path_ = this.protocols._getPath('domain/categoryConfig'); path_ = `${path_}/${rootNodeID}/${encodeURIComponent(categoryName)}`; return this.protocols.apiDelete(path_); } /** * Get array of tags for a node. * * @param nodeID {string} * @returns {*} Tags promise. * then: array of tags * catch: {status: err code, statusText: status text, * message: err message} * * @example * smartorg.tagsFor(nodeId).then( * function (result) { * console.log(result); * }).catch(function (err) { * console.log(err); * }); */ tagsFor(nodeID) { var path_ = this.protocols._getPath('domain/tags'); path_ = `${path_}/${nodeID}`; return this.protocols.apiGet(path_); } /** * This callback is called when the saveTags response succeeds * * @callback SaveTagsPromisePromiseCallbackSuccess * @param {string} statusMessage - status of saveTags */ /** * This callback is called when the saveTags response fails * * @callback SaveTagsPromisePromiseCallbackSuccess * @param {string} statusMessage - error message */ /** Resolves with a {@link SaveTagsPromisePromiseCallbackSuccess}, fails with a {@link SaveTagsPromisePromiseCallbackSuccess} * * @typedef {Promise} SaveTagsPromise */ /** * @typedef {Array<String>} TagSet * @example * //First element in the array is the node ID * //Second element in the array is a comma delimited string of 1 or more CategoryName:CategoryItemName, all is required * ["b8652f5d935cf2e22e8e5d01de065d5d","all, Region:Africa, Funded:No, CropType:legumes"] */ /** * Saves array of tags for a node * @param nodeID * @param {Array<TagSet>} newTagString * @returns {SaveTagsPromise} * @example * smartorg.saveTags(nodeId, newTagString) * .then(function(msg) { * * console.log(msg); * }) * .catch(function(err) { * console.error(err); * }); */ saveTags(nodeID, newTagString) { var path_ = this.protocols._getPath('domain/tags'); path_ = `${path_}/${nodeID}`; var body_ = JSON.parse(newTagString); return this.protocols.apiPost(path_, body_); } /** * Save a node's description. * Both two parameters need to encode in base 64. * * @param nodeID {string} Tree node Id. * @param description {string} Html format description. */ saveDescripton(nodeID, description) { var path_ = this.protocols._getPath('domain/description'); path_ = `${path_}/${nodeID}`; var body_ = { 'description': description }; return this.protocols.apiPut(path_, body_); } /** * Save a node's smartText. * Both two parameters need to encode in base 64. * * @param nodeID {string} Tree node Id. * @param smartText {string} Html format smartText. */ saveSmartText(nodeID, smartText) { var path_ = this.protocols._getPath('domain/smartText'); path_ = `${path_}/${nodeID}`; var body_ = { 'smartText': smartText }; return this.protocols.apiPut(path_, body_); } /** * Lookup inputs and outputs that need to go into the universal table * by key. We need to supply nodeID, and at least one of * input or output keys (or both). * @param nodeID {string} Tree node Id. * @param schema {object} - contains selectedInputKeys {Array}, * selectedOutputKeys {Array} and selectedTableInputKeys {object} * @param packedReportOptions - contains encoded reportOptions * @returns list for fields to be displayed in universal output */ getFieldList(nodeID, schema, packedReportOptions) { var path_ = this.protocols._getPath('domain/universal/io/fields'); path_ = `${path_}`; var body = { "nodeID": nodeID, "schema": schema, "packedReportOptions": packedReportOptions }; return this.protocols.apiPost(path_, body); } /** * lookup inputs from astro_data and gives the specific fields * @param templateName * @param leafOrPlatform * @param nodeID {string} Tree node Id. * @returns list for fields to be displayed in universal output */ getDisplayNameList(templateName, leafOrPlatform, nodeID) { var path_ = this.protocols._getPath('domain/universal/io/displayNames'); path_ = `${path_}/${encodeURIComponent(templateName)}/${leafOrPlatform}/${nodeID}`; return this.protocols.apiGet(path_); } /** * saving univSchema to rootNode * @param nodeID {string} * @param schema - has templateName, IOKeys & access * @param oldName - to check and replace it with new schema name */ saveUnivSchemaToRoot(nodeID, schema, oldName) { var path_ = this.protocols._getPath('domain/universal/io/saveUnivSchemaToRoot'); path_ = `${path_}`; var body = { "nodeID": nodeID, "schema": schema, "oldName": oldName }; return this.protocols.apiPost(path_, body); } /** * delete specific schema from rootNode * @param nodeID {string} * @param schemaName {string} */ deleteUnivSchemaFromRoot(nodeID, schemaName) { var path_ = this.protocols._getPath('domain/universal/io/deleteUnivSchemaFromRoot'); path_ = `${path_}/${nodeID}/${encodeURIComponent(schemaName)}`; return this.protocols.apiPut(path_, undefined); } /** * replace univSchema in rootNode * @param nodeID {string} * @param schemaName {string} * @param oldSchemaName {string} * @param univSchema - schema has templateName, inputKeys, outputKeys & access */ replaceUnivSchemaInRoot(nodeID, schemaName, univSchema, oldSchemaName) { var path_ = this.protocols._getPath('domain/universal/io/replaceUnivSchemaInRoot'); path_ = `${path_}/${nodeID}/${encodeURIComponent(schemaName)}/${encodeURIComponent(oldSchemaName)}`; return this.protocols.apiPost(path_, univSchema); } /** * save inputs to corresponding nodes * @param inputs {{}} * */ universalSaveInputs(inputs) { var path_ = this.protocols._getPath('domain/universal/io/saveInputs'); var body = { "inputs": inputs }; return this.protocols.apiPost(path_, body); } /** * Get current api version number. * * @returns {*} Api version number promise. * * //to do: Fan this is not complete needs @example * then: string of version number. * catchL {status: err code, statusText: status text, * message: err message} */ getApiVersionNumber() { var path_ = this.protocols._getPath('domain/api/version/number'); return this.protocols.apiGetNoAuth(path_); } /** * Get simple outputs from node data * @returns {*} simple outputs * */ getSimpleOutputs(nodeID) { var path_ = this.protocols._getPath('domain/output'); path_ = `${path_}/${nodeID}`; return this.protocols.apiGet(path_); } /** * lookup host specific short code to return url * @param {string} shortCode - the short code to lookup url * @returns ShortUrl or 404 Not Found */ getInfoForShortURL(shortCode) { var path_ = this.protocols._getPath('framework/shorturl'); path_ = `${path_}/${shortCode}`; return this.protocols.apiGet(path_); } /** * @typedef {object} ShortUrl * @property {string} _id - short url code e.g. JwijDXE * @property {string} _rev - internal document revision ( ignore ) * @property {string} url - long url * @property {boolean} byPassLogin * @property {string} urlLinkName - e.g. Report 2016 PMF submission * @property {string} csum - checksum of the long url used for duplicate prevention ( ignore ) * @property {array.<string>} CategoryEntries - e.g US, Asia, Europe */ /** * This callback is called when the ShortUrlPromise response succeeds * * @callback ShortUrlPromiseeCallbackSuccess * @param {ShortUrl[]} ShortUrl - a ShortUrl object */ /** * This callback is called when the ShortUrlPromise response fails * * @callback ShortUrlPromiseCallbackError * @param {string} message - base64 encoded error message */ /** * Resolves with a {@link ShortUrlPromiseeCallbackSuccess}, * fails with a {@link ShortUrlPromiseCallbackError} * * @typedef {Promise} ShortUrlPromise */ /** * * @param {string} urlToShorten - long url to shorten * @param {boolean} byPassLogin - true or false flag to bypass login * @param {string} urlLinkName - optional link or report name * @returns ShortUrlPromise */ createShortURL(urlToShorten, byPassLogin, urlLinkName) { var path_ = this.protocols._getPath('framework/shorturl/'); // note the / at the end, this is important to match url for POST var body_ = { "ByPassLogin": byPassLogin, "urlToShorten": encodeURIComponent(urlToShorten), "urlLinkName": urlLinkName }; return this.protocols.apiPost(path_, body_); } /** * Generate zendesk authentication url (token) for one login. * * @returns {*} Get url promise. * then: url string. * catch: error status, text and message. * * @example * smartorg.zendeskAuthUrl().then( * function (result) { * console.log(result); * }) * .catch(function (err) { * console.err(err); * }); */ zendeskAuthUrl(page) { var path_ = this.protocols._getPath('domain/zenlogin'); path_ = `${path_}/${page}`; return this.protocols.apiGet(path_); } /** * Generate zendesk authentication url (token) for one login. * Return to page specified by front end. * * If url is not start with "https://smartorg.zendesk.com", * it will redirect you to that page. * * @returns {*} Get url promise. * then: url string. * catch: error status, text and message. * * @example * smartorg.zendeskRedirect(returnTo).then( * function (result) { * console.log(result); * }) * .catch(function (err) { * console.err(err); * }); */ zendeskRedirect(returnTo) { var path_ = this.protocols._getPath('domain/zendesk/redirect'); path_ = `${path_}/${encodeURIComponent(returnTo)}`; return this.protocols.apiGet(path_); } /** * Get current logged in user profile. * * @returns {*} Get user profile promise. * then: dict of user profile info. * catch: error status, text and message. * * @example * smartorg.getUserProfile().then( * function (result) { * console.log(result); * }) * .catch(function (err) { * console.err(err); * }); */ getUserProfile() { var path_ = this.protocols._getPath('domain/user'); return this.protocols.apiGet(path_); } /** * This callback is called when the SaveUserProfilePromise * response succeeds * * @callback SaveUserProfilePromiseCallbackSuccess * @param {string} message - plaintext message */ /** * This callback is called when the SaveUserProfilePromise * response fails * * @callback SaveUserProfilePromiseCallbackError * @param {string} message - plaintext message */ /** * Resolves with a {@link SaveUserProfilePromiseCallbackSuccess}, * fails with a {@link SaveUserProfilePromiseCallbackError} * * @typedef {Promise} SaveUserProfilePromise */ /** * Save (update) user profile information. This one is for user * to change their own profiles. * * @param username {string} Username as login name. * @param name {string} User full name in "Lastname, Firstname" * @param email {string} * @param phone1 {string} Phone number, only + and numbers. * @param organisation {string} * @returns {*|Promise.<T>|Promise|axios.Promise} */ saveUserProfile(username, name, email, phone1, organisation) { var path_ = this.protocols._getPath('domain/user'); var body_ = { 'username': username, 'name': name, 'phone1': phone1, 'email': email, 'organisation': organisation }; return this.protocols.apiPut(path_, body_); } /** * This callback is called when the UserProfileByIdPromise * response succeeds * * @callback UserProfileByIdPromiseCallbackSuccess * @param {object} userInfo - A user object with all property * except password */ /** * This callback is called when the UserProfileByIdPromise * response fails * * @callback UserProfileByIdPromiseCallbackError * @param {string} message - plaintext message */ /** * Resolves with a {@link UserProfileByIdPromiseCallbackSuccess}, * fails with a {@link UserProfileByIdPromiseCallbackError} * * @typedef {Promise} UserProfileByIdPromise */ /** * Read user profile by his id. * * @param userId {string} Unique user database id. * @returns {*|Promise.<T>|Promise|axios.Promise} */ getUserProfileByID(userId) { var path_ = this.protocols._getPath('framework/user'); path_ = `${path_}/${userId}`; return this.protocols.apiGet(path_); } /** * This callback is called when the NewUserPromise * response succeeds * * @callback NewUserPromiseCallbackSuccess * @param {string} message - plaintext message */ /** * This callback is called when the NewUserPromise * response fails * * @callback NewUserPromiseCallbackError * @param {string} message - plaintext message */ /** * Resolves with a {@link NewUserPromiseCallbackSuccess}, * fails with a {@link NewUserPromiseCallbackError} * * @typedef {Promise} NewUserPromise */ /** * Creates a new user * @param username {string} Unique username. Server will double * check if it is unique. * @param name {string} Full name of user in format "Last, First". * @param password {string} Password in plain text. x_x * @param email {string} * @param phone1 {string} In format +14081231234. * @param organisation {string} * @param defaultGroupName {string} Group name instead of id. * @returns {*|Promise.<T>|Promise|axios.Promise} */ newUser(username, name, password, email, phone1, organisation, defaultGroupName) { //debugger; var path_ = this.protocols._getPath('framework/user'); var body_ = { 'username': username, 'name': name, 'password': password, 'phone1': phone1, 'email': email, 'organisation': organisation, 'defaultGroup': defaultGroupName }; return this.protocols.apiPost(path_, body_); } /** * This callback is called when the ModifyUserPromise * response succeeds * * @callback ModifyUserPromiseCallbackSuccess * @param {string} message - plaintext message */ /** * This callback is called when the ModifyUserPromise * response fails * * @callback ModifyUserPromiseCallbackError * @param {string} message - plaintext message */ /** * Resolves with a {@link ModifyUserPromiseCallbackSuccess}, * fails with a {@link ModifyUserPromiseCallbackError} * * @typedef {Promise} ModifyUserPromise */ /** * Similar to save user profile. This one is for address book use. * * @param userID {string} Unique user database id. * @param username {string} Unique username. Server will double * check if it is unique. * @param name {string} Full name of user in format "Last, First". * @param email {string} * @param phone1 {string} In format +14081231234. * @param organisation {string} * @param defaultGroupName {string} Group name instead of id. * @returns {*|Promise.<T>|Promise|axios.Promise} */ modifyExistingUser(userID, username, name, email, phone1, organisation, defaultGroupName) { var path_ = this.protocols._getPath('framework/user'); var body_ = { 'userID': userID, 'username': username, 'name': name, 'phone1': phone1, 'email': email, 'organisation': organisation, 'defaultGroup': defaultGroupName }; return this.protocols.apiPut(path_, body_); } /** * Update user admin settings, including force user to change * password on login and reset user to first login status. * * @param userId {string} Unique user id (couch db doc id). * @param adminSettings {object} A dict contains everything needs * to be set. For now it has passwordChange and * resetToFirstLogin. Anything come in later just add to the * dict object. * * @returns {*|Promise.<T>|Promise|axios.Promise} * Result status promise. * then: status 0, no data. * catch: status not 0, exception object or message array. */ updateUserAdminSettings(userId, adminSettings) { var path_ = this.protocols._getPath('framework/user/settings'); var body_ = { 'userID': userId, 'passwordChange': adminSettings['passwordChange'], 'resetToFirstLogin': adminSettings['resetToFirstLogin'] }; return this.protocols.apiPut(path_, body_); } /** * This callback is called when the ListUserPromise * response succeeds * * @callback ListUserPromiseCallbackSuccess * @param {Array<object>} userlist - List of user objects. */ /** * This callback is called when the ListUserPromise * response fails * * @callback ListUserPromiseCallbackError * @param {string} message - plaintext message */ /** * Resolves with a {@link ListUserPromiseCallbackSuccess}, * fails with a {@link ListUserPromiseCallbackError} * * @typedef {Promise} ListUserPromise */ /** * Get list of all user with all info except password. * @returns {*|Promise.<T>|Promise|axios.Promise} */ getListOfUsers() { var path_ = this.protocols._getPath('framework/user'); return this.protocols.apiGet(path_); } /** * This callback is called when the DeleteUserPromise * response succeeds * * @callback DeleteUserPromiseCallbackSuccess * @param {string} message - plaintext message */ /** * This callback is called when the DeleteUserPromise * response fails * * @callback DeleteUserPromiseCallbackError * @param {string} message - plaintext message */ /** * Resolves with a {@link DeleteUserPromiseCallbackSuccess}, * fails with a {@link DeleteUserPromiseCallbackError} * * @typedef {Promise} DeleteUserPromise */ /** * Delete a user from database by his id. * * @param userId {string} User unique id. * @returns {*|Promise.<T>|Promise|axios.Promise} */ deleteUser(userId) { var path_ = this.protocols._getPath('framework/user'); path_ = `${path_}/${userId}`; return this.protocols.apiDelete(path_); } /** * Call this api to change the password for user. * * @param oldpassword {string} - users: pass in clear text old * password. admin use: pass in clear text string *optional* * for admin reset ( must be called by user in administrators * group ) * @param newpassword {string} - clear text new user password * @returns {string} - status message of modifying password * A promise. * then: dict of result, status 0 as success, message as * array of strings of messages. * catch: error status, text and message. */ resetPassword(oldpassword, newpassword) { var path_ = this.protocols._getPath('framework/password'); var body_ = { 'oldpassword': oldpassword, 'newpassword': newpassword }; return this.protocols.apiPut(path_, body_); } /** * Call this api to change password to current logged in user. * Special version for first time login and reset password. * * TODO: Fix this security glitch! * * @param newpassword {string} Clear text new user password * @returns {*|Promise.<T>|Promise|axios.Promise} * A promise. * then: dict of result, status 0 as success, message as * array of strings of messages. * catch: error status, text and message. */ changePasswordWithoutOld(newpassword) { var path_ = this.protocols._getPath('framework/password'); var body_ = { 'newpassword': newpassword }; return this.protocols.apiPost(path_, body_); } /** * Admin users call this function to set other user's password. * Server will check if the user calling this function is admin. * * @param username {string} This function use username instead of * user id. Username should also be unique. * @param password {string} Plain text new user password * @returns {*|Promise.<T>|Promise|axios.Promise} */ adminSetPassword(username, password) { var path_ = this.protocols._getPath('framework/password/admin'); var body_ = { 'username': username, 'newpassword': password }; return this.protocols.apiPost(path_, body_); } /** * Get a list of all groups with name, id, and list of users of * groups. * * @returns {*|Promise.<T>|Promise|axios.Promise} */ getListOfGroups() { var path_ = this.protocols._getPath('framework/group'); return this.protocols.apiGet(path_); } /** * Create a new group. * * @param groupName {string} Group name, should be unique. * @param description {string} Description of the group. * @returns {*|Promise.<T>|Promise|axios.Promise} */ createNewGroup(groupName, description) { var path_ = this.protocols._getPath('framework/group'); var body_ = { 'groupName': groupName, 'groupDescription': description }; return this.protocols.apiPost(path_, body_); } /** * Edit a group info. Only group description can be change. * * @param groupId {string} Unique database id for group. * @param groupName {string} Unique group name. * @param description {string} * @returns {*|Promise.<T>|Promise|axios.Promise} */ editGroup(groupId, groupName, description) { // Group name should be able to change but now we are // using group name as id in some place, so we must keep it // unchanged. var path_ = this.protocols._getPath('framework/group'); path_ = `${path_}/${groupId}`; var body_ = { 'groupName': groupName, 'groupDescription': description }; return this.protocols.apiPut(path_, body_); } /** * Delete a group from database. * * @param groupId {string} Unique database id for group. * @returns {*|Promise.<T>|Promise|axios.Promise} */ deleteGroup(groupId) { // Chosen group will remain there. Need to fix sometime. var path_ = this.protocols._getPath('framework/group'); path_ = `${path_}/${groupId}`; return this.protocols.apiDelete(path_); } /** * Add a user to a group. * * @param groupId {string} Group to add a user to. * @param userId {string} Add this user to group. * @returns {*|Promise.<T>|Promise|axios.Promise} */ groupAddUser(groupId, userId) { var path_ = this.protocols._getPath('framework/usergroup'); path_ = `${path_}/${groupId}/${userId}`; return this.protocols.apiPost(path_, {}); } /** * Remove a user from a group. * * @param groupId {string} Group to remove user. * @param userId {string} This user will be removed from given * group. * @returns {*|Promise.<T>|Promise|axios.Promise} */ groupRemoveUser(groupId, userId) { var path_ = this.protocols._getPath('framework/usergroup'); path_ = `${path_}/${groupId}/${userId}`; return this.protocols.apiDelete(path_); } /** * Update user email address. Will be obselete soon. * * @param email {string} Email address. * @returns {*|Promise.<T>|Promise|axios.Promise} */ updateUserEmail(email) { var path_ = this.protocols._getPath('domain/user/email'); path_ = `${path_}/${email}`; var body_ = {}; return this.protocols.apiPost(path_, body_); } /** * Confirm email address by username and key. At this point user * should not be logged in, so this call will bypass authentication * and use username. * * @param username {string} Username, should be unique. * @param key {string} System generated one time key. * @returns {*|Promise.<T>|Promise|axios.Promise} */ confirmUserEmail(username, key) { // Maybe user id is a better idea. var path_ = this.protocols._getPath('domain/user/email'); path_ = `${path_}/${username}/confirm/${key}`; return this.protocols.apiPostNoAuth(path_, {}); } /** * @param treeID {string} - The treeID for which category * assignment is sought * @returns {object} - Category assignment object */ getAssignCategory(treeID) { var path_ = this.protocols._getPath('domain/getAssignCategory'); path_ = `${path_}/${encodeURIComponent(treeID)}`; return this.protocols.apiGet(path_); } /** * Get template restriction by tree id. * * @param treeId {string} Root node name as tree id. * * @returns {*|Promise.<T>|Promise|axios.Promise} Resolved will * be a list of chosen template names and a list of unchosen. */ getTemplateRestrictions(treeId) { var path_ = this.protocols._getPath('domain/restrict/template'); path_ = `${path_}/${encodeURIComponent(treeId)}`; return this.protocols.apiGet(path_); } /** * Set template restriction. * * @param treeId {string} Root node name as tree id. * @param chosenTemplates {Array<string>} Array of chosen template * names. We do not save unchosen ones. * @returns {*|Promise.<T>|Promise|axios.Promise} */ setTemplateRestrictions(treeId, chosenTemplates) { var path_ = this.protocols._getPath('domain/restrict/template'); path_ = `${path_}/${encodeURIComponent(treeId)}`; var body_ = {'chosen': chosenTemplates}; return this.protocols.apiPut(path_, body_); } /** * Get group restrictions. Same thing as templates. * * @param treeId {string} Root node name as tree id. * @returns {*|Promise.<T>|Promise|axios.Promise} Two arrays of * chosen and unchosen. */ getGroupRestrictions(treeId) { var path_ = this.protocols._getPath('domain/restrict/group'); path_ = `${path_}/${encodeURIComponent(treeId)}`; return this.protocols.apiGet(path_); } /** * Set group restrictions. * * @param treeId {string} Root node name as tree id. * @param chosenGroups {Array<string>} Array of chosen group * names. We do not save unchosen ones. * @returns {*|Promise.<T>|Promise|axios.Promise} */ setGroupRestrictions(treeId, chosenGroups) { // Deleted groups will still be in this list. Need to fix. var path_ = this.protocols._getPath('domain/restrict/group'); path_ = `${path_}/${encodeURIComponent(treeId)}`; var body_ = {'chosen': chosenGroups}; return this.protocols.apiPut(path_, body_); } /** * Set group restrictions and template restrictions at the same * time. * * @param treeId {string} Root node name as tree id. * @param groups {Array<string>} Array of chosen group names. * @param templates {Array<string>} Array of chosen template * names. * @returns {*|Promise.<T>|Promise|axios.Promise} */ setGroupsAndTemplatesRestrictions(treeId, groups, templates) { var path_ = this.protocols._getPath('domain/restrict/both'); path_ = `${path_}/${encodeURIComponent(treeId)}`; var body_ = { 'groups': groups, 'templates': templates }; return this.protocols.apiPut(path_, body_); } /** * Get access control list through tree id. * * @param treeId {string} Root node name as tree id. * @returns {*|Promise.<T>|Promise|axios.Promise} Resolved will * get a acl object with owner and acl groups. */ getAcl(treeId) { var path_ = this.protocols._getPath('domain/acl'); path_ = `${path_}/${encodeURIComponent(treeId)}`; return this.protocols.apiGet(path_); } /** * Set acl info. * * @param treeId {string} Root node name as tree id. * @param acl {object} Though we request acl object here, we only * save group info into database. * @returns {*|Promise.<T>|Promise|axios.Promise} */ setAcl(treeId, acl) { var path_ = this.protocols._getPath('domain/acl'); path_ = `${path_}/${encodeURIComponent(treeId)}`; var body_ = { 'acl': acl }; return this.protocols.apiPut(path_, body_); } /** * Get welcome message, including license and security warning. * * @param messageType {string} Can be LICENSE and SECURITY_WARNING. * @returns {*|Promise.<T>|Promise|axios.Promise} */ getWelcomeMessage(messageType) { var path_ = this.protocols._getPath('domain/welcome/message'); path_ = `${path_}/${messageType}`; return this.protocols.apiGet(path_); } /** * Set welcome message. This function will push whatever string * passed in without doing any encoding. So encode the message * before calling this. * * @param messageType {string} Can be LICENSE and SECURITY_WARNING. * @param message {string} Message to be save into database. * @param state {boolean} True for always display. * @returns {*|Promise.<T>|Promise|axios.Promise} */ setWelcomeMessage(messageType, message, state) { var path_ = this.protocols._getPath('domain/welcome/message'); path_ = `${path_}/${messageType}`; var body_ = { 'message': message, 'state': state }; return this.protocols.apiPut(path_, body_); } /** * Accept license or security warnings. * * @param messageType {string} Can be LICENSE and SECURITY_WARNING. * @returns {*|Promise.<T>|Promise|axios.Promise} */ acceptWelcomeMessage(messageType) { var path_ = this.protocols._getPath('domain/welcome/accept'); path_ = `${path_}/${messageType}`; return this.protocols.apiPut(path_, {}); } /** * Fetch input data in a excel format string. * * @param treeID {string} Tree id, ie. root node name. * @param nodeID {string} Node id, can be any node. Will download * input of a subtree from this node. * * @return {*|Promise.<T>|Promise|axios.Promise} * Download input promise. * then: * catch: */ fetchInputData(treeID, nodeID) { var path_ = this.protocols._getPath('domain/download/input'); path_ = `${path_}/${encodeURIComponent(treeID)}/${nodeID}`; return this.protocols.apiGet(path_); } /** * Request reset password. * @param username {string} * @param email {string} * @returns {*|Promise.<T>|Promise|axios.Promise} */ requestResetPassword(username, email) { var path_ = this.protocols._getPath('framework/password/request'); path_ = `${path_}/${username}/${email}`; return this.protocols.apiGetNoAuth(path_); } /** * Check if the username and key matches and not expired. * * @param username {string} * @param key {string} * @returns {*|Promise.<T>|Promise|axios.Promise} */ checkResetPasswordKey(username, key) { var path_ = this.protocols._getPath('framework/password/reset'); path_ = `${path_}/${username}/${key}`; return this.protocols.apiGetNoAuth(path_); } /** * Reset password to new password. Will check the username and * key again to make sure everything is correct. * * @param username {string} * @param key {string} * @param newPassword {string} * @returns {*|Promise.<T>|Promise|axios.Promise} */ resetPasswordThroughEmail(username, key, newPassword) { var path_ = this.protocols._getPath('framework/password/reset'); path_ = `${path_}/${username}/${key}`; var body_ = { newpass: newPassword }; return this.protocols.apiPostNoAuth(path_, body_); } /** * Downloads spreadsheet model applicable at node with given nodeID. * Data is a json object with the following structure: * @example * smartorg.downloadSpreadsheet(myNodeID).then(function(answer) { * console.log(answer.templateName); // e.g. simpleLaunch * console.log(answer.extension); // e.g. xls * console.log(answer.modelData); // Base-64 encoded binary data * }).catch(function(err) { * console.log(err); * }); * @param nodeID * @return {*|Promise|axios.Promise} */ downloadSpreadsheet(nodeID) { var path_ = this.protocols._getPath('domain/downloadTemplate'); path_ = `${path_}/${nodeID}`; var body_ = {}; return this.protocols.apiPostNoAuth(path_, body_); } } export default SmartOrg; // module.exports = SmartOrg; //For users not using a module loading eg(browersify), need a way // to expose it to them via the window object if (typeof window != 'undefined') { window.SmartOrg = SmartOrg; } //[NOTES] // // [1] - Promises - alt way to bubble promise up to next catch statement ... // throw new APIErr({'status':error.status,'statusText':error.statusText,'message':error.data.message}) // // [2] - Symbols - a neat way to set ACL/scope on methods etc ... // export const createHMACget = Symbol('createHMACget'); // is possible to use reflection but hides this sufficiently for now ... // also if you wanted to extend SmartOrg ... avoids name collisions // // [3] - Symbols - Private Fxn in action // symbols way to define unique primatives and give controll over access to properties and avoid collisions // prototype instances named props on fxns // this is a way to hide - /* var rangal = new Rangal("server.smartorg.com"); rangal.login(username,password, function(loginStatus) {}); rangal.treeFor("Product Launch", function(treeJSON) {}); rangal.actionByDisplayName("Product Launch", "Breath Strips Node ID", "Tornado Action ID", function(tornadoJSON) {}); rangal.portfolios(function(portfolioJSON) {}); rangal.actionMenuFor("Product Launch", "Breath Strips", function(actionMenuJSON){}); */