Răsfoiți Sursa

Handle v1 response when email is already in use

James Allen 8 ani în urmă
părinte
comite
ca97698724

+ 8 - 0
services/web/app/coffee/Features/Errors/Errors.coffee

@@ -75,6 +75,13 @@ UnconfirmedEmailError = (message) ->
 	return error
 UnconfirmedEmailError.prototype.__proto___ = Error.prototype
 
+EmailExistsError = (message) ->
+	error = new Error(message)
+	error.name = "EmailExistsError"
+	error.__proto__ = EmailExistsError.prototype
+	return error
+EmailExistsError.prototype.__proto___ = Error.prototype
+
 module.exports = Errors =
 	NotFoundError: NotFoundError
 	ServiceNotConfiguredError: ServiceNotConfiguredError
@@ -87,3 +94,4 @@ module.exports = Errors =
 	ProjectHistoryDisabledError: ProjectHistoryDisabledError
 	V1ConnectionError: V1ConnectionError
 	UnconfirmedEmailError: UnconfirmedEmailError
+	EmailExistsError: EmailExistsError

+ 5 - 0
services/web/app/coffee/Features/User/UserEmailsController.coffee

@@ -51,6 +51,11 @@ module.exports = UserEmailsController =
 			if error?
 				if error instanceof Errors.UnconfirmedEmailError
 					return res.sendStatus 409
+				else if error instanceof Errors.EmailExistsError
+					return res.status(409).json {
+						error:
+							message: "The email '#{email}' is already in use by another account"
+					}
 				else
 					return next(error)
 			else

+ 3 - 1
services/web/app/coffee/Features/User/UserUpdater.coffee

@@ -142,7 +142,9 @@ module.exports = UserUpdater =
 				if error?
 					error = new Errors.V1ConnectionError('No V1 connection') if error.code == 'ECONNREFUSED'
 					return callback(error)
-				if 200 <= response.statusCode < 300
+				if response.statusCode == 409 # Conflict
+					return callback(new Errors.EmailExistsError('email exists in v1'))
+				else if 200 <= response.statusCode < 300
 					return callback()
 				else
 					return callback new Error("non-success code from v1: #{response.statusCode}")

+ 52 - 2
services/web/test/acceptance/coffee/UserEmailsTests.coffee

@@ -304,7 +304,7 @@ describe "UserEmails", ->
 			], done
 
 	describe 'setting a default email', ->
-		it 'should update confirmed emails', (done) ->
+		it 'should update confirmed emails for users not in v1', (done) ->
 			token = null
 			async.series [
 				(cb) =>
@@ -384,7 +384,7 @@ describe "UserEmails", ->
 						cb()
 			], done
 
-		it 'should update the email in v2', (done) ->
+		it 'should update the email in v1 if confirmed', (done) ->
 			token = null
 			async.series [
 				(cb) =>
@@ -430,3 +430,53 @@ describe "UserEmails", ->
 					MockV1Api.updateEmail.calledWith(42, 'new-confirmed-default-in-v1@example.com')
 				).to.equal true
 				done()
+
+		it 'should return an error if the email exists in v1', (done) ->
+			MockV1Api.existingEmails.push 'exists-in-v1@example.com'
+			async.series [
+				(cb) =>
+					db.users.update {
+						_id: ObjectId(@user._id)
+					}, {
+						$set: {
+							'overleaf.id': 42
+						}
+					}, cb
+				(cb) =>
+					@user.request {
+						method: 'POST',
+						url: '/user/emails',
+						json:
+							email: 'exists-in-v1@example.com'
+					}, (error, response, body) =>
+						return done(error) if error?
+						expect(response.statusCode).to.equal 204
+						cb()
+				(cb) =>
+					# Mark the email as confirmed
+					db.users.update {
+						'emails.email': 'exists-in-v1@example.com'
+					}, { 
+						$set: {
+							'emails.$.confirmedAt': new Date()
+						}
+					}, cb
+				(cb) =>
+					@user.request {
+						method: 'POST',
+						url: '/user/emails/default',
+						json:
+							email: 'exists-in-v1@example.com'
+					}, (error, response, body) =>
+						return done(error) if error?
+						expect(response.statusCode).to.equal 409
+						expect(body.error).to.deep.equal {
+							message: "The email 'exists-in-v1@example.com' is already in use by another account"
+						}
+						cb()
+				(cb) =>
+					@user.request { url: '/user/emails', json: true }, (error, response, body) ->
+						expect(body[0].default).to.equal true
+						expect(body[1].default).to.equal false
+						cb()
+			], done

+ 8 - 2
services/web/test/acceptance/coffee/helpers/MockV1Api.coffee

@@ -30,6 +30,8 @@ module.exports = MockV1Api =
 
 	updateEmail: sinon.stub()
 
+	existingEmails: []
+
 	setAffiliations: (affiliations) -> @affiliations = affiliations
 
 	run: () ->
@@ -67,8 +69,12 @@ module.exports = MockV1Api =
 			res.json []
 
 		app.put '/api/v1/sharelatex/users/:id/email', (req, res, next) =>
-			@updateEmail parseInt(req.params.id), req.body.email
-			res.sendStatus 200
+			{ email } = req.body
+			if email in @existingEmails
+				return res.sendStatus 409
+			else
+				@updateEmail parseInt(req.params.id), email
+				return res.sendStatus 200
 
 		app.listen 5000, (error) ->
 			throw error if error?