UserGetter.coffee 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. mongojs = require("../../infrastructure/mongojs")
  2. metrics = require('metrics-sharelatex')
  3. logger = require('logger-sharelatex')
  4. db = mongojs.db
  5. ObjectId = mongojs.ObjectId
  6. settings = require "settings-sharelatex"
  7. request = require "request"
  8. module.exports = UserGetter =
  9. getUser: (query, projection, callback = (error, user) ->) ->
  10. if query?.email?
  11. return callback(new Error("Don't use getUser to find user by email"), null)
  12. if arguments.length == 2
  13. callback = projection
  14. projection = {}
  15. if typeof query == "string"
  16. try
  17. query = _id: ObjectId(query)
  18. catch e
  19. return callback(null, null)
  20. else if query instanceof ObjectId
  21. query = _id: query
  22. db.users.findOne query, projection, callback
  23. getUserEmail: (userId, callback = (error, email) ->) ->
  24. @getUser userId, { email: 1 }, (error, user) ->
  25. callback(error, user?.email)
  26. getUserFullEmails: (userId, callback = (error, emails) ->) ->
  27. @getUser userId, { email: 1, emails: 1 }, (error, user) ->
  28. return callback error if error?
  29. return callback new Error('User not Found') unless user
  30. getAffiliations userId, (error, affiliationsData) ->
  31. return callback error if error?
  32. callback null, decorateFullEmails(user.email, user.emails, affiliationsData)
  33. getUserByMainEmail: (email, projection, callback = (error, user) ->) ->
  34. email = email.trim()
  35. if arguments.length == 2
  36. callback = projection
  37. projection = {}
  38. db.users.findOne email: email, projection, callback
  39. getUserByAnyEmail: (email, projection, callback = (error, user) ->) ->
  40. email = email.trim()
  41. if arguments.length == 2
  42. callback = projection
  43. projection = {}
  44. # $exists: true MUST be set to use the partial index
  45. query = emails: { $exists: true }, 'emails.email': email
  46. db.users.findOne query, projection, (error, user) =>
  47. return callback(error, user) if error? or user?
  48. # While multiple emails are being rolled out, check for the main email as
  49. # well
  50. @getUserByMainEmail email, projection, callback
  51. getUsers: (user_ids, projection, callback = (error, users) ->) ->
  52. try
  53. user_ids = user_ids.map (u) -> ObjectId(u.toString())
  54. catch error
  55. return callback error
  56. db.users.find { _id: { $in: user_ids} }, projection, callback
  57. getUserOrUserStubById: (user_id, projection, callback = (error, user) ->) ->
  58. try
  59. query = _id: ObjectId(user_id.toString())
  60. catch e
  61. return callback(new Error(e))
  62. db.users.findOne query, projection, (error, user) ->
  63. return callback(error) if error?
  64. return callback(null, user) if user?
  65. db.userstubs.findOne query, projection, callback
  66. # check for duplicate email address. This is also enforced at the DB level
  67. ensureUniqueEmailAddress: (newEmail, callback) ->
  68. @getUserByAnyEmail newEmail, (error, user) ->
  69. return callback(message: 'alread_exists') if user?
  70. callback(error)
  71. decorateFullEmails = (defaultEmail, emailsData, affiliationsData) ->
  72. emailsData.map (emailData) ->
  73. emailData.default = emailData.email == defaultEmail
  74. affiliation = affiliationsData.find (aff) -> aff.email == emailData.email
  75. if affiliation?
  76. { institution, inferred, role, department } = affiliation
  77. emailData.affiliation = { institution, inferred, role, department }
  78. else
  79. emailsData.affiliation = null
  80. emailData
  81. getAffiliations = (userId, callback = (error) ->) ->
  82. return callback(null, []) unless settings?.apis?.v1?.url # service is not configured
  83. request {
  84. method: 'GET'
  85. url: "#{settings.apis.v1.url}/api/v2/users/#{userId.toString()}/affiliations"
  86. auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }
  87. json: true,
  88. timeout: 20 * 1000
  89. }, (error, response, body) ->
  90. return callback(error) if error?
  91. unless 200 <= response.statusCode < 300
  92. errorMessage = "Couldn't get affiliations: #{response.statusCode}"
  93. return callback(new Error(errorMessage))
  94. callback(null, body)
  95. [
  96. 'getUser',
  97. 'getUserEmail',
  98. 'getUserByMainEmail',
  99. 'getUserByAnyEmail',
  100. 'getUsers',
  101. 'getUserOrUserStubById',
  102. 'ensureUniqueEmailAddress',
  103. ].map (method) ->
  104. metrics.timeAsyncMethod UserGetter, method, 'mongo.UserGetter', logger