diff --git a/common/models/user.js b/common/models/user.js index 032a5d3d41..39080d1ff4 100644 --- a/common/models/user.js +++ b/common/models/user.js @@ -591,33 +591,26 @@ module.exports = function(User) { User.prototype.requestAuthEmail = requestAuthEmail; User.prototype.requestUpdateEmail = function requestUpdateEmail(newEmail) { + const currentEmail = this.email; const isOwnEmail = isTheSame(newEmail, currentEmail); - const sameUpdate = isTheSame(newEmail, this.newEmail); - const messageOrNull = getWaitMessage(this.emailVerifyTTL); - if (isOwnEmail) { - if (this.emailVerified) { - // email is already associated and verified with this account - throw wrapHandledError( - new Error('email is already verified'), - { - type: 'info', - message: `${newEmail} is already associated with this account.` - } - ); - } else if (!this.emailVerified && messageOrNull) { - // email is associated but unverified and - // email is within time limit - throw wrapHandledError( - new Error(), - { - type: 'info', - message: messageOrNull - } - ); + const isResendUpdateToSameEmail = isTheSame(newEmail, this.newEmail); + const isLinkSentWithinLimit = getWaitMessage(this.emailVerifyTTL); + const isVerifiedEmail = this.emailVerified; + + if (isOwnEmail && isVerifiedEmail) { + // email is already associated and verified with this account + throw wrapHandledError( + new Error('email is already verified'), + { + type: 'info', + message: ` + ${newEmail} is already associated with this account. + You can update a new email address instead.` } + ); } - if (sameUpdate && messageOrNull) { + if (isResendUpdateToSameEmail && isLinkSentWithinLimit) { // trying to update with the same newEmail and // confirmation email is still valid throw wrapHandledError( @@ -626,29 +619,34 @@ module.exports = function(User) { type: 'info', message: dedent` We have already sent an email confirmation request to ${newEmail}. - Please check your inbox.` + ${isLinkSentWithinLimit}` } ); } if (!isEmail('' + newEmail)) { throw createEmailError(); } + // newEmail is not associated with this user, and // this attempt to change email is the first or // previous attempts have expired - - if (isOwnEmail || (sameUpdate && !messageOrNull)) { - const update = { + if ( + !isOwnEmail || + (isOwnEmail && !isVerifiedEmail) || + (isResendUpdateToSameEmail && !isLinkSentWithinLimit) + ) { + const updateConfig = { newEmail, emailVerified: false, emailVerifyTTL: new Date() }; - return this.update$(update).toPromise() - .then(() => { - Object.assign(this, update); - return; - }) - .then(() => this.requestAuthEmail(false, newEmail).toPromise()); + return Observable.forkJoin( + this.update$(updateConfig), + this.requestAuthEmail(false, newEmail), + (user, message) => ({ user, message }) + ) + .map(({ message }) => message); + } else { return 'Something unexpected happened whilst updating your email.'; } diff --git a/server/boot/settings.js b/server/boot/settings.js index 4ccfa2944b..e240dd2e48 100644 --- a/server/boot/settings.js +++ b/server/boot/settings.js @@ -37,9 +37,13 @@ export default function settingsController(app) { .withMessage('Email format is invalid.') ]; - function updateMyEmail(req, res) { + function updateMyEmail(req, res, next) { const { user, body: { email } } = req; - return res.json({ message: user.requestUpdateEmail(email) } ); + return user.requestUpdateEmail(email) + .subscribe( + (message) => res.json({ message: message }), + next + ); } const updateMyCurrentChallengeValidators = [