UserGetter.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* eslint-disable
  2. camelcase,
  3. handle-callback-err,
  4. max-len,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * DS207: Consider shorter variations of null checks
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. let UserGetter
  15. const mongojs = require('../../infrastructure/mongojs')
  16. const metrics = require('metrics-sharelatex')
  17. const logger = require('logger-sharelatex')
  18. const { db } = mongojs
  19. const { ObjectId } = mongojs
  20. const { getUserAffiliations } = require('../Institutions/InstitutionsAPI')
  21. const Errors = require('../Errors/Errors')
  22. module.exports = UserGetter = {
  23. getUser(query, projection, callback) {
  24. if (callback == null) {
  25. callback = function(error, user) {}
  26. }
  27. if (query == null) {
  28. return callback(new Error('no query provided'))
  29. }
  30. if (arguments.length === 2) {
  31. callback = projection
  32. projection = {}
  33. }
  34. if (typeof query === 'string') {
  35. try {
  36. query = { _id: ObjectId(query) }
  37. } catch (e) {
  38. return callback(null, null)
  39. }
  40. } else if (query instanceof ObjectId) {
  41. query = { _id: query }
  42. }
  43. return db.users.findOne(query, projection, callback)
  44. },
  45. getUserEmail(userId, callback) {
  46. if (callback == null) {
  47. callback = function(error, email) {}
  48. }
  49. return this.getUser(userId, { email: 1 }, (error, user) =>
  50. callback(error, user != null ? user.email : undefined)
  51. )
  52. },
  53. getUserFullEmails(userId, callback) {
  54. if (callback == null) {
  55. callback = function(error, emails) {}
  56. }
  57. return this.getUser(userId, { email: 1, emails: 1 }, function(error, user) {
  58. if (error != null) {
  59. return callback(error)
  60. }
  61. if (!user) {
  62. return callback(new Error('User not Found'))
  63. }
  64. return getUserAffiliations(userId, function(error, affiliationsData) {
  65. if (error != null) {
  66. return callback(error)
  67. }
  68. return callback(
  69. null,
  70. decorateFullEmails(user.email, user.emails || [], affiliationsData)
  71. )
  72. })
  73. })
  74. },
  75. getUserByMainEmail(email, projection, callback) {
  76. if (callback == null) {
  77. callback = function(error, user) {}
  78. }
  79. email = email.trim()
  80. if (arguments.length === 2) {
  81. callback = projection
  82. projection = {}
  83. }
  84. return db.users.findOne({ email }, projection, callback)
  85. },
  86. getUserByAnyEmail(email, projection, callback) {
  87. if (callback == null) {
  88. callback = function(error, user) {}
  89. }
  90. email = email.trim()
  91. if (arguments.length === 2) {
  92. callback = projection
  93. projection = {}
  94. }
  95. // $exists: true MUST be set to use the partial index
  96. const query = { emails: { $exists: true }, 'emails.email': email }
  97. return db.users.findOne(query, projection, (error, user) => {
  98. if (error != null || user != null) {
  99. return callback(error, user)
  100. }
  101. // While multiple emails are being rolled out, check for the main email as
  102. // well
  103. return this.getUserByMainEmail(email, projection, callback)
  104. })
  105. },
  106. getUsersByAnyConfirmedEmail(emails, projection, callback) {
  107. if (callback == null) {
  108. callback = function(error, user) {}
  109. }
  110. if (arguments.length === 2) {
  111. callback = projection
  112. projection = {}
  113. }
  114. // $exists: true MUST be set to use the partial index
  115. const query = {
  116. emails: {
  117. $exists: true,
  118. $elemMatch: { email: { $in: emails }, confirmedAt: { $exists: true } }
  119. }
  120. }
  121. return db.users.find(query, projection, (error, users) => {
  122. return callback(error, users)
  123. })
  124. },
  125. getUsersByV1Ids(v1Ids, projection, callback) {
  126. if (callback == null) {
  127. callback = function(error, user) {}
  128. }
  129. if (arguments.length === 2) {
  130. callback = projection
  131. projection = {}
  132. }
  133. const query = { 'overleaf.id': { $in: v1Ids } }
  134. return db.users.find(query, projection, (error, users) => {
  135. return callback(error, users)
  136. })
  137. },
  138. getUsersByHostname(hostname, projection, callback) {
  139. if (callback == null) {
  140. callback = function(error, users) {}
  141. }
  142. const reversedHostname = hostname
  143. .trim()
  144. .split('')
  145. .reverse()
  146. .join('')
  147. const query = {
  148. emails: { $exists: true },
  149. 'emails.reversedHostname': reversedHostname
  150. }
  151. return db.users.find(query, projection, callback)
  152. },
  153. getUsers(user_ids, projection, callback) {
  154. if (callback == null) {
  155. callback = function(error, users) {}
  156. }
  157. try {
  158. user_ids = user_ids.map(u => ObjectId(u.toString()))
  159. } catch (error1) {
  160. const error = error1
  161. return callback(error)
  162. }
  163. return db.users.find({ _id: { $in: user_ids } }, projection, callback)
  164. },
  165. getUserOrUserStubById(user_id, projection, callback) {
  166. let query
  167. if (callback == null) {
  168. callback = function(error, user, isStub) {}
  169. }
  170. try {
  171. query = { _id: ObjectId(user_id.toString()) }
  172. } catch (e) {
  173. return callback(new Error(e))
  174. }
  175. return db.users.findOne(query, projection, function(error, user) {
  176. if (error != null) {
  177. return callback(error)
  178. }
  179. if (user != null) {
  180. return callback(null, user, false)
  181. }
  182. return db.userstubs.findOne(query, projection, function(error, user) {
  183. if (error) {
  184. return callback(error)
  185. }
  186. if (user == null) {
  187. return callback()
  188. }
  189. return callback(null, user, true)
  190. })
  191. })
  192. },
  193. // check for duplicate email address. This is also enforced at the DB level
  194. ensureUniqueEmailAddress(newEmail, callback) {
  195. return this.getUserByAnyEmail(newEmail, function(error, user) {
  196. if (user != null) {
  197. return callback(new Errors.EmailExistsError())
  198. }
  199. return callback(error)
  200. })
  201. }
  202. }
  203. var decorateFullEmails = (defaultEmail, emailsData, affiliationsData) =>
  204. emailsData.map(function(emailData) {
  205. emailData.default = emailData.email === defaultEmail
  206. const affiliation = affiliationsData.find(
  207. aff => aff.email === emailData.email
  208. )
  209. if (affiliation != null) {
  210. const { institution, inferred, role, department } = affiliation
  211. emailData.affiliation = { institution, inferred, role, department }
  212. } else {
  213. emailsData.affiliation = null
  214. }
  215. return emailData
  216. })
  217. ;[
  218. 'getUser',
  219. 'getUserEmail',
  220. 'getUserByMainEmail',
  221. 'getUserByAnyEmail',
  222. 'getUsers',
  223. 'getUserOrUserStubById',
  224. 'ensureUniqueEmailAddress'
  225. ].map(method =>
  226. metrics.timeAsyncMethod(UserGetter, method, 'mongo.UserGetter', logger)
  227. )