pull out editor-client and editor-api

This commit is contained in:
Nick O'Leary
2018-08-17 22:10:54 +01:00
parent 6b79c6135f
commit e57d8ba0ef
287 changed files with 245 additions and 294 deletions

View File

@@ -0,0 +1,131 @@
/**
* 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.
**/
/**
* @namespace RED.comms
*/
/**
* @typedef CommsConnection
* @type {object}
* @property {string} session - a unique session identifier
* @property {Object} user - the user associated with the connection
* @property {Function} send - publish a message to the connection
*/
var runtime;
var retained = {};
var connections = [];
function handleCommsEvent(event) {
publish(event.topic,event.data,event.retain);
}
function handleStatusEvent(event) {
publish("status/"+event.id,event.status,true);
}
function handleRuntimeEvent(event) {
runtime.log.trace("runtime event: "+JSON.stringify(event));
publish("notification/"+event.id,event.payload||{},event.retain);
}
function publish(topic,data,retain) {
if (retain) {
retained[topic] = data;
} else {
delete retained[topic];
}
connections.forEach(connection => connection.send(topic,data))
}
var api = module.exports = {
init: function(_runtime) {
runtime = _runtime;
connections = [];
retained = {};
runtime.events.removeListener("node-status",handleStatusEvent);
runtime.events.on("node-status",handleStatusEvent);
runtime.events.removeListener("runtime-event",handleRuntimeEvent);
runtime.events.on("runtime-event",handleRuntimeEvent);
runtime.events.removeListener("comms",handleCommsEvent);
runtime.events.on("comms",handleCommsEvent);
},
/**
* Registers a new comms connection
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {CommsConnection} opts.client - the client connection
* @return {Promise<Object>} - resolves when complete
* @memberof RED.comms
*/
addConnection: function(opts) {
connections.push(opts.client);
return Promise.resolve();
},
/**
* Unregisters a comms connection
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {CommsConnection} opts.client - the client connection
* @return {Promise<Object>} - resolves when complete
* @memberof RED.comms
*/
removeConnection: function(opts) {
for (var i=0;i<connections.length;i++) {
if (connections[i] === opts.client) {
connections.splice(i,1);
break;
}
}
return Promise.resolve();
},
/**
* Subscribes a comms connection to a given topic. Currently, all clients get
* automatically subscribed to everything and cannot unsubscribe. Sending a subscribe
* request will trigger retained messages to be sent.
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {CommsConnection} opts.client - the client connection
* @param {String} opts.topic - the topic to subscribe to
* @return {Promise<Object>} - resolves when complete
* @memberof RED.comms
*/
subscribe: function(opts) {
var re = new RegExp("^"+opts.topic.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
for (var t in retained) {
if (re.test(t)) {
opts.client.send(t,retained[t]);
}
}
return Promise.resolve();
},
/**
* TODO: Unsubscribes a comms connection from a given topic
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {CommsConnection} opts.client - the client connection
* @param {String} opts.topic - the topic to unsubscribe from
* @return {Promise<Object>} - resolves when complete
* @memberof RED.comms
*/
unsubscribe: function(opts) {}
};

View File

@@ -0,0 +1,156 @@
/**
* 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.
**/
/**
* @namespace RED.context
*/
var runtime;
// TODO: move runtime/util to util/index
var util = require("@node-red/util").util;
function exportContextStore(scope,ctx, store, result, callback) {
ctx.keys(store,function(err, keys) {
if (err) {
return callback(err);
}
result[store] = {};
var c = keys.length;
if (c === 0) {
callback(null);
} else {
keys.forEach(function(key) {
ctx.get(key,store,function(err, v) {
if (err) {
return callback(err);
}
if (scope !== 'global' ||
store === runtime.nodes.listContextStores().default ||
!runtime.settings.hasOwnProperty("functionGlobalContext") ||
!runtime.settings.functionGlobalContext.hasOwnProperty(key) ||
runtime.settings.functionGlobalContext[key] !== v) {
result[store][key] = util.encodeObject({msg:v});
}
c--;
if (c === 0) {
callback(null);
}
});
});
}
});
}
var api = module.exports = {
init: function(_runtime) {
runtime = _runtime;
},
/**
* Gets the info of an individual node set
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.scope - the scope of the context
* @param {String} opts.id - the id of the context
* @param {String} opts.store - the context store
* @param {String} opts.key - the context key
* @return {Promise} - the node information
* @memberof RED.nodes
*/
getValue: function(opts) {
return new Promise(function(resolve,reject) {
var scope = opts.scope;
var id = opts.id;
var store = opts.store;
var key = opts.key;
var availableStores = runtime.nodes.listContextStores();
//{ default: 'default', stores: [ 'default', 'file' ] }
if (store && availableStores.stores.indexOf(store) === -1) {
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key,error:"not_found"});
var err = new Error();
err.code = "not_found";
err.status = 404;
return reject(err);
}
var ctx;
if (scope === 'global') {
ctx = runtime.nodes.getContext('global');
} else if (scope === 'flow') {
ctx = runtime.nodes.getContext(id);
} else if (scope === 'node') {
var node = runtime.nodes.getNode(id);
if (node) {
ctx = node.context();
}
}
if (ctx) {
if (key) {
store = store || availableStores.default;
ctx.get(key,store,function(err, v) {
var encoded = util.encodeObject({msg:v});
if (store !== availableStores.default) {
encoded.store = store;
}
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key});
resolve(encoded);
});
return;
} else {
var stores;
if (!store) {
stores = availableStores.stores;
} else {
stores = [store];
}
var result = {};
var c = stores.length;
var errorReported = false;
stores.forEach(function(store) {
exportContextStore(scope,ctx,store,result,function(err) {
if (err) {
// TODO: proper error reporting
if (!errorReported) {
errorReported = true;
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key,error:"unexpected_error"});
var err = new Error();
err.code = "unexpected_error";
err.status = 400;
return reject(err);
}
return;
}
c--;
if (c === 0) {
if (!errorReported) {
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key});
resolve(result);
}
}
});
})
}
} else {
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key});
resolve({});
}
})
}
}

View File

@@ -0,0 +1,251 @@
/**
* 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.
**/
/**
* @namespace RED.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<Flows>} - the active flow configuration
* @memberof RED.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<Flows>} - the active flow configuration
* @memberof RED.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();
} 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<String>} - the id of the added flow
* @memberof RED.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<Flow>} - the active flow configuration
* @memberof RED.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<String>} - the id of the updated flow
* @memberof RED.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 RED.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<Object>} - the safe credentials
* @memberof RED.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);
})
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.
**/
/**
* A user accessing the API
* @typedef User
* @type {object}
*/
var runtime;
/**
* @namespace RED
*/
var api = module.exports = {
init: function(_runtime) {
runtime = _runtime;
api.comms.init(runtime);
api.flows.init(runtime);
api.nodes.init(runtime);
api.settings.init(runtime);
api.library.init(runtime);
api.projects.init(runtime);
api.context.init(runtime);
},
comms: require("./comms"),
flows: require("./flows"),
library: require("./library"),
nodes: require("./nodes"),
settings: require("./settings"),
projects: require("./projects"),
context: require("./context"),
/**
* Returns whether the runtime is started
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<Boolean>} - whether the runtime is started
* @memberof RED
*/
isStarted: function(opts) {
return Promise.resolve(runtime.isStarted());
},
/**
* Returns version number of the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<String>} - the runtime version number
* @memberof RED
*/
version: function(opts) {
return Promise.resolve(runtime.version());
}
}

View File

@@ -0,0 +1,120 @@
/**
* 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.
**/
/**
* @namespace RED.library
*/
var runtime;
var api = module.exports = {
init: function(_runtime) {
runtime = _runtime;
},
/**
* Gets an entry from the library.
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.type - the type of entry
* @param {String} opts.path - the path of the entry
* @return {Promise<String|Object>} - resolves when complete
* @memberof RED.library
*/
getEntry: function(opts) {
return new Promise(function(resolve,reject) {
runtime.library.getEntry(opts.type,opts.path).then(function(result) {
runtime.log.audit({event: "library.get",type:opts.type,path:opts.path});
return resolve(result);
}).catch(function(err) {
if (err) {
runtime.log.warn(runtime.log._("api.library.error-load-entry",{path:opts.path,message:err.toString()}));
if (err.code === 'forbidden') {
err.status = 403;
return reject(err);
} else if (err.code === "not_found") {
err.status = 404;
} else {
err.status = 400;
}
runtime.log.audit({event: "library.get",type:opts.type,path:opts.path,error:err.code});
return reject(err);
}
runtime.log.audit({event: "library.get",type:opts.type,error:"not_found"});
var error = new Error();
error.code = "not_found";
error.status = 404;
return reject(error);
});
})
},
/**
* Saves an entry to the library
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.type - the type of entry
* @param {String} opts.path - the path of the entry
* @param {Object} opts.meta - any meta data associated with the entry
* @param {String} opts.body - the body of the entry
* @return {Promise} - resolves when complete
* @memberof RED.library
*/
saveEntry: function(opts) {
return new Promise(function(resolve,reject) {
runtime.library.saveEntry(opts.type,opts.path,opts.meta,opts.body).then(function() {
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path});
return resolve();
}).catch(function(err) {
runtime.log.warn(runtime.log._("api.library.error-save-entry",{path:opts.path,message:err.toString()}));
if (err.code === 'forbidden') {
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path,error:"forbidden"});
err.status = 403;
return reject(err);
}
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path,error:"unexpected_error",message:err.toString()});
var error = new Error();
error.status = 400;
return reject(error);
});
})
},
/**
* Returns a complete listing of all entries of a given type in the library.
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.type - the type of entry
* @return {Promise<Object>} - the entry listing
* @memberof RED.library
*/
getEntries: function(opts) {
return new Promise(function(resolve,reject) {
if (opts.type !== 'flows') {
return reject(new Error("API only supports flows"));
}
runtime.storage.getAllFlows().then(function(flows) {
runtime.log.audit({event: "library.get.all",type:"flow"});
var examples = runtime.nodes.getNodeExampleFlows();
if (examples) {
flows.d = flows.d||{};
flows.d._examples_ = examples;
}
return resolve(flows);
});
})
}
}

View File

@@ -0,0 +1,442 @@
/**
* 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.
**/
/**
* @namespace RED.nodes
*/
var fs = require("fs");
var runtime;
function putNode(node, enabled) {
var info;
var promise;
if (!node.err && node.enabled === enabled) {
promise = Promise.resolve(node);
} else {
if (enabled) {
promise = runtime.nodes.enableNode(node.id);
} else {
promise = runtime.nodes.disableNode(node.id);
}
}
return promise;
}
var api = module.exports = {
init: function(_runtime) {
runtime = _runtime;
},
/**
* Gets the info of an individual node set
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the node set to return
* @return {Promise<NodeInfo>} - the node information
* @memberof RED.nodes
*/
getNodeInfo: function(opts) {
return new Promise(function(resolve,reject) {
var id = opts.id;
var result = runtime.nodes.getNodeInfo(id);
if (result) {
runtime.log.audit({event: "nodes.info.get",id:id});
delete result.loaded;
return resolve(result);
} else {
runtime.log.audit({event: "nodes.info.get",id:id,error:"not_found"});
var err = new Error();
err.code = "not_found";
err.status = 404;
return reject(err);
}
})
},
/**
* Gets the list of node modules installed in the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<NodeList>} - the list of node modules
* @memberof RED.nodes
*/
getNodeList: function(opts) {
return new Promise(function(resolve,reject) {
runtime.log.audit({event: "nodes.list.get"});
return resolve(runtime.nodes.getNodeList());
})
},
/**
* Gets an individual node's html content
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the node set to return
* @param {String} opts.lang - the locale language to return
* @return {Promise<String>} - the node html content
* @memberof RED.nodes
*/
getNodeConfig: function(opts) {
return new Promise(function(resolve,reject) {
var id = opts.id;
var lang = opts.lang;
var result = runtime.nodes.getNodeConfig(id,lang);
if (result) {
runtime.log.audit({event: "nodes.config.get",id:id});
return resolve(result);
} else {
runtime.log.audit({event: "nodes.config.get",id:id,error:"not_found"});
var err = new Error();
err.code = "not_found";
err.status = 404;
return reject(err);
}
});
},
/**
* Gets all node html content
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.lang - the locale language to return
* @return {Promise<String>} - the node html content
* @memberof RED.nodes
*/
getNodeConfigs: function(opts) {
return new Promise(function(resolve,reject) {
runtime.log.audit({event: "nodes.configs.get"});
return resolve(runtime.nodes.getNodeConfigs(opts.lang));
});
},
/**
* Gets the info of a node module
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.module - the id of the module to return
* @return {Promise<ModuleInfo>} - the node module info
* @memberof RED.nodes
*/
getModuleInfo: function(opts) {
return new Promise(function(resolve,reject) {
var result = runtime.nodes.getModuleInfo(opts.module);
if (result) {
runtime.log.audit({event: "nodes.module.get",id:opts.module});
return resolve(result);
} else {
runtime.log.audit({event: "nodes.module.get",id:opts.module,error:"not_found"});
var err = new Error();
err.code = "not_found";
err.status = 404;
return reject(err);
}
})
},
/**
* Install a new module into the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.module - the id of the module to install
* @param {String} opts.version - (optional) the version of the module to install
* @return {Promise<ModuleInfo>} - the node module info
* @memberof RED.nodes
*/
addModule: function(opts) {
return new Promise(function(resolve,reject) {
if (!runtime.settings.available()) {
runtime.log.audit({event: "nodes.install",error:"settings_unavailable"});
var err = new Error("Settings unavailable");
err.code = "settings_unavailable";
err.status = 400;
return reject(err);
}
if (opts.module) {
var existingModule = runtime.nodes.getModuleInfo(opts.module);
if (existingModule) {
if (!opts.version || existingModule.version === opts.version) {
runtime.log.audit({event: "nodes.install",module:opts.module, version:opts.version, error:"module_already_loaded"});
var err = new Error("Module already loaded");
err.code = "module_already_loaded";
err.status = 400;
return reject(err);
}
if (!existingModule.local) {
runtime.log.audit({event: "nodes.install",module:opts.module, version:opts.version, error:"module_not_local"});
var err = new Error("Module not locally installed");
err.code = "module_not_local";
err.status = 400;
return reject(err);
}
}
runtime.nodes.installModule(opts.module,opts.version).then(function(info) {
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version});
return resolve(info);
}).catch(function(err) {
if (err.code === 404) {
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:"not_found"});
// TODO: code/status
err.status = 404;
} else if (err.code) {
err.status = 400;
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:err.code});
} else {
err.status = 400;
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:err.code||"unexpected_error",message:err.toString()});
}
return reject(err);
})
} else {
runtime.log.audit({event: "nodes.install",module:opts.module,error:"invalid_request"});
var err = new Error("Invalid request");
err.code = "invalid_request";
err.status = 400;
return reject(err);
}
});
},
/**
* Removes a module from the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.module - the id of the module to remove
* @return {Promise} - resolves when complete
* @memberof RED.nodes
*/
removeModule: function(opts) {
return new Promise(function(resolve,reject) {
if (!runtime.settings.available()) {
runtime.log.audit({event: "nodes.install",error:"settings_unavailable"});
var err = new Error("Settings unavailable");
err.code = "settings_unavailable";
err.status = 400;
return reject(err);
}
var module = runtime.nodes.getModuleInfo(opts.module);
if (!module) {
runtime.log.audit({event: "nodes.remove",module:opts.module,error:"not_found"});
var err = new Error();
err.code = "not_found";
err.status = 404;
return reject(err);
}
try {
runtime.nodes.uninstallModule(opts.module).then(function() {
runtime.log.audit({event: "nodes.remove",module:opts.module});
resolve();
}).catch(function(err) {
err.status = 400;
runtime.log.audit({event: "nodes.remove",module:opts.module,error:err.code||"unexpected_error",message:err.toString()});
return reject(err);
})
} catch(error) {
runtime.log.audit({event: "nodes.remove",module:opts.module,error:error.code||"unexpected_error",message:error.toString()});
error.status = 400;
return reject(error);
}
});
},
/**
* Enables or disables a module in the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.module - the id of the module to enable or disable
* @param {String} opts.enabled - whether the module should be enabled or disabled
* @return {Promise<ModuleInfo>} - the module info object
* @memberof RED.nodes
*/
setModuleState: function(opts) {
var mod = opts.module;
return new Promise(function(resolve,reject) {
if (!runtime.settings.available()) {
runtime.log.audit({event: "nodes.module.set",error:"settings_unavailable"});
var err = new Error("Settings unavailable");
err.code = "settings_unavailable";
err.status = 400;
return reject(err);
}
try {
var module = runtime.nodes.getModuleInfo(mod);
if (!module) {
runtime.log.audit({event: "nodes.module.set",module:mod,error:"not_found"});
var err = new Error();
err.code = "not_found";
err.status = 404;
return reject(err);
}
var nodes = module.nodes;
var promises = [];
for (var i = 0; i < nodes.length; ++i) {
promises.push(putNode(nodes[i],opts.enabled));
}
Promise.all(promises).then(function() {
return resolve(runtime.nodes.getModuleInfo(mod));
}).catch(function(err) {
err.status = 400;
return reject(err);
});
} catch(error) {
runtime.log.audit({event: "nodes.module.set",module:mod,enabled:opts.enabled,error:error.code||"unexpected_error",message:error.toString()});
error.status = 400;
return reject(error);
}
});
},
/**
* Enables or disables a n individual node-set in the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the node-set to enable or disable
* @param {String} opts.enabled - whether the module should be enabled or disabled
* @return {Promise<ModuleInfo>} - the module info object
* @memberof RED.nodes
*/
setNodeSetState: function(opts) {
return new Promise(function(resolve,reject) {
if (!runtime.settings.available()) {
runtime.log.audit({event: "nodes.info.set",error:"settings_unavailable"});
var err = new Error("Settings unavailable");
err.code = "settings_unavailable";
err.status = 400;
return reject(err);
}
var id = opts.id;
var enabled = opts.enabled;
try {
var node = runtime.nodes.getNodeInfo(id);
if (!node) {
runtime.log.audit({event: "nodes.info.set",id:id,error:"not_found"});
var err = new Error();
err.code = "not_found";
err.status = 404;
return reject(err);
} else {
delete node.loaded;
putNode(node,enabled).then(function(result) {
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled});
return resolve(result);
}).catch(function(err) {
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:err.code||"unexpected_error",message:err.toString()});
err.status = 400;
return reject(err);
});
}
} catch(error) {
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:error.code||"unexpected_error",message:error.toString()});
error.status = 400;
return reject(error);
}
});
},
/**
* Gets all registered module message catalogs
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {User} opts.lang - the i18n language to return. If not set, uses runtime default (en-US)
* @return {Promise<Object>} - the message catalogs
* @memberof RED.nodes
*/
getModuleCatalogs: function(opts) {
return new Promise(function(resolve,reject) {
var namespace = opts.module;
var lang = opts.lang;
var prevLang = runtime.i18n.i.language;
// Trigger a load from disk of the language if it is not the default
runtime.i18n.i.changeLanguage(lang, function(){
var nodeList = runtime.nodes.getNodeList();
var result = {};
nodeList.forEach(function(n) {
if (n.module !== "node-red") {
result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{};
}
});
resolve(result);
});
runtime.i18n.i.changeLanguage(prevLang);
});
},
/**
* Gets a modules message catalog
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {User} opts.module - the module
* @param {User} opts.lang - the i18n language to return. If not set, uses runtime default (en-US)
* @return {Promise<Object>} - the message catalog
* @memberof RED.nodes
*/
getModuleCatalog: function(opts) {
return new Promise(function(resolve,reject) {
var namespace = opts.module;
var lang = opts.lang;
var prevLang = runtime.i18n.i.lng();
// Trigger a load from disk of the language if it is not the default
runtime.i18n.i.changeLanguage(lang, function(){
var catalog = runtime.i18n.getResourceBundle(lang, namespace);
resolve(catalog||{});
});
runtime.i18n.i.changeLanguage(prevLang);
});
},
/**
* Gets the list of all icons available in the modules installed within the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<IconList>} - the list of all icons
* @memberof RED.nodes
*/
getIconList: function(opts) {
return new Promise(function(resolve,reject) {
runtime.log.audit({event: "nodes.icons.get"});
return resolve(runtime.nodes.getNodeIcons());
});
},
/**
* Gets a node icon
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.module - the id of the module requesting the icon
* @param {String} opts.icon - the name of the icon
* @return {Promise<Buffer>} - the icon file as a Buffer or null if no icon available
* @memberof RED.nodes
*/
getIcon: function(opts) {
return new Promise(function(resolve,reject) {
var iconPath = runtime.nodes.getNodeIconPath(opts.module,opts.icon);
if (iconPath) {
fs.readFile(iconPath,function(err,data) {
if (err) {
err.status = 400;
return reject(err);
}
return resolve(data)
});
} else {
resolve(null);
}
});
}
}

View File

@@ -0,0 +1,440 @@
/**
* 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.
**/
/**
* @namespace RED.projects
*/
var runtime;
var api = module.exports = {
init: function(_runtime) {
runtime = _runtime;
},
available: function(opts) {
return Promise.resolve(!!runtime.storage.projects);
},
/**
* List projects known to the runtime
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
listProjects: function(opts) {
return runtime.storage.projects.listProjects(opts.user).then(function(list) {
var active = runtime.storage.projects.getActiveProject(opts.user);
var response = {
projects: list
};
if (active) {
response.active = active.name;
}
return response;
}).catch(function(err) {
err.status = 400;
throw err;
})
},
/**
* Create a new project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {Object} opts.project - the project information
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
createProject: function(opts) {
return runtime.storage.projects.createProject(opts.user, opts.project)
},
/**
* Initialises an empty project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project to initialise
* @param {Object} opts.project - the project information
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
initialiseProject: function(opts) {
// Initialised set when creating default files for an empty repo
return runtime.storage.projects.initialiseProject(opts.user, opts.id, opts.project)
},
/**
* Gets the active project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<Object>} - the active project
* @memberof RED.projects
*/
getActiveProject: function(opts) {
return Promise.resolve(runtime.storage.projects.getActiveProject(opts.user));
},
/**
*
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project to activate
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
setActiveProject: function(opts) {
var currentProject = runtime.storage.projects.getActiveProject(opts.user);
if (!currentProject || opts.id !== currentProject.name) {
return runtime.storage.projects.setActiveProject(opts.user, opts.id);
} else {
return Promise.resolve();
}
},
/**
* Gets a projects metadata
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project to get
* @return {Promise<Object>} - the project metadata
* @memberof RED.projects
*/
getProject: function(opts) {
return runtime.storage.projects.getProject(opts.user, opts.id)
},
/**
* Updates the metadata of an existing project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project to update
* @param {Object} opts.project - the project information
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
updateProject: function(opts) {
return runtime.storage.projects.updateProject(opts.user, opts.id, opts.project);
},
/**
* Deletes a project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project to update
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
deleteProject: function(opts) {
return runtime.storage.projects.deleteProject(opts.user, opts.id);
},
/**
* Gets current git status of a project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {Boolean} opts.remote - whether to include status of remote repos
* @return {Promise<Object>} - the project status
* @memberof RED.projects
*/
getStatus: function(opts) {
return runtime.storage.projects.getStatus(opts.user, opts.id, opts.remote)
},
/**
* Get a list of local branches
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {Boolean} opts.remote - whether to return remote branches (true) or local (false)
* @return {Promise<Object>} - a list of the local branches
* @memberof RED.projects
*/
getBranches: function(opts) {
return runtime.storage.projects.getBranches(opts.user, opts.id, opts.remote);
},
/**
* Gets the status of a branch
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.branch - the name of the branch
* @return {Promise<Object>} - the status of the branch
* @memberof RED.projects
*/
getBranchStatus: function(opts) {
return runtime.storage.projects.getBranchStatus(opts.user, opts.id, opts.branch);
},
/**
* Sets the current local branch
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.branch - the name of the branch
* @param {Boolean} opts.create - whether to create the branch if it doesn't exist
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
setBranch: function(opts) {
return runtime.storage.projects.setBranch(opts.user, opts.id, opts.branch, opts.create)
},
/**
* Deletes a branch
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.branch - the name of the branch
* @param {Boolean} opts.force - whether to force delete
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
deleteBranch: function(opts) {
return runtime.storage.projects.deleteBranch(opts.user, opts.id, opts.branch, false, opts.force);
},
/**
* Commits the current staged files
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.message - the message to associate with the commit
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
commit: function(opts) {
return runtime.storage.projects.commit(opts.user, opts.id,{message: opts.message});
},
/**
* Gets the details of a single commit
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.sha - the sha of the commit to return
* @return {Promise<Object>} - the commit details
* @memberof RED.projects
*/
getCommit: function(opts) {
return runtime.storage.projects.getCommit(opts.user, opts.id, opts.sha);
},
/**
* Gets the commit history of the project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.limit - limit how many to return
* @param {String} opts.before - id of the commit to work back from
* @return {Promise<Array>} - an array of commits
* @memberof RED.projects
*/
getCommits: function(opts) {
return runtime.storage.projects.getCommits(opts.user, opts.id, {
limit: opts.limit || 20,
before: opts.before
});
},
/**
* Abort an in-progress merge
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
abortMerge: function(opts) {
return runtime.storage.projects.abortMerge(opts.user, opts.id);
},
/**
* Resolves a merge conflict
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.path - the path of the file being merged
* @param {String} opts.resolutions - how to resolve the merge conflict
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
resolveMerge: function(opts) {
return runtime.storage.projects.resolveMerge(opts.user, opts.id, opts.path, opts.resolution);
},
/**
* Gets a listing of the files in the project
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @return {Promise<Object>} - the file listing
* @memberof RED.projects
*/
getFiles: function(opts) {
return runtime.storage.projects.getFiles(opts.user, opts.id);
},
/**
* Gets the contents of a file
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.path - the path of the file
* @param {String} opts.tree - the version control tree to use
* @return {Promise<String>} - the content of the file
* @memberof RED.projects
*/
getFile: function(opts) {
return runtime.storage.projects.getFile(opts.user, opts.id,opts.path,opts.tree);
},
/**
*
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String|Array} opts.path - the path of the file, or an array of paths
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
stageFile: function(opts) {
return runtime.storage.projects.stageFile(opts.user, opts.id, opts.path);
},
/**
*
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.path - the path of the file. If not set, all staged files are unstaged
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
unstageFile: function(opts) {
return runtime.storage.projects.unstageFile(opts.user, opts.id, opts.path);
},
/**
* Reverts changes to a file back to its commited version
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.path - the path of the file
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
revertFile: function(opts) {
return runtime.storage.projects.revertFile(opts.user, opts.id,opts.path)
},
/**
* Get the diff of a file
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.path - the path of the file
* @param {String} opts.type - the type of diff
* @return {Promise<Object>} - the requested diff
* @memberof RED.projects
*/
getFileDiff: function(opts) {
return runtime.storage.projects.getFileDiff(opts.user, opts.id, opts.path, opts.type);
},
/**
* Gets a list of the project remotes
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @return {Promise<Object>} - a list of project remotes
* @memberof RED.projects
*/
getRemotes: function(opts) {
return runtime.storage.projects.getRemotes(opts.user, opts.id);
},
/**
*
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {Object} opts.remote - the remote metadata
* @param {String} opts.remote.name - the name of the remote
* @param {String} opts.remote.url - the url of the remote
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
addRemote: function(opts) {
return runtime.storage.projects.addRemote(opts.user, opts.id, opts.remote)
},
/**
* Remove a project remote
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.remote - the name of the remote
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
removeRemote: function(opts) {
return runtime.storage.projects.removeRemote(opts.user, opts.id, opts.remote);
},
/**
*
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {Object} opts.remote - the remote metadata
* @param {String} opts.remote.name - the name of the remote
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
updateRemote: function(opts) {
return runtime.storage.projects.updateRemote(opts.user, opts.id, opts.remote.name, opts.remote)
},
/**
* Pull changes from the remote
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
pull: function(opts) {
return runtime.storage.projects.pull(opts.user, opts.id, opts.remote, opts.track, opts.allowUnrelatedHistories);
},
/**
* Push changes to a remote
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {String} opts.id - the id of the project
* @param {String} opts.remote - the name of the remote
* @param {String} opts.track - whether to set the remote as the upstream
* @return {Promise<Object>} - resolves when complete
* @memberof RED.projects
*/
push: function(opts) {
return runtime.storage.projects.push(opts.user, opts.id, opts.remote, opts.track);
}
}

View File

@@ -0,0 +1,267 @@
/**
* 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.
**/
/**
* @namespace RED.settings
*/
var util = require("util");
var runtime;
function extend(target, source) {
var keys = Object.keys(source);
var i = keys.length;
while(i--) {
var value = source[keys[i]]
var type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) {
target[keys[i]] = value;
} else if (value === null) {
if (target.hasOwnProperty(keys[i])) {
delete target[keys[i]];
}
} else {
// Object
if (target.hasOwnProperty(keys[i])) {
target[keys[i]] = extend(target[keys[i]],value);
} else {
target[keys[i]] = value;
}
}
}
return target;
}
function getSSHKeyUsername(userObj) {
var username = '__default';
if ( userObj && userObj.name ) {
username = userObj.name;
}
return username;
}
var api = module.exports = {
init: function(_runtime) {
runtime = _runtime;
},
/**
* Gets the runtime settings object
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<Object>} - the runtime settings
* @memberof RED.settings
*/
getRuntimeSettings: function(opts) {
return new Promise(function(resolve,reject) {
try {
var safeSettings = {
httpNodeRoot: runtime.settings.httpNodeRoot||"/",
version: runtime.settings.version
}
if (opts.user) {
safeSettings.user = {}
var props = ["anonymous","username","image","permissions"];
props.forEach(prop => {
if (opts.user.hasOwnProperty(prop)) {
safeSettings.user[prop] = opts.user[prop];
}
})
}
safeSettings.context = runtime.nodes.listContextStores();
if (util.isArray(runtime.settings.paletteCategories)) {
safeSettings.paletteCategories = runtime.settings.paletteCategories;
}
if (runtime.settings.flowFilePretty) {
safeSettings.flowFilePretty = runtime.settings.flowFilePretty;
}
if (!runtime.nodes.paletteEditorEnabled()) {
safeSettings.editorTheme = safeSettings.editorTheme || {};
safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {};
safeSettings.editorTheme.palette.editable = false;
}
if (runtime.storage.projects) {
var activeProject = runtime.storage.projects.getActiveProject();
if (activeProject) {
safeSettings.project = activeProject;
} else if (runtime.storage.projects.flowFileExists()) {
safeSettings.files = {
flow: runtime.storage.projects.getFlowFilename(),
credentials: runtime.storage.projects.getCredentialsFilename()
}
}
safeSettings.git = {
globalUser: runtime.storage.projects.getGlobalGitUser()
}
}
safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType();
runtime.settings.exportNodeSettings(safeSettings);
resolve(safeSettings);
}catch(err) {
console.log(err);
}
});
},
/**
* Gets an individual user's settings object
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<Object>} - the user settings
* @memberof RED.settings
*/
getUserSettings: function(opts) {
var username;
if (!opts.user || opts.user.anonymous) {
username = '_';
} else {
username = opts.user.username;
}
return Promise.resolve(runtime.settings.getUserSettings(username)||{});
},
/**
* Updates an individual user's settings object.
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {Object} opts.settings - the updates to the user settings
* @return {Promise<Object>} - the user settings
* @memberof RED.settings
*/
updateUserSettings: function(opts) {
var username;
if (!opts.user || opts.user.anonymous) {
username = '_';
} else {
username = opts.user.username;
}
return new Promise(function(resolve,reject) {
var currentSettings = runtime.settings.getUserSettings(username)||{};
currentSettings = extend(currentSettings, opts.settings);
try {
runtime.settings.setUserSettings(username, currentSettings).then(function() {
runtime.log.audit({event: "settings.update",username:username});
return resolve();
}).catch(function(err) {
runtime.log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()});
err.status = 400;
return reject(err);
});
} catch(err) {
log.warn(log._("settings.user-not-available",{message:log._("settings.not-available")}));
log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()});
err.status = 400;
return reject(err);
}
});
},
/**
* Gets a list of a user's ssh keys
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @return {Promise<Object>} - the user's ssh keys
* @memberof RED.settings
*/
getUserKeys: function(opts) {
return new Promise(function(resolve,reject) {
var username = getSSHKeyUsername(opts.user);
runtime.storage.projects.ssh.listSSHKeys(username).then(function(list) {
return resolve(list);
}).catch(function(err) {
err.status = 400;
return reject(err);
});
});
},
/**
* Gets a user's ssh public key
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {User} opts.id - the id of the key to return
* @return {Promise<String>} - the user's ssh public key
* @memberof RED.settings
*/
getUserKey: function(opts) {
return new Promise(function(resolve,reject) {
var username = getSSHKeyUsername(opts.user);
// console.log('username:', username);
runtime.storage.projects.ssh.getSSHKey(username, opts.id).then(function(data) {
if (data) {
return resolve(data);
} else {
var err = new Error("Key not found");
err.code = "not_found";
err.status = 404;
return reject(err);
}
}).catch(function(err) {
err.status = 400;
return reject(err);
});
});
},
/**
* Generates a new ssh key pair
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {User} opts.name - the id of the key to return
* @param {User} opts.password - (optional) the password for the key pair
* @param {User} opts.comment - (option) a comment to associate with the key pair
* @param {User} opts.size - (optional) the size of the key. Default: 2048
* @return {Promise<String>} - the id of the generated key
* @memberof RED.settings
*/
generateUserKey: function(opts) {
return new Promise(function(resolve,reject) {
var username = getSSHKeyUsername(opts.user);
runtime.storage.projects.ssh.generateSSHKey(username, opts).then(function(name) {
return resolve(name);
}).catch(function(err) {
err.status = 400;
return reject(err);
});
});
},
/**
* Deletes a user's ssh key pair
* @param {Object} opts
* @param {User} opts.user - the user calling the api
* @param {User} opts.id - the id of the key to delete
* @return {Promise} - resolves when deleted
* @memberof RED.settings
*/
removeUserKey: function(opts) {
return new Promise(function(resolve,reject) {
var username = getSSHKeyUsername(req.user);
runtime.storage.projects.ssh.deleteSSHKey(username, opts.id).then(function() {
return resolve();
}).catch(function(err) {
err.status = 400;
return reject(err);
});
});
}
}