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 flows = require("./flows");
|
||||
var flow = require("./flow");
|
||||
var info = require("./info");
|
||||
var auth = require("../auth");
|
||||
|
||||
var apiUtil = require("../util");
|
||||
@ -28,7 +27,6 @@ module.exports = {
|
||||
init: function(runtime) {
|
||||
flows.init(runtime);
|
||||
flow.init(runtime);
|
||||
info.init(runtime);
|
||||
nodes.init(runtime);
|
||||
|
||||
var needsPermission = auth.needsPermission;
|
||||
@ -54,9 +52,6 @@ module.exports = {
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,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;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ var path = require('path');
|
||||
|
||||
var comms = require("./comms");
|
||||
var library = require("./library");
|
||||
var info = require("./settings");
|
||||
|
||||
var auth = require("../auth");
|
||||
var needsPermission = auth.needsPermission;
|
||||
@ -41,7 +42,7 @@ module.exports = {
|
||||
log = runtime.log;
|
||||
var settings = runtime.settings;
|
||||
if (!settings.disableEditor) {
|
||||
|
||||
info.init(runtime);
|
||||
comms.init(server,runtime);
|
||||
|
||||
var ui = require("./ui");
|
||||
@ -89,6 +90,14 @@ module.exports = {
|
||||
credentials.init(runtime);
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
@ -23,7 +23,7 @@ module.exports = {
|
||||
runtime = _runtime;
|
||||
settings = runtime.settings;
|
||||
},
|
||||
settings: function(req,res) {
|
||||
runtimeSettings: function(req,res) {
|
||||
var safeSettings = {
|
||||
httpNodeRoot: settings.httpNodeRoot||"/",
|
||||
version: settings.version,
|
||||
@ -51,5 +51,29 @@ module.exports = {
|
||||
|
||||
settings.exportNodeSettings(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;
|
||||
},
|
||||
errorHandler: function(err,req,res,next) {
|
||||
console.error(err.stack);
|
||||
if (err.message === "request entity too large") {
|
||||
log.error(err);
|
||||
} else {
|
||||
|
@ -20,22 +20,29 @@ var assert = require("assert");
|
||||
var log = require("./log");
|
||||
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;
|
||||
// nodeSettings are those settings that a node module defines as being available
|
||||
var nodeSettings = null;
|
||||
|
||||
// A subset of globalSettings that deal with per-user settings
|
||||
var userSettings = null;
|
||||
|
||||
var disableNodeSettings = null;
|
||||
var storage = null;
|
||||
|
||||
var persistentSettings = {
|
||||
init: function(settings) {
|
||||
userSettings = settings;
|
||||
localSettings = settings;
|
||||
for (var i in settings) {
|
||||
/* istanbul ignore else */
|
||||
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
|
||||
(function() {
|
||||
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"); });
|
||||
})();
|
||||
}
|
||||
@ -48,11 +55,15 @@ var persistentSettings = {
|
||||
storage = _storage;
|
||||
return storage.getSettings().then(function(_settings) {
|
||||
globalSettings = _settings;
|
||||
userSettings = globalSettings.users || {};
|
||||
});
|
||||
},
|
||||
get: function(prop) {
|
||||
if (userSettings.hasOwnProperty(prop)) {
|
||||
return clone(userSettings[prop]);
|
||||
if (prop === 'users') {
|
||||
throw new Error("Do not access user settings directly. Use settings.getUserSettings");
|
||||
}
|
||||
if (localSettings.hasOwnProperty(prop)) {
|
||||
return clone(localSettings[prop]);
|
||||
}
|
||||
if (globalSettings === null) {
|
||||
throw new Error(log._("settings.not-available"));
|
||||
@ -61,7 +72,10 @@ var persistentSettings = {
|
||||
},
|
||||
|
||||
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}));
|
||||
}
|
||||
if (globalSettings === null) {
|
||||
@ -77,7 +91,7 @@ var persistentSettings = {
|
||||
}
|
||||
},
|
||||
delete: function(prop) {
|
||||
if (userSettings.hasOwnProperty(prop)) {
|
||||
if (localSettings.hasOwnProperty(prop)) {
|
||||
throw new Error(log._("settings.property-read-only", {prop:prop}));
|
||||
}
|
||||
if (globalSettings === null) {
|
||||
@ -95,14 +109,15 @@ var persistentSettings = {
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
for (var i in userSettings) {
|
||||
for (var i in localSettings) {
|
||||
/* istanbul ignore else */
|
||||
if (userSettings.hasOwnProperty(i)) {
|
||||
if (localSettings.hasOwnProperty(i)) {
|
||||
delete persistentSettings[i];
|
||||
}
|
||||
}
|
||||
userSettings = null;
|
||||
localSettings = null;
|
||||
globalSettings = null;
|
||||
userSettings = null;
|
||||
storage = null;
|
||||
},
|
||||
registerNodeSettings: function(type, opts) {
|
||||
@ -126,8 +141,8 @@ var persistentSettings = {
|
||||
if (setting.exportable) {
|
||||
if (safeSettings.hasOwnProperty(property)) {
|
||||
// Cannot overwrite existing setting
|
||||
} else if (userSettings.hasOwnProperty(property)) {
|
||||
safeSettings[property] = userSettings[property];
|
||||
} else if (localSettings.hasOwnProperty(property)) {
|
||||
safeSettings[property] = localSettings[property];
|
||||
} else if (setting.hasOwnProperty('value')) {
|
||||
safeSettings[property] = setting.value;
|
||||
}
|
||||
@ -148,6 +163,21 @@ var persistentSettings = {
|
||||
types.forEach(function(type) {
|
||||
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 flows = require("../../../../red/api/admin/flows");
|
||||
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
|
||||
@ -33,7 +32,7 @@ describe("api/admin/index", function() {
|
||||
describe("Ensure all API routes are correctly mounted, with the expected permissions checks", function() {
|
||||
var app;
|
||||
var mockList = [
|
||||
flows,flow,info,nodes
|
||||
flows,flow,nodes
|
||||
]
|
||||
var permissionChecks = {};
|
||||
var lastRequest;
|
||||
@ -68,8 +67,6 @@ describe("api/admin/index", function() {
|
||||
sinon.stub(nodes,"getSet",stubApp);
|
||||
sinon.stub(nodes,"putSet",stubApp);
|
||||
|
||||
sinon.stub(info,"settings",stubApp);
|
||||
|
||||
});
|
||||
after(function() {
|
||||
mockList.forEach(function(m) {
|
||||
@ -91,7 +88,6 @@ describe("api/admin/index", function() {
|
||||
nodes.getSet.restore();
|
||||
nodes.putSet.restore();
|
||||
|
||||
info.settings.restore();
|
||||
});
|
||||
|
||||
before(function() {
|
||||
@ -285,15 +281,5 @@ describe("api/admin/index", function() {
|
||||
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 editorApi = require("../../../../red/api/editor");
|
||||
var comms = require("../../../../red/api/editor/comms");
|
||||
var info = require("../../../../red/api/editor/settings");
|
||||
|
||||
|
||||
describe("api/editor/index", function() {
|
||||
@ -27,9 +28,11 @@ describe("api/editor/index", function() {
|
||||
describe("disabled the editor", function() {
|
||||
beforeEach(function() {
|
||||
sinon.stub(comms,'init', function(){});
|
||||
sinon.stub(info,'init', function(){});
|
||||
});
|
||||
afterEach(function() {
|
||||
comms.init.restore();
|
||||
info.init.restore();
|
||||
});
|
||||
it("disables the editor", function() {
|
||||
var editorApp = editorApi.init({},{
|
||||
@ -37,6 +40,7 @@ describe("api/editor/index", function() {
|
||||
});
|
||||
should.not.exist(editorApp);
|
||||
comms.init.called.should.be.false();
|
||||
info.init.called.should.be.false();
|
||||
});
|
||||
});
|
||||
describe("enables the editor", function() {
|
||||
@ -61,9 +65,10 @@ describe("api/editor/index", function() {
|
||||
before(function() {
|
||||
app = editorApi.init({},{
|
||||
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(){}},
|
||||
isStarted: function() { return isStarted; }
|
||||
isStarted: function() { return isStarted; },
|
||||
nodes: {paletteEditorEnabled: function() { return false }}
|
||||
});
|
||||
});
|
||||
it('serves the editor', function(done) {
|
||||
@ -105,5 +110,14 @@ describe("api/editor/index", function() {
|
||||
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 app = express();
|
||||
var info = require("../../../../red/api/admin/info");
|
||||
var info = require("../../../../red/api/editor/settings");
|
||||
var theme = require("../../../../red/api/editor/theme");
|
||||
|
||||
describe("api/admin/info", function() {
|
||||
describe("api/editor/settings", function() {
|
||||
describe("settings handler", function() {
|
||||
before(function() {
|
||||
sinon.stub(theme,"settings",function() { return { test: 456 };});
|
||||
app = express();
|
||||
app.get("/settings",info.settings);
|
||||
app.get("/settings",info.runtimeSettings);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
@ -49,7 +49,8 @@ describe("api/admin/info", function() {
|
||||
},
|
||||
nodes: {
|
||||
paletteEditorEnabled: function() { return true; }
|
||||
}
|
||||
},
|
||||
log: { error: console.error }
|
||||
});
|
||||
request(app)
|
||||
.get("/settings")
|
||||
@ -78,7 +79,8 @@ describe("api/admin/info", function() {
|
||||
},
|
||||
nodes: {
|
||||
paletteEditorEnabled: function() { return false; }
|
||||
}
|
||||
},
|
||||
log: { error: console.error }
|
||||
});
|
||||
request(app)
|
||||
.get("/settings")
|
Loading…
Reference in New Issue
Block a user