From 42516206d9813c1c6851bc44499b7fd8f5ec2b66 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 30 Apr 2018 10:57:14 +0100 Subject: [PATCH] Move module message catalogs under runtime api --- editor/js/i18n.js | 6 ++-- editor/js/red.js | 2 +- red/api/admin/index.js | 2 ++ red/api/admin/nodes.js | 25 ++++++++++++++++ red/api/editor/index.js | 1 - red/api/editor/locales.js | 15 ---------- red/runtime-api/nodes.js | 50 +++++++++++++++++++++++++++++--- test/red/api/admin/index_spec.js | 36 ++++++++++++++++++++++- test/red/api/admin/nodes_spec.js | 43 +++++++++++++++++++++++++++ 9 files changed, 155 insertions(+), 25 deletions(-) diff --git a/editor/js/i18n.js b/editor/js/i18n.js index 0e2d0968a..196488958 100644 --- a/editor/js/i18n.js +++ b/editor/js/i18n.js @@ -36,7 +36,7 @@ RED.i18n = (function() { } }, - loadCatalog: function(namespace,done) { + loadNodeCatalog: function(namespace,done) { var languageList = i18n.functions.toLanguages(i18n.detectLanguage()); var toLoad = languageList.length; languageList.forEach(function(lang) { @@ -45,7 +45,7 @@ RED.i18n = (function() { "Accept":"application/json" }, cache: false, - url: 'locales/'+namespace+'?lng='+lang, + url: 'nodes/'+namespace+'/messages?lng='+lang, success: function(data) { i18n.addResourceBundle(lang,namespace,data); toLoad--; @@ -68,7 +68,7 @@ RED.i18n = (function() { "Accept":"application/json" }, cache: false, - url: 'locales/nodes?lng='+lang, + url: 'nodes/messages?lng='+lang, success: function(data) { var namespaces = Object.keys(data); namespaces.forEach(function(ns) { diff --git a/editor/js/red.js b/editor/js/red.js index fe3b01b44..930cd2bdb 100644 --- a/editor/js/red.js +++ b/editor/js/red.js @@ -282,7 +282,7 @@ var RED = (function() { var id = m.id; RED.nodes.addNodeSet(m); addedTypes = addedTypes.concat(m.types); - RED.i18n.loadCatalog(id, function() { + RED.i18n.loadNodeCatalog(id, function() { $.get('nodes/'+id, function(data) { $("body").append(data); }); diff --git a/red/api/admin/index.js b/red/api/admin/index.js index 9679eaefc..4cafb1dfd 100644 --- a/red/api/admin/index.js +++ b/red/api/admin/index.js @@ -46,6 +46,8 @@ module.exports = { // Nodes adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler); adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler); + adminApp.get(/\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler); + adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler); adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler); adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler); adminApp.delete(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler); diff --git a/red/api/admin/nodes.js b/red/api/admin/nodes.js index 31f231f78..b6ad7a7e8 100644 --- a/red/api/admin/nodes.js +++ b/red/api/admin/nodes.js @@ -135,6 +135,31 @@ module.exports = { }, + getModuleCatalog: function(req,res) { + var opts = { + user: req.user, + module: req.params[0], + lang: req.query.lng + } + runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) { + res.json(result); + }).catch(function(err) { + apiUtils.rejectHandler(req,res,err); + }) + }, + + getModuleCatalogs: function(req,res) { + var opts = { + user: req.user, + lang: req.query.lng + } + runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) { + res.json(result); + }).catch(function(err) { + apiUtils.rejectHandler(req,res,err); + }) + }, + getIcons: function(req,res) { var opts = { user: req.user diff --git a/red/api/editor/index.js b/red/api/editor/index.js index fb617c154..fc874826d 100644 --- a/red/api/editor/index.js +++ b/red/api/editor/index.js @@ -83,7 +83,6 @@ module.exports = { // Locales var locales = require("./locales"); locales.init(runtimeAPI); - editorApp.get('/locales/nodes',locales.getAllNodes,apiUtil.errorHandler); editorApp.get(/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler); // Library diff --git a/red/api/editor/locales.js b/red/api/editor/locales.js index 464933d90..fe8f51ab4 100644 --- a/red/api/editor/locales.js +++ b/red/api/editor/locales.js @@ -38,20 +38,5 @@ module.exports = { }); i18n.i.setLng(prevLang); - }, - getAllNodes: function(req,res) { - var lngs = req.query.lng; - var opts = { - user: req.user - } - runtimeAPI.nodes.getNodeList(opts).then(function(nodeList) { - var result = {}; - nodeList.forEach(function(n) { - if (n.module !== "node-red") { - result[n.id] = i18n.catalog(n.id,lngs)||{}; - } - }); - res.json(result); - }) } } diff --git a/red/runtime-api/nodes.js b/red/runtime-api/nodes.js index 7a101c783..6e6fa7ac9 100644 --- a/red/runtime-api/nodes.js +++ b/red/runtime-api/nodes.js @@ -350,13 +350,55 @@ var api = module.exports = { }, /** - * TODO: getModuleCatalogs + * 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} - the message catalogs + * @memberof RED.nodes */ - getModuleCatalogs: function() {}, + getModuleCatalogs: 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.setLng(lang, function(){ + var nodeList = runtime.nodes.getNodeList(); + var result = {}; + nodeList.forEach(function(n) { + if (n.module !== "node-red") { + result[n.id] = runtime.i18n.catalog(n.id,lang)||{}; + } + }); + resolve(result); + }); + runtime.i18n.i.setLng(prevLang); + }); + }, + /** - * TODO: getModuleCatalog + * 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} - the message catalog + * @memberof RED.nodes */ - getModuleCatalog: function() {}, + 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.setLng(lang, function(){ + var catalog = runtime.i18n.catalog(namespace,lang); + resolve(catalog||{}); + }); + runtime.i18n.i.setLng(prevLang); + }); + }, /** * Gets the list of all icons available in the modules installed within the runtime diff --git a/test/red/api/admin/index_spec.js b/test/red/api/admin/index_spec.js index 00941d0fa..9827cd669 100644 --- a/test/red/api/admin/index_spec.js +++ b/test/red/api/admin/index_spec.js @@ -66,7 +66,8 @@ describe("api/admin/index", function() { sinon.stub(nodes,"delete",stubApp); sinon.stub(nodes,"getSet",stubApp); sinon.stub(nodes,"putSet",stubApp); - + sinon.stub(nodes,"getModuleCatalog",stubApp); + sinon.stub(nodes,"getModuleCatalogs",stubApp); }); after(function() { mockList.forEach(function(m) { @@ -87,6 +88,8 @@ describe("api/admin/index", function() { nodes.delete.restore(); nodes.getSet.restore(); nodes.putSet.restore(); + nodes.getModuleCatalog.restore(); + nodes.getModuleCatalogs.restore(); }); @@ -281,5 +284,36 @@ describe("api/admin/index", function() { done(); }) }); + + it('GET /nodes/messages', function(done) { + request(app).get("/nodes/messages").expect(200).end(function(err,res) { + if (err) { + return done(err); + } + permissionChecks.should.have.property('nodes.read',1); + + done(); + }) + }); + it('GET /nodes/module/set/messages', function(done) { + request(app).get("/nodes/module/set/messages").expect(200).end(function(err,res) { + if (err) { + return done(err); + } + permissionChecks.should.have.property('nodes.read',1); + lastRequest.params.should.have.property(0,'module/set'); + done(); + }) + }); + it('GET /nodes/@scope/module/set/messages', function(done) { + request(app).get("/nodes/@scope/module/set/messages").expect(200).end(function(err,res) { + if (err) { + return done(err); + } + permissionChecks.should.have.property('nodes.read',1); + lastRequest.params.should.have.property(0,'@scope/module/set'); + done(); + }) + }); }); }); diff --git a/test/red/api/admin/nodes_spec.js b/test/red/api/admin/nodes_spec.js index fb970a65c..5a757ab06 100644 --- a/test/red/api/admin/nodes_spec.js +++ b/test/red/api/admin/nodes_spec.js @@ -32,6 +32,8 @@ describe("api/admin/nodes", function() { app.use(bodyParser.json()); app.get("/nodes",nodes.getAll); app.post("/nodes",nodes.post); + app.get(/\/nodes\/messages/,nodes.getModuleCatalogs); + app.get(/\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,nodes.getModuleCatalog); app.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.getModule); app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.putModule); app.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.getSet); @@ -431,4 +433,45 @@ describe("api/admin/nodes", function() { }); }); }); + + describe('get module messages', function() { + it('returns message catalog', function(done) { + nodes.init({ + nodes:{ + getModuleCatalog: function(opts) { + return Promise.resolve(opts); + } + } + }); + request(app) + .get('/nodes/module/set/messages') + .expect(200) + .end(function(err,res) { + if (err) { + throw err; + } + res.body.should.eql({ module: 'module/set' }); + done(); + }); + }); + it('returns all node catalogs', function(done) { + nodes.init({ + nodes:{ + getModuleCatalogs: function(opts) { + return Promise.resolve({a:1}); + } + } + }); + request(app) + .get('/nodes/messages') + .expect(200) + .end(function(err,res) { + if (err) { + throw err; + } + res.body.should.eql({a:1}); + done(); + }); + }); + }) });