diff --git a/Documentation/Books/Users/ConfigureArango/Endpoint.mdpp b/Documentation/Books/Users/ConfigureArango/Endpoint.mdpp index eb39b6e183..e720637b1a 100644 --- a/Documentation/Books/Users/ConfigureArango/Endpoint.mdpp +++ b/Documentation/Books/Users/ConfigureArango/Endpoint.mdpp @@ -5,15 +5,35 @@ The ArangoDB server can listen for incoming requests on multiple *endpoints*. The endpoints are normally specified either in ArangoDB's configuration file or on the command-line, using the ["--server.endpoint"](../ConfigureArango/Arangod.md) option. The default endpoint for ArangoDB is *tcp://127.0.0.1:8529* or *tcp://localhost:8529*. +ArangoDB can also do a so called *broadcast bind* using *tcp://0.0.0.0:8529*. This way +it will be reachable on all interfaces of the host. This may be useful +on development systems that frequently change their network setup like laptops. The number of endpoints can also be changed at runtime using the API described below. Each endpoint can optionally be restricted to a specific list of databases -only, thus allowing the usage of different port numbers for different databases. +only, thus allowing the usage of different port numbers for different databases. This may be useful in multi-tenant setups. A multi-endpoint setup may also be useful to turn on encrypted communication for just specific databases. +Endpoints equal TCP ports to be bound. On one specific ethernet interface each port +can only be bound **exactly once**. You can look up your available interfaces using +the *ifconfig* command on Linux / MacOSX - the Windows equivalent is *ipconfig* +([See Wikipedia for more details](http://en.wikipedia.org/wiki/Ifconfig)). +The general names of the interfaces differ on OS's and hardwares they run on. +However, typically every host has a so called +[loopback interface](http://en.wikipedia.org/wiki/Loop_device), which is a +virtual interface. By convention it always has the address *127.0.0.1* or *::1* (ipv6), +and can only be reached from exactly the very same host. +Ethernet interfaces usually have names like *eth0*, *wlan0*, *eth1:17*, *le0* or +a plain text name in Windows. + +To find out which services already use ports (so ArangoDB can't bind them anymore), +you can use the [netstat command](http://en.wikipedia.org/wiki/Netstat) +(it behaves a little different on each platform, run it with *-lnpt* on Linux, *-p tcp* +on MacOSX or with *-an* on windows for valuable information). + The JavaScript interface for endpoints provides operations to add new endpoints at runtime, and optionally restrict them for use with specific databases. The interface also can be used to update existing endpoints or remove them at runtime. @@ -36,4 +56,4 @@ When not in the default database, you must first switch to it using the !SUBSECTION Remove -@startDocuBlock removeEndpoint \ No newline at end of file +@startDocuBlock removeEndpoint diff --git a/Documentation/Books/Users/book.json b/Documentation/Books/Users/book.json index cd2681dfdf..93fba49576 100644 --- a/Documentation/Books/Users/book.json +++ b/Documentation/Books/Users/book.json @@ -12,5 +12,8 @@ "top": 35, "bottom": 35 } + }, + "styles": { + "website": "styles/website.css" } } diff --git a/Documentation/Books/Users/styles/website.css b/Documentation/Books/Users/styles/website.css new file mode 100755 index 0000000000..5466d7d07c --- /dev/null +++ b/Documentation/Books/Users/styles/website.css @@ -0,0 +1 @@ +div.example_show_button { border: medium solid lightgray; text-align: center; position: relative; top: -10px; } .book .book-body .navigation.navigation-next { right: 10px !important; } .book .book-summary ul.summary li.active>a,.book .book-summary ul.summary li a:hover { color: #000 !important; background: #80A54D !important; text-decoration: none; } .book .book-body .page-wrapper .page-inner section.normal .deprecated{ background-color: rgba(240,240,0,0.4); } .gsib_a { padding: 0px !important; } .gsc-control-cse { border: 0px !important; background-color: transparent !important; } .gsc-input { margin: 0px !important; } \ No newline at end of file diff --git a/arangod/VocBase/server.cpp b/arangod/VocBase/server.cpp index c9a80e2446..3630e2c18b 100644 --- a/arangod/VocBase/server.cpp +++ b/arangod/VocBase/server.cpp @@ -1993,16 +1993,10 @@ int TRI_StartServer (TRI_server_t* server, if (server->_appPath != nullptr && strlen(server->_appPath) > 0 && ! TRI_IsDirectory(server->_appPath)) { - if (! performUpgrade) { - LOG_ERROR("specified --javascript.app-path directory '%s' does not exist. " - "Please start again with --upgrade option to create it.", - server->_appPath); - return TRI_ERROR_BAD_PARAMETER; - } long systemError; std::string errorMessage; - res = TRI_CreateDirectory(server->_appPath, systemError, errorMessage); + int res = TRI_CreateRecursiveDirectory(server->_appPath, systemError, errorMessage); if (res != TRI_ERROR_NO_ERROR) { LOG_ERROR("unable to create --javascript.app-path directory '%s': %s", @@ -2010,6 +2004,10 @@ int TRI_StartServer (TRI_server_t* server, errorMessage.c_str()); return res; } + else { + LOG_INFO("created --javascript.app-path directory '%s'.", + server->_appPath); + } } // create subdirectories if not yet present diff --git a/arangod/Wal/LogfileManager.cpp b/arangod/Wal/LogfileManager.cpp index 3a7e052439..91b8151740 100644 --- a/arangod/Wal/LogfileManager.cpp +++ b/arangod/Wal/LogfileManager.cpp @@ -28,6 +28,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "LogfileManager.h" +#include "Basics/files.h" #include "Basics/hashes.h" #include "Basics/json.h" #include "Basics/logging.h" @@ -266,7 +267,18 @@ bool LogfileManager::prepare () { _directory = (*_databasePath); if (! basics::FileUtils::isDirectory(_directory)) { - LOG_FATAL_AND_EXIT("database directory '%s' does not exist.", _directory.c_str()); + std::string systemErrorStr; + long errorNo; + + int res = TRI_CreateRecursiveDirectory(_directory.c_str(), errorNo, systemErrorStr); + if (res != TRI_ERROR_NO_ERROR) { + LOG_FATAL_AND_EXIT("unable to create database directory: %s", + systemErrorStr.c_str()); + } + else { + LOG_INFO("created database directory '%s'.", + _directory.c_str()); + } } // append "/journals" diff --git a/js/client/modules/org/arangodb/foxx/manager.js b/js/client/modules/org/arangodb/foxx/manager.js index 231f57022a..d81abd2905 100644 --- a/js/client/modules/org/arangodb/foxx/manager.js +++ b/js/client/modules/org/arangodb/foxx/manager.js @@ -1,4 +1,5 @@ /*jshint unused: false */ +'use strict'; //////////////////////////////////////////////////////////////////////////////// /// @brief ArangoDB Application Launcher @@ -29,26 +30,24 @@ /// @author Copyright 2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -(function() { - 'use strict'; // ----------------------------------------------------------------------------- // --SECTION-- imports // ----------------------------------------------------------------------------- - var arangodb = require("org/arangodb"); - var arangosh = require("org/arangodb/arangosh"); - var errors = arangodb.errors; - var ArangoError = arangodb.ArangoError; - var checkParameter = arangodb.checkParameter; - var arango = require("internal").arango; - var fs = require("fs"); +var arangodb = require("org/arangodb"); +var arangosh = require("org/arangodb/arangosh"); +var errors = arangodb.errors; +var ArangoError = arangodb.ArangoError; +var checkParameter = arangodb.checkParameter; +var arango = require("internal").arango; +var fs = require("fs"); - var throwFileNotFound = arangodb.throwFileNotFound; - var throwBadParameter = arangodb.throwBadParameter; +var throwFileNotFound = arangodb.throwFileNotFound; +var throwBadParameter = arangodb.throwBadParameter; - var utils = require("org/arangodb/foxx/manager-utils"); - var store = require("org/arangodb/foxx/store"); +var utils = require("org/arangodb/foxx/manager-utils"); +var store = require("org/arangodb/foxx/store"); // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- @@ -57,83 +56,83 @@ /// @brief extracts command-line options //////////////////////////////////////////////////////////////////////////////// - var extractCommandLineOptions = function(args) { +var extractCommandLineOptions = function(args) { - var options = {}; - var nargs = []; - var i; + var options = {}; + var nargs = []; + var i; - var reOption = /^([\-_a-zA-Z0-9]*)=(.*)$/; - var reNumeric = /^(0|.0|([0-9]*(\.[0-9]*)?))$/; - var arg, match, key, value; + var reOption = /^([\-_a-zA-Z0-9]*)=(.*)$/; + var reNumeric = /^(0|.0|([0-9]*(\.[0-9]*)?))$/; + var arg, match, key, value; - for (i = 0; i < args.length; ++i) { - arg = args[i]; - match = reOption.exec(arg); + for (i = 0; i < args.length; ++i) { + arg = args[i]; + match = reOption.exec(arg); - if (match !== null) { - key = match[1]; - value = match[2]; + if (match !== null) { + key = match[1]; + value = match[2]; - if (reNumeric.test(value)) { - options[key] = parseFloat(value); - } - else { - options[key] = value; - } + if (reNumeric.test(value)) { + options[key] = parseFloat(value); } else { - nargs.push(args[i]); + options[key] = value; } } + else { + nargs.push(args[i]); + } + } - return { 'options': options, 'args': nargs }; - }; + return { 'options': options, 'args': nargs }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief extract options from CLI options //////////////////////////////////////////////////////////////////////////////// - var extractOptions = function (args) { - var opts = extractCommandLineOptions(args); - if (3 < opts.args.length) { - var options = JSON.parse(opts.args[3]); +var extractOptions = function (args) { + var opts = extractCommandLineOptions(args); + if (3 < opts.args.length) { + var options = JSON.parse(opts.args[3]); - if (options.hasOwnProperty("configuration")) { - var key; + if (options.hasOwnProperty("configuration")) { + var key; - for (key in opts.options) { - if (opts.options.hasOwnProperty(key)) { - options.configuration[key] = opts.options[key]; - } + for (key in opts.options) { + if (opts.options.hasOwnProperty(key)) { + options.configuration[key] = opts.options[key]; } } - else { - options.configuration = opts.options; - } - - return options; + } + else { + options.configuration = opts.options; } - return { configuration: opts.options }; - }; + return options; + } + + return { configuration: opts.options }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief prints out usage message for the command-line tool //////////////////////////////////////////////////////////////////////////////// - var cmdUsage = function () { - var printf = arangodb.printf; - var fm = "foxx-manager"; +var cmdUsage = function () { + var printf = arangodb.printf; + var fm = "foxx-manager"; - printf("Example usage:\n"); - printf(" %s install option1=value1\n", fm); - printf(" %s uninstall \n\n", fm); + printf("Example usage:\n"); + printf(" %s install option1=value1\n", fm); + printf(" %s uninstall \n\n", fm); - printf("Further help:\n"); - printf(" %s help for the list of foxx-manager commands\n", fm); - printf(" %s --help for the list of options\n", fm); - }; + printf("Further help:\n"); + printf(" %s help for the list of foxx-manager commands\n", fm); + printf(" %s --help for the list of options\n", fm); +}; // ----------------------------------------------------------------------------- // --SECTION-- public functions @@ -144,63 +143,63 @@ /// @brief outputs the help //////////////////////////////////////////////////////////////////////////////// - var help = function () { +var help = function () { - /*jshint maxlen: 200 */ - var commands = { - "available" : "lists all Foxx applications available in the local repository", - "configuration" : "request the configuration information for the given mountpoint", - "configure" : "sets the configuration for the given mountpoint", - "dependencies" : "request the dependencies information for the given mountpoint", - "development" : "activates development mode for the given mountpoint", - "help" : "shows this help", - "info" : "displays information about a Foxx application", - "install" : "installs a foxx application identified by the given information to the given mountpoint", - "installed" : "alias for the 'list' command", - "list" : "lists all installed Foxx applications", - "production" : "activates production mode for the given mountpoint", - "replace" : ["replaces an installed Foxx application", + /*jshint maxlen: 200 */ + var commands = { + "available" : "lists all Foxx applications available in the local repository", + "configuration" : "request the configuration information for the given mountpoint", + "configure" : "sets the configuration for the given mountpoint", + "dependencies" : "request the dependencies information for the given mountpoint", + "development" : "activates development mode for the given mountpoint", + "help" : "shows this help", + "info" : "displays information about a Foxx application", + "install" : "installs a foxx application identified by the given information to the given mountpoint", + "installed" : "alias for the 'list' command", + "list" : "lists all installed Foxx applications", + "production" : "activates production mode for the given mountpoint", + "replace" : ["replaces an installed Foxx application", + "WARNING: this action will remove application data if the application implements teardown!" ], + "run" : "runs the given script of a foxx app mounted at the given mountpoint", + "search" : "searches the local foxx-apps repository", + "set-dependencies": "sets the dependencies for the given mountpoint", + "setup" : "executes the setup script", + "teardown" : [ "executes the teardown script", "WARNING: this action will remove application data if the application implements teardown!" ], - "run" : "runs the given script of a foxx app mounted at the given mountpoint", - "search" : "searches the local foxx-apps repository", - "set-dependencies": "sets the dependencies for the given mountpoint", - "setup" : "executes the setup script", - "teardown" : [ "executes the teardown script", - "WARNING: this action will remove application data if the application implements teardown!" ], - "tests" : "runs the tests of a foxx application mounted at the given mountpoint", - "uninstall" : ["uninstalls a Foxx application and calls its teardown method", - "WARNING: this will remove all data and code of the application!" ], - "update" : "updates the local foxx-apps repository with data from the central foxx-apps repository", - "upgrade" : ["upgrades an installed Foxx application", - "Note: this action will not call setup or teardown" ] - }; - - arangodb.print("\nThe following commands are available:\n"); - var keys = Object.keys(commands).sort(); - - var i; - var pad, name, extra; - for (i = 0; i < keys.length; ++i) { - pad = " "; - name = keys[i] + pad; - extra = commands[keys[i]]; - - if (typeof extra !== 'string') { - // list of strings - extra = extra.join("\n " + pad) + "\n"; - } - arangodb.printf(" %s %s\n", name.substr(0, pad.length), extra); - } - - arangodb.print(); - arangodb.print("Use foxx-manager --help to show a list of global options\n"); - arangodb.print("There is also an online manual available at:"); - arangodb.print("https://docs.arangodb.com/FoxxManager/README.html"); - - // additional newline - arangodb.print(); + "tests" : "runs the tests of a foxx application mounted at the given mountpoint", + "uninstall" : ["uninstalls a Foxx application and calls its teardown method", + "WARNING: this will remove all data and code of the application!" ], + "update" : "updates the local foxx-apps repository with data from the central foxx-apps repository", + "upgrade" : ["upgrades an installed Foxx application", + "Note: this action will not call setup or teardown" ] }; + arangodb.print("\nThe following commands are available:\n"); + var keys = Object.keys(commands).sort(); + + var i; + var pad, name, extra; + for (i = 0; i < keys.length; ++i) { + pad = " "; + name = keys[i] + pad; + extra = commands[keys[i]]; + + if (typeof extra !== 'string') { + // list of strings + extra = extra.join("\n " + pad) + "\n"; + } + arangodb.printf(" %s %s\n", name.substr(0, pad.length), extra); + } + + arangodb.print(); + arangodb.print("Use foxx-manager --help to show a list of global options\n"); + arangodb.print("There is also an online manual available at:"); + arangodb.print("https://docs.arangodb.com/FoxxManager/README.html"); + + // additional newline + arangodb.print(); +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief runs a script on a Foxx application /// @@ -211,60 +210,60 @@ /// Output: /// - //////////////////////////////////////////////////////////////////////////////// - var runScript = function(mount, name, options) { - checkParameter( - "run(, , [])", - [ [ "Mount path", "string" ], [ "Script name", "string" ] ], - [ mount, name ] ); - var res; - var req = { - name: name, - mount: mount, - options: options - }; - res = arango.POST("/_admin/foxx/script", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return res; +var runScript = function(mount, name, options) { + checkParameter( + "run(, , [])", + [ [ "Mount path", "string" ], [ "Script name", "string" ] ], + [ mount, name ] ); + var res; + var req = { + name: name, + mount: mount, + options: options }; + res = arango.POST("/_admin/foxx/script", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return res; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief Zips and copies a local app to the server. //////////////////////////////////////////////////////////////////////////////// - var moveAppToServer = function(appInfo) { - if (! fs.exists(appInfo)) { - throwFileNotFound("Cannot find file: " + appInfo + "."); +var moveAppToServer = function(appInfo) { + if (! fs.exists(appInfo)) { + throwFileNotFound("Cannot find file: " + appInfo + "."); + } + var filePath; + var shouldDelete = false; + if (fs.isDirectory(appInfo)) { + filePath = utils.zipDirectory(appInfo); + shouldDelete = true; + } + if (fs.isFile(appInfo)) { + filePath = appInfo; + } + if (!filePath) { + throwBadParameter("Invalid file: " + appInfo + ". Has to be a direcotry or zip archive"); + } + var response = arango.SEND_FILE("/_api/upload", filePath); + if (shouldDelete) { + try { + fs.remove(filePath); } - var filePath; - var shouldDelete = false; - if (fs.isDirectory(appInfo)) { - filePath = utils.zipDirectory(appInfo); - shouldDelete = true; + catch (err2) { + arangodb.printf("Cannot remove temporary file '%s'\n", filePath); } - if (fs.isFile(appInfo)) { - filePath = appInfo; - } - if (!filePath) { - throwBadParameter("Invalid file: " + appInfo + ". Has to be a direcotry or zip archive"); - } - var response = arango.SEND_FILE("/_api/upload", filePath); - if (shouldDelete) { - try { - fs.remove(filePath); - } - catch (err2) { - arangodb.printf("Cannot remove temporary file '%s'\n", filePath); - } - } - if (! response.filename) { - throw new ArangoError({ - errorNum: errors.ERROR_APPLICATION_UPLOAD_FAILED.code, - errorMessage: errors.ERROR_APPLICATION_UPLOAD_FAILED.message - + ": " + String(response.errorMessage) - }); - } - return response.filename; - }; + } + if (! response.filename) { + throw new ArangoError({ + errorNum: errors.ERROR_APPLICATION_UPLOAD_FAILED.code, + errorMessage: errors.ERROR_APPLICATION_UPLOAD_FAILED.message + + ": " + String(response.errorMessage) + }); + } + return response.filename; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief Installs a new foxx application on the given mount point. @@ -272,58 +271,58 @@ /// TODO: Long Documentation! //////////////////////////////////////////////////////////////////////////////// - var install = function(appInfo, mount, options) { - checkParameter( - "install(, , [])", - [ [ "Install information", "string" ], - [ "Mount path", "string" ] ], - [ appInfo, mount ] ); +var install = function(appInfo, mount, options) { + checkParameter( + "install(, , [])", + [ [ "Install information", "string" ], + [ "Mount path", "string" ] ], + [ appInfo, mount ] ); - utils.validateMount(mount); - if (fs.exists(appInfo)) { - appInfo = moveAppToServer(appInfo); - } - var res; - var req = { - appInfo: appInfo, - mount: mount, - options: options - }; - - res = arango.POST("/_admin/foxx/install", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; + utils.validateMount(mount); + if (fs.exists(appInfo)) { + appInfo = moveAppToServer(appInfo); + } + var res; + var req = { + appInfo: appInfo, + mount: mount, + options: options }; + res = arango.POST("/_admin/foxx/install", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief Uninstalls the foxx application on the given mount point. /// /// TODO: Long Documentation! //////////////////////////////////////////////////////////////////////////////// - var uninstall = function(mount, options) { - checkParameter( - "uninstall(, [])", - [ [ "Mount path", "string" ] ], - [ mount ] ); - var res; - var req = { - mount: mount, - options: options || {} - }; - utils.validateMount(mount); - res = arango.POST("/_admin/foxx/uninstall", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; +var uninstall = function(mount, options) { + checkParameter( + "uninstall(, [])", + [ [ "Mount path", "string" ] ], + [ mount ] ); + var res; + var req = { + mount: mount, + options: options || {} }; + utils.validateMount(mount); + res = arango.POST("/_admin/foxx/uninstall", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief Replaces a foxx application on the given mount point by an other one. @@ -331,422 +330,421 @@ /// TODO: Long Documentation! //////////////////////////////////////////////////////////////////////////////// - var replace = function(appInfo, mount, options) { - checkParameter( - "replace(, , [])", - [ [ "Install information", "string" ], - [ "Mount path", "string" ] ], - [ appInfo, mount ] ); +var replace = function(appInfo, mount, options) { + checkParameter( + "replace(, , [])", + [ [ "Install information", "string" ], + [ "Mount path", "string" ] ], + [ appInfo, mount ] ); - utils.validateMount(mount); - if (fs.exists(appInfo)) { - appInfo = moveAppToServer(appInfo); - } - var res; - var req = { - appInfo: appInfo, - mount: mount, - options: options - }; - - res = arango.POST("/_admin/foxx/replace", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; + utils.validateMount(mount); + if (fs.exists(appInfo)) { + appInfo = moveAppToServer(appInfo); + } + var res; + var req = { + appInfo: appInfo, + mount: mount, + options: options }; + res = arango.POST("/_admin/foxx/replace", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief Upgrade a foxx application on the given mount point by a new one. /// /// TODO: Long Documentation! //////////////////////////////////////////////////////////////////////////////// - var upgrade = function(appInfo, mount, options) { - checkParameter( - "upgrade(, , [])", - [ [ "Install information", "string" ], - [ "Mount path", "string" ] ], - [ appInfo, mount ] ); - utils.validateMount(mount); - if (fs.exists(appInfo)) { - appInfo = moveAppToServer(appInfo); - } - var res; - var req = { - appInfo: appInfo, - mount: mount, - options: options - }; - - res = arango.POST("/_admin/foxx/upgrade", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; +var upgrade = function(appInfo, mount, options) { + checkParameter( + "upgrade(, , [])", + [ [ "Install information", "string" ], + [ "Mount path", "string" ] ], + [ appInfo, mount ] ); + utils.validateMount(mount); + if (fs.exists(appInfo)) { + appInfo = moveAppToServer(appInfo); + } + var res; + var req = { + appInfo: appInfo, + mount: mount, + options: options }; + res = arango.POST("/_admin/foxx/upgrade", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief Activate the development mode for the application on the given mount point. //////////////////////////////////////////////////////////////////////////////// - var development = function(mount) { - checkParameter( - "development()", - [ [ "Mount path", "string" ] ], - [ mount ] ); - utils.validateMount(mount); - var res; - var req = { - mount: mount, - activate: true - }; - res = arango.POST("/_admin/foxx/development", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; +var development = function(mount) { + checkParameter( + "development()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + utils.validateMount(mount); + var res; + var req = { + mount: mount, + activate: true }; + res = arango.POST("/_admin/foxx/development", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief Activate the production mode for the application on the given mount point. //////////////////////////////////////////////////////////////////////////////// - var production = function(mount) { - checkParameter( - "production()", - [ [ "Mount path", "string" ] ], - [ mount ] ); - utils.validateMount(mount); - var res; - var req = { - mount: mount, - activate: false - }; - res = arango.POST("/_admin/foxx/development", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; +var production = function(mount) { + checkParameter( + "production()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + utils.validateMount(mount); + var res; + var req = { + mount: mount, + activate: false }; + res = arango.POST("/_admin/foxx/development", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; - //////////////////////////////////////////////////////////////////////////////// - /// @brief Configure the app at the mountpoint - //////////////////////////////////////////////////////////////////////////////// - - var configure = function(mount, options) { - checkParameter( - "configure()", - [ [ "Mount path", "string" ] ], - [ mount ] ); - utils.validateMount(mount); - var req = { - mount: mount, - options: options - }; - var res = arango.POST("/_admin/foxx/configure", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; - }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief Configure the app at the mountpoint +//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /// @brief Get the configuration for the app at the given mountpoint - //////////////////////////////////////////////////////////////////////////////// - - var configuration = function(mount) { - checkParameter( - "configuration()", - [ [ "Mount path", "string" ] ], - [ mount ] ); - utils.validateMount(mount); - var req = { - mount: mount - }; - var res = arango.POST("/_admin/foxx/configuration", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return res; +var configure = function(mount, options) { + checkParameter( + "configure()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + utils.validateMount(mount); + var req = { + mount: mount, + options: options }; + var res = arango.POST("/_admin/foxx/configure", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; - //////////////////////////////////////////////////////////////////////////////// - /// @brief Configure the dependencies of the app at the mountpoint - //////////////////////////////////////////////////////////////////////////////// - - var setDependencies = function(mount, options) { - checkParameter( - "setDependencies()", - [ [ "Mount path", "string" ] ], - [ mount ] ); - utils.validateMount(mount); - var req = { - mount: mount, - options: options - }; - var res = arango.POST("/_admin/foxx/set-dependencies", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return { - name: res.name, - version: res.version, - mount: res.mount - }; - }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief Get the configuration for the app at the given mountpoint +//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - /// @brief Get the dependencies of the app at the given mountpoint - //////////////////////////////////////////////////////////////////////////////// - - var dependencies = function(mount) { - checkParameter( - "dependencies()", - [ [ "Mount path", "string" ] ], - [ mount ] ); - utils.validateMount(mount); - var req = { - mount: mount - }; - var res = arango.POST("/_admin/foxx/dependencies", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return res; +var configuration = function(mount) { + checkParameter( + "configuration()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + utils.validateMount(mount); + var req = { + mount: mount }; + var res = arango.POST("/_admin/foxx/configuration", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return res; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Configure the dependencies of the app at the mountpoint +//////////////////////////////////////////////////////////////////////////////// + +var setDependencies = function(mount, options) { + checkParameter( + "setDependencies()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + utils.validateMount(mount); + var req = { + mount: mount, + options: options + }; + var res = arango.POST("/_admin/foxx/set-dependencies", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return { + name: res.name, + version: res.version, + mount: res.mount + }; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Get the dependencies of the app at the given mountpoint +//////////////////////////////////////////////////////////////////////////////// + +var dependencies = function(mount) { + checkParameter( + "dependencies()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + utils.validateMount(mount); + var req = { + mount: mount + }; + var res = arango.POST("/_admin/foxx/dependencies", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return res; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief run a Foxx application's tests //////////////////////////////////////////////////////////////////////////////// - var tests = function (mount, options) { - checkParameter( - "tests(, [])", - [ [ "Mount path", "string" ] ], - [ mount ] - ); - utils.validateMount(mount); - var req = { - mount: mount, - options: options - }; - var res = arango.POST("/_admin/foxx/tests", JSON.stringify(req)); - arangosh.checkRequestResult(res); - return res; +var tests = function (mount, options) { + checkParameter( + "tests(, [])", + [ [ "Mount path", "string" ] ], + [ mount ] + ); + utils.validateMount(mount); + var req = { + mount: mount, + options: options }; + var res = arango.POST("/_admin/foxx/tests", JSON.stringify(req)); + arangosh.checkRequestResult(res); + return res; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief command line dispatcher //////////////////////////////////////////////////////////////////////////////// - var run = function (args) { - if (args === undefined || args.length === 0) { - arangodb.print("Expecting a command, please try:\n"); - cmdUsage(); - return 0; +var run = function (args) { + if (args === undefined || args.length === 0) { + arangodb.print("Expecting a command, please try:\n"); + cmdUsage(); + return 0; + } + + var type = args[0]; + var printf = arangodb.printf; + var res; + var options; + + + try { + switch (type) { + case "setup": + runScript(args[1], "setup"); + break; + case "teardown": + runScript(args[1], "teardown"); + break; + case "run": + options = args.slice(3).map(function (arg) { + return JSON.parse(arg); + }); + res = runScript(args[1], args[2], options); + printf(JSON.stringify(res, null, 2) + "\n"); + break; + case "tests": + options = args[2] ? JSON.parse(args[2]) : undefined; + res = tests(args[1], options); + printf(JSON.stringify(res, null, 2) + "\n"); + break; + case "install": + options = extractOptions(args); + res = install(args[1], args[2], options); + printf("Application %s version %s installed successfully at mount point %s\n", + res.name, + res.version, + res.mount); + printf("options used: %s\n", JSON.stringify(options)); + break; + case "replace": + options = extractOptions(args); + res = replace(args[1], args[2], options); + printf("Application %s version %s replaced successfully at mount point %s\n", + res.name, + res.version, + res.mount); + break; + case "upgrade": + options = extractOptions(args); + res = upgrade(args[1], args[2], options); + printf("Application %s version %s upgraded successfully at mount point %s\n", + res.name, + res.version, + res.mount); + break; + case "uninstall": + options = extractOptions(args).configuration || {}; + res = uninstall(args[1], options); + + printf("Application %s version %s uninstalled successfully from mount point %s\n", + res.name, + res.version, + res.mount); + break; + case "list": + case "installed": + if (1 < args.length && args[1] === "prefix") { + utils.list(true); + } + else { + utils.list(); + } + break; + case "listDevelopment": + if (1 < args.length && args[1] === "prefix") { + utils.listDevelopment(true); + } + else { + utils.listDevelopment(); + } + break; + case "available": + store.available(); + break; + case "info": + store.info(args[1]); + break; + case "search": + store.search(args[1]); + break; + case "update": + store.update(); + break; + case "help": + help(); + break; + case "development": + res = development(args[1]); + printf("Activated development mode for Application %s version %s on mount point %s\n", + res.name, + res.version, + res.mount); + break; + case "production": + res = production(args[1]); + printf("Activated production mode for Application %s version %s on mount point %s\n", + res.name, + res.version, + res.mount); + break; + case "configure": + options = extractOptions(args).configuration || {}; + res = configure(args[1], options); + printf("Reconfigured Application %s version %s on mount point %s\n", + res.name, + res.version, + res.mount); + break; + case "configuration": + res = configuration(args[1]); + printf("Configuration options:\n%s\n", JSON.stringify(res, undefined, 2)); + break; + case "set-dependencies": + options = extractOptions(args).configuration || {}; + res = setDependencies(args[1], options); + printf("Reconfigured dependencies of Application %s version %s on mount point %s\n", + res.name, + res.version, + res.mount); + break; + case "dependencies": + res = dependencies(args[1]); + printf("Dependencies:\n%s\n", JSON.stringify(res, undefined, 2)); + break; + default: + printf("Unknown command '%s', please try:\n", type); + cmdUsage(); + } + return 0; + } + catch (err) { + if (err instanceof ArangoError) { + printf("%s\n", err.errorMessage); + } + else { + printf("%s\n", err.message); } - var type = args[0]; - var printf = arangodb.printf; - var res; - var options; - - - try { - switch (type) { - case "setup": - runScript(args[1], "setup"); - break; - case "teardown": - runScript(args[1], "teardown"); - break; - case "run": - options = args.slice(3).map(function (arg) { - return JSON.parse(arg); - }); - res = runScript(args[1], args[2], options); - printf(JSON.stringify(res, null, 2) + "\n"); - break; - case "tests": - options = args[2] ? JSON.parse(args[2]) : undefined; - res = tests(args[1], options); - printf(JSON.stringify(res, null, 2) + "\n"); - break; - case "install": - options = extractOptions(args); - res = install(args[1], args[2], options); - printf("Application %s version %s installed successfully at mount point %s\n", - res.name, - res.version, - res.mount); - printf("options used: %s\n", JSON.stringify(options)); - break; - case "replace": - options = extractOptions(args); - res = replace(args[1], args[2], options); - printf("Application %s version %s replaced successfully at mount point %s\n", - res.name, - res.version, - res.mount); - break; - case "upgrade": - options = extractOptions(args); - res = upgrade(args[1], args[2], options); - printf("Application %s version %s upgraded successfully at mount point %s\n", - res.name, - res.version, - res.mount); - break; - case "uninstall": - options = extractOptions(args).configuration || {}; - res = uninstall(args[1], options); - - printf("Application %s version %s uninstalled successfully from mount point %s\n", - res.name, - res.version, - res.mount); - break; - case "list": - case "installed": - if (1 < args.length && args[1] === "prefix") { - utils.list(true); - } - else { - utils.list(); - } - break; - case "listDevelopment": - if (1 < args.length && args[1] === "prefix") { - utils.listDevelopment(true); - } - else { - utils.listDevelopment(); - } - break; - case "available": - store.available(); - break; - case "info": - store.info(args[1]); - break; - case "search": - store.search(args[1]); - break; - case "update": - store.update(); - break; - case "help": - help(); - break; - case "development": - res = development(args[1]); - printf("Activated development mode for Application %s version %s on mount point %s\n", - res.name, - res.version, - res.mount); - break; - case "production": - res = production(args[1]); - printf("Activated production mode for Application %s version %s on mount point %s\n", - res.name, - res.version, - res.mount); - break; - case "configure": - options = extractOptions(args).configuration || {}; - res = configure(args[1], options); - printf("Reconfigured Application %s version %s on mount point %s\n", - res.name, - res.version, - res.mount); - break; - case "configuration": - res = configuration(args[1]); - printf("Configuration options:\n%s\n", JSON.stringify(res, undefined, 2)); - break; - case "set-dependencies": - options = extractOptions(args).configuration || {}; - res = setDependencies(args[1], options); - printf("Reconfigured dependencies of Application %s version %s on mount point %s\n", - res.name, - res.version, - res.mount); - break; - case "dependencies": - res = dependencies(args[1]); - printf("Dependencies:\n%s\n", JSON.stringify(res, undefined, 2)); - break; - default: - printf("Unknown command '%s', please try:\n", type); - cmdUsage(); - } - return 0; - } - catch (err) { - if (err instanceof ArangoError) { - printf("%s\n", err.errorMessage); - } - else { - printf("%s\n", err.message); - } - - return 1; - } - }; + return 1; + } +}; // ----------------------------------------------------------------------------- // --SECTION-- exports // ----------------------------------------------------------------------------- - exports.install = install; - exports.setup = function (mount, opts) {return runScript(mount, "setup", opts);}; - exports.teardown = function (mount, opts) {return runScript(mount, "teardown", opts);}; - exports.run = runScript; - exports.tests = tests; - exports.uninstall = uninstall; - exports.replace = replace; - exports.upgrade = upgrade; - exports.development = development; - exports.production = production; - exports.configure = configure; - exports.configuration = configuration; - exports.setDependencies = setDependencies; - exports.dependencies = dependencies; +exports.install = install; +exports.setup = function (mount, opts) {return runScript(mount, "setup", opts);}; +exports.teardown = function (mount, opts) {return runScript(mount, "teardown", opts);}; +exports.run = runScript; +exports.tests = tests; +exports.uninstall = uninstall; +exports.replace = replace; +exports.upgrade = upgrade; +exports.development = development; +exports.production = production; +exports.configure = configure; +exports.configuration = configuration; +exports.setDependencies = setDependencies; +exports.dependencies = dependencies; //////////////////////////////////////////////////////////////////////////////// /// @brief Clientside only API //////////////////////////////////////////////////////////////////////////////// - exports.run = run; - exports.help = help; +exports.run = run; +exports.help = help; //////////////////////////////////////////////////////////////////////////////// /// @brief Exports from foxx utils module. //////////////////////////////////////////////////////////////////////////////// - exports.mountedApp = utils.mountedApp; - exports.list = utils.list; - exports.listJson = utils.listJson; - exports.listDevelopment = utils.listDevelopment; - exports.listDevelopmentJson = utils.listDevelopmentJson; +exports.mountedApp = utils.mountedApp; +exports.list = utils.list; +exports.listJson = utils.listJson; +exports.listDevelopment = utils.listDevelopment; +exports.listDevelopmentJson = utils.listDevelopmentJson; //////////////////////////////////////////////////////////////////////////////// /// @brief Exports from foxx store module. //////////////////////////////////////////////////////////////////////////////// - exports.available = store.available; - exports.availableJson = store.availableJson; - exports.search = store.search; - exports.searchJson = store.searchJson; - exports.update = store.update; - exports.info = store.info; +exports.available = store.available; +exports.availableJson = store.availableJson; +exports.search = store.search; +exports.searchJson = store.searchJson; +exports.update = store.update; +exports.info = store.info; -}()); // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/js/common/modules/org/arangodb/foxx/store.js b/js/common/modules/org/arangodb/foxx/store.js index df3bd2cd37..686f94be41 100644 --- a/js/common/modules/org/arangodb/foxx/store.js +++ b/js/common/modules/org/arangodb/foxx/store.js @@ -1,4 +1,4 @@ -/*jslint continue:true */ +'use strict'; //////////////////////////////////////////////////////////////////////////////// /// @brief Foxx application store @@ -27,26 +27,23 @@ /// @author Copyright 2015, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -(function() { - 'use strict'; - // ----------------------------------------------------------------------------- // --SECTION-- global variables // ----------------------------------------------------------------------------- - var checkedFishBowl = false; +var checkedFishBowl = false; // ----------------------------------------------------------------------------- // --SECTION-- imports // ----------------------------------------------------------------------------- - var arangodb = require("org/arangodb"); - var db = arangodb.db; - var download = require("internal").download; - var fs = require("fs"); - var throwDownloadError = arangodb.throwDownloadError; - var utils = require("org/arangodb/foxx/manager-utils"); +var arangodb = require("org/arangodb"); +var db = arangodb.db; +var download = require("internal").download; +var fs = require("fs"); +var throwDownloadError = arangodb.throwDownloadError; +var utils = require("org/arangodb/foxx/manager-utils"); // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -56,9 +53,9 @@ /// @brief returns the fishbowl repository //////////////////////////////////////////////////////////////////////////////// - function getFishbowlUrl () { - return "arangodb/foxx-apps"; - } +function getFishbowlUrl () { + return "arangodb/foxx-apps"; +} //////////////////////////////////////////////////////////////////////////////// /// @brief returns the fishbowl collection @@ -68,190 +65,190 @@ /// used in context of the database. //////////////////////////////////////////////////////////////////////////////// - var getFishbowlStorage = function() { +var getFishbowlStorage = function() { - var c = db._collection('_fishbowl'); - if (c === null) { - c = db._create('_fishbowl', { isSystem : true }); - } + var c = db._collection('_fishbowl'); + if (c === null) { + c = db._create('_fishbowl', { isSystem : true }); + } - if (c !== null && ! checkedFishBowl) { - // ensure indexes - c.ensureFulltextIndex("description"); - c.ensureFulltextIndex("name"); - checkedFishBowl = true; - } + if (c !== null && ! checkedFishBowl) { + // ensure indexes + c.ensureFulltextIndex("description"); + c.ensureFulltextIndex("name"); + checkedFishBowl = true; + } - return c; - }; + return c; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief comparator for applications //////////////////////////////////////////////////////////////////////////////// - var compareApps = function(l, r) { - var left = l.name.toLowerCase(); - var right = r.name.toLowerCase(); +var compareApps = function(l, r) { + var left = l.name.toLowerCase(); + var right = r.name.toLowerCase(); - if (left < right) { - return -1; - } + if (left < right) { + return -1; + } - if (right < left) { - return 1; - } + if (right < left) { + return 1; + } - return 0; - }; + return 0; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief comparator for versions //////////////////////////////////////////////////////////////////////////////// - var compareVersions = function (a, b) { - var i; +var compareVersions = function (a, b) { + var i; - if (a === b) { - return 0; - } - - // error handling - if (typeof a !== "string") { - return -1; - } - if (typeof b !== "string") { - return 1; - } - - var aComponents = a.split("."); - var bComponents = b.split("."); - var len = Math.min(aComponents.length, bComponents.length); - - // loop while the components are equal - for (i = 0; i < len; i++) { - - // A bigger than B - if (parseInt(aComponents[i], 10) > parseInt(bComponents[i], 10)) { - return 1; - } - - // B bigger than A - if (parseInt(aComponents[i], 10) < parseInt(bComponents[i], 10)) { - return -1; - } - } - - // If one's a prefix of the other, the longer one is bigger one. - if (aComponents.length > bComponents.length) { - return 1; - } - - if (aComponents.length < bComponents.length) { - return -1; - } - - // Otherwise they are the same. + if (a === b) { return 0; - }; + } + + // error handling + if (typeof a !== "string") { + return -1; + } + if (typeof b !== "string") { + return 1; + } + + var aComponents = a.split("."); + var bComponents = b.split("."); + var len = Math.min(aComponents.length, bComponents.length); + + // loop while the components are equal + for (i = 0; i < len; i++) { + + // A bigger than B + if (parseInt(aComponents[i], 10) > parseInt(bComponents[i], 10)) { + return 1; + } + + // B bigger than A + if (parseInt(aComponents[i], 10) < parseInt(bComponents[i], 10)) { + return -1; + } + } + + // If one's a prefix of the other, the longer one is bigger one. + if (aComponents.length > bComponents.length) { + return 1; + } + + if (aComponents.length < bComponents.length) { + return -1; + } + + // Otherwise they are the same. + return 0; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief updates the fishbowl from a zip archive //////////////////////////////////////////////////////////////////////////////// - var updateFishbowlFromZip = function(filename) { - var i; - var tempPath = fs.getTempPath(); - var toSave = [ ]; +var updateFishbowlFromZip = function(filename) { + var i; + var tempPath = fs.getTempPath(); + var toSave = [ ]; - try { - fs.makeDirectoryRecursive(tempPath); - var root = fs.join(tempPath, "foxx-apps-master/applications"); - - // remove any previous files in the directory - fs.listTree(root).forEach(function (file) { - if (file.match(/\.json$/)) { - try { - fs.remove(fs.join(root, file)); - } - catch (ignore) { - } - } - }); - - fs.unzipFile(filename, tempPath, false, true); - - if (! fs.exists(root)) { - throw new Error("'applications' directory is missing in foxx-apps-master, giving up"); - } - - var m = fs.listTree(root); - var reSub = /(.*)\.json$/; - var f, match, app, desc; - - for (i = 0; i < m.length; ++i) { - f = m[i]; - match = reSub.exec(f); - if (match === null) { - continue; - } - - app = fs.join(root, f); + try { + fs.makeDirectoryRecursive(tempPath); + var root = fs.join(tempPath, "foxx-apps-master/applications"); + // remove any previous files in the directory + fs.listTree(root).forEach(function (file) { + if (file.match(/\.json$/)) { try { - desc = JSON.parse(fs.read(app)); - } - catch (err1) { - arangodb.printf("Cannot parse description for app '" + f + "': %s\n", String(err1)); - continue; - } - - desc._key = match[1]; - - if (! desc.hasOwnProperty("name")) { - desc.name = match[1]; - } - - toSave.push(desc); - } - - if (toSave.length > 0) { - var fishbowl = getFishbowlStorage(); - - db._executeTransaction({ - collections: { - write: fishbowl.name() - }, - action: function (params) { - var c = require("internal").db._collection(params.collection); - c.truncate(); - - params.apps.forEach(function(app) { - c.save(app); - }); - }, - params: { - apps: toSave, - collection: fishbowl.name() - } - }); - - arangodb.printf("Updated local repository information with %d application(s)\n", - toSave.length); - } - } - catch (err) { - if (tempPath !== undefined && tempPath !== "") { - try { - fs.removeDirectoryRecursive(tempPath); + fs.remove(fs.join(root, file)); } catch (ignore) { } } + }); - throw err; + fs.unzipFile(filename, tempPath, false, true); + + if (! fs.exists(root)) { + throw new Error("'applications' directory is missing in foxx-apps-master, giving up"); } - }; + + var m = fs.listTree(root); + var reSub = /(.*)\.json$/; + var f, match, app, desc; + + for (i = 0; i < m.length; ++i) { + f = m[i]; + match = reSub.exec(f); + if (match === null) { + continue; + } + + app = fs.join(root, f); + + try { + desc = JSON.parse(fs.read(app)); + } + catch (err1) { + arangodb.printf("Cannot parse description for app '" + f + "': %s\n", String(err1)); + continue; + } + + desc._key = match[1]; + + if (! desc.hasOwnProperty("name")) { + desc.name = match[1]; + } + + toSave.push(desc); + } + + if (toSave.length > 0) { + var fishbowl = getFishbowlStorage(); + + db._executeTransaction({ + collections: { + write: fishbowl.name() + }, + action: function (params) { + var c = require("internal").db._collection(params.collection); + c.truncate(); + + params.apps.forEach(function(app) { + c.save(app); + }); + }, + params: { + apps: toSave, + collection: fishbowl.name() + } + }); + + arangodb.printf("Updated local repository information with %d application(s)\n", + toSave.length); + } + } + catch (err) { + if (tempPath !== undefined && tempPath !== "") { + try { + fs.removeDirectoryRecursive(tempPath); + } + catch (ignore) { + } + } + + throw err; + } +}; // ----------------------------------------------------------------------------- // --SECTION-- public functions @@ -261,87 +258,87 @@ /// @brief returns the search result for FOXX applications //////////////////////////////////////////////////////////////////////////////// - var searchJson = function (name) { +var searchJson = function (name) { - var fishbowl = getFishbowlStorage(); + var fishbowl = getFishbowlStorage(); - if (fishbowl.count() === 0) { - arangodb.print("Repository is empty, please use 'update'"); + if (fishbowl.count() === 0) { + arangodb.print("Repository is empty, please use 'update'"); - return []; + return []; + } + + var docs; + + if (name === undefined || (typeof name === "string" && name.length === 0)) { + docs = fishbowl.toArray(); + } + else { + name = name.replace(/[^a-zA-Z0-9]/g, ' '); + + // get results by looking in "description" attribute + docs = fishbowl.fulltext("description", "prefix:" + name).toArray(); + + // build a hash of keys + var i; + var keys = { }; + + for (i = 0; i < docs.length; ++i) { + keys[docs[i]._key] = 1; } - var docs; + // get results by looking in "name" attribute + var docs2= fishbowl.fulltext("name", "prefix:" + name).toArray(); - if (name === undefined || (typeof name === "string" && name.length === 0)) { - docs = fishbowl.toArray(); - } - else { - name = name.replace(/[^a-zA-Z0-9]/g, ' '); - - // get results by looking in "description" attribute - docs = fishbowl.fulltext("description", "prefix:" + name).toArray(); - - // build a hash of keys - var i; - var keys = { }; - - for (i = 0; i < docs.length; ++i) { - keys[docs[i]._key] = 1; + // merge the two result sets, avoiding duplicates + for (i = 0; i < docs2.length; ++i) { + if (!keys.hasOwnProperty(docs2[i]._key)) { + docs.push(docs2[i]); } - // get results by looking in "name" attribute - var docs2= fishbowl.fulltext("name", "prefix:" + name).toArray(); - - // merge the two result sets, avoiding duplicates - for (i = 0; i < docs2.length; ++i) { - if (!keys.hasOwnProperty(docs2[i]._key)) { - docs.push(docs2[i]); - } - - } } + } - return docs; - }; + return docs; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief searchs for an available FOXX applications //////////////////////////////////////////////////////////////////////////////// - var search = function (name) { - var docs = searchJson(name); +var search = function (name) { + var docs = searchJson(name); - arangodb.printTable( - docs.sort(compareApps), - [ "name", "author", "description" ], - { - prettyStrings: true, - totalString: "%s application(s) found", - emptyString: "no applications found", - rename: { - name : "Name", - author : "Author", - description : "Description" - } + arangodb.printTable( + docs.sort(compareApps), + [ "name", "author", "description" ], + { + prettyStrings: true, + totalString: "%s application(s) found", + emptyString: "no applications found", + rename: { + name : "Name", + author : "Author", + description : "Description" } - ); - }; + } + ); +}; //////////////////////////////////////////////////////////////////////////////// /// @brief extracts the highest version number from the document //////////////////////////////////////////////////////////////////////////////// function extractMaxVersion (versionDoc) { - var maxVersion = "-"; - var versions = Object.keys(versionDoc); - versions.sort(compareVersions); - if (versions.length > 0) { - versions.reverse(); - maxVersion = versions[0]; - } - return maxVersion; +var maxVersion = "-"; +var versions = Object.keys(versionDoc); +versions.sort(compareVersions); +if (versions.length > 0) { + versions.reverse(); + maxVersion = versions[0]; +} +return maxVersion; } //////////////////////////////////////////////////////////////////////////////// @@ -349,26 +346,26 @@ function extractMaxVersion (versionDoc) { //////////////////////////////////////////////////////////////////////////////// function availableJson() { - var fishbowl = getFishbowlStorage(); - var cursor = fishbowl.all(); - var result = []; - var doc, maxVersion, res; +var fishbowl = getFishbowlStorage(); +var cursor = fishbowl.all(); +var result = []; +var doc, maxVersion, res; - while (cursor.hasNext()) { - doc = cursor.next(); - maxVersion = extractMaxVersion(doc.versions); +while (cursor.hasNext()) { + doc = cursor.next(); + maxVersion = extractMaxVersion(doc.versions); - res = { - name: doc.name, - description: doc.description || "", - author: doc.author || "", - latestVersion: maxVersion - }; + res = { + name: doc.name, + description: doc.description || "", + author: doc.author || "", + latestVersion: maxVersion + }; - result.push(res); - } + result.push(res); +} - return result; +return result; } @@ -379,181 +376,179 @@ function availableJson() { //////////////////////////////////////////////////////////////////////////////// - var update = function() { - var url = utils.buildGithubUrl(getFishbowlUrl()); - var filename = fs.getTempFile("downloads", false); - var path = fs.getTempFile("zip", false); +var update = function() { + var url = utils.buildGithubUrl(getFishbowlUrl()); + var filename = fs.getTempFile("downloads", false); + var path = fs.getTempFile("zip", false); + + try { + 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); + } + + updateFishbowlFromZip(filename); + + filename = undefined; + } + catch (err) { + if (filename !== undefined && fs.exists(filename)) { + fs.remove(filename); + } try { - 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); - } - - updateFishbowlFromZip(filename); - - filename = undefined; + fs.removeDirectoryRecursive(path); } - catch (err) { - if (filename !== undefined && fs.exists(filename)) { - fs.remove(filename); - } - - try { - fs.removeDirectoryRecursive(path); - } - catch (ignore) { - } - - throw err; + catch (ignore) { } - }; + + throw err; + } +}; //////////////////////////////////////////////////////////////////////////////// /// @brief prints all available FOXX applications //////////////////////////////////////////////////////////////////////////////// - var available = function () { - var list = availableJson(); +var available = function () { + var list = availableJson(); - arangodb.printTable( - list.sort(compareApps), - [ "name", "author", "description", "latestVersion" ], - { - prettyStrings: true, - totalString: "%s application(s) found", - emptyString: "no applications found, please use 'update'", - rename: { - "name" : "Name", - "author" : "Author", - "description" : "Description", - "latestVersion" : "Latest Version" - } + arangodb.printTable( + list.sort(compareApps), + [ "name", "author", "description", "latestVersion" ], + { + prettyStrings: true, + totalString: "%s application(s) found", + emptyString: "no applications found, please use 'update'", + rename: { + "name" : "Name", + "author" : "Author", + "description" : "Description", + "latestVersion" : "Latest Version" } - ); - }; + } + ); +}; //////////////////////////////////////////////////////////////////////////////// /// @brief gets json-info for an available FOXX application //////////////////////////////////////////////////////////////////////////////// var infoJson = function (name) { - utils.validateAppName(name); +utils.validateAppName(name); - var fishbowl = getFishbowlStorage(); +var fishbowl = getFishbowlStorage(); - if (fishbowl.count() === 0) { - arangodb.print("Repository is empty, please use 'update'"); - return; - } +if (fishbowl.count() === 0) { + arangodb.print("Repository is empty, please use 'update'"); + return; +} - var desc; +var desc; - try { - desc = fishbowl.document(name); - return desc; - } - catch (err) { - arangodb.print("No application '" + name + "' available, please try 'search'"); - return; - } +try { + desc = fishbowl.document(name); + return desc; +} +catch (err) { + arangodb.print("No application '" + name + "' available, please try 'search'"); + return; +} }; //////////////////////////////////////////////////////////////////////////////// /// @brief create a download URL for the given app information //////////////////////////////////////////////////////////////////////////////// - var buildUrl = function(appInfo) { - // TODO Validate - var infoSplit = appInfo.split(":"); - var name = infoSplit[0]; - var version = infoSplit[1]; - var storeInfo = infoJson(name); - if (storeInfo === undefined) { - throw "Application not found"; +var buildUrl = function(appInfo) { + // TODO Validate + var infoSplit = appInfo.split(":"); + var name = infoSplit[0]; + var version = infoSplit[1]; + var storeInfo = infoJson(name); + if (storeInfo === undefined) { + throw "Application not found"; + } + var versions = storeInfo.versions; + var versionInfo; + if (version === undefined) { + versionInfo = versions[extractMaxVersion(versions)]; + } else { + if (!versions.hasOwnProperty(version)) { + throw "Unknown version"; } - var versions = storeInfo.versions; - var versionInfo; - if (version === undefined) { - versionInfo = versions[extractMaxVersion(versions)]; - } else { - if (!versions.hasOwnProperty(version)) { - throw "Unknown version"; - } - versionInfo = versions[version]; - } - return utils.buildGithubUrl(versionInfo.location, versionInfo.tag); - }; + versionInfo = versions[version]; + } + return utils.buildGithubUrl(versionInfo.location, versionInfo.tag); +}; //////////////////////////////////////////////////////////////////////////////// /// @brief prints info for an available FOXX application //////////////////////////////////////////////////////////////////////////////// - var info = function (name) { - var desc = infoJson(name); - arangodb.printf("Name: %s\n", desc.name); +var info = function (name) { + var desc = infoJson(name); + arangodb.printf("Name: %s\n", desc.name); - if (desc.hasOwnProperty('author')) { - arangodb.printf("Author: %s\n", desc.author); + if (desc.hasOwnProperty('author')) { + arangodb.printf("Author: %s\n", desc.author); + } + + var isSystem = desc.hasOwnProperty('isSystem') && desc.isSystem; + arangodb.printf("System: %s\n", JSON.stringify(isSystem)); + + if (desc.hasOwnProperty('description')) { + arangodb.printf("Description: %s\n\n", desc.description); + } + + var header = false; + var versions = Object.keys(desc.versions); + versions.sort(compareVersions); + + versions.forEach(function (v) { + var version = desc.versions[v]; + + if (! header) { + arangodb.print("Versions:"); + header = true; } - var isSystem = desc.hasOwnProperty('isSystem') && desc.isSystem; - arangodb.printf("System: %s\n", JSON.stringify(isSystem)); - - if (desc.hasOwnProperty('description')) { - arangodb.printf("Description: %s\n\n", desc.description); + if (version.type === "github") { + if (version.hasOwnProperty("tag")) { + arangodb.printf('%s: fetch github "%s" "%s"\n', v, version.location, version.tag); + } + else if (v.hasOwnProperty("branch")) { + arangodb.printf('%s: fetch github "%s" "%s"\n', v, version.location, version.branch); + } + else { + arangodb.printf('%s: fetch "github" "%s"\n', v, version.location); + } } + }); - var header = false; - var versions = Object.keys(desc.versions); - versions.sort(compareVersions); - - versions.forEach(function (v) { - var version = desc.versions[v]; - - if (! header) { - arangodb.print("Versions:"); - header = true; - } - - if (version.type === "github") { - if (version.hasOwnProperty("tag")) { - arangodb.printf('%s: fetch github "%s" "%s"\n', v, version.location, version.tag); - } - else if (v.hasOwnProperty("branch")) { - arangodb.printf('%s: fetch github "%s" "%s"\n', v, version.location, version.branch); - } - else { - arangodb.printf('%s: fetch "github" "%s"\n', v, version.location); - } - } - }); - - arangodb.printf("\n"); - }; + arangodb.printf("\n"); +}; // ----------------------------------------------------------------------------- // --SECTION-- export public API // ----------------------------------------------------------------------------- - exports.available = available; - exports.availableJson = availableJson; - exports.buildUrl = buildUrl; - exports.getFishbowlStorage = getFishbowlStorage; - exports.info = info; - exports.search = search; - exports.searchJson = searchJson; - exports.update = update; +exports.available = available; +exports.availableJson = availableJson; +exports.buildUrl = buildUrl; +exports.getFishbowlStorage = getFishbowlStorage; +exports.info = info; +exports.search = search; +exports.searchJson = searchJson; +exports.update = update; - // Temporary export to avoid breaking the client - exports.compareVersions = compareVersions; - -}()); +// Temporary export to avoid breaking the client +exports.compareVersions = compareVersions; // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE diff --git a/js/common/modules/org/arangodb/graph-examples/example-graph.js b/js/common/modules/org/arangodb/graph-examples/example-graph.js index 899c91be08..dd09c64d1a 100644 --- a/js/common/modules/org/arangodb/graph-examples/example-graph.js +++ b/js/common/modules/org/arangodb/graph-examples/example-graph.js @@ -1,4 +1,4 @@ -/*jshint strict: false */ +'use strict'; //////////////////////////////////////////////////////////////////////////////// /// @brief Graph Data for Example @@ -26,92 +26,90 @@ /// @author Michael Hackstein /// @author Copyright 2011-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -(function() { - var Graph = require("org/arangodb/general-graph"); +var Graph = require("org/arangodb/general-graph"); - var createTraversalExample = function() { - var g = Graph._create("knows_graph", - [Graph._relation("knows", "persons", "persons")] - ); - var a = g.persons.save({name: "Alice", _key: "alice"})._id; - var b = g.persons.save({name: "Bob", _key: "bob"})._id; - var c = g.persons.save({name: "Charlie", _key: "charlie"})._id; - var d = g.persons.save({name: "Dave", _key: "dave"})._id; - var e = g.persons.save({name: "Eve", _key: "eve"})._id; - g.knows.save(a, b, {}); - g.knows.save(b, c, {}); - g.knows.save(b, d, {}); - g.knows.save(e, a, {}); - g.knows.save(e, b, {}); - return g; - }; +var createTraversalExample = function() { + var g = Graph._create("knows_graph", + [Graph._relation("knows", "persons", "persons")] + ); + var a = g.persons.save({name: "Alice", _key: "alice"})._id; + var b = g.persons.save({name: "Bob", _key: "bob"})._id; + var c = g.persons.save({name: "Charlie", _key: "charlie"})._id; + var d = g.persons.save({name: "Dave", _key: "dave"})._id; + var e = g.persons.save({name: "Eve", _key: "eve"})._id; + g.knows.save(a, b, {}); + g.knows.save(b, c, {}); + g.knows.save(b, d, {}); + g.knows.save(e, a, {}); + g.knows.save(e, b, {}); + return g; +}; - var createSocialGraph = function() { - var edgeDefinition = []; - edgeDefinition.push(Graph._relation("relation", ["female", "male"], ["female", "male"])); - var g = Graph._create("social", edgeDefinition); - var a = g.female.save({name: "Alice", _key: "alice"}); - var b = g.male.save({name: "Bob", _key: "bob"}); - var c = g.male.save({name: "Charly", _key: "charly"}); - var d = g.female.save({name: "Diana", _key: "diana"}); - g.relation.save(a._id, b._id, {type: "married", _key: "aliceAndBob"}); - g.relation.save(a._id, c._id, {type: "friend", _key: "aliceAndCharly"}); - g.relation.save(c._id, d._id, {type: "married", _key: "charlyAndDiana"}); - g.relation.save(b._id, d._id, {type: "friend", _key: "bobAndDiana"}); - return g; - }; +var createSocialGraph = function() { + var edgeDefinition = []; + edgeDefinition.push(Graph._relation("relation", ["female", "male"], ["female", "male"])); + var g = Graph._create("social", edgeDefinition); + var a = g.female.save({name: "Alice", _key: "alice"}); + var b = g.male.save({name: "Bob", _key: "bob"}); + var c = g.male.save({name: "Charly", _key: "charly"}); + var d = g.female.save({name: "Diana", _key: "diana"}); + g.relation.save(a._id, b._id, {type: "married", _key: "aliceAndBob"}); + g.relation.save(a._id, c._id, {type: "friend", _key: "aliceAndCharly"}); + g.relation.save(c._id, d._id, {type: "married", _key: "charlyAndDiana"}); + g.relation.save(b._id, d._id, {type: "friend", _key: "bobAndDiana"}); + return g; +}; - var createRoutePlannerGraph = function() { - var edgeDefinition = []; - edgeDefinition.push(Graph._relation( - "germanHighway", ["germanCity"], ["germanCity"]) - ); - edgeDefinition.push( - Graph._relation("frenchHighway", ["frenchCity"], ["frenchCity"]) - ); - edgeDefinition.push(Graph._relation( - "internationalHighway", ["frenchCity", "germanCity"], ["frenchCity", "germanCity"]) - ); - var g = Graph._create("routeplanner", edgeDefinition); - var berlin = g.germanCity.save({_key: "Berlin", population : 3000000, isCapital : true}); - var cologne = g.germanCity.save({_key: "Cologne", population : 1000000, isCapital : false}); - var hamburg = g.germanCity.save({_key: "Hamburg", population : 1000000, isCapital : false}); - var lyon = g.frenchCity.save({_key: "Lyon", population : 80000, isCapital : false}); - var paris = g.frenchCity.save({_key: "Paris", population : 4000000, isCapital : true}); - g.germanHighway.save(berlin._id, cologne._id, {distance: 850}); - g.germanHighway.save(berlin._id, hamburg._id, {distance: 400}); - g.germanHighway.save(hamburg._id, cologne._id, {distance: 500}); - g.frenchHighway.save(paris._id, lyon._id, {distance: 550}); - g.internationalHighway.save(berlin._id, lyon._id, {distance: 1100}); - g.internationalHighway.save(berlin._id, paris._id, {distance: 1200}); - g.internationalHighway.save(hamburg._id, paris._id, {distance: 900}); - g.internationalHighway.save(hamburg._id, lyon._id, {distance: 1300}); - g.internationalHighway.save(cologne._id, lyon._id, {distance: 700}); - g.internationalHighway.save(cologne._id, paris._id, {distance: 550}); - return g; - }; +var createRoutePlannerGraph = function() { + var edgeDefinition = []; + edgeDefinition.push(Graph._relation( + "germanHighway", ["germanCity"], ["germanCity"]) + ); + edgeDefinition.push( + Graph._relation("frenchHighway", ["frenchCity"], ["frenchCity"]) + ); + edgeDefinition.push(Graph._relation( + "internationalHighway", ["frenchCity", "germanCity"], ["frenchCity", "germanCity"]) + ); + var g = Graph._create("routeplanner", edgeDefinition); + var berlin = g.germanCity.save({_key: "Berlin", population : 3000000, isCapital : true}); + var cologne = g.germanCity.save({_key: "Cologne", population : 1000000, isCapital : false}); + var hamburg = g.germanCity.save({_key: "Hamburg", population : 1000000, isCapital : false}); + var lyon = g.frenchCity.save({_key: "Lyon", population : 80000, isCapital : false}); + var paris = g.frenchCity.save({_key: "Paris", population : 4000000, isCapital : true}); + g.germanHighway.save(berlin._id, cologne._id, {distance: 850}); + g.germanHighway.save(berlin._id, hamburg._id, {distance: 400}); + g.germanHighway.save(hamburg._id, cologne._id, {distance: 500}); + g.frenchHighway.save(paris._id, lyon._id, {distance: 550}); + g.internationalHighway.save(berlin._id, lyon._id, {distance: 1100}); + g.internationalHighway.save(berlin._id, paris._id, {distance: 1200}); + g.internationalHighway.save(hamburg._id, paris._id, {distance: 900}); + g.internationalHighway.save(hamburg._id, lyon._id, {distance: 1300}); + g.internationalHighway.save(cologne._id, lyon._id, {distance: 700}); + g.internationalHighway.save(cologne._id, paris._id, {distance: 550}); + return g; +}; - var dropGraph = function(name) { - if (Graph._exists(name)) { - return Graph._drop(name, true); - } - }; +var dropGraph = function(name) { + if (Graph._exists(name)) { + return Graph._drop(name, true); + } +}; - var loadGraph = function(name) { - dropGraph(name); - switch (name) { - case "knows_graph": - return createTraversalExample(); - case "routeplanner": - return createRoutePlannerGraph(); - case "social": - return createSocialGraph(); - } +var loadGraph = function(name) { + dropGraph(name); + switch (name) { + case "knows_graph": + return createTraversalExample(); + case "routeplanner": + return createRoutePlannerGraph(); + case "social": + return createSocialGraph(); + } - }; +}; - exports.loadGraph = loadGraph; - exports.dropGraph = dropGraph; -}()); +exports.loadGraph = loadGraph; +exports.dropGraph = dropGraph; diff --git a/js/server/modules/org/arangodb/foxx/arangoApp.js b/js/server/modules/org/arangodb/foxx/arangoApp.js index 9f28817c85..d45f69db00 100644 --- a/js/server/modules/org/arangodb/foxx/arangoApp.js +++ b/js/server/modules/org/arangodb/foxx/arangoApp.js @@ -1,4 +1,4 @@ -/*jshint strict: false */ +'use strict'; //////////////////////////////////////////////////////////////////////////////// /// @brief Foxx application module @@ -28,40 +28,37 @@ /// @author Copyright 2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -(function() { - 'use strict'; - // ----------------------------------------------------------------------------- // --SECTION-- imports // ----------------------------------------------------------------------------- - - var fs = require("fs"); - var internal = require("internal"); - var db = internal.db; - 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; + +var fs = require("fs"); +var internal = require("internal"); +var db = internal.db; +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) { - var res = {}; - if (config !== undefined) { - Object.keys(config).forEach(function (attr) { - if (config[attr].default !== undefined) { - res[attr] = config[attr].default; - } - }); - } - return res; +function applyDefaultConfig(config) { + var res = {}; + if (config !== undefined) { + Object.keys(config).forEach(function (attr) { + if (config[attr].default !== undefined) { + res[attr] = config[attr].default; + } + }); } + return res; +} // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors @@ -71,56 +68,56 @@ // --SECTION-- AppContext // ----------------------------------------------------------------------------- - function AppContext(app) { - var prefix = fs.safeJoin(app._root, app._path); +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._options.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; + 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._options.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 + "'"); } - AppContext.prototype.foxxFilename = function (path) { - return fs.safeJoin(this._prefix, path); - }; + return replaced; +}; - AppContext.prototype.collectionName = function (name) { - var replaced = this.collectionPrefix.replace(/[:\.]+/g, '_') + - name.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64); +AppContext.prototype.collection = function (name) { + return db._collection(this.collectionName(name)); +}; - 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.path = function (name) { + return fs.join(this._prefix, name); +}; - AppContext.prototype.comment = function (str) { - this.comments.push(str); - }; +AppContext.prototype.comment = function (str) { + this.comments.push(str); +}; - AppContext.prototype.clearComments = function () { - this.comments = []; - }; +AppContext.prototype.clearComments = function () { + this.comments = []; +}; // ----------------------------------------------------------------------------- // --SECTION-- ArangoApp @@ -131,7 +128,7 @@ //////////////////////////////////////////////////////////////////////////////// function isSystemMount(mount) { - return (/^\/_/).test(mount); +return (/^\/_/).test(mount); } //////////////////////////////////////////////////////////////////////////////// @@ -139,72 +136,72 @@ function isSystemMount(mount) { //////////////////////////////////////////////////////////////////////////////// function computeRootAppPath(mount, isValidation) { - if (isValidation) { - return ""; - } - if (isSystemMount(mount)) { - return module.systemAppPath(); - } - return module.appPath(); +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, "_") + "_"; +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.configure(cfg); + // Apply the default configuration and ignore all missing options + var cfg = config.options.configuration; + this._options.configuration = applyDefaultConfig(this._manifest.configuration); + this.configure(cfg); - var deps = config.options.dependencies; - this._options.dependencies = {}; - this._dependencies = {}; - this.updateDeps(deps); + 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); + 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); - } + 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 @@ -214,9 +211,9 @@ function computeRootAppPath(mount, isValidation) { /// @brief prints a package //////////////////////////////////////////////////////////////////////////////// - ArangoApp.prototype._PRINT = function (context) { - context.output += '[app "' + this._name + '" (' + this._version + ')]'; - }; +ArangoApp.prototype._PRINT = function (context) { + context.output += '[app "' + this._name + '" (' + this._version + ')]'; +}; // ----------------------------------------------------------------------------- // --SECTION-- public methods @@ -226,216 +223,215 @@ function computeRootAppPath(mount, isValidation) { /// @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; +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; +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; - }; +ArangoApp.prototype.development = function(activate) { + this._isDevelopment = activate; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief set app dependencies //////////////////////////////////////////////////////////////////////////////// - ArangoApp.prototype.updateDeps = function (deps) { - var expected = this._manifest.dependencies; - var invalid = []; +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); + _.each(deps, function (mount, name) { + if (!expected[name]) { + invalid.push("Unexpected dependency " + name); + } + this._options.dependencies[name] = mount; + }, this); + + _.each(this._options.dependencies, function (mount, name) { + Object.defineProperty(this._dependencies, name, { + configurable: true, + enumerable: true, + get: function () { + return require("org/arangodb/foxx").requireApp(mount); } - this._options.dependencies[name] = mount; - }, this); + }); + }, this); - _.each(this._options.dependencies, function (mount, name) { - Object.defineProperty(this._dependencies, name, { - configurable: true, - enumerable: true, - get: function () { - return require("org/arangodb/foxx").requireApp(mount); - } - }); - }, this); - - return invalid; - }; + return invalid; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief set app configuration //////////////////////////////////////////////////////////////////////////////// - ArangoApp.prototype.configure = function(config) { - var expected = this._manifest.configuration; - var invalid = []; - this._options.configuration = this._options.configuration || {}; +ArangoApp.prototype.configure = function(config) { + var expected = this._manifest.configuration; + var invalid = []; + this._options.configuration = this._options.configuration || {}; - _.each(config, function (value, name) { - if (!expected[name]) { - invalid.push("Unexpected Option " + name); + _.each(config, function (value, name) { + if (!expected[name]) { + invalid.push("Unexpected Option " + name); + } else { + var type = expected[name].type; + var result = utils.parameterTypes[type].validate(value); + if (result.error) { + invalid.push(result.error.message.replace(/^"value"/, '"' + name + '"')); } else { - var type = expected[name].type; - var result = utils.parameterTypes[type].validate(value); - if (result.error) { - invalid.push(result.error.message.replace(/^"value"/, '"' + name + '"')); - } else { - this._options.configuration[name] = result.value; - } + this._options.configuration[name] = result.value; } - }, this); + } + }, this); - return invalid; - }; + 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 - }); +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; - }; + }); + 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; - }; +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; - }) || _.any(deps, function (dep) { - return dep.current === undefined; - }); - }; +ArangoApp.prototype.needsConfiguration = function() { + var config = this.getConfiguration(); + var deps = this.getDependencies(); + return _.any(config, function (cfg) { + return cfg.current === undefined; + }) || _.any(deps, function (dep) { + return dep.current === undefined; + }); +}; //////////////////////////////////////////////////////////////////////////////// /// @brief loadAppScript //////////////////////////////////////////////////////////////////////////////// - ArangoApp.prototype.loadAppScript = function (filename, options) { - options = options || {}; +ArangoApp.prototype.loadAppScript = function (filename, options) { + options = options || {}; - var appContext = _.extend({}, options.appContext, this._context); - var full = fs.join(this._root, this._path, filename); + var appContext = _.extend({}, options.appContext, this._context); + var full = fs.join(this._root, this._path, filename); - if (!fs.exists(full)) { - throwFileNotFound(full); + 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; + } +}; - 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; -}()); +exports.ArangoApp = ArangoApp; // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE diff --git a/js/server/modules/org/arangodb/foxx/routing.js b/js/server/modules/org/arangodb/foxx/routing.js index c540a9fc83..e87beca618 100644 --- a/js/server/modules/org/arangodb/foxx/routing.js +++ b/js/server/modules/org/arangodb/foxx/routing.js @@ -1,4 +1,4 @@ -/*jshint strict: false */ +'use strict'; //////////////////////////////////////////////////////////////////////////////// /// @brief Foxx routing @@ -27,24 +27,22 @@ /// @author Copyright 2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -(function() { - 'use strict'; // ----------------------------------------------------------------------------- // --SECTION-- Imports // ----------------------------------------------------------------------------- - var arangodb = require("org/arangodb"); - var ArangoError = arangodb.ArangoError; - var errors = arangodb.errors; - var preprocess = require("org/arangodb/foxx/preprocessor").preprocess; - var _ = require("underscore"); - var fs = require("fs"); - var is = require("org/arangodb/is"); - var console = require("console"); - var actions = require("org/arangodb/actions"); +var arangodb = require("org/arangodb"); +var ArangoError = arangodb.ArangoError; +var errors = arangodb.errors; +var preprocess = require("org/arangodb/foxx/preprocessor").preprocess; +var _ = require("underscore"); +var fs = require("fs"); +var is = require("org/arangodb/is"); +var console = require("console"); +var actions = require("org/arangodb/actions"); - var exportCache = {}; +var exportCache = {}; // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -53,370 +51,370 @@ //////////////////////////////////////////////////////////////////////////////// /// @brief excludes certain files //////////////////////////////////////////////////////////////////////////////// - - var excludeFile = function (name) { - var parts = name.split('/'); - if (parts.length > 0) { - var last = parts[parts.length - 1]; +var excludeFile = function (name) { + var parts = name.split('/'); - // exclude all files starting with . - if (last[0] === '.') { - return true; - } + if (parts.length > 0) { + var last = parts[parts.length - 1]; + + // exclude all files starting with . + if (last[0] === '.') { + return true; } + } - return false; - }; + return false; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief builds one asset of an app //////////////////////////////////////////////////////////////////////////////// - var buildAssetContent = function(app, assets, basePath) { - var i, j, m; +var buildAssetContent = function(app, assets, basePath) { + var i, j, m; - var reSub = /(.*)\/\*\*$/; - var reAll = /(.*)\/\*$/; + var reSub = /(.*)\/\*\*$/; + var reAll = /(.*)\/\*$/; - var files = []; + var files = []; - for (j = 0; j < assets.length; ++j) { - var asset = assets[j]; - var match = reSub.exec(asset); + for (j = 0; j < assets.length; ++j) { + var asset = assets[j]; + var match = reSub.exec(asset); + + if (match !== null) { + m = fs.listTree(fs.join(basePath, match[1])); + + // files are sorted in file-system order. + // this makes the order non-portable + // we'll be sorting the files now using JS sort + // so the order is more consistent across multiple platforms + m.sort(); + + for (i = 0; i < m.length; ++i) { + var filename = fs.join(basePath, match[1], m[i]); + + if (! excludeFile(m[i])) { + if (fs.isFile(filename)) { + files.push(filename); + } + } + } + } + else { + match = reAll.exec(asset); if (match !== null) { - m = fs.listTree(fs.join(basePath, match[1])); - - // files are sorted in file-system order. - // this makes the order non-portable - // we'll be sorting the files now using JS sort - // so the order is more consistent across multiple platforms - m.sort(); - - for (i = 0; i < m.length; ++i) { - var filename = fs.join(basePath, match[1], m[i]); - - if (! excludeFile(m[i])) { - if (fs.isFile(filename)) { - files.push(filename); - } - } - } + throw new Error("Not implemented"); } else { - match = reAll.exec(asset); - - if (match !== null) { - throw new Error("Not implemented"); - } - else { - if (! excludeFile(asset)) { - files.push(fs.join(basePath, asset)); - } + if (! excludeFile(asset)) { + files.push(fs.join(basePath, asset)); } } } + } - var content = ""; + var content = ""; - for (i = 0; i < files.length; ++i) { - try { - var c = fs.read(files[i]); + for (i = 0; i < files.length; ++i) { + try { + var c = fs.read(files[i]); - content += c + "\n"; - } - catch (err) { - console.error("Cannot read asset '%s'", files[i]); - } + content += c + "\n"; } + catch (err) { + console.error("Cannot read asset '%s'", files[i]); + } + } + + return content; +}; - return content; - }; - //////////////////////////////////////////////////////////////////////////////// /// @brief installs an asset for an app //////////////////////////////////////////////////////////////////////////////// - var buildFileAsset = function(app, path, basePath, asset) { - var content = buildAssetContent(app, asset.files, basePath); - var type; +var buildFileAsset = function(app, path, basePath, asset) { + var content = buildAssetContent(app, asset.files, basePath); + var type; - // ............................................................................. - // content-type detection - // ............................................................................. + // ............................................................................. + // content-type detection + // ............................................................................. - // contentType explicitly specified for asset - if (asset.contentType) { - type = asset.contentType; - } + // contentType explicitly specified for asset + if (asset.contentType) { + type = asset.contentType; + } - // path contains a dot, derive content type from path - else if (path.match(/\.[a-zA-Z0-9]+$/)) { - type = arangodb.guessContentType(path); - } + // path contains a dot, derive content type from path + else if (path.match(/\.[a-zA-Z0-9]+$/)) { + type = arangodb.guessContentType(path); + } - // path does not contain a dot, - // derive content type from included asset names - else if (asset.files.length > 0) { - type = arangodb.guessContentType(asset.files[0]); - } + // path does not contain a dot, + // derive content type from included asset names + else if (asset.files.length > 0) { + type = arangodb.guessContentType(asset.files[0]); + } - // use built-in defaulti content-type - else { - type = arangodb.guessContentType(""); - } + // use built-in defaulti content-type + else { + type = arangodb.guessContentType(""); + } - // ............................................................................. - // return content - // ............................................................................. + // ............................................................................. + // return content + // ............................................................................. - return { contentType: type, body: content }; - }; + return { contentType: type, body: content }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief generates asset action //////////////////////////////////////////////////////////////////////////////// - var buildAssetRoute = function (app, path, basePath, asset) { - var c = buildFileAsset(app, path, basePath, asset); +var buildAssetRoute = function (app, path, basePath, asset) { + var c = buildFileAsset(app, path, basePath, asset); - return { - url: { match: path }, - content: { contentType: c.contentType, body: c.body } - }; + return { + url: { match: path }, + content: { contentType: c.contentType, body: c.body } }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief installs the assets of an app //////////////////////////////////////////////////////////////////////////////// - var installAssets = function (app, routes) { - var path; +var installAssets = function (app, routes) { + var path; - var desc = app._manifest; + var desc = app._manifest; - if (! desc) { - throw new Error("Invalid application manifest"); - } + if (! desc) { + throw new Error("Invalid application manifest"); + } - var normalized; - var route; + var normalized; + var route; - if (desc.hasOwnProperty('assets')) { - for (path in desc.assets) { - if (desc.assets.hasOwnProperty(path)) { - var asset = desc.assets[path]; - var basePath = fs.join(app._root, app._path); + if (desc.hasOwnProperty('assets')) { + for (path in desc.assets) { + if (desc.assets.hasOwnProperty(path)) { + var asset = desc.assets[path]; + var basePath = fs.join(app._root, app._path); - if (asset.hasOwnProperty('basePath')) { - basePath = asset.basePath; - } - - normalized = arangodb.normalizeURL("/" + path); - - if (asset.hasOwnProperty('files')) { - route = buildAssetRoute(app, normalized, basePath, asset); - routes.routes.push(route); - } + if (asset.hasOwnProperty('basePath')) { + basePath = asset.basePath; } - } - } - if (desc.hasOwnProperty('files')) { - for (path in desc.files) { - if (desc.files.hasOwnProperty(path)) { - var directory = desc.files[path]; - - normalized = arangodb.normalizeURL("/" + path); - - route = { - url: { match: normalized + "/*" }, - action: { - "do": "org/arangodb/actions/pathHandler", - "options": { - root: app._root, - path: fs.join(app._path, directory) - } - } - }; + normalized = arangodb.normalizeURL("/" + path); + if (asset.hasOwnProperty('files')) { + route = buildAssetRoute(app, normalized, basePath, asset); routes.routes.push(route); } } } - }; + } + + if (desc.hasOwnProperty('files')) { + for (path in desc.files) { + if (desc.files.hasOwnProperty(path)) { + var directory = desc.files[path]; + + normalized = arangodb.normalizeURL("/" + path); + + route = { + url: { match: normalized + "/*" }, + action: { + "do": "org/arangodb/actions/pathHandler", + "options": { + root: app._root, + path: fs.join(app._path, directory) + } + } + }; + + routes.routes.push(route); + } + } + } +}; //////////////////////////////////////////////////////////////////////////////// /// @brief returns the transform script //////////////////////////////////////////////////////////////////////////////// - var transformScript = function (file) { - if (/\.coffee$/.test(file)) { - return function (content) { - return preprocess(content, "coffee"); - }; - } +var transformScript = function (file) { + if (/\.coffee$/.test(file)) { + return function (content) { + return preprocess(content, "coffee"); + }; + } - return preprocess; - }; + return preprocess; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief create middleware matchers //////////////////////////////////////////////////////////////////////////////// - var createMiddlewareMatchers = function (rt, routes, controller, prefix) { - var j, route; - for (j = 0; j < rt.length; ++j) { - route = rt[j]; - if (route.hasOwnProperty("url")) { - route.url.match = arangodb.normalizeURL(prefix + "/" + route.url.match); - } - route.context = controller; - routes.middleware.push(route); +var createMiddlewareMatchers = function (rt, routes, controller, prefix) { + var j, route; + for (j = 0; j < rt.length; ++j) { + route = rt[j]; + if (route.hasOwnProperty("url")) { + route.url.match = arangodb.normalizeURL(prefix + "/" + route.url.match); } - }; + route.context = controller; + routes.middleware.push(route); + } +}; //////////////////////////////////////////////////////////////////////////////// /// @brief transform the internal route objects into proper routing callbacks //////////////////////////////////////////////////////////////////////////////// - var transformControllerToRoute = function (routeInfo, route, isDevel) { - return function (req, res) { - var i, errInfo, tmp; - try { - // Check constraints - if (routeInfo.hasOwnProperty("constraints")) { - var constraints = routeInfo.constraints; - try { - _.each({ - urlParameters: constraints.urlParams, - parameters: constraints.queryParams - }, function (paramConstraints, paramsPropertyName) { - var params = req[paramsPropertyName]; - _.each(paramConstraints, function (constraint, paramName) { - var result = constraint.validate(params[paramName]); - params[paramName] = result.value; - if (result.error) { - result.error.message = 'Invalid value for "' + paramName + '": ' + result.error.message; - throw result.error; - } - }); +var transformControllerToRoute = function (routeInfo, route, isDevel) { + return function (req, res) { + var i, errInfo, tmp; + try { + // Check constraints + if (routeInfo.hasOwnProperty("constraints")) { + var constraints = routeInfo.constraints; + try { + _.each({ + urlParameters: constraints.urlParams, + parameters: constraints.queryParams + }, function (paramConstraints, paramsPropertyName) { + var params = req[paramsPropertyName]; + _.each(paramConstraints, function (constraint, paramName) { + var result = constraint.validate(params[paramName]); + params[paramName] = result.value; + if (result.error) { + result.error.message = 'Invalid value for "' + paramName + '": ' + result.error.message; + throw result.error; + } }); - } catch (err) { - actions.resultBad(req, res, actions.HTTP_BAD, err.message); - return; - } + }); + } catch (err) { + actions.resultBad(req, res, actions.HTTP_BAD, err.message); + return; } - // Apply request checks - for (i = 0; i < routeInfo.checks.length; ++i) { - routeInfo.checks[i].check(req); - } - // Add Body Params - for (i = 0; i < routeInfo.bodyParams.length; ++i) { - tmp = routeInfo.bodyParams[i]; - req.parameters[tmp.paramName] = tmp.construct(tmp.extract(req)); - } - routeInfo.callback(req, res); - } catch (e) { - for (i = 0; i < routeInfo.errorResponses.length; ++i) { - errInfo = routeInfo.errorResponses[i]; - if ( - (typeof errInfo.errorClass === 'string' && e.name === errInfo.errorClass) || - (typeof errInfo.errorClass === 'function' && e instanceof errInfo.errorClass) - ) { - res.status(errInfo.code); - if (is.notExisty(errInfo.errorHandler)) { - res.json({error: errInfo.reason}); - } else { - res.json(errInfo.errorHandler(e)); - } - return; - } - } - // Default Error Handler - var body = { - error: e.message || String(e) - }; - if (isDevel) { - body.stack = e.stack; - } - res.status(500); - res.json(body); - console.errorLines("Error in foxx route '%s': '%s', Stacktrace: %s", - route, e.message || String(e), e.stack || ""); } - }; + // Apply request checks + for (i = 0; i < routeInfo.checks.length; ++i) { + routeInfo.checks[i].check(req); + } + // Add Body Params + for (i = 0; i < routeInfo.bodyParams.length; ++i) { + tmp = routeInfo.bodyParams[i]; + req.parameters[tmp.paramName] = tmp.construct(tmp.extract(req)); + } + routeInfo.callback(req, res); + } catch (e) { + for (i = 0; i < routeInfo.errorResponses.length; ++i) { + errInfo = routeInfo.errorResponses[i]; + if ( + (typeof errInfo.errorClass === 'string' && e.name === errInfo.errorClass) || + (typeof errInfo.errorClass === 'function' && e instanceof errInfo.errorClass) + ) { + res.status(errInfo.code); + if (is.notExisty(errInfo.errorHandler)) { + res.json({error: errInfo.reason}); + } else { + res.json(errInfo.errorHandler(e)); + } + return; + } + } + // Default Error Handler + var body = { + error: e.message || String(e) + }; + if (isDevel) { + body.stack = e.stack; + } + res.status(500); + res.json(body); + console.errorLines("Error in foxx route '%s': '%s', Stacktrace: %s", + route, e.message || String(e), e.stack || ""); + } }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief transform the internal route objects into proper routing callbacks //////////////////////////////////////////////////////////////////////////////// - var transformRoutes = function (rt, routes, controller, prefix, isDevel) { - var j, route; - for (j = 0; j < rt.length; ++j) { - route = rt[j]; - route.action = { - callback: transformControllerToRoute(route.action, route.url || "No Route", isDevel) - }; - if (route.hasOwnProperty("url")) { - route.url.match = arangodb.normalizeURL(prefix + "/" + route.url.match); - } - route.context = controller; - routes.routes.push(route); +var transformRoutes = function (rt, routes, controller, prefix, isDevel) { + var j, route; + for (j = 0; j < rt.length; ++j) { + route = rt[j]; + route.action = { + callback: transformControllerToRoute(route.action, route.url || "No Route", isDevel) + }; + if (route.hasOwnProperty("url")) { + route.url.match = arangodb.normalizeURL(prefix + "/" + route.url.match); } - }; + route.context = controller; + routes.routes.push(route); + } +}; - var routeRegEx = /^(\/:?[a-zA-Z0-9_\-%]+)+\/?$/; +var routeRegEx = /^(\/:?[a-zA-Z0-9_\-%]+)+\/?$/; - var validateRoute = function(route) { - if (route[0] !== "/") { +var validateRoute = function(route) { + if (route[0] !== "/") { + throw new ArangoError({ + errorNum: errors.ERROR_INVALID_MOUNTPOINT.code, + errorMessage: "Route has to start with /." + }); + } + if (!routeRegEx.test(route)) { + // Controller routes may be /. Foxxes are not allowed to + if (route.length !== 1) { throw new ArangoError({ errorNum: errors.ERROR_INVALID_MOUNTPOINT.code, - errorMessage: "Route has to start with /." + errorMessage: "Route parts '" + route + "' may only contain a-z, A-Z, 0-9 or _. But may start with a :" }); } - if (!routeRegEx.test(route)) { - // Controller routes may be /. Foxxes are not allowed to - if (route.length !== 1) { - throw new ArangoError({ - errorNum: errors.ERROR_INVALID_MOUNTPOINT.code, - errorMessage: "Route parts '" + route + "' may only contain a-z, A-Z, 0-9 or _. But may start with a :" - }); - } - } - }; + } +}; //////////////////////////////////////////////////////////////////////////////// /// @brief Checks if an apps exports are already cached //////////////////////////////////////////////////////////////////////////////// - var isExported = function(mount) { - var dbname = arangodb.db._name(); - if (!exportCache.hasOwnProperty(dbname)) { - exportCache[dbname] = {}; - return false; - } - if (!exportCache[dbname].hasOwnProperty(mount)) { - return false; - } - return true; - }; +var isExported = function(mount) { + var dbname = arangodb.db._name(); + if (!exportCache.hasOwnProperty(dbname)) { + exportCache[dbname] = {}; + return false; + } + if (!exportCache[dbname].hasOwnProperty(mount)) { + return false; + } + return true; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief Checks if an apps exports are already cached //////////////////////////////////////////////////////////////////////////////// - var setIsExported = function(mount) { - var dbname = arangodb.db._name(); - if (!exportCache.hasOwnProperty(dbname)) { - exportCache[dbname] = {}; - } - exportCache[dbname][mount] = true; - }; +var setIsExported = function(mount) { + var dbname = arangodb.db._name(); + if (!exportCache.hasOwnProperty(dbname)) { + exportCache[dbname] = {}; + } + exportCache[dbname][mount] = true; +}; // ----------------------------------------------------------------------------- // --SECTION-- public functions @@ -426,158 +424,158 @@ /// @brief computes the exports of an app //////////////////////////////////////////////////////////////////////////////// - var exportApp = function (app) { - if (app.needsConfiguration()) { - throw new ArangoError({ - errorNum: errors.ERROR_APP_NEEDS_CONFIGURATION.code, - errorMessage: errors.ERROR_APP_NEEDS_CONFIGURATION.message +var exportApp = function (app) { + if (app.needsConfiguration()) { + throw new ArangoError({ + errorNum: errors.ERROR_APP_NEEDS_CONFIGURATION.code, + errorMessage: errors.ERROR_APP_NEEDS_CONFIGURATION.message + }); + } + if (!app._isDevelopment && isExported(app._mount)) { + return app._exports; + } + + app._exports = {}; + + // mount all exports + if (app._manifest.hasOwnProperty("exports")) { + var appExports = app._manifest.exports; + + if (typeof appExports === "string") { + app._exports = app.loadAppScript(appExports); + } else if (appExports) { + Object.keys(appExports).forEach(function (key) { + app._exports[key] = app.loadAppScript(appExports[key]); }); } - if (!app._isDevelopment && isExported(app._mount)) { - return app._exports; - } + } + setIsExported(app._mount); + return app._exports; - app._exports = {}; - - // mount all exports - if (app._manifest.hasOwnProperty("exports")) { - var appExports = app._manifest.exports; - - if (typeof appExports === "string") { - app._exports = app.loadAppScript(appExports); - } else if (appExports) { - Object.keys(appExports).forEach(function (key) { - app._exports[key] = app.loadAppScript(appExports[key]); - }); - } - } - setIsExported(app._mount); - return app._exports; - - }; +}; //////////////////////////////////////////////////////////////////////////////// /// @brief computes the exports of an app //////////////////////////////////////////////////////////////////////////////// - var invalidateExportCache = function () { - exportCache = {}; - }; +var invalidateExportCache = function () { + exportCache = {}; +}; - //////////////////////////////////////////////////////////////////////////////// - ///// @brief escapes all html reserved characters that are not allowed in
-  //////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+///// @brief escapes all html reserved characters that are not allowed in 
+//////////////////////////////////////////////////////////////////////////////////
 function escapeHTML (string) {
-  var list = string.split("");
-  var i = 0;
-  for (i = 0; i < list.length; ++i) {
-    switch (list[i]) {
-      case "'":
-      list[i] = "'";
-      break;
-      case '"':
-      list[i] = """;
-      break;
-      case "&":
-      list[i] = "&";
-      break;
-      case "<":
-      list[i] = "<";
-      break;
-      case ">":
-      list[i] = ">";
-      break;
-      default:
-    }
+var list = string.split("");
+var i = 0;
+for (i = 0; i < list.length; ++i) {
+  switch (list[i]) {
+    case "'":
+    list[i] = "'";
+    break;
+    case '"':
+    list[i] = """;
+    break;
+    case "&":
+    list[i] = "&";
+    break;
+    case "<":
+    list[i] = "<";
+    break;
+    case ">":
+    list[i] = ">";
+    break;
+    default:
   }
-  return list.join("");
+}
+return list.join("");
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 /// @brief routes a default Configuration Required app
 ////////////////////////////////////////////////////////////////////////////////
 
-  var routeNeedsConfigurationApp = function(app) {
+var routeNeedsConfigurationApp = function(app) {
 
-    return {
-      urlPrefix: "",
-      name: 'foxx("' + app._mount + '")',
-      routes: [{
-        "internal": true,
-        "url" : {
-          match: "/*",
-          methods: actions.ALL_METHODS
-        },
-        "action": {
-          "callback": function(req, res) {
-            res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE;
-            res.contentType = "text/html; charset=utf-8";
-            if (app._isDevelopment) {
-              res.body = "Service Unavailable

" + - "This service is not configured.

"; - res.body += "

Configuration Information

"; - res.body += "
";
-              res.body += escapeHTML(JSON.stringify(app.getConfiguration(), undefined, 2));
-              res.body += "
"; - res.budy += ""; + return { + urlPrefix: "", + name: 'foxx("' + app._mount + '")', + routes: [{ + "internal": true, + "url" : { + match: "/*", + methods: actions.ALL_METHODS + }, + "action": { + "callback": function(req, res) { + res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE; + res.contentType = "text/html; charset=utf-8"; + if (app._isDevelopment) { + res.body = "Service Unavailable

" + + "This service is not configured.

"; + res.body += "

Configuration Information

"; + res.body += "
";
+            res.body += escapeHTML(JSON.stringify(app.getConfiguration(), undefined, 2));
+            res.body += "
"; + res.budy += ""; - } else { - res.body = "Service Unavailable

" + - "This service is not configured.

"; + } else { + res.body = "Service Unavailable

" + + "This service is not configured.

"; - } - return; } + return; } - }], - middleware: [], - context: {}, - models: {}, + } + }], + middleware: [], + context: {}, + models: {}, - foxx: true - }; - + foxx: true }; + +}; //////////////////////////////////////////////////////////////////////////////// /// @brief routes this app if the original is broken app //////////////////////////////////////////////////////////////////////////////// - var routeBrokenApp = function(app, err) { +var routeBrokenApp = function(app, err) { - return { - urlPrefix: "", - name: 'foxx("' + app._mount + '")', - routes: [{ - "internal": true, - "url" : { - match: "/*", - methods: actions.ALL_METHODS - }, - "action": { - "callback": function(req, res) { - res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE; - res.contentType = "text/html; charset=utf-8"; - if (app._isDevelopment) { - res.body = "" + escapeHTML(String(err)) + - "
" + escapeHTML(String(err.stack)) + "
"; - } else { - res.body = "Service Unavailable

" + - "This service is temporarily not available. Please check the log file for errors.

"; + return { + urlPrefix: "", + name: 'foxx("' + app._mount + '")', + routes: [{ + "internal": true, + "url" : { + match: "/*", + methods: actions.ALL_METHODS + }, + "action": { + "callback": function(req, res) { + res.responseCode = actions.HTTP_SERVICE_UNAVAILABLE; + res.contentType = "text/html; charset=utf-8"; + if (app._isDevelopment) { + res.body = "" + escapeHTML(String(err)) + + "
" + escapeHTML(String(err.stack)) + "
"; + } else { + res.body = "Service Unavailable

" + + "This service is temporarily not available. Please check the log file for errors.

"; - } - return; } + return; } - }], - middleware: [], - context: {}, - models: {}, + } + }], + middleware: [], + context: {}, + models: {}, - foxx: true - }; - + foxx: true }; + +}; @@ -585,116 +583,115 @@ function escapeHTML (string) { /// @brief computes the routes of an app //////////////////////////////////////////////////////////////////////////////// - var routeApp = function (app, isInstallProcess) { - if (app.needsConfiguration()) { - return routeNeedsConfigurationApp(app); +var routeApp = function (app, isInstallProcess) { + if (app.needsConfiguration()) { + return routeNeedsConfigurationApp(app); + } + + var defaultDocument = app._manifest.defaultDocument; + + // setup the routes + var routes = { + urlPrefix: "", + name: 'foxx("' + app._mount + '")', + routes: [], + middleware: [], + context: {}, + models: {}, + + foxx: true, + + appContext: { + app: app, + module: app._context.appModule } + }; - var defaultDocument = app._manifest.defaultDocument; - - // setup the routes - var routes = { - urlPrefix: "", - name: 'foxx("' + app._mount + '")', - routes: [], - middleware: [], - context: {}, - models: {}, - - foxx: true, - - appContext: { - app: app, - module: app._context.appModule - } - }; - - if ((app._mount + defaultDocument) !== app._mount) { - // only add redirection if src and target are not the same - routes.routes.push({ - "url" : { match: "/" }, - "action" : { - "do" : "org/arangodb/actions/redirectRequest", - "options" : { - "permanently" : !app._isDevelopment, - "destination" : defaultDocument, - "relative" : true - } + if ((app._mount + defaultDocument) !== app._mount) { + // only add redirection if src and target are not the same + routes.routes.push({ + "url" : { match: "/" }, + "action" : { + "do" : "org/arangodb/actions/redirectRequest", + "options" : { + "permanently" : !app._isDevelopment, + "destination" : defaultDocument, + "relative" : true } + } + }); + } + + // mount all controllers + var controllers = app._manifest.controllers; + + try { + if (controllers) { + Object.keys(controllers).forEach(function (key) { + mountController(app, routes, key, controllers[key]); }); } - // mount all controllers - var controllers = app._manifest.controllers; + // install all files and assets + installAssets(app, routes); - try { - if (controllers) { - Object.keys(controllers).forEach(function (key) { - mountController(app, routes, key, controllers[key]); - }); - } - - // install all files and assets - installAssets(app, routes); - - // return the new routes - return routes; - } catch (e) { - console.error("Cannot compute Foxx application routes: %s", String(e)); - if (e.hasOwnProperty("stack")) { - console.errorLines(e.stack); - } - if (isInstallProcess) { - throw e; - } - return routeBrokenApp(app, e); + // return the new routes + return routes; + } catch (e) { + console.error("Cannot compute Foxx application routes: %s", String(e)); + if (e.hasOwnProperty("stack")) { + console.errorLines(e.stack); } - return null; + if (isInstallProcess) { + throw e; + } + return routeBrokenApp(app, e); + } + return null; +}; + +var mountController = function (app, routes, mountPoint, file) { + validateRoute(mountPoint); + + // set up a context for the application start function + var tmpContext = { + prefix: arangodb.normalizeURL("/" + mountPoint), // app mount + foxxes: [] }; - var mountController = function (app, routes, mountPoint, file) { - validateRoute(mountPoint); + app.loadAppScript(file, { + transform: transformScript(file), + appContext: tmpContext + }); - // set up a context for the application start function - var tmpContext = { - prefix: arangodb.normalizeURL("/" + mountPoint), // app mount - foxxes: [] - }; + // ............................................................................. + // routingInfo + // ............................................................................. - app.loadAppScript(file, { - transform: transformScript(file), - appContext: tmpContext - }); + var foxxes = tmpContext.foxxes; + for (var i = 0; i < foxxes.length; i++) { + var foxx = foxxes[i]; + var ri = foxx.routingInfo; - // ............................................................................. - // routingInfo - // ............................................................................. + _.extend(routes.models, foxx.models); - var foxxes = tmpContext.foxxes; - for (var i = 0; i < foxxes.length; i++) { - var foxx = foxxes[i]; - var ri = foxx.routingInfo; - - _.extend(routes.models, foxx.models); - - if (ri.hasOwnProperty("middleware")) { - createMiddlewareMatchers(ri.middleware, routes, mountPoint, ri.urlPrefix); - } - if (ri.hasOwnProperty("routes")) { - transformRoutes(ri.routes, routes, mountPoint, ri.urlPrefix, tmpContext.isDevelopment); - } + if (ri.hasOwnProperty("middleware")) { + createMiddlewareMatchers(ri.middleware, routes, mountPoint, ri.urlPrefix); } - }; + if (ri.hasOwnProperty("routes")) { + transformRoutes(ri.routes, routes, mountPoint, ri.urlPrefix, tmpContext.isDevelopment); + } + } +}; // ----------------------------------------------------------------------------- // --SECTION-- Exports // ----------------------------------------------------------------------------- - exports.exportApp = exportApp; - exports.routeApp = routeApp; - exports.invalidateExportCache = invalidateExportCache; - exports.__test_transformControllerToRoute = transformControllerToRoute; -}()); +exports.exportApp = exportApp; +exports.routeApp = routeApp; +exports.invalidateExportCache = invalidateExportCache; +exports.__test_transformControllerToRoute = transformControllerToRoute; // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE diff --git a/js/server/modules/org/arangodb/foxx/sessions.js b/js/server/modules/org/arangodb/foxx/sessions.js index 1ed1a7a94a..d39ca31533 100644 --- a/js/server/modules/org/arangodb/foxx/sessions.js +++ b/js/server/modules/org/arangodb/foxx/sessions.js @@ -174,9 +174,6 @@ function Sessions(opts) { if (opts.cookie.secret && typeof opts.cookie.secret !== 'string') { throw new Error('Cookie secret must be a string or empty.'); } - if (!opts.cookie.name) { - opts.cookie.name = 'sid'; - } } else if (opts.type === 'header') { if (opts.header && typeof opts.header !== 'string') { throw new Error('Header name must be a string or empty.'); diff --git a/js/server/modules/org/arangodb/foxx/swaggerDocs.js b/js/server/modules/org/arangodb/foxx/swaggerDocs.js index e46b943bb6..f0268ee2c8 100644 --- a/js/server/modules/org/arangodb/foxx/swaggerDocs.js +++ b/js/server/modules/org/arangodb/foxx/swaggerDocs.js @@ -1,3 +1,4 @@ +'use strict'; //////////////////////////////////////////////////////////////////////////////// /// @brief Foxx Swagger documentation @@ -26,67 +27,63 @@ /// @author Copyright 2015, ArangoDB GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -(function() { - 'use strict'; +var foxxInternal = require("org/arangodb/foxx/internals"); +var _ = require("underscore"); +var internal = require("internal"); - var foxxInternal = require("org/arangodb/foxx/internals"); - var _ = require("underscore"); - var internal = require("internal"); +// Wraps the docs object of a route to add swagger compatible documentation +var SwaggerDocs = function (docs, models) { + this.docs = docs; + this.models = models; +}; - // Wraps the docs object of a route to add swagger compatible documentation - var SwaggerDocs = function (docs, models) { - this.docs = docs; - this.models = models; - }; +SwaggerDocs.prototype.addNickname = function (httpMethod, match) { + this.docs.nickname = foxxInternal.constructNickname(httpMethod, match); +}; - SwaggerDocs.prototype.addNickname = function (httpMethod, match) { - this.docs.nickname = foxxInternal.constructNickname(httpMethod, match); - }; +SwaggerDocs.prototype.addPathParam = function (paramName, description, dataType, required) { + this.docs.parameters.push(foxxInternal.constructPathParamDoc(paramName, description, dataType, required)); +}; - SwaggerDocs.prototype.addPathParam = function (paramName, description, dataType, required) { - this.docs.parameters.push(foxxInternal.constructPathParamDoc(paramName, description, dataType, required)); - }; +SwaggerDocs.prototype.addQueryParam = function (paramName, description, dataType, required, allowMultiple) { + this.docs.parameters.push(foxxInternal.constructQueryParamDoc( + paramName, + description, + dataType, + required, + allowMultiple + )); +}; - SwaggerDocs.prototype.addQueryParam = function (paramName, description, dataType, required, allowMultiple) { - this.docs.parameters.push(foxxInternal.constructQueryParamDoc( - paramName, - description, - dataType, - required, - allowMultiple - )); - }; +SwaggerDocs.prototype.addBodyParam = function (paramName, description, jsonSchema) { - SwaggerDocs.prototype.addBodyParam = function (paramName, description, jsonSchema) { + var token = internal.genRandomAlphaNumbers(32); + this.models[token] = jsonSchema; - var token = internal.genRandomAlphaNumbers(32); - this.models[token] = jsonSchema; + var param = _.find(this.docs.parameters, function (parameter) { + return parameter.name === 'undocumented body'; + }); - var param = _.find(this.docs.parameters, function (parameter) { - return parameter.name === 'undocumented body'; + if (_.isUndefined(param)) { + this.docs.parameters.push({ + name: paramName, + paramType: "body", + description: description, + dataType: token }); + } else { + param.name = paramName; + param.description = description; + param.dataType = token; + } +}; - if (_.isUndefined(param)) { - this.docs.parameters.push({ - name: paramName, - paramType: "body", - description: description, - dataType: token - }); - } else { - param.name = paramName; - param.description = description; - param.dataType = token; - } - }; +SwaggerDocs.prototype.addSummary = function (summary) { + this.docs.summary = summary; +}; - SwaggerDocs.prototype.addSummary = function (summary) { - this.docs.summary = summary; - }; - - SwaggerDocs.prototype.addNotes = function (notes) { - this.docs.notes = notes; - }; +SwaggerDocs.prototype.addNotes = function (notes) { + this.docs.notes = notes; +}; exports.Docs = SwaggerDocs; -}());