mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-08 11:43:11 +00:00
add/remove affiliations when adding/removing emails
This commit is contained in:
parent
4c6c4a2b23
commit
d3b2a2650f
4 changed files with 144 additions and 24 deletions
services/web
app/coffee/Features/User
test/unit/coffee/User
|
@ -20,7 +20,11 @@ module.exports = UserEmailsController =
|
|||
email = EmailHelper.parseEmail(req.body.email)
|
||||
return res.sendStatus 422 unless email?
|
||||
|
||||
UserUpdater.addEmailAddress userId, email, (error)->
|
||||
affiliationOptions =
|
||||
university: req.body.university
|
||||
role: req.body.role
|
||||
department: req.body.department
|
||||
UserUpdater.addEmailAddress userId, email, affiliationOptions, (error)->
|
||||
return next(error) if error?
|
||||
UserEmailsConfirmationHandler.sendConfirmationEmail userId, email, (err) ->
|
||||
return next(error) if error?
|
||||
|
@ -65,4 +69,4 @@ module.exports = UserEmailsController =
|
|||
else
|
||||
next(error)
|
||||
else
|
||||
res.sendStatus 200
|
||||
res.sendStatus 200
|
||||
|
|
|
@ -7,6 +7,8 @@ ObjectId = mongojs.ObjectId
|
|||
UserGetter = require("./UserGetter")
|
||||
EmailHelper = require "../Helpers/EmailHelper"
|
||||
Errors = require "../Errors/Errors"
|
||||
settings = require "settings-sharelatex"
|
||||
request = require "request"
|
||||
|
||||
module.exports = UserUpdater =
|
||||
updateUser: (query, update, callback = (error) ->) ->
|
||||
|
@ -44,29 +46,43 @@ module.exports = UserUpdater =
|
|||
|
||||
# Add a new email address for the user. Email cannot be already used by this
|
||||
# or any other user
|
||||
addEmailAddress: (userId, newEmail, callback) ->
|
||||
addEmailAddress: (userId, newEmail, affiliationOptions, callback) ->
|
||||
unless callback? # affiliationOptions is optional
|
||||
callback = affiliationOptions
|
||||
affiliationOptions = {}
|
||||
|
||||
UserGetter.ensureUniqueEmailAddress newEmail, (error) =>
|
||||
return callback(error) if error?
|
||||
|
||||
update = $push: emails: email: newEmail, createdAt: new Date()
|
||||
@updateUser userId, update, (error) ->
|
||||
addAffiliation userId, newEmail, affiliationOptions, (error) =>
|
||||
if error?
|
||||
logger.err error: error, 'problem updating users emails'
|
||||
logger.err error: error, 'problem adding affiliation'
|
||||
return callback(error)
|
||||
callback()
|
||||
|
||||
update = $push: emails: email: newEmail, createdAt: new Date()
|
||||
@updateUser userId, update, (error) ->
|
||||
if error?
|
||||
logger.err error: error, 'problem updating users emails'
|
||||
return callback(error)
|
||||
callback()
|
||||
|
||||
# remove one of the user's email addresses. The email cannot be the user's
|
||||
# default email address
|
||||
removeEmailAddress: (userId, email, callback) ->
|
||||
query = _id: userId, email: $ne: email
|
||||
update = $pull: emails: email: email
|
||||
@updateUser query, update, (error, res) ->
|
||||
removeAffiliation userId, email, (error) =>
|
||||
if error?
|
||||
logger.err error:error, 'problem removing users email'
|
||||
logger.err error: error, 'problem removing affiliation'
|
||||
return callback(error)
|
||||
if res.n == 0
|
||||
return callback(new Error('Cannot remove default email'))
|
||||
callback()
|
||||
|
||||
query = _id: userId, email: $ne: email
|
||||
update = $pull: emails: email: email
|
||||
@updateUser query, update, (error, res) ->
|
||||
if error?
|
||||
logger.err error:error, 'problem removing users email'
|
||||
return callback(error)
|
||||
if res.n == 0
|
||||
return callback(new Error('Cannot remove default email'))
|
||||
callback()
|
||||
|
||||
|
||||
# set the default email address by setting the `email` attribute. The email
|
||||
|
@ -99,6 +115,44 @@ module.exports = UserUpdater =
|
|||
return callback(new Errors.NotFoundError('user id and email do no match'))
|
||||
callback()
|
||||
|
||||
addAffiliation = (userId, email, { university, department, role }, callback = (error) ->) ->
|
||||
makeAffiliationRequest {
|
||||
method: 'POST'
|
||||
path: "/api/v2/users/#{userId.toString()}/affiliations"
|
||||
body: { email, university, department, role }
|
||||
defaultErrorMessage: "Couldn't create affiliation"
|
||||
}, callback
|
||||
|
||||
removeAffiliation = (userId, email, callback = (error) ->) ->
|
||||
email = encodeURIComponent(email)
|
||||
makeAffiliationRequest {
|
||||
method: 'DELETE'
|
||||
path: "/api/v2/users/#{userId.toString()}/affiliations/#{email}"
|
||||
extraSuccessStatusCodes: [404] # `Not Found` responses are considered successful
|
||||
defaultErrorMessage: "Couldn't remove affiliation"
|
||||
}, callback
|
||||
|
||||
makeAffiliationRequest = (requestOptions, callback = (error) ->) ->
|
||||
requestOptions.extraSuccessStatusCodes ||= []
|
||||
request {
|
||||
method: requestOptions.method
|
||||
url: "#{settings.apis.v1.url}#{requestOptions.path}"
|
||||
body: requestOptions.body
|
||||
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }
|
||||
json: true,
|
||||
timeout: 20 * 1000
|
||||
}, (error, response, body) ->
|
||||
return callback(error) if error?
|
||||
isSuccess = 200 <= response.statusCode < 300
|
||||
isSuccess ||= response.statusCode in requestOptions.extraSuccessStatusCodes
|
||||
unless isSuccess
|
||||
if body?.errors
|
||||
errorMessage = "#{response.statusCode}: #{body.errors}"
|
||||
else
|
||||
errorMessage = "#{requestOptions.defaultErrorMessage}: #{response.statusCode}"
|
||||
return callback(new Error(errorMessage))
|
||||
|
||||
callback(null)
|
||||
|
||||
[
|
||||
'updateUser'
|
||||
|
|
|
@ -53,10 +53,14 @@ describe "UserEmailsController", ->
|
|||
describe 'Add', ->
|
||||
beforeEach ->
|
||||
@newEmail = 'new_email@baz.com'
|
||||
@req.body.email = @newEmail
|
||||
@req.body =
|
||||
email: @newEmail
|
||||
university: { name: 'University Name' }
|
||||
department: 'Department'
|
||||
role: 'Role'
|
||||
@EmailHelper.parseEmail.returns @newEmail
|
||||
@UserUpdater.addEmailAddress.callsArgWith 2, null
|
||||
@UserEmailsConfirmationHandler.sendConfirmationEmail = sinon.stub().yields()
|
||||
@UserUpdater.addEmailAddress.callsArgWith 3, null
|
||||
|
||||
it 'adds new email', (done) ->
|
||||
@UserEmailsController.add @req,
|
||||
|
@ -64,6 +68,13 @@ describe "UserEmailsController", ->
|
|||
code.should.equal 204
|
||||
assertCalledWith @EmailHelper.parseEmail, @newEmail
|
||||
assertCalledWith @UserUpdater.addEmailAddress, @user._id, @newEmail
|
||||
|
||||
affiliationOptions = @UserUpdater.addEmailAddress.lastCall.args[2]
|
||||
Object.keys(affiliationOptions).length.should.equal 3
|
||||
affiliationOptions.university.should.equal @req.body.university
|
||||
affiliationOptions.department.should.equal @req.body.department
|
||||
affiliationOptions.role.should.equal @req.body.role
|
||||
|
||||
done()
|
||||
|
||||
it 'sends an email confirmation', (done) ->
|
||||
|
@ -75,7 +86,6 @@ describe "UserEmailsController", ->
|
|||
|
||||
it 'handles email parse error', (done) ->
|
||||
@EmailHelper.parseEmail.returns null
|
||||
|
||||
@UserEmailsController.add @req,
|
||||
sendStatus: (code) =>
|
||||
code.should.equal 422
|
||||
|
|
|
@ -11,7 +11,6 @@ describe "UserUpdater", ->
|
|||
|
||||
beforeEach ->
|
||||
tk.freeze(Date.now())
|
||||
@settings = {}
|
||||
@mongojs =
|
||||
db:{}
|
||||
ObjectId:(id)-> return id
|
||||
|
@ -20,12 +19,15 @@ describe "UserUpdater", ->
|
|||
getUserByAnyEmail: sinon.stub()
|
||||
ensureUniqueEmailAddress: sinon.stub()
|
||||
@logger = err: sinon.stub(), log: ->
|
||||
settings = apis: { v1: { url: '', user: '', pass: '' } }
|
||||
@request = sinon.stub()
|
||||
@UserUpdater = SandboxedModule.require modulePath, requires:
|
||||
"settings-sharelatex":@settings
|
||||
"logger-sharelatex": @logger
|
||||
"./UserGetter": @UserGetter
|
||||
"../../infrastructure/mongojs":@mongojs
|
||||
"metrics-sharelatex": timeAsyncMethod: sinon.stub()
|
||||
'settings-sharelatex': settings
|
||||
'request': @request
|
||||
|
||||
@stubbedUser =
|
||||
_id: "3131231"
|
||||
|
@ -66,10 +68,10 @@ describe "UserUpdater", ->
|
|||
describe 'addEmailAddress', ->
|
||||
beforeEach ->
|
||||
@UserGetter.ensureUniqueEmailAddress = sinon.stub().callsArgWith(1)
|
||||
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, null)
|
||||
@request.callsArgWith(1, null, { statusCode: 201 })
|
||||
|
||||
it 'add email', (done)->
|
||||
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, null)
|
||||
|
||||
@UserUpdater.addEmailAddress @stubbedUser._id, @newEmail, (err)=>
|
||||
@UserGetter.ensureUniqueEmailAddress.called.should.equal true
|
||||
should.not.exist(err)
|
||||
|
@ -79,6 +81,27 @@ describe "UserUpdater", ->
|
|||
).should.equal true
|
||||
done()
|
||||
|
||||
it 'add affiliation', (done)->
|
||||
affiliationOptions =
|
||||
university: { id: 1 }
|
||||
role: 'Prof'
|
||||
department: 'Math'
|
||||
@UserUpdater.addEmailAddress @stubbedUser._id, @newEmail, affiliationOptions, (err)=>
|
||||
should.not.exist(err)
|
||||
@request.calledOnce.should.equal true
|
||||
requestOptions = @request.lastCall.args[0]
|
||||
expectedUrl = "/api/v2/users/#{@stubbedUser._id}/affiliations"
|
||||
requestOptions.url.should.equal expectedUrl
|
||||
requestOptions.method.should.equal 'POST'
|
||||
|
||||
body = requestOptions.body
|
||||
Object.keys(body).length.should.equal 4
|
||||
body.email.should.equal @newEmail
|
||||
body.university.should.equal affiliationOptions.university
|
||||
body.department.should.equal affiliationOptions.department
|
||||
body.role.should.equal affiliationOptions.role
|
||||
done()
|
||||
|
||||
it 'handle error', (done)->
|
||||
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, new Error('nope'))
|
||||
|
||||
|
@ -87,10 +110,21 @@ describe "UserUpdater", ->
|
|||
should.exist(err)
|
||||
done()
|
||||
|
||||
describe 'removeEmailAddress', ->
|
||||
it 'remove email', (done)->
|
||||
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, nMatched: 1)
|
||||
it 'handle affiliation error', (done)->
|
||||
body = errors: 'affiliation error message'
|
||||
@request.callsArgWith(1, null, { statusCode: 422 }, body)
|
||||
@UserUpdater.addEmailAddress @stubbedUser._id, @newEmail, (err)=>
|
||||
err.message.should.have.string 422
|
||||
err.message.should.have.string body.errors
|
||||
@UserUpdater.updateUser.called.should.equal false
|
||||
done()
|
||||
|
||||
describe 'removeEmailAddress', ->
|
||||
beforeEach ->
|
||||
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, nMatched: 1)
|
||||
@request.callsArgWith(1, null, { statusCode: 404 })
|
||||
|
||||
it 'remove email', (done)->
|
||||
@UserUpdater.removeEmailAddress @stubbedUser._id, @newEmail, (err)=>
|
||||
should.not.exist(err)
|
||||
@UserUpdater.updateUser.calledWith(
|
||||
|
@ -99,6 +133,17 @@ describe "UserUpdater", ->
|
|||
).should.equal true
|
||||
done()
|
||||
|
||||
it 'remove affiliation', (done)->
|
||||
@UserUpdater.removeEmailAddress @stubbedUser._id, @newEmail, (err)=>
|
||||
should.not.exist(err)
|
||||
@request.calledOnce.should.equal true
|
||||
requestOptions = @request.lastCall.args[0]
|
||||
expectedUrl = "/api/v2/users/#{@stubbedUser._id}/affiliations/"
|
||||
expectedUrl += encodeURIComponent(@newEmail)
|
||||
requestOptions.url.should.equal expectedUrl
|
||||
requestOptions.method.should.equal 'DELETE'
|
||||
done()
|
||||
|
||||
it 'handle error', (done)->
|
||||
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, new Error('nope'))
|
||||
|
||||
|
@ -113,6 +158,13 @@ describe "UserUpdater", ->
|
|||
should.exist(err)
|
||||
done()
|
||||
|
||||
it 'handle affiliation error', (done)->
|
||||
@request.callsArgWith(1, null, { statusCode: 500 })
|
||||
@UserUpdater.removeEmailAddress @stubbedUser._id, @newEmail, (err)=>
|
||||
err.message.should.exist
|
||||
@UserUpdater.updateUser.called.should.equal false
|
||||
done()
|
||||
|
||||
describe 'setDefaultEmailAddress', ->
|
||||
it 'set default', (done)->
|
||||
@UserUpdater.updateUser = sinon.stub().callsArgWith(2, null, n: 1)
|
||||
|
|
Loading…
Add table
Reference in a new issue