-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expose Replace* methods
#2316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose Replace* methods
#2316
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -111,9 +111,15 @@ describe('access control - integration', function() { | |
| assert.equal(user.password, undefined); | ||
| }); | ||
| }); | ||
|
|
||
| // user has replaceOnPUT = false; so then both PUT and PATCH should be allowed for update | ||
| lt.describe.whenCalledRemotely('PUT', '/api/users/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
|
|
||
| lt.describe.whenCalledRemotely('PATCH', '/api/users/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add test(s) for new replace* endpoints too, to verify that ACLs work correctly for them too.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see you are testing new replace* endpoints below for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I already have tests for |
||
| }); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForUser); | ||
|
|
@@ -163,7 +169,7 @@ describe('access control - integration', function() { | |
| } | ||
| }); | ||
|
|
||
| describe('/accounts', function() { | ||
| describe('/accounts with replaceOnPUT true', function() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Modifying existing test suite and adding more tests into it is not a good practice. It makes it more difficult to understand the scope of this change, why are we changing existing tests not related to replace* methods to run against a model with A better approach is to create a new
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I should have read the full patch before commenting. So you actually did what I proposed in |
||
| var count = 0; | ||
| before(function() { | ||
| var roleModel = loopback.getModelByType(loopback.Role); | ||
|
|
@@ -177,56 +183,145 @@ describe('access control - integration', function() { | |
| }); | ||
| }); | ||
|
|
||
| lt.beforeEach.givenModel('account'); | ||
| lt.beforeEach.givenModel('accountWithReplaceOnPUTtrue'); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('GET', '/api/accounts'); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', '/api/accounts'); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', '/api/accounts'); | ||
| lt.it.shouldBeDeniedWhenCalledAnonymously('GET', '/api/accounts-replacing'); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', '/api/accounts-replacing'); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', '/api/accounts-replacing'); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('GET', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', urlForAccount); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('POST', '/api/accounts'); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', '/api/accounts'); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', '/api/accounts'); | ||
| lt.it.shouldBeDeniedWhenCalledAnonymously('POST', '/api/accounts-replacing'); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', '/api/accounts-replacing'); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', '/api/accounts-replacing'); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('POST', urlForReplaceAccountPOST); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', urlForReplaceAccountPOST); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', urlForReplaceAccountPOST); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PUT', urlForAccount); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('PATCH', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('PATCH', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PATCH', urlForAccount); | ||
|
|
||
| lt.describe.whenLoggedInAsUser(CURRENT_USER, function() { | ||
| var actId; | ||
| beforeEach(function(done) { | ||
| var self = this; | ||
|
|
||
| // Create an account under the given user | ||
| app.models.account.create({ | ||
| app.models.accountWithReplaceOnPUTtrue.create({ | ||
| userId: self.user.id, | ||
| balance: 100, | ||
| }, function(err, act) { | ||
| self.url = '/api/accounts/' + act.id; | ||
| actId = act.id; | ||
| self.url = '/api/accounts-replacing/' + actId; | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| lt.describe.whenCalledRemotely('PATCH', '/api/accounts-replacing/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
| lt.describe.whenCalledRemotely('PUT', '/api/accounts-replacing/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
| lt.describe.whenCalledRemotely('GET', '/api/accounts-replacing/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
| lt.describe.whenCalledRemotely('DELETE', '/api/accounts-replacing/:id', function() { | ||
| lt.it.shouldBeDenied(); | ||
| }); | ||
| describe('replace on POST verb', function() { | ||
| beforeEach(function(done) { | ||
| this.url = '/api/accounts-replacing/' + actId + '/replace'; | ||
| done(); | ||
| }); | ||
| lt.describe.whenCalledRemotely('POST', '/api/accounts-replacing/:id/replace', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForAccount); | ||
|
|
||
| lt.describe.whenCalledRemotely('PUT', '/api/accounts/:id', function() { | ||
| function urlForAccount() { | ||
| return '/api/accounts-replacing/' + this.accountWithReplaceOnPUTtrue.id; | ||
| } | ||
| function urlForReplaceAccountPOST() { | ||
| return '/api/accounts-replacing/' + this.accountWithReplaceOnPUTtrue.id + '/replace'; | ||
| } | ||
| }); | ||
|
|
||
| describe('/accounts with replaceOnPUT false', function() { | ||
| lt.beforeEach.givenModel('accountWithReplaceOnPUTfalse'); | ||
| lt.it.shouldBeDeniedWhenCalledAnonymously('POST', urlForReplaceAccountPOST); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', urlForReplaceAccountPOST); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', urlForReplaceAccountPOST); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PUT', urlForAccount); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('PATCH', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('PATCH', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PATCH', urlForAccount); | ||
|
|
||
| lt.describe.whenLoggedInAsUser(CURRENT_USER, function() { | ||
| var actId; | ||
| beforeEach(function(done) { | ||
| var self = this; | ||
| // Create an account under the given user | ||
| app.models.accountWithReplaceOnPUTfalse.create({ | ||
| userId: self.user.id, | ||
| balance: 100, | ||
| }, function(err, act) { | ||
| actId = act.id; | ||
| self.url = '/api/accounts-updating/' + actId; | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| lt.describe.whenCalledRemotely('PATCH', '/api/accounts-updating/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
|
|
||
| lt.describe.whenCalledRemotely('PUT', '/api/accounts-updating/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
| lt.describe.whenCalledRemotely('GET', '/api/accounts/:id', function() { | ||
| lt.describe.whenCalledRemotely('GET', '/api/accounts-updating/:id', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
| lt.describe.whenCalledRemotely('DELETE', '/api/accounts/:id', function() { | ||
| lt.describe.whenCalledRemotely('DELETE', '/api/accounts-updating/:id', function() { | ||
| lt.it.shouldBeDenied(); | ||
| }); | ||
|
|
||
| describe('replace on POST verb', function() { | ||
| beforeEach(function(done) { | ||
| this.url = '/api/accounts-updating/' + actId + '/replace'; | ||
| done(); | ||
| }); | ||
| lt.describe.whenCalledRemotely('POST', '/api/accounts-updating/:id/replace', function() { | ||
| lt.it.shouldBeAllowed(); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForAccount); | ||
| lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForAccount); | ||
|
|
||
| function urlForAccount() { | ||
| return '/api/accounts/' + this.account.id; | ||
| return '/api/accounts-updating/' + this.accountWithReplaceOnPUTfalse.id; | ||
| } | ||
| function urlForReplaceAccountPOST() { | ||
| return '/api/accounts-updating/' + this.accountWithReplaceOnPUTfalse.id + '/replace'; | ||
| } | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| { | ||
| "name": "accountWithReplaceOnPUTfalse", | ||
| "plural": "accounts-updating", | ||
| "relations": { | ||
| "transactions": { | ||
| "model": "transaction", | ||
| "type": "hasMany" | ||
| }, | ||
| "user": { | ||
| "model": "user", | ||
| "type": "belongsTo", | ||
| "foreignKey": "userId" | ||
| } | ||
| }, | ||
| "acls": [ | ||
| { | ||
| "accessType": "*", | ||
| "permission": "DENY", | ||
| "principalType": "ROLE", | ||
| "principalId": "$everyone" | ||
| }, | ||
| { | ||
| "accessType": "*", | ||
| "permission": "ALLOW", | ||
| "principalType": "ROLE", | ||
| "principalId": "$owner" | ||
| }, | ||
| { | ||
| "permission": "DENY", | ||
| "principalType": "ROLE", | ||
| "principalId": "$owner", | ||
| "property": "deleteById" | ||
| }, | ||
| { | ||
| "accessType": "*", | ||
| "permission": "DENY", | ||
| "property": "find", | ||
| "principalType": "ROLE", | ||
| "principalId": "$dummy" | ||
| } | ||
| ], | ||
| "properties": {}, | ||
| "replaceOnPUT": false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,5 +19,6 @@ | |
| "principalType": "ROLE", | ||
| "principalId": "$everyone" | ||
| } | ||
| ] | ||
| ], | ||
| "replaceOnPUT": false | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test will have to be changed when back-ported to 2.x, because
replaceByIdwill be exposed at/api/users/:id/replaceonly. Could you please add a note so that we don't forget?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, only now I realised that you are explicitly setting
replaceOnPUT=falseforUsermodel. In that case, I think we need to add a test case verifying thatPOST /api/users/:id/replaceis allowed.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we decided not to include ACL test for
replaceforusermodel because it replacesemail,password,...which breaks... instead we are testing it foraccountmodel...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.