From f5016a2ce9b592b7f0a02ed77d197e1c5f48b40b Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Fri, 26 Jul 2013 22:46:53 +0200 Subject: [PATCH 1/2] cleanup --- CHANGELOG | 2 + js/actions/api-foxx.js | 193 ++++++-------- js/client/modules/org/arangodb/arangosh.js | 6 + .../modules/org/arangodb/foxx-manager.js | 236 +++++++++--------- js/common/modules/org/arangodb-common.js | 74 +++++- js/server/modules/org/arangodb/actions.js | 147 +++-------- .../modules/org/arangodb/foxx-manager.js | 203 ++++++++++++--- js/server/modules/org/arangodb/foxx.js | 2 +- 8 files changed, 480 insertions(+), 383 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 640d9cab2d..00733b3d62 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ v1.4 ---- +* defineHttp now only expects a single context + * added collection detail dialog (web interface) Shows collection properties, figures (datafiles, journals, attributes, etc.) diff --git a/js/actions/api-foxx.js b/js/actions/api-foxx.js index 2b038bfcb8..275e00d9a3 100644 --- a/js/actions/api-foxx.js +++ b/js/actions/api-foxx.js @@ -36,72 +36,12 @@ var arangodb = require("org/arangodb"); var actions = require("org/arangodb/actions"); var foxxManager = require("org/arangodb/foxx-manager"); +var easyPostCallback = actions.easyPostCallback; + // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief sets up a FOXX dev application -//////////////////////////////////////////////////////////////////////////////// - -actions.defineHttp({ - url : "_admin/foxx/dev-setup", - context : "admin", - prefix : false, - - callback : function (req, res) { - 'use strict'; - - var result; - var body = actions.getJsonBody(req, res); - - if (body === undefined) { - return; - } - - var name = body.name; - - try { - result = foxxManager.devSetup(name); - actions.resultOk(req, res, actions.HTTP_OK, result); - } - catch (err) { - actions.resultException(req, res, err, undefined, false); - } - } -}); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief tears down a FOXX dev application -//////////////////////////////////////////////////////////////////////////////// - -actions.defineHttp({ - url : "_admin/foxx/dev-teardown", - context : "admin", - prefix : false, - - callback : function (req, res) { - 'use strict'; - - var result; - var body = actions.getJsonBody(req, res); - - if (body === undefined) { - return; - } - - var name = body.name; - - try { - result = foxxManager.devTeardown(name); - actions.resultOk(req, res, actions.HTTP_OK, result); - } - catch (err) { - actions.resultException(req, res, err, undefined, false); - } - } -}); - //////////////////////////////////////////////////////////////////////////////// /// @brief fetches a FOXX application //////////////////////////////////////////////////////////////////////////////// @@ -194,57 +134,35 @@ actions.defineHttp({ context : "admin", prefix : false, - callback : function (req, res) { - 'use strict'; + callback: easyPostCallback({ + body: true, + callback: function (body) { + var appId = body.appId; + var mount = body.mount; + var options = body.options || {}; - var body = actions.getJsonBody(req, res); - - if (body === undefined) { - return; + return foxxManager.mount(appId, mount, options); } - - var appId = body.appId; - var mount = body.mount; - var options = body.options || {}; - - try { - var result = foxxManager.mount(appId, mount, options); - actions.resultOk(req, res, actions.HTTP_OK, result); - } - catch (err) { - actions.resultException(req, res, err, undefined, false); - } - } + }) }); //////////////////////////////////////////////////////////////////////////////// -/// @brief unmounts a FOXX application +/// @brief sets up a FOXX application //////////////////////////////////////////////////////////////////////////////// actions.defineHttp({ - url : "_admin/foxx/unmount", + url : "_admin/foxx/setup", context : "admin", prefix : false, - callback : function (req, res) { - 'use strict'; + callback: easyPostCallback({ + body: true, + callback: function (body) { + var mount = body.mount; - var body = actions.getJsonBody(req, res); - - if (body === undefined) { - return; + return foxxManager.teardown(mount); } - - var key = body.key; - - try { - var result = foxxManager.unmount(key); - actions.resultOk(req, res, actions.HTTP_OK, result); - } - catch (err) { - actions.resultException(req, res, err, undefined, false); - } - } + }) }); //////////////////////////////////////////////////////////////////////////////// @@ -256,28 +174,71 @@ actions.defineHttp({ context : "admin", prefix : false, - callback : function (req, res) { - 'use strict'; + callback: easyPostCallback({ + body: true, + callback: function (body) { + var mount = body.mount; - var result; - var body = actions.getJsonBody(req, res); - - if (body === undefined) { - return; + return foxxManager.teardown(mount); } + }) +}); - var appId = body.appId; - var mount = body.mount; - var collectionPrefix = body.collectionPrefix; +//////////////////////////////////////////////////////////////////////////////// +/// @brief unmounts a FOXX application +//////////////////////////////////////////////////////////////////////////////// - try { - result = foxxManager.teardown(appId, mount, collectionPrefix); - actions.resultOk(req, res, actions.HTTP_OK, result); +actions.defineHttp({ + url : "_admin/foxx/unmount", + context : "admin", + prefix : false, + + callback: easyPostCallback({ + body: true, + callback: function (body) { + var mount = body.mount; + + return foxxManager.unmount(mount); } - catch (err) { - actions.resultException(req, res, err, undefined, false); + }) +}); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief sets up a FOXX dev application +//////////////////////////////////////////////////////////////////////////////// + +actions.defineHttp({ + url : "_admin/foxx/dev-setup", + context : "admin", + prefix : false, + + callback: easyPostCallback({ + body: true, + callback: function (body) { + var name = body.name; + + return foxxManager.devSetup(name); } - } + }) +}); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tears down a FOXX dev application +//////////////////////////////////////////////////////////////////////////////// + +actions.defineHttp({ + url : "_admin/foxx/dev-teardown", + context : "admin", + prefix : false, + + callback: easyPostCallback({ + body: true, + callback: function (body) { + var name = body.name; + + return foxxManager.devTeardown(name); + } + }) }); // ----------------------------------------------------------------------------- diff --git a/js/client/modules/org/arangodb/arangosh.js b/js/client/modules/org/arangodb/arangosh.js index 65873ea3e3..6512916e51 100644 --- a/js/client/modules/org/arangodb/arangosh.js +++ b/js/client/modules/org/arangodb/arangosh.js @@ -108,6 +108,12 @@ exports.checkRequestResult = function (requestResult) { throw new ArangoError(requestResult); } + + var copy = requestResult._shallowCopy; + + delete copy.error; + + return copy; }; //////////////////////////////////////////////////////////////////////////////// diff --git a/js/client/modules/org/arangodb/foxx-manager.js b/js/client/modules/org/arangodb/foxx-manager.js index b075130e36..29efe0a4db 100644 --- a/js/client/modules/org/arangodb/foxx-manager.js +++ b/js/client/modules/org/arangodb/foxx-manager.js @@ -29,8 +29,6 @@ /// @author Copyright 2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -var internal = require("internal"); - var fs = require("fs"); var arangodb = require("org/arangodb"); @@ -38,8 +36,14 @@ var arangosh = require("org/arangodb/arangosh"); var errors = arangodb.errors; var ArangoError = arangodb.ArangoError; -var arango = internal.arango; var db = arangodb.db; +var throwDownloadError = arangodb.throwDownloadError; +var throwFileNoteFound = arangodb.throwFileNoteFound; +var throwBadParameter = arangodb.throwBadParameter; +var checkParameter = arangodb.checkParameter; + +var arango = require("internal").arango; +var download = require("internal").download; // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -56,7 +60,7 @@ function getStorage () { } //////////////////////////////////////////////////////////////////////////////// -/// @brief returns the aal collection +/// @brief returns the fishbowl collection //////////////////////////////////////////////////////////////////////////////// function getFishbowlStorage () { @@ -99,45 +103,6 @@ function buildGithubFishbowlUrl (name) { return "https://raw.github.com/" + getFishbowlUrl() + "/master/applications/" + name + ".json"; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief thrown an error in case a download failed -//////////////////////////////////////////////////////////////////////////////// - -function throwDownloadError (msg) { - 'use strict'; - - throw new ArangoError({ - errorNum: errors.ERROR_APPLICATION_DOWNLOAD_FAILED.code, - errorMessage: errors.ERROR_APPLICATION_DOWNLOAD_FAILED.message + ': ' + String(msg) - }); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief thrown an error in case of missing file -//////////////////////////////////////////////////////////////////////////////// - -function throwFileNoteFound (msg) { - 'use strict'; - - throw new ArangoError({ - errorNum: errors.ERROR_FILE_NOT_FOUND.code, - errorMessage: errors.ERROR_FILE_NOT_FOUND.message + ': ' + String(msg) - }); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief thrown an error in case of a bad parameter -//////////////////////////////////////////////////////////////////////////////// - -function throwBadParameter (msg) { - 'use strict'; - - throw new ArangoError({ - errorNum: errors.ERROR_BAD_PARAMETER.code, - errorMessage: errors.ERROR_BAD_PARAMETER.message + ': ' + String(msg) - }); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief validate an app name and fail if it is invalid //////////////////////////////////////////////////////////////////////////////// @@ -346,7 +311,11 @@ function processGithubRepository (source) { var tempFile = fs.getTempFile("downloads", false); try { - var result = internal.download(url, "", { method: "get", followRedirects: true, timeout: 30 }, tempFile); + var result = download(url, "", { + method: "get", + followRedirects: true, + timeout: 30 + }, tempFile); if (result.code >= 200 && result.code <= 299) { source.filename = tempFile; @@ -384,7 +353,7 @@ function processSource (src) { } // upload file to the server - var response = internal.arango.SEND_FILE("/_api/upload", src.filename); + var response = arango.SEND_FILE("/_api/upload", src.filename); if (src.removeFile && src.filename !== '') { try { @@ -510,7 +479,11 @@ function updateFishbowl () { var path = fs.getTempFile("zip", false); try { - var result = internal.download(url, "", { method: "get", followRedirects: true, timeout: 30 }, filename); + var result = download(url, "", { + method: "get", + followRedirects: true, + timeout: 30 + }, filename); if (result.code < 200 || result.code > 299) { throwDownloadError("Github download from '" + url + "' failed with error code " + result.code); @@ -592,6 +565,8 @@ exports.run = function (args) { } var type = args[0]; + var printf = arangodb.printf; + var res; try { if (type === 'fetch') { @@ -605,6 +580,15 @@ exports.run = function (args) { exports.mount(args[1], args[2]); } } + else if (type === 'setup') { + exports.setup(args[1]); + } + else if (type === 'teardown') { + exports.teardown(args[1]); + } + else if (type === 'unmount') { + res = exports.unmount(args[1]); + } else if (type === 'install') { if (3 < args.length) { exports.install(args[1], args[2], JSON.parse(args[3])); @@ -612,12 +596,17 @@ exports.run = function (args) { else { exports.install(args[1], args[2]); } - } - else if (type === 'unmount') { - exports.unmount(args[1]); + + printf("Application %s installed successfully at mount point %s\n", + res.appId, + res.mount); } else if (type === 'uninstall') { - exports.uninstall(args[1]); + res = exports.uninstall(args[1]); + + printf("Application %s unmounted successfully from mount point %s\n", + res.appId, + res.mount); } else if (type === 'list') { if (1 < args.length && args[1] === "prefix") { @@ -671,21 +660,18 @@ exports.run = function (args) { exports.fetch = function (type, location, version) { 'use strict'; - var usage = ", usage: fetch(, , [])"; - - if (typeof type === "undefined") { - throwBadParameter("Type missing" + usage); - } - - if (typeof location === "undefined") { - throwBadParameter("Location missing" + usage); - } + checkParameter( + "fetch(, , [])", + [ [ "Location type", "string" ], + [ "Location", "string" ] ], + [ type, location ] ); var source = { type: type, location: location, version: version }; + var filename = processSource(source); if (typeof source.name === "undefined") { @@ -703,9 +689,8 @@ exports.fetch = function (type, location, version) { }; var res = arango.POST("/_admin/foxx/fetch", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { path: res.path, app: res.app }; + return arangosh.checkRequestResult(res); }; //////////////////////////////////////////////////////////////////////////////// @@ -715,15 +700,11 @@ exports.fetch = function (type, location, version) { exports.mount = function (appId, mount, options) { 'use strict'; - var usage = ", usage: mount(, , [])"; - - if (typeof appId === "undefined") { - throwBadParameter("AppId missing" + usage); - } - - if (typeof mount === "undefined") { - throwBadParameter("Mount missing" + usage); - } + checkParameter( + "mount(, , [])", + [ [ "Application identifier", "string" ], + [ "Mount path", "string" ] ], + [ appId, mount ] ); var req = { appId: appId, @@ -735,38 +716,75 @@ exports.mount = function (appId, mount, options) { validateMount(mount); var res = arango.POST("/_admin/foxx/mount", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { appId: res.appId, mountId: res.mountId }; + return arangosh.checkRequestResult(res); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief sets up a FOXX application +//////////////////////////////////////////////////////////////////////////////// + +exports.setup = function (mount) { + 'use strict'; + + checkParameter( + "setup()", + [ [ "Mount identifier", "string" ] ], + [ mount ] ); + + var req = { + mount: mount + }; + + validateMount(mount); + + var res = arango.POST("/_admin/foxx/setup", JSON.stringify(req)); + arangosh.checkRequestResult(res); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tears down a FOXX application +//////////////////////////////////////////////////////////////////////////////// + +exports.teardown = function (mount) { + 'use strict'; + + checkParameter( + "teardown()", + [ [ "Mount identifier", "string" ] ], + [ mount ] ); + + var req = { + mount: mount + }; + + validateMount(mount); + + var res = arango.POST("/_admin/foxx/teardown", JSON.stringify(req)); + arangosh.checkRequestResult(res); }; //////////////////////////////////////////////////////////////////////////////// /// @brief unmounts a FOXX application //////////////////////////////////////////////////////////////////////////////// -exports.unmount = function (key) { +exports.unmount = function (mount) { 'use strict'; - var usage = ", usage: unmount()"; + checkParameter( + "unmount()", + [ [ "Mount identifier", "string" ] ], + [ mount ] ); - if (typeof key === "undefined") { - throwBadParameter("Mount point or MountID missing" + usage); - } - - validateAppName(key); + validateAppName(mount); var req = { - key: key + mount: mount }; var res = arango.POST("/_admin/foxx/unmount", JSON.stringify(req)); - arangosh.checkRequestResult(res); - - arangodb.printf("Application %s unmounted successfully from mount point %s\n", - res.appId, - res.mount); - return { appId: res.appId, mount: res.mount, collectionPrefix: res.collectionPrefix }; + return arangosh.checkRequestResult(res); }; //////////////////////////////////////////////////////////////////////////////// @@ -776,15 +794,11 @@ exports.unmount = function (key) { exports.install = function (name, mount, options) { 'use strict'; - var usage = ", usage: install(, , [])"; - - if (typeof name === "undefined") { - throwBadParameter("Name missing" + usage); - } - - if (typeof mount === "undefined") { - throwBadParameter("Mount missing" + usage); - } + checkParameter( + "install(, , [])", + [ [ "Name", "string" ], + [ "Mount path", "string" ]], + [ name, mount ] ); validateMount(mount); @@ -850,33 +864,27 @@ exports.install = function (name, mount, options) { throw new Error("Cannot extract application id"); } - return exports.mount(appId, mount, options); + var res = exports.mount(appId, mount, options); + exports.setup(appId, mount); + + return res; }; //////////////////////////////////////////////////////////////////////////////// /// @brief uninstalls a FOXX application //////////////////////////////////////////////////////////////////////////////// -exports.uninstall = function (key) { +exports.uninstall = function (mount) { 'use strict'; - var usage = ", usage: uninstall()"; + checkParameter( + "teardown()", + [ [ "Mount identifier", "string" ] ], + [ mount ] ); - if (typeof key === "undefined") { - throwBadParameter("Mount point or MountID missing" + usage); - } + exports.teardown(mount); - var req = { - key: key - }; - - validateAppName(key); - - var doc = exports.unmount(key); - var res = arango.POST("/_admin/foxx/teardown", JSON.stringify(doc)); - arangosh.checkRequestResult(res); - - arangodb.printf("Application uninstalled successfully\n"); + return exports.unmount(mount); }; //////////////////////////////////////////////////////////////////////////////// @@ -1199,7 +1207,9 @@ exports.help = function () { var commands = { "fetch" : "fetches a foxx application from the central foxx-apps repository into the local repository", "mount" : "mounts a fetched foxx application to a local URL", - "install" : "fetches a foxx application from the central foxx-apps repository and mounts it to a local URL", + "setup" : "setup executes the setup script (app must already be mounted)", + "install" : "fetches a foxx application from the central foxx-apps repository, mounts it to a local URL and sets it up", + "teardown" : "teardown execute the teardown script (app must be still be mounted)", "unmount" : "unmounts a mounted foxx application", "uninstall" : "unmounts a mounted foxx application and calls its teardown method", "list" : "lists all installed foxx applications", diff --git a/js/common/modules/org/arangodb-common.js b/js/common/modules/org/arangodb-common.js index e3ccd7c5a9..5cceedec67 100644 --- a/js/common/modules/org/arangodb-common.js +++ b/js/common/modules/org/arangodb-common.js @@ -134,12 +134,6 @@ exports.guessContentType = function (filename) { return "text/plain; charset=utf-8"; }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief inspect -//////////////////////////////////////////////////////////////////////////////// - -exports.inspect = internal.inspect; - //////////////////////////////////////////////////////////////////////////////// /// @brief normalizeURL /// @@ -220,6 +214,12 @@ exports.normalizeURL = function (path) { return r + n.join('/'); }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief inspect +//////////////////////////////////////////////////////////////////////////////// + +exports.inspect = internal.inspect; + //////////////////////////////////////////////////////////////////////////////// /// @brief output /// @@ -457,6 +457,68 @@ exports.stringPadding = function (str, len, pad, dir) { return str; }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief throws an error in case a download failed +//////////////////////////////////////////////////////////////////////////////// + +exports.throwDownloadError = function (msg) { + 'use strict'; + + throw new exports.ArangoError({ + errorNum: exports.errors.ERROR_APPLICATION_DOWNLOAD_FAILED.code, + errorMessage: exports.errors.ERROR_APPLICATION_DOWNLOAD_FAILED.message + ': ' + String(msg) + }); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief throws an error in case of missing file +//////////////////////////////////////////////////////////////////////////////// + +exports.throwFileNoteFound = function (msg) { + 'use strict'; + + throw new exports.ArangoError({ + errorNum: exports.errors.ERROR_FILE_NOT_FOUND.code, + errorMessage: exports.errors.ERROR_FILE_NOT_FOUND.message + ': ' + String(msg) + }); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief throws an error in case of a bad parameter +//////////////////////////////////////////////////////////////////////////////// + +exports.throwBadParameter = function (msg) { + 'use strict'; + + throw new exports.ArangoError({ + errorNum: exports.errors.ERROR_BAD_PARAMETER.code, + errorMessage: exports.errors.ERROR_BAD_PARAMETER.message + ': ' + String(msg) + }); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief checks parameter, throws an error if missing +//////////////////////////////////////////////////////////////////////////////// + +exports.checkParameter = function (usage, descs, vars) { + 'use strict'; + + var i; + + for (i = 0; i < descs.length; ++i) { + var desc = descs[i]; + + if (typeof vars[i] === "undefined") { + exports.throwBadParameter(desc[0] + " missing, usage: " + usage); + } + + if (typeof vars[i] !== desc[1]) { + exports.throwBadParameter(desc[0] + " should be a '" + desc[1] + "', " + + "not '" + (typeof vars[i]) + "'"); + } + } +}; + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/js/server/modules/org/arangodb/actions.js b/js/server/modules/org/arangodb/actions.js index 1e68355a7f..2672206003 100644 --- a/js/server/modules/org/arangodb/actions.js +++ b/js/server/modules/org/arangodb/actions.js @@ -42,11 +42,6 @@ var moduleExists = function(name) { return module.exists; }; // --SECTION-- private variables // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoActions -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief routing cache //////////////////////////////////////////////////////////////////////////////// @@ -59,19 +54,10 @@ var RoutingCache = {}; var ALL_METHODS = [ "DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" ]; -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoActions -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief function that's returned for non-implemented actions //////////////////////////////////////////////////////////////////////////////// @@ -875,19 +861,10 @@ function flattenRouting (routes, path, urlParameters, depth, prefix) { return result; } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoActions -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief returns a result of a query as documents /// @@ -909,21 +886,8 @@ function flattenRouting (routes, path, urlParameters, depth, prefix) { /// /// @FA{options.context} /// -/// The context to which this actions belongs. Possible values are "admin", -/// "monitoring", "api", and "user". All contexts apart from "user" are reserved -/// for system actions and are database independent. All actions except "user" -/// and "api" are executed in a different worker queue than the normal queue for -/// clients. The "api" actions are used by the client api to communicate with -/// the ArangoDB server. Both the "api" and "user" actions are using the same -/// worker queue. -/// -/// It is possible to specify a list of contexts, in case an actions belongs to -/// more than one context. -/// -/// Note that the url for "user" actions is automatically prefixed -/// with @LIT{_action}. This applies to all specified contexts. For example, if -/// the context contains "admin" and "user" and the url is @LIT{hello}, then the -/// action is accessible under @LIT{/_action/hello} - even for the admin context. +/// The context to which this actions belongs. Possible values are "admin" +/// and "user". /// /// @FA{options.callback}(@FA{request}, @FA{response}) /// @@ -959,36 +923,13 @@ function defineHttp (options) { 'use strict'; var url = options.url; - var contexts = options.context; + var context = options.context; var callback = options.callback; var parameters = options.parameters; var prefix = true; - var userContext = false; - var i; - if (! contexts) { - contexts = "user"; - } - - if (typeof contexts === "string") { - if (contexts === "user") { - userContext = true; - } - - contexts = [ contexts ]; - } - else { - for (i = 0; i < contexts.length && ! userContext; ++i) { - var context = contexts[i]; - - if (context === "user") { - userContext = true; - } - } - } - - if (userContext) { - url = "_action/" + url; + if (typeof context === "undefined") { + context = "user"; } if (typeof callback !== "function") { @@ -1000,17 +941,18 @@ function defineHttp (options) { prefix = options.prefix; } - var parameter = { parameters : parameters, prefix : prefix }; + var parameter = { + parameters : parameters, + prefix : prefix + }; - if (0 < contexts.length) { - console.debug("defining action '%s' in contexts '%s'", url, contexts); + console.debug("defining action '%s' in context '%s'", url, context); - try { - internal.defineAction(url, callback, parameter, contexts); - } - catch (err) { - console.error("action '%s' encountered error: %s", url, err); - } + try { + internal.defineAction(url, callback, parameter, [context]); + } + catch (err) { + console.error("action '%s' encountered error: %s", url, err); } } @@ -1398,19 +1340,10 @@ function firstRouting (type, parts) { }); } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- standard HTTP responses // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoActions -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief convenience function to return an HTTP 400 error for a bad parameter //////////////////////////////////////////////////////////////////////////////// @@ -1599,19 +1532,10 @@ function resultTemporaryRedirect (req, res, destination, headers) { res.headers.location = destination; } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- ArangoDB specific responses // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoActions -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief returns a result set from a cursor //////////////////////////////////////////////////////////////////////////////// @@ -1796,19 +1720,34 @@ function resultException (req, res, err, headers, verbose) { resultError(req, res, code, num, msg, headers); } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- specific actions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoActions -/// @{ +/// @brief creates a simple post callback //////////////////////////////////////////////////////////////////////////////// +function easyPostCallback (opts) { + 'use strict'; + + return function (req, res) { + var body = getJsonBody(req, res); + + if (opts.body === true && body === undefined) { + return; + } + + try { + var result = opts.callback(body); + resultOk(req, res, exports.HTTP_OK, result); + } + catch (err) { + resultException(req, res, err, undefined, false); + } + }; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief echos a request //////////////////////////////////////////////////////////////////////////////// @@ -1964,19 +1903,10 @@ function addCookie (res, name, value, lifeTime, path, domain, secure, httpOnly) res.cookies.push(cookie); } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- MODULE EXPORTS // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoActions -/// @{ -//////////////////////////////////////////////////////////////////////////////// - // public functions exports.defineHttp = defineHttp; exports.getErrorMessage = getErrorMessage; @@ -2006,6 +1936,7 @@ exports.indexNotFound = indexNotFound; exports.resultException = resultException; // standard actions +exports.easyPostCallback = easyPostCallback; exports.echoRequest = echoRequest; exports.logRequest = logRequest; exports.redirectRequest = redirectRequest; @@ -2061,10 +1992,6 @@ exports.HTTP_NOT_IMPLEMENTED = 501; exports.HTTP_BAD_GATEWAY = 502; exports.HTTP_SERVICE_UNAVAILABLE = 503; -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/js/server/modules/org/arangodb/foxx-manager.js b/js/server/modules/org/arangodb/foxx-manager.js index e1c2ae0b00..36de6de366 100644 --- a/js/server/modules/org/arangodb/foxx-manager.js +++ b/js/server/modules/org/arangodb/foxx-manager.js @@ -28,12 +28,13 @@ /// @author Copyright 2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -var internal = require("internal"); +var arangodb = require("org/arangodb"); var console = require("console"); var fs = require("fs"); -var arangodb = require("org/arangodb"); +var executeGlobalContextFunction = require("internal").executeGlobalContextFunction; +var checkParameter = arangodb.checkParameter; // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -55,6 +56,43 @@ function prefixFromMount (mount) { return mount.substr(1).replace(/\//g, "_"); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief finds mount document from mount path or identifier +//////////////////////////////////////////////////////////////////////////////// + +function mountFromId (mount) { + var aal = getStorage(); + var doc = aal.firstExample({ type: "mount", _id: mount }); + + if (doc === null) { + doc = aal.firstExample({ type: "mount", _key: mount }); + } + + if (doc === null) { + doc = aal.firstExample({ type: "mount", mount: mount }); + } + + if (doc === null) { + throw new Error("Cannot find mount identifier or path '" + mount + "'"); + } + + return doc; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates app object from application identifier +//////////////////////////////////////////////////////////////////////////////// + +function appFromAppId (appId) { + var app = module.createApp(appId); + + if (app === null) { + throw new Error("Cannot find application '" + appId + "'"); + } + + return app; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief builds one asset of an app //////////////////////////////////////////////////////////////////////////////// @@ -193,7 +231,7 @@ function executeAppScript (app, name, mount, prefix) { var desc = app._manifest; if (! desc) { - throw new Error("Invalid application manifest, app " + internal.inspect(app)); + throw new Error("Invalid application manifest, app " + arangodb.inspect(app)); } var root; @@ -303,10 +341,10 @@ function upsertAalAppEntry (manifest, thumbnail, path) { } //////////////////////////////////////////////////////////////////////////////// -/// @brief installs an app +/// @brief mounts an app //////////////////////////////////////////////////////////////////////////////// -function installAalApp (app, mount, prefix) { +function mountAalApp (app, mount, prefix) { 'use strict'; var aal = getStorage(); @@ -510,7 +548,7 @@ function routingAalApp (app, mount, prefix, dev) { // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @brief scans available FOXX applications +/// @brief scans fetched FOXX applications //////////////////////////////////////////////////////////////////////////////// exports.scanAppDirectory = function () { @@ -572,11 +610,28 @@ exports.scanAppDirectory = function () { //////////////////////////////////////////////////////////////////////////////// /// @brief mounts a FOXX application +/// +/// Input: +/// * appId: the application identifier +/// * mount: the mount path starting with a "/" +/// * options: +/// collectionPrefix: overwrites the default prefix +/// reload: reload the routing info (default: true) +/// +/// Output: +/// * appId: the application identifier (must be mounted) +/// * mountId: the mount identifier //////////////////////////////////////////////////////////////////////////////// exports.mount = function (appId, mount, options) { 'use strict'; + checkParameter( + "mount(, , [])", + [ [ "Application identifier", "string" ], + [ "Mount path", "string" ] ], + [ appId, mount ] ); + var aal = getStorage(); // ............................................................................. @@ -598,16 +653,15 @@ exports.mount = function (appId, mount, options) { // ............................................................................. var doc; - var desc; try { var prefix = options && options.collectionPrefix; - doc = installAalApp(app, mount, prefix, false); + doc = mountAalApp(app, mount, prefix, false); } catch (err) { if (doc !== undefined) { - desc = aal.document(doc._key)._shallowCopy; + var desc = aal.document(doc._key)._shallowCopy; desc.error = String(err); desc.active = false; @@ -625,62 +679,120 @@ exports.mount = function (appId, mount, options) { if ( typeof options === "undefined" || typeof options.reload === "undefined" || options.reload === true) { - internal.executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()"); + executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()"); } return { appId: app._id, mountId: doc._key }; }; //////////////////////////////////////////////////////////////////////////////// -/// @brief unmounts a FOXX application +/// @brief sets up a FOXX application +/// +/// Input: +/// * mount: the mount identifier or path +/// +/// Output: +/// - //////////////////////////////////////////////////////////////////////////////// -exports.unmount = function (key) { +exports.setup = function (mount) { 'use strict'; - var aal = getStorage(); - var doc = aal.firstExample({ type: "mount", _key: key }); + checkParameter( + "setup()", + [ [ "Mount identifier", "string" ] ], + [ mount ] ); - if (doc === null) { - doc = aal.firstExample({ type: "mount", mount: key }); - } + var doc = mountFromId(mount); + var app = appFromAppId(doc.id); - if (doc === null) { - throw new Error("Key '" + key + "' is neither a mount point nor a MountId"); + setupApp(app, mount, doc.collectionPrefix); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tears down a FOXX application +/// +/// Input: +/// * mount: the mount path starting with a "/" +/// +/// Output: +/// - +//////////////////////////////////////////////////////////////////////////////// + +exports.teardown = function (mount) { + 'use strict'; + + checkParameter( + "teardown()", + [ [ "Mount identifier", "string" ] ], + [ mount ] ); + + var appId; + + try { + var doc = mountFromId(mount); + + appId = doc.app; + var app = appFromAppId(appId); + + teardownApp(app, mount, doc.collectionPrefix); } + catch (err) { + console.error("Teardown not possible for mount '%s': %s", mount, String(err)); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief unmounts a FOXX application +/// +/// Input: +/// * key: mount key o mount point +/// +/// Output: +/// * appId: the application identifier +/// * mount: the mount path starting with "/" +/// * collectionPrefix: the collection prefix +//////////////////////////////////////////////////////////////////////////////// + +exports.unmount = function (mount) { + 'use strict'; + + checkParameter( + "unmount()", + [ [ "Mount identifier", "string" ] ], + [ mount ] ); + + var doc = mountFromId(mount); if (doc.isSystem) { throw new Error("Cannot unmount system application"); } - aal.remove(doc); + getStorage().remove(doc); - internal.executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()"); + executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()"); return { appId: doc.app, mount: doc.mount, collectionPrefix: doc.collectionPrefix }; }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief tears down a FOXX application -//////////////////////////////////////////////////////////////////////////////// - -exports.teardown = function (appId, mount, collectionPrefix) { - 'use strict'; - - try { - var app = module.createApp(appId); - teardownApp(app, mount, collectionPrefix); - } - catch (err) { - console.error("Teardown not possible for application '%s': %s", appId, String(err)); - } -}; - //////////////////////////////////////////////////////////////////////////////// /// @brief sets up a development app +/// +/// Input: +/// * filename: the directory name of the development app +/// +/// Output: +/// - //////////////////////////////////////////////////////////////////////////////// exports.devSetup = function (filename) { + 'use strict'; + + checkParameter( + "devSetup()", + [ [ "Application folder", "string" ] ], + [ filename ] ); + var root = module.devAppPath(); var m = fs.join(root, filename, "manifest.json"); @@ -711,9 +823,22 @@ exports.devSetup = function (filename) { //////////////////////////////////////////////////////////////////////////////// /// @brief tears down up a development app +/// +/// Input: +/// * filename: the directory name of the development app +/// +/// Output: +/// - //////////////////////////////////////////////////////////////////////////////// exports.devTeardown = function (filename) { + 'use strict'; + + checkParameter( + "devTeardown()", + [ [ "Application folder", "string" ] ], + [ filename ] ); + var root = module.devAppPath(); var m = fs.join(root, filename, "manifest.json"); @@ -747,6 +872,8 @@ exports.devTeardown = function (filename) { //////////////////////////////////////////////////////////////////////////////// exports.appRoutes = function () { + 'use strict'; + var aal = getStorage(); var find = aal.byExample({ type: "mount", active: true }); @@ -790,6 +917,8 @@ exports.appRoutes = function () { //////////////////////////////////////////////////////////////////////////////// exports.developmentRoutes = function () { + 'use strict'; + var routes = []; var root = module.devAppPath(); diff --git a/js/server/modules/org/arangodb/foxx.js b/js/server/modules/org/arangodb/foxx.js index 47d99c8fb5..1a55830870 100644 --- a/js/server/modules/org/arangodb/foxx.js +++ b/js/server/modules/org/arangodb/foxx.js @@ -662,7 +662,7 @@ BaseMiddleware = function (templateCollection, helperCollection) { var responseFunctions, requestFunctions, _ = require("underscore"); - + requestFunctions = { //////////////////////////////////////////////////////////////////////////////// From 5820afd50752590f9150c10a0569b7dfede3a206 Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Fri, 26 Jul 2013 23:01:22 +0200 Subject: [PATCH 2/2] merged --- html/admin/js/modules/org/arangodb-common.js | 74 +++++++++++++++++-- .../modules/org/arangodb/foxx-manager.js | 3 +- .../modules/org/arangodb/foxx-manager.js | 1 + 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/html/admin/js/modules/org/arangodb-common.js b/html/admin/js/modules/org/arangodb-common.js index be2e2d756d..b3377a602c 100644 --- a/html/admin/js/modules/org/arangodb-common.js +++ b/html/admin/js/modules/org/arangodb-common.js @@ -135,12 +135,6 @@ exports.guessContentType = function (filename) { return "text/plain; charset=utf-8"; }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief inspect -//////////////////////////////////////////////////////////////////////////////// - -exports.inspect = internal.inspect; - //////////////////////////////////////////////////////////////////////////////// /// @brief normalizeURL /// @@ -221,6 +215,12 @@ exports.normalizeURL = function (path) { return r + n.join('/'); }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief inspect +//////////////////////////////////////////////////////////////////////////////// + +exports.inspect = internal.inspect; + //////////////////////////////////////////////////////////////////////////////// /// @brief output /// @@ -458,6 +458,68 @@ exports.stringPadding = function (str, len, pad, dir) { return str; }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief throws an error in case a download failed +//////////////////////////////////////////////////////////////////////////////// + +exports.throwDownloadError = function (msg) { + 'use strict'; + + throw new exports.ArangoError({ + errorNum: exports.errors.ERROR_APPLICATION_DOWNLOAD_FAILED.code, + errorMessage: exports.errors.ERROR_APPLICATION_DOWNLOAD_FAILED.message + ': ' + String(msg) + }); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief throws an error in case of missing file +//////////////////////////////////////////////////////////////////////////////// + +exports.throwFileNoteFound = function (msg) { + 'use strict'; + + throw new exports.ArangoError({ + errorNum: exports.errors.ERROR_FILE_NOT_FOUND.code, + errorMessage: exports.errors.ERROR_FILE_NOT_FOUND.message + ': ' + String(msg) + }); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief throws an error in case of a bad parameter +//////////////////////////////////////////////////////////////////////////////// + +exports.throwBadParameter = function (msg) { + 'use strict'; + + throw new exports.ArangoError({ + errorNum: exports.errors.ERROR_BAD_PARAMETER.code, + errorMessage: exports.errors.ERROR_BAD_PARAMETER.message + ': ' + String(msg) + }); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief checks parameter, throws an error if missing +//////////////////////////////////////////////////////////////////////////////// + +exports.checkParameter = function (usage, descs, vars) { + 'use strict'; + + var i; + + for (i = 0; i < descs.length; ++i) { + var desc = descs[i]; + + if (typeof vars[i] === "undefined") { + exports.throwBadParameter(desc[0] + " missing, usage: " + usage); + } + + if (typeof vars[i] !== desc[1]) { + exports.throwBadParameter(desc[0] + " should be a '" + desc[1] + "', " + + "not '" + (typeof vars[i]) + "'"); + } + } +}; + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/js/client/modules/org/arangodb/foxx-manager.js b/js/client/modules/org/arangodb/foxx-manager.js index 2f161b9e68..0d49e34507 100644 --- a/js/client/modules/org/arangodb/foxx-manager.js +++ b/js/client/modules/org/arangodb/foxx-manager.js @@ -1220,7 +1220,8 @@ exports.help = function () { "fetch" : "fetches a foxx application from the central foxx-apps repository into the local repository", "mount" : "mounts a fetched foxx application to a local URL", "setup" : "setup executes the setup script (app must already be mounted)", - "install" : "fetches a foxx application from the central foxx-apps repository, mounts it to a local URL and sets it up", + "install" : "fetches a foxx application from the central foxx-apps repository, mounts it to a local URL " + + "and sets it up", "teardown" : "teardown execute the teardown script (app must be still be mounted)", "unmount" : "unmounts a mounted foxx application", "uninstall" : "unmounts a mounted foxx application and calls its teardown method", diff --git a/js/server/modules/org/arangodb/foxx-manager.js b/js/server/modules/org/arangodb/foxx-manager.js index e1deae43c6..20ad157fb7 100644 --- a/js/server/modules/org/arangodb/foxx-manager.js +++ b/js/server/modules/org/arangodb/foxx-manager.js @@ -665,6 +665,7 @@ exports.mount = function (appId, mount, options) { options = options || { }; + try { doc = mountAalApp(app, mount, options); } catch (err) {