EditorControllerTests.js 28 KB

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