v5.page.test.ts 64 KB

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