mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Allow user to accept invitation
closes #3081 - added route `/ghost/api/v0.1/authentication/invitation` - added accept invitation - added signup with token - removed check() from users api - fixed promise in resetPassword()
This commit is contained in:
parent
f114f4f2f6
commit
84cfd529ed
8 changed files with 66 additions and 16 deletions
|
@ -5,6 +5,7 @@ var SignupController = Ember.ObjectController.extend(ValidationEngine, {
|
||||||
name: null,
|
name: null,
|
||||||
email: null,
|
email: null,
|
||||||
password: null,
|
password: null,
|
||||||
|
token: null,
|
||||||
submitting: false,
|
submitting: false,
|
||||||
|
|
||||||
// ValidationEngine settings
|
// ValidationEngine settings
|
||||||
|
@ -12,16 +13,25 @@ var SignupController = Ember.ObjectController.extend(ValidationEngine, {
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
signup: function () {
|
signup: function () {
|
||||||
var self = this;
|
var self = this,
|
||||||
|
data = self.getProperties('name', 'email', 'password', 'token');
|
||||||
|
|
||||||
self.notifications.closePassive();
|
self.notifications.closePassive();
|
||||||
|
|
||||||
this.toggleProperty('submitting');
|
this.toggleProperty('submitting');
|
||||||
this.validate({ format: false }).then(function () {
|
this.validate({ format: false }).then(function () {
|
||||||
ajax({
|
ajax({
|
||||||
url: self.get('ghostPaths').adminUrl('signup'),
|
url: self.get('ghostPaths').apiUrl('authentication', 'invitation'),
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: self.getProperties('name', 'email', 'password')
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
invitation: [{
|
||||||
|
name: data.name,
|
||||||
|
email: data.email,
|
||||||
|
password: data.password,
|
||||||
|
token: data.token
|
||||||
|
}]
|
||||||
|
}
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
self.get('session').authenticate('ember-simple-auth-authenticator:oauth2-password-grant', {
|
self.get('session').authenticate('ember-simple-auth-authenticator:oauth2-password-grant', {
|
||||||
identification: self.get('email'),
|
identification: self.get('email'),
|
||||||
|
|
|
@ -18,7 +18,7 @@ Router.map(function () {
|
||||||
this.route('setup');
|
this.route('setup');
|
||||||
this.route('signin');
|
this.route('signin');
|
||||||
this.route('signout');
|
this.route('signout');
|
||||||
this.route('signup');
|
this.route('signup', { path: '/signup/:token' });
|
||||||
this.route('forgotten');
|
this.route('forgotten');
|
||||||
this.route('reset', { path: '/reset/:token' });
|
this.route('reset', { path: '/reset/:token' });
|
||||||
this.resource('posts', { path: '/' }, function () {
|
this.resource('posts', { path: '/' }, function () {
|
||||||
|
|
|
@ -2,7 +2,19 @@ import styleBody from 'ghost/mixins/style-body';
|
||||||
import loadingIndicator from 'ghost/mixins/loading-indicator';
|
import loadingIndicator from 'ghost/mixins/loading-indicator';
|
||||||
|
|
||||||
var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
||||||
classNames: ['ghost-signup']
|
classNames: ['ghost-signup'],
|
||||||
|
beforeModel: function () {
|
||||||
|
if (this.get('session').isAuthenticated) {
|
||||||
|
this.transitionTo(Ember.SimpleAuth.routeAfterAuthentication);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setupController: function (controller, params) {
|
||||||
|
var tokenText = atob(params.token),
|
||||||
|
email = tokenText.split('|')[1];
|
||||||
|
controller.token = params.token;
|
||||||
|
controller.email = email;
|
||||||
|
controller.name = email.substring(0, email.indexOf('@'));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default SignupRoute;
|
export default SignupRoute;
|
||||||
|
|
|
@ -91,6 +91,38 @@ authentication = {
|
||||||
return when.reject(new errors.UnauthorizedError(error.message));
|
return when.reject(new errors.UnauthorizedError(error.message));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ### Accept Invitation
|
||||||
|
* @param {User} object the user to create
|
||||||
|
* @returns {Promise(User}} Newly created user
|
||||||
|
*/
|
||||||
|
acceptInvitation: function acceptInvitation(object) {
|
||||||
|
var resetToken,
|
||||||
|
newPassword,
|
||||||
|
ne2Password,
|
||||||
|
name,
|
||||||
|
email;
|
||||||
|
|
||||||
|
return utils.checkObject(object, 'invitation').then(function (checkedInvitation) {
|
||||||
|
resetToken = checkedInvitation.invitation[0].token;
|
||||||
|
newPassword = checkedInvitation.invitation[0].password;
|
||||||
|
ne2Password = checkedInvitation.invitation[0].password;
|
||||||
|
email = checkedInvitation.invitation[0].email;
|
||||||
|
name = checkedInvitation.invitation[0].name;
|
||||||
|
|
||||||
|
return settings.read({context: {internal: true}, key: 'dbHash'}).then(function (response) {
|
||||||
|
var dbHash = response.settings[0].value;
|
||||||
|
return dataProvider.User.resetPassword(resetToken, newPassword, ne2Password, dbHash);
|
||||||
|
}).then(function (user) {
|
||||||
|
return dataProvider.User.edit({name: name, email: email}, {id: user.id});
|
||||||
|
}).then(function () {
|
||||||
|
return when.resolve({invitation: [{message: 'Invitation accepted.'}]});
|
||||||
|
}).otherwise(function (error) {
|
||||||
|
return when.reject(new errors.UnauthorizedError(error.message));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ users = {
|
||||||
* @param {{context}} options
|
* @param {{context}} options
|
||||||
* @returns {Promise(User}} Newly created user
|
* @returns {Promise(User}} Newly created user
|
||||||
*/
|
*/
|
||||||
|
// TODO: remove and rename invite to add when setup is implemented
|
||||||
add: function add(object, options) {
|
add: function add(object, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
@ -213,16 +214,12 @@ users = {
|
||||||
* @param {User} object the user to create
|
* @param {User} object the user to create
|
||||||
* @returns {Promise(User}} Newly created user
|
* @returns {Promise(User}} Newly created user
|
||||||
*/
|
*/
|
||||||
// TODO: create a proper API end point and use JSON API format
|
// TODO: remove when setup is implemented
|
||||||
register: function register(object) {
|
register: function register(object) {
|
||||||
// TODO: if we want to prevent users from being created with the signup form this is the right place to do it
|
// TODO: if we want to prevent users from being created with the signup form this is the right place to do it
|
||||||
return users.add(object, {context: {internal: true}});
|
return users.add(object, {context: {internal: true}});
|
||||||
},
|
},
|
||||||
|
|
||||||
check: function check(object) {
|
|
||||||
return dataProvider.User.check(object);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ### Change Password
|
* ### Change Password
|
||||||
* @param {password} object
|
* @param {password} object
|
||||||
|
|
|
@ -50,8 +50,7 @@ var middleware = {
|
||||||
|
|
||||||
if (res.isAdmin) {
|
if (res.isAdmin) {
|
||||||
if (subPath.indexOf('/ghost/api/') === 0
|
if (subPath.indexOf('/ghost/api/') === 0
|
||||||
&& path.indexOf('/ghost/api/v0.1/authentication/token') !== 0
|
&& path.indexOf('/ghost/api/v0.1/authentication/') !== 0) {
|
||||||
&& path.indexOf('/ghost/api/v0.1/authentication/passwordreset/') !== 0) {
|
|
||||||
|
|
||||||
return passport.authenticate('bearer', { session: false, failWithError: true },
|
return passport.authenticate('bearer', { session: false, failWithError: true },
|
||||||
function (err, user, info) {
|
function (err, user, info) {
|
||||||
|
|
|
@ -216,7 +216,6 @@ User = ghostBookshelf.Model.extend({
|
||||||
if (!user || user.get('status') === 'invited') {
|
if (!user || user.get('status') === 'invited') {
|
||||||
return when.reject(new Error('NotFound'));
|
return when.reject(new Error('NotFound'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.get('status') !== 'locked') {
|
if (user.get('status') !== 'locked') {
|
||||||
return nodefn.call(bcrypt.compare, object.password, user.get('password')).then(function (matched) {
|
return nodefn.call(bcrypt.compare, object.password, user.get('password')).then(function (matched) {
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
|
@ -376,9 +375,7 @@ User = ghostBookshelf.Model.extend({
|
||||||
var foundUser = results[0],
|
var foundUser = results[0],
|
||||||
passwordHash = results[1];
|
passwordHash = results[1];
|
||||||
|
|
||||||
foundUser.save({password: passwordHash, status: 'active'});
|
return foundUser.save({password: passwordHash, status: 'active'});
|
||||||
|
|
||||||
return foundUser;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ apiRoutes = function (middleware) {
|
||||||
// ## Authentication
|
// ## Authentication
|
||||||
router.post('/ghost/api/v0.1/authentication/passwordreset', api.http(api.authentication.generateResetToken));
|
router.post('/ghost/api/v0.1/authentication/passwordreset', api.http(api.authentication.generateResetToken));
|
||||||
router.put('/ghost/api/v0.1/authentication/passwordreset', api.http(api.authentication.resetPassword));
|
router.put('/ghost/api/v0.1/authentication/passwordreset', api.http(api.authentication.resetPassword));
|
||||||
|
|
||||||
|
router.post('/ghost/api/v0.1/authentication/invitation', api.http(api.authentication.acceptInvitation));
|
||||||
|
|
||||||
router.post('/ghost/api/v0.1/authentication/token',
|
router.post('/ghost/api/v0.1/authentication/token',
|
||||||
middleware.addClientSecret,
|
middleware.addClientSecret,
|
||||||
middleware.authenticateClient,
|
middleware.authenticateClient,
|
||||||
|
|
Loading…
Add table
Reference in a new issue