From b1c1b030152092cc2669bf697896aa22b60c6b9e Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Sun, 24 Aug 2014 19:34:26 -0700 Subject: [PATCH] Redirect user if signup invitation isn't valid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #3565 - Added server API isInvitation (analog to isSetup), checking if an invitation exists for a given email address. - If the invitation is no longer valid (or didn’t exist in the first place), the user is redirected and an error notification is shown. --- core/client/routes/signup.js | 21 ++++++++++++++++++++- core/server/api/authentication.js | 30 ++++++++++++++++++++++++++++++ core/server/routes/api.js | 1 + 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/core/client/routes/signup.js b/core/client/routes/signup.js index eb88079974..8c008b10a0 100644 --- a/core/client/routes/signup.js +++ b/core/client/routes/signup.js @@ -1,3 +1,4 @@ +import ajax from 'ghost/utils/ajax'; import styleBody from 'ghost/mixins/style-body'; import loadingIndicator from 'ghost/mixins/loading-indicator'; @@ -10,7 +11,8 @@ var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, { } }, setupController: function (controller, params) { - var tokenText, + var self = this, + tokenText, email, re = /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/; if (re.test(params.token)) { @@ -23,6 +25,23 @@ var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, { this.transitionTo('signin'); this.notifications.showError('Invalid token.', {delayed: true}); } + + ajax({ + url: this.get('ghostPaths.url').api('authentication', 'invitation'), + type: 'GET', + dataType: 'json', + data: { + email: email + } + }).then(function (response) { + if (response && response.invitation && response.invitation[0].valid === false) { + self.transitionTo('signin'); + self.notifications.showError('The invitation does not exist or is no longer valid.', {delayed: true}); + } + }).catch(function (error) { + self.notifications.showAPIError(error); + }); + } else { this.transitionTo('signin'); this.notifications.showError('Invalid token.', {delayed: true}); diff --git a/core/server/api/authentication.js b/core/server/api/authentication.js index f84d7c93fc..1fdde8957d 100644 --- a/core/server/api/authentication.js +++ b/core/server/api/authentication.js @@ -148,6 +148,36 @@ authentication = { }); }, + /** + * ### Check for invitation + * @param {Object} options + * @param {string} options.email The email to check for an invitation on + * @returns {Promise(Invitation}} An invitation status + */ + isInvitation: function (options) { + if (!options.email) { + return Promise.reject(new errors.NoPermissionError('The server did not receive a valid email')); + } + + return authentication.isSetup().then(function (result) { + var setup = result.setup[0].status; + + if (!setup) { + return Promise.reject(new errors.NoPermissionError('Setup must be completed before making this request.')); + } + + if (options.email) { + return dataProvider.User.findOne({email: options.email, status: 'invited'}).then(function (response) { + if (response) { + return {invitation: [{valid: true}]}; + } else { + return {invitation: [{valid: false}]}; + } + }); + } + }); + }, + isSetup: function () { return dataProvider.User.query(function (qb) { qb.whereIn('status', ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked']); diff --git a/core/server/routes/api.js b/core/server/routes/api.js index 595ca1a069..348c265033 100644 --- a/core/server/routes/api.js +++ b/core/server/routes/api.js @@ -72,6 +72,7 @@ apiRoutes = function (middleware) { ); router.put('/authentication/passwordreset', api.http(api.authentication.resetPassword)); 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.get('/authentication/setup', api.http(api.authentication.isSetup)); router.post('/authentication/token',