/** * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ /** * @mixin @node-red/runtime_flows */ /** * @typedef Flows * @type {object} * @property {string} rev - the flow revision identifier * @property {Array} flows - the flow configuration, an array of node configuration objects */ /** * @typedef Flow * @type {object} * @property {string} id - the flow identifier * @property {string} label - a label for the flow * @property {Array} nodes - an array of node configuration objects */ var runtime; var api = module.exports = { init: function(_runtime) { runtime = _runtime; }, /** * Gets the current flow configuration * @param {Object} opts * @param {User} opts.user - the user calling the api * @return {Promise} - the active flow configuration * @memberof @node-red/runtime_flows */ getFlows: function(opts) { return new Promise(function(resolve,reject) { runtime.log.audit({event: "flows.get"}/*,req*/); return resolve(runtime.nodes.getFlows()); }); }, /** * Sets the current flow configuration * @param {Object} opts * @param {User} opts.user - the user calling the api * @return {Promise} - the active flow configuration * @memberof @node-red/runtime_flows */ setFlows: function(opts) { return new Promise(function(resolve,reject) { var flows = opts.flows; var deploymentType = opts.deploymentType||"full"; runtime.log.audit({event: "flows.set",type:deploymentType}/*,req*/); var apiPromise; if (deploymentType === 'reload') { apiPromise = runtime.nodes.loadFlows(true); } else { if (flows.hasOwnProperty('rev')) { var currentVersion = runtime.nodes.getFlows().rev; if (currentVersion !== flows.rev) { var err; err = new Error(); err.code = "version_mismatch"; err.status = 409; //TODO: log warning return reject(err); } } apiPromise = runtime.nodes.setFlows(flows.flows,deploymentType); } apiPromise.then(function(flowId) { return resolve({rev:flowId}); }).catch(function(err) { runtime.log.warn(runtime.log._("api.flows.error-"+(deploymentType === 'reload'?'reload':'save'),{message:err.message})); runtime.log.warn(err.stack); return reject(err); }); }); }, /** * Adds a flow configuration * @param {Object} opts * @param {User} opts.user - the user calling the api * @param {Object} opts.flow - the flow to add * @return {Promise} - the id of the added flow * @memberof @node-red/runtime_flows */ addFlow: function(opts) { return new Promise(function(resolve,reject) { var flow = opts.flow; runtime.nodes.addFlow(flow).then(function(id) { runtime.log.audit({event: "flow.add",id:id}); return resolve(id); }).catch(function(err) { runtime.log.audit({event: "flow.add",error:err.code||"unexpected_error",message:err.toString()}); err.status = 400; return reject(err); }) }) }, /** * Gets an individual flow configuration * @param {Object} opts * @param {User} opts.user - the user calling the api * @param {Object} opts.id - the id of the flow to retrieve * @return {Promise} - the active flow configuration * @memberof @node-red/runtime_flows */ getFlow: function(opts) { return new Promise(function (resolve,reject) { var flow = runtime.nodes.getFlow(opts.id); if (flow) { runtime.log.audit({event: "flow.get",id:opts.id}); return resolve(flow); } else { runtime.log.audit({event: "flow.get",id:opts.id,error:"not_found"}); var err = new Error(); err.code = "not_found"; err.status = 404; return reject(err); } }) }, /** * Updates an existing flow configuration * @param {Object} opts * @param {User} opts.user - the user calling the api * @param {Object} opts.id - the id of the flow to update * @param {Object} opts.flow - the flow configuration * @return {Promise} - the id of the updated flow * @memberof @node-red/runtime_flows */ updateFlow: function(opts) { return new Promise(function (resolve,reject) { var flow = opts.flow; var id = opts.id; try { runtime.nodes.updateFlow(id,flow).then(function() { runtime.log.audit({event: "flow.update",id:id}); return resolve(id); }).catch(function(err) { runtime.log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()}); err.status = 400; return reject(err); }) } catch(err) { if (err.code === 404) { runtime.log.audit({event: "flow.update",id:id,error:"not_found"}); // TODO: this swap around of .code and .status isn't ideal err.status = 404; err.code = "not_found"; return reject(err); } else { runtime.log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()}); err.status = 400; return reject(err); } } }); }, /** * Deletes a flow * @param {Object} opts * @param {User} opts.user - the user calling the api * @param {Object} opts.id - the id of the flow to delete * @return {Promise} - resolves if successful * @memberof @node-red/runtime_flows */ deleteFlow: function(opts) { return new Promise(function (resolve,reject) { var id = opts.id; try { runtime.nodes.removeFlow(id).then(function() { runtime.log.audit({event: "flow.remove",id:id}); return resolve(); }).catch(function(err) { runtime.log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}); err.status = 400; return reject(err); }); } catch(err) { if (err.code === 404) { runtime.log.audit({event: "flow.remove",id:id,error:"not_found"}); // TODO: this swap around of .code and .status isn't ideal err.status = 404; err.code = "not_found"; return reject(err); } else { runtime.log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}); err.status = 400; return reject(err); } } }); }, /** * Gets the safe credentials for a node * @param {Object} opts * @param {User} opts.user - the user calling the api * @param {String} opts.type - the node type to return the credential information for * @param {String} opts.id - the node id * @return {Promise} - the safe credentials * @memberof @node-red/runtime_flows */ getNodeCredentials: function(opts) { return new Promise(function(resolve,reject) { runtime.log.audit({event: "credentials.get",type:opts.type,id:opts.id}); var credentials = runtime.nodes.getCredentials(opts.id); if (!credentials) { return resolve({}); } var definition = runtime.nodes.getCredentialDefinition(opts.type) || {}; var sendCredentials = {}; for (var cred in definition) { if (definition.hasOwnProperty(cred)) { if (definition[cred].type == "password") { var key = 'has_' + cred; sendCredentials[key] = credentials[cred] != null && credentials[cred] !== ''; continue; } sendCredentials[cred] = credentials[cred] || ''; } } resolve(sendCredentials); }) } }