mirror of https://gitee.com/bigwinds/arangodb
Implemented FoxxService
This commit is contained in:
parent
309dcb2c17
commit
252cba5e9f
|
@ -57,7 +57,7 @@ publicController.get("/whoAmI", function(req, res) {
|
||||||
var uid = req.session && req.session.get("uid");
|
var uid = req.session && req.session.get("uid");
|
||||||
var user = null;
|
var user = null;
|
||||||
if (uid) {
|
if (uid) {
|
||||||
var users = Foxx.requireApp("_system/users").userStorage;
|
var users = Foxx.getExports("_system/users").userStorage;
|
||||||
try {
|
try {
|
||||||
user = users.get(uid).get("user");
|
user = users.get(uid).get("user");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -82,11 +82,11 @@ publicController.post("/login", function (req, res) {
|
||||||
} else {
|
} else {
|
||||||
req.session = publicController.sessions.getSessionStorage().create();
|
req.session = publicController.sessions.getSessionStorage().create();
|
||||||
}
|
}
|
||||||
var users = Foxx.requireApp("_system/users").userStorage;
|
var users = Foxx.getExports("_system/users").userStorage;
|
||||||
var credentials = req.parameters.credentials;
|
var credentials = req.parameters.credentials;
|
||||||
var user = users.resolve(credentials.get("username"));
|
var user = users.resolve(credentials.get("username"));
|
||||||
if (!user) throw new UnauthorizedError();
|
if (!user) throw new UnauthorizedError();
|
||||||
var auth = Foxx.requireApp("_system/simple-auth").auth;
|
var auth = Foxx.getExports("_system/simple-auth").auth;
|
||||||
var valid = auth.verifyPassword(user.get("authData").simple, credentials.get("password"));
|
var valid = auth.verifyPassword(user.get("authData").simple, credentials.get("password"));
|
||||||
if (!valid) throw new UnauthorizedError();
|
if (!valid) throw new UnauthorizedError();
|
||||||
req.session.setUser(user);
|
req.session.setUser(user);
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
var FoxxController = require("org/arangodb/foxx").Controller,
|
var FoxxController = require("org/arangodb/foxx").Controller,
|
||||||
UnauthorizedError = require("http-errors").Unauthorized,
|
UnauthorizedError = require("http-errors").Unauthorized,
|
||||||
internal = require("internal"),
|
internal = require("internal"),
|
||||||
Configuration = require("models/configuration").Model,
|
Configuration = require("./models/configuration").Model,
|
||||||
controller = new FoxxController(applicationContext),
|
controller = new FoxxController(applicationContext),
|
||||||
db = require("internal").db,
|
db = require("internal").db,
|
||||||
FoxxManager = require("org/arangodb/foxx/manager");
|
FoxxManager = require("org/arangodb/foxx/manager");
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var defaultThumb = require("/lib/defaultThumbnail").defaultThumb;
|
var defaultThumb = require("./lib/defaultThumbnail").defaultThumb;
|
||||||
|
|
||||||
controller.activateSessions({
|
controller.activateSessions({
|
||||||
autoCreateSession: false,
|
autoCreateSession: false,
|
||||||
|
@ -212,7 +212,7 @@
|
||||||
var mount = validateMount(req);
|
var mount = validateMount(req);
|
||||||
var app = FoxxManager.lookupApp(mount);
|
var app = FoxxManager.lookupApp(mount);
|
||||||
if (app.hasOwnProperty("_thumbnail")) {
|
if (app.hasOwnProperty("_thumbnail")) {
|
||||||
res.body = app._thumbnail;
|
res.body = app.thumbnail;
|
||||||
} else {
|
} else {
|
||||||
res.body = defaultThumb;
|
res.body = defaultThumb;
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@
|
||||||
controller.get("/download/zip", function(req, res) {
|
controller.get("/download/zip", function(req, res) {
|
||||||
var mount = validateMount(req);
|
var mount = validateMount(req);
|
||||||
var app = FoxxManager.lookupApp(mount);
|
var app = FoxxManager.lookupApp(mount);
|
||||||
var dir = fs.join(fs.makeAbsolute(app._root), app._path);
|
var dir = fs.join(fs.makeAbsolute(app.root), app.path);
|
||||||
var zipPath = fmUtils.zipDirectory(dir);
|
var zipPath = fmUtils.zipDirectory(dir);
|
||||||
res.set("Content-Type", "application/octet-stream");
|
res.set("Content-Type", "application/octet-stream");
|
||||||
res.set("Content-Disposition", "attachment; filename=app.zip");
|
res.set("Content-Disposition", "attachment; filename=app.zip");
|
||||||
|
|
|
@ -114,17 +114,18 @@ function Module(id, parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.context = {
|
this.context = {
|
||||||
module: this,
|
|
||||||
exports: this.exports,
|
|
||||||
require: createRequire(this),
|
|
||||||
print: internal.print,
|
print: internal.print,
|
||||||
process: NATIVE_MODULES.process,
|
process: NATIVE_MODULES.process,
|
||||||
console: NATIVE_MODULES.console,
|
console: NATIVE_MODULES.console,
|
||||||
|
module: this,
|
||||||
|
exports: this.exports,
|
||||||
|
require: createRequire(this),
|
||||||
__filename: null,
|
__filename: null,
|
||||||
__dirname: null
|
__dirname: null
|
||||||
};
|
};
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
Object.keys(parent.context).forEach(function (key) {
|
Object.keys(parent.context).forEach(function (key) {
|
||||||
if (!hasOwnProperty(this.context, key)) {
|
if (!hasOwnProperty(this.context, key)) {
|
||||||
this.context[key] = parent.context[key];
|
this.context[key] = parent.context[key];
|
||||||
}
|
}
|
||||||
|
@ -563,6 +564,18 @@ Module._extensions['.json'] = function(module, filename) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Module._extensions['.coffee'] = function(module, filename) {
|
||||||
|
require('org/arangodb/deprecated')(
|
||||||
|
'2.8',
|
||||||
|
'CoffeeScript support is deprecated,'
|
||||||
|
+ ' please pre-compile CoffeeScript modules to JavaScript using external build tools.'
|
||||||
|
);
|
||||||
|
var content = fs.readFileSync(filename, 'utf8');
|
||||||
|
var cs = require('coffee-script');
|
||||||
|
module._compile(cs.compile(stripBOM(content), {bare: true}), filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// backwards compatibility
|
// backwards compatibility
|
||||||
Module.Module = Module;
|
Module.Module = Module;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
const internal = require('internal');
|
const internal = require('internal');
|
||||||
const path = require('path');
|
const fs = require('fs');
|
||||||
|
|
||||||
module.exports = exports = new EventEmitter();
|
module.exports = exports = new EventEmitter();
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ exports.stdout = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
exports.cwd = function () {
|
exports.cwd = function () {
|
||||||
return path.resolve(internal.appPath);
|
return fs.makeAbsolute('');
|
||||||
};
|
};
|
||||||
exports.nextTick = function (fn) {
|
exports.nextTick = function (fn) {
|
||||||
fn();
|
fn();
|
||||||
|
|
|
@ -1037,7 +1037,7 @@ function foxxRouting (req, res, options, next) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var app = foxxManager.lookupApp(mount);
|
var app = foxxManager.lookupApp(mount);
|
||||||
var devel = app._isDevelopment;
|
var devel = app.isDevelopment;
|
||||||
|
|
||||||
if (devel || ! options.hasOwnProperty('routing')) {
|
if (devel || ! options.hasOwnProperty('routing')) {
|
||||||
delete options.error;
|
delete options.error;
|
||||||
|
@ -1047,8 +1047,8 @@ function foxxRouting (req, res, options, next) {
|
||||||
app = foxxManager.lookupApp(mount);
|
app = foxxManager.lookupApp(mount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app._isBroken) {
|
if (app.isBroken) {
|
||||||
throw app._error;
|
throw app.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.routing = flattenRoutingTree(buildRoutingTree([foxxManager.routes(mount)]));
|
options.routing = flattenRoutingTree(buildRoutingTree([foxxManager.routes(mount)]));
|
||||||
|
|
|
@ -1,480 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief Foxx application module
|
|
||||||
///
|
|
||||||
/// @file
|
|
||||||
///
|
|
||||||
/// DISCLAIMER
|
|
||||||
///
|
|
||||||
/// Copyright 2013 triagens GmbH, Cologne, Germany
|
|
||||||
///
|
|
||||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
/// you may not use this file except in compliance with the License.
|
|
||||||
/// You may obtain a copy of the License at
|
|
||||||
///
|
|
||||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
///
|
|
||||||
/// Unless required by applicable law or agreed to in writing, software
|
|
||||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
/// See the License for the specific language governing permissions and
|
|
||||||
/// limitations under the License.
|
|
||||||
///
|
|
||||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
|
||||||
///
|
|
||||||
/// @author Dr. Frank Celler
|
|
||||||
/// @author Michael Hackstein
|
|
||||||
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- imports
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
var fs = require("fs");
|
|
||||||
var internal = require("internal");
|
|
||||||
var Module = require('module');
|
|
||||||
var db = internal.db;
|
|
||||||
var joi = require("joi");
|
|
||||||
var _= require("underscore");
|
|
||||||
var utils = require("org/arangodb/foxx/manager-utils");
|
|
||||||
var console = require("console");
|
|
||||||
var arangodb = require("org/arangodb");
|
|
||||||
var ArangoError = arangodb.ArangoError;
|
|
||||||
var errors = arangodb.errors;
|
|
||||||
var throwFileNotFound = arangodb.throwFileNotFound;
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- private functions
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function applyDefaultConfig(config, parse) {
|
|
||||||
var res = {};
|
|
||||||
if (config !== undefined) {
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- constructors and destructors
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- AppContext
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function AppContext(app) {
|
|
||||||
var prefix = fs.safeJoin(app._root, app._path);
|
|
||||||
|
|
||||||
this._prefix = prefix;
|
|
||||||
this.comments = [];
|
|
||||||
this.name = app._name;
|
|
||||||
this.version = app._version;
|
|
||||||
this.mount = app._mount;
|
|
||||||
this.collectionPrefix = app._collectionPrefix;
|
|
||||||
this.options = app._options;
|
|
||||||
this.configuration = app._configuration;
|
|
||||||
this.dependencies = app._dependencies;
|
|
||||||
this.basePath = prefix;
|
|
||||||
this.baseUrl = '/_db/' + encodeURIComponent(db._name()) + app._mount;
|
|
||||||
this.isDevelopment = app._isDevelopment;
|
|
||||||
this.isProduction = ! app._isDevelopment;
|
|
||||||
this.manifest = app._manifest;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppContext.prototype.foxxFilename = function (path) {
|
|
||||||
return fs.safeJoin(this._prefix, path);
|
|
||||||
};
|
|
||||||
|
|
||||||
AppContext.prototype.collectionName = function (name) {
|
|
||||||
var replaced = this.collectionPrefix.replace(/[:\.]+/g, '_') +
|
|
||||||
name.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);
|
|
||||||
|
|
||||||
if (replaced.length === 0) {
|
|
||||||
throw new Error("Cannot derive collection name from '" + name + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
return replaced;
|
|
||||||
};
|
|
||||||
|
|
||||||
AppContext.prototype.collection = function (name) {
|
|
||||||
return db._collection(this.collectionName(name));
|
|
||||||
};
|
|
||||||
|
|
||||||
AppContext.prototype.path = function (name) {
|
|
||||||
return fs.join(this._prefix, name);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
AppContext.prototype.comment = function (str) {
|
|
||||||
this.comments.push(str);
|
|
||||||
};
|
|
||||||
|
|
||||||
AppContext.prototype.clearComments = function () {
|
|
||||||
this.comments = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- ArangoApp
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief Checks if the mountpoint is reserved for system apps
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
function isSystemMount(mount) {
|
|
||||||
return (/^\/_/).test(mount);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief returns the root path for application. Knows about system apps
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
function computeRootAppPath(mount, isValidation) {
|
|
||||||
if (isValidation) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if (isSystemMount(mount)) {
|
|
||||||
return Module._systemAppPath;
|
|
||||||
}
|
|
||||||
return Module._appPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief ArangoApp constructor
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
function ArangoApp(config) {
|
|
||||||
if (config.error) {
|
|
||||||
this._error = config.error;
|
|
||||||
this._isBroken = true;
|
|
||||||
}
|
|
||||||
this._manifest = config.manifest || {
|
|
||||||
name: "unknown",
|
|
||||||
version: "error"
|
|
||||||
};
|
|
||||||
if (!this._manifest.configuration) {
|
|
||||||
this._manifest.configuration = {};
|
|
||||||
}
|
|
||||||
if (!this._manifest.dependencies) {
|
|
||||||
this._manifest.dependencies = {};
|
|
||||||
}
|
|
||||||
this._name = this._manifest.name;
|
|
||||||
this._version = this._manifest.version;
|
|
||||||
this._root = computeRootAppPath(config.mount, config.id === "__internal");
|
|
||||||
this._path = config.path;
|
|
||||||
this._options = config.options;
|
|
||||||
this._mount = config.mount;
|
|
||||||
this._isSystem = config.isSystem || false;
|
|
||||||
this._isDevelopment = config.isDevelopment || false;
|
|
||||||
this._exports = {};
|
|
||||||
this._collectionPrefix = this._mount.substr(1).replace(/-/g, "_").replace(/\//g, "_") + "_";
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
this._options.dependencies = {};
|
|
||||||
this._dependencies = {};
|
|
||||||
this.updateDeps(deps);
|
|
||||||
|
|
||||||
this._context = new AppContext(this);
|
|
||||||
this._context.appPackage = module.createAppPackage(this);
|
|
||||||
this._context.appModule = this._context.appPackage.createAppModule(this);
|
|
||||||
|
|
||||||
if (! this._manifest.hasOwnProperty("defaultDocument")) {
|
|
||||||
this._manifest.defaultDocument = "index.html";
|
|
||||||
}
|
|
||||||
if (this._manifest.hasOwnProperty("thumbnail")) {
|
|
||||||
var thumbfile = fs.join(this._root, this._path, this._manifest.thumbnail);
|
|
||||||
try {
|
|
||||||
this._thumbnail = fs.read64(thumbfile);
|
|
||||||
} catch (err) {
|
|
||||||
console.warnLines(
|
|
||||||
"Cannot read thumbnail '%s' : %s", thumbfile, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- private methods
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief prints a package
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype._PRINT = function (context) {
|
|
||||||
context.output += '[app "' + this._name + '" (' + this._version + ')]';
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- public methods
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief creates a Json representation of itself to be persisted
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.toJSON = function () {
|
|
||||||
var json = {
|
|
||||||
manifest: this._manifest,
|
|
||||||
name: this._name,
|
|
||||||
version: this._version,
|
|
||||||
path: this._path,
|
|
||||||
options: this._options,
|
|
||||||
mount: this._mount,
|
|
||||||
root: this._root,
|
|
||||||
isSystem: this._isSystem,
|
|
||||||
isDevelopment: this._isDevelopment
|
|
||||||
};
|
|
||||||
if (this.hasOwnProperty("_error")) {
|
|
||||||
json.error = this._error;
|
|
||||||
}
|
|
||||||
if (this._manifest.hasOwnProperty("author")) {
|
|
||||||
json.author = this._manifest.author;
|
|
||||||
}
|
|
||||||
if (this._manifest.hasOwnProperty("description")) {
|
|
||||||
json.description = this._manifest.description;
|
|
||||||
}
|
|
||||||
if (this.hasOwnProperty("_thumbnail")) {
|
|
||||||
json.thumbnail = this._thumbnail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return json;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief creates a reduced Json representation of itself for output
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.simpleJSON = function () {
|
|
||||||
var json = {
|
|
||||||
name: this._name,
|
|
||||||
version: this._version,
|
|
||||||
mount: this._mount
|
|
||||||
};
|
|
||||||
return json;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief toggles development mode
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.development = function(activate) {
|
|
||||||
this._isDevelopment = activate;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief set app dependencies
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.updateDeps = function (deps) {
|
|
||||||
var expected = this._manifest.dependencies;
|
|
||||||
var invalid = [];
|
|
||||||
|
|
||||||
_.each(deps, function (mount, name) {
|
|
||||||
if (!expected[name]) {
|
|
||||||
invalid.push("Unexpected dependency " + name);
|
|
||||||
}
|
|
||||||
this._options.dependencies[name] = mount || undefined;
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
_.each(this._options.dependencies, function (mount, name) {
|
|
||||||
if (mount) {
|
|
||||||
Object.defineProperty(this._dependencies, name, {
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
get: function () {
|
|
||||||
return require("org/arangodb/foxx").requireApp(mount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
return invalid;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief set app configuration
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.configure = function(config) {
|
|
||||||
var expected = this._manifest.configuration;
|
|
||||||
var invalid = [];
|
|
||||||
this._options.configuration = this._options.configuration || {};
|
|
||||||
|
|
||||||
_.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];
|
|
||||||
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 + '"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!error) {
|
|
||||||
if (schema.isJoi) {
|
|
||||||
schema = schema.optional().allow(null);
|
|
||||||
if (expected[name].default !== undefined) {
|
|
||||||
schema = schema.default(expected[name].default);
|
|
||||||
}
|
|
||||||
result = schema.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] = rawValue;
|
|
||||||
this._configuration[name] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
return invalid;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief get app configuration
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.getConfiguration = function (simple) {
|
|
||||||
var config = {};
|
|
||||||
var definitions = this._manifest.configuration;
|
|
||||||
var options = this._options.configuration;
|
|
||||||
_.each(definitions, function (dfn, name) {
|
|
||||||
var value = options[name] === undefined ? dfn.default : options[name];
|
|
||||||
config[name] = simple ? value : _.extend(_.clone(dfn), {
|
|
||||||
title: utils.getReadableName(name),
|
|
||||||
current: value
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief get app dependencies
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.getDependencies = function(simple) {
|
|
||||||
var deps = {};
|
|
||||||
var definitions = this._manifest.dependencies;
|
|
||||||
var options = this._options.dependencies;
|
|
||||||
_.each(definitions, function (dfn, name) {
|
|
||||||
deps[name] = simple ? options[name] : {
|
|
||||||
definition: dfn,
|
|
||||||
title: utils.getReadableName(name),
|
|
||||||
current: options[name]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return deps;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief App needs to be configured
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.needsConfiguration = function() {
|
|
||||||
var config = this.getConfiguration();
|
|
||||||
var deps = this.getDependencies();
|
|
||||||
return _.any(config, function (cfg) {
|
|
||||||
return cfg.current === undefined && cfg.required !== false;
|
|
||||||
}) || _.any(deps, function (dep) {
|
|
||||||
return dep.current === undefined && dep.definition.required !== false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief loadAppScript
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ArangoApp.prototype.loadAppScript = function (filename, options) {
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
var appContext = _.extend({}, options.appContext, this._context);
|
|
||||||
var full = fs.join(this._root, this._path, filename);
|
|
||||||
|
|
||||||
if (!fs.exists(full)) {
|
|
||||||
throwFileNotFound(full);
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileContent = fs.read(full);
|
|
||||||
|
|
||||||
if (options.transform) {
|
|
||||||
fileContent = options.transform(fileContent);
|
|
||||||
} else if (/\.coffee$/.test(filename)) {
|
|
||||||
var cs = require("coffee-script");
|
|
||||||
fileContent = cs.compile(fileContent, {bare: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
var context = {};
|
|
||||||
|
|
||||||
if (options.context) {
|
|
||||||
Object.keys(options.context).forEach(function (key) {
|
|
||||||
context[key] = options.context[key];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var localModule = appContext.appPackage.createAppModule(this, filename);
|
|
||||||
|
|
||||||
context.__filename = full;
|
|
||||||
context.__dirname = module.normalizeModuleName(full + "/..");
|
|
||||||
context.console = require("org/arangodb/foxx/console")(this._mount);
|
|
||||||
context.applicationContext = appContext;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return localModule.run(fileContent, context);
|
|
||||||
} catch(e) {
|
|
||||||
if (e instanceof ArangoError) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
var err = new ArangoError({
|
|
||||||
errorNum: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.code,
|
|
||||||
errorMessage: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.message
|
|
||||||
+ "\nFile: " + filename
|
|
||||||
});
|
|
||||||
err.stack = e.stack;
|
|
||||||
err.cause = e;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.ArangoApp = ArangoApp;
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- END-OF-FILE
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Local Variables:
|
|
||||||
// mode: outline-minor
|
|
||||||
// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
|
|
||||||
// End:
|
|
|
@ -43,7 +43,7 @@ const semver = require('semver');
|
||||||
const utils = require('org/arangodb/foxx/manager-utils');
|
const utils = require('org/arangodb/foxx/manager-utils');
|
||||||
const store = require('org/arangodb/foxx/store');
|
const store = require('org/arangodb/foxx/store');
|
||||||
const deprecated = require('org/arangodb/deprecated');
|
const deprecated = require('org/arangodb/deprecated');
|
||||||
const ArangoApp = require('org/arangodb/foxx/arangoApp').ArangoApp;
|
const FoxxService = require('org/arangodb/foxx/service');
|
||||||
const TemplateEngine = require('org/arangodb/foxx/templateEngine').Engine;
|
const TemplateEngine = require('org/arangodb/foxx/templateEngine').Engine;
|
||||||
const routeApp = require('org/arangodb/foxx/routing').routeApp;
|
const routeApp = require('org/arangodb/foxx/routing').routeApp;
|
||||||
const exportApp = require('org/arangodb/foxx/routing').exportApp;
|
const exportApp = require('org/arangodb/foxx/routing').exportApp;
|
||||||
|
@ -61,7 +61,6 @@ const executeGlobalContextFunction = require('internal').executeGlobalContextFun
|
||||||
const actions = require('org/arangodb/actions');
|
const actions = require('org/arangodb/actions');
|
||||||
const plainServerVersion = require("org/arangodb").plainServerVersion;
|
const plainServerVersion = require("org/arangodb").plainServerVersion;
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const Module = require('module');
|
|
||||||
|
|
||||||
const throwDownloadError = arangodb.throwDownloadError;
|
const throwDownloadError = arangodb.throwDownloadError;
|
||||||
const throwFileNotFound = arangodb.throwFileNotFound;
|
const throwFileNotFound = arangodb.throwFileNotFound;
|
||||||
|
@ -263,8 +262,8 @@ function refillCaches(dbname) {
|
||||||
|
|
||||||
while (cursor.hasNext()) {
|
while (cursor.hasNext()) {
|
||||||
var config = _.clone(cursor.next());
|
var config = _.clone(cursor.next());
|
||||||
var app = new ArangoApp(config);
|
var app = new FoxxService(config);
|
||||||
var mount = app._mount;
|
var mount = app.mount;
|
||||||
cache[mount] = app;
|
cache[mount] = app;
|
||||||
routes.push(mount);
|
routes.push(mount);
|
||||||
}
|
}
|
||||||
|
@ -449,9 +448,9 @@ function isSystemMount(mount) {
|
||||||
|
|
||||||
function computeRootAppPath(mount) {
|
function computeRootAppPath(mount) {
|
||||||
if (isSystemMount(mount)) {
|
if (isSystemMount(mount)) {
|
||||||
return Module._systemAppPath;
|
return FoxxService._systemAppPath;
|
||||||
}
|
}
|
||||||
return Module._appPath;
|
return FoxxService._appPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -490,12 +489,12 @@ function computeAppPath(mount) {
|
||||||
|
|
||||||
function executeAppScript(scriptName, app, argv) {
|
function executeAppScript(scriptName, app, argv) {
|
||||||
var readableName = utils.getReadableName(scriptName);
|
var readableName = utils.getReadableName(scriptName);
|
||||||
var scripts = app._manifest.scripts;
|
var scripts = app.manifest.scripts;
|
||||||
|
|
||||||
// Only run setup/teardown scripts if they exist
|
// Only run setup/teardown scripts if they exist
|
||||||
if (scripts[scriptName] || (scriptName !== 'setup' && scriptName !== 'teardown')) {
|
if (scripts[scriptName] || (scriptName !== 'setup' && scriptName !== 'teardown')) {
|
||||||
try {
|
try {
|
||||||
return app.loadAppScript(scripts[scriptName], {
|
return app.run(scripts[scriptName], {
|
||||||
appContext: {
|
appContext: {
|
||||||
argv: argv ? (Array.isArray(argv) ? argv : [argv]) : []
|
argv: argv ? (Array.isArray(argv) ? argv : [argv]) : []
|
||||||
}
|
}
|
||||||
|
@ -503,7 +502,7 @@ function executeAppScript(scriptName, app, argv) {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!(e.cause || e).statusCode) {
|
if (!(e.cause || e).statusCode) {
|
||||||
let details = String((e.cause || e).stack || e.cause || e);
|
let details = String((e.cause || e).stack || e.cause || e);
|
||||||
console.errorLines(`Running script "${readableName}" not possible for mount "${app._mount}":\n${details}`);
|
console.errorLines(`Running script "${readableName}" not possible for mount "${app.mount}":\n${details}`);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -557,7 +556,7 @@ function appConfig(mount, options, activateDevelopment) {
|
||||||
function createApp(mount, options, activateDevelopment) {
|
function createApp(mount, options, activateDevelopment) {
|
||||||
var dbname = arangodb.db._name();
|
var dbname = arangodb.db._name();
|
||||||
var config = appConfig(mount, options, activateDevelopment);
|
var config = appConfig(mount, options, activateDevelopment);
|
||||||
var app = new ArangoApp(config);
|
var app = new FoxxService(config);
|
||||||
appCache[dbname][mount] = app;
|
appCache[dbname][mount] = app;
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
@ -821,10 +820,10 @@ function readme(mount) {
|
||||||
let app = lookupApp(mount);
|
let app = lookupApp(mount);
|
||||||
let path, readmeText;
|
let path, readmeText;
|
||||||
|
|
||||||
path = fs.join(app._root, app._path, 'README.md');
|
path = fs.join(app.root, app.path, 'README.md');
|
||||||
readmeText = fs.exists(path) && fs.read(path);
|
readmeText = fs.exists(path) && fs.read(path);
|
||||||
if (!readmeText) {
|
if (!readmeText) {
|
||||||
path = fs.join(app._root, app._path, 'README');
|
path = fs.join(app.root, app.path, 'README');
|
||||||
readmeText = fs.exists(path) && fs.read(path);
|
readmeText = fs.exists(path) && fs.read(path);
|
||||||
}
|
}
|
||||||
return readmeText || null;
|
return readmeText || null;
|
||||||
|
@ -933,7 +932,7 @@ function rescanFoxx(mount) {
|
||||||
if (definition !== null) {
|
if (definition !== null) {
|
||||||
collection.remove(definition._key);
|
collection.remove(definition._key);
|
||||||
}
|
}
|
||||||
_scanFoxx(mount, old._options, old._isDevelopment);
|
_scanFoxx(mount, old.options, old.isDevelopment);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -978,7 +977,7 @@ function _validateApp(appInfo) {
|
||||||
var tempPath = fs.getTempFile('apps', false);
|
var tempPath = fs.getTempFile('apps', false);
|
||||||
try {
|
try {
|
||||||
_buildAppInPath(appInfo, tempPath, {});
|
_buildAppInPath(appInfo, tempPath, {});
|
||||||
var tmp = new ArangoApp(fakeAppConfig(tempPath));
|
var tmp = new FoxxService(fakeAppConfig(tempPath));
|
||||||
if (!tmp.needsConfiguration()) {
|
if (!tmp.needsConfiguration()) {
|
||||||
routeApp(tmp, true);
|
routeApp(tmp, true);
|
||||||
exportApp(tmp);
|
exportApp(tmp);
|
||||||
|
@ -1376,7 +1375,7 @@ function upgrade(appInfo, mount, options) {
|
||||||
options.configuration[key] = oldConf[key];
|
options.configuration[key] = oldConf[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var oldDeps = oldApp._options.dependencies || {};
|
var oldDeps = oldApp.options.dependencies || {};
|
||||||
options.dependencies = options.dependencies || {};
|
options.dependencies = options.dependencies || {};
|
||||||
Object.keys(oldDeps).forEach(function (key) {
|
Object.keys(oldDeps).forEach(function (key) {
|
||||||
if (!options.dependencies.hasOwnProperty(key)) {
|
if (!options.dependencies.hasOwnProperty(key)) {
|
||||||
|
@ -1464,7 +1463,7 @@ function configure(mount, options) {
|
||||||
[ mount ] );
|
[ mount ] );
|
||||||
utils.validateMount(mount, true);
|
utils.validateMount(mount, true);
|
||||||
var app = lookupApp(mount);
|
var app = lookupApp(mount);
|
||||||
var invalid = app.configure(options.configuration || {});
|
var invalid = app.applyConfiguration(options.configuration || {});
|
||||||
if (invalid.length > 0) {
|
if (invalid.length > 0) {
|
||||||
// TODO Error handling
|
// TODO Error handling
|
||||||
console.log(invalid);
|
console.log(invalid);
|
||||||
|
@ -1485,7 +1484,7 @@ function updateDeps(mount, options) {
|
||||||
[ mount ] );
|
[ mount ] );
|
||||||
utils.validateMount(mount, true);
|
utils.validateMount(mount, true);
|
||||||
var app = lookupApp(mount);
|
var app = lookupApp(mount);
|
||||||
var invalid = app.updateDeps(options.dependencies || {});
|
var invalid = app.applyDependencies(options.dependencies || {});
|
||||||
if (invalid.length > 0) {
|
if (invalid.length > 0) {
|
||||||
// TODO Error handling
|
// TODO Error handling
|
||||||
console.log(invalid);
|
console.log(invalid);
|
||||||
|
@ -1547,7 +1546,7 @@ function syncWithFolder(options) {
|
||||||
options.replace = true;
|
options.replace = true;
|
||||||
appCache = appCache || {};
|
appCache = appCache || {};
|
||||||
appCache[dbname] = {};
|
appCache[dbname] = {};
|
||||||
var folders = fs.listTree(Module._appPath).filter(filterAppRoots);
|
var folders = fs.listTree(FoxxService._appPath).filter(filterAppRoots);
|
||||||
var collection = utils.getStorage();
|
var collection = utils.getStorage();
|
||||||
return folders.map(function (folder) {
|
return folders.map(function (folder) {
|
||||||
var mount;
|
var mount;
|
||||||
|
|
|
@ -86,7 +86,7 @@ exports.run = function runMochaTests(app, reporterName) {
|
||||||
files.forEach(function (file) {
|
files.forEach(function (file) {
|
||||||
var context = {};
|
var context = {};
|
||||||
suite.emit('pre-require', context, file, mocha);
|
suite.emit('pre-require', context, file, mocha);
|
||||||
suite.emit('require', app.loadAppScript(file, {context: context}), file, mocha);
|
suite.emit('require', app.run(file, {context: context}), file, mocha);
|
||||||
suite.emit('post-require', global, file, mocha);
|
suite.emit('post-require', global, file, mocha);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -111,11 +111,11 @@ function isNotPattern(pattern) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function findTestFiles(app) {
|
function findTestFiles(app) {
|
||||||
var patterns = app._manifest.tests || [];
|
var patterns = app.manifest.tests || [];
|
||||||
if (patterns.every(isNotPattern)) {
|
if (patterns.every(isNotPattern)) {
|
||||||
return patterns.slice();
|
return patterns.slice();
|
||||||
}
|
}
|
||||||
var basePath = fs.join(app._root, app._path);
|
var basePath = fs.join(app.root, app.path);
|
||||||
var paths = fs.listTree(basePath);
|
var paths = fs.listTree(basePath);
|
||||||
var matchers = patterns.map(function (pattern) {
|
var matchers = patterns.map(function (pattern) {
|
||||||
if (pattern.charAt(0) === '/') {
|
if (pattern.charAt(0) === '/') {
|
||||||
|
|
|
@ -193,7 +193,7 @@ var buildAssetRoute = function (app, path, basePath, asset) {
|
||||||
var installAssets = function (app, routes) {
|
var installAssets = function (app, routes) {
|
||||||
var path;
|
var path;
|
||||||
|
|
||||||
var desc = app._manifest;
|
var desc = app.manifest;
|
||||||
|
|
||||||
if (! desc) {
|
if (! desc) {
|
||||||
throw new Error("Invalid application manifest");
|
throw new Error("Invalid application manifest");
|
||||||
|
@ -206,7 +206,7 @@ var installAssets = function (app, routes) {
|
||||||
for (path in desc.assets) {
|
for (path in desc.assets) {
|
||||||
if (desc.assets.hasOwnProperty(path)) {
|
if (desc.assets.hasOwnProperty(path)) {
|
||||||
var asset = desc.assets[path];
|
var asset = desc.assets[path];
|
||||||
var basePath = fs.join(app._root, app._path);
|
var basePath = fs.join(app.root, app.path);
|
||||||
|
|
||||||
if (asset.hasOwnProperty('basePath')) {
|
if (asset.hasOwnProperty('basePath')) {
|
||||||
basePath = asset.basePath;
|
basePath = asset.basePath;
|
||||||
|
@ -247,8 +247,8 @@ var installAssets = function (app, routes) {
|
||||||
action: {
|
action: {
|
||||||
"do": "org/arangodb/actions/pathHandler",
|
"do": "org/arangodb/actions/pathHandler",
|
||||||
"options": {
|
"options": {
|
||||||
root: app._root,
|
root: app.root,
|
||||||
path: fs.join(app._path, directory),
|
path: fs.join(app.path, directory),
|
||||||
gzip: gzip
|
gzip: gzip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,26 +444,26 @@ var exportApp = function (app) {
|
||||||
errorMessage: errors.ERROR_APP_NEEDS_CONFIGURATION.message
|
errorMessage: errors.ERROR_APP_NEEDS_CONFIGURATION.message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!app._isDevelopment && isExported(app._mount)) {
|
if (!app.isDevelopment && isExported(app.mount)) {
|
||||||
return app._exports;
|
return app.main.exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
app._exports = {};
|
app.main.exports = {};
|
||||||
|
|
||||||
// mount all exports
|
// mount all exports
|
||||||
if (app._manifest.hasOwnProperty("exports")) {
|
if (app.manifest.hasOwnProperty("exports")) {
|
||||||
var appExports = app._manifest.exports;
|
var appExports = app.manifest.exports;
|
||||||
|
|
||||||
if (typeof appExports === "string") {
|
if (typeof appExports === "string") {
|
||||||
app._exports = app.loadAppScript(appExports);
|
app.main.exports = app.run(appExports);
|
||||||
} else if (appExports) {
|
} else if (appExports) {
|
||||||
Object.keys(appExports).forEach(function (key) {
|
Object.keys(appExports).forEach(function (key) {
|
||||||
app._exports[key] = app.loadAppScript(appExports[key]);
|
app.main.exports[key] = app.run(appExports[key]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIsExported(app._mount);
|
setIsExported(app.mount);
|
||||||
return app._exports;
|
return app.exports;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -512,7 +512,7 @@ var routeNeedsConfigurationApp = function(app) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
urlPrefix: "",
|
urlPrefix: "",
|
||||||
name: 'foxx("' + app._mount + '")',
|
name: 'foxx("' + app.mount + '")',
|
||||||
routes: [{
|
routes: [{
|
||||||
"internal": true,
|
"internal": true,
|
||||||
"url" : {
|
"url" : {
|
||||||
|
@ -523,7 +523,7 @@ var routeNeedsConfigurationApp = function(app) {
|
||||||
"callback": function(req, res) {
|
"callback": function(req, res) {
|
||||||
res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE;
|
res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE;
|
||||||
res.contentType = "text/html; charset=utf-8";
|
res.contentType = "text/html; charset=utf-8";
|
||||||
if (app._isDevelopment) {
|
if (app.isDevelopment) {
|
||||||
res.body = "<html><head><title>Service Unavailable</title></head><body><p>" +
|
res.body = "<html><head><title>Service Unavailable</title></head><body><p>" +
|
||||||
"This service is not configured.</p>";
|
"This service is not configured.</p>";
|
||||||
res.body += "<h3>Configuration Information</h3>";
|
res.body += "<h3>Configuration Information</h3>";
|
||||||
|
@ -558,7 +558,7 @@ var routeBrokenApp = function(app, err) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
urlPrefix: "",
|
urlPrefix: "",
|
||||||
name: 'foxx("' + app._mount + '")',
|
name: 'foxx("' + app.mount + '")',
|
||||||
routes: [{
|
routes: [{
|
||||||
"internal": true,
|
"internal": true,
|
||||||
"url" : {
|
"url" : {
|
||||||
|
@ -569,7 +569,7 @@ var routeBrokenApp = function(app, err) {
|
||||||
"callback": function(req, res) {
|
"callback": function(req, res) {
|
||||||
res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE;
|
res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE;
|
||||||
res.contentType = "text/html; charset=utf-8";
|
res.contentType = "text/html; charset=utf-8";
|
||||||
if (app._isDevelopment) {
|
if (app.isDevelopment) {
|
||||||
var errToPrint = err.cause ? err.cause : err;
|
var errToPrint = err.cause ? err.cause : err;
|
||||||
res.body = "<html><head><title>" + escapeHTML(String(errToPrint)) +
|
res.body = "<html><head><title>" + escapeHTML(String(errToPrint)) +
|
||||||
"</title></head><body><pre>" + escapeHTML(String(errToPrint.stack)) + "</pre></body></html>";
|
"</title></head><body><pre>" + escapeHTML(String(errToPrint.stack)) + "</pre></body></html>";
|
||||||
|
@ -602,12 +602,12 @@ var routeApp = function (app, isInstallProcess) {
|
||||||
return routeNeedsConfigurationApp(app);
|
return routeNeedsConfigurationApp(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultDocument = app._manifest.defaultDocument;
|
var defaultDocument = app.manifest.defaultDocument;
|
||||||
|
|
||||||
// setup the routes
|
// setup the routes
|
||||||
var routes = {
|
var routes = {
|
||||||
urlPrefix: "",
|
urlPrefix: "",
|
||||||
name: 'foxx("' + app._mount + '")',
|
name: 'foxx("' + app.mount + '")',
|
||||||
routes: [],
|
routes: [],
|
||||||
middleware: [],
|
middleware: [],
|
||||||
context: {},
|
context: {},
|
||||||
|
@ -617,18 +617,18 @@ var routeApp = function (app, isInstallProcess) {
|
||||||
|
|
||||||
appContext: {
|
appContext: {
|
||||||
app: app,
|
app: app,
|
||||||
module: app._context.appModule
|
module: app.main
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((app._mount + defaultDocument) !== app._mount) {
|
if ((app.mount + defaultDocument) !== app.mount) {
|
||||||
// only add redirection if src and target are not the same
|
// only add redirection if src and target are not the same
|
||||||
routes.routes.push({
|
routes.routes.push({
|
||||||
"url" : { match: "/" },
|
"url" : { match: "/" },
|
||||||
"action" : {
|
"action" : {
|
||||||
"do" : "org/arangodb/actions/redirectRequest",
|
"do" : "org/arangodb/actions/redirectRequest",
|
||||||
"options" : {
|
"options" : {
|
||||||
"permanently" : !app._isDevelopment,
|
"permanently" : !app.isDevelopment,
|
||||||
"destination" : defaultDocument,
|
"destination" : defaultDocument,
|
||||||
"relative" : true
|
"relative" : true
|
||||||
}
|
}
|
||||||
|
@ -637,7 +637,7 @@ var routeApp = function (app, isInstallProcess) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mount all controllers
|
// mount all controllers
|
||||||
var controllers = app._manifest.controllers;
|
var controllers = app.manifest.controllers;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (controllers) {
|
if (controllers) {
|
||||||
|
@ -664,19 +664,16 @@ var routeApp = function (app, isInstallProcess) {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
var mountController = function (app, routes, mountPoint, file) {
|
var mountController = function (service, routes, mount, filename) {
|
||||||
validateRoute(mountPoint);
|
validateRoute(mount);
|
||||||
|
|
||||||
// set up a context for the application start function
|
// set up a context for the application start function
|
||||||
var tmpContext = {
|
var tmpContext = {
|
||||||
prefix: arangodb.normalizeURL("/" + mountPoint), // app mount
|
prefix: arangodb.normalizeURL(`/${mount}`), // app mount
|
||||||
foxxes: []
|
foxxes: []
|
||||||
};
|
};
|
||||||
|
|
||||||
app.loadAppScript(file, {
|
service.run(filename, {appContext: tmpContext});
|
||||||
transform: transformScript(file),
|
|
||||||
appContext: tmpContext
|
|
||||||
});
|
|
||||||
|
|
||||||
// .............................................................................
|
// .............................................................................
|
||||||
// routingInfo
|
// routingInfo
|
||||||
|
@ -689,11 +686,11 @@ var mountController = function (app, routes, mountPoint, file) {
|
||||||
|
|
||||||
_.extend(routes.models, foxx.models);
|
_.extend(routes.models, foxx.models);
|
||||||
|
|
||||||
if (ri.hasOwnProperty("middleware")) {
|
if (ri.hasOwnProperty('middleware')) {
|
||||||
createMiddlewareMatchers(ri.middleware, routes, mountPoint, ri.urlPrefix);
|
createMiddlewareMatchers(ri.middleware, routes, mount, ri.urlPrefix);
|
||||||
}
|
}
|
||||||
if (ri.hasOwnProperty("routes")) {
|
if (ri.hasOwnProperty('routes')) {
|
||||||
transformRoutes(ri.routes, routes, mountPoint, ri.urlPrefix, app._isDevelopment);
|
transformRoutes(ri.routes, routes, mount, ri.urlPrefix, service._isDevelopment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
|
const ArangoError = require('org/arangodb').ArangoError;
|
||||||
|
const errors = require('org/arangodb').errors;
|
||||||
const internal = require('internal');
|
const internal = require('internal');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const Module = require('module');
|
const Module = require('module');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const parameterTypes = require('org/arangodb/foxx/manager-utils').parameterTypes;
|
const parameterTypes = require('org/arangodb/foxx/manager-utils').parameterTypes;
|
||||||
|
const getReadableName = require('org/arangodb/foxx/manager-utils').getReadableName;
|
||||||
const getExports = require('org/arangodb/foxx').getExports;
|
const getExports = require('org/arangodb/foxx').getExports;
|
||||||
|
|
||||||
const APP_PATH = internal.appPath ? path.resolve(internal.appPath) : undefined;
|
const APP_PATH = internal.appPath ? path.resolve(internal.appPath) : undefined;
|
||||||
|
@ -13,8 +16,100 @@ const STARTUP_PATH = internal.startupPath ? path.resolve(internal.startupPath) :
|
||||||
const DEV_APP_PATH = internal.devAppPath ? path.resolve(internal.devAppPath) : undefined;
|
const DEV_APP_PATH = internal.devAppPath ? path.resolve(internal.devAppPath) : undefined;
|
||||||
|
|
||||||
class AppContext {
|
class AppContext {
|
||||||
|
constructor(service) {
|
||||||
|
this.basePath = path.resolve(service.root, service.path);
|
||||||
|
this.comments = [];
|
||||||
|
Object.defineProperty(this, '_service', {
|
||||||
|
get() {
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foxxFilename(filename) {
|
||||||
|
return fs.safeJoin(this._prefix, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
path(name) {
|
||||||
|
return path.join(this._prefix, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionName(name) {
|
||||||
|
let fqn = (
|
||||||
|
this.collectionPrefix
|
||||||
|
+ name.replace(/[^a-z0-9]/ig, '_').replace(/(^_+|_+$)/g, '').substr(0, 64)
|
||||||
|
);
|
||||||
|
if (!fqn.length) {
|
||||||
|
throw new Error(`Cannot derive collection name from "${name}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collection(name) {
|
||||||
|
return internal.db._collection(this.collectionName(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
get _prefix() {
|
||||||
|
return this.basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseUrl() {
|
||||||
|
return `/_db/${encodeURIComponent(internal.db._name())}/${this._service.mount.slice(1)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get collectionPrefix() {
|
||||||
|
return this._service.collectionPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
get mount() {
|
||||||
|
return this._service.mount;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this._service.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get version() {
|
||||||
|
return this._service.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
get manifest() {
|
||||||
|
return this._service.manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isDevelopment() {
|
||||||
|
return this._service.isDevelopment;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isProduction() {
|
||||||
|
return !this.isDevelopment;
|
||||||
|
}
|
||||||
|
|
||||||
|
get options() {
|
||||||
|
return this._service.options;
|
||||||
|
}
|
||||||
|
|
||||||
|
get configuration() {
|
||||||
|
return this._service.configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
get dependencies() {
|
||||||
|
return this._service.dependencies;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object.defineProperties(AppContext.prototype, {
|
||||||
|
comment: {
|
||||||
|
value: function (str) {
|
||||||
|
this.comments.push(str);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearComments: {
|
||||||
|
value: function () {
|
||||||
|
this.comments.splice(0, this.comments.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function createConfiguration(definitions) {
|
function createConfiguration(definitions) {
|
||||||
const config = {};
|
const config = {};
|
||||||
Object.keys(definitions).forEach(function (name) {
|
Object.keys(definitions).forEach(function (name) {
|
||||||
|
@ -33,7 +128,7 @@ function createDependencies(definitions, options) {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
get() {
|
get() {
|
||||||
const mount = options.dependencies[name];
|
const mount = options[name];
|
||||||
return mount ? getExports(mount) : undefined;
|
return mount ? getExports(mount) : undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -96,6 +191,7 @@ class FoxxService {
|
||||||
this.main = new Module(`foxx:${data.mount}`);
|
this.main = new Module(`foxx:${data.mount}`);
|
||||||
this.main.filename = path.resolve(this.root, this.path, lib, '.foxx');
|
this.main.filename = path.resolve(this.root, this.path, lib, '.foxx');
|
||||||
this.main.context.applicationContext = new AppContext(this);
|
this.main.context.applicationContext = new AppContext(this);
|
||||||
|
this.main.context.console = require('org/arangodb/foxx/console')(this.mount);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyConfiguration(config) {
|
applyConfiguration(config) {
|
||||||
|
@ -161,6 +257,121 @@ class FoxxService {
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_PRINT(context) {
|
||||||
|
context.output += `[FoxxService "${this.name}" (${this.version}) on ${this.mount}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
const result = {
|
||||||
|
name: this.name,
|
||||||
|
version: this.version,
|
||||||
|
manifest: this.manifest,
|
||||||
|
path: this.path,
|
||||||
|
options: this.options,
|
||||||
|
mount: this.mount,
|
||||||
|
isSystem: this.isSystem,
|
||||||
|
isDevelopment: this.isDevelopment
|
||||||
|
};
|
||||||
|
if (this.error) {
|
||||||
|
result.error = this.error;
|
||||||
|
}
|
||||||
|
if (this.manifest.author) {
|
||||||
|
result.author = this.manifest.author;
|
||||||
|
}
|
||||||
|
if (this.manifest.description) {
|
||||||
|
result.description = this.manifest.description;
|
||||||
|
}
|
||||||
|
if (this.thumbnail) {
|
||||||
|
result.thumbnail = this.thumbnail;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleJSON() {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
version: this.version,
|
||||||
|
mount: this.mount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
development(isDevelopment) {
|
||||||
|
this.isDevelopment = isDevelopment;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration(simple) {
|
||||||
|
var config = {};
|
||||||
|
var definitions = this.manifest.configuration;
|
||||||
|
var options = this.options.configuration;
|
||||||
|
_.each(definitions, function (dfn, name) {
|
||||||
|
var value = options[name] === undefined ? dfn.default : options[name];
|
||||||
|
config[name] = simple ? value : _.extend(_.clone(dfn), {
|
||||||
|
title: getReadableName(name),
|
||||||
|
current: value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDependencies(simple) {
|
||||||
|
var deps = {};
|
||||||
|
var definitions = this.manifest.dependencies;
|
||||||
|
var options = this.options.dependencies;
|
||||||
|
_.each(definitions, function (dfn, name) {
|
||||||
|
deps[name] = simple ? options[name] : {
|
||||||
|
definition: dfn,
|
||||||
|
title: getReadableName(name),
|
||||||
|
current: options[name]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return deps;
|
||||||
|
}
|
||||||
|
|
||||||
|
needsConfiguration() {
|
||||||
|
var config = this.getConfiguration();
|
||||||
|
var deps = this.getDependencies();
|
||||||
|
return _.any(config, function (cfg) {
|
||||||
|
return cfg.current === undefined && cfg.required !== false;
|
||||||
|
}) || _.any(deps, function (dep) {
|
||||||
|
return dep.current === undefined && dep.definition.required !== false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
run(filename, options) {
|
||||||
|
options = options || {};
|
||||||
|
filename = path.resolve(this.main.context.__dirname, filename);
|
||||||
|
|
||||||
|
var module = new Module(filename, this.main);
|
||||||
|
module.context.applicationContext = _.extend(
|
||||||
|
new AppContext(this.main.context.applicationContext._service),
|
||||||
|
this.main.context.applicationContext,
|
||||||
|
options.appContext
|
||||||
|
);
|
||||||
|
|
||||||
|
if (options.context) {
|
||||||
|
Object.keys(options.context).forEach(function (key) {
|
||||||
|
module.context[key] = options.context[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
module.load(filename);
|
||||||
|
return module.exports;
|
||||||
|
} catch(e) {
|
||||||
|
if (e instanceof ArangoError) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
var err = new ArangoError({
|
||||||
|
errorNum: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.code,
|
||||||
|
errorMessage: errors.ERROR_FAILED_TO_EXECUTE_SCRIPT.message
|
||||||
|
+ '\nFile: ' + filename
|
||||||
|
});
|
||||||
|
err.stack = e.stack;
|
||||||
|
err.cause = e;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get exports() {
|
get exports() {
|
||||||
return this.main.exports;
|
return this.main.exports;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +399,7 @@ class FoxxService {
|
||||||
if (this.isSystem) {
|
if (this.isSystem) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return this.mount.substr(1).replace(/-/g, '_').replace(/\//g, '_') + '_';
|
return this.mount.substr(1).replace(/[-.:/]/g, '_') + '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get _startupPath() {
|
static get _startupPath() {
|
||||||
|
@ -203,7 +414,7 @@ class FoxxService {
|
||||||
|
|
||||||
static get _systemAppPath() {
|
static get _systemAppPath() {
|
||||||
return APP_PATH ? (
|
return APP_PATH ? (
|
||||||
path.join(this._appPath, 'apps', 'system')
|
path.join(STARTUP_PATH, 'apps', 'system')
|
||||||
) : undefined;
|
) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,7 @@ class Sessions {
|
||||||
if (typeof this.configuration.sessionStorage !== 'string') {
|
if (typeof this.configuration.sessionStorage !== 'string') {
|
||||||
return this.configuration.sessionStorage;
|
return this.configuration.sessionStorage;
|
||||||
}
|
}
|
||||||
return Foxx.requireApp(this.configuration.sessionStorage).sessionStorage;
|
return Foxx.getExports(this.configuration.sessionStorage).sessionStorage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
var internal = require('internal');
|
||||||
var ArangoError = require('org/arangodb').ArangoError;
|
var ArangoError = require('org/arangodb').ArangoError;
|
||||||
var errors = require('org/arangodb').errors;
|
var errors = require('org/arangodb').errors;
|
||||||
var resultNotFound = require('org/arangodb/actions').resultNotFound;
|
var resultNotFound = require('org/arangodb/actions').resultNotFound;
|
||||||
|
@ -96,7 +97,7 @@ function swaggerPath(path, basePath) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
if (!basePath) {
|
if (!basePath) {
|
||||||
basePath = fs.join(module.startupPath(), 'server', 'assets', 'swagger');
|
basePath = fs.join(internal.startupPath, 'server', 'assets', 'swagger');
|
||||||
}
|
}
|
||||||
return fs.safeJoin(basePath, path);
|
return fs.safeJoin(basePath, path);
|
||||||
}
|
}
|
||||||
|
@ -117,12 +118,12 @@ function swaggerJson(req, res, opts) {
|
||||||
res.json({
|
res.json({
|
||||||
swagger: '2.0',
|
swagger: '2.0',
|
||||||
info: {
|
info: {
|
||||||
description: app && app._manifest.description,
|
description: app && app.manifest.description,
|
||||||
version: app && app._manifest.version,
|
version: app && app.manifest.version,
|
||||||
title: app && app._manifest.name,
|
title: app && app.manifest.name,
|
||||||
license: app && app._manifest.license && {name: app._manifest.license}
|
license: app && app.manifest.license && {name: app.manifest.license}
|
||||||
},
|
},
|
||||||
basePath: '/_db/' + encodeURIComponent(req.database) + (app ? app._mount : opts.appPath),
|
basePath: '/_db/' + encodeURIComponent(req.database) + (app ? app.mount : opts.appPath),
|
||||||
schemes: [req.protocol],
|
schemes: [req.protocol],
|
||||||
paths: swagger.paths,
|
paths: swagger.paths,
|
||||||
// securityDefinitions: {},
|
// securityDefinitions: {},
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
var db = require("org/arangodb").db;
|
var db = require("org/arangodb").db;
|
||||||
var internal = require("internal");
|
var internal = require("internal");
|
||||||
var Module = require('module');
|
var FoxxService = require('org/arangodb/foxx/service');
|
||||||
var jsunity = require("jsunity");
|
var jsunity = require("jsunity");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ function runSetup () {
|
||||||
'use strict';
|
'use strict';
|
||||||
internal.debugClearFailAt();
|
internal.debugClearFailAt();
|
||||||
|
|
||||||
var appPath = fs.join(Module._appPath, "..");
|
var appPath = fs.join(FoxxService._appPath, "..");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db._dropDatabase("UnitTestsRecovery1");
|
db._dropDatabase("UnitTestsRecovery1");
|
||||||
|
@ -84,7 +84,7 @@ function recoverySuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testFoxxDirectories : function () {
|
testFoxxDirectories : function () {
|
||||||
var appPath = fs.join(Module._appPath, "..");
|
var appPath = fs.join(FoxxService._appPath, "..");
|
||||||
|
|
||||||
assertTrue(fs.isDirectory(fs.join(appPath, "UnitTestsRecovery1")));
|
assertTrue(fs.isDirectory(fs.join(appPath, "UnitTestsRecovery1")));
|
||||||
assertTrue(fs.isFile(fs.join(appPath, "UnitTestsRecovery1", "foo.json")));
|
assertTrue(fs.isFile(fs.join(appPath, "UnitTestsRecovery1", "foo.json")));
|
||||||
|
|
Loading…
Reference in New Issue