1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Disable palette editor if npm not found

This commit is contained in:
Nick O'Leary 2016-10-12 22:30:32 +01:00
parent a76674032d
commit 49f72881f4
11 changed files with 108 additions and 30 deletions

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2014, 2015 IBM Corp. * Copyright 2014, 2016 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,10 +15,12 @@
**/ **/
var theme = require("./theme"); var theme = require("./theme");
var util = require('util'); var util = require('util');
var runtime;
var settings; var settings;
module.exports = { module.exports = {
init: function(runtime) { init: function(_runtime) {
runtime = _runtime;
settings = runtime.settings; settings = runtime.settings;
}, },
settings: function(req,res) { settings: function(req,res) {
@ -40,6 +42,12 @@ module.exports = {
if (settings.flowFilePretty) { if (settings.flowFilePretty) {
safeSettings.flowFilePretty = settings.flowFilePretty; safeSettings.flowFilePretty = settings.flowFilePretty;
} }
if (!runtime.nodes.paletteEditorEnabled()) {
safeSettings.editorTheme = safeSettings.editorTheme || {};
safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {};
safeSettings.editorTheme.palette.editable = false;
}
res.json(safeSettings); res.json(safeSettings);
} }

View File

@ -38,6 +38,7 @@ var defaultContext = {
var theme = null; var theme = null;
var themeContext = clone(defaultContext); var themeContext = clone(defaultContext);
var themeSettings = null; var themeSettings = null;
var runtime = null;
function serveFile(app,baseUrl,file) { function serveFile(app,baseUrl,file) {
try { try {

View File

@ -98,7 +98,6 @@ function start() {
} }
log.info(log._("runtime.version",{component:"Node.js ",version:process.version})); log.info(log._("runtime.version",{component:"Node.js ",version:process.version}));
log.info(os.type()+" "+os.release()+" "+os.arch()+" "+os.endianness()); log.info(os.type()+" "+os.release()+" "+os.arch()+" "+os.endianness());
log.info(log._("server.loading"));
return redNodes.load().then(function() { return redNodes.load().then(function() {
var i; var i;

View File

@ -9,6 +9,10 @@
"server": { "server": {
"loading": "Loading palette nodes", "loading": "Loading palette nodes",
"palette-editor": {
"disabled": "Palette editor disabled : user settings",
"npm-not-found": "Palette editor disabled : npm command not found"
},
"errors": "Failed to register __count__ node type", "errors": "Failed to register __count__ node type",
"errors_plural": "Failed to register __count__ node types", "errors_plural": "Failed to register __count__ node types",
"errors-help": "Run with -v for details", "errors-help": "Run with -v for details",

View File

@ -110,6 +110,7 @@ module.exports = {
getNode: flows.get, getNode: flows.get,
eachNode: flows.eachNode, eachNode: flows.eachNode,
paletteEditorEnabled: registry.paletteEditorEnabled,
installModule: registry.installModule, installModule: registry.installModule,
uninstallModule: uninstallModule, uninstallModule: uninstallModule,

View File

@ -34,7 +34,7 @@ function init(runtime) {
function load() { function load() {
registry.load(); registry.load();
return loader.load(); return installer.checkPrereq().then(loader.load);
} }
function addModule(module) { function addModule(module) {
@ -80,5 +80,7 @@ module.exports = {
installModule: installer.installModule, installModule: installer.installModule,
uninstallModule: installer.uninstallModule, uninstallModule: installer.uninstallModule,
cleanModuleList: registry.cleanModuleList cleanModuleList: registry.cleanModuleList,
paletteEditorEnabled: installer.paletteEditorEnabled
}; };

View File

@ -25,6 +25,8 @@ var log = require("../../log");
var events = require("../../events"); var events = require("../../events");
var child_process = require('child_process'); var child_process = require('child_process');
var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
var paletteEditorEnabled = false;
var settings; var settings;
@ -86,7 +88,7 @@ function installModule(module) {
log.info(log._("server.install.installing",{name: module})); log.info(log._("server.install.installing",{name: module}));
var installDir = settings.userDir || process.env.NODE_RED_HOME || "."; var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
var child = child_process.execFile('npm',['install','--production',installName], var child = child_process.execFile(npmCommand,['install','--production',installName],
{ {
cwd: installDir cwd: installDir
}, },
@ -160,7 +162,7 @@ function uninstallModule(module) {
var list = registry.removeModule(module); var list = registry.removeModule(module);
log.info(log._("server.install.uninstalling",{name:module})); log.info(log._("server.install.uninstalling",{name:module}));
var child = child_process.execFile('npm',['remove',module], var child = child_process.execFile(npmCommand,['remove',module],
{ {
cwd: installDir cwd: installDir
}, },
@ -183,9 +185,35 @@ function uninstallModule(module) {
}); });
} }
function checkPrereq() {
if (settings.hasOwnProperty('editorTheme') &&
settings.editorTheme.hasOwnProperty('palette') &&
settings.editorTheme.palette.hasOwnProperty('editable') &&
settings.editorTheme.palette.editable === false
) {
log.info(log._("server.palette-editor.disabled"));
paletteEditorEnabled = false;
return when.resolve();
} else {
return when.promise(function(resolve) {
child_process.execFile(npmCommand,['-v'],function(err) {
if (err) {
log.info(log._("server.palette-editor.npm-not-found"));
paletteEditorEnabled = false;
} else {
paletteEditorEnabled = true;
}
resolve();
});
})
}
}
module.exports = { module.exports = {
init: init, init: init,
checkPrereq: checkPrereq,
installModule: installModule, installModule: installModule,
uninstallModule: uninstallModule uninstallModule: uninstallModule,
paletteEditorEnabled: function() {
return paletteEditorEnabled
}
} }

View File

@ -36,6 +36,7 @@ function load(defaultNodesDir,disableNodePathScan) {
// We should expose that as an option at some point, although the // We should expose that as an option at some point, although the
// performance gains are minimal. // performance gains are minimal.
//return loadNodeFiles(registry.getModuleList()); //return loadNodeFiles(registry.getModuleList());
runtime.log.info(runtime.log._("server.loading"));
var nodeFiles = localfilesystem.getNodeFiles(defaultNodesDir,disableNodePathScan); var nodeFiles = localfilesystem.getNodeFiles(defaultNodesDir,disableNodePathScan);
return loadNodeFiles(nodeFiles); return loadNodeFiles(nodeFiles);

View File

@ -30,7 +30,9 @@ describe("api index", function() {
before(function() { before(function() {
api.init({},{ api.init({},{
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:true}, settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:true},
events: {on:function(){},removeListener: function(){}} events: {on:function(){},removeListener: function(){}},
log: {info:function(){},_:function(){}},
nodes: {paletteEditorEnabled: function(){return true}}
}); });
app = api.adminApp; app = api.adminApp;
}); });

View File

@ -28,14 +28,6 @@ describe("info api", 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 };});
info.init({
settings: {
foo: 123,
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"]
}
})
app = express(); app = express();
app.get("/settings",info.settings); app.get("/settings",info.settings);
}); });
@ -45,6 +37,17 @@ describe("info api", function() {
}); });
it('returns the filtered settings', function(done) { it('returns the filtered settings', function(done) {
info.init({
settings: {
foo: 123,
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"]
},
nodes: {
paletteEditorEnabled: function() { return true; }
}
});
request(app) request(app)
.get("/settings") .get("/settings")
.expect(200) .expect(200)
@ -60,6 +63,35 @@ describe("info api", function() {
done(); done();
}); });
}); });
it('overrides palette editable if runtime says it is disabled', function(done) {
info.init({
settings: {
httpNodeRoot: "testHttpNodeRoot",
version: "testVersion",
paletteCategories :["red","blue","green"]
},
nodes: {
paletteEditorEnabled: function() { return false; }
}
});
request(app)
.get("/settings")
.expect(200)
.end(function(err,res) {
if (err) {
return done(err);
}
res.body.should.have.property("httpNodeRoot","testHttpNodeRoot");
res.body.should.have.property("version","testVersion");
res.body.should.have.property("paletteCategories",["red","blue","green"]);
res.body.should.have.property("editorTheme");
res.body.editorTheme.should.have.property("test",456);
res.body.editorTheme.should.have.property("palette",{editable:false});
done();
});
})
}); });
}); });

View File

@ -44,7 +44,7 @@ describe("red/nodes/registry/loader",function() {
}) })
describe("#init",function() { describe("#init",function() {
it("init",function() { it("init",function() {
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){},log:{info:function(){},_:function(){}}}});
localfilesystem.init.called.should.be.true(); localfilesystem.init.called.should.be.true();
}); });
}); });
@ -53,7 +53,7 @@ describe("red/nodes/registry/loader",function() {
it("load empty set without settings available", function(done) { it("load empty set without settings available", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};})); stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};})); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};}));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return false;}}});
loader.load("foo",true).then(function() { loader.load("foo",true).then(function() {
localfilesystem.getNodeFiles.called.should.be.true(); localfilesystem.getNodeFiles.called.should.be.true();
localfilesystem.getNodeFiles.lastCall.args[0].should.eql('foo'); localfilesystem.getNodeFiles.lastCall.args[0].should.eql('foo');
@ -65,7 +65,7 @@ describe("red/nodes/registry/loader",function() {
it("load empty set with settings available triggers registery save", function(done) { it("load empty set with settings available triggers registery save", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};})); stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};})); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};}));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load("foo",true).then(function() { loader.load("foo",true).then(function() {
registry.saveNodeList.called.should.be.true(); registry.saveNodeList.called.should.be.true();
done(); done();
@ -96,7 +96,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true(); registry.addNodeSet.called.should.be.true();
registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode1"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode1");
@ -144,7 +144,7 @@ describe("red/nodes/registry/loader",function() {
// This module isn't already loaded // This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true(); registry.addNodeSet.called.should.be.true();
registry.addNodeSet.lastCall.args[0].should.eql("node-red/MultipleNodes1"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/MultipleNodes1");
@ -197,7 +197,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true(); registry.addNodeSet.called.should.be.true();
registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode2"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode2");
@ -247,7 +247,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true(); registry.addNodeSet.called.should.be.true();
registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode3"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode3");
@ -294,7 +294,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true(); registry.addNodeSet.called.should.be.true();
registry.addNodeSet.lastCall.args[0].should.eql("node-red/DoesNotExist"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/DoesNotExist");
@ -321,7 +321,7 @@ describe("red/nodes/registry/loader",function() {
describe("#addModule",function() { describe("#addModule",function() {
it("throws error if settings unavailable", function() { it("throws error if settings unavailable", function() {
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return false;}}});
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
loader.addModule("test-module"); loader.addModule("test-module");
@ -330,7 +330,7 @@ describe("red/nodes/registry/loader",function() {
it("returns rejected error if module already loaded", function(done) { it("returns rejected error if module already loaded", function(done) {
stubs.push(sinon.stub(registry,"getModuleInfo",function(){return{}})); stubs.push(sinon.stub(registry,"getModuleInfo",function(){return{}}));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("test-module").otherwise(function(err) { loader.addModule("test-module").otherwise(function(err) {
err.code.should.eql("module_already_loaded"); err.code.should.eql("module_already_loaded");
@ -342,7 +342,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(localfilesystem,"getModuleFiles",function() { stubs.push(sinon.stub(localfilesystem,"getModuleFiles",function() {
throw new Error("failure"); throw new Error("failure");
})); }));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("test-module").otherwise(function(err) { loader.addModule("test-module").otherwise(function(err) {
err.message.should.eql("failure"); err.message.should.eql("failure");
done(); done();
@ -374,7 +374,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" })); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addNodeSet", function(){ return })); stubs.push(sinon.stub(registry,"addNodeSet", function(){ return }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("TestNodeModule").then(function(result) { loader.addModule("TestNodeModule").then(function(result) {
result.should.eql("a node list"); result.should.eql("a node list");
registry.addNodeSet.calledOnce.should.be.true(); registry.addNodeSet.calledOnce.should.be.true();