From 317e00d92c7cdffead9de737830a07a4189f59b2 Mon Sep 17 00:00:00 2001 From: bmatson Date: Thu, 19 Oct 2017 16:25:58 -0400 Subject: [PATCH] Update nestRemoting to pass optionsFromContext Fix the code invoking relation getter to correctly pass through the "options" argument. --- lib/model.js | 35 +++++++++++++--------- test/multiple-user-principal-types.test.js | 1 - test/relations.integration.js | 23 +++++++++++++- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/lib/model.js b/lib/model.js index ca49a22e6..b3b6ec69e 100644 --- a/lib/model.js +++ b/lib/model.js @@ -947,38 +947,45 @@ module.exports = function(registry) { } }); + const lastArg = opts.accepts[opts.accepts.length - 1] || {}; + const hasOptionsFromContext = + (lastArg.arg || lastArg.name) === 'options' && + lastArg.type === 'object' && lastArg.http; + if (relation.multiple) { sharedClass.defineMethod(methodName, opts, function(fkId) { - var args = Array.prototype.slice.call(arguments, 1); - var last = args[args.length - 1]; - var cb = typeof last === 'function' ? last : null; - this[getterName](fkId, function(err, inst) { - if (err && cb) return cb(err); + const args = Array.prototype.slice.call(arguments, 1); + const cb = args[args.length - 1]; + const contextOptions = + hasOptionsFromContext && args[args.length - 2] || {}; + this[getterName](fkId, contextOptions, function(err, inst) { + if (err) return cb(err); if (inst instanceof relation.modelTo) { try { nestedFn.apply(inst, args); } catch (err) { - if (cb) return cb(err); + return cb(err); } - } else if (cb) { + } else { cb(err, null); } }); }, method.isStatic); } else { sharedClass.defineMethod(methodName, opts, function() { - var args = Array.prototype.slice.call(arguments); - var last = args[args.length - 1]; - var cb = typeof last === 'function' ? last : null; - this[getterName](function(err, inst) { - if (err && cb) return cb(err); + const args = Array.prototype.slice.call(arguments); + const cb = args[args.length - 1]; + const contextOptions = + hasOptionsFromContext && args[args.length - 2] || {}; + this[getterName](contextOptions, function(err, inst) { + if (err) return cb(err); if (inst instanceof relation.modelTo) { try { nestedFn.apply(inst, args); } catch (err) { - if (cb) return cb(err); + return cb(err); } - } else if (cb) { + } else { cb(err, null); } }); diff --git a/test/multiple-user-principal-types.test.js b/test/multiple-user-principal-types.test.js index a41233601..e4a41f57b 100644 --- a/test/multiple-user-principal-types.test.js +++ b/test/multiple-user-principal-types.test.js @@ -695,7 +695,6 @@ describe('Multiple users with custom principalType', function() { }); it('fails when the access token belongs to a different user mode', () => { - debugger; logServerErrorsOtherThan(403, app); return supertest(app) .post('/AnotherUsers/change-password') diff --git a/test/relations.integration.js b/test/relations.integration.js index 3000a3957..ab68dc776 100644 --- a/test/relations.integration.js +++ b/test/relations.integration.js @@ -1439,6 +1439,8 @@ describe('relations - integration', function() { }); describe('nested relations', function() { + let accessOptions; + before(function defineModels() { var Book = app.registry.createModel( 'Book', @@ -1486,7 +1488,8 @@ describe('relations - integration', function() { throw new Error('This should not crash the app'); }; - Page.remoteMethod('__throw__errors', {isStatic: false, http: {path: '/throws', verb: 'get'}}); + Page.remoteMethod('__throw__errors', {isStatic: false, http: {path: '/throws', verb: 'get'}, + accepts: [{arg: 'options', type: 'object', http: 'optionsFromRequest'}]}); // Now `pages` has nestRemoting set to true and no need to call nestRemoting() // Book.nestRemoting('pages'); @@ -1507,6 +1510,15 @@ describe('relations - integration', function() { next(); }); + + Page.observe('access', function(ctx, next) { + accessOptions = ctx.options; + next(); + }); + }); + + beforeEach(function resetAccessOptions() { + accessOptions = 'access hook not triggered'; }); before(function createBook(done) { @@ -1619,6 +1631,7 @@ describe('relations - integration', function() { it('enables nested relationship routes - belongsTo findById', function(done) { var test = this; this.get('/api/images/' + test.image.id + '/book/pages/' + test.page.id) + .expect(200) .end(function(err, res) { if (err) return done(err); @@ -1658,6 +1671,14 @@ describe('relations - integration', function() { }); }); + it('passes options to nested relationship routes', function() { + return this.get(`/api/books/${this.book.id}/pages/${this.page.id}/notes/${this.note.id}`) + .expect(200) + .then(res => { + expect(accessOptions).to.have.property('accessToken'); + }); + }); + it('should nest remote hooks of ModelTo - hasMany findById', function(done) { var test = this; this.get('/api/books/' + test.book.id + '/chapters/' + test.chapter.id + '/notes/' + test.cnote.id)