1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
Jan Steemann 2013-07-26 23:08:25 +02:00
commit 3f3560a47d
8 changed files with 551 additions and 391 deletions

View File

@ -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.)

View File

@ -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
// -----------------------------------------------------------------------------

View File

@ -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);
}
})
});
// -----------------------------------------------------------------------------

View File

@ -108,6 +108,12 @@ exports.checkRequestResult = function (requestResult) {
throw new ArangoError(requestResult);
}
var copy = requestResult._shallowCopy;
delete copy.error;
return copy;
};
////////////////////////////////////////////////////////////////////////////////

View File

@ -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(<type>, <location>, [<version>])";
if (typeof type === "undefined") {
throwBadParameter("Type missing" + usage);
}
if (typeof location === "undefined") {
throwBadParameter("Location missing" + usage);
}
checkParameter(
"fetch(<type>, <location>, [<version>])",
[ [ "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(<appId>, <mount>, [<options>])";
if (typeof appId === "undefined") {
throwBadParameter("AppId missing" + usage);
}
if (typeof mount === "undefined") {
throwBadParameter("Mount missing" + usage);
}
checkParameter(
"mount(<appId>, <mount>, [<options>])",
[ [ "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>)",
[ [ "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>)",
[ [ "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(<mount>)";
checkParameter(
"unmount(<mount>)",
[ [ "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(<name>, <mount>, [<options>])";
if (typeof name === "undefined") {
throwBadParameter("Name missing" + usage);
}
if (typeof mount === "undefined") {
throwBadParameter("Mount missing" + usage);
}
checkParameter(
"install(<name>, <mount>, [<options>])",
[ [ "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(<mount>)";
checkParameter(
"teardown(<mount>)",
[ [ "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);
};
////////////////////////////////////////////////////////////////////////////////
@ -1211,7 +1219,10 @@ 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",

View File

@ -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
// -----------------------------------------------------------------------------

View File

@ -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
////////////////////////////////////////////////////////////////////////////////
@ -1978,19 +1917,10 @@ function stringifyRequestAddress (req) {
return out;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- MODULE EXPORTS
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoActions
/// @{
////////////////////////////////////////////////////////////////////////////////
// public functions
exports.defineHttp = defineHttp;
exports.getErrorMessage = getErrorMessage;
@ -2021,6 +1951,7 @@ exports.indexNotFound = indexNotFound;
exports.resultException = resultException;
// standard actions
exports.easyPostCallback = easyPostCallback;
exports.echoRequest = echoRequest;
exports.logRequest = logRequest;
exports.redirectRequest = redirectRequest;
@ -2076,10 +2007,6 @@ exports.HTTP_NOT_IMPLEMENTED = 501;
exports.HTTP_BAD_GATEWAY = 502;
exports.HTTP_SERVICE_UNAVAILABLE = 503;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -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;
@ -304,10 +342,10 @@ function upsertAalAppEntry (manifest, thumbnail, path) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief installs an app
/// @brief mounts an app
////////////////////////////////////////////////////////////////////////////////
function installAalApp (app, mount, options) {
function mountAalApp (app, mount, options) {
'use strict';
var aal = getStorage();
@ -519,7 +557,7 @@ function routingAalApp (app, mount, options, dev) {
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief scans available FOXX applications
/// @brief scans fetched FOXX applications
////////////////////////////////////////////////////////////////////////////////
exports.scanAppDirectory = function () {
@ -581,11 +619,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(<appId>, <mount>, [<options>])",
[ [ "Application identifier", "string" ],
[ "Mount path", "string" ] ],
[ appId, mount ] );
var aal = getStorage();
// .............................................................................
@ -607,16 +662,15 @@ exports.mount = function (appId, mount, options) {
// .............................................................................
var doc;
var desc;
options = options || { };
try {
doc = installAalApp(app, mount, options);
doc = mountAalApp(app, mount, options);
}
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;
@ -633,62 +687,120 @@ exports.mount = function (appId, mount, options) {
if ( 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>)",
[ [ "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>)",
[ [ "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>)",
[ [ "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(<mount>)",
[ [ "Application folder", "string" ] ],
[ filename ] );
var root = module.devAppPath();
var m = fs.join(root, filename, "manifest.json");
@ -700,7 +812,7 @@ exports.devSetup = function (filename) {
var mount = "/dev/" + filename;
var prefix = prefixFromMount(mount);
var app = module.createApp(appId, { });
var app = module.createApp(appId, {});
if (app === null) {
throw new Error("Cannot find application '" + appId + "'");
@ -719,9 +831,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(<mount>)",
[ [ "Application folder", "string" ] ],
[ filename ] );
var root = module.devAppPath();
var m = fs.join(root, filename, "manifest.json");
@ -733,7 +858,7 @@ exports.devTeardown = function (filename) {
var mount = "/dev/" + filename;
var prefix = prefixFromMount(mount);
var app = module.createApp(appId, { });
var app = module.createApp(appId, {});
if (app === null) {
throw new Error("Cannot find application '" + appId + "'");
@ -755,6 +880,8 @@ exports.devTeardown = function (filename) {
////////////////////////////////////////////////////////////////////////////////
exports.appRoutes = function () {
'use strict';
var aal = getStorage();
var find = aal.byExample({ type: "mount", active: true });
@ -769,7 +896,7 @@ exports.appRoutes = function () {
options.collectionPrefix = doc.collectionPrefix || undefined;
try {
var app = module.createApp(appId, options || { });
var app = module.createApp(appId, options || {});
if (app === null) {
throw new Error("Cannot find application '" + appId + "'");
@ -799,6 +926,8 @@ exports.appRoutes = function () {
////////////////////////////////////////////////////////////////////////////////
exports.developmentRoutes = function () {
'use strict';
var routes = [];
var root = module.devAppPath();