v5.public-page.test.ts 65 KB

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