mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add /settings/user end point
This commit is contained in:
parent
a7e14f1093
commit
fff0b15ae5
@ -19,7 +19,6 @@ var express = require("express");
|
|||||||
var nodes = require("./nodes");
|
var nodes = require("./nodes");
|
||||||
var flows = require("./flows");
|
var flows = require("./flows");
|
||||||
var flow = require("./flow");
|
var flow = require("./flow");
|
||||||
var info = require("./info");
|
|
||||||
var auth = require("../auth");
|
var auth = require("../auth");
|
||||||
|
|
||||||
var apiUtil = require("../util");
|
var apiUtil = require("../util");
|
||||||
@ -28,7 +27,6 @@ module.exports = {
|
|||||||
init: function(runtime) {
|
init: function(runtime) {
|
||||||
flows.init(runtime);
|
flows.init(runtime);
|
||||||
flow.init(runtime);
|
flow.init(runtime);
|
||||||
info.init(runtime);
|
|
||||||
nodes.init(runtime);
|
nodes.init(runtime);
|
||||||
|
|
||||||
var needsPermission = auth.needsPermission;
|
var needsPermission = auth.needsPermission;
|
||||||
@ -54,9 +52,6 @@ module.exports = {
|
|||||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler);
|
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler);
|
||||||
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler);
|
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler);
|
||||||
|
|
||||||
// Settings
|
|
||||||
adminApp.get("/settings",needsPermission("settings.read"),info.settings,apiUtil.errorHandler);
|
|
||||||
|
|
||||||
return adminApp;
|
return adminApp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ var path = require('path');
|
|||||||
|
|
||||||
var comms = require("./comms");
|
var comms = require("./comms");
|
||||||
var library = require("./library");
|
var library = require("./library");
|
||||||
|
var info = require("./settings");
|
||||||
|
|
||||||
var auth = require("../auth");
|
var auth = require("../auth");
|
||||||
var needsPermission = auth.needsPermission;
|
var needsPermission = auth.needsPermission;
|
||||||
@ -41,7 +42,7 @@ module.exports = {
|
|||||||
log = runtime.log;
|
log = runtime.log;
|
||||||
var settings = runtime.settings;
|
var settings = runtime.settings;
|
||||||
if (!settings.disableEditor) {
|
if (!settings.disableEditor) {
|
||||||
|
info.init(runtime);
|
||||||
comms.init(server,runtime);
|
comms.init(server,runtime);
|
||||||
|
|
||||||
var ui = require("./ui");
|
var ui = require("./ui");
|
||||||
@ -89,6 +90,14 @@ module.exports = {
|
|||||||
credentials.init(runtime);
|
credentials.init(runtime);
|
||||||
editorApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,apiUtil.errorHandler);
|
editorApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,apiUtil.errorHandler);
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
editorApp.get("/settings",needsPermission("settings.read"),info.runtimeSettings,apiUtil.errorHandler);
|
||||||
|
// User Settings
|
||||||
|
editorApp.get("/settings/user",needsPermission("settings.read"),info.userSettings,apiUtil.errorHandler);
|
||||||
|
// User Settings
|
||||||
|
editorApp.post("/settings/user",needsPermission("settings.write"),info.updateUserSettings,apiUtil.errorHandler);
|
||||||
|
|
||||||
|
|
||||||
return editorApp;
|
return editorApp;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -23,7 +23,7 @@ module.exports = {
|
|||||||
runtime = _runtime;
|
runtime = _runtime;
|
||||||
settings = runtime.settings;
|
settings = runtime.settings;
|
||||||
},
|
},
|
||||||
settings: function(req,res) {
|
runtimeSettings: function(req,res) {
|
||||||
var safeSettings = {
|
var safeSettings = {
|
||||||
httpNodeRoot: settings.httpNodeRoot||"/",
|
httpNodeRoot: settings.httpNodeRoot||"/",
|
||||||
version: settings.version,
|
version: settings.version,
|
||||||
@ -51,5 +51,29 @@ module.exports = {
|
|||||||
|
|
||||||
settings.exportNodeSettings(safeSettings);
|
settings.exportNodeSettings(safeSettings);
|
||||||
res.json(safeSettings);
|
res.json(safeSettings);
|
||||||
|
},
|
||||||
|
userSettings: function(req, res) {
|
||||||
|
var username;
|
||||||
|
if (!req.user || req.user.anonymous) {
|
||||||
|
username = '_';
|
||||||
|
} else {
|
||||||
|
username = req.user.username;
|
||||||
|
}
|
||||||
|
res.json(settings.getUserSettings(username)||{});
|
||||||
|
},
|
||||||
|
updateUserSettings: function(req,res) {
|
||||||
|
var username;
|
||||||
|
if (!req.user || req.user.anonymous) {
|
||||||
|
username = '_';
|
||||||
|
} else {
|
||||||
|
username = req.user.username;
|
||||||
|
}
|
||||||
|
settings.setUserSettings(username, req.body).then(function() {
|
||||||
|
log.audit({event: "settings.update",username:username},req);
|
||||||
|
res.status(204).end();
|
||||||
|
}).otherwise(function(err) {
|
||||||
|
log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()},req);
|
||||||
|
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,6 +24,7 @@ module.exports = {
|
|||||||
i18n = _runtime.i18n;
|
i18n = _runtime.i18n;
|
||||||
},
|
},
|
||||||
errorHandler: function(err,req,res,next) {
|
errorHandler: function(err,req,res,next) {
|
||||||
|
console.error(err.stack);
|
||||||
if (err.message === "request entity too large") {
|
if (err.message === "request entity too large") {
|
||||||
log.error(err);
|
log.error(err);
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,22 +20,29 @@ var assert = require("assert");
|
|||||||
var log = require("./log");
|
var log = require("./log");
|
||||||
var util = require("./util");
|
var util = require("./util");
|
||||||
|
|
||||||
var userSettings = null;
|
// localSettings are those provided in the runtime settings.js file
|
||||||
|
var localSettings = null;
|
||||||
|
// globalSettings are provided by storage - .config.json on localfilesystem
|
||||||
var globalSettings = null;
|
var globalSettings = null;
|
||||||
|
// nodeSettings are those settings that a node module defines as being available
|
||||||
var nodeSettings = null;
|
var nodeSettings = null;
|
||||||
|
|
||||||
|
// A subset of globalSettings that deal with per-user settings
|
||||||
|
var userSettings = null;
|
||||||
|
|
||||||
var disableNodeSettings = null;
|
var disableNodeSettings = null;
|
||||||
var storage = null;
|
var storage = null;
|
||||||
|
|
||||||
var persistentSettings = {
|
var persistentSettings = {
|
||||||
init: function(settings) {
|
init: function(settings) {
|
||||||
userSettings = settings;
|
localSettings = settings;
|
||||||
for (var i in settings) {
|
for (var i in settings) {
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
if (settings.hasOwnProperty(i) && i !== 'load' && i !== 'get' && i !== 'set' && i !== 'available' && i !== 'reset') {
|
if (settings.hasOwnProperty(i) && i !== 'load' && i !== 'get' && i !== 'set' && i !== 'available' && i !== 'reset') {
|
||||||
// Don't allow any of the core functions get replaced via settings
|
// Don't allow any of the core functions get replaced via settings
|
||||||
(function() {
|
(function() {
|
||||||
var j = i;
|
var j = i;
|
||||||
persistentSettings.__defineGetter__(j,function() { return userSettings[j]; });
|
persistentSettings.__defineGetter__(j,function() { return localSettings[j]; });
|
||||||
persistentSettings.__defineSetter__(j,function() { throw new Error("Property '"+j+"' is read-only"); });
|
persistentSettings.__defineSetter__(j,function() { throw new Error("Property '"+j+"' is read-only"); });
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
@ -48,11 +55,15 @@ var persistentSettings = {
|
|||||||
storage = _storage;
|
storage = _storage;
|
||||||
return storage.getSettings().then(function(_settings) {
|
return storage.getSettings().then(function(_settings) {
|
||||||
globalSettings = _settings;
|
globalSettings = _settings;
|
||||||
|
userSettings = globalSettings.users || {};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
get: function(prop) {
|
get: function(prop) {
|
||||||
if (userSettings.hasOwnProperty(prop)) {
|
if (prop === 'users') {
|
||||||
return clone(userSettings[prop]);
|
throw new Error("Do not access user settings directly. Use settings.getUserSettings");
|
||||||
|
}
|
||||||
|
if (localSettings.hasOwnProperty(prop)) {
|
||||||
|
return clone(localSettings[prop]);
|
||||||
}
|
}
|
||||||
if (globalSettings === null) {
|
if (globalSettings === null) {
|
||||||
throw new Error(log._("settings.not-available"));
|
throw new Error(log._("settings.not-available"));
|
||||||
@ -61,7 +72,10 @@ var persistentSettings = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set: function(prop,value) {
|
set: function(prop,value) {
|
||||||
if (userSettings.hasOwnProperty(prop)) {
|
if (prop === 'users') {
|
||||||
|
throw new Error("Do not access user settings directly. Use settings.setUserSettings");
|
||||||
|
}
|
||||||
|
if (localSettings.hasOwnProperty(prop)) {
|
||||||
throw new Error(log._("settings.property-read-only", {prop:prop}));
|
throw new Error(log._("settings.property-read-only", {prop:prop}));
|
||||||
}
|
}
|
||||||
if (globalSettings === null) {
|
if (globalSettings === null) {
|
||||||
@ -77,7 +91,7 @@ var persistentSettings = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
delete: function(prop) {
|
delete: function(prop) {
|
||||||
if (userSettings.hasOwnProperty(prop)) {
|
if (localSettings.hasOwnProperty(prop)) {
|
||||||
throw new Error(log._("settings.property-read-only", {prop:prop}));
|
throw new Error(log._("settings.property-read-only", {prop:prop}));
|
||||||
}
|
}
|
||||||
if (globalSettings === null) {
|
if (globalSettings === null) {
|
||||||
@ -95,14 +109,15 @@ var persistentSettings = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
for (var i in userSettings) {
|
for (var i in localSettings) {
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
if (userSettings.hasOwnProperty(i)) {
|
if (localSettings.hasOwnProperty(i)) {
|
||||||
delete persistentSettings[i];
|
delete persistentSettings[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
userSettings = null;
|
localSettings = null;
|
||||||
globalSettings = null;
|
globalSettings = null;
|
||||||
|
userSettings = null;
|
||||||
storage = null;
|
storage = null;
|
||||||
},
|
},
|
||||||
registerNodeSettings: function(type, opts) {
|
registerNodeSettings: function(type, opts) {
|
||||||
@ -126,8 +141,8 @@ var persistentSettings = {
|
|||||||
if (setting.exportable) {
|
if (setting.exportable) {
|
||||||
if (safeSettings.hasOwnProperty(property)) {
|
if (safeSettings.hasOwnProperty(property)) {
|
||||||
// Cannot overwrite existing setting
|
// Cannot overwrite existing setting
|
||||||
} else if (userSettings.hasOwnProperty(property)) {
|
} else if (localSettings.hasOwnProperty(property)) {
|
||||||
safeSettings[property] = userSettings[property];
|
safeSettings[property] = localSettings[property];
|
||||||
} else if (setting.hasOwnProperty('value')) {
|
} else if (setting.hasOwnProperty('value')) {
|
||||||
safeSettings[property] = setting.value;
|
safeSettings[property] = setting.value;
|
||||||
}
|
}
|
||||||
@ -148,6 +163,21 @@ var persistentSettings = {
|
|||||||
types.forEach(function(type) {
|
types.forEach(function(type) {
|
||||||
disableNodeSettings[type] = true;
|
disableNodeSettings[type] = true;
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
getUserSettings: function(username) {
|
||||||
|
console.log(username);
|
||||||
|
return userSettings[username];
|
||||||
|
},
|
||||||
|
setUserSettings: function(username,settings) {
|
||||||
|
var current = userSettings[username];
|
||||||
|
userSettings[username] = settings;
|
||||||
|
try {
|
||||||
|
assert.deepEqual(current,settings);
|
||||||
|
return when.resolve();
|
||||||
|
} catch(err) {
|
||||||
|
globalSettings.user = userSettings;
|
||||||
|
return storage.saveSettings(globalSettings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ var auth = require("../../../../red/api/auth");
|
|||||||
var nodes = require("../../../../red/api/admin/nodes");
|
var nodes = require("../../../../red/api/admin/nodes");
|
||||||
var flows = require("../../../../red/api/admin/flows");
|
var flows = require("../../../../red/api/admin/flows");
|
||||||
var flow = require("../../../../red/api/admin/flow");
|
var flow = require("../../../../red/api/admin/flow");
|
||||||
var info = require("../../../../red/api/admin/info");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure all API routes are correctly mounted, with the expected permissions checks
|
* Ensure all API routes are correctly mounted, with the expected permissions checks
|
||||||
@ -33,7 +32,7 @@ describe("api/admin/index", function() {
|
|||||||
describe("Ensure all API routes are correctly mounted, with the expected permissions checks", function() {
|
describe("Ensure all API routes are correctly mounted, with the expected permissions checks", function() {
|
||||||
var app;
|
var app;
|
||||||
var mockList = [
|
var mockList = [
|
||||||
flows,flow,info,nodes
|
flows,flow,nodes
|
||||||
]
|
]
|
||||||
var permissionChecks = {};
|
var permissionChecks = {};
|
||||||
var lastRequest;
|
var lastRequest;
|
||||||
@ -68,8 +67,6 @@ describe("api/admin/index", function() {
|
|||||||
sinon.stub(nodes,"getSet",stubApp);
|
sinon.stub(nodes,"getSet",stubApp);
|
||||||
sinon.stub(nodes,"putSet",stubApp);
|
sinon.stub(nodes,"putSet",stubApp);
|
||||||
|
|
||||||
sinon.stub(info,"settings",stubApp);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
after(function() {
|
after(function() {
|
||||||
mockList.forEach(function(m) {
|
mockList.forEach(function(m) {
|
||||||
@ -91,7 +88,6 @@ describe("api/admin/index", function() {
|
|||||||
nodes.getSet.restore();
|
nodes.getSet.restore();
|
||||||
nodes.putSet.restore();
|
nodes.putSet.restore();
|
||||||
|
|
||||||
info.settings.restore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@ -285,15 +281,5 @@ describe("api/admin/index", function() {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GET /settings', function(done) {
|
|
||||||
request(app).get("/settings").expect(200).end(function(err,res) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
permissionChecks.should.have.property('settings.read',1);
|
|
||||||
done();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -20,6 +20,7 @@ var request = require("supertest");
|
|||||||
var express = require("express");
|
var express = require("express");
|
||||||
var editorApi = require("../../../../red/api/editor");
|
var editorApi = require("../../../../red/api/editor");
|
||||||
var comms = require("../../../../red/api/editor/comms");
|
var comms = require("../../../../red/api/editor/comms");
|
||||||
|
var info = require("../../../../red/api/editor/settings");
|
||||||
|
|
||||||
|
|
||||||
describe("api/editor/index", function() {
|
describe("api/editor/index", function() {
|
||||||
@ -27,9 +28,11 @@ describe("api/editor/index", function() {
|
|||||||
describe("disabled the editor", function() {
|
describe("disabled the editor", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
sinon.stub(comms,'init', function(){});
|
sinon.stub(comms,'init', function(){});
|
||||||
|
sinon.stub(info,'init', function(){});
|
||||||
});
|
});
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
comms.init.restore();
|
comms.init.restore();
|
||||||
|
info.init.restore();
|
||||||
});
|
});
|
||||||
it("disables the editor", function() {
|
it("disables the editor", function() {
|
||||||
var editorApp = editorApi.init({},{
|
var editorApp = editorApi.init({},{
|
||||||
@ -37,6 +40,7 @@ describe("api/editor/index", function() {
|
|||||||
});
|
});
|
||||||
should.not.exist(editorApp);
|
should.not.exist(editorApp);
|
||||||
comms.init.called.should.be.false();
|
comms.init.called.should.be.false();
|
||||||
|
info.init.called.should.be.false();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("enables the editor", function() {
|
describe("enables the editor", function() {
|
||||||
@ -61,9 +65,10 @@ describe("api/editor/index", function() {
|
|||||||
before(function() {
|
before(function() {
|
||||||
app = editorApi.init({},{
|
app = editorApi.init({},{
|
||||||
log:{audit:function(){},error:function(msg){errors.push(msg)}},
|
log:{audit:function(){},error:function(msg){errors.push(msg)}},
|
||||||
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false},
|
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false,exportNodeSettings:function(){}},
|
||||||
events:{on:function(){},removeListener:function(){}},
|
events:{on:function(){},removeListener:function(){}},
|
||||||
isStarted: function() { return isStarted; }
|
isStarted: function() { return isStarted; },
|
||||||
|
nodes: {paletteEditorEnabled: function() { return false }}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('serves the editor', function(done) {
|
it('serves the editor', function(done) {
|
||||||
@ -105,5 +110,14 @@ describe("api/editor/index", function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('GET /settings', function(done) {
|
||||||
|
request(app).get("/settings").expect(200).end(function(err,res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
// permissionChecks.should.have.property('settings.read',1);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,15 +21,15 @@ var sinon = require('sinon');
|
|||||||
var when = require('when');
|
var when = require('when');
|
||||||
|
|
||||||
var app = express();
|
var app = express();
|
||||||
var info = require("../../../../red/api/admin/info");
|
var info = require("../../../../red/api/editor/settings");
|
||||||
var theme = require("../../../../red/api/editor/theme");
|
var theme = require("../../../../red/api/editor/theme");
|
||||||
|
|
||||||
describe("api/admin/info", function() {
|
describe("api/editor/settings", function() {
|
||||||
describe("settings handler", function() {
|
describe("settings handler", function() {
|
||||||
before(function() {
|
before(function() {
|
||||||
sinon.stub(theme,"settings",function() { return { test: 456 };});
|
sinon.stub(theme,"settings",function() { return { test: 456 };});
|
||||||
app = express();
|
app = express();
|
||||||
app.get("/settings",info.settings);
|
app.get("/settings",info.runtimeSettings);
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function() {
|
after(function() {
|
||||||
@ -49,7 +49,8 @@ describe("api/admin/info", function() {
|
|||||||
},
|
},
|
||||||
nodes: {
|
nodes: {
|
||||||
paletteEditorEnabled: function() { return true; }
|
paletteEditorEnabled: function() { return true; }
|
||||||
}
|
},
|
||||||
|
log: { error: console.error }
|
||||||
});
|
});
|
||||||
request(app)
|
request(app)
|
||||||
.get("/settings")
|
.get("/settings")
|
||||||
@ -78,7 +79,8 @@ describe("api/admin/info", function() {
|
|||||||
},
|
},
|
||||||
nodes: {
|
nodes: {
|
||||||
paletteEditorEnabled: function() { return false; }
|
paletteEditorEnabled: function() { return false; }
|
||||||
}
|
},
|
||||||
|
log: { error: console.error }
|
||||||
});
|
});
|
||||||
request(app)
|
request(app)
|
||||||
.get("/settings")
|
.get("/settings")
|
Loading…
Reference in New Issue
Block a user