diff options
| author | Jules Laplace <jules@okfoc.us> | 2017-03-16 21:03:55 +0100 |
|---|---|---|
| committer | Jules Laplace <jules@okfoc.us> | 2017-03-16 21:03:55 +0100 |
| commit | 13fd58333e8280effb679ac93913971b096d5fe3 (patch) | |
| tree | c1fb731eb1a8a61b3e237c9feaaa1f7b2e2b6923 | |
| parent | 8e05164678d302700c794feecd50d83357f7719d (diff) | |
CRUD users
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | .jshintrc | 1 | ||||
| -rw-r--r-- | src/hooks/index.js | 9 | ||||
| -rw-r--r-- | src/services/meal/hooks/index.js | 3 | ||||
| -rw-r--r-- | src/services/meal/meal-model.js | 2 | ||||
| -rw-r--r-- | src/services/user/hooks/index.js | 91 | ||||
| -rw-r--r-- | src/services/user/user-model.js | 2 | ||||
| -rw-r--r-- | test/services/user/index.test.js | 96 |
8 files changed, 184 insertions, 24 deletions
@@ -29,3 +29,7 @@ node_modules lib/ data/ + +*~ +*.swp + @@ -1,4 +1,5 @@ { + "asi": true, "node": true, "esnext": true, "bitwise": true, diff --git a/src/hooks/index.js b/src/hooks/index.js index 2b122bb..4c535c4 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -8,12 +8,3 @@ const hooks = require('feathers-hooks'); const auth = require('feathers-authentication').hooks; -const or = require('promise-or'); - -exports.restrictToOwnersOrAdmins = function() { - var ownerHook = auth.restrictToOwner() - var adminHook = auth.restrictToRoles({ roles: ["admin"] }) - return function(hook) { - return or(ownerHook(hook), adminHook(hook)) - }; -}; diff --git a/src/services/meal/hooks/index.js b/src/services/meal/hooks/index.js index 2e2795a..dd0d7ca 100644 --- a/src/services/meal/hooks/index.js +++ b/src/services/meal/hooks/index.js @@ -9,7 +9,6 @@ exports.before = { auth.verifyToken(), auth.populateUser(), auth.restrictToAuthenticated(), - globalHooks.restrictToOwnersOrAdmins(), ], find: [], get: [], @@ -26,6 +25,6 @@ exports.after = { create: [], update: [], patch: [], - remove: [] + remove: [], }; diff --git a/src/services/meal/meal-model.js b/src/services/meal/meal-model.js index d15b244..90f35ca 100644 --- a/src/services/meal/meal-model.js +++ b/src/services/meal/meal-model.js @@ -21,7 +21,7 @@ module.exports = function(sequelize) { type: Sequelize.INTEGER, allowNull: false }, - user_id: { + userid: { type: Sequelize.INTEGER, references: { model: sequelize.model('users'), diff --git a/src/services/user/hooks/index.js b/src/services/user/hooks/index.js index 9dfe425..85f8e04 100644 --- a/src/services/user/hooks/index.js +++ b/src/services/user/hooks/index.js @@ -4,39 +4,114 @@ const globalHooks = require('../../../hooks'); const hooks = require('feathers-hooks'); const auth = require('feathers-authentication').hooks; +var _feathersErrors = require('feathers-errors'); +var _feathersErrors2 = _interopRequireDefault(_feathersErrors); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function validateRoleOnCreate () { + return function(hook) { + var _this = this; + + var userRole = hook.params.user && hook.params.user.role; + + return new Promise(function (resolve, reject) { + // Set provider as undefined so we avoid an infinite loop if this hook is + // set on the resource we are requesting. + var params = Object.assign({}, hook.params, { provider: undefined }); + + if (! hook.data.role) { + hook.data.role = 'user' + resolve(hook); + } + if (userRole && userRole.toString() === 'user') { + reject(new _feathersErrors2.default.Forbidden('You do not have permission to create new users.')); + } + else if (userRole && userRole.toString() === 'manager' && hook.data.role.toString() !== 'user') { + reject(new _feathersErrors2.default.Forbidden('You do not have permission to change this user\'s role.')); + } + else { + resolve(hook); + } + }); + } +} + +function validateRoleOnUpdate () { + return function(hook) { + var _this = this; + + var userRole = hook.params.user.role; + + return new Promise(function (resolve, reject) { + // Set provider as undefined so we avoid an infinite loop if this hook is + // set on the resource we are requesting. + var params = Object.assign({}, hook.params, { provider: undefined }); + + return _this.get(hook.id, params).then(function (data) { + if (data.toJSON) { + data = data.toJSON(); + } else if (data.toObject) { + data = data.toObject(); + } + + var dataRole = data.role; + if (userRole.toString() === 'user' && dataRole.toString() !== 'user') { + reject(new _feathersErrors2.default.Forbidden('You do not have permission to change your role.')); + } + else if (userRole.toString() === 'manager' && dataRole.toString() !== 'user') { + reject(new _feathersErrors2.default.Forbidden('You do not have permission to change this user\'s role.')); + } + else { + resolve(hook); + } + }).catch(reject); + }); + } +} + +const roleConfig = { + fieldName: 'role', + roles: ['manager','admin'], + owner: true, + ownerField: 'id' +} + exports.before = { all: [], find: [ auth.verifyToken(), auth.populateUser(), - auth.restrictToAuthenticated() + auth.restrictToAuthenticated(), ], get: [ auth.verifyToken(), auth.populateUser(), auth.restrictToAuthenticated(), - auth.restrictToOwner({ ownerField: 'id' }) + auth.restrictToRoles(roleConfig), ], create: [ - auth.hashPassword() + auth.hashPassword(), + validateRoleOnCreate(), ], update: [ auth.verifyToken(), auth.populateUser(), auth.restrictToAuthenticated(), - auth.restrictToOwner({ ownerField: 'id' }) + auth.restrictToRoles(roleConfig), + validateRoleOnUpdate(), ], patch: [ auth.verifyToken(), auth.populateUser(), auth.restrictToAuthenticated(), - auth.restrictToOwner({ ownerField: 'id' }) + validateRoleOnUpdate(), + validateRoleOnUpdate(), ], remove: [ auth.verifyToken(), auth.populateUser(), auth.restrictToAuthenticated(), - auth.restrictToOwner({ ownerField: 'id' }) + validateRoleOnUpdate(), ] }; @@ -47,5 +122,7 @@ exports.after = { create: [], update: [], patch: [], - remove: [] + remove: [ + // remove user's meals + ], }; diff --git a/src/services/user/user-model.js b/src/services/user/user-model.js index 03db95b..d7c00ee 100644 --- a/src/services/user/user-model.js +++ b/src/services/user/user-model.js @@ -19,7 +19,7 @@ module.exports = function(sequelize) { allowNull: false }, role: { - type: Sequelize.ENUM('user', 'manager', 'admin'), + type: Sequelize.STRING, allowNull: false }, goal: { diff --git a/test/services/user/index.test.js b/test/services/user/index.test.js index a43dcae..83dc105 100644 --- a/test/services/user/index.test.js +++ b/test/services/user/index.test.js @@ -1,10 +1,98 @@ 'use strict'; +const chai = require('chai') +const chaiHttp = require('chai-http') +const should = chai.should(); const assert = require('assert'); const app = require('../../../src/app'); -describe('user service', function() { +const User = app.service('users') +const authentication = require('feathers-authentication/client'); +const bodyParser = require('body-parser'); +var token, userid + +app + .use(bodyParser.json()) + .use(bodyParser.urlencoded({ extended: true })) + .configure(authentication()); +chai.use(chaiHttp); + + +describe('user service', () => { + before((done) => { + this.server = app.listen(3030) + this.server.once('listening', () => { + done() + }) + }) + + after((done) => { + this.server.close(function(){}) + done() + }) + it('registered the users service', () => { - assert.ok(app.service('users')); - }); -}); + assert.ok(app.service('users')) + }) + + it('should create a new user', (done) => { + chai.request(app) + .post('/users') + .set('Accept', 'application/json') + .send({ + email: 'test@test.com', + password: 'password', + goal: 2000, + }) + .end((err, res) => { + res.body.should.have.property('email') + res.body.email.should.equal('test@test.com') + res.body.should.not.have.property('password') + res.body.goal.should.equal(2000) + done() + }) + }) + + it('should authenticate a new user', (done) => { + chai.request(app) + .post('/auth/local') + .set('Accept', 'application/json') + .send({ + email: 'test@test.com', + password: 'password', + }) + .end((err, res) => { + res.body.should.have.property('token') + res.body.should.have.property('data') + res.body.data.should.have.property('id') + token = res.body.token + userid = res.body.data.id + done() + }) + }) + + it('user should be able to update itself', (done) => { + chai.request(app) + .patch('/users/'.concat(userid)) + .set('Accept', 'application/json') + .set('Authorization', 'Bearer '.concat(token)) + .send({ + goal: 2500, + }) + .end((err, res) => { + done() + }) + }) + + it('user should be able to destroy itself', (done) => { + chai.request(app) + .delete('/users/'.concat(userid)) + .set('Accept', 'application/json') + .set('Authorization', 'Bearer '.concat(token)) + .send() + .end((err, res) => { + done() + }) + }) + +}) |
