Check configs for shared method settings
This commit is contained in:
parent
716ed4569f
commit
26af1472e7
|
@ -11,6 +11,7 @@ var RemoteObjects = require('strong-remoting');
|
|||
var classify = require('underscore.string/classify');
|
||||
var camelize = require('underscore.string/camelize');
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* The `App` object represents a Loopback application.
|
||||
|
@ -435,9 +436,54 @@ function configureModel(ModelCtor, config, app) {
|
|||
config = extend({}, config);
|
||||
config.dataSource = dataSource;
|
||||
|
||||
setSharedMethodSharedProperties(ModelCtor, app, config);
|
||||
|
||||
app.registry.configureModel(ModelCtor, config);
|
||||
}
|
||||
|
||||
function setSharedMethodSharedProperties(model, app, modelConfigs) {
|
||||
var settings = {};
|
||||
|
||||
// apply config.json settings
|
||||
var config = app.get('remoting');
|
||||
var configHasSharedMethodsSettings = config &&
|
||||
config.sharedMethods &&
|
||||
typeof config.sharedMethods === 'object';
|
||||
if (configHasSharedMethodsSettings)
|
||||
util._extend(settings, config.sharedMethods);
|
||||
|
||||
// apply model-config.json settings
|
||||
var modelConfig = modelConfigs.options;
|
||||
var modelConfigHasSharedMethodsSettings = modelConfig &&
|
||||
modelConfig.remoting &&
|
||||
modelConfig.remoting.sharedMethods &&
|
||||
typeof modelConfig.remoting.sharedMethods === 'object';
|
||||
if (modelConfigHasSharedMethodsSettings)
|
||||
util._extend(settings, modelConfig.remoting.sharedMethods);
|
||||
|
||||
// validate setting values
|
||||
Object.keys(settings).forEach(function(setting) {
|
||||
var settingValue = settings[setting];
|
||||
var settingValueType = typeof settingValue;
|
||||
if (settingValueType !== 'boolean')
|
||||
throw new TypeError('Expected boolean, got ' + settingValueType);
|
||||
});
|
||||
|
||||
// set sharedMethod.shared using the merged settings
|
||||
var sharedMethods = model.sharedClass.methods({includeDisabled: true});
|
||||
sharedMethods.forEach(function(sharedMethod) {
|
||||
// use the specific setting if it exists
|
||||
var hasSpecificSetting = settings.hasOwnProperty(sharedMethod.name);
|
||||
if (hasSpecificSetting) {
|
||||
sharedMethod.shared = settings[sharedMethod.name];
|
||||
} else { // otherwise, use the default setting if it exists
|
||||
var hasDefaultSetting = settings.hasOwnProperty('*');
|
||||
if (hasDefaultSetting)
|
||||
sharedMethod.shared = settings['*'];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearHandlerCache(app) {
|
||||
app._handlers = undefined;
|
||||
}
|
||||
|
|
|
@ -618,6 +618,12 @@ module.exports = function(registry) {
|
|||
description: 'Delete all matching records.',
|
||||
accessType: 'WRITE',
|
||||
accepts: {arg: 'where', type: 'object', description: 'filter.where object'},
|
||||
returns: {
|
||||
arg: 'count',
|
||||
type: 'object',
|
||||
description: 'The number of instances deleted',
|
||||
root: true
|
||||
},
|
||||
http: {verb: 'del', path: '/'},
|
||||
shared: false
|
||||
});
|
||||
|
@ -632,6 +638,12 @@ module.exports = function(registry) {
|
|||
{arg: 'data', type: 'object', http: {source: 'body'},
|
||||
description: 'An object of model property name/value pairs'},
|
||||
],
|
||||
returns: {
|
||||
arg: 'count',
|
||||
description: 'The number of instances updated',
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {verb: 'post', path: '/update'}
|
||||
});
|
||||
|
||||
|
@ -641,7 +653,8 @@ module.exports = function(registry) {
|
|||
accessType: 'WRITE',
|
||||
accepts: {arg: 'id', type: 'any', description: 'Model id', required: true,
|
||||
http: {source: 'path'}},
|
||||
http: {verb: 'del', path: '/:id'}
|
||||
http: {verb: 'del', path: '/:id'},
|
||||
returns: {arg: 'count', type: 'object', root: true}
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'count', {
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
"nodemailer-stub-transport": "^0.1.5",
|
||||
"serve-favicon": "^2.2.0",
|
||||
"stable": "^0.1.5",
|
||||
"strong-remoting": "^2.15.0",
|
||||
"strong-remoting": "^2.21.0",
|
||||
"uid2": "0.0.3",
|
||||
"underscore.string": "^3.0.3"
|
||||
},
|
||||
|
|
|
@ -117,14 +117,15 @@ describe('remoting - integration', function() {
|
|||
'findById(id:any,filter:object):store GET /stores/:id',
|
||||
'find(filter:object):store GET /stores',
|
||||
'findOne(filter:object):store GET /stores/findOne',
|
||||
'updateAll(where:object,data:object) POST /stores/update',
|
||||
'deleteById(id:any) DELETE /stores/:id',
|
||||
'updateAll(where:object,data:object):object POST /stores/update',
|
||||
'deleteById(id:any):object DELETE /stores/:id',
|
||||
'count(where:object):number GET /stores/count',
|
||||
'prototype.updateAttributes(data:object):store PUT /stores/:id'
|
||||
'prototype.updateAttributes(data:object):store PUT /stores/:id',
|
||||
'createChangeStream(options:object):ReadableStream POST /stores/change-stream'
|
||||
];
|
||||
|
||||
// The list of methods is from docs:
|
||||
// http://docs.strongloop.com/display/LB/Exposing+models+over+a+REST+API
|
||||
// https://docs.strongloop.com/display/public/LB/Exposing+models+over+REST
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
var path = require('path');
|
||||
|
||||
describe('loopback.rest', function() {
|
||||
var MyModel;
|
||||
beforeEach(function() {
|
||||
|
@ -14,6 +16,20 @@ describe('loopback.rest', function() {
|
|||
.end(done);
|
||||
});
|
||||
|
||||
it('should report 200 for DELETE /:id found', function(done) {
|
||||
app.set('legacyExplorer', false);
|
||||
app.model(MyModel);
|
||||
app.use(loopback.rest());
|
||||
MyModel.create({name: 'm1'}, function(err, inst) {
|
||||
request(app)
|
||||
.del('/mymodels/' + inst.id)
|
||||
.expect(200, function(err, res) {
|
||||
expect(res.body.count).to.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should report 404 for GET /:id not found', function(done) {
|
||||
app.model(MyModel);
|
||||
app.use(loopback.rest());
|
||||
|
@ -337,4 +353,124 @@ describe('loopback.rest', function() {
|
|||
User.login(credentials, cb);
|
||||
});
|
||||
}
|
||||
|
||||
describe('shared methods', function() {
|
||||
function getFixturePath(dirName) {
|
||||
return path.join(__dirname, 'fixtures/shared-methods/' + dirName +
|
||||
'/server/server.js');
|
||||
}
|
||||
|
||||
describe('with specific definitions in model-config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('model-config-defined-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true', function(done) {
|
||||
var app = require(getFixturePath('model-config-defined-true'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with default definitions in model-config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('model-config-default-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true', function(done) {
|
||||
var app = require(getFixturePath('model-config-default-true'));
|
||||
app.models.Todo.create([
|
||||
{content: 'a'},
|
||||
{content: 'b'},
|
||||
{content: 'c'}
|
||||
], function() {
|
||||
request(app)
|
||||
.del('/todos')
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body.count).to.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with specific definitions in config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-defined-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-defined-true'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(200, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with default definitions in config.json', function() {
|
||||
it('should not be exposed when the definition value is false',
|
||||
function(done) {
|
||||
var app = require(getFixturePath('config-default-false'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should be exposed when the definition value is true', function(done) {
|
||||
var app = require(getFixturePath('config-default-true'));
|
||||
app.models.Todo.create([
|
||||
{content: 'a'},
|
||||
{content: 'b'},
|
||||
{content: 'c'}
|
||||
], function() {
|
||||
request(app)
|
||||
.del('/todos')
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
expect(res.body.count).to.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// The fixture in `shared-method/both-configs-set/config.json` has `*:false`
|
||||
// set which disables the REST endpoints for built-in models such as User as
|
||||
// a side effect since tests share the same loopback instance. As a
|
||||
// consequence, this causes the tests in user.integration to fail.
|
||||
describe.skip('with definitions in both config.json and model-config.json',
|
||||
function() {
|
||||
it('should prioritize the settings in model-config.json', function(done) {
|
||||
var app = require(getFixturePath('both-configs-set'));
|
||||
request(app)
|
||||
.del('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should fall back to config.json settings if setting is not found in' +
|
||||
'model-config.json', function(done) {
|
||||
var app = require(getFixturePath('both-configs-set'));
|
||||
request(app)
|
||||
.get('/todos')
|
||||
.expect(404, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,14 +34,10 @@ describe('users - integration', function() {
|
|||
var accessToken;
|
||||
|
||||
it('should create a new user', function(done) {
|
||||
var url = '/api/users';
|
||||
|
||||
this.post(url)
|
||||
this.post('/api/users')
|
||||
.send({username: 'x', email: 'x@y.com', password: 'x'})
|
||||
.expect(200, function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
if (err) return done(err);
|
||||
expect(res.body.id).to.exist;
|
||||
userId = res.body.id;
|
||||
done();
|
||||
|
|
Loading…
Reference in New Issue