From 36c548d69f8a005cac336dff74dda2947c02a9e2 Mon Sep 17 00:00:00 2001 From: Ritchie Martori Date: Tue, 29 Jul 2014 14:16:50 -0700 Subject: [PATCH] Add custom remote method definitions --- app.js | 5 ++- models.json | 2 +- models/data-source-definition.js | 24 +++++++++-- models/workspace.js | 33 +++++++++++++- test/rest.js | 74 ++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 test/rest.js diff --git a/app.js b/app.js index 4e6ccd13..50ba4c2d 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,7 @@ var methodOverride = require('method-override'); var app = module.exports = loopback(); var boot = require('loopback-boot'); var started = new Date(); +var env = app.get('env'); // long stack traces require('longjohn'); @@ -37,7 +38,9 @@ require('./connector'); */ app.use(loopback.favicon()); -app.use(loopback.logger(app.get('env') === 'development' ? 'dev' : 'default')); +if(env !== 'test') { + app.use(loopback.logger(env === 'development' ? 'dev' : 'default')); +} app.use(loopback.cookieParser(app.get('cookieSecret'))); app.use(loopback.token({model: app.models.accessToken})); app.use(methodOverride()); diff --git a/models.json b/models.json index e7c99104..543eabae 100644 --- a/models.json +++ b/models.json @@ -11,7 +11,7 @@ "properties": { "name": {"id": true, "type": "string"} }, - "public": false, + "public": true, "dataSource": "db" }, "PackageDefinition": { diff --git a/models/data-source-definition.js b/models/data-source-definition.js index 99a6196c..697ea6a7 100644 --- a/models/data-source-definition.js +++ b/models/data-source-definition.js @@ -50,6 +50,10 @@ DataSourceDefinition.prototype.testConnection = function(cb) { dataSource.connect(); } +loopback.remoteMethod(DataSourceDefinition.prototype.testConnection, { + returns: { arg: 'status', type: 'boolean' } +}); + /** * Discover the model definition by table name from this data source. Use the `name` * provided by items from returned from `DataSourceDefinition.getSchema()`. @@ -66,6 +70,15 @@ DataSourceDefinition.prototype.discoverModelDefinition = function(name, options, this.toDataSource().discoverSchemas(name, options, cb); } +loopback.remoteMethod(DataSourceDefinition.prototype.discoverModelDefinition, { + accepts: [{ + arg: 'modelName', type: 'string' + }, { + arg: 'options', type: 'object' + }], + returns: { arg: 'status', type: 'boolean' } +}); + /** * Get a list of table / collection names, owners and types. * @@ -74,7 +87,7 @@ DataSourceDefinition.prototype.discoverModelDefinition = function(name, options, * @options {Object} options Discovery options. See below. * @property {Boolean} all If true, discover all models; if false, discover only * models owned by the current user. - * @property {Boolean} views If true, nclude views; if false, only tables. + * @property {Boolean} views If true, include views; if false, only tables. * @property {Number} limit Page size * @property {Number} offset Starting index * @callback {Function} callback @@ -86,6 +99,11 @@ DataSourceDefinition.prototype.getSchema = function(options, cb) { this.toDataSource().discoverModelDefinitions(options, cb); } +loopback.remoteMethod(DataSourceDefinition.prototype.getSchema, { + accepts: { arg: 'options', type: 'object'}, + returns: { arg: 'models', type: 'array' } +}); + /** * Run a migration on the data source. Creates indexes, tables, collections, etc. * @@ -96,7 +114,7 @@ DataSourceDefinition.prototype.getSchema = function(options, cb) { */ DataSourceDefinition.prototype.automigrate = function() { - + throw new Error('not implemented'); } /** @@ -107,7 +125,7 @@ DataSourceDefinition.prototype.automigrate = function() { */ DataSourceDefinition.prototype.autoupdate = function() { - + throw new Error('not implemented'); } /** diff --git a/models/workspace.js b/models/workspace.js index 93ab629e..ca7b7fe4 100644 --- a/models/workspace.js +++ b/models/workspace.js @@ -1,3 +1,4 @@ +var loopback = require('loopback'); var extend = require('util')._extend; var fs = require('fs'); var ncp = require('ncp'); @@ -34,9 +35,20 @@ var Workspace = app.models.Workspace; */ Workspace.getAvailableTemplates = function(cb) { - fs.readdir(TEMPLATE_DIR, cb); + fs.readdir(TEMPLATE_DIR, function(err, files) { + cb(err, err ? undefined : files.filter(dirFilter)); + }); +} + +function dirFilter(file) { + return file.indexOf('.') === -1; } +loopback.remoteMethod(Workspace.getAvailableTemplates, { + http: {verb: 'get', path: '/component-templates'}, + returns: {arg: 'templates', type: 'array'} +}); + /** * Recursively copy files. * API consumers may override this function, e.g. to detect existing files @@ -115,6 +127,11 @@ Workspace.addComponent = function(options, cb) { async.series(steps, cb); }; +loopback.remoteMethod(Workspace.addComponent, { + http: {verb: 'post', path: '/component'}, + accepts: {arg: 'options', type: 'object', http: {source: 'body'}} +}); + function createFacet(name, template, cb) { var steps = []; @@ -196,6 +213,15 @@ Workspace.createFromTemplate = function(templateName, name, cb) { }, cb); } +loopback.remoteMethod(Workspace.createFromTemplate, { + http: {verb: 'post', path: '/'}, + accepts: [{ + arg: 'templateName', type: 'string' + }, { + arg: 'name', type: 'string', http: {source: 'body'} + }] +}); + /** * @typedef {{name, description,supportedByStrongLoop}} ConnectorMeta */ @@ -214,6 +240,11 @@ Workspace.listAvailableConnectors = function(cb) { cb(null, staticConnectorList); }; +loopback.remoteMethod(Workspace.listAvailableConnectors, { + http: {verb: 'get', path: '/connectors'}, + returns: {arg: 'connectors', type: 'array', root: true} +}); + /** * Check if the project is a valid directory. * The callback is called with no arguments when the project is valid. diff --git a/test/rest.js b/test/rest.js new file mode 100644 index 00000000..346c841e --- /dev/null +++ b/test/rest.js @@ -0,0 +1,74 @@ +var app = require('../app'); +var request = require('supertest'); + +describe('REST API', function () { + beforeEach(givenEmptySandbox); + + describe('/workspaces', function () { + describe('POST /workspaces', function () { + beforeEach(function(done) { + request(app) + .post('/api/workspaces') + .set('Content-Type', 'application/json') + .send({ + templateName: 'api-server', + name: 'sandbox' + }) + .expect(204) + .end(done); + }); + it('should add a facet from a template', function (done) { + app.models.Facet.find(function(err, defs) { + if(err) return done(err); + var names = toNames(defs); + expect(names).to.contain('server'); + done(); + }); + }); + }); + + /*** + *** SKIP UNTIL NON ROOT COMPONENT SUPPORT IS ADDED *** + ***/ + + describe.skip('POST /workspaces/component', function () { + beforeEach(function(done) { + request(app) + .post('/api/workspaces/component') + .set('Content-Type', 'application/json') + .send({ + template: 'rest' + }) + .end(done); + }); + it('should add a component from a template', function (done) { + app.models.ComponentDefinition.find(function(err, defs) { + expect(toNames(defs)).to.contain('rest'); + done(); + }); + }); + }); + + describe('POST /workspaces/connectors', function () { + beforeEach(function(done) { + this.req = request(app) + .get('/api/workspaces/connectors') + .set('Accepts', 'application/json') + .end(done); + }); + it('should return a list of connectors', function () { + var connectors = toNames(this.req.res.body); + expect(connectors).to.contain('memory'); + expect(connectors).to.contain('mysql'); + expect(connectors).to.contain('postgresql'); + expect(connectors).to.contain('oracle'); + expect(connectors).to.contain('mssql'); + expect(connectors).to.contain('mongodb'); + expect(connectors).to.contain('soap'); + expect(connectors).to.contain('rest'); + expect(connectors).to.contain('neo4j'); + expect(connectors).to.contain('kafka'); + }); + }); + }); +});