From fc15d421d6531e5ab7f9049b45fba7a9abce853b Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Tue, 16 Jun 2015 17:58:22 +0200 Subject: [PATCH] Implemeneted JSON configs. Cleaned up optional configs. --- .../Books/Users/Foxx/Develop/Manifest.mdpp | 1 + .../js/views/applicationDetailView.js | 56 ++++++++++++------- js/common/bootstrap/modules.js | 4 +- .../org/arangodb/foxx/manager-utils.js | 9 +-- .../modules/org/arangodb/foxx/arangoApp.js | 50 +++++++++++++---- 5 files changed, 83 insertions(+), 37 deletions(-) diff --git a/Documentation/Books/Users/Foxx/Develop/Manifest.mdpp b/Documentation/Books/Users/Foxx/Develop/Manifest.mdpp index 77776dc534..d10ecc2335 100644 --- a/Documentation/Books/Users/Foxx/Develop/Manifest.mdpp +++ b/Documentation/Books/Users/Foxx/Develop/Manifest.mdpp @@ -146,6 +146,7 @@ The **type** can be any of the following: * **boolean** or **bool**: `true` or `false`. * **number**: any finite decimal or integer number. * **string**: any string value. +* **json**: any well-formed JSON value. If the configuration has parameters that do not specify a default value, you need to configure the app before it becomes active. diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/views/applicationDetailView.js b/js/apps/system/_admin/aardvark/APP/frontend/js/views/applicationDetailView.js index 1ba3d97b37..e5767ea8f6 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/views/applicationDetailView.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/views/applicationDetailView.js @@ -219,21 +219,26 @@ var cfg = {}; _.each(this.model.get('config'), function(opt, key) { var $el = $('#app_config_' + key); - var val = window.arangoHelper.escapeHtml($el.val()); + var val = $el.val(); if (opt.type === 'boolean' || opt.type === 'bool') { cfg[key] = $el.is(':checked'); return; } if (val === '' && opt.hasOwnProperty('default')) { cfg[key] = opt.default; + if (opt.type === 'json') { + cfg[key] = JSON.stringify(opt.default); + } return; } if (opt.type === 'number') { cfg[key] = parseFloat(val); } else if (opt.type === 'integer' || opt.type === 'int') { cfg[key] = parseInt(val, 10); + } else if (opt.type === 'json') { + cfg[key] = val && JSON.stringify(JSON.parse(val)); } else { - cfg[key] = val; + cfg[key] = window.arangoHelper.escapeHtml(val); return; } }); @@ -257,9 +262,36 @@ obj.current || false ); } - var defaultValue; - var currentValue; + var defaultValue = obj.default === undefined ? '' : String(obj.default); + var currentValue = obj.current === undefined ? '' : String(obj.current); + var mandatory = false; var checks = []; + if (obj.default === undefined && obj.required !== false) { + mandatory = true; + checks.push({ + rule: Joi.any().required(), + msg: 'No default found. Has to be added' + }); + } + if (obj.type === 'json') { + defaultValue = obj.default === undefined ? '' : JSON.stringify(obj.default); + currentValue = obj.current === undefined ? '' : obj.current; + checks.push({ + rule: function (v) { + return v && JSON.parse(v); + }, + msg: 'Must be well-formed JSON or empty.' + }); + return window.modalView.createBlobEntry( + 'app_config_' + name, + name, + currentValue, + obj.description, + defaultValue, + mandatory, + checks + ); + } if (obj.type === 'integer' || obj.type === 'int') { checks.push({ rule: Joi.number().integer().optional().allow(''), @@ -276,27 +308,13 @@ msg: 'Has to be a string.' }); } - if (obj.default !== undefined) { - defaultValue = String(obj.default); - } else { - defaultValue = ''; - checks.push({ - rule: Joi.string().required(), - msg: 'No default found. Has to be added' - }); - } - if (obj.current !== undefined) { - currentValue = String(obj.current); - } else { - currentValue = ''; - } return window.modalView.createTextEntry( 'app_config_' + name, name, currentValue, obj.description, defaultValue, - obj.required !== false, + mandatory, checks ); }); diff --git a/js/common/bootstrap/modules.js b/js/common/bootstrap/modules.js index 610d576286..aee87b69df 100644 --- a/js/common/bootstrap/modules.js +++ b/js/common/bootstrap/modules.js @@ -1399,7 +1399,7 @@ function require (path) { try { fn = internal.executeScript("(" + script + ")", undefined, filename); } catch (e) { - require('console').errorLines(e); + require('console').errorLines(e.stack || String(e)); throw extend(new internal.ArangoError({ errorNum: internal.errors.ERROR_SYNTAX_ERROR_IN_SCRIPT.code, errorMessage: internal.errors.ERROR_SYNTAX_ERROR_IN_SCRIPT.message @@ -1416,7 +1416,7 @@ function require (path) { return args[key]; })); } catch (e) { - require('console').errorLines(e); + require('console').errorLines(e.stack || String(e)); throw extend(new internal.ArangoError({ errorNum: internal.errors.ERROR_MODULE_FAILURE.code, errorMessage: internal.errors.ERROR_MODULE_FAILURE.message diff --git a/js/common/modules/org/arangodb/foxx/manager-utils.js b/js/common/modules/org/arangodb/foxx/manager-utils.js index d3ee6de6f4..df8cd4ba12 100644 --- a/js/common/modules/org/arangodb/foxx/manager-utils.js +++ b/js/common/modules/org/arangodb/foxx/manager-utils.js @@ -456,10 +456,11 @@ function updateApp (mount, update) { /// @brief define validators for parameter types //////////////////////////////////////////////////////////////////////////////// var parameterTypes = { - integer: joi.number().integer().required(), - boolean: joi.boolean().required(), - string: joi.string().required(), - number: joi.number().required() + integer: joi.number().integer(), + boolean: joi.boolean(), + string: joi.string(), + number: joi.number(), + json: function (v) {return v && JSON.parse(v);} }; parameterTypes.int = parameterTypes.integer; parameterTypes.bool = parameterTypes.boolean; diff --git a/js/server/modules/org/arangodb/foxx/arangoApp.js b/js/server/modules/org/arangodb/foxx/arangoApp.js index 51ea1f7cfa..9f594d0a5e 100644 --- a/js/server/modules/org/arangodb/foxx/arangoApp.js +++ b/js/server/modules/org/arangodb/foxx/arangoApp.js @@ -35,6 +35,7 @@ var fs = require("fs"); var internal = require("internal"); var db = internal.db; +var joi = require("joi"); var _= require("underscore"); var utils = require("org/arangodb/foxx/manager-utils"); var console = require("console"); @@ -48,12 +49,15 @@ var throwFileNotFound = arangodb.throwFileNotFound; // --SECTION-- private functions // ----------------------------------------------------------------------------- -function applyDefaultConfig(config) { +function applyDefaultConfig(config, parse) { var res = {}; if (config !== undefined) { - Object.keys(config).forEach(function (attr) { - if (config[attr].default !== undefined) { - res[attr] = config[attr].default; + Object.keys(config).forEach(function (key) { + if (config[key].default !== undefined) { + res[key] = config[key].default; + if (!parse && config[key].type === 'json') { + res[key] = JSON.stringify(res[key]); + } } }); } @@ -78,7 +82,7 @@ function AppContext(app) { this.mount = app._mount; this.collectionPrefix = app._collectionPrefix; this.options = app._options; - this.configuration = app._options.configuration; + this.configuration = app._configuration; this.dependencies = app._dependencies; this.basePath = prefix; this.baseUrl = '/_db/' + encodeURIComponent(db._name()) + app._mount; @@ -178,6 +182,7 @@ function ArangoApp(config) { // Apply the default configuration and ignore all missing options var cfg = config.options.configuration; this._options.configuration = applyDefaultConfig(this._manifest.configuration); + this._configuration = applyDefaultConfig(this._manifest.configuration, true); this.configure(cfg); var deps = config.options.dependencies; @@ -309,20 +314,41 @@ ArangoApp.prototype.configure = function(config) { var invalid = []; this._options.configuration = this._options.configuration || {}; - _.each(config, function (value, name) { + _.each(config, function (rawValue, name) { if (!expected[name]) { invalid.push("Unexpected Option " + name); } else { + var value = rawValue; var type = expected[name].type; var schema = utils.parameterTypes[type]; - if (!expected[name].required) { - schema = schema.optional(); + var error; + var result; + if (expected[name].required !== false) { + result = joi.any().required().validate(value); + if (result.error) { + error = result.error.message.replace(/^"value"/, '"' + name + '"'); + } } - var result = schema.validate(value); - if (result.error) { - invalid.push(result.error.message.replace(/^"value"/, '"' + name + '"')); + if (!error) { + if (schema.isJoi) { + result = schema.optional().allow(null).validate(value); + if (result.error) { + error = result.error.message.replace(/^"value"/, '"' + name + '"'); + } + value = result.value; + } else { + try { + value = schema(value); + } catch (e) { + error = '"' + name + '": ' + e.message; + } + } + } + if (error) { + invalid.push(error); } else { - this._options.configuration[name] = result.value; + this._options.configuration[name] = rawValue; + this._configuration[name] = value; } } }, this);