v5.public-page.test.ts 64 KB

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