UserGetterTests.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /* eslint-disable
  2. handle-callback-err,
  3. max-len,
  4. no-return-assign,
  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. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. const { ObjectId } = require('mongojs')
  14. const should = require('chai').should()
  15. const SandboxedModule = require('sandboxed-module')
  16. const assert = require('assert')
  17. const path = require('path')
  18. const sinon = require('sinon')
  19. const modulePath = path.join(
  20. __dirname,
  21. '../../../../app/src/Features/User/UserGetter'
  22. )
  23. const { expect } = require('chai')
  24. const Errors = require('../../../../app/src/Features/Errors/Errors')
  25. describe('UserGetter', function() {
  26. beforeEach(function() {
  27. this.fakeUser = {
  28. _id: '12390i',
  29. email: 'email2@foo.bar',
  30. emails: [
  31. { email: 'email1@foo.bar', reversedHostname: 'rab.oof' },
  32. { email: 'email2@foo.bar', reversedHostname: 'rab.oof' }
  33. ]
  34. }
  35. this.findOne = sinon.stub().callsArgWith(2, null, this.fakeUser)
  36. this.find = sinon.stub().callsArgWith(2, null, [this.fakeUser])
  37. this.Mongo = {
  38. db: {
  39. users: {
  40. findOne: this.findOne,
  41. find: this.find
  42. }
  43. },
  44. ObjectId
  45. }
  46. const settings = { apis: { v1: { url: 'v1.url', user: '', pass: '' } } }
  47. this.getUserAffiliations = sinon.stub().callsArgWith(1, null, [])
  48. return (this.UserGetter = SandboxedModule.require(modulePath, {
  49. globals: {
  50. console: console
  51. },
  52. requires: {
  53. 'logger-sharelatex': {
  54. log() {}
  55. },
  56. '../../infrastructure/mongojs': this.Mongo,
  57. 'metrics-sharelatex': {
  58. timeAsyncMethod: sinon.stub()
  59. },
  60. 'settings-sharelatex': settings,
  61. '../Institutions/InstitutionsAPI': {
  62. getUserAffiliations: this.getUserAffiliations
  63. },
  64. '../../infrastructure/Features': {
  65. hasFeature: sinon.stub().returns(true)
  66. },
  67. '../Errors/Errors': Errors
  68. }
  69. }))
  70. })
  71. describe('getUser', function() {
  72. it('should get user', function(done) {
  73. const query = { _id: 'foo' }
  74. const projection = { email: 1 }
  75. return this.UserGetter.getUser(query, projection, (error, user) => {
  76. this.findOne.called.should.equal(true)
  77. this.findOne.calledWith(query, projection).should.equal(true)
  78. user.should.deep.equal(this.fakeUser)
  79. return done()
  80. })
  81. })
  82. it('should not allow null query', function(done) {
  83. return this.UserGetter.getUser(null, {}, (error, user) => {
  84. error.should.exist
  85. return done()
  86. })
  87. })
  88. })
  89. describe('getUserFullEmails', function() {
  90. it('should get user', function(done) {
  91. this.UserGetter.getUser = sinon
  92. .stub()
  93. .callsArgWith(2, null, this.fakeUser)
  94. const projection = { email: 1, emails: 1 }
  95. return this.UserGetter.getUserFullEmails(
  96. this.fakeUser._id,
  97. (error, fullEmails) => {
  98. this.UserGetter.getUser.called.should.equal(true)
  99. this.UserGetter.getUser
  100. .calledWith(this.fakeUser._id, projection)
  101. .should.equal(true)
  102. return done()
  103. }
  104. )
  105. })
  106. it('should fetch emails data', function(done) {
  107. this.UserGetter.getUser = sinon
  108. .stub()
  109. .callsArgWith(2, null, this.fakeUser)
  110. return this.UserGetter.getUserFullEmails(
  111. this.fakeUser._id,
  112. (error, fullEmails) => {
  113. assert.deepEqual(fullEmails, [
  114. {
  115. email: 'email1@foo.bar',
  116. reversedHostname: 'rab.oof',
  117. default: false
  118. },
  119. {
  120. email: 'email2@foo.bar',
  121. reversedHostname: 'rab.oof',
  122. default: true
  123. }
  124. ])
  125. return done()
  126. }
  127. )
  128. })
  129. it('should merge affiliation data', function(done) {
  130. this.UserGetter.getUser = sinon
  131. .stub()
  132. .callsArgWith(2, null, this.fakeUser)
  133. const affiliationsData = [
  134. {
  135. email: 'email1@foo.bar',
  136. role: 'Prof',
  137. department: 'Maths',
  138. inferred: false,
  139. institution: { name: 'University Name', isUniversity: true }
  140. }
  141. ]
  142. this.getUserAffiliations.callsArgWith(1, null, affiliationsData)
  143. return this.UserGetter.getUserFullEmails(
  144. this.fakeUser._id,
  145. (error, fullEmails) => {
  146. assert.deepEqual(fullEmails, [
  147. {
  148. email: 'email1@foo.bar',
  149. reversedHostname: 'rab.oof',
  150. default: false,
  151. affiliation: {
  152. institution: affiliationsData[0].institution,
  153. inferred: affiliationsData[0].inferred,
  154. department: affiliationsData[0].department,
  155. role: affiliationsData[0].role
  156. }
  157. },
  158. {
  159. email: 'email2@foo.bar',
  160. reversedHostname: 'rab.oof',
  161. default: true
  162. }
  163. ])
  164. return done()
  165. }
  166. )
  167. })
  168. it('should get user when it has no emails field', function(done) {
  169. this.fakeUser = {
  170. _id: '12390i',
  171. email: 'email2@foo.bar'
  172. }
  173. this.UserGetter.getUser = sinon
  174. .stub()
  175. .callsArgWith(2, null, this.fakeUser)
  176. const projection = { email: 1, emails: 1 }
  177. return this.UserGetter.getUserFullEmails(
  178. this.fakeUser._id,
  179. (error, fullEmails) => {
  180. this.UserGetter.getUser.called.should.equal(true)
  181. this.UserGetter.getUser
  182. .calledWith(this.fakeUser._id, projection)
  183. .should.equal(true)
  184. assert.deepEqual(fullEmails, [])
  185. return done()
  186. }
  187. )
  188. })
  189. })
  190. describe('getUserbyMainEmail', function() {
  191. it('query user by main email', function(done) {
  192. const email = 'hello@world.com'
  193. const projection = { emails: 1 }
  194. return this.UserGetter.getUserByMainEmail(
  195. email,
  196. projection,
  197. (error, user) => {
  198. this.findOne.called.should.equal(true)
  199. this.findOne.calledWith({ email }, projection).should.equal(true)
  200. return done()
  201. }
  202. )
  203. })
  204. it('return user if found', function(done) {
  205. const email = 'hello@world.com'
  206. return this.UserGetter.getUserByMainEmail(email, (error, user) => {
  207. user.should.deep.equal(this.fakeUser)
  208. return done()
  209. })
  210. })
  211. it('trim email', function(done) {
  212. const email = 'hello@world.com'
  213. return this.UserGetter.getUserByMainEmail(` ${email} `, (error, user) => {
  214. this.findOne.called.should.equal(true)
  215. this.findOne.calledWith({ email }).should.equal(true)
  216. return done()
  217. })
  218. })
  219. })
  220. describe('getUserByAnyEmail', function() {
  221. it('query user for any email', function(done) {
  222. const email = 'hello@world.com'
  223. const expectedQuery = {
  224. emails: { $exists: true },
  225. 'emails.email': email
  226. }
  227. const projection = { emails: 1 }
  228. return this.UserGetter.getUserByAnyEmail(
  229. ` ${email} `,
  230. projection,
  231. (error, user) => {
  232. this.findOne.calledWith(expectedQuery, projection).should.equal(true)
  233. user.should.deep.equal(this.fakeUser)
  234. return done()
  235. }
  236. )
  237. })
  238. it('query contains $exists:true so partial index is used', function(done) {
  239. const expectedQuery = {
  240. emails: { $exists: true },
  241. 'emails.email': ''
  242. }
  243. return this.UserGetter.getUserByAnyEmail('', {}, (error, user) => {
  244. this.findOne.calledWith(expectedQuery, {}).should.equal(true)
  245. return done()
  246. })
  247. })
  248. it('checks main email as well', function(done) {
  249. this.findOne.callsArgWith(2, null, null)
  250. const email = 'hello@world.com'
  251. const projection = { emails: 1 }
  252. return this.UserGetter.getUserByAnyEmail(
  253. ` ${email} `,
  254. projection,
  255. (error, user) => {
  256. this.findOne.calledTwice.should.equal(true)
  257. this.findOne.calledWith({ email }, projection).should.equal(true)
  258. return done()
  259. }
  260. )
  261. })
  262. })
  263. describe('getUsersByHostname', function() {
  264. it('should find user by hostname', function(done) {
  265. const hostname = 'bar.foo'
  266. const expectedQuery = {
  267. emails: { $exists: true },
  268. 'emails.reversedHostname': hostname
  269. .split('')
  270. .reverse()
  271. .join('')
  272. }
  273. const projection = { emails: 1 }
  274. return this.UserGetter.getUsersByHostname(
  275. hostname,
  276. projection,
  277. (error, users) => {
  278. this.find.calledOnce.should.equal(true)
  279. this.find.calledWith(expectedQuery, projection).should.equal(true)
  280. return done()
  281. }
  282. )
  283. })
  284. })
  285. describe('getUsersByV1Id', function() {
  286. it('should find users by list of v1 ids', function(done) {
  287. const v1Ids = [501]
  288. const expectedQuery = {
  289. 'overleaf.id': { $in: v1Ids }
  290. }
  291. const projection = { emails: 1 }
  292. return this.UserGetter.getUsersByV1Ids(
  293. v1Ids,
  294. projection,
  295. (error, users) => {
  296. this.find.calledOnce.should.equal(true)
  297. this.find.calledWith(expectedQuery, projection).should.equal(true)
  298. return done()
  299. }
  300. )
  301. })
  302. })
  303. describe('ensureUniqueEmailAddress', function() {
  304. beforeEach(function() {
  305. return (this.UserGetter.getUserByAnyEmail = sinon.stub())
  306. })
  307. it('should return error if existing user is found', function(done) {
  308. this.UserGetter.getUserByAnyEmail.callsArgWith(1, null, this.fakeUser)
  309. return this.UserGetter.ensureUniqueEmailAddress(this.newEmail, err => {
  310. should.exist(err)
  311. expect(err).to.be.an.instanceof(Errors.EmailExistsError)
  312. return done()
  313. })
  314. })
  315. it('should return null if no user is found', function(done) {
  316. this.UserGetter.getUserByAnyEmail.callsArgWith(1)
  317. return this.UserGetter.ensureUniqueEmailAddress(this.newEmail, err => {
  318. should.not.exist(err)
  319. return done()
  320. })
  321. })
  322. })
  323. })