EditorControllerTests.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. /* eslint-disable
  2. n/handle-callback-err,
  3. max-len,
  4. no-return-assign,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const SandboxedModule = require('sandboxed-module')
  15. const sinon = require('sinon')
  16. const { expect } = require('chai')
  17. const modulePath = require('path').join(
  18. __dirname,
  19. '../../../../app/src/Features/Editor/EditorController'
  20. )
  21. const MockClient = require('../helpers/MockClient')
  22. const assert = require('assert')
  23. const { ObjectId } = require('mongodb')
  24. describe('EditorController', function () {
  25. beforeEach(function () {
  26. this.project_id = 'test-project-id'
  27. this.source = 'dropbox'
  28. this.user_id = new ObjectId()
  29. this.doc = { _id: (this.doc_id = 'test-doc-id') }
  30. this.docName = 'doc.tex'
  31. this.docLines = ['1234', 'dskl']
  32. this.file = { _id: (this.file_id = 'dasdkjk') }
  33. this.fileName = 'file.png'
  34. this.fsPath = '/folder/file.png'
  35. this.linkedFileData = { provider: 'url' }
  36. this.newFile = { _id: 'new-file-id' }
  37. this.folder_id = '123ksajdn'
  38. this.folder = { _id: this.folder_id }
  39. this.folderName = 'folder'
  40. this.callback = sinon.stub()
  41. return (this.EditorController = SandboxedModule.require(modulePath, {
  42. requires: {
  43. '../Project/ProjectEntityUpdateHandler':
  44. (this.ProjectEntityUpdateHandler = {}),
  45. '../Project/ProjectOptionsHandler': (this.ProjectOptionsHandler = {
  46. setCompiler: sinon.stub().yields(),
  47. setImageName: sinon.stub().yields(),
  48. setSpellCheckLanguage: sinon.stub().yields(),
  49. }),
  50. '../Project/ProjectDetailsHandler': (this.ProjectDetailsHandler = {
  51. setProjectDescription: sinon.stub().yields(),
  52. renameProject: sinon.stub().yields(),
  53. setPublicAccessLevel: sinon.stub().yields(),
  54. }),
  55. '../Project/ProjectDeleter': (this.ProjectDeleter = {}),
  56. '../DocumentUpdater/DocumentUpdaterHandler':
  57. (this.DocumentUpdaterHandler = {
  58. flushDocToMongo: sinon.stub().yields(),
  59. setDocument: sinon.stub().yields(),
  60. }),
  61. './EditorRealTimeController': (this.EditorRealTimeController = {
  62. emitToRoom: sinon.stub(),
  63. }),
  64. '@overleaf/metrics': (this.Metrics = { inc: sinon.stub() }),
  65. },
  66. }))
  67. })
  68. describe('addDoc', function () {
  69. beforeEach(function () {
  70. this.ProjectEntityUpdateHandler.addDocWithRanges = sinon
  71. .stub()
  72. .yields(null, this.doc, this.folder_id)
  73. return this.EditorController.addDoc(
  74. this.project_id,
  75. this.folder_id,
  76. this.docName,
  77. this.docLines,
  78. this.source,
  79. this.user_id,
  80. this.callback
  81. )
  82. })
  83. it('should add the doc using the project entity handler', function () {
  84. return this.ProjectEntityUpdateHandler.addDocWithRanges
  85. .calledWith(
  86. this.project_id,
  87. this.folder_id,
  88. this.docName,
  89. this.docLines,
  90. {},
  91. this.user_id,
  92. this.source
  93. )
  94. .should.equal(true)
  95. })
  96. it('should send the update out to the users in the project', function () {
  97. return this.EditorRealTimeController.emitToRoom
  98. .calledWith(
  99. this.project_id,
  100. 'reciveNewDoc',
  101. this.folder_id,
  102. this.doc,
  103. this.source,
  104. this.user_id
  105. )
  106. .should.equal(true)
  107. })
  108. it('calls the callback', function () {
  109. return this.callback.calledWith(null, this.doc).should.equal(true)
  110. })
  111. })
  112. describe('addFile', function () {
  113. beforeEach(function () {
  114. this.ProjectEntityUpdateHandler.addFile = sinon
  115. .stub()
  116. .yields(null, this.file, this.folder_id)
  117. return this.EditorController.addFile(
  118. this.project_id,
  119. this.folder_id,
  120. this.fileName,
  121. this.fsPath,
  122. this.linkedFileData,
  123. this.source,
  124. this.user_id,
  125. this.callback
  126. )
  127. })
  128. it('should add the folder using the project entity handler', function () {
  129. return this.ProjectEntityUpdateHandler.addFile
  130. .calledWith(
  131. this.project_id,
  132. this.folder_id,
  133. this.fileName,
  134. this.fsPath,
  135. this.linkedFileData,
  136. this.user_id,
  137. this.source
  138. )
  139. .should.equal(true)
  140. })
  141. it('should send the update of a new folder out to the users in the project', function () {
  142. return this.EditorRealTimeController.emitToRoom
  143. .calledWith(
  144. this.project_id,
  145. 'reciveNewFile',
  146. this.folder_id,
  147. this.file,
  148. this.source,
  149. this.linkedFileData,
  150. this.user_id
  151. )
  152. .should.equal(true)
  153. })
  154. it('calls the callback', function () {
  155. return this.callback.calledWith(null, this.file).should.equal(true)
  156. })
  157. })
  158. describe('upsertDoc', function () {
  159. beforeEach(function () {
  160. this.ProjectEntityUpdateHandler.upsertDoc = sinon
  161. .stub()
  162. .yields(null, this.doc, false)
  163. return this.EditorController.upsertDoc(
  164. this.project_id,
  165. this.folder_id,
  166. this.docName,
  167. this.docLines,
  168. this.source,
  169. this.user_id,
  170. this.callback
  171. )
  172. })
  173. it('upserts the doc using the project entity handler', function () {
  174. return this.ProjectEntityUpdateHandler.upsertDoc
  175. .calledWith(
  176. this.project_id,
  177. this.folder_id,
  178. this.docName,
  179. this.docLines,
  180. this.source
  181. )
  182. .should.equal(true)
  183. })
  184. it('returns the doc', function () {
  185. return this.callback.calledWith(null, this.doc).should.equal(true)
  186. })
  187. describe('doc does not exist', function () {
  188. beforeEach(function () {
  189. this.ProjectEntityUpdateHandler.upsertDoc = sinon
  190. .stub()
  191. .yields(null, this.doc, true)
  192. return this.EditorController.upsertDoc(
  193. this.project_id,
  194. this.folder_id,
  195. this.docName,
  196. this.docLines,
  197. this.source,
  198. this.user_id,
  199. this.callback
  200. )
  201. })
  202. it('sends an update out to users in the project', function () {
  203. return this.EditorRealTimeController.emitToRoom
  204. .calledWith(
  205. this.project_id,
  206. 'reciveNewDoc',
  207. this.folder_id,
  208. this.doc,
  209. this.source,
  210. this.user_id
  211. )
  212. .should.equal(true)
  213. })
  214. })
  215. })
  216. describe('upsertFile', function () {
  217. beforeEach(function () {
  218. this.ProjectEntityUpdateHandler.upsertFile = sinon
  219. .stub()
  220. .yields(null, this.newFile, false, this.file)
  221. return this.EditorController.upsertFile(
  222. this.project_id,
  223. this.folder_id,
  224. this.fileName,
  225. this.fsPath,
  226. this.linkedFileData,
  227. this.source,
  228. this.user_id,
  229. this.callback
  230. )
  231. })
  232. it('upserts the file using the project entity handler', function () {
  233. return this.ProjectEntityUpdateHandler.upsertFile
  234. .calledWith(
  235. this.project_id,
  236. this.folder_id,
  237. this.fileName,
  238. this.fsPath,
  239. this.linkedFileData,
  240. this.user_id,
  241. this.source
  242. )
  243. .should.equal(true)
  244. })
  245. it('returns the file', function () {
  246. return this.callback.calledWith(null, this.newFile).should.equal(true)
  247. })
  248. describe('file does not exist', function () {
  249. beforeEach(function () {
  250. this.ProjectEntityUpdateHandler.upsertFile = sinon
  251. .stub()
  252. .yields(null, this.file, true)
  253. return this.EditorController.upsertFile(
  254. this.project_id,
  255. this.folder_id,
  256. this.fileName,
  257. this.fsPath,
  258. this.linkedFileData,
  259. this.source,
  260. this.user_id,
  261. this.callback
  262. )
  263. })
  264. it('should send the update out to users in the project', function () {
  265. return this.EditorRealTimeController.emitToRoom
  266. .calledWith(
  267. this.project_id,
  268. 'reciveNewFile',
  269. this.folder_id,
  270. this.file,
  271. this.source,
  272. this.linkedFileData,
  273. this.user_id
  274. )
  275. .should.equal(true)
  276. })
  277. })
  278. })
  279. describe('upsertDocWithPath', function () {
  280. beforeEach(function () {
  281. this.docPath = '/folder/doc'
  282. this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
  283. .stub()
  284. .yields(null, this.doc, false, [], this.folder)
  285. return this.EditorController.upsertDocWithPath(
  286. this.project_id,
  287. this.docPath,
  288. this.docLines,
  289. this.source,
  290. this.user_id,
  291. this.callback
  292. )
  293. })
  294. it('upserts the doc using the project entity handler', function () {
  295. return this.ProjectEntityUpdateHandler.upsertDocWithPath
  296. .calledWith(this.project_id, this.docPath, this.docLines, this.source)
  297. .should.equal(true)
  298. })
  299. describe('doc does not exist', function () {
  300. beforeEach(function () {
  301. this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
  302. .stub()
  303. .yields(null, this.doc, true, [], this.folder)
  304. return this.EditorController.upsertDocWithPath(
  305. this.project_id,
  306. this.docPath,
  307. this.docLines,
  308. this.source,
  309. this.user_id,
  310. this.callback
  311. )
  312. })
  313. it('should send the update for the doc out to users in the project', function () {
  314. return this.EditorRealTimeController.emitToRoom
  315. .calledWith(
  316. this.project_id,
  317. 'reciveNewDoc',
  318. this.folder_id,
  319. this.doc,
  320. this.source,
  321. this.user_id
  322. )
  323. .should.equal(true)
  324. })
  325. })
  326. describe('folders required for doc do not exist', function () {
  327. beforeEach(function () {
  328. const folders = [
  329. (this.folderA = { _id: 2, parentFolder_id: 1 }),
  330. (this.folderB = { _id: 3, parentFolder_id: 2 }),
  331. ]
  332. this.ProjectEntityUpdateHandler.upsertDocWithPath = sinon
  333. .stub()
  334. .yields(null, this.doc, true, folders, this.folderB)
  335. return this.EditorController.upsertDocWithPath(
  336. this.project_id,
  337. this.docPath,
  338. this.docLines,
  339. this.source,
  340. this.user_id,
  341. this.callback
  342. )
  343. })
  344. it('should send the update for each folder to users in the project', function () {
  345. this.EditorRealTimeController.emitToRoom
  346. .calledWith(
  347. this.project_id,
  348. 'reciveNewFolder',
  349. this.folderA.parentFolder_id,
  350. this.folderA
  351. )
  352. .should.equal(true)
  353. return this.EditorRealTimeController.emitToRoom
  354. .calledWith(
  355. this.project_id,
  356. 'reciveNewFolder',
  357. this.folderB.parentFolder_id,
  358. this.folderB
  359. )
  360. .should.equal(true)
  361. })
  362. })
  363. })
  364. describe('upsertFileWithPath', function () {
  365. beforeEach(function () {
  366. this.filePath = '/folder/file'
  367. this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
  368. .stub()
  369. .yields(null, this.newFile, false, this.file, [], this.folder)
  370. return this.EditorController.upsertFileWithPath(
  371. this.project_id,
  372. this.filePath,
  373. this.fsPath,
  374. this.linkedFileData,
  375. this.source,
  376. this.user_id,
  377. this.callback
  378. )
  379. })
  380. it('upserts the file using the project entity handler', function () {
  381. return this.ProjectEntityUpdateHandler.upsertFileWithPath
  382. .calledWith(
  383. this.project_id,
  384. this.filePath,
  385. this.fsPath,
  386. this.linkedFileData,
  387. this.user_id,
  388. this.source
  389. )
  390. .should.equal(true)
  391. })
  392. describe('file does not exist', function () {
  393. beforeEach(function () {
  394. this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
  395. .stub()
  396. .yields(null, this.file, true, undefined, [], this.folder)
  397. return this.EditorController.upsertFileWithPath(
  398. this.project_id,
  399. this.filePath,
  400. this.fsPath,
  401. this.linkedFileData,
  402. this.source,
  403. this.user_id,
  404. this.callback
  405. )
  406. })
  407. it('should send the update for the file out to users in the project', function () {
  408. return this.EditorRealTimeController.emitToRoom
  409. .calledWith(
  410. this.project_id,
  411. 'reciveNewFile',
  412. this.folder_id,
  413. this.file,
  414. this.source,
  415. this.linkedFileData,
  416. this.user_id
  417. )
  418. .should.equal(true)
  419. })
  420. })
  421. describe('folders required for file do not exist', function () {
  422. beforeEach(function () {
  423. const folders = [
  424. (this.folderA = { _id: 2, parentFolder_id: 1 }),
  425. (this.folderB = { _id: 3, parentFolder_id: 2 }),
  426. ]
  427. this.ProjectEntityUpdateHandler.upsertFileWithPath = sinon
  428. .stub()
  429. .yields(null, this.file, true, undefined, folders, this.folderB)
  430. return this.EditorController.upsertFileWithPath(
  431. this.project_id,
  432. this.filePath,
  433. this.fsPath,
  434. this.linkedFileData,
  435. this.source,
  436. this.user_id,
  437. this.callback
  438. )
  439. })
  440. it('should send the update for each folder to users in the project', function () {
  441. this.EditorRealTimeController.emitToRoom
  442. .calledWith(
  443. this.project_id,
  444. 'reciveNewFolder',
  445. this.folderA.parentFolder_id,
  446. this.folderA
  447. )
  448. .should.equal(true)
  449. return this.EditorRealTimeController.emitToRoom
  450. .calledWith(
  451. this.project_id,
  452. 'reciveNewFolder',
  453. this.folderB.parentFolder_id,
  454. this.folderB
  455. )
  456. .should.equal(true)
  457. })
  458. })
  459. })
  460. describe('addFolder', function () {
  461. beforeEach(function () {
  462. this.EditorController._notifyProjectUsersOfNewFolder = sinon
  463. .stub()
  464. .yields()
  465. this.ProjectEntityUpdateHandler.addFolder = sinon
  466. .stub()
  467. .yields(null, this.folder, this.folder_id)
  468. return this.EditorController.addFolder(
  469. this.project_id,
  470. this.folder_id,
  471. this.folderName,
  472. this.source,
  473. this.user_id,
  474. this.callback
  475. )
  476. })
  477. it('should add the folder using the project entity handler', function () {
  478. return this.ProjectEntityUpdateHandler.addFolder
  479. .calledWith(this.project_id, this.folder_id, this.folderName)
  480. .should.equal(true)
  481. })
  482. it('should notifyProjectUsersOfNewFolder', function () {
  483. return this.EditorController._notifyProjectUsersOfNewFolder
  484. .calledWith(this.project_id, this.folder_id, this.folder, this.user_id)
  485. .should.equal(true)
  486. })
  487. it('should return the folder in the callback', function () {
  488. return this.callback.calledWith(null, this.folder).should.equal(true)
  489. })
  490. })
  491. describe('mkdirp', function () {
  492. beforeEach(function () {
  493. this.path = 'folder1/folder2'
  494. this.folders = [
  495. (this.folderA = { _id: 2, parentFolder_id: 1 }),
  496. (this.folderB = { _id: 3, parentFolder_id: 2 }),
  497. ]
  498. this.EditorController._notifyProjectUsersOfNewFolders = sinon
  499. .stub()
  500. .yields()
  501. this.ProjectEntityUpdateHandler.mkdirp = sinon
  502. .stub()
  503. .yields(null, this.folders, this.folder)
  504. return this.EditorController.mkdirp(
  505. this.project_id,
  506. this.path,
  507. this.callback
  508. )
  509. })
  510. it('should create the folder using the project entity handler', function () {
  511. return this.ProjectEntityUpdateHandler.mkdirp
  512. .calledWith(this.project_id, this.path)
  513. .should.equal(true)
  514. })
  515. it('should notifyProjectUsersOfNewFolder', function () {
  516. return this.EditorController._notifyProjectUsersOfNewFolders.calledWith(
  517. this.project_id,
  518. this.folders
  519. )
  520. })
  521. it('should return the folder in the callback', function () {
  522. return this.callback
  523. .calledWith(null, this.folders, this.folder)
  524. .should.equal(true)
  525. })
  526. })
  527. describe('deleteEntity', function () {
  528. beforeEach(function () {
  529. this.entity_id = 'entity_id_here'
  530. this.type = 'doc'
  531. this.ProjectEntityUpdateHandler.deleteEntity = sinon.stub().yields()
  532. return this.EditorController.deleteEntity(
  533. this.project_id,
  534. this.entity_id,
  535. this.type,
  536. this.source,
  537. this.user_id,
  538. this.callback
  539. )
  540. })
  541. it('should delete the folder using the project entity handler', function () {
  542. return this.ProjectEntityUpdateHandler.deleteEntity
  543. .calledWith(
  544. this.project_id,
  545. this.entity_id,
  546. this.type,
  547. this.user_id,
  548. this.source
  549. )
  550. .should.equal(true)
  551. })
  552. it('notify users an entity has been deleted', function () {
  553. return this.EditorRealTimeController.emitToRoom
  554. .calledWith(
  555. this.project_id,
  556. 'removeEntity',
  557. this.entity_id,
  558. this.source
  559. )
  560. .should.equal(true)
  561. })
  562. })
  563. describe('deleteEntityWithPath', function () {
  564. beforeEach(function () {
  565. this.entity_id = 'entity_id_here'
  566. this.ProjectEntityUpdateHandler.deleteEntityWithPath = sinon
  567. .stub()
  568. .yields(null, this.entity_id)
  569. this.path = 'folder1/folder2'
  570. return this.EditorController.deleteEntityWithPath(
  571. this.project_id,
  572. this.path,
  573. this.source,
  574. this.user_id,
  575. this.callback
  576. )
  577. })
  578. it('should delete the folder using the project entity handler', function () {
  579. return this.ProjectEntityUpdateHandler.deleteEntityWithPath
  580. .calledWith(this.project_id, this.path, this.user_id, this.source)
  581. .should.equal(true)
  582. })
  583. it('notify users an entity has been deleted', function () {
  584. return this.EditorRealTimeController.emitToRoom
  585. .calledWith(
  586. this.project_id,
  587. 'removeEntity',
  588. this.entity_id,
  589. this.source
  590. )
  591. .should.equal(true)
  592. })
  593. })
  594. describe('updateProjectDescription', function () {
  595. beforeEach(function () {
  596. this.description = 'new description'
  597. return this.EditorController.updateProjectDescription(
  598. this.project_id,
  599. this.description,
  600. this.callback
  601. )
  602. })
  603. it('should send the new description to the project details handler', function () {
  604. return this.ProjectDetailsHandler.setProjectDescription
  605. .calledWith(this.project_id, this.description)
  606. .should.equal(true)
  607. })
  608. it('should notify the other clients about the updated description', function () {
  609. return this.EditorRealTimeController.emitToRoom
  610. .calledWith(
  611. this.project_id,
  612. 'projectDescriptionUpdated',
  613. this.description
  614. )
  615. .should.equal(true)
  616. })
  617. })
  618. describe('deleteProject', function () {
  619. beforeEach(function () {
  620. this.err = 'errro'
  621. return (this.ProjectDeleter.deleteProject = sinon
  622. .stub()
  623. .callsArgWith(1, this.err))
  624. })
  625. it('should call the project handler', function (done) {
  626. return this.EditorController.deleteProject(this.project_id, err => {
  627. err.should.equal(this.err)
  628. this.ProjectDeleter.deleteProject
  629. .calledWith(this.project_id)
  630. .should.equal(true)
  631. return done()
  632. })
  633. })
  634. })
  635. describe('renameEntity', function () {
  636. beforeEach(function (done) {
  637. this.entity_id = 'entity_id_here'
  638. this.entityType = 'doc'
  639. this.newName = 'bobsfile.tex'
  640. this.ProjectEntityUpdateHandler.renameEntity = sinon.stub().yields()
  641. return this.EditorController.renameEntity(
  642. this.project_id,
  643. this.entity_id,
  644. this.entityType,
  645. this.newName,
  646. this.user_id,
  647. this.source,
  648. done
  649. )
  650. })
  651. it('should call the project handler', function () {
  652. return this.ProjectEntityUpdateHandler.renameEntity
  653. .calledWith(
  654. this.project_id,
  655. this.entity_id,
  656. this.entityType,
  657. this.newName,
  658. this.user_id,
  659. this.source
  660. )
  661. .should.equal(true)
  662. })
  663. it('should emit the update to the room', function () {
  664. return this.EditorRealTimeController.emitToRoom
  665. .calledWith(
  666. this.project_id,
  667. 'reciveEntityRename',
  668. this.entity_id,
  669. this.newName
  670. )
  671. .should.equal(true)
  672. })
  673. })
  674. describe('moveEntity', function () {
  675. beforeEach(function () {
  676. this.entity_id = 'entity_id_here'
  677. this.entityType = 'doc'
  678. this.ProjectEntityUpdateHandler.moveEntity = sinon.stub().yields()
  679. return this.EditorController.moveEntity(
  680. this.project_id,
  681. this.entity_id,
  682. this.folder_id,
  683. this.entityType,
  684. this.user_id,
  685. this.source,
  686. this.callback
  687. )
  688. })
  689. it('should call the ProjectEntityUpdateHandler', function () {
  690. return this.ProjectEntityUpdateHandler.moveEntity
  691. .calledWith(
  692. this.project_id,
  693. this.entity_id,
  694. this.folder_id,
  695. this.entityType,
  696. this.user_id,
  697. this.source
  698. )
  699. .should.equal(true)
  700. })
  701. it('should emit the update to the room', function () {
  702. return this.EditorRealTimeController.emitToRoom
  703. .calledWith(
  704. this.project_id,
  705. 'reciveEntityMove',
  706. this.entity_id,
  707. this.folder_id
  708. )
  709. .should.equal(true)
  710. })
  711. it('calls the callback', function () {
  712. return this.callback.called.should.equal(true)
  713. })
  714. })
  715. describe('renameProject', function () {
  716. beforeEach(function () {
  717. this.err = 'errro'
  718. this.newName = 'new name here'
  719. return this.EditorController.renameProject(
  720. this.project_id,
  721. this.newName,
  722. this.callback
  723. )
  724. })
  725. it('should call the EditorController', function () {
  726. return this.ProjectDetailsHandler.renameProject
  727. .calledWith(this.project_id, this.newName)
  728. .should.equal(true)
  729. })
  730. it('should emit the update to the room', function () {
  731. return this.EditorRealTimeController.emitToRoom
  732. .calledWith(this.project_id, 'projectNameUpdated', this.newName)
  733. .should.equal(true)
  734. })
  735. })
  736. describe('setCompiler', function () {
  737. beforeEach(function () {
  738. this.compiler = 'latex'
  739. return this.EditorController.setCompiler(
  740. this.project_id,
  741. this.compiler,
  742. this.callback
  743. )
  744. })
  745. it('should send the new compiler and project id to the project options handler', function () {
  746. this.ProjectOptionsHandler.setCompiler
  747. .calledWith(this.project_id, this.compiler)
  748. .should.equal(true)
  749. return this.EditorRealTimeController.emitToRoom
  750. .calledWith(this.project_id, 'compilerUpdated', this.compiler)
  751. .should.equal(true)
  752. })
  753. })
  754. describe('setImageName', function () {
  755. beforeEach(function () {
  756. this.imageName = 'texlive-1234.5'
  757. return this.EditorController.setImageName(
  758. this.project_id,
  759. this.imageName,
  760. this.callback
  761. )
  762. })
  763. it('should send the new imageName and project id to the project options handler', function () {
  764. this.ProjectOptionsHandler.setImageName
  765. .calledWith(this.project_id, this.imageName)
  766. .should.equal(true)
  767. return this.EditorRealTimeController.emitToRoom
  768. .calledWith(this.project_id, 'imageNameUpdated', this.imageName)
  769. .should.equal(true)
  770. })
  771. })
  772. describe('setSpellCheckLanguage', function () {
  773. beforeEach(function () {
  774. this.languageCode = 'fr'
  775. return this.EditorController.setSpellCheckLanguage(
  776. this.project_id,
  777. this.languageCode,
  778. this.callback
  779. )
  780. })
  781. it('should send the new languageCode and project id to the project options handler', function () {
  782. this.ProjectOptionsHandler.setSpellCheckLanguage
  783. .calledWith(this.project_id, this.languageCode)
  784. .should.equal(true)
  785. return this.EditorRealTimeController.emitToRoom
  786. .calledWith(
  787. this.project_id,
  788. 'spellCheckLanguageUpdated',
  789. this.languageCode
  790. )
  791. .should.equal(true)
  792. })
  793. })
  794. describe('setPublicAccessLevel', function () {
  795. describe('when setting to private', function () {
  796. beforeEach(function () {
  797. this.newAccessLevel = 'private'
  798. this.ProjectDetailsHandler.ensureTokensArePresent = sinon
  799. .stub()
  800. .yields()
  801. return this.EditorController.setPublicAccessLevel(
  802. this.project_id,
  803. this.newAccessLevel,
  804. this.callback
  805. )
  806. })
  807. it('should set the access level', function () {
  808. return this.ProjectDetailsHandler.setPublicAccessLevel
  809. .calledWith(this.project_id, this.newAccessLevel)
  810. .should.equal(true)
  811. })
  812. it('should broadcast the access level change', function () {
  813. return this.EditorRealTimeController.emitToRoom
  814. .calledWith(this.project_id, 'project:publicAccessLevel:changed')
  815. .should.equal(true)
  816. })
  817. it('should not ensure tokens are present for project', function () {
  818. return this.ProjectDetailsHandler.ensureTokensArePresent
  819. .calledWith(this.project_id)
  820. .should.equal(false)
  821. })
  822. })
  823. describe('when setting to tokenBased', function () {
  824. beforeEach(function () {
  825. this.newAccessLevel = 'tokenBased'
  826. this.tokens = { readOnly: 'aaa', readAndWrite: '42bbb' }
  827. this.ProjectDetailsHandler.ensureTokensArePresent = sinon
  828. .stub()
  829. .yields()
  830. return this.EditorController.setPublicAccessLevel(
  831. this.project_id,
  832. this.newAccessLevel,
  833. this.callback
  834. )
  835. })
  836. it('should set the access level', function () {
  837. return this.ProjectDetailsHandler.setPublicAccessLevel
  838. .calledWith(this.project_id, this.newAccessLevel)
  839. .should.equal(true)
  840. })
  841. it('should broadcast the access level change', function () {
  842. return this.EditorRealTimeController.emitToRoom
  843. .calledWith(this.project_id, 'project:publicAccessLevel:changed')
  844. .should.equal(true)
  845. })
  846. it('should ensure tokens are present for project', function () {
  847. return this.ProjectDetailsHandler.ensureTokensArePresent
  848. .calledWith(this.project_id)
  849. .should.equal(true)
  850. })
  851. })
  852. })
  853. describe('setRootDoc', function () {
  854. beforeEach(function () {
  855. this.newRootDocID = '21312321321'
  856. this.ProjectEntityUpdateHandler.setRootDoc = sinon.stub().yields()
  857. return this.EditorController.setRootDoc(
  858. this.project_id,
  859. this.newRootDocID,
  860. this.callback
  861. )
  862. })
  863. it('should call the ProjectEntityUpdateHandler', function () {
  864. return this.ProjectEntityUpdateHandler.setRootDoc
  865. .calledWith(this.project_id, this.newRootDocID)
  866. .should.equal(true)
  867. })
  868. it('should emit the update to the room', function () {
  869. return this.EditorRealTimeController.emitToRoom
  870. .calledWith(this.project_id, 'rootDocUpdated', this.newRootDocID)
  871. .should.equal(true)
  872. })
  873. })
  874. })