ProjectLocatorTests.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /* eslint-disable
  2. camelcase,
  3. handle-callback-err,
  4. max-len,
  5. no-return-assign,
  6. no-use-before-define,
  7. */
  8. // TODO: This file was created by bulk-decaffeinate.
  9. // Fix any style issues and re-enable lint.
  10. /*
  11. * decaffeinate suggestions:
  12. * DS102: Remove unnecessary code created because of implicit returns
  13. * DS207: Consider shorter variations of null checks
  14. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  15. */
  16. const spies = require('chai-spies')
  17. const chai = require('chai').use(spies)
  18. const { assert } = require('chai')
  19. const should = chai.should()
  20. const modulePath = '../../../../app/src/Features/Project/ProjectLocator'
  21. const SandboxedModule = require('sandboxed-module')
  22. const sinon = require('sinon')
  23. const Errors = require('../../../../app/src/Features/Errors/Errors')
  24. const { expect } = require('chai')
  25. var Project = (Project = class Project {})
  26. const project = { _id: '1234566', rootFolder: [] }
  27. const rootDoc = { name: 'rootDoc', _id: 'das239djd' }
  28. const doc1 = { name: 'otherDoc.txt', _id: 'dsad2ddd' }
  29. const doc2 = { name: 'docname.txt', _id: 'dsad2ddddd' }
  30. const file1 = { name: 'file1', _id: 'dsa9lkdsad' }
  31. const subSubFile = { name: 'subSubFile', _id: 'd1d2dk' }
  32. const subSubDoc = { name: 'subdoc.txt', _id: '321dmdwi' }
  33. const secondSubFolder = {
  34. name: 'secondSubFolder',
  35. _id: 'dsa3e23',
  36. docs: [subSubDoc],
  37. fileRefs: [subSubFile],
  38. folders: []
  39. }
  40. const subFolder = {
  41. name: 'subFolder',
  42. _id: 'dsadsa93',
  43. folders: [secondSubFolder, null],
  44. docs: [],
  45. fileRefs: []
  46. }
  47. const subFolder1 = { name: 'subFolder1', _id: '123asdjoij' }
  48. const rootFolder = {
  49. _id: '123sdskd',
  50. docs: [doc1, doc2, null, rootDoc],
  51. fileRefs: [file1],
  52. folders: [subFolder1, subFolder]
  53. }
  54. project.rootFolder[0] = rootFolder
  55. project.rootDoc_id = rootDoc._id
  56. describe('ProjectLocator', function() {
  57. beforeEach(function() {
  58. Project.findById = (project_id, callback) => {
  59. return callback(null, project)
  60. }
  61. this.ProjectGetter = {
  62. getProject: sinon.stub().callsArgWith(2, null, project)
  63. }
  64. return (this.locator = SandboxedModule.require(modulePath, {
  65. globals: {
  66. console: console
  67. },
  68. requires: {
  69. '../../models/Project': { Project },
  70. '../../models/User': { User: this.User },
  71. './ProjectGetter': this.ProjectGetter,
  72. 'logger-sharelatex': {
  73. log() {},
  74. err() {},
  75. warn() {}
  76. }
  77. }
  78. }))
  79. })
  80. describe('finding a doc', function() {
  81. it('finds one at the root level', function(done) {
  82. return this.locator.findElement(
  83. { project_id: project._id, element_id: doc2._id, type: 'docs' },
  84. (err, foundElement, path, parentFolder) => {
  85. assert(err == null)
  86. foundElement._id.should.equal(doc2._id)
  87. path.fileSystem.should.equal(`/${doc2.name}`)
  88. parentFolder._id.should.equal(project.rootFolder[0]._id)
  89. path.mongo.should.equal('rootFolder.0.docs.1')
  90. return done()
  91. }
  92. )
  93. })
  94. it('when it is nested', function(done) {
  95. return this.locator.findElement(
  96. { project_id: project._id, element_id: subSubDoc._id, type: 'doc' },
  97. (err, foundElement, path, parentFolder) => {
  98. assert(err == null)
  99. should.equal(foundElement._id, subSubDoc._id)
  100. path.fileSystem.should.equal(
  101. `/${subFolder.name}/${secondSubFolder.name}/${subSubDoc.name}`
  102. )
  103. parentFolder._id.should.equal(secondSubFolder._id)
  104. path.mongo.should.equal('rootFolder.0.folders.1.folders.0.docs.0')
  105. return done()
  106. }
  107. )
  108. })
  109. it('should give error if element could not be found', function(done) {
  110. return this.locator.findElement(
  111. { project_id: project._id, element_id: 'ddsd432nj42', type: 'docs' },
  112. (err, foundElement, path, parentFolder) => {
  113. err.should.deep.equal(new Errors.NotFoundError('entity not found'))
  114. return done()
  115. }
  116. )
  117. })
  118. })
  119. describe('finding a folder', function() {
  120. it('should return root folder when looking for root folder', function(done) {
  121. return this.locator.findElement(
  122. { project_id: project._id, element_id: rootFolder._id, type: 'folder' },
  123. (err, foundElement, path, parentFolder) => {
  124. assert(!err)
  125. foundElement._id.should.equal(rootFolder._id)
  126. return done()
  127. }
  128. )
  129. })
  130. it('when at root', function(done) {
  131. return this.locator.findElement(
  132. { project_id: project._id, element_id: subFolder._id, type: 'folder' },
  133. (err, foundElement, path, parentFolder) => {
  134. assert(!err)
  135. foundElement._id.should.equal(subFolder._id)
  136. path.fileSystem.should.equal(`/${subFolder.name}`)
  137. parentFolder._id.should.equal(rootFolder._id)
  138. path.mongo.should.equal('rootFolder.0.folders.1')
  139. return done()
  140. }
  141. )
  142. })
  143. it('when deeply nested', function(done) {
  144. return this.locator.findElement(
  145. {
  146. project_id: project._id,
  147. element_id: secondSubFolder._id,
  148. type: 'folder'
  149. },
  150. (err, foundElement, path, parentFolder) => {
  151. assert(!err)
  152. foundElement._id.should.equal(secondSubFolder._id)
  153. path.fileSystem.should.equal(
  154. `/${subFolder.name}/${secondSubFolder.name}`
  155. )
  156. parentFolder._id.should.equal(subFolder._id)
  157. path.mongo.should.equal('rootFolder.0.folders.1.folders.0')
  158. return done()
  159. }
  160. )
  161. })
  162. })
  163. describe('finding a file', function() {
  164. it('when at root', function(done) {
  165. return this.locator.findElement(
  166. { project_id: project._id, element_id: file1._id, type: 'fileRefs' },
  167. (err, foundElement, path, parentFolder) => {
  168. assert(!err)
  169. foundElement._id.should.equal(file1._id)
  170. path.fileSystem.should.equal(`/${file1.name}`)
  171. parentFolder._id.should.equal(rootFolder._id)
  172. path.mongo.should.equal('rootFolder.0.fileRefs.0')
  173. return done()
  174. }
  175. )
  176. })
  177. it('when deeply nested', function(done) {
  178. return this.locator.findElement(
  179. {
  180. project_id: project._id,
  181. element_id: subSubFile._id,
  182. type: 'fileRefs'
  183. },
  184. (err, foundElement, path, parentFolder) => {
  185. assert(!err)
  186. foundElement._id.should.equal(subSubFile._id)
  187. path.fileSystem.should.equal(
  188. `/${subFolder.name}/${secondSubFolder.name}/${subSubFile.name}`
  189. )
  190. parentFolder._id.should.equal(secondSubFolder._id)
  191. path.mongo.should.equal('rootFolder.0.folders.1.folders.0.fileRefs.0')
  192. return done()
  193. }
  194. )
  195. })
  196. })
  197. describe('finding an element with wrong element type', function() {
  198. it('should add an s onto the element type', function(done) {
  199. return this.locator.findElement(
  200. { project_id: project._id, element_id: subSubDoc._id, type: 'doc' },
  201. (err, foundElement, path, parentFolder) => {
  202. assert(!err)
  203. foundElement._id.should.equal(subSubDoc._id)
  204. return done()
  205. }
  206. )
  207. })
  208. it('should convert file to fileRefs', function(done) {
  209. return this.locator.findElement(
  210. { project_id: project._id, element_id: file1._id, type: 'fileRefs' },
  211. (err, foundElement, path, parentFolder) => {
  212. assert(!err)
  213. foundElement._id.should.equal(file1._id)
  214. return done()
  215. }
  216. )
  217. })
  218. })
  219. describe('should be able to take actual project as well as id', function() {
  220. const doc3 = {
  221. _id: '123dsdj3',
  222. name: 'doc3'
  223. }
  224. const rootFolder2 = {
  225. _id: '123sddedskd',
  226. docs: [doc3]
  227. }
  228. const project2 = {
  229. _id: '1234566',
  230. rootFolder: [rootFolder2]
  231. }
  232. it('should find doc in project', function(done) {
  233. return this.locator.findElement(
  234. { project: project2, element_id: doc3._id, type: 'docs' },
  235. (err, foundElement, path, parentFolder) => {
  236. assert(err == null)
  237. foundElement._id.should.equal(doc3._id)
  238. path.fileSystem.should.equal(`/${doc3.name}`)
  239. parentFolder._id.should.equal(project2.rootFolder[0]._id)
  240. path.mongo.should.equal('rootFolder.0.docs.0')
  241. return done()
  242. }
  243. )
  244. })
  245. })
  246. describe('finding root doc', function() {
  247. it('should return root doc when passed project', function(done) {
  248. return this.locator.findRootDoc(project, (err, doc) => {
  249. assert(err == null)
  250. doc._id.should.equal(rootDoc._id)
  251. return done()
  252. })
  253. })
  254. it('should return root doc when passed project_id', function(done) {
  255. return this.locator.findRootDoc(project._id, (err, doc) => {
  256. assert(err == null)
  257. doc._id.should.equal(rootDoc._id)
  258. return done()
  259. })
  260. })
  261. it('should return null when the project has no rootDoc', function(done) {
  262. project.rootDoc_id = null
  263. return this.locator.findRootDoc(project, (err, doc) => {
  264. assert(err == null)
  265. expect(doc).to.equal(null)
  266. return done()
  267. })
  268. })
  269. it('should return null when the rootDoc_id no longer exists', function(done) {
  270. project.rootDoc_id = 'doesntexist'
  271. return this.locator.findRootDoc(project, (err, doc) => {
  272. assert(err == null)
  273. expect(doc).to.equal(null)
  274. return done()
  275. })
  276. })
  277. })
  278. describe('findElementByPath', function() {
  279. it('should take a doc path and return the element for a root level document', function(done) {
  280. const path = `${doc1.name}`
  281. return this.locator.findElementByPath(
  282. { project, path },
  283. (err, element, type) => {
  284. element.should.deep.equal(doc1)
  285. expect(type).to.equal('doc')
  286. return done()
  287. }
  288. )
  289. })
  290. it('should take a doc path and return the element for a root level document with a starting slash', function(done) {
  291. const path = `/${doc1.name}`
  292. return this.locator.findElementByPath(
  293. { project, path },
  294. (err, element, type) => {
  295. element.should.deep.equal(doc1)
  296. expect(type).to.equal('doc')
  297. return done()
  298. }
  299. )
  300. })
  301. it('should take a doc path and return the element for a nested document', function(done) {
  302. const path = `${subFolder.name}/${secondSubFolder.name}/${subSubDoc.name}`
  303. return this.locator.findElementByPath(
  304. { project, path },
  305. (err, element, type) => {
  306. element.should.deep.equal(subSubDoc)
  307. expect(type).to.equal('doc')
  308. return done()
  309. }
  310. )
  311. })
  312. it('should take a file path and return the element for a root level document', function(done) {
  313. const path = `${file1.name}`
  314. return this.locator.findElementByPath(
  315. { project, path },
  316. (err, element, type) => {
  317. element.should.deep.equal(file1)
  318. expect(type).to.equal('file')
  319. return done()
  320. }
  321. )
  322. })
  323. it('should take a file path and return the element for a nested document', function(done) {
  324. const path = `${subFolder.name}/${secondSubFolder.name}/${
  325. subSubFile.name
  326. }`
  327. return this.locator.findElementByPath(
  328. { project, path },
  329. (err, element, type) => {
  330. element.should.deep.equal(subSubFile)
  331. expect(type).to.equal('file')
  332. return done()
  333. }
  334. )
  335. })
  336. it('should take a file path and return the element for a nested document case insenstive', function(done) {
  337. const path = `${subFolder.name.toUpperCase()}/${secondSubFolder.name.toUpperCase()}/${subSubFile.name.toUpperCase()}`
  338. return this.locator.findElementByPath(
  339. { project, path },
  340. (err, element, type) => {
  341. element.should.deep.equal(subSubFile)
  342. expect(type).to.equal('file')
  343. return done()
  344. }
  345. )
  346. })
  347. it('should take a file path and return the element for a nested folder', function(done) {
  348. const path = `${subFolder.name}/${secondSubFolder.name}`
  349. return this.locator.findElementByPath(
  350. { project, path },
  351. (err, element, type) => {
  352. element.should.deep.equal(secondSubFolder)
  353. expect(type).to.equal('folder')
  354. return done()
  355. }
  356. )
  357. })
  358. it('should take a file path and return the root folder', function(done) {
  359. const path = '/'
  360. return this.locator.findElementByPath(
  361. { project, path },
  362. (err, element, type) => {
  363. element.should.deep.equal(rootFolder)
  364. expect(type).to.equal('folder')
  365. return done()
  366. }
  367. )
  368. })
  369. it('should return an error if the file can not be found inside know folder', function(done) {
  370. const path = `${subFolder.name}/${secondSubFolder.name}/exist.txt`
  371. return this.locator.findElementByPath(
  372. { project, path },
  373. (err, element, type) => {
  374. err.should.not.equal(undefined)
  375. assert.equal(element, undefined)
  376. expect(type).to.be.undefined
  377. return done()
  378. }
  379. )
  380. })
  381. it('should return an error if the file can not be found inside unknown folder', function(done) {
  382. const path = 'this/does/not/exist.txt'
  383. return this.locator.findElementByPath(
  384. { project, path },
  385. (err, element, type) => {
  386. err.should.not.equal(undefined)
  387. assert.equal(element, undefined)
  388. expect(type).to.be.undefined
  389. return done()
  390. }
  391. )
  392. })
  393. describe('where duplicate folder exists', function() {
  394. beforeEach(function() {
  395. this.duplicateFolder = {
  396. name: 'duplicate1',
  397. _id: '1234',
  398. folders: [
  399. {
  400. name: '1',
  401. docs: [{ name: 'main.tex', _id: '456' }],
  402. folders: [],
  403. fileRefs: []
  404. }
  405. ],
  406. docs: [(this.doc = { name: 'main.tex', _id: '456' })],
  407. fileRefs: []
  408. }
  409. return (this.project = {
  410. rootFolder: [
  411. {
  412. folders: [this.duplicateFolder, this.duplicateFolder],
  413. fileRefs: [],
  414. docs: []
  415. }
  416. ]
  417. })
  418. })
  419. it('should not call the callback more than once', function(done) {
  420. const path = `${this.duplicateFolder.name}/${this.doc.name}`
  421. return this.locator.findElementByPath(
  422. { project: this.project, path },
  423. () => done()
  424. )
  425. }) // mocha will throw exception if done called multiple times
  426. it('should not call the callback more than once when the path is longer than 1 level below the duplicate level', function(done) {
  427. const path = `${this.duplicateFolder.name}/1/main.tex`
  428. return this.locator.findElementByPath(
  429. { project: this.project, path },
  430. () => done()
  431. )
  432. })
  433. }) // mocha will throw exception if done called multiple times
  434. describe('with a null doc', function() {
  435. beforeEach(function() {
  436. return (this.project = {
  437. rootFolder: [
  438. {
  439. folders: [],
  440. fileRefs: [],
  441. docs: [{ name: 'main.tex' }, null, { name: 'other.tex' }]
  442. }
  443. ]
  444. })
  445. })
  446. it('should not crash with a null', function(done) {
  447. const path = '/other.tex'
  448. return this.locator.findElementByPath(
  449. { project: this.project, path },
  450. (err, element) => {
  451. element.name.should.equal('other.tex')
  452. return done()
  453. }
  454. )
  455. })
  456. })
  457. describe('with a null project', function() {
  458. beforeEach(function() {
  459. return (this.ProjectGetter = { getProject: sinon.stub().callsArg(2) })
  460. })
  461. it('should not crash with a null', function(done) {
  462. const path = '/other.tex'
  463. return this.locator.findElementByPath(
  464. { project_id: project._id, path },
  465. (err, element) => {
  466. expect(err).to.exist
  467. return done()
  468. }
  469. )
  470. })
  471. })
  472. describe('with a project_id', function() {
  473. it('should take a doc path and return the element for a root level document', function(done) {
  474. const path = `${doc1.name}`
  475. return this.locator.findElementByPath(
  476. { project_id: project._id, path },
  477. (err, element, type) => {
  478. this.ProjectGetter.getProject
  479. .calledWith(project._id, { rootFolder: true, rootDoc_id: true })
  480. .should.equal(true)
  481. element.should.deep.equal(doc1)
  482. expect(type).to.equal('doc')
  483. return done()
  484. }
  485. )
  486. })
  487. })
  488. })
  489. describe('findUsersProjectByName finding a project by user_id and project name', function() {
  490. it('should return the project from an array case insenstive', function(done) {
  491. const user_id = '123jojoidns'
  492. const stubbedProject = { name: 'findThis' }
  493. const projects = {
  494. owned: [
  495. { name: 'notThis' },
  496. { name: 'wellll' },
  497. stubbedProject,
  498. { name: 'Noooo' }
  499. ]
  500. }
  501. this.ProjectGetter.findAllUsersProjects = sinon
  502. .stub()
  503. .callsArgWith(2, null, projects)
  504. return this.locator.findUsersProjectByName(
  505. user_id,
  506. stubbedProject.name.toLowerCase(),
  507. (err, project) => {
  508. project.should.equal(stubbedProject)
  509. return done()
  510. }
  511. )
  512. })
  513. it('should return the project which is not archived', function(done) {
  514. const user_id = '123jojoidns'
  515. const stubbedProject = { name: 'findThis', _id: 12331321 }
  516. const projects = {
  517. owned: [
  518. { name: 'notThis' },
  519. { name: 'wellll' },
  520. { name: 'findThis', archived: true },
  521. stubbedProject,
  522. { name: 'findThis', archived: true },
  523. { name: 'Noooo' }
  524. ]
  525. }
  526. this.ProjectGetter.findAllUsersProjects = sinon
  527. .stub()
  528. .callsArgWith(2, null, projects)
  529. return this.locator.findUsersProjectByName(
  530. user_id,
  531. stubbedProject.name.toLowerCase(),
  532. (err, project) => {
  533. project._id.should.equal(stubbedProject._id)
  534. return done()
  535. }
  536. )
  537. })
  538. it('should search collab projects as well', function(done) {
  539. const user_id = '123jojoidns'
  540. const stubbedProject = { name: 'findThis' }
  541. const projects = {
  542. owned: [{ name: 'notThis' }, { name: 'wellll' }, { name: 'Noooo' }],
  543. readAndWrite: [stubbedProject]
  544. }
  545. this.ProjectGetter.findAllUsersProjects = sinon
  546. .stub()
  547. .callsArgWith(2, null, projects)
  548. return this.locator.findUsersProjectByName(
  549. user_id,
  550. stubbedProject.name.toLowerCase(),
  551. (err, project) => {
  552. project.should.equal(stubbedProject)
  553. return done()
  554. }
  555. )
  556. })
  557. })
  558. })