v5.public-page.test.ts 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681
  1. /* eslint-disable no-unused-vars */
  2. import { advanceTo } from 'jest-date-mock';
  3. import mongoose from 'mongoose';
  4. import { getInstance } from '../setup-crowi';
  5. describe('PageService page operations with only public pages', () => {
  6. let dummyUser1;
  7. let dummyUser2;
  8. let crowi;
  9. let Page;
  10. let Revision;
  11. let User;
  12. let Tag;
  13. let PageTagRelation;
  14. let Bookmark;
  15. let Comment;
  16. let ShareLink;
  17. let PageRedirect;
  18. let xssSpy;
  19. let rootPage;
  20. beforeAll(async() => {
  21. crowi = await getInstance();
  22. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  23. User = mongoose.model('User');
  24. Page = mongoose.model('Page');
  25. Revision = mongoose.model('Revision');
  26. Tag = mongoose.model('Tag');
  27. PageTagRelation = mongoose.model('PageTagRelation');
  28. Bookmark = mongoose.model('Bookmark');
  29. Comment = mongoose.model('Comment');
  30. ShareLink = mongoose.model('ShareLink');
  31. PageRedirect = mongoose.model('PageRedirect');
  32. /*
  33. * Common
  34. */
  35. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  36. dummyUser2 = await User.findOne({ username: 'v5DummyUser2' });
  37. xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
  38. rootPage = await Page.findOne({ path: '/' });
  39. if (rootPage == null) {
  40. const pages = await Page.insertMany([{ path: '/', grant: Page.GRANT_PUBLIC }]);
  41. rootPage = pages[0];
  42. }
  43. /*
  44. * Rename
  45. */
  46. const pageIdForRename1 = new mongoose.Types.ObjectId();
  47. const pageIdForRename2 = new mongoose.Types.ObjectId();
  48. const pageIdForRename3 = new mongoose.Types.ObjectId();
  49. const pageIdForRename4 = new mongoose.Types.ObjectId();
  50. const pageIdForRename5 = new mongoose.Types.ObjectId();
  51. const pageIdForRename7 = new mongoose.Types.ObjectId();
  52. const pageIdForRename8 = new mongoose.Types.ObjectId();
  53. const pageIdForRename9 = new mongoose.Types.ObjectId();
  54. const pageIdForRename10 = new mongoose.Types.ObjectId();
  55. const pageIdForRename11 = new mongoose.Types.ObjectId();
  56. const pageIdForRename12 = new mongoose.Types.ObjectId();
  57. const pageIdForRename13 = new mongoose.Types.ObjectId();
  58. const pageIdForRename14 = new mongoose.Types.ObjectId();
  59. const pageIdForRename16 = new mongoose.Types.ObjectId();
  60. const pageIdForRename17 = new mongoose.Types.ObjectId();
  61. const pageIdForRename18 = new mongoose.Types.ObjectId();
  62. const pageIdForRename19 = new mongoose.Types.ObjectId();
  63. const pageIdForRename20 = new mongoose.Types.ObjectId();
  64. const pageIdForRename21 = new mongoose.Types.ObjectId();
  65. const pageIdForRename22 = new mongoose.Types.ObjectId();
  66. const pageIdForRename23 = new mongoose.Types.ObjectId();
  67. // Create Pages
  68. await Page.insertMany([
  69. {
  70. _id: pageIdForRename1,
  71. path: '/v5_ParentForRename1',
  72. grant: Page.GRANT_PUBLIC,
  73. creator: dummyUser1,
  74. lastUpdateUser: dummyUser1._id,
  75. parent: rootPage._id,
  76. },
  77. {
  78. _id: pageIdForRename2,
  79. path: '/v5_ParentForRename2',
  80. grant: Page.GRANT_PUBLIC,
  81. parent: rootPage._id,
  82. isEmpty: true,
  83. },
  84. {
  85. // id not needed for this data
  86. path: '/v5_ParentForRename2/dummyChild1',
  87. grant: Page.GRANT_PUBLIC,
  88. creator: dummyUser1,
  89. lastUpdateUser: dummyUser1._id,
  90. parent: pageIdForRename2,
  91. },
  92. {
  93. _id: pageIdForRename3,
  94. path: '/v5_ParentForRename3',
  95. grant: Page.GRANT_PUBLIC,
  96. creator: dummyUser1,
  97. lastUpdateUser: dummyUser1._id,
  98. parent: rootPage._id,
  99. },
  100. {
  101. _id: pageIdForRename4,
  102. path: '/v5_ParentForRename4',
  103. grant: Page.GRANT_PUBLIC,
  104. creator: dummyUser1,
  105. lastUpdateUser: dummyUser1._id,
  106. parent: rootPage._id,
  107. },
  108. {
  109. _id: pageIdForRename5,
  110. path: '/v5_ParentForRename5',
  111. grant: Page.GRANT_PUBLIC,
  112. creator: dummyUser1,
  113. lastUpdateUser: dummyUser1._id,
  114. parent: rootPage._id,
  115. },
  116. {
  117. _id: pageIdForRename7,
  118. path: '/v5_ParentForRename7',
  119. grant: Page.GRANT_PUBLIC,
  120. creator: dummyUser1,
  121. lastUpdateUser: dummyUser1._id,
  122. parent: rootPage._id,
  123. },
  124. {
  125. _id: pageIdForRename8,
  126. path: '/v5_ParentForRename8',
  127. grant: Page.GRANT_PUBLIC,
  128. creator: dummyUser1,
  129. lastUpdateUser: dummyUser1._id,
  130. parent: rootPage._id,
  131. },
  132. {
  133. _id: pageIdForRename9,
  134. path: '/v5_ParentForRename9',
  135. grant: Page.GRANT_PUBLIC,
  136. creator: dummyUser1,
  137. lastUpdateUser: dummyUser1._id,
  138. parent: rootPage._id,
  139. },
  140. {
  141. _id: pageIdForRename10,
  142. path: '/v5_ChildForRename1',
  143. grant: Page.GRANT_PUBLIC,
  144. creator: dummyUser1,
  145. lastUpdateUser: dummyUser1._id,
  146. parent: rootPage._id,
  147. },
  148. {
  149. _id: pageIdForRename11,
  150. path: '/v5_ChildForRename2',
  151. grant: Page.GRANT_PUBLIC,
  152. creator: dummyUser1,
  153. lastUpdateUser: dummyUser1._id,
  154. parent: rootPage._id,
  155. },
  156. {
  157. _id: pageIdForRename12,
  158. path: '/v5_ChildForRename3',
  159. grant: Page.GRANT_PUBLIC,
  160. creator: dummyUser1,
  161. lastUpdateUser: dummyUser1._id,
  162. parent: rootPage._id,
  163. updatedAt: new Date('2021'),
  164. },
  165. {
  166. _id: pageIdForRename13,
  167. path: '/v5_ChildForRename4',
  168. grant: Page.GRANT_PUBLIC,
  169. creator: dummyUser1,
  170. lastUpdateUser: dummyUser1._id,
  171. parent: rootPage._id,
  172. },
  173. {
  174. _id: pageIdForRename14,
  175. path: '/v5_ChildForRename5',
  176. grant: Page.GRANT_PUBLIC,
  177. creator: dummyUser1,
  178. lastUpdateUser: dummyUser1._id,
  179. parent: rootPage._id,
  180. },
  181. {
  182. _id: pageIdForRename16,
  183. path: '/v5_ChildForRename7',
  184. grant: Page.GRANT_PUBLIC,
  185. parent: rootPage._id,
  186. isEmpty: true,
  187. },
  188. {
  189. path: '/v5_ChildForRename5/v5_GrandchildForRename5',
  190. grant: Page.GRANT_PUBLIC,
  191. creator: dummyUser1,
  192. lastUpdateUser: dummyUser1._id,
  193. parent: pageIdForRename14,
  194. updatedAt: new Date('2021'),
  195. },
  196. {
  197. path: '/v5_ChildForRename7/v5_GrandchildForRename7',
  198. grant: Page.GRANT_PUBLIC,
  199. creator: dummyUser1,
  200. lastUpdateUser: dummyUser1._id,
  201. parent: pageIdForRename16,
  202. },
  203. {
  204. _id: pageIdForRename17,
  205. path: '/v5_pageForRename17',
  206. grant: Page.GRANT_PUBLIC,
  207. creator: dummyUser1,
  208. lastUpdateUser: dummyUser1._id,
  209. parent: rootPage._id,
  210. },
  211. {
  212. _id: pageIdForRename18,
  213. path: '/v5_pageForRename17/v5_pageForRename18',
  214. grant: Page.GRANT_PUBLIC,
  215. creator: dummyUser1,
  216. lastUpdateUser: dummyUser1._id,
  217. parent: pageIdForRename17,
  218. },
  219. {
  220. _id: pageIdForRename19,
  221. path: '/v5_pageForRename19',
  222. grant: Page.GRANT_PUBLIC,
  223. parent: rootPage._id,
  224. isEmpty: true,
  225. },
  226. {
  227. _id: pageIdForRename20,
  228. path: '/v5_pageForRename19/v5_pageForRename20',
  229. grant: Page.GRANT_PUBLIC,
  230. creator: dummyUser1,
  231. lastUpdateUser: dummyUser1._id,
  232. parent: pageIdForRename19,
  233. },
  234. {
  235. _id: pageIdForRename21,
  236. path: '/v5_pageForRename21',
  237. grant: Page.GRANT_PUBLIC,
  238. creator: dummyUser1,
  239. lastUpdateUser: dummyUser1._id,
  240. parent: rootPage._id,
  241. },
  242. {
  243. _id: pageIdForRename22,
  244. path: '/v5_pageForRename21/v5_pageForRename22',
  245. grant: Page.GRANT_PUBLIC,
  246. isEmpty: true,
  247. parent: pageIdForRename21,
  248. },
  249. {
  250. _id: pageIdForRename23,
  251. path: '/v5_pageForRename21/v5_pageForRename22/v5_pageForRename23',
  252. grant: Page.GRANT_PUBLIC,
  253. creator: dummyUser1,
  254. lastUpdateUser: dummyUser1._id,
  255. parent: pageIdForRename22,
  256. },
  257. ]);
  258. /*
  259. * Duplicate
  260. */
  261. // page ids
  262. const pageIdForDuplicate1 = new mongoose.Types.ObjectId();
  263. const pageIdForDuplicate2 = new mongoose.Types.ObjectId();
  264. const pageIdForDuplicate3 = new mongoose.Types.ObjectId();
  265. const pageIdForDuplicate4 = new mongoose.Types.ObjectId();
  266. const pageIdForDuplicate5 = new mongoose.Types.ObjectId();
  267. const pageIdForDuplicate6 = new mongoose.Types.ObjectId();
  268. const pageIdForDuplicate7 = new mongoose.Types.ObjectId();
  269. const pageIdForDuplicate8 = new mongoose.Types.ObjectId();
  270. const pageIdForDuplicate9 = new mongoose.Types.ObjectId();
  271. const pageIdForDuplicate10 = new mongoose.Types.ObjectId();
  272. const pageIdForDuplicate11 = new mongoose.Types.ObjectId();
  273. const pageIdForDuplicate12 = new mongoose.Types.ObjectId();
  274. const pageIdForDuplicate13 = new mongoose.Types.ObjectId();
  275. const pageIdForDuplicate14 = new mongoose.Types.ObjectId();
  276. const pageIdForDuplicate15 = new mongoose.Types.ObjectId();
  277. // revision ids
  278. const revisionIdForDuplicate1 = new mongoose.Types.ObjectId();
  279. const revisionIdForDuplicate2 = new mongoose.Types.ObjectId();
  280. const revisionIdForDuplicate3 = new mongoose.Types.ObjectId();
  281. const revisionIdForDuplicate4 = new mongoose.Types.ObjectId();
  282. const revisionIdForDuplicate5 = new mongoose.Types.ObjectId();
  283. const revisionIdForDuplicate6 = new mongoose.Types.ObjectId();
  284. const revisionIdForDuplicate7 = new mongoose.Types.ObjectId();
  285. const revisionIdForDuplicate8 = new mongoose.Types.ObjectId();
  286. const revisionIdForDuplicate9 = new mongoose.Types.ObjectId();
  287. const revisionIdForDuplicate10 = new mongoose.Types.ObjectId();
  288. const revisionIdForDuplicate11 = new mongoose.Types.ObjectId();
  289. const revisionIdForDuplicate12 = new mongoose.Types.ObjectId();
  290. await Page.insertMany([
  291. {
  292. _id: pageIdForDuplicate1,
  293. path: '/v5_PageForDuplicate1',
  294. grant: Page.GRANT_PUBLIC,
  295. creator: dummyUser1,
  296. lastUpdateUser: dummyUser1._id,
  297. parent: rootPage._id,
  298. revision: revisionIdForDuplicate1,
  299. },
  300. {
  301. _id: pageIdForDuplicate2,
  302. path: '/v5_PageForDuplicate2',
  303. grant: Page.GRANT_PUBLIC,
  304. parent: rootPage._id,
  305. isEmpty: true,
  306. },
  307. {
  308. _id: pageIdForDuplicate3,
  309. path: '/v5_PageForDuplicate2/v5_ChildForDuplicate2',
  310. grant: Page.GRANT_PUBLIC,
  311. creator: dummyUser1,
  312. lastUpdateUser: dummyUser1._id,
  313. parent: pageIdForDuplicate2,
  314. revision: revisionIdForDuplicate2,
  315. },
  316. {
  317. _id: pageIdForDuplicate4,
  318. path: '/v5_PageForDuplicate3',
  319. grant: Page.GRANT_PUBLIC,
  320. creator: dummyUser1,
  321. lastUpdateUser: dummyUser1._id,
  322. parent: rootPage._id,
  323. revision: revisionIdForDuplicate3,
  324. },
  325. {
  326. _id: pageIdForDuplicate5,
  327. path: '/v5_PageForDuplicate3/v5_Child_1_ForDuplicate3',
  328. grant: Page.GRANT_PUBLIC,
  329. creator: dummyUser1,
  330. lastUpdateUser: dummyUser1._id,
  331. parent: pageIdForDuplicate4,
  332. revision: revisionIdForDuplicate4,
  333. },
  334. {
  335. _id: pageIdForDuplicate6,
  336. path: '/v5_PageForDuplicate3/v5_Child_2_ForDuplicate3',
  337. grant: Page.GRANT_PUBLIC,
  338. creator: dummyUser1,
  339. lastUpdateUser: dummyUser1._id,
  340. parent: pageIdForDuplicate4,
  341. revision: revisionIdForDuplicate5,
  342. },
  343. {
  344. _id: pageIdForDuplicate7,
  345. path: '/v5_PageForDuplicate4',
  346. grant: Page.GRANT_PUBLIC,
  347. creator: dummyUser1,
  348. lastUpdateUser: dummyUser1._id,
  349. parent: rootPage._id,
  350. revision: revisionIdForDuplicate6,
  351. },
  352. {
  353. _id: pageIdForDuplicate8,
  354. path: '/v5_PageForDuplicate4/v5_empty_PageForDuplicate4',
  355. grant: Page.GRANT_PUBLIC,
  356. parent: pageIdForDuplicate7,
  357. isEmpty: true,
  358. },
  359. {
  360. _id: pageIdForDuplicate9,
  361. path: '/v5_PageForDuplicate4/v5_empty_PageForDuplicate4/v5_grandchild_PageForDuplicate4',
  362. grant: Page.GRANT_PUBLIC,
  363. creator: dummyUser1,
  364. lastUpdateUser: dummyUser1._id,
  365. parent: pageIdForDuplicate8,
  366. revision: revisionIdForDuplicate7,
  367. },
  368. {
  369. _id: pageIdForDuplicate10,
  370. path: '/v5_PageForDuplicate5',
  371. grant: Page.GRANT_PUBLIC,
  372. creator: dummyUser1,
  373. lastUpdateUser: dummyUser1._id,
  374. parent: rootPage._id,
  375. revision: revisionIdForDuplicate8,
  376. },
  377. {
  378. _id: pageIdForDuplicate11,
  379. path: '/v5_PageForDuplicate6',
  380. grant: Page.GRANT_PUBLIC,
  381. creator: dummyUser1,
  382. lastUpdateUser: dummyUser1._id,
  383. parent: rootPage._id,
  384. revision: revisionIdForDuplicate9,
  385. },
  386. {
  387. _id: pageIdForDuplicate13,
  388. path: '/v5_empty_PageForDuplicate7',
  389. grant: Page.GRANT_PUBLIC,
  390. parent: rootPage._id,
  391. isEmpty: true,
  392. },
  393. {
  394. _id: pageIdForDuplicate14,
  395. path: '/v5_empty_PageForDuplicate7/v5_child_PageForDuplicate7',
  396. grant: Page.GRANT_PUBLIC,
  397. creator: dummyUser1,
  398. lastUpdateUser: dummyUser1._id,
  399. parent: pageIdForDuplicate13,
  400. revision: revisionIdForDuplicate11,
  401. },
  402. {
  403. _id: pageIdForDuplicate15,
  404. path: '/v5_empty_PageForDuplicate7/v5_child_PageForDuplicate7/v5_grandchild_PageForDuplicate7',
  405. grant: Page.GRANT_PUBLIC,
  406. creator: dummyUser1,
  407. lastUpdateUser: dummyUser1._id,
  408. parent: pageIdForDuplicate14,
  409. revision: revisionIdForDuplicate12,
  410. },
  411. ]);
  412. await Revision.insertMany([
  413. {
  414. _id: revisionIdForDuplicate1,
  415. body: 'body1',
  416. format: 'markdown',
  417. pageId: pageIdForDuplicate1,
  418. author: dummyUser1,
  419. },
  420. {
  421. _id: revisionIdForDuplicate2,
  422. body: 'body3',
  423. format: 'markdown',
  424. pageId: pageIdForDuplicate3,
  425. author: dummyUser1,
  426. },
  427. {
  428. _id: revisionIdForDuplicate3,
  429. body: 'parent_page_body4',
  430. format: 'markdown',
  431. pageId: pageIdForDuplicate4,
  432. author: dummyUser1,
  433. },
  434. {
  435. _id: revisionIdForDuplicate4,
  436. body: 'revision_id_4_child_page_body',
  437. format: 'markdown',
  438. pageId: pageIdForDuplicate5,
  439. author: dummyUser1,
  440. },
  441. {
  442. _id: revisionIdForDuplicate5,
  443. body: 'revision_id_5_child_page_body',
  444. format: 'markdown',
  445. pageId: pageIdForDuplicate6,
  446. author: dummyUser1,
  447. },
  448. {
  449. _id: revisionIdForDuplicate6,
  450. body: '/v5_PageForDuplicate4',
  451. format: 'markdown',
  452. pageId: pageIdForDuplicate7,
  453. author: dummyUser1,
  454. },
  455. {
  456. _id: revisionIdForDuplicate7,
  457. body: '/v5_PageForDuplicate4/v5_empty_PageForDuplicate4/v5_grandchild_PageForDuplicate4',
  458. format: 'markdown',
  459. pageId: pageIdForDuplicate9,
  460. author: dummyUser1,
  461. },
  462. {
  463. _id: revisionIdForDuplicate8,
  464. body: '/v5_PageForDuplicate5',
  465. format: 'markdown',
  466. pageId: pageIdForDuplicate10,
  467. author: dummyUser1,
  468. },
  469. {
  470. _id: revisionIdForDuplicate9,
  471. body: '/v5_PageForDuplicate6',
  472. format: 'markdown',
  473. pageId: pageIdForDuplicate11,
  474. author: dummyUser1,
  475. },
  476. {
  477. _id: revisionIdForDuplicate10,
  478. body: '/v5_PageForDuplicate6',
  479. format: 'comment',
  480. pageId: pageIdForDuplicate12,
  481. author: dummyUser1,
  482. },
  483. {
  484. _id: revisionIdForDuplicate11,
  485. body: '/v5_child_PageForDuplicate7',
  486. format: 'markdown',
  487. pageId: pageIdForDuplicate14,
  488. author: dummyUser1,
  489. },
  490. {
  491. _id: revisionIdForDuplicate12,
  492. body: '/v5_grandchild_PageForDuplicate7',
  493. format: 'markdown',
  494. pageId: pageIdForDuplicate15,
  495. author: dummyUser1,
  496. },
  497. ]);
  498. const tagForDuplicate1 = new mongoose.Types.ObjectId();
  499. const tagForDuplicate2 = new mongoose.Types.ObjectId();
  500. await Tag.insertMany([
  501. { _id: tagForDuplicate1, name: 'duplicate_Tag1' },
  502. { _id: tagForDuplicate2, name: 'duplicate_Tag2' },
  503. ]);
  504. await PageTagRelation.insertMany([
  505. { relatedPage: pageIdForDuplicate10, relatedTag: tagForDuplicate1 },
  506. { relatedPage: pageIdForDuplicate10._id, relatedTag: tagForDuplicate2 },
  507. ]);
  508. await Comment.insertMany([
  509. {
  510. commentPosition: -1,
  511. isMarkdown: true,
  512. page: pageIdForDuplicate11,
  513. creator: dummyUser1._id,
  514. revision: revisionIdForDuplicate10,
  515. comment: 'this is comment',
  516. },
  517. ]);
  518. /**
  519. * Delete
  520. */
  521. const pageIdForDelete1 = new mongoose.Types.ObjectId();
  522. const pageIdForDelete2 = new mongoose.Types.ObjectId();
  523. const pageIdForDelete3 = new mongoose.Types.ObjectId();
  524. const pageIdForDelete4 = new mongoose.Types.ObjectId();
  525. const pageIdForDelete5 = new mongoose.Types.ObjectId();
  526. await Page.insertMany([
  527. {
  528. path: '/trash/v5_PageForDelete1',
  529. grant: Page.GRANT_PUBLIC,
  530. creator: dummyUser1,
  531. lastUpdateUser: dummyUser1._id,
  532. status: Page.STATUS_DELETED,
  533. },
  534. {
  535. path: '/v5_PageForDelete2',
  536. grant: Page.GRANT_PUBLIC,
  537. creator: dummyUser1,
  538. lastUpdateUser: dummyUser1._id,
  539. parent: rootPage._id,
  540. status: Page.STATUS_PUBLISHED,
  541. },
  542. {
  543. _id: pageIdForDelete1,
  544. path: '/v5_PageForDelete3',
  545. grant: Page.GRANT_PUBLIC,
  546. creator: dummyUser1,
  547. lastUpdateUser: dummyUser1._id,
  548. parent: rootPage._id,
  549. status: Page.STATUS_PUBLISHED,
  550. },
  551. {
  552. _id: pageIdForDelete2,
  553. path: '/v5_PageForDelete3/v5_PageForDelete4',
  554. grant: Page.GRANT_PUBLIC,
  555. parent: pageIdForDelete1,
  556. status: Page.STATUS_PUBLISHED,
  557. isEmpty: true,
  558. },
  559. {
  560. path: '/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5',
  561. grant: Page.GRANT_PUBLIC,
  562. creator: dummyUser1,
  563. lastUpdateUser: dummyUser1._id,
  564. parent: pageIdForDelete2,
  565. status: Page.STATUS_PUBLISHED,
  566. },
  567. {
  568. _id: pageIdForDelete3,
  569. path: '/v5_PageForDelete6',
  570. grant: Page.GRANT_PUBLIC,
  571. creator: dummyUser1,
  572. lastUpdateUser: dummyUser1._id,
  573. parent: rootPage._id,
  574. status: Page.STATUS_PUBLISHED,
  575. },
  576. {
  577. _id: pageIdForDelete4,
  578. path: '/user',
  579. grant: Page.GRANT_PUBLIC,
  580. parent: rootPage._id,
  581. status: Page.STATUS_PUBLISHED,
  582. isEmpty: true,
  583. },
  584. {
  585. _id: pageIdForDelete5,
  586. path: '/user/v5DummyUser1',
  587. grant: Page.GRANT_PUBLIC,
  588. creator: dummyUser1,
  589. lastUpdateUser: dummyUser1._id,
  590. parent: pageIdForDelete4,
  591. status: Page.STATUS_PUBLISHED,
  592. },
  593. ]);
  594. const tagIdForDelete1 = new mongoose.Types.ObjectId();
  595. const tagIdForDelete2 = new mongoose.Types.ObjectId();
  596. await Tag.insertMany([
  597. { _id: tagIdForDelete1, name: 'TagForDelete1' },
  598. { _id: tagIdForDelete2, name: 'TagForDelete2' },
  599. ]);
  600. await PageTagRelation.insertMany([
  601. { relatedPage: pageIdForDelete3, relatedTag: tagIdForDelete1 },
  602. { relatedPage: pageIdForDelete3, relatedTag: tagIdForDelete2 },
  603. ]);
  604. /**
  605. * Delete completely
  606. */
  607. const pageIdForDeleteCompletely1 = new mongoose.Types.ObjectId();
  608. const pageIdForDeleteCompletely2 = new mongoose.Types.ObjectId();
  609. const pageIdForDeleteCompletely3 = new mongoose.Types.ObjectId();
  610. const pageIdForDeleteCompletely4 = new mongoose.Types.ObjectId();
  611. const pageIdForDeleteCompletely5 = new mongoose.Types.ObjectId();
  612. const pageIdForDeleteCompletely6 = new mongoose.Types.ObjectId();
  613. const pageIdForDeleteCompletely7 = new mongoose.Types.ObjectId();
  614. const pageIdForDeleteCompletely8 = new mongoose.Types.ObjectId();
  615. const revisionIdForDeleteCompletely1 = new mongoose.Types.ObjectId();
  616. const revisionIdForDeleteCompletely2 = new mongoose.Types.ObjectId();
  617. const revisionIdForDeleteCompletely3 = new mongoose.Types.ObjectId();
  618. const revisionIdForDeleteCompletely4 = new mongoose.Types.ObjectId();
  619. await Page.insertMany([
  620. {
  621. _id: pageIdForDeleteCompletely1,
  622. path: '/v5_PageForDeleteCompletely1',
  623. grant: Page.GRANT_PUBLIC,
  624. creator: dummyUser1,
  625. lastUpdateUser: dummyUser1._id,
  626. parent: rootPage._id,
  627. status: Page.STATUS_PUBLISHED,
  628. },
  629. {
  630. _id: pageIdForDeleteCompletely2,
  631. path: '/v5_PageForDeleteCompletely2',
  632. grant: Page.GRANT_PUBLIC,
  633. creator: dummyUser1,
  634. lastUpdateUser: dummyUser1._id,
  635. parent: rootPage._id,
  636. status: Page.STATUS_PUBLISHED,
  637. },
  638. {
  639. _id: pageIdForDeleteCompletely3,
  640. path: '/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3',
  641. grant: Page.GRANT_PUBLIC,
  642. parent: pageIdForDeleteCompletely2,
  643. status: Page.STATUS_PUBLISHED,
  644. isEmpty: true,
  645. },
  646. {
  647. _id: pageIdForDeleteCompletely4,
  648. path: '/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3/v5_PageForDeleteCompletely4',
  649. grant: Page.GRANT_PUBLIC,
  650. creator: dummyUser1,
  651. lastUpdateUser: dummyUser1._id,
  652. parent: pageIdForDeleteCompletely3,
  653. status: Page.STATUS_PUBLISHED,
  654. },
  655. {
  656. _id: pageIdForDeleteCompletely5,
  657. path: '/trash/v5_PageForDeleteCompletely5',
  658. grant: Page.GRANT_PUBLIC,
  659. creator: dummyUser1,
  660. lastUpdateUser: dummyUser1._id,
  661. parent: rootPage._id,
  662. status: Page.STATUS_DELETED,
  663. },
  664. {
  665. _id: pageIdForDeleteCompletely6,
  666. path: '/v5_PageForDeleteCompletely6',
  667. grant: Page.GRANT_PUBLIC,
  668. creator: dummyUser1,
  669. lastUpdateUser: dummyUser1._id,
  670. parent: rootPage._id,
  671. status: Page.STATUS_PUBLISHED,
  672. },
  673. {
  674. _id: pageIdForDeleteCompletely7,
  675. path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7',
  676. grant: Page.GRANT_PUBLIC,
  677. creator: dummyUser1,
  678. lastUpdateUser: dummyUser1._id,
  679. parent: pageIdForDeleteCompletely6,
  680. status: Page.STATUS_PUBLISHED,
  681. },
  682. {
  683. _id: pageIdForDeleteCompletely8,
  684. path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7/v5_PageForDeleteCompletely8',
  685. grant: Page.GRANT_PUBLIC,
  686. creator: dummyUser1,
  687. lastUpdateUser: dummyUser1._id,
  688. parent: pageIdForDeleteCompletely7,
  689. status: Page.STATUS_PUBLISHED,
  690. },
  691. ]);
  692. await Revision.insertMany([
  693. {
  694. _id: revisionIdForDeleteCompletely1,
  695. format: 'markdown',
  696. pageId: pageIdForDeleteCompletely2,
  697. body: 'pageIdForDeleteCompletely2',
  698. },
  699. {
  700. _id: revisionIdForDeleteCompletely2,
  701. format: 'markdown',
  702. pageId: pageIdForDeleteCompletely4,
  703. body: 'pageIdForDeleteCompletely4',
  704. },
  705. {
  706. _id: revisionIdForDeleteCompletely3,
  707. format: 'markdown',
  708. pageId: pageIdForDeleteCompletely5,
  709. body: 'pageIdForDeleteCompletely5',
  710. },
  711. {
  712. _id: revisionIdForDeleteCompletely4,
  713. format: 'markdown',
  714. pageId: pageIdForDeleteCompletely2,
  715. body: 'comment_pageIdForDeleteCompletely3',
  716. },
  717. ]);
  718. const tagForDeleteCompletely1 = new mongoose.Types.ObjectId();
  719. const tagForDeleteCompletely2 = new mongoose.Types.ObjectId();
  720. await Tag.insertMany([
  721. { name: 'TagForDeleteCompletely1' },
  722. { name: 'TagForDeleteCompletely2' },
  723. ]);
  724. await PageTagRelation.insertMany([
  725. { relatedPage: pageIdForDeleteCompletely2, relatedTag: tagForDeleteCompletely1 },
  726. { relatedPage: pageIdForDeleteCompletely4, relatedTag: tagForDeleteCompletely2 },
  727. ]);
  728. await Bookmark.insertMany([
  729. {
  730. page: pageIdForDeleteCompletely2,
  731. user: dummyUser1._id,
  732. },
  733. {
  734. page: pageIdForDeleteCompletely2,
  735. user: dummyUser2._id,
  736. },
  737. ]);
  738. await Comment.insertMany([
  739. {
  740. commentPosition: -1,
  741. isMarkdown: true,
  742. page: pageIdForDeleteCompletely2,
  743. creator: dummyUser1._id,
  744. revision: revisionIdForDeleteCompletely4,
  745. comment: 'comment_ForDeleteCompletely4',
  746. },
  747. ]);
  748. await PageRedirect.insertMany([
  749. {
  750. fromPath: '/from/v5_PageForDeleteCompletely2',
  751. toPath: '/v5_PageForDeleteCompletely2',
  752. },
  753. {
  754. fromPath: '/from/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3/v5_PageForDeleteCompletely4',
  755. toPath: '/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3/v5_PageForDeleteCompletely4',
  756. },
  757. ]);
  758. await ShareLink.insertMany([
  759. {
  760. relatedPage: pageIdForDeleteCompletely2,
  761. expiredAt: null,
  762. description: 'sharlink_v5PageForDeleteCompletely2',
  763. },
  764. {
  765. relatedPage: pageIdForDeleteCompletely4,
  766. expiredAt: null,
  767. description: 'sharlink_v5PageForDeleteCompletely4',
  768. },
  769. ]);
  770. /**
  771. * Revert
  772. */
  773. const pageIdForRevert1 = new mongoose.Types.ObjectId();
  774. const pageIdForRevert2 = new mongoose.Types.ObjectId();
  775. const pageIdForRevert3 = new mongoose.Types.ObjectId();
  776. const revisionIdForRevert1 = new mongoose.Types.ObjectId();
  777. const revisionIdForRevert2 = new mongoose.Types.ObjectId();
  778. const revisionIdForRevert3 = new mongoose.Types.ObjectId();
  779. await Page.insertMany([
  780. {
  781. _id: pageIdForRevert1,
  782. path: '/trash/v5_revert1',
  783. grant: Page.GRANT_PUBLIC,
  784. creator: dummyUser1,
  785. lastUpdateUser: dummyUser1._id,
  786. revision: revisionIdForRevert1,
  787. status: Page.STATUS_DELETED,
  788. },
  789. {
  790. _id: pageIdForRevert2,
  791. path: '/trash/v5_revert2',
  792. grant: Page.GRANT_PUBLIC,
  793. creator: dummyUser1,
  794. lastUpdateUser: dummyUser1._id,
  795. revision: revisionIdForRevert2,
  796. status: Page.STATUS_DELETED,
  797. },
  798. {
  799. _id: pageIdForRevert3,
  800. path: '/trash/v5_revert2/v5_revert3/v5_revert4',
  801. grant: Page.GRANT_PUBLIC,
  802. creator: dummyUser1,
  803. lastUpdateUser: dummyUser1._id,
  804. revision: revisionIdForRevert3,
  805. status: Page.STATUS_DELETED,
  806. },
  807. ]);
  808. await Revision.insertMany([
  809. {
  810. _id: revisionIdForRevert1,
  811. pageId: pageIdForRevert1,
  812. body: 'revert1',
  813. format: 'comment',
  814. author: dummyUser1,
  815. },
  816. {
  817. _id: revisionIdForRevert2,
  818. pageId: pageIdForRevert2,
  819. body: 'revert2',
  820. format: 'comment',
  821. author: dummyUser1,
  822. },
  823. {
  824. _id: revisionIdForRevert3,
  825. pageId: pageIdForRevert3,
  826. body: 'revert3',
  827. format: 'comment',
  828. author: dummyUser1,
  829. },
  830. ]);
  831. const tagIdRevert1 = new mongoose.Types.ObjectId();
  832. await Tag.insertMany([
  833. { _id: tagIdRevert1, name: 'revertTag1' },
  834. ]);
  835. await PageTagRelation.insertMany([
  836. {
  837. relatedPage: pageIdForRevert1,
  838. relatedTag: tagIdRevert1,
  839. isPageTrashed: true,
  840. },
  841. ]);
  842. });
  843. describe('Rename', () => {
  844. const renamePage = async(page, newPagePath, user, options) => {
  845. // mock return value
  846. const mockedRenameSubOperation = jest.spyOn(crowi.pageService, 'renameSubOperation').mockReturnValue(null);
  847. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  848. const renamedPage = await crowi.pageService.renamePage(page, newPagePath, user, options);
  849. // retrieve the arguments passed when calling method renameSubOperation inside renamePage method
  850. const argsForRenameSubOperation = mockedRenameSubOperation.mock.calls[0];
  851. // restores the original implementation
  852. mockedRenameSubOperation.mockRestore();
  853. mockedCreateAndSendNotifications.mockRestore();
  854. // rename descendants
  855. await crowi.pageService.renameSubOperation(...argsForRenameSubOperation);
  856. return renamedPage;
  857. };
  858. test('Should NOT rename top page', async() => {
  859. expect(rootPage).toBeTruthy();
  860. let isThrown = false;
  861. try {
  862. await crowi.pageService.renamePage(rootPage, '/new_root', dummyUser1, {});
  863. }
  864. catch (err) {
  865. isThrown = true;
  866. }
  867. expect(isThrown).toBe(true);
  868. });
  869. test('Should rename/move to under non-empty page', async() => {
  870. const parentPage = await Page.findOne({ path: '/v5_ParentForRename1' });
  871. const childPage = await Page.findOne({ path: '/v5_ChildForRename1' });
  872. expect(childPage).toBeTruthy();
  873. expect(parentPage).toBeTruthy();
  874. const newPath = '/v5_ParentForRename1/renamedChildForRename1';
  875. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  876. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename1' });
  877. expect(xssSpy).toHaveBeenCalled();
  878. expect(renamedPage.path).toBe(newPath);
  879. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  880. expect(childPageBeforeRename).toBeNull();
  881. });
  882. test('Should rename/move to under empty page', async() => {
  883. const parentPage = await Page.findOne({ path: '/v5_ParentForRename2' });
  884. const childPage = await Page.findOne({ path: '/v5_ChildForRename2' });
  885. expect(childPage).toBeTruthy();
  886. expect(parentPage).toBeTruthy();
  887. expect(parentPage.isEmpty).toBe(true);
  888. const newPath = '/v5_ParentForRename2/renamedChildForRename2';
  889. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  890. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename2' });
  891. expect(xssSpy).toHaveBeenCalled();
  892. expect(renamedPage.path).toBe(newPath);
  893. expect(parentPage.isEmpty).toBe(true);
  894. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  895. expect(childPageBeforeRename).toBeNull();
  896. });
  897. test('Should rename/move with option updateMetadata: true', async() => {
  898. const parentPage = await Page.findOne({ path: '/v5_ParentForRename3' });
  899. const childPage = await Page.findOne({ path: '/v5_ChildForRename3' });
  900. expect(childPage).toBeTruthy();
  901. expect(parentPage).toBeTruthy();
  902. expect(childPage.lastUpdateUser).toStrictEqual(dummyUser1._id);
  903. const newPath = '/v5_ParentForRename3/renamedChildForRename3';
  904. const oldUpdateAt = childPage.updatedAt;
  905. const renamedPage = await renamePage(childPage, newPath, dummyUser2, { updateMetadata: true });
  906. expect(xssSpy).toHaveBeenCalled();
  907. expect(renamedPage.path).toBe(newPath);
  908. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  909. expect(renamedPage.lastUpdateUser).toStrictEqual(dummyUser2._id);
  910. expect(renamedPage.updatedAt.getFullYear()).toBeGreaterThan(oldUpdateAt.getFullYear());
  911. });
  912. test('Should move with option createRedirectPage: true', async() => {
  913. const parentPage = await Page.findOne({ path: '/v5_ParentForRename4' });
  914. const childPage = await Page.findOne({ path: '/v5_ChildForRename4' });
  915. expect(parentPage).toBeTruthy();
  916. expect(childPage).toBeTruthy();
  917. const oldPath = childPage.path;
  918. const newPath = '/v5_ParentForRename4/renamedChildForRename4';
  919. const renamedPage = await renamePage(childPage, newPath, dummyUser2, { createRedirectPage: true });
  920. const pageRedirect = await PageRedirect.findOne({ fromPath: oldPath, toPath: renamedPage.path });
  921. expect(xssSpy).toHaveBeenCalled();
  922. expect(renamedPage.path).toBe(newPath);
  923. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  924. expect(pageRedirect).toBeTruthy();
  925. });
  926. test('Should rename/move with descendants', async() => {
  927. const parentPage = await Page.findOne({ path: '/v5_ParentForRename5' });
  928. const childPage = await Page.findOne({ path: '/v5_ChildForRename5' });
  929. const grandchild = await Page.findOne({ parent: childPage._id, path: '/v5_ChildForRename5/v5_GrandchildForRename5' });
  930. expect(parentPage).toBeTruthy();
  931. expect(childPage).toBeTruthy();
  932. expect(grandchild).toBeTruthy();
  933. const newPath = '/v5_ParentForRename5/renamedChildForRename5';
  934. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  935. // find child of renamed page
  936. const renamedGrandchild = await Page.findOne({ parent: renamedPage._id });
  937. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename5' });
  938. const grandchildBeforeRename = await Page.findOne({ path: grandchild.path });
  939. expect(xssSpy).toHaveBeenCalled();
  940. expect(renamedPage.path).toBe(newPath);
  941. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  942. expect(childPageBeforeRename).toBeNull();
  943. expect(grandchildBeforeRename).toBeNull();
  944. // grandchild's parent should be the renamed page
  945. expect(renamedGrandchild.parent).toStrictEqual(renamedPage._id);
  946. expect(renamedGrandchild.path).toBe('/v5_ParentForRename5/renamedChildForRename5/v5_GrandchildForRename5');
  947. });
  948. test('Should rename/move empty page', async() => {
  949. const parentPage = await Page.findOne({ path: '/v5_ParentForRename7' });
  950. const childPage = await Page.findOne({ path: '/v5_ChildForRename7', isEmpty: true });
  951. const grandchild = await Page.findOne({ parent: childPage._id, path: '/v5_ChildForRename7/v5_GrandchildForRename7' });
  952. expect(parentPage).toBeTruthy();
  953. expect(childPage).toBeTruthy();
  954. expect(grandchild).toBeTruthy();
  955. const newPath = '/v5_ParentForRename7/renamedChildForRename7';
  956. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  957. const grandchildAfterRename = await Page.findOne({ parent: renamedPage._id });
  958. const grandchildBeforeRename = await Page.findOne({ path: '/v5_ChildForRename7/v5_GrandchildForRename7' });
  959. expect(xssSpy).toHaveBeenCalled();
  960. expect(renamedPage.path).toBe(newPath);
  961. expect(renamedPage.isEmpty).toBe(true);
  962. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  963. expect(grandchildBeforeRename).toBeNull();
  964. // grandchild's parent should be renamed page
  965. expect(grandchildAfterRename.parent).toStrictEqual(renamedPage._id);
  966. expect(grandchildAfterRename.path).toBe('/v5_ParentForRename7/renamedChildForRename7/v5_GrandchildForRename7');
  967. });
  968. test('Should NOT rename/move with existing path', async() => {
  969. const page = await Page.findOne({ path: '/v5_ParentForRename8' });
  970. expect(page).toBeTruthy();
  971. const newPath = '/v5_ParentForRename9';
  972. let isThrown;
  973. try {
  974. await renamePage(page, newPath, dummyUser1, {});
  975. }
  976. catch (err) {
  977. isThrown = true;
  978. }
  979. expect(isThrown).toBe(true);
  980. });
  981. test('Rename non-empty page path to its descendant non-empty page path', async() => {
  982. const initialPathForPage1 = '/v5_pageForRename17';
  983. const initialPathForPage2 = '/v5_pageForRename17/v5_pageForRename18';
  984. const page1 = await Page.findOne({ path: initialPathForPage1, isEmpty: false });
  985. const page2 = await Page.findOne({ path: initialPathForPage2, isEmpty: false, parent: page1._id });
  986. expect(page1).toBeTruthy();
  987. expect(page2).toBeTruthy();
  988. const newParentalPath = '/v5_pageForRename17/v5_pageForRename18';
  989. const newPath = newParentalPath + page1.path;
  990. await renamePage(page1, newPath, dummyUser1, {});
  991. const renamedPage = await Page.findOne({ path: newParentalPath + initialPathForPage1 });
  992. const renamedPageChild = await Page.findOne({ path: newParentalPath + initialPathForPage2 });
  993. const newlyCreatedEmptyPage1 = await Page.findOne({ path: '/v5_pageForRename17' });
  994. const newlyCreatedEmptyPage2 = await Page.findOne({ path: '/v5_pageForRename17/v5_pageForRename18' });
  995. expect(renamedPage).toBeTruthy();
  996. expect(renamedPageChild).toBeTruthy();
  997. expect(newlyCreatedEmptyPage1).toBeTruthy();
  998. expect(newlyCreatedEmptyPage2).toBeTruthy();
  999. // check parent
  1000. expect(newlyCreatedEmptyPage1.parent).toStrictEqual(rootPage._id);
  1001. expect(newlyCreatedEmptyPage2.parent).toStrictEqual(newlyCreatedEmptyPage1._id);
  1002. expect(renamedPage.parent).toStrictEqual(newlyCreatedEmptyPage2._id);
  1003. expect(renamedPageChild.parent).toStrictEqual(renamedPage._id);
  1004. // check isEmpty
  1005. expect(newlyCreatedEmptyPage1.isEmpty).toBeTruthy();
  1006. expect(newlyCreatedEmptyPage2.isEmpty).toBeTruthy();
  1007. expect(renamedPage.isEmpty).toBe(false);
  1008. expect(renamedPageChild.isEmpty).toBe(false);
  1009. });
  1010. test('Rename empty page path to its descendant non-empty page path', async() => {
  1011. const initialPathForPage1 = '/v5_pageForRename19';
  1012. const initialPathForPage2 = '/v5_pageForRename19/v5_pageForRename20';
  1013. const page1 = await Page.findOne({ path: initialPathForPage1, isEmpty: true });
  1014. const page2 = await Page.findOne({ path: initialPathForPage2, isEmpty: false, parent: page1._id });
  1015. expect(page1).toBeTruthy();
  1016. expect(page2).toBeTruthy();
  1017. const newParentalPath = '/v5_pageForRename19/v5_pageForRename20';
  1018. const newPath = newParentalPath + page1.path;
  1019. await renamePage(page1, newPath, dummyUser1, {});
  1020. const renamedPage = await Page.findOne({ path: newParentalPath + initialPathForPage1 });
  1021. const renamedPageChild = await Page.findOne({ path: newParentalPath + initialPathForPage2 });
  1022. const newlyCreatedEmptyPage1 = await Page.findOne({ path: '/v5_pageForRename19' });
  1023. const newlyCreatedEmptyPage2 = await Page.findOne({ path: '/v5_pageForRename19/v5_pageForRename20' });
  1024. expect(renamedPage).toBeTruthy();
  1025. expect(renamedPageChild).toBeTruthy();
  1026. expect(newlyCreatedEmptyPage1).toBeTruthy();
  1027. expect(newlyCreatedEmptyPage2).toBeTruthy();
  1028. // check parent
  1029. expect(newlyCreatedEmptyPage1.parent).toStrictEqual(rootPage._id);
  1030. expect(newlyCreatedEmptyPage2.parent).toStrictEqual(newlyCreatedEmptyPage1._id);
  1031. expect(renamedPage.parent).toStrictEqual(newlyCreatedEmptyPage2._id);
  1032. expect(renamedPageChild.parent).toStrictEqual(renamedPage._id);
  1033. // check isEmpty
  1034. expect(newlyCreatedEmptyPage1.isEmpty).toBeTruthy();
  1035. expect(newlyCreatedEmptyPage2.isEmpty).toBeTruthy();
  1036. expect(renamedPage.isEmpty).toBeTruthy();
  1037. expect(renamedPageChild.isEmpty).toBe(false);
  1038. });
  1039. test('Rename the path of a non-empty page to its grandchild page path that has an empty parent', async() => {
  1040. const initialPathForPage1 = '/v5_pageForRename21';
  1041. const initialPathForPage2 = '/v5_pageForRename21/v5_pageForRename22';
  1042. const initialPathForPage3 = '/v5_pageForRename21/v5_pageForRename22/v5_pageForRename23';
  1043. const page1 = await Page.findOne({ path: initialPathForPage1, isEmpty: false });
  1044. const page2 = await Page.findOne({ path: initialPathForPage2, isEmpty: true, parent: page1._id });
  1045. const page3 = await Page.findOne({ path: initialPathForPage3, isEmpty: false, parent: page2._id });
  1046. expect(page1).toBeTruthy();
  1047. expect(page2).toBeTruthy();
  1048. expect(page3).toBeTruthy();
  1049. const newParentalPath = '/v5_pageForRename21/v5_pageForRename22/v5_pageForRename23';
  1050. const newPath = newParentalPath + page1.path;
  1051. await renamePage(page1, newPath, dummyUser1, {});
  1052. const renamedPage = await Page.findOne({ path: newParentalPath + initialPathForPage1 });
  1053. const renamedPageChild = await Page.findOne({ path: newParentalPath + initialPathForPage2 });
  1054. const renamedPageGrandchild = await Page.findOne({ path: newParentalPath + initialPathForPage3 });
  1055. const newlyCreatedEmptyPage1 = await Page.findOne({ path: '/v5_pageForRename21' });
  1056. const newlyCreatedEmptyPage2 = await Page.findOne({ path: '/v5_pageForRename21/v5_pageForRename22' });
  1057. const newlyCreatedEmptyPage3 = await Page.findOne({ path: '/v5_pageForRename21/v5_pageForRename22/v5_pageForRename23' });
  1058. expect(renamedPage).toBeTruthy();
  1059. expect(renamedPageChild).toBeTruthy();
  1060. expect(renamedPageGrandchild).toBeTruthy();
  1061. expect(newlyCreatedEmptyPage1).toBeTruthy();
  1062. expect(newlyCreatedEmptyPage2).toBeTruthy();
  1063. expect(newlyCreatedEmptyPage3).toBeTruthy();
  1064. // check parent
  1065. expect(newlyCreatedEmptyPage1.parent).toStrictEqual(rootPage._id);
  1066. expect(newlyCreatedEmptyPage2.parent).toStrictEqual(newlyCreatedEmptyPage1._id);
  1067. expect(newlyCreatedEmptyPage3.parent).toStrictEqual(newlyCreatedEmptyPage2._id);
  1068. expect(renamedPage.parent).toStrictEqual(newlyCreatedEmptyPage3._id);
  1069. expect(renamedPageChild.parent).toStrictEqual(renamedPage._id);
  1070. expect(renamedPageGrandchild.parent).toStrictEqual(renamedPageChild._id);
  1071. // check isEmpty
  1072. expect(newlyCreatedEmptyPage1.isEmpty).toBeTruthy();
  1073. expect(newlyCreatedEmptyPage2.isEmpty).toBeTruthy();
  1074. expect(newlyCreatedEmptyPage3.isEmpty).toBeTruthy();
  1075. expect(renamedPage.isEmpty).toBe(false);
  1076. expect(renamedPageChild.isEmpty).toBeTruthy();
  1077. expect(renamedPageGrandchild.isEmpty).toBe(false);
  1078. });
  1079. });
  1080. describe('Duplicate', () => {
  1081. const duplicate = async(page, newPagePath, user, isRecursively) => {
  1082. // mock return value
  1083. const mockedDuplicateRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'duplicateRecursivelyMainOperation').mockReturnValue(null);
  1084. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1085. const duplicatedPage = await crowi.pageService.duplicate(page, newPagePath, user, isRecursively);
  1086. // retrieve the arguments passed when calling method duplicateRecursivelyMainOperation inside duplicate method
  1087. const argsForDuplicateRecursivelyMainOperation = mockedDuplicateRecursivelyMainOperation.mock.calls[0];
  1088. // restores the original implementation
  1089. mockedDuplicateRecursivelyMainOperation.mockRestore();
  1090. mockedCreateAndSendNotifications.mockRestore();
  1091. // duplicate descendants
  1092. if (isRecursively) {
  1093. await crowi.pageService.duplicateRecursivelyMainOperation(...argsForDuplicateRecursivelyMainOperation);
  1094. }
  1095. return duplicatedPage;
  1096. };
  1097. test('Should duplicate single page', async() => {
  1098. const page = await Page.findOne({ path: '/v5_PageForDuplicate1' });
  1099. expect(page).toBeTruthy();
  1100. const newPagePath = '/duplicatedv5PageForDuplicate1';
  1101. const duplicatedPage = await duplicate(page, newPagePath, dummyUser1, false);
  1102. const duplicatedRevision = await Revision.findOne({ pageId: duplicatedPage._id });
  1103. const baseRevision = await Revision.findOne({ pageId: page._id });
  1104. // new path
  1105. expect(xssSpy).toHaveBeenCalled();
  1106. expect(duplicatedPage.path).toBe(newPagePath);
  1107. expect(duplicatedPage._id).not.toStrictEqual(page._id);
  1108. expect(duplicatedPage.revision).toStrictEqual(duplicatedRevision._id);
  1109. expect(duplicatedRevision.body).toEqual(baseRevision.body);
  1110. });
  1111. test('Should NOT duplicate single empty page', async() => {
  1112. const page = await Page.findOne({ path: '/v5_PageForDuplicate2' });
  1113. expect(page).toBeTruthy();
  1114. let isThrown;
  1115. let duplicatedPage;
  1116. try {
  1117. const newPagePath = '/duplicatedv5PageForDuplicate2';
  1118. duplicatedPage = await duplicate(page, newPagePath, dummyUser1, false);
  1119. }
  1120. catch (err) {
  1121. isThrown = true;
  1122. }
  1123. expect(duplicatedPage).toBeUndefined();
  1124. expect(isThrown).toBe(true);
  1125. });
  1126. test('Should duplicate multiple pages', async() => {
  1127. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate3' });
  1128. const revision = await Revision.findOne({ pageId: basePage._id });
  1129. const childPage1 = await Page.findOne({ path: '/v5_PageForDuplicate3/v5_Child_1_ForDuplicate3' }).populate({ path: 'revision', model: 'Revision' });
  1130. const childPage2 = await Page.findOne({ path: '/v5_PageForDuplicate3/v5_Child_2_ForDuplicate3' }).populate({ path: 'revision', model: 'Revision' });
  1131. const revisionForChild1 = childPage1.revision;
  1132. const revisionForChild2 = childPage2.revision;
  1133. expect(basePage).toBeTruthy();
  1134. expect(revision).toBeTruthy();
  1135. expect(childPage1).toBeTruthy();
  1136. expect(childPage2).toBeTruthy();
  1137. expect(revisionForChild1).toBeTruthy();
  1138. expect(revisionForChild2).toBeTruthy();
  1139. const newPagePath = '/duplicatedv5PageForDuplicate3';
  1140. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, true);
  1141. const duplicatedChildPage1 = await Page.findOne({ parent: duplicatedPage._id, path: '/duplicatedv5PageForDuplicate3/v5_Child_1_ForDuplicate3' })
  1142. .populate({ path: 'revision', model: 'Revision' });
  1143. const duplicatedChildPage2 = await Page.findOne({ parent: duplicatedPage._id, path: '/duplicatedv5PageForDuplicate3/v5_Child_2_ForDuplicate3' })
  1144. .populate({ path: 'revision', model: 'Revision' });
  1145. const revisionForDuplicatedPage = await Revision.findOne({ pageId: duplicatedPage._id });
  1146. const revisionBodyForDupChild1 = duplicatedChildPage1.revision;
  1147. const revisionBodyForDupChild2 = duplicatedChildPage2.revision;
  1148. expect(duplicatedPage).toBeTruthy();
  1149. expect(duplicatedChildPage1).toBeTruthy();
  1150. expect(duplicatedChildPage2).toBeTruthy();
  1151. expect(revisionForDuplicatedPage).toBeTruthy();
  1152. expect(revisionBodyForDupChild1).toBeTruthy();
  1153. expect(revisionBodyForDupChild2).toBeTruthy();
  1154. expect(xssSpy).toHaveBeenCalled();
  1155. expect(duplicatedPage.path).toBe(newPagePath);
  1156. expect(duplicatedChildPage1.path).toBe('/duplicatedv5PageForDuplicate3/v5_Child_1_ForDuplicate3');
  1157. expect(duplicatedChildPage2.path).toBe('/duplicatedv5PageForDuplicate3/v5_Child_2_ForDuplicate3');
  1158. });
  1159. test('Should duplicate multiple pages with empty child in it', async() => {
  1160. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate4' });
  1161. const baseChild = await Page.findOne({ parent: basePage._id, isEmpty: true });
  1162. const baseGrandchild = await Page.findOne({ parent: baseChild._id });
  1163. expect(basePage).toBeTruthy();
  1164. expect(baseChild).toBeTruthy();
  1165. expect(baseGrandchild).toBeTruthy();
  1166. const newPagePath = '/duplicatedv5PageForDuplicate4';
  1167. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, true);
  1168. const duplicatedChild = await Page.findOne({ parent: duplicatedPage._id });
  1169. const duplicatedGrandchild = await Page.findOne({ parent: duplicatedChild._id });
  1170. expect(xssSpy).toHaveBeenCalled();
  1171. expect(duplicatedPage).toBeTruthy();
  1172. expect(duplicatedGrandchild).toBeTruthy();
  1173. expect(duplicatedPage.path).toBe(newPagePath);
  1174. expect(duplicatedChild.path).toBe('/duplicatedv5PageForDuplicate4/v5_empty_PageForDuplicate4');
  1175. expect(duplicatedGrandchild.path).toBe('/duplicatedv5PageForDuplicate4/v5_empty_PageForDuplicate4/v5_grandchild_PageForDuplicate4');
  1176. expect(duplicatedChild.isEmpty).toBe(true);
  1177. expect(duplicatedGrandchild.parent).toStrictEqual(duplicatedChild._id);
  1178. expect(duplicatedChild.parent).toStrictEqual(duplicatedPage._id);
  1179. });
  1180. test('Should duplicate tags', async() => {
  1181. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate5' });
  1182. const tag1 = await Tag.findOne({ name: 'duplicate_Tag1' });
  1183. const tag2 = await Tag.findOne({ name: 'duplicate_Tag2' });
  1184. const basePageTagRelation1 = await PageTagRelation.findOne({ relatedTag: tag1._id });
  1185. const basePageTagRelation2 = await PageTagRelation.findOne({ relatedTag: tag2._id });
  1186. expect(basePage).toBeTruthy();
  1187. expect(tag1).toBeTruthy();
  1188. expect(tag2).toBeTruthy();
  1189. expect(basePageTagRelation1).toBeTruthy();
  1190. expect(basePageTagRelation2).toBeTruthy();
  1191. const newPagePath = '/duplicatedv5PageForDuplicate5';
  1192. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, false);
  1193. const duplicatedTagRelations = await PageTagRelation.find({ relatedPage: duplicatedPage._id });
  1194. expect(xssSpy).toHaveBeenCalled();
  1195. expect(duplicatedPage.path).toBe(newPagePath);
  1196. expect(duplicatedTagRelations.length).toBeGreaterThanOrEqual(2);
  1197. });
  1198. test('Should NOT duplicate comments', async() => {
  1199. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate6' });
  1200. const basePageComments = await Comment.find({ page: basePage._id });
  1201. expect(basePage).toBeTruthy();
  1202. expect(basePageComments.length).toBeGreaterThan(0); // length > 0
  1203. const newPagePath = '/duplicatedv5PageForDuplicate6';
  1204. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, false);
  1205. const duplicatedComments = await Comment.find({ page: duplicatedPage._id });
  1206. expect(xssSpy).toHaveBeenCalled();
  1207. expect(duplicatedPage.path).toBe(newPagePath);
  1208. expect(basePageComments.length).not.toBe(duplicatedComments.length);
  1209. });
  1210. test('Should duplicate empty page with descendants', async() => {
  1211. const basePage = await Page.findOne({ path: '/v5_empty_PageForDuplicate7' });
  1212. const basePageChild = await Page.findOne({ parent: basePage._id }).populate({ path: 'revision', model: 'Revision' });
  1213. const basePageGrandhild = await Page.findOne({ parent: basePageChild._id }).populate({ path: 'revision', model: 'Revision' });
  1214. expect(basePage).toBeTruthy();
  1215. expect(basePageChild).toBeTruthy();
  1216. expect(basePageGrandhild).toBeTruthy();
  1217. expect(basePageChild.revision).toBeTruthy();
  1218. expect(basePageGrandhild.revision).toBeTruthy();
  1219. const newPagePath = '/duplicatedv5EmptyPageForDuplicate7';
  1220. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, true);
  1221. const duplicatedChild = await Page.findOne({ parent: duplicatedPage._id }).populate({ path: 'revision', model: 'Revision' });
  1222. const duplicatedGrandchild = await Page.findOne({ parent: duplicatedChild._id }).populate({ path: 'revision', model: 'Revision' });
  1223. expect(duplicatedPage).toBeTruthy();
  1224. expect(duplicatedChild).toBeTruthy();
  1225. expect(duplicatedGrandchild).toBeTruthy();
  1226. expect(duplicatedChild.revision).toBeTruthy();
  1227. expect(duplicatedGrandchild.revision).toBeTruthy();
  1228. expect(xssSpy).toHaveBeenCalled();
  1229. expect(duplicatedPage.path).toBe(newPagePath);
  1230. expect(duplicatedPage.isEmpty).toBe(true);
  1231. expect(duplicatedChild.revision.body).toBe(basePageChild.revision.body);
  1232. expect(duplicatedGrandchild.revision.body).toBe(basePageGrandhild.revision.body);
  1233. expect(duplicatedChild.path).toBe('/duplicatedv5EmptyPageForDuplicate7/v5_child_PageForDuplicate7');
  1234. expect(duplicatedGrandchild.path).toBe('/duplicatedv5EmptyPageForDuplicate7/v5_child_PageForDuplicate7/v5_grandchild_PageForDuplicate7');
  1235. expect(duplicatedGrandchild.parent).toStrictEqual(duplicatedChild._id);
  1236. expect(duplicatedChild.parent).toStrictEqual(duplicatedPage._id);
  1237. });
  1238. });
  1239. describe('Delete', () => {
  1240. const deletePage = async(page, user, options, isRecursively) => {
  1241. const mockedDeleteRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteRecursivelyMainOperation').mockReturnValue(null);
  1242. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1243. const deletedPage = await crowi.pageService.deletePage(page, user, options, isRecursively);
  1244. const argsForDeleteRecursivelyMainOperation = mockedDeleteRecursivelyMainOperation.mock.calls[0];
  1245. mockedDeleteRecursivelyMainOperation.mockRestore();
  1246. mockedCreateAndSendNotifications.mockRestore();
  1247. if (isRecursively) {
  1248. await crowi.pageService.deleteRecursivelyMainOperation(...argsForDeleteRecursivelyMainOperation);
  1249. }
  1250. return deletedPage;
  1251. };
  1252. test('Should NOT delete root page', async() => {
  1253. let isThrown;
  1254. expect(rootPage).toBeTruthy();
  1255. try { await deletePage(rootPage, dummyUser1, {}, false) }
  1256. catch (err) { isThrown = true }
  1257. const page = await Page.findOne({ path: '/' });
  1258. expect(isThrown).toBe(true);
  1259. expect(page).toBeTruthy();
  1260. });
  1261. test('Should NOT delete trashed page', async() => {
  1262. const trashedPage = await Page.findOne({ path: '/trash/v5_PageForDelete1' });
  1263. expect(trashedPage).toBeTruthy();
  1264. let isThrown;
  1265. try { await deletePage(trashedPage, dummyUser1, {}, false) }
  1266. catch (err) { isThrown = true }
  1267. const page = await Page.findOne({ path: '/trash/v5_PageForDelete1' });
  1268. expect(page).toBeTruthy();
  1269. expect(isThrown).toBe(true);
  1270. });
  1271. test('Should NOT delete /user/hoge page', async() => {
  1272. const dummyUser1Page = await Page.findOne({ path: '/user/v5DummyUser1' });
  1273. expect(dummyUser1Page).toBeTruthy();
  1274. let isThrown;
  1275. try { await deletePage(dummyUser1Page, dummyUser1, {}, false) }
  1276. catch (err) { isThrown = true }
  1277. const page = await Page.findOne({ path: '/user/v5DummyUser1' });
  1278. expect(page).toBeTruthy();
  1279. expect(isThrown).toBe(true);
  1280. });
  1281. test('Should delete single page', async() => {
  1282. const pageToDelete = await Page.findOne({ path: '/v5_PageForDelete2' });
  1283. expect(pageToDelete).toBeTruthy();
  1284. const deletedPage = await deletePage(pageToDelete, dummyUser1, {}, false);
  1285. const page = await Page.findOne({ path: '/v5_PageForDelete2' });
  1286. expect(page).toBeNull();
  1287. expect(deletedPage.path).toBe(`/trash${pageToDelete.path}`);
  1288. expect(deletedPage.parent).toBeNull();
  1289. expect(deletedPage.status).toBe(Page.STATUS_DELETED);
  1290. });
  1291. test('Should delete multiple pages including empty child', async() => {
  1292. const parentPage = await Page.findOne({ path: '/v5_PageForDelete3' });
  1293. const childPage = await Page.findOne({ path: '/v5_PageForDelete3/v5_PageForDelete4' });
  1294. const grandchildPage = await Page.findOne({ path: '/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5' });
  1295. expect(parentPage).toBeTruthy();
  1296. expect(childPage).toBeTruthy();
  1297. expect(grandchildPage).toBeTruthy();
  1298. const deletedParentPage = await deletePage(parentPage, dummyUser1, {}, true);
  1299. const deletedChildPage = await Page.findOne({ path: '/trash/v5_PageForDelete3/v5_PageForDelete4' });
  1300. const deletedGrandchildPage = await Page.findOne({ path: '/trash/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5' });
  1301. // originally NOT empty page should exist with status 'deleted' and parent set null
  1302. expect(deletedParentPage._id).toStrictEqual(parentPage._id);
  1303. expect(deletedParentPage.status).toBe(Page.STATUS_DELETED);
  1304. expect(deletedParentPage.parent).toBeNull();
  1305. // originally empty page should NOT exist
  1306. expect(deletedChildPage).toBeNull();
  1307. // originally NOT empty page should exist with status 'deleted' and parent set null
  1308. expect(deletedGrandchildPage._id).toStrictEqual(grandchildPage._id);
  1309. expect(deletedGrandchildPage.status).toBe(Page.STATUS_DELETED);
  1310. expect(deletedGrandchildPage.parent).toBeNull();
  1311. });
  1312. test('Should delete page tag relation', async() => {
  1313. const pageToDelete = await Page.findOne({ path: '/v5_PageForDelete6' });
  1314. const tag1 = await Tag.findOne({ name: 'TagForDelete1' });
  1315. const tag2 = await Tag.findOne({ name: 'TagForDelete2' });
  1316. const pageRelation1 = await PageTagRelation.findOne({ relatedTag: tag1._id });
  1317. const pageRelation2 = await PageTagRelation.findOne({ relatedTag: tag2._id });
  1318. expect(pageToDelete).toBeTruthy();
  1319. expect(tag1).toBeTruthy();
  1320. expect(tag2).toBeTruthy();
  1321. expect(pageRelation1).toBeTruthy();
  1322. expect(pageRelation2).toBeTruthy();
  1323. const deletedPage = await deletePage(pageToDelete, dummyUser1, {}, false);
  1324. const page = await Page.findOne({ path: '/v5_PageForDelete6' });
  1325. const deletedTagRelation1 = await PageTagRelation.findOne({ _id: pageRelation1._id });
  1326. const deletedTagRelation2 = await PageTagRelation.findOne({ _id: pageRelation2._id });
  1327. expect(page).toBe(null);
  1328. expect(deletedPage.status).toBe(Page.STATUS_DELETED);
  1329. expect(deletedTagRelation1.isPageTrashed).toBe(true);
  1330. expect(deletedTagRelation2.isPageTrashed).toBe(true);
  1331. });
  1332. });
  1333. describe('Delete completely', () => {
  1334. const deleteCompletely = async(page, user, options = {}, isRecursively = false, preventEmitting = false) => {
  1335. const mockedDeleteCompletelyRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteCompletelyRecursivelyMainOperation').mockReturnValue(null);
  1336. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1337. await crowi.pageService.deleteCompletely(page, user, options, isRecursively, preventEmitting);
  1338. const argsForDeleteCompletelyRecursivelyMainOperation = mockedDeleteCompletelyRecursivelyMainOperation.mock.calls[0];
  1339. mockedDeleteCompletelyRecursivelyMainOperation.mockRestore();
  1340. mockedCreateAndSendNotifications.mockRestore();
  1341. if (isRecursively) {
  1342. await crowi.pageService.deleteCompletelyRecursivelyMainOperation(...argsForDeleteCompletelyRecursivelyMainOperation);
  1343. }
  1344. return;
  1345. };
  1346. test('Should NOT completely delete root page', async() => {
  1347. expect(rootPage).toBeTruthy();
  1348. let isThrown;
  1349. try { await deleteCompletely(rootPage, dummyUser1, {}, false) }
  1350. catch (err) { isThrown = true }
  1351. const page = await Page.findOne({ path: '/' });
  1352. expect(page).toBeTruthy();
  1353. expect(isThrown).toBe(true);
  1354. });
  1355. test('Should completely delete single page', async() => {
  1356. const page = await Page.findOne({ path: '/v5_PageForDeleteCompletely1' });
  1357. expect(page).toBeTruthy();
  1358. await deleteCompletely(page, dummyUser1, {}, false);
  1359. const deletedPage = await Page.findOne({ _id: page._id, path: '/v5_PageForDeleteCompletely1' });
  1360. expect(deletedPage).toBeNull();
  1361. });
  1362. test('Should completely delete multiple pages', async() => {
  1363. const parentPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely2' });
  1364. const childPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3' });
  1365. const grandchildPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3/v5_PageForDeleteCompletely4' });
  1366. const tag1 = await Tag.findOne({ name: 'TagForDeleteCompletely1' });
  1367. const tag2 = await Tag.findOne({ name: 'TagForDeleteCompletely2' });
  1368. const pageTagRelation1 = await PageTagRelation.findOne({ relatedPage: parentPage._id });
  1369. const pageTagRelation2 = await PageTagRelation.findOne({ relatedPage: grandchildPage._id });
  1370. const bookmark = await Bookmark.findOne({ page: parentPage._id });
  1371. const comment = await Comment.findOne({ page: parentPage._id });
  1372. const pageRedirect1 = await PageRedirect.findOne({ toPath: parentPage.path });
  1373. const pageRedirect2 = await PageRedirect.findOne({ toPath: grandchildPage.path });
  1374. const shareLink1 = await ShareLink.findOne({ relatedPage: parentPage._id });
  1375. const shareLink2 = await ShareLink.findOne({ relatedPage: grandchildPage._id });
  1376. expect(parentPage).toBeTruthy();
  1377. expect(childPage).toBeTruthy();
  1378. expect(grandchildPage).toBeTruthy();
  1379. expect(tag1).toBeTruthy();
  1380. expect(tag2).toBeTruthy();
  1381. expect(pageTagRelation1).toBeTruthy();
  1382. expect(pageTagRelation2).toBeTruthy();
  1383. expect(bookmark).toBeTruthy();
  1384. expect(comment).toBeTruthy();
  1385. expect(pageRedirect1).toBeTruthy();
  1386. expect(pageRedirect2).toBeTruthy();
  1387. expect(shareLink1).toBeTruthy();
  1388. expect(shareLink2).toBeTruthy();
  1389. await deleteCompletely(parentPage, dummyUser1, {}, true);
  1390. const deletedPages = await Page.find({ _id: { $in: [parentPage._id, childPage._id, grandchildPage._id] } });
  1391. const deletedRevisions = await Revision.find({ pageId: { $in: [parentPage._id, grandchildPage._id] } });
  1392. const tags = await Tag.find({ _id: { $in: [tag1._id, tag2._id] } });
  1393. const deletedPageTagRelations = await PageTagRelation.find({ _id: { $in: [pageTagRelation1._id, pageTagRelation2._id] } });
  1394. const deletedBookmarks = await Bookmark.find({ _id: bookmark._id });
  1395. const deletedComments = await Comment.find({ _id: comment._id });
  1396. const deletedPageRedirects = await PageRedirect.find({ _id: { $in: [pageRedirect1._id, pageRedirect2._id] } });
  1397. const deletedShareLinks = await ShareLink.find({ _id: { $in: [shareLink1._id, shareLink2._id] } });
  1398. // page should be null
  1399. expect(deletedPages.length).toBe(0);
  1400. // revision should be null
  1401. expect(deletedRevisions.length).toBe(0);
  1402. // tag should be Truthy
  1403. expect(tags).toBeTruthy();
  1404. // pageTagRelation should be null
  1405. expect(deletedPageTagRelations.length).toBe(0);
  1406. // bookmark should be null
  1407. expect(deletedBookmarks.length).toBe(0);
  1408. // comment should be null
  1409. expect(deletedComments.length).toBe(0);
  1410. // pageRedirect should be null
  1411. expect(deletedPageRedirects.length).toBe(0);
  1412. // sharelink should be null
  1413. expect(deletedShareLinks.length).toBe(0);
  1414. });
  1415. test('Should completely delete trashed page', async() => {
  1416. const page = await Page.findOne({ path: '/trash/v5_PageForDeleteCompletely5' });
  1417. const revision = await Revision.findOne({ pageId: page._id });
  1418. expect(page).toBeTruthy();
  1419. expect(revision).toBeTruthy();
  1420. await deleteCompletely(page, dummyUser1, {}, false);
  1421. const deltedPage = await Page.findOne({ _id: page._id });
  1422. const deltedRevision = await Revision.findOne({ _id: revision._id });
  1423. expect(deltedPage).toBeNull();
  1424. expect(deltedRevision).toBeNull();
  1425. });
  1426. test('Should completely deleting page in the middle results in having an empty page', async() => {
  1427. const parentPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely6' });
  1428. const childPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7' });
  1429. const grandchildPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7/v5_PageForDeleteCompletely8' });
  1430. expect(parentPage).toBeTruthy();
  1431. expect(childPage).toBeTruthy();
  1432. expect(grandchildPage).toBeTruthy();
  1433. await deleteCompletely(childPage, dummyUser1, {}, false);
  1434. const parentPageAfterDelete = await Page.findOne({ path: '/v5_PageForDeleteCompletely6' });
  1435. const childPageAfterDelete = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7' });
  1436. const grandchildPageAfterDelete = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7/v5_PageForDeleteCompletely8' });
  1437. const childOfDeletedPage = await Page.findOne({ parent: childPageAfterDelete._id });
  1438. expect(parentPageAfterDelete).toBeTruthy();
  1439. expect(childPageAfterDelete).toBeTruthy();
  1440. expect(grandchildPageAfterDelete).toBeTruthy();
  1441. expect(childPageAfterDelete._id).not.toStrictEqual(childPage._id);
  1442. expect(childPageAfterDelete.isEmpty).toBe(true);
  1443. expect(childPageAfterDelete.parent).toStrictEqual(parentPage._id);
  1444. expect(childOfDeletedPage._id).toStrictEqual(grandchildPage._id);
  1445. });
  1446. });
  1447. describe('revert', () => {
  1448. const revertDeletedPage = async(page, user, options = {}, isRecursively = false) => {
  1449. // mock return value
  1450. const mockedRevertRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'revertRecursivelyMainOperation').mockReturnValue(null);
  1451. const revertedPage = await crowi.pageService.revertDeletedPage(page, user, options, isRecursively);
  1452. const argsForRecursivelyMainOperation = mockedRevertRecursivelyMainOperation.mock.calls[0];
  1453. // restores the original implementation
  1454. mockedRevertRecursivelyMainOperation.mockRestore();
  1455. if (isRecursively) {
  1456. await crowi.pageService.revertRecursivelyMainOperation(...argsForRecursivelyMainOperation);
  1457. }
  1458. return revertedPage;
  1459. };
  1460. test('revert single deleted page', async() => {
  1461. const deletedPage = await Page.findOne({ path: '/trash/v5_revert1', status: Page.STATUS_DELETED });
  1462. const revision = await Revision.findOne({ pageId: deletedPage._id });
  1463. const tag = await Tag.findOne({ name: 'revertTag1' });
  1464. const deletedPageTagRelation = await PageTagRelation.findOne({ relatedPage: deletedPage._id, relatedTag: tag._id, isPageTrashed: true });
  1465. expect(deletedPage).toBeTruthy();
  1466. expect(revision).toBeTruthy();
  1467. expect(tag).toBeTruthy();
  1468. expect(deletedPageTagRelation).toBeTruthy();
  1469. const revertedPage = await revertDeletedPage(deletedPage, dummyUser1, {}, false);
  1470. const pageTagRelation = await PageTagRelation.findOne({ relatedPage: deletedPage._id, relatedTag: tag._id });
  1471. expect(revertedPage.parent).toStrictEqual(rootPage._id);
  1472. expect(revertedPage.path).toBe('/v5_revert1');
  1473. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1474. expect(pageTagRelation.isPageTrashed).toBe(false);
  1475. });
  1476. test('revert multiple deleted page (has non existent page in the middle)', async() => {
  1477. const deletedPage1 = await Page.findOne({ path: '/trash/v5_revert2', status: Page.STATUS_DELETED });
  1478. const deletedPage2 = await Page.findOne({ path: '/trash/v5_revert2/v5_revert3/v5_revert4', status: Page.STATUS_DELETED });
  1479. const revision1 = await Revision.findOne({ pageId: deletedPage1._id });
  1480. const revision2 = await Revision.findOne({ pageId: deletedPage2._id });
  1481. expect(deletedPage1).toBeTruthy();
  1482. expect(deletedPage2).toBeTruthy();
  1483. expect(revision1).toBeTruthy();
  1484. expect(revision2).toBeTruthy();
  1485. const revertedPage1 = await revertDeletedPage(deletedPage1, dummyUser1, {}, true);
  1486. const revertedPage2 = await Page.findOne({ _id: deletedPage2._id });
  1487. const newlyCreatedPage = await Page.findOne({ path: '/v5_revert2/v5_revert3' });
  1488. expect(revertedPage1).toBeTruthy();
  1489. expect(revertedPage2).toBeTruthy();
  1490. expect(newlyCreatedPage).toBeTruthy();
  1491. expect(revertedPage1.parent).toStrictEqual(rootPage._id);
  1492. expect(revertedPage1.path).toBe('/v5_revert2');
  1493. expect(revertedPage2.path).toBe('/v5_revert2/v5_revert3/v5_revert4');
  1494. expect(newlyCreatedPage.parent).toStrictEqual(revertedPage1._id);
  1495. expect(revertedPage2.parent).toStrictEqual(newlyCreatedPage._id);
  1496. expect(revertedPage1.status).toBe(Page.STATUS_PUBLISHED);
  1497. expect(revertedPage2.status).toBe(Page.STATUS_PUBLISHED);
  1498. expect(newlyCreatedPage.status).toBe(Page.STATUS_PUBLISHED);
  1499. });
  1500. });
  1501. });