1
0
Fork 0
arangodb/js/apps/system/_admin/aardvark/APP/foxxes.js

426 lines
13 KiB
JavaScript

/*global applicationContext */
"use strict";
////////////////////////////////////////////////////////////////////////////////
/// @brief A Foxx.Controller to show all Foxx Applications
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Michael Hackstein
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
(function() {
var internal = require("internal");
var db = require("org/arangodb").db;
var NotFound = require("http-errors").NotFound;
var FoxxController = require("org/arangodb/foxx").Controller;
var UnauthorizedError = require("http-errors").Unauthorized;
var controller = new FoxxController(applicationContext);
var ArangoError = require("org/arangodb").ArangoError;
var FoxxManager = require("org/arangodb/foxx/manager");
var fmUtils = require("org/arangodb/foxx/manager-utils");
var actions = require("org/arangodb/actions");
var joi = require("joi");
var marked = require("marked");
var highlightAuto = require("highlight.js").highlightAuto;
var docu = require("./lib/swagger").Swagger;
var underscore = require("underscore");
var mountPoint = {
type: joi.string().required().description(
"The mount point of the app. Has to be url-encoded."
)
};
var scriptName = {
type: joi.string().required().description(
"The name of an app's script to run."
)
};
var fs = require("fs");
var defaultThumb = require("/lib/defaultThumbnail").defaultThumb;
controller.activateSessions({
autoCreateSession: false,
cookie: {name: "arango_sid_" + db._name()}
});
controller.allRoutes
.errorResponse(UnauthorizedError, 401, "unauthorized")
.onlyIf(function (req, res) {
if (!internal.options()["server.disable-authentication"] && (!req.session || !req.session.get('uid'))) {
throw new UnauthorizedError();
}
});
controller.extend({
installer: function() {
this.queryParam("mount", mountPoint);
this.queryParam("upgrade", {type: joi.boolean().optional().description(
"Trigger to upgrade the app installed at the mountpoint. Triggers setup."
)});
this.queryParam("replace", {type: joi.boolean().optional().description(
"Trigger to replace the app installed at the mountpoint. Triggers teardown and setup."
)});
}
});
// ------------------------------------------------------------
// SECTION install
// ------------------------------------------------------------
var validateMount = function(req) {
var mount = req.params("mount");
// Validation
mount = decodeURIComponent(mount);
return mount;
};
var installApp = function(req, res, appInfo, options) {
var mount = validateMount(req);
var upgrade = req.params("upgrade") || false;
var replace = req.params("replace") || false;
var app;
if (upgrade) {
app = FoxxManager.upgrade(appInfo, mount, options);
} else if (replace) {
app = FoxxManager.replace(appInfo, mount, options);
} else {
app = FoxxManager.install(appInfo, mount, options);
}
var config = FoxxManager.configuration(mount);
res.json({
error: false,
configuration: config,
name: app.name,
version: app.version
});
};
/** Install a Foxx from the store
*
* Downloads a Foxx from the store and installs it at the given mount
*/
controller.put("/store", function(req, res) {
var content = JSON.parse(req.requestBody),
name = content.name,
version = content.version;
installApp(req, res, name + ":" + version);
})
.installer();
/** Install a Foxx from Github
*
* Install a Foxx with user/repository and version
*/
controller.put("/git", function (req, res) {
var content = JSON.parse(req.requestBody),
url = content.url,
version = content.version;
installApp(req, res, "git:" + url + ":" + (version || "master"));
})
.installer();
/** Generate a new foxx
*
* Generate a new empty foxx on the given mount point
*/
controller.put("/generate", function (req, res) {
var info = JSON.parse(req.requestBody);
installApp(req, res, "EMPTY", info);
})
.installer();
/** Install a Foxx from temporary zip file
*
* Install a Foxx from the given zip path.
* This path has to be created via _api/upload
*/
controller.put("/zip", function (req, res) {
var content = JSON.parse(req.requestBody),
file = content.zipFile;
installApp(req, res, file);
})
.installer();
/** Uninstall a Foxx
*
* Uninstall the Foxx at the given mount-point.
*/
controller.delete("/", function (req, res) {
var mount = validateMount(req);
var runTeardown = req.parameters.teardown;
var app = FoxxManager.uninstall(mount, {
teardown: runTeardown
});
res.json({
error: false,
name: app.name,
version: app.version
});
})
.queryParam("mount", mountPoint)
.queryParam("teardown", joi.boolean().default(true));
// ------------------------------------------------------------
// SECTION information
// ------------------------------------------------------------
/** List all Foxxes
*
* Get a List of all running foxxes
*/
controller.get('/', function (req, res) {
var foxxes = FoxxManager.listJson();
foxxes.forEach(function (foxx) {
var readme = FoxxManager.readme(foxx.mount);
if (readme) {
foxx.readme = marked(readme, {
highlight(code) {
return highlightAuto(code).value;
}
});
}
});
res.json(foxxes);
});
/** Get the thumbnail of a Foxx
*
* Used to request the thumbnail of the given Foxx in order to display it on the screen.
*/
controller.get("/thumbnail", function (req, res) {
res.transformations = [ "base64decode" ];
var mount = validateMount(req);
var app = FoxxManager.lookupApp(mount);
if (app.hasOwnProperty("_thumbnail")) {
res.body = app._thumbnail;
} else {
res.body = defaultThumb;
}
// evil mimetype detection attempt...
var start = require("internal").base64Decode(res.body.substr(0, 8));
if (start.indexOf("PNG") !== -1) {
res.contentType = "image/png";
}
})
.queryParam("mount", mountPoint);
/** Get the configuration for an app
*
* Used to request the configuration options for apps
*/
controller.get("/config", function(req, res) {
var mount = validateMount(req);
res.json(FoxxManager.configuration(mount));
})
.queryParam("mount", mountPoint);
/** Set the configuration for an app
*
* Used to overwrite the configuration options for apps
*/
controller.patch("/config", function(req, res) {
var mount = validateMount(req);
var data = req.body();
res.json(FoxxManager.configure(mount, {configuration: data}));
})
.queryParam("mount", mountPoint);
/** Get the dependencies for an app
*
* Used to request the dependencies options for apps
*/
controller.get("/deps", function(req, res) {
var mount = validateMount(req);
res.json(FoxxManager.dependencies(mount));
})
.queryParam("mount", mountPoint);
/** Set the dependencies for an app
*
* Used to overwrite the dependencies options for apps
*/
controller.patch("/deps", function(req, res) {
var mount = validateMount(req);
var data = req.body();
res.json(FoxxManager.updateDeps(mount, {dependencies: data}));
})
.queryParam("mount", mountPoint);
/** Run tests for an app
*
* Used to run the tests of an app
*/
controller.post("/tests", function (req, res) {
var options = req.body();
var mount = validateMount(req);
res.json(FoxxManager.runTests(mount, options));
})
.queryParam("mount", mountPoint);
/** Run a script for an app
*
* Used to trigger any script of an app
*/
controller.post("/scripts/:name", function (req, res) {
var mount = validateMount(req);
var name = req.params("name");
var argv = req.params("argv");
try {
res.json(FoxxManager.runScript(name, mount, argv));
} catch (e) {
throw e.cause || e;
}
})
.queryParam("mount", mountPoint)
.pathParam("name", scriptName)
.bodyParam(
"argv",
joi.any().default(null)
.description('Options to pass to the script.')
);
/** Trigger setup script for an app
*
* Used to trigger the setup script of an app
*/
controller.patch("/setup", function(req, res) {
var mount = validateMount(req);
res.json(FoxxManager.runScript("setup", mount));
})
.queryParam("mount", mountPoint);
/** Trigger teardown script for an app
*
* Used to trigger the teardown script of an app
*/
controller.patch("/teardown", function(req, res) {
var mount = validateMount(req);
res.json(FoxxManager.runScript("teardown", mount));
})
.queryParam("mount", mountPoint);
/** Activate/Deactivate development mode for an app
*
* Used to toggle between production and development mode
*/
controller.patch("/devel", function(req, res) {
var mount = validateMount(req);
var activate = Boolean(req.body());
if (activate) {
res.json(FoxxManager.development(mount));
} else {
res.json(FoxxManager.production(mount));
}
})
.queryParam("mount", mountPoint);
/** Download an app as zip archive
*
* Download a foxx app packed in a zip archive
*/
controller.get("/download/zip", function(req, res) {
var mount = validateMount(req);
var app = FoxxManager.lookupApp(mount);
var dir = fs.join(fs.makeAbsolute(app._root), app._path);
var zipPath = fmUtils.zipDirectory(dir);
res.set("Content-Type", "application/octet-stream");
res.set("Content-Disposition", "attachment; filename=app.zip");
res.body = fs.readFileSync(zipPath);
})
.queryParam("mount", mountPoint);
// ------------------------------------------------------------
// SECTION store
// ------------------------------------------------------------
/** List all Foxxes in Fishbowl
*
* Get the information for all Apps availbale in the Fishbowl and ready for download
*
*/
controller.get('/fishbowl', function (req, res) {
FoxxManager.update();
res.json(FoxxManager.availableJson());
}).summary("List of all foxx apps submitted to the fishbowl store.")
.notes("This function contacts the fishbowl and reports which apps are available for install")
.errorResponse(ArangoError, 503, "Could not connect to store.");
// ------------------------------------------------------------
// SECTION documentation
// ------------------------------------------------------------
controller.apiDocumentation('/docs/standalone', function (req, res) {
return {
appPath: req.parameters.mount
};
});
controller.apiDocumentation('/docs', function (req, res) {
return {
indexFile: 'index-alt.html',
appPath: req.parameters.mount
};
});
/** Returns the billboard URL for swagger
*
* Returns the billboard URL for the application mounted
* at the given mountpoint
*/
controller.get('/billboard', function(req, res) {
var mount = decodeURIComponent(decodeURIComponent(req.params("mount")));
var path = req.protocol + "://" + req.headers.host +
"/_db/" + encodeURIComponent(req.database) +
"/_admin/aardvark/foxxes/docu";
res.json({
swaggerVersion: "1.1",
basePath: path,
apis: [
{path: mount}
]
});
})
.queryParam("mount", mountPoint);
/** Returns the generated Swagger JSON description for one foxx
*
* This function returns the Swagger JSON API description of the foxx
* installed under the given mount point.
*/
controller.get('/docu/*', function(req, res) {
var mount = "";
underscore.each(req.suffix, function(part) {
mount += "/" + part;
});
res.json(docu(mount));
});
}());