Merge pull request #5349 from acburdine/onboarding-api

Add PUT route to authentication setup
This commit is contained in:
Hannah Wolfe 2015-06-30 12:03:21 +01:00
commit b8415e8b90
4 changed files with 171 additions and 52 deletions

View File

@ -9,6 +9,45 @@ var _ = require('lodash'),
config = require('../config'),
authentication;
function setupTasks(object) {
var setupUser,
internal = {context: {internal: true}};
return utils.checkObject(object, 'setup').then(function (checkedSetupData) {
setupUser = {
name: checkedSetupData.setup[0].name,
email: checkedSetupData.setup[0].email,
password: checkedSetupData.setup[0].password,
blogTitle: checkedSetupData.setup[0].blogTitle,
status: 'active'
};
return dataProvider.User.findOne({role: 'Owner', status: 'all'});
}).then(function (ownerUser) {
if (ownerUser) {
return dataProvider.User.setup(setupUser, _.extend({id: ownerUser.id}, internal));
} else {
return dataProvider.Role.findOne({name: 'Owner'}).then(function (ownerRole) {
setupUser.roles = [ownerRole.id];
return dataProvider.User.add(setupUser, internal);
});
}
}).then(function (user) {
var userSettings = [];
// Handles the additional values set by the setup screen.
if (!_.isEmpty(setupUser.blogTitle)) {
userSettings.push({key: 'title', value: setupUser.blogTitle});
userSettings.push({key: 'description', value: 'Thoughts, stories and ideas.'});
}
setupUser = user.toJSON(internal);
return settings.edit({settings: userSettings}, {context: {user: setupUser.id}});
}).then(function () {
return Promise.resolve(setupUser);
});
}
/**
* ## Authentication API Methods
*
@ -153,7 +192,7 @@ authentication = {
* @param {string} options.email The email to check for an invitation on
* @returns {Promise(Invitation}} An invitation status
*/
isInvitation: function (options) {
isInvitation: function isInvitation(options) {
return authentication.isSetup().then(function (result) {
var setup = result.setup[0].status;
@ -175,7 +214,7 @@ authentication = {
});
},
isSetup: function () {
isSetup: function isSetup() {
return dataProvider.User.query(function (qb) {
qb.whereIn('status', ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked']);
}).fetch().then(function (users) {
@ -187,9 +226,8 @@ authentication = {
});
},
setup: function (object) {
var setupUser,
internal = {context: {internal: true}};
setup: function setup(object) {
var setupUser;
return authentication.isSetup().then(function (result) {
var setup = result.setup[0].status;
@ -198,37 +236,10 @@ authentication = {
return Promise.reject(new errors.NoPermissionError('Setup has already been completed.'));
}
return utils.checkObject(object, 'setup');
}).then(function (checkedSetupData) {
setupUser = {
name: checkedSetupData.setup[0].name,
email: checkedSetupData.setup[0].email,
password: checkedSetupData.setup[0].password,
blogTitle: checkedSetupData.setup[0].blogTitle,
status: 'active'
};
return setupTasks(object);
}).then(function (result) {
setupUser = result;
return dataProvider.User.findOne({role: 'Owner', status: 'all'});
}).then(function (ownerUser) {
if (ownerUser) {
return dataProvider.User.setup(setupUser, _.extend({id: ownerUser.id}, internal));
} else {
return dataProvider.Role.findOne({name: 'Owner'}).then(function (ownerRole) {
setupUser.roles = [ownerRole.id];
return dataProvider.User.add(setupUser, internal);
});
}
}).then(function (user) {
var userSettings = [];
// Handles the additional values set by the setup screen.
if (!_.isEmpty(setupUser.blogTitle)) {
userSettings.push({key: 'title', value: setupUser.blogTitle});
userSettings.push({key: 'description', value: 'Thoughts, stories and ideas.'});
}
setupUser = user.toJSON(internal);
return settings.edit({settings: userSettings}, {context: {user: setupUser.id}});
}).then(function () {
var data = {
ownerEmail: setupUser.email
};
@ -260,22 +271,21 @@ authentication = {
});
},
revoke: function (object) {
var token;
if (object.token_type_hint && object.token_type_hint === 'access_token') {
token = dataProvider.Accesstoken;
} else if (object.token_type_hint && object.token_type_hint === 'refresh_token') {
token = dataProvider.Refreshtoken;
} else {
return errors.BadRequestError('Invalid token_type_hint given.');
updateSetup: function updateSetup(object, options) {
if (!options.context || !options.context.user) {
return Promise.reject(new errors.NoPermissionError('You are not logged in.'));
}
return token.destroyByToken({token: object.token}).then(function () {
return Promise.resolve({token: object.token});
}, function () {
// On error we still want a 200. See https://tools.ietf.org/html/rfc7009#page-5
return Promise.resolve({token: object.token, error: 'Invalid token provided'});
return dataProvider.User.findOne({role: 'Owner', status: 'all'}).then(function (result) {
var user = result.toJSON();
if (user.id !== options.context.user) {
return Promise.reject(new errors.NoPermissionError('You are not the blog owner.'));
}
return setupTasks(object);
}).then(function (result) {
return Promise.resolve({users: [result]});
});
}
};

View File

@ -111,7 +111,8 @@ middleware = {
});
if (subPath.indexOf('/ghost/api/') === 0
&& path.indexOf('/ghost/api/v0.1/authentication/') !== 0) {
&& (path.indexOf('/ghost/api/v0.1/authentication/') !== 0
|| (path.indexOf('/ghost/api/v0.1/authentication/') === 0 && req.method === 'PUT'))) {
return passport.authenticate('bearer', {session: false, failWithError: true},
function authenticate(err, user, info) {
if (err) {

View File

@ -77,6 +77,7 @@ apiRoutes = function apiRoutes(middleware) {
router.post('/authentication/invitation', api.http(api.authentication.acceptInvitation));
router.get('/authentication/invitation', api.http(api.authentication.isInvitation));
router.post('/authentication/setup', api.http(api.authentication.setup));
router.put('/authentication/setup', api.http(api.authentication.updateSetup));
router.get('/authentication/setup', api.http(api.authentication.isSetup));
router.post('/authentication/token',
middleware.spamPrevention.signin,

View File

@ -7,7 +7,8 @@ var testUtils = require('../../utils'),
// Stuff we are testing
mail = rewire('../../../server/api/mail'),
AuthAPI = require('../../../server/api/authentication');
AuthAPI = require('../../../server/api/authentication'),
context = testUtils.context;
describe('Authentication API', function () {
// Keep the DB clean
@ -81,7 +82,7 @@ describe('Authentication API', function () {
name: 'test user',
email: 'test@example.com',
password: 'areallygoodpassword',
title: 'a test blog'
blogTitle: 'a test blog'
};
AuthAPI.setup({setup: [setupData]}).then(function () {
@ -98,6 +99,112 @@ describe('Authentication API', function () {
});
});
describe('Setup Update', function () {
describe('Setup not complete', function () {
beforeEach(testUtils.setup('roles', 'owner:pre', 'settings', 'perms:setting', 'perms:init'));
it('should report that setup has not been completed', function (done) {
AuthAPI.isSetup().then(function (result) {
should.exist(result);
result.setup[0].status.should.be.false;
done();
}).catch(done);
});
it('should not allow setup to be updated', function (done) {
var setupData = {
name: 'test user',
email: 'test@example.com',
password: 'areallygoodpassword',
blogTitle: 'a test blog'
};
AuthAPI.updateSetup({setup: [setupData]}, {}).then(function () {
done(new Error('Update was able to be run'));
}).catch(function (err) {
should.exist(err);
err.name.should.equal('NoPermissionError');
err.code.should.equal(403);
done();
});
});
});
describe('Not Owner', function () {
beforeEach(testUtils.setup('roles', 'users:roles', 'settings', 'perms:setting', 'perms:init', 'perms:user'));
it('should report that setup has been completed', function (done) {
AuthAPI.isSetup().then(function (result) {
should.exist(result);
result.setup[0].status.should.be.true;
done();
}).catch(done);
});
it('should not allow setup to be updated', function (done) {
var setupData = {
name: 'test user',
email: 'test@example.com',
password: 'areallygoodpassword',
blogTitle: 'a test blog'
};
AuthAPI.updateSetup({setup: [setupData]}, context.author).then(function () {
done(new Error('Update was able to be run'));
}).catch(function (err) {
should.exist(err);
err.name.should.equal('NoPermissionError');
err.code.should.equal(403);
done();
});
});
});
describe('Owner', function () {
beforeEach(testUtils.setup('roles', 'users:roles', 'settings', 'perms:setting', 'perms:init'));
it('should report that setup has been completed', function (done) {
AuthAPI.isSetup().then(function (result) {
should.exist(result);
result.setup[0].status.should.be.true;
done();
}).catch(done);
});
it('should allow setup to be updated', function (done) {
var setupData = {
name: 'test user',
email: 'test@example.com',
password: 'areallygoodpassword',
blogTitle: 'a test blog'
};
AuthAPI.updateSetup({setup: [setupData]}, context.owner).then(function (result) {
should.exist(result);
should.exist(result.users);
should.not.exist(result.meta);
result.users.should.have.length(1);
testUtils.API.checkResponse(result.users[0], 'user');
var newUser = result.users[0];
newUser.id.should.equal(1);
newUser.name.should.equal(setupData.name);
newUser.email.should.equal(setupData.email);
done();
}).catch(done);
});
});
});
// describe('Authentication', function () {
// describe('Setup not completed', function () {