mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
do not use v1 for setting default email
GitOrigin-RevId: 00d4610ae55c0a90699d4bc79e7d08d432087abe
This commit is contained in:
parent
0a2a32120f
commit
d9b5941642
5 changed files with 117 additions and 144 deletions
|
@ -87,18 +87,12 @@ module.exports = UserEmailsController = {
|
||||||
if (email == null) {
|
if (email == null) {
|
||||||
return res.sendStatus(422)
|
return res.sendStatus(422)
|
||||||
}
|
}
|
||||||
|
UserUpdater.setDefaultEmailAddress(userId, email, err => {
|
||||||
return UserUpdater.updateV1AndSetDefaultEmailAddress(
|
if (err) {
|
||||||
userId,
|
return UserEmailsController._handleEmailError(err, req, res, next)
|
||||||
email,
|
|
||||||
function(error) {
|
|
||||||
if (error != null) {
|
|
||||||
return UserEmailsController._handleEmailError(error, req, res, next)
|
|
||||||
} else {
|
|
||||||
return res.sendStatus(200)
|
|
||||||
}
|
}
|
||||||
}
|
res.sendStatus(200)
|
||||||
)
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
endorse(req, res, next) {
|
endorse(req, res, next) {
|
||||||
|
|
|
@ -28,8 +28,6 @@ const {
|
||||||
const FeaturesUpdater = require('../Subscription/FeaturesUpdater')
|
const FeaturesUpdater = require('../Subscription/FeaturesUpdater')
|
||||||
const EmailHelper = require('../Helpers/EmailHelper')
|
const EmailHelper = require('../Helpers/EmailHelper')
|
||||||
const Errors = require('../Errors/Errors')
|
const Errors = require('../Errors/Errors')
|
||||||
const Settings = require('settings-sharelatex')
|
|
||||||
const request = require('request')
|
|
||||||
const NewsletterManager = require('../Newsletter/NewsletterManager')
|
const NewsletterManager = require('../Newsletter/NewsletterManager')
|
||||||
|
|
||||||
module.exports = UserUpdater = {
|
module.exports = UserUpdater = {
|
||||||
|
@ -71,7 +69,7 @@ module.exports = UserUpdater = {
|
||||||
return cb(error)
|
return cb(error)
|
||||||
}),
|
}),
|
||||||
cb => UserUpdater.addEmailAddress(userId, newEmail, cb),
|
cb => UserUpdater.addEmailAddress(userId, newEmail, cb),
|
||||||
cb => UserUpdater.setDefaultEmailAddress(userId, newEmail, cb),
|
cb => UserUpdater.setDefaultEmailAddress(userId, newEmail, true, cb),
|
||||||
cb => UserUpdater.removeEmailAddress(userId, oldEmail, cb)
|
cb => UserUpdater.removeEmailAddress(userId, oldEmail, cb)
|
||||||
],
|
],
|
||||||
callback
|
callback
|
||||||
|
@ -156,112 +154,47 @@ module.exports = UserUpdater = {
|
||||||
|
|
||||||
// set the default email address by setting the `email` attribute. The email
|
// set the default email address by setting the `email` attribute. The email
|
||||||
// must be one of the user's multiple emails (`emails` attribute)
|
// must be one of the user's multiple emails (`emails` attribute)
|
||||||
setDefaultEmailAddress(userId, email, callback) {
|
setDefaultEmailAddress(userId, email, allowUnconfirmed, callback) {
|
||||||
|
if (typeof allowUnconfirmed === 'function') {
|
||||||
|
callback = allowUnconfirmed
|
||||||
|
allowUnconfirmed = false
|
||||||
|
}
|
||||||
email = EmailHelper.parseEmail(email)
|
email = EmailHelper.parseEmail(email)
|
||||||
if (email == null) {
|
if (email == null) {
|
||||||
return callback(new Error('invalid email'))
|
return callback(new Error('invalid email'))
|
||||||
}
|
}
|
||||||
return UserGetter.getUserEmail(userId, (error, oldEmail) => {
|
UserGetter.getUser(userId, { email: 1, emails: 1 }, (err, user) => {
|
||||||
if (typeof err !== 'undefined' && err !== null) {
|
if (err) {
|
||||||
return callback(error)
|
return callback(err)
|
||||||
|
}
|
||||||
|
if (!user) {
|
||||||
|
return callback(new Error('invalid userId'))
|
||||||
|
}
|
||||||
|
const oldEmail = user.email
|
||||||
|
const userEmail = user.emails.find(e => e.email === email)
|
||||||
|
if (!userEmail) {
|
||||||
|
return callback(new Error('Default email does not belong to user'))
|
||||||
|
}
|
||||||
|
if (!userEmail.confirmedAt && !allowUnconfirmed) {
|
||||||
|
return callback(new Errors.UnconfirmedEmailError())
|
||||||
}
|
}
|
||||||
const query = { _id: userId, 'emails.email': email }
|
const query = { _id: userId, 'emails.email': email }
|
||||||
const update = { $set: { email } }
|
const update = { $set: { email } }
|
||||||
return this.updateUser(query, update, function(error, res) {
|
UserUpdater.updateUser(query, update, (err, res) => {
|
||||||
if (error != null) {
|
if (err) {
|
||||||
logger.warn({ error }, 'problem setting default emails')
|
return callback(err)
|
||||||
return callback(error)
|
|
||||||
} else if (res.n === 0) {
|
|
||||||
// TODO: Check n or nMatched?
|
|
||||||
return callback(new Error('Default email does not belong to user'))
|
|
||||||
} else {
|
|
||||||
NewsletterManager.changeEmail(oldEmail, email, function() {})
|
|
||||||
return callback()
|
|
||||||
}
|
}
|
||||||
|
// this should not happen
|
||||||
|
if (res.n === 0) {
|
||||||
|
return callback(new Error('email update error'))
|
||||||
|
}
|
||||||
|
// do not wait - this will log its own errors
|
||||||
|
NewsletterManager.changeEmail(oldEmail, email, () => {})
|
||||||
|
callback()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
updateV1AndSetDefaultEmailAddress(userId, email, callback) {
|
|
||||||
return this.updateEmailAddressInV1(userId, email, error => {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
return this.setDefaultEmailAddress(userId, email, callback)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
updateEmailAddressInV1(userId, newEmail, callback) {
|
|
||||||
if (!Settings.apis.v1.url) {
|
|
||||||
return callback()
|
|
||||||
}
|
|
||||||
return UserGetter.getUser(userId, { 'overleaf.id': 1, emails: 1 }, function(
|
|
||||||
error,
|
|
||||||
user
|
|
||||||
) {
|
|
||||||
let email
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
if (user == null) {
|
|
||||||
return callback(new Errors.NotFoundError('no user found'))
|
|
||||||
}
|
|
||||||
if ((user.overleaf != null ? user.overleaf.id : undefined) == null) {
|
|
||||||
return callback()
|
|
||||||
}
|
|
||||||
let newEmailIsConfirmed = false
|
|
||||||
for (email of Array.from(user.emails)) {
|
|
||||||
if (email.email === newEmail && email.confirmedAt != null) {
|
|
||||||
newEmailIsConfirmed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!newEmailIsConfirmed) {
|
|
||||||
return callback(
|
|
||||||
new Errors.UnconfirmedEmailError(
|
|
||||||
"can't update v1 with unconfirmed email"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return request(
|
|
||||||
{
|
|
||||||
baseUrl: Settings.apis.v1.url,
|
|
||||||
url: `/api/v1/sharelatex/users/${user.overleaf.id}/email`,
|
|
||||||
method: 'PUT',
|
|
||||||
auth: {
|
|
||||||
user: Settings.apis.v1.user,
|
|
||||||
pass: Settings.apis.v1.pass,
|
|
||||||
sendImmediately: true
|
|
||||||
},
|
|
||||||
json: {
|
|
||||||
user: {
|
|
||||||
email: newEmail
|
|
||||||
}
|
|
||||||
},
|
|
||||||
timeout: 5 * 1000
|
|
||||||
},
|
|
||||||
function(error, response, body) {
|
|
||||||
if (error != null) {
|
|
||||||
if (error.code === 'ECONNREFUSED') {
|
|
||||||
error = new Errors.V1ConnectionError('No V1 connection')
|
|
||||||
}
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
if (response.statusCode === 409) {
|
|
||||||
// Conflict
|
|
||||||
return callback(new Errors.EmailExistsError('email exists in v1'))
|
|
||||||
} else if (response.statusCode >= 200 && response.statusCode < 300) {
|
|
||||||
return callback()
|
|
||||||
} else {
|
|
||||||
return callback(
|
|
||||||
new Error(`non-success code from v1: ${response.statusCode}`)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
confirmEmail(userId, email, confirmedAt, callback) {
|
confirmEmail(userId, email, confirmedAt, callback) {
|
||||||
if (arguments.length === 3) {
|
if (arguments.length === 3) {
|
||||||
callback = confirmedAt
|
callback = confirmedAt
|
||||||
|
|
|
@ -653,7 +653,7 @@ describe('UserEmails', function() {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should update the email in v1 if confirmed', function(done) {
|
it('should not update the email in v1', function(done) {
|
||||||
const token = null
|
const token = null
|
||||||
return async.series(
|
return async.series(
|
||||||
[
|
[
|
||||||
|
@ -725,18 +725,13 @@ describe('UserEmails', function() {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return done(error)
|
return done(error)
|
||||||
}
|
}
|
||||||
expect(
|
expect(MockV1Api.updateEmail.callCount).to.equal(0)
|
||||||
MockV1Api.updateEmail.calledWith(
|
done()
|
||||||
42,
|
|
||||||
'new-confirmed-default-in-v1@example.com'
|
|
||||||
)
|
|
||||||
).to.equal(true)
|
|
||||||
return done()
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return an error if the email exists in v1', function(done) {
|
it('should not return an error if the email exists in v1', function(done) {
|
||||||
MockV1Api.existingEmails.push('exists-in-v1@example.com')
|
MockV1Api.existingEmails.push('exists-in-v1@example.com')
|
||||||
return async.series(
|
return async.series(
|
||||||
[
|
[
|
||||||
|
@ -798,11 +793,8 @@ describe('UserEmails', function() {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return done(error)
|
return done(error)
|
||||||
}
|
}
|
||||||
expect(response.statusCode).to.equal(409)
|
expect(response.statusCode).to.equal(200)
|
||||||
expect(body).to.deep.equal({
|
cb()
|
||||||
message: 'This email is already registered'
|
|
||||||
})
|
|
||||||
return cb()
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -810,8 +802,8 @@ describe('UserEmails', function() {
|
||||||
return this.user.request(
|
return this.user.request(
|
||||||
{ url: '/user/emails', json: true },
|
{ url: '/user/emails', json: true },
|
||||||
function(error, response, body) {
|
function(error, response, body) {
|
||||||
expect(body[0].default).to.equal(true)
|
expect(body[0].default).to.equal(false)
|
||||||
expect(body[1].default).to.equal(false)
|
expect(body[1].default).to.equal(true)
|
||||||
return cb()
|
return cb()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -187,22 +187,22 @@ describe('UserEmailsController', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.email = 'email_to_set_default@bar.com'
|
this.email = 'email_to_set_default@bar.com'
|
||||||
this.req.body.email = this.email
|
this.req.body.email = this.email
|
||||||
return this.EmailHelper.parseEmail.returns(this.email)
|
this.EmailHelper.parseEmail.returns(this.email)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sets default email', function(done) {
|
it('sets default email', function(done) {
|
||||||
this.UserUpdater.updateV1AndSetDefaultEmailAddress.callsArgWith(2, null)
|
this.UserUpdater.setDefaultEmailAddress.yields()
|
||||||
|
|
||||||
return this.UserEmailsController.setDefault(this.req, {
|
this.UserEmailsController.setDefault(this.req, {
|
||||||
sendStatus: code => {
|
sendStatus: code => {
|
||||||
code.should.equal(200)
|
code.should.equal(200)
|
||||||
assertCalledWith(this.EmailHelper.parseEmail, this.email)
|
assertCalledWith(this.EmailHelper.parseEmail, this.email)
|
||||||
assertCalledWith(
|
assertCalledWith(
|
||||||
this.UserUpdater.updateV1AndSetDefaultEmailAddress,
|
this.UserUpdater.setDefaultEmailAddress,
|
||||||
this.user._id,
|
this.user._id,
|
||||||
this.email
|
this.email
|
||||||
)
|
)
|
||||||
return done()
|
done()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -210,7 +210,7 @@ describe('UserEmailsController', function() {
|
||||||
it('handles email parse error', function(done) {
|
it('handles email parse error', function(done) {
|
||||||
this.EmailHelper.parseEmail.returns(null)
|
this.EmailHelper.parseEmail.returns(null)
|
||||||
|
|
||||||
return this.UserEmailsController.setDefault(this.req, {
|
this.UserEmailsController.setDefault(this.req, {
|
||||||
sendStatus: code => {
|
sendStatus: code => {
|
||||||
code.should.equal(422)
|
code.should.equal(422)
|
||||||
assertNotCalled(this.UserUpdater.setDefaultEmailAddress)
|
assertNotCalled(this.UserUpdater.setDefaultEmailAddress)
|
||||||
|
|
|
@ -74,7 +74,8 @@ describe('UserUpdater', function() {
|
||||||
name: 'bob',
|
name: 'bob',
|
||||||
email: 'hello@world.com'
|
email: 'hello@world.com'
|
||||||
}
|
}
|
||||||
return (this.newEmail = 'bob@bob.com')
|
this.newEmail = 'bob@bob.com'
|
||||||
|
this.callback = sinon.stub()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => tk.reset())
|
afterEach(() => tk.reset())
|
||||||
|
@ -83,7 +84,7 @@ describe('UserUpdater', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.UserGetter.getUserEmail.callsArgWith(1, null, this.stubbedUser.email)
|
this.UserGetter.getUserEmail.callsArgWith(1, null, this.stubbedUser.email)
|
||||||
this.UserUpdater.addEmailAddress = sinon.stub().callsArgWith(2)
|
this.UserUpdater.addEmailAddress = sinon.stub().callsArgWith(2)
|
||||||
this.UserUpdater.setDefaultEmailAddress = sinon.stub().callsArgWith(2)
|
this.UserUpdater.setDefaultEmailAddress = sinon.stub().yields()
|
||||||
return (this.UserUpdater.removeEmailAddress = sinon
|
return (this.UserUpdater.removeEmailAddress = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(2))
|
.callsArgWith(2))
|
||||||
|
@ -325,14 +326,20 @@ describe('UserUpdater', function() {
|
||||||
|
|
||||||
describe('setDefaultEmailAddress', function() {
|
describe('setDefaultEmailAddress', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.UserGetter.getUserEmail.callsArgWith(1, null, this.stubbedUser.email)
|
this.stubbedUser.emails = [
|
||||||
return this.NewsletterManager.changeEmail.callsArgWith(2, null)
|
{
|
||||||
|
email: this.newEmail,
|
||||||
|
confirmedAt: new Date()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.UserGetter.getUser = sinon.stub().yields(null, this.stubbedUser)
|
||||||
|
this.NewsletterManager.changeEmail.callsArgWith(2, null)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('set default', function(done) {
|
it('set default', function(done) {
|
||||||
this.UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, { n: 1 })
|
this.UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, { n: 1 })
|
||||||
|
|
||||||
return this.UserUpdater.setDefaultEmailAddress(
|
this.UserUpdater.setDefaultEmailAddress(
|
||||||
this.stubbedUser._id,
|
this.stubbedUser._id,
|
||||||
this.newEmail,
|
this.newEmail,
|
||||||
err => {
|
err => {
|
||||||
|
@ -343,7 +350,7 @@ describe('UserUpdater', function() {
|
||||||
{ $set: { email: this.newEmail } }
|
{ $set: { email: this.newEmail } }
|
||||||
)
|
)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
return done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -351,7 +358,7 @@ describe('UserUpdater', function() {
|
||||||
it('set changed the email in newsletter', function(done) {
|
it('set changed the email in newsletter', function(done) {
|
||||||
this.UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, { n: 1 })
|
this.UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, { n: 1 })
|
||||||
|
|
||||||
return this.UserUpdater.setDefaultEmailAddress(
|
this.UserUpdater.setDefaultEmailAddress(
|
||||||
this.stubbedUser._id,
|
this.stubbedUser._id,
|
||||||
this.newEmail,
|
this.newEmail,
|
||||||
err => {
|
err => {
|
||||||
|
@ -359,7 +366,7 @@ describe('UserUpdater', function() {
|
||||||
this.NewsletterManager.changeEmail
|
this.NewsletterManager.changeEmail
|
||||||
.calledWith(this.stubbedUser.email, this.newEmail)
|
.calledWith(this.stubbedUser.email, this.newEmail)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
return done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -369,12 +376,12 @@ describe('UserUpdater', function() {
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(2, new Error('nope'))
|
.callsArgWith(2, new Error('nope'))
|
||||||
|
|
||||||
return this.UserUpdater.setDefaultEmailAddress(
|
this.UserUpdater.setDefaultEmailAddress(
|
||||||
this.stubbedUser._id,
|
this.stubbedUser._id,
|
||||||
this.newEmail,
|
this.newEmail,
|
||||||
err => {
|
err => {
|
||||||
should.exist(err)
|
should.exist(err)
|
||||||
return done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -382,26 +389,73 @@ describe('UserUpdater', function() {
|
||||||
it('handle missed update', function(done) {
|
it('handle missed update', function(done) {
|
||||||
this.UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, { n: 0 })
|
this.UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, { n: 0 })
|
||||||
|
|
||||||
return this.UserUpdater.setDefaultEmailAddress(
|
this.UserUpdater.setDefaultEmailAddress(
|
||||||
this.stubbedUser._id,
|
this.stubbedUser._id,
|
||||||
this.newEmail,
|
this.newEmail,
|
||||||
err => {
|
err => {
|
||||||
should.exist(err)
|
should.exist(err)
|
||||||
return done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('validates email', function(done) {
|
it('validates email', function(done) {
|
||||||
return this.UserUpdater.setDefaultEmailAddress(
|
this.UserUpdater.setDefaultEmailAddress(
|
||||||
this.stubbedUser._id,
|
this.stubbedUser._id,
|
||||||
'.edu',
|
'.edu',
|
||||||
err => {
|
err => {
|
||||||
should.exist(err)
|
should.exist(err)
|
||||||
return done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when email not confirmed', () => {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.stubbedUser.emails = [
|
||||||
|
{
|
||||||
|
email: this.newEmail,
|
||||||
|
confirmedAt: null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.UserGetter.getUser = sinon.stub().yields(null, this.stubbedUser)
|
||||||
|
this.UserUpdater.updateUser = sinon.stub()
|
||||||
|
this.NewsletterManager.changeEmail = sinon.stub()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should callback with error', function() {
|
||||||
|
this.UserUpdater.setDefaultEmailAddress(
|
||||||
|
this.stubbedUser._id,
|
||||||
|
this.newEmail,
|
||||||
|
this.callback
|
||||||
|
)
|
||||||
|
this.callback.firstCall.args[0].name.should.equal(
|
||||||
|
'UnconfirmedEmailError'
|
||||||
|
)
|
||||||
|
this.UserUpdater.updateUser.callCount.should.equal(0)
|
||||||
|
this.NewsletterManager.changeEmail.callCount.should.equal(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when email does not belong to user', () => {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.stubbedUser.emails = []
|
||||||
|
this.UserGetter.getUser = sinon.stub().yields(null, this.stubbedUser)
|
||||||
|
this.UserUpdater.updateUser = sinon.stub()
|
||||||
|
this.NewsletterManager.changeEmail = sinon.stub()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should callback with error', function() {
|
||||||
|
this.UserUpdater.setDefaultEmailAddress(
|
||||||
|
this.stubbedUser._id,
|
||||||
|
this.newEmail,
|
||||||
|
this.callback
|
||||||
|
)
|
||||||
|
this.callback.firstCall.args[0].name.should.equal('Error')
|
||||||
|
this.UserUpdater.updateUser.callCount.should.equal(0)
|
||||||
|
this.NewsletterManager.changeEmail.callCount.should.equal(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirmEmail', function() {
|
describe('confirmEmail', function() {
|
||||||
|
|
Loading…
Reference in a new issue