v5.page.test.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. import { addSeconds } from 'date-fns/addSeconds';
  2. import mongoose from 'mongoose';
  3. import { PageActionStage, PageActionType } from '../../../src/interfaces/page-operation';
  4. import { getInstance } from '../setup-crowi';
  5. describe('Test page service methods', () => {
  6. let crowi;
  7. let Page;
  8. let Revision;
  9. let User;
  10. let Tag;
  11. let Bookmark;
  12. let Comment;
  13. let ShareLink;
  14. let PageRedirect;
  15. let PageOperation;
  16. let xssSpy;
  17. let rootPage;
  18. let dummyUser1;
  19. let dummyUser2;
  20. let globalGroupUser1;
  21. let globalGroupUser2;
  22. let globalGroupUser3;
  23. let pageOpId1;
  24. let pageOpId2;
  25. let pageOpId3;
  26. let pageOpId4;
  27. let pageOpId5;
  28. let pageOpId6;
  29. beforeAll(async() => {
  30. crowi = await getInstance();
  31. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  32. User = mongoose.model('User');
  33. Page = mongoose.model('Page');
  34. Revision = mongoose.model('Revision');
  35. Tag = mongoose.model('Tag');
  36. Bookmark = mongoose.model('Bookmark');
  37. Comment = mongoose.model('Comment');
  38. ShareLink = mongoose.model('ShareLink');
  39. PageRedirect = mongoose.model('PageRedirect');
  40. PageOperation = mongoose.model('PageOperation');
  41. /*
  42. * Common
  43. */
  44. xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
  45. // ***********************************************************************************************************
  46. // * Do NOT change properties of globally used documents. Otherwise, it might cause some errors in other tests
  47. // ***********************************************************************************************************
  48. // users
  49. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  50. dummyUser2 = await User.findOne({ username: 'v5DummyUser2' });
  51. globalGroupUser1 = await User.findOne({ username: 'gGroupUser1' });
  52. globalGroupUser2 = await User.findOne({ username: 'gGroupUser2' });
  53. globalGroupUser3 = await User.findOne({ username: 'gGroupUser3' });
  54. // page
  55. rootPage = await Page.findOne({ path: '/' });
  56. /**
  57. * pages
  58. */
  59. const pageId0 = new mongoose.Types.ObjectId();
  60. const pageId1 = new mongoose.Types.ObjectId();
  61. const pageId2 = new mongoose.Types.ObjectId();
  62. const pageId3 = new mongoose.Types.ObjectId();
  63. const pageId4 = new mongoose.Types.ObjectId();
  64. const pageId5 = new mongoose.Types.ObjectId();
  65. const pageId6 = new mongoose.Types.ObjectId();
  66. const pageId7 = new mongoose.Types.ObjectId();
  67. const pageId8 = new mongoose.Types.ObjectId();
  68. const pageId9 = new mongoose.Types.ObjectId();
  69. const pageId10 = new mongoose.Types.ObjectId();
  70. const pageId11 = new mongoose.Types.ObjectId();
  71. const pageId12 = new mongoose.Types.ObjectId();
  72. const pageId13 = new mongoose.Types.ObjectId();
  73. const pageId14 = new mongoose.Types.ObjectId();
  74. const pageId15 = new mongoose.Types.ObjectId();
  75. const pageId16 = new mongoose.Types.ObjectId();
  76. const pageId17 = new mongoose.Types.ObjectId();
  77. const pageId18 = new mongoose.Types.ObjectId();
  78. const pageId19 = new mongoose.Types.ObjectId();
  79. const pageId20 = new mongoose.Types.ObjectId();
  80. await Page.insertMany([
  81. {
  82. _id: pageId0,
  83. path: '/resume_rename_0',
  84. parent: rootPage._id,
  85. grant: Page.GRANT_PUBLIC,
  86. creator: dummyUser1,
  87. lastUpdateUser: dummyUser1._id,
  88. descendantCount: 1,
  89. isEmpty: false,
  90. },
  91. {
  92. _id: pageId1,
  93. path: '/resume_rename_0/resume_rename_1',
  94. parent: pageId0,
  95. grant: Page.GRANT_PUBLIC,
  96. creator: dummyUser1,
  97. lastUpdateUser: dummyUser1._id,
  98. descendantCount: 2,
  99. isEmpty: false,
  100. },
  101. {
  102. _id: pageId2,
  103. path: '/resume_rename_1/resume_rename_2',
  104. parent: pageId1,
  105. grant: Page.GRANT_PUBLIC,
  106. creator: dummyUser1,
  107. lastUpdateUser: dummyUser1._id,
  108. descendantCount: 1,
  109. isEmpty: false,
  110. },
  111. {
  112. _id: pageId3,
  113. path: '/resume_rename_1/resume_rename_2/resume_rename_3',
  114. parent: pageId2,
  115. grant: Page.GRANT_PUBLIC,
  116. creator: dummyUser1,
  117. lastUpdateUser: dummyUser1._id,
  118. descendantCount: 0,
  119. isEmpty: false,
  120. },
  121. {
  122. _id: pageId4,
  123. path: '/resume_rename_4',
  124. parent: rootPage._id,
  125. grant: Page.GRANT_PUBLIC,
  126. creator: dummyUser1,
  127. lastUpdateUser: dummyUser1._id,
  128. descendantCount: 0,
  129. isEmpty: false,
  130. },
  131. {
  132. _id: pageId5,
  133. path: '/resume_rename_4/resume_rename_5',
  134. parent: pageId4,
  135. grant: Page.GRANT_PUBLIC,
  136. creator: dummyUser1,
  137. lastUpdateUser: dummyUser1._id,
  138. descendantCount: 1,
  139. isEmpty: false,
  140. },
  141. {
  142. _id: pageId6,
  143. path: '/resume_rename_5/resume_rename_6',
  144. parent: pageId5,
  145. grant: Page.GRANT_PUBLIC,
  146. creator: dummyUser1,
  147. lastUpdateUser: dummyUser1._id,
  148. descendantCount: 0,
  149. isEmpty: false,
  150. },
  151. {
  152. _id: pageId7,
  153. path: '/resume_rename_7',
  154. parent: rootPage._id,
  155. grant: Page.GRANT_PUBLIC,
  156. creator: dummyUser1,
  157. lastUpdateUser: dummyUser1._id,
  158. descendantCount: 0,
  159. isEmpty: false,
  160. },
  161. {
  162. _id: pageId8,
  163. path: '/resume_rename_8',
  164. parent: rootPage._id,
  165. grant: Page.GRANT_PUBLIC,
  166. creator: dummyUser1,
  167. lastUpdateUser: dummyUser1._id,
  168. descendantCount: 1,
  169. isEmpty: false,
  170. },
  171. {
  172. _id: pageId9,
  173. path: '/resume_rename_8/resume_rename_9',
  174. parent: pageId8,
  175. grant: Page.GRANT_PUBLIC,
  176. creator: dummyUser1,
  177. lastUpdateUser: dummyUser1._id,
  178. descendantCount: 1,
  179. isEmpty: false,
  180. },
  181. {
  182. path: '/resume_rename_9/resume_rename_10',
  183. parent: pageId9,
  184. grant: Page.GRANT_PUBLIC,
  185. creator: dummyUser1,
  186. lastUpdateUser: dummyUser1._id,
  187. descendantCount: 0,
  188. isEmpty: false,
  189. },
  190. {
  191. _id: pageId10,
  192. path: '/resume_rename_11',
  193. parent: rootPage._id,
  194. grant: Page.GRANT_PUBLIC,
  195. creator: dummyUser1,
  196. lastUpdateUser: dummyUser1._id,
  197. descendantCount: 3,
  198. isEmpty: false,
  199. },
  200. {
  201. _id: pageId11,
  202. path: '/resume_rename_11/resume_rename_12',
  203. parent: pageId10,
  204. grant: Page.GRANT_PUBLIC,
  205. creator: dummyUser1,
  206. lastUpdateUser: dummyUser1._id,
  207. descendantCount: 2,
  208. isEmpty: false,
  209. },
  210. {
  211. _id: pageId12,
  212. path: '/resume_rename_11/resume_rename_12/resume_rename_13',
  213. parent: pageId11,
  214. grant: Page.GRANT_PUBLIC,
  215. creator: dummyUser1,
  216. lastUpdateUser: dummyUser1._id,
  217. descendantCount: 1,
  218. isEmpty: false,
  219. },
  220. {
  221. path: '/resume_rename_11/resume_rename_12/resume_rename_13/resume_rename_14',
  222. parent: pageId12,
  223. grant: Page.GRANT_PUBLIC,
  224. creator: dummyUser1,
  225. lastUpdateUser: dummyUser1._id,
  226. descendantCount: 0,
  227. isEmpty: false,
  228. },
  229. {
  230. _id: pageId13,
  231. path: '/resume_rename_15',
  232. parent: rootPage._id,
  233. grant: Page.GRANT_PUBLIC,
  234. creator: dummyUser1,
  235. lastUpdateUser: dummyUser1._id,
  236. descendantCount: 2,
  237. isEmpty: false,
  238. },
  239. {
  240. _id: pageId14,
  241. path: '/resume_rename_15/resume_rename_16',
  242. parent: pageId13,
  243. grant: Page.GRANT_PUBLIC,
  244. creator: dummyUser1,
  245. lastUpdateUser: dummyUser1._id,
  246. descendantCount: 0,
  247. isEmpty: false,
  248. },
  249. {
  250. _id: pageId15,
  251. path: '/resume_rename_15/resume_rename_17',
  252. parent: pageId13,
  253. grant: Page.GRANT_PUBLIC,
  254. creator: dummyUser1,
  255. lastUpdateUser: dummyUser1._id,
  256. descendantCount: 1,
  257. isEmpty: false,
  258. },
  259. {
  260. _id: pageId16,
  261. path: '/resume_rename_15/resume_rename_17/resume_rename_18',
  262. parent: pageId15,
  263. grant: Page.GRANT_PUBLIC,
  264. creator: dummyUser1,
  265. lastUpdateUser: dummyUser1._id,
  266. descendantCount: 1,
  267. isEmpty: false,
  268. },
  269. {
  270. _id: pageId17,
  271. path: '/resume_rename_15/resume_rename_17/resume_rename_18/resume_rename_19',
  272. parent: pageId16,
  273. grant: Page.GRANT_PUBLIC,
  274. creator: dummyUser1,
  275. lastUpdateUser: dummyUser1._id,
  276. descendantCount: 0,
  277. isEmpty: false,
  278. },
  279. {
  280. _id: pageId18,
  281. path: '/fix_descendantCount_1',
  282. parent: rootPage._id,
  283. grant: Page.GRANT_PUBLIC,
  284. creator: dummyUser1,
  285. lastUpdateUser: dummyUser1._id,
  286. descendantCount: 100, // broken
  287. isEmpty: false,
  288. },
  289. {
  290. _id: pageId19,
  291. path: '/fix_descendantCount_1/fix_descendantCount_2',
  292. parent: pageId18,
  293. grant: Page.GRANT_PUBLIC,
  294. creator: dummyUser1,
  295. lastUpdateUser: dummyUser1._id,
  296. descendantCount: 100, // broken
  297. isEmpty: true,
  298. },
  299. {
  300. path: '/fix_descendantCount_1/fix_descendantCount_2/fix_descendantCount_3',
  301. parent: pageId19,
  302. grant: Page.GRANT_PUBLIC,
  303. creator: dummyUser1,
  304. lastUpdateUser: dummyUser1._id,
  305. descendantCount: 100, // broken
  306. isEmpty: false,
  307. },
  308. {
  309. _id: pageId20,
  310. path: '/fix_descendantCount_4',
  311. parent: rootPage._id,
  312. grant: Page.GRANT_PUBLIC,
  313. creator: dummyUser1,
  314. lastUpdateUser: dummyUser1._id,
  315. descendantCount: 100, // broken
  316. isEmpty: false,
  317. },
  318. {
  319. path: '/fix_descendantCount_4/fix_descendantCount_5',
  320. parent: pageId20,
  321. grant: Page.GRANT_PUBLIC,
  322. creator: dummyUser1,
  323. lastUpdateUser: dummyUser1._id,
  324. descendantCount: 100, // broken
  325. isEmpty: false,
  326. },
  327. ]);
  328. /**
  329. * PageOperation
  330. */
  331. pageOpId1 = new mongoose.Types.ObjectId();
  332. pageOpId2 = new mongoose.Types.ObjectId();
  333. pageOpId3 = new mongoose.Types.ObjectId();
  334. pageOpId4 = new mongoose.Types.ObjectId();
  335. const pageOpRevisionId1 = new mongoose.Types.ObjectId();
  336. const pageOpRevisionId2 = new mongoose.Types.ObjectId();
  337. const pageOpRevisionId3 = new mongoose.Types.ObjectId();
  338. const pageOpRevisionId4 = new mongoose.Types.ObjectId();
  339. await PageOperation.insertMany([
  340. {
  341. _id: pageOpId1,
  342. actionType: 'Rename',
  343. actionStage: 'Sub',
  344. fromPath: '/resume_rename_1',
  345. toPath: '/resume_rename_0/resume_rename_1',
  346. page: {
  347. _id: pageId1,
  348. parent: rootPage._id,
  349. descendantCount: 2,
  350. isEmpty: false,
  351. path: '/resume_rename_1',
  352. revision: pageOpRevisionId1,
  353. status: 'published',
  354. grant: 1,
  355. grantedUsers: [],
  356. grantedGroups: [],
  357. creator: dummyUser1._id,
  358. lastUpdateUser: dummyUser1._id,
  359. },
  360. user: {
  361. _id: dummyUser1._id,
  362. },
  363. options: {
  364. createRedirectPage: false,
  365. updateMetadata: true,
  366. },
  367. unprocessableExpiryDate: null,
  368. },
  369. {
  370. _id: pageOpId2,
  371. actionType: 'Rename',
  372. actionStage: 'Sub',
  373. fromPath: '/resume_rename_5',
  374. toPath: '/resume_rename_4/resume_rename_5',
  375. page: {
  376. _id: pageId5,
  377. parent: rootPage._id,
  378. descendantCount: 2,
  379. isEmpty: false,
  380. path: '/resume_rename_5',
  381. revision: pageOpRevisionId2,
  382. status: 'published',
  383. grant: 1,
  384. grantedUsers: [],
  385. grantedGroups: [],
  386. creator: dummyUser1._id,
  387. lastUpdateUser: dummyUser1._id,
  388. },
  389. user: {
  390. _id: dummyUser1._id,
  391. },
  392. options: {
  393. createRedirectPage: false,
  394. updateMetadata: true,
  395. },
  396. unprocessableExpiryDate: new Date(),
  397. },
  398. {
  399. _id: pageOpId3,
  400. actionType: 'Rename',
  401. actionStage: 'Sub',
  402. fromPath: '/resume_rename_7',
  403. // toPath NOT exist
  404. page: {
  405. _id: pageId7,
  406. parent: rootPage._id,
  407. descendantCount: 2,
  408. isEmpty: false,
  409. path: '/resume_rename_7',
  410. revision: pageOpRevisionId3,
  411. status: 'published',
  412. grant: 1,
  413. grantedUsers: [],
  414. grantedGroups: [],
  415. creator: dummyUser1._id,
  416. lastUpdateUser: dummyUser1._id,
  417. },
  418. user: {
  419. _id: dummyUser1._id,
  420. },
  421. options: {
  422. createRedirectPage: false,
  423. updateMetadata: true,
  424. },
  425. unprocessableExpiryDate: new Date(),
  426. },
  427. {
  428. _id: pageOpId4,
  429. actionType: 'Rename',
  430. actionStage: 'Sub',
  431. fromPath: '/resume_rename_9',
  432. toPath: '/resume_rename_8/resume_rename_9',
  433. page: {
  434. _id: pageId9,
  435. parent: rootPage._id,
  436. descendantCount: 1,
  437. isEmpty: false,
  438. path: '/resume_rename_9',
  439. revision: pageOpRevisionId4,
  440. status: 'published',
  441. grant: Page.GRANT_PUBLIC,
  442. grantedUsers: [],
  443. grantedGroups: [],
  444. creator: dummyUser1._id,
  445. lastUpdateUser: dummyUser1._id,
  446. },
  447. user: {
  448. _id: dummyUser1._id,
  449. },
  450. options: {
  451. createRedirectPage: false,
  452. updateMetadata: true,
  453. },
  454. unprocessableExpiryDate: null,
  455. },
  456. ]);
  457. });
  458. describe('restart renameOperation', () => {
  459. const resumeRenameSubOperation = async(renamePage, pageOp, activity?) => {
  460. const mockedPathsAndDescendantCountOfAncestors = jest.spyOn(crowi.pageService, 'fixPathsAndDescendantCountOfAncestors').mockReturnValue(null);
  461. await crowi.pageService.resumeRenameSubOperation(renamePage, pageOp, activity);
  462. const argsForRenameSubOperation = mockedPathsAndDescendantCountOfAncestors.mock.calls[0];
  463. mockedPathsAndDescendantCountOfAncestors.mockRestore();
  464. await crowi.pageService.fixPathsAndDescendantCountOfAncestors(...argsForRenameSubOperation);
  465. };
  466. test('it should successfully restart rename operation', async() => {
  467. // paths before renaming
  468. const _path0 = '/resume_rename_0'; // out of renaming scope
  469. const _path1 = '/resume_rename_0/resume_rename_1'; // renamed already
  470. const _path2 = '/resume_rename_1/resume_rename_2'; // not renamed yet
  471. const _path3 = '/resume_rename_1/resume_rename_2/resume_rename_3'; // not renamed yet
  472. // paths after renaming
  473. const path0 = '/resume_rename_0';
  474. const path1 = '/resume_rename_0/resume_rename_1';
  475. const path2 = '/resume_rename_0/resume_rename_1/resume_rename_2';
  476. const path3 = '/resume_rename_0/resume_rename_1/resume_rename_2/resume_rename_3';
  477. // activity options
  478. const activity = 'randomActivityId';
  479. // page
  480. const _page0 = await Page.findOne({ path: _path0 });
  481. const _page1 = await Page.findOne({ path: _path1 });
  482. const _page2 = await Page.findOne({ path: _path2 });
  483. const _page3 = await Page.findOne({ path: _path3 });
  484. expect(_page0).toBeTruthy();
  485. expect(_page1).toBeTruthy();
  486. expect(_page2).toBeTruthy();
  487. expect(_page3).toBeTruthy();
  488. expect(_page0.descendantCount).toBe(1);
  489. expect(_page1.descendantCount).toBe(2);
  490. expect(_page2.descendantCount).toBe(1);
  491. expect(_page3.descendantCount).toBe(0);
  492. // page operation
  493. const fromPath = '/resume_rename_1';
  494. const toPath = '/resume_rename_0/resume_rename_1';
  495. const _pageOperation = await PageOperation.findOne({
  496. _id: pageOpId1, fromPath, toPath, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  497. });
  498. expect(_pageOperation).toBeTruthy();
  499. // rename
  500. await resumeRenameSubOperation(_page1, _pageOperation, activity);
  501. // page
  502. const page0 = await Page.findById(_page0._id);
  503. const page1 = await Page.findById(_page1._id);
  504. const page2 = await Page.findById(_page2._id);
  505. const page3 = await Page.findById(_page3._id);
  506. expect(page0).toBeTruthy();
  507. expect(page1).toBeTruthy();
  508. expect(page2).toBeTruthy();
  509. expect(page3).toBeTruthy();
  510. // check paths after renaming
  511. expect(page0.path).toBe(path0);
  512. expect(page1.path).toBe(path1);
  513. expect(page2.path).toBe(path2);
  514. expect(page3.path).toBe(path3);
  515. // page operation
  516. const pageOperation = await PageOperation.findById(_pageOperation._id);
  517. expect(pageOperation).toBeNull(); // should not exist
  518. expect(page0.descendantCount).toBe(3);
  519. expect(page1.descendantCount).toBe(2);
  520. expect(page2.descendantCount).toBe(1);
  521. expect(page3.descendantCount).toBe(0);
  522. });
  523. test('it should successfully restart rename operation when unprocessableExpiryDate is null', async() => {
  524. // paths before renaming
  525. const _path0 = '/resume_rename_8'; // out of renaming scope
  526. const _path1 = '/resume_rename_8/resume_rename_9'; // renamed already
  527. const _path2 = '/resume_rename_9/resume_rename_10'; // not renamed yet
  528. // paths after renaming
  529. const path0 = '/resume_rename_8';
  530. const path1 = '/resume_rename_8/resume_rename_9';
  531. const path2 = '/resume_rename_8/resume_rename_9/resume_rename_10';
  532. // activity options
  533. const activityParameters = {
  534. ip: '::ffff:127.0.0.1',
  535. endpoint: '/_api/v3/pages/rename',
  536. activityId: '62e291bc10e0ab61bd691794',
  537. };
  538. // page
  539. const _page0 = await Page.findOne({ path: _path0 });
  540. const _page1 = await Page.findOne({ path: _path1 });
  541. const _page2 = await Page.findOne({ path: _path2 });
  542. expect(_page0).toBeTruthy();
  543. expect(_page1).toBeTruthy();
  544. expect(_page2).toBeTruthy();
  545. expect(_page0.descendantCount).toBe(1);
  546. expect(_page1.descendantCount).toBe(1);
  547. expect(_page2.descendantCount).toBe(0);
  548. // page operation
  549. const fromPath = '/resume_rename_9';
  550. const toPath = '/resume_rename_8/resume_rename_9';
  551. const _pageOperation = await PageOperation.findOne({
  552. _id: pageOpId4, fromPath, toPath, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  553. });
  554. expect(_pageOperation).toBeTruthy();
  555. // rename
  556. await resumeRenameSubOperation(_page1, _pageOperation, activityParameters);
  557. // page
  558. const page0 = await Page.findById(_page0._id);
  559. const page1 = await Page.findById(_page1._id);
  560. const page2 = await Page.findById(_page2._id);
  561. expect(page0).toBeTruthy();
  562. expect(page1).toBeTruthy();
  563. expect(page2).toBeTruthy();
  564. // check paths after renaming
  565. expect(page0.path).toBe(path0);
  566. expect(page1.path).toBe(path1);
  567. expect(page2.path).toBe(path2);
  568. // page operation
  569. const pageOperation = await PageOperation.findById(_pageOperation._id);
  570. expect(pageOperation).toBeNull(); // should not exist
  571. // others
  572. expect(page1.parent).toStrictEqual(page0._id);
  573. expect(page2.parent).toStrictEqual(page1._id);
  574. expect(page0.descendantCount).toBe(2);
  575. expect(page1.descendantCount).toBe(1);
  576. expect(page2.descendantCount).toBe(0);
  577. });
  578. test('it should fail and throw error if the current time is behind unprocessableExpiryDate', async() => {
  579. // path before renaming
  580. const _path0 = '/resume_rename_4'; // out of renaming scope
  581. const _path1 = '/resume_rename_4/resume_rename_5'; // renamed already
  582. const _path2 = '/resume_rename_5/resume_rename_6'; // not renamed yet
  583. // page
  584. const _page0 = await Page.findOne({ path: _path0 });
  585. const _page1 = await Page.findOne({ path: _path1 });
  586. const _page2 = await Page.findOne({ path: _path2 });
  587. expect(_page0).toBeTruthy();
  588. expect(_page1).toBeTruthy();
  589. expect(_page2).toBeTruthy();
  590. // page operation
  591. const fromPath = '/resume_rename_5';
  592. const toPath = '/resume_rename_4/resume_rename_5';
  593. const _pageOperation = await PageOperation.findOne({
  594. _id: pageOpId2, fromPath, toPath, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  595. });
  596. expect(_pageOperation).toBeTruthy();
  597. // Make `unprocessableExpiryDate` 15 seconds ahead of current time.
  598. // The number 15 seconds has no meaning other than placing time in the furue.
  599. const pageOperation = await PageOperation.findByIdAndUpdate(_pageOperation._id, { unprocessableExpiryDate: addSeconds(new Date(), 15) }, { new: true });
  600. expect(pageOperation).toBeTruthy();
  601. await expect(resumeRenameSubOperation(_page1, pageOperation)).rejects.toThrow(new Error('This page operation is currently being processed'));
  602. // cleanup
  603. await PageOperation.findByIdAndDelete(pageOperation._id);
  604. });
  605. test('Missing property(toPath) for PageOperation should throw error', async() => {
  606. // page
  607. const _path1 = '/resume_rename_7';
  608. const _page1 = await Page.findOne({ path: _path1 });
  609. expect(_page1).toBeTruthy();
  610. // page operation
  611. const pageOperation = await PageOperation.findOne({
  612. _id: pageOpId3, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  613. });
  614. expect(pageOperation).toBeTruthy();
  615. const promise = resumeRenameSubOperation(_page1, pageOperation);
  616. await expect(promise).rejects.toThrow(new Error(`Property toPath is missing which is needed to resume rename operation(${pageOperation._id})`));
  617. // cleanup
  618. await PageOperation.findByIdAndDelete(pageOperation._id);
  619. });
  620. });
  621. describe('updateDescendantCountOfPagesWithPaths', () => {
  622. test('should fix descendantCount of pages with one of the given paths', async() => {
  623. // path
  624. const _path1 = '/fix_descendantCount_1';
  625. const _path2 = '/fix_descendantCount_1/fix_descendantCount_2'; // empty
  626. const _path3 = '/fix_descendantCount_1/fix_descendantCount_2/fix_descendantCount_3';
  627. const _path4 = '/fix_descendantCount_4';
  628. const _path5 = '/fix_descendantCount_4/fix_descendantCount_5';
  629. // page
  630. const _page1 = await Page.findOne({ path: _path1 });
  631. const _page2 = await Page.findOne({ path: _path2 });
  632. const _page3 = await Page.findOne({ path: _path3 });
  633. const _page4 = await Page.findOne({ path: _path4 });
  634. const _page5 = await Page.findOne({ path: _path5 });
  635. // check existance
  636. expect(_page1).toBeTruthy();
  637. expect(_page2).toBeTruthy();
  638. expect(_page3).toBeTruthy();
  639. expect(_page4).toBeTruthy();
  640. expect(_page5).toBeTruthy();
  641. // check descendantCount (all broken)
  642. expect(_page1.descendantCount).toBe(100);
  643. expect(_page2.descendantCount).toBe(100);
  644. expect(_page3.descendantCount).toBe(100);
  645. expect(_page4.descendantCount).toBe(100);
  646. expect(_page5.descendantCount).toBe(100);
  647. // check isEmpty
  648. expect(_page1.isEmpty).toBe(false);
  649. expect(_page2.isEmpty).toBe(true);
  650. expect(_page3.isEmpty).toBe(false);
  651. expect(_page4.isEmpty).toBe(false);
  652. expect(_page5.isEmpty).toBe(false);
  653. // check parent
  654. expect(_page1.parent).toStrictEqual(rootPage._id);
  655. expect(_page2.parent).toStrictEqual(_page1._id);
  656. expect(_page3.parent).toStrictEqual(_page2._id);
  657. expect(_page4.parent).toStrictEqual(rootPage._id);
  658. expect(_page5.parent).toStrictEqual(_page4._id);
  659. await crowi.pageService.updateDescendantCountOfPagesWithPaths([_path1, _path2, _path3, _path4, _path5]);
  660. // page
  661. const page1 = await Page.findById(_page1._id);
  662. const page2 = await Page.findById(_page2._id);
  663. const page3 = await Page.findById(_page3._id);
  664. const page4 = await Page.findById(_page4._id);
  665. const page5 = await Page.findById(_page5._id);
  666. // check existance
  667. expect(page1).toBeTruthy();
  668. expect(page2).toBeTruthy();
  669. expect(page3).toBeTruthy();
  670. expect(page4).toBeTruthy();
  671. expect(page5).toBeTruthy();
  672. // check descendantCount (all fixed)
  673. expect(page1.descendantCount).toBe(1);
  674. expect(page2.descendantCount).toBe(1);
  675. expect(page3.descendantCount).toBe(0);
  676. expect(page4.descendantCount).toBe(1);
  677. expect(page5.descendantCount).toBe(0);
  678. // check isEmpty
  679. expect(page1.isEmpty).toBe(false);
  680. expect(page2.isEmpty).toBe(true);
  681. expect(page3.isEmpty).toBe(false);
  682. expect(page4.isEmpty).toBe(false);
  683. expect(page5.isEmpty).toBe(false);
  684. // check parent
  685. expect(page1.parent).toStrictEqual(rootPage._id);
  686. expect(page2.parent).toStrictEqual(page1._id);
  687. expect(page3.parent).toStrictEqual(page2._id);
  688. expect(page4.parent).toStrictEqual(rootPage._id);
  689. expect(page5.parent).toStrictEqual(page4._id);
  690. });
  691. });
  692. });