UserUpdater.coffee 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. logger = require("logger-sharelatex")
  2. mongojs = require("../../infrastructure/mongojs")
  3. metrics = require("metrics-sharelatex")
  4. db = mongojs.db
  5. async = require("async")
  6. ObjectId = mongojs.ObjectId
  7. UserGetter = require("./UserGetter")
  8. EmailHelper = require "../Helpers/EmailHelper"
  9. Errors = require "../Errors/Errors"
  10. settings = require "settings-sharelatex"
  11. request = require "request"
  12. module.exports = UserUpdater =
  13. updateUser: (query, update, callback = (error) ->) ->
  14. if typeof query == "string"
  15. query = _id: ObjectId(query)
  16. else if query instanceof ObjectId
  17. query = _id: query
  18. else if typeof query._id == "string"
  19. query._id = ObjectId(query._id)
  20. db.users.update query, update, callback
  21. #
  22. # DEPRECATED
  23. #
  24. # Change the user's main email address by adding a new email, switching the
  25. # default email and removing the old email. Prefer manipulating multiple
  26. # emails and the default rather than calling this method directly
  27. #
  28. changeEmailAddress: (userId, newEmail, callback)->
  29. logger.log userId: userId, newEmail: newEmail, "updaing email address of user"
  30. oldEmail = null
  31. async.series [
  32. (cb) ->
  33. UserGetter.getUserEmail userId, (error, email) ->
  34. oldEmail = email
  35. cb(error)
  36. (cb) -> UserUpdater.addEmailAddress userId, newEmail, cb
  37. (cb) -> UserUpdater.setDefaultEmailAddress userId, newEmail, cb
  38. (cb) -> UserUpdater.removeEmailAddress userId, oldEmail, cb
  39. ], callback
  40. # Add a new email address for the user. Email cannot be already used by this
  41. # or any other user
  42. addEmailAddress: (userId, newEmail, affiliationOptions, callback) ->
  43. unless callback? # affiliationOptions is optional
  44. callback = affiliationOptions
  45. affiliationOptions = {}
  46. UserGetter.ensureUniqueEmailAddress newEmail, (error) =>
  47. return callback(error) if error?
  48. addAffiliation userId, newEmail, affiliationOptions, (error) =>
  49. if error?
  50. logger.err error: error, 'problem adding affiliation'
  51. return callback(error)
  52. update = $push: emails: email: newEmail, createdAt: new Date()
  53. @updateUser userId, update, (error) ->
  54. if error?
  55. logger.err error: error, 'problem updating users emails'
  56. return callback(error)
  57. callback()
  58. # remove one of the user's email addresses. The email cannot be the user's
  59. # default email address
  60. removeEmailAddress: (userId, email, callback) ->
  61. removeAffiliation userId, email, (error) =>
  62. if error?
  63. logger.err error: error, 'problem removing affiliation'
  64. return callback(error)
  65. query = _id: userId, email: $ne: email
  66. update = $pull: emails: email: email
  67. @updateUser query, update, (error, res) ->
  68. if error?
  69. logger.err error:error, 'problem removing users email'
  70. return callback(error)
  71. if res.n == 0
  72. return callback(new Error('Cannot remove email'))
  73. callback()
  74. # set the default email address by setting the `email` attribute. The email
  75. # must be one of the user's multiple emails (`emails` attribute)
  76. setDefaultEmailAddress: (userId, email, callback) ->
  77. query = _id: userId, 'emails.email': email
  78. update = $set: email: email
  79. @updateUser query, update, (error, res) ->
  80. if error?
  81. logger.err error:error, 'problem setting default emails'
  82. return callback(error)
  83. if res.n == 0 # TODO: Check n or nMatched?
  84. return callback(new Error('Default email does not belong to user'))
  85. callback()
  86. confirmEmail: (userId, email, callback) ->
  87. email = EmailHelper.parseEmail(email)
  88. return callback(new Error('invalid email')) if !email?
  89. logger.log {userId, email}, 'confirming user email'
  90. query =
  91. _id: userId
  92. 'emails.email': email
  93. update =
  94. $set:
  95. 'emails.$.confirmedAt': new Date()
  96. @updateUser query, update, (error, res) ->
  97. return callback(error) if error?
  98. logger.log {res, userId, email}, "tried to confirm email"
  99. if res.n == 0
  100. return callback(new Errors.NotFoundError('user id and email do no match'))
  101. callback()
  102. addAffiliation = (userId, email, { university, department, role }, callback = (error) ->) ->
  103. makeAffiliationRequest {
  104. method: 'POST'
  105. path: "/api/v2/users/#{userId.toString()}/affiliations"
  106. body: { email, university, department, role }
  107. defaultErrorMessage: "Couldn't create affiliation"
  108. }, callback
  109. removeAffiliation = (userId, email, callback = (error) ->) ->
  110. email = encodeURIComponent(email)
  111. makeAffiliationRequest {
  112. method: 'DELETE'
  113. path: "/api/v2/users/#{userId.toString()}/affiliations/#{email}"
  114. extraSuccessStatusCodes: [404] # `Not Found` responses are considered successful
  115. defaultErrorMessage: "Couldn't remove affiliation"
  116. }, callback
  117. makeAffiliationRequest = (requestOptions, callback = (error) ->) ->
  118. return callback(null) unless settings?.apis?.v1?.url # service is not configured
  119. requestOptions.extraSuccessStatusCodes ||= []
  120. request {
  121. method: requestOptions.method
  122. url: "#{settings.apis.v1.url}#{requestOptions.path}"
  123. body: requestOptions.body
  124. auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }
  125. json: true,
  126. timeout: 20 * 1000
  127. }, (error, response, body) ->
  128. return callback(error) if error?
  129. isSuccess = 200 <= response.statusCode < 300
  130. isSuccess ||= response.statusCode in requestOptions.extraSuccessStatusCodes
  131. unless isSuccess
  132. if body?.errors
  133. errorMessage = "#{response.statusCode}: #{body.errors}"
  134. else
  135. errorMessage = "#{requestOptions.defaultErrorMessage}: #{response.statusCode}"
  136. return callback(new Error(errorMessage))
  137. callback(null)
  138. [
  139. 'updateUser'
  140. 'changeEmailAddress'
  141. 'setDefaultEmailAddress'
  142. 'addEmailAddress'
  143. 'removeEmailAddress'
  144. ].map (method) ->
  145. metrics.timeAsyncMethod(UserUpdater, method, 'mongo.UserUpdater', logger)