v5.public-page.test.ts 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679
  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 mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  847. const renamedPage = await crowi.pageService.renamePage(page, newPagePath, user, options);
  848. // retrieve the arguments passed when calling method renameSubOperation inside renamePage method
  849. const argsForRenameSubOperation = mockedRenameSubOperation.mock.calls[0];
  850. // restores the original implementation
  851. mockedRenameSubOperation.mockRestore();
  852. mockedCreateAndSendNotifications.mockRestore();
  853. // rename descendants
  854. await crowi.pageService.renameSubOperation(...argsForRenameSubOperation);
  855. return renamedPage;
  856. };
  857. test('Should NOT rename top page', async() => {
  858. expect(rootPage).toBeTruthy();
  859. let isThrown = false;
  860. try {
  861. await crowi.pageService.renamePage(rootPage, '/new_root', dummyUser1, {});
  862. }
  863. catch (err) {
  864. isThrown = true;
  865. }
  866. expect(isThrown).toBe(true);
  867. });
  868. test('Should rename/move to under non-empty page', async() => {
  869. const parentPage = await Page.findOne({ path: '/v5_ParentForRename1' });
  870. const childPage = await Page.findOne({ path: '/v5_ChildForRename1' });
  871. expect(childPage).toBeTruthy();
  872. expect(parentPage).toBeTruthy();
  873. const newPath = '/v5_ParentForRename1/renamedChildForRename1';
  874. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  875. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename1' });
  876. expect(xssSpy).toHaveBeenCalled();
  877. expect(renamedPage.path).toBe(newPath);
  878. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  879. expect(childPageBeforeRename).toBeNull();
  880. });
  881. test('Should rename/move to under empty page', async() => {
  882. const parentPage = await Page.findOne({ path: '/v5_ParentForRename2' });
  883. const childPage = await Page.findOne({ path: '/v5_ChildForRename2' });
  884. expect(childPage).toBeTruthy();
  885. expect(parentPage).toBeTruthy();
  886. expect(parentPage.isEmpty).toBe(true);
  887. const newPath = '/v5_ParentForRename2/renamedChildForRename2';
  888. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  889. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename2' });
  890. expect(xssSpy).toHaveBeenCalled();
  891. expect(renamedPage.path).toBe(newPath);
  892. expect(parentPage.isEmpty).toBe(true);
  893. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  894. expect(childPageBeforeRename).toBeNull();
  895. });
  896. test('Should rename/move with option updateMetadata: true', async() => {
  897. const parentPage = await Page.findOne({ path: '/v5_ParentForRename3' });
  898. const childPage = await Page.findOne({ path: '/v5_ChildForRename3' });
  899. expect(childPage).toBeTruthy();
  900. expect(parentPage).toBeTruthy();
  901. expect(childPage.lastUpdateUser).toStrictEqual(dummyUser1._id);
  902. const newPath = '/v5_ParentForRename3/renamedChildForRename3';
  903. const oldUpdateAt = childPage.updatedAt;
  904. const renamedPage = await renamePage(childPage, newPath, dummyUser2, { updateMetadata: true });
  905. expect(xssSpy).toHaveBeenCalled();
  906. expect(renamedPage.path).toBe(newPath);
  907. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  908. expect(renamedPage.lastUpdateUser).toStrictEqual(dummyUser2._id);
  909. expect(renamedPage.updatedAt.getFullYear()).toBeGreaterThan(oldUpdateAt.getFullYear());
  910. });
  911. test('Should move with option createRedirectPage: true', async() => {
  912. const parentPage = await Page.findOne({ path: '/v5_ParentForRename4' });
  913. const childPage = await Page.findOne({ path: '/v5_ChildForRename4' });
  914. expect(parentPage).toBeTruthy();
  915. expect(childPage).toBeTruthy();
  916. const oldPath = childPage.path;
  917. const newPath = '/v5_ParentForRename4/renamedChildForRename4';
  918. const renamedPage = await renamePage(childPage, newPath, dummyUser2, { createRedirectPage: true });
  919. const pageRedirect = await PageRedirect.findOne({ fromPath: oldPath, toPath: renamedPage.path });
  920. expect(xssSpy).toHaveBeenCalled();
  921. expect(renamedPage.path).toBe(newPath);
  922. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  923. expect(pageRedirect).toBeTruthy();
  924. });
  925. test('Should rename/move with descendants', async() => {
  926. const parentPage = await Page.findOne({ path: '/v5_ParentForRename5' });
  927. const childPage = await Page.findOne({ path: '/v5_ChildForRename5' });
  928. const grandchild = await Page.findOne({ parent: childPage._id, path: '/v5_ChildForRename5/v5_GrandchildForRename5' });
  929. expect(parentPage).toBeTruthy();
  930. expect(childPage).toBeTruthy();
  931. expect(grandchild).toBeTruthy();
  932. const newPath = '/v5_ParentForRename5/renamedChildForRename5';
  933. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  934. // find child of renamed page
  935. const renamedGrandchild = await Page.findOne({ parent: renamedPage._id });
  936. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename5' });
  937. const grandchildBeforeRename = await Page.findOne({ path: grandchild.path });
  938. expect(xssSpy).toHaveBeenCalled();
  939. expect(renamedPage.path).toBe(newPath);
  940. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  941. expect(childPageBeforeRename).toBeNull();
  942. expect(grandchildBeforeRename).toBeNull();
  943. // grandchild's parent should be the renamed page
  944. expect(renamedGrandchild.parent).toStrictEqual(renamedPage._id);
  945. expect(renamedGrandchild.path).toBe('/v5_ParentForRename5/renamedChildForRename5/v5_GrandchildForRename5');
  946. });
  947. test('Should rename/move empty page', async() => {
  948. const parentPage = await Page.findOne({ path: '/v5_ParentForRename7' });
  949. const childPage = await Page.findOne({ path: '/v5_ChildForRename7', isEmpty: true });
  950. const grandchild = await Page.findOne({ parent: childPage._id, path: '/v5_ChildForRename7/v5_GrandchildForRename7' });
  951. expect(parentPage).toBeTruthy();
  952. expect(childPage).toBeTruthy();
  953. expect(grandchild).toBeTruthy();
  954. const newPath = '/v5_ParentForRename7/renamedChildForRename7';
  955. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  956. const grandchildAfterRename = await Page.findOne({ parent: renamedPage._id });
  957. const grandchildBeforeRename = await Page.findOne({ path: '/v5_ChildForRename7/v5_GrandchildForRename7' });
  958. expect(xssSpy).toHaveBeenCalled();
  959. expect(renamedPage.path).toBe(newPath);
  960. expect(renamedPage.isEmpty).toBe(true);
  961. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  962. expect(grandchildBeforeRename).toBeNull();
  963. // grandchild's parent should be renamed page
  964. expect(grandchildAfterRename.parent).toStrictEqual(renamedPage._id);
  965. expect(grandchildAfterRename.path).toBe('/v5_ParentForRename7/renamedChildForRename7/v5_GrandchildForRename7');
  966. });
  967. test('Should NOT rename/move with existing path', async() => {
  968. const page = await Page.findOne({ path: '/v5_ParentForRename8' });
  969. expect(page).toBeTruthy();
  970. const newPath = '/v5_ParentForRename9';
  971. let isThrown;
  972. try {
  973. await renamePage(page, newPath, dummyUser1, {});
  974. }
  975. catch (err) {
  976. isThrown = true;
  977. }
  978. expect(isThrown).toBe(true);
  979. });
  980. test('Rename non-empty page path to its descendant non-empty page path', async() => {
  981. const initialPathForPage1 = '/v5_pageForRename17';
  982. const initialPathForPage2 = '/v5_pageForRename17/v5_pageForRename18';
  983. const page1 = await Page.findOne({ path: initialPathForPage1, isEmpty: false });
  984. const page2 = await Page.findOne({ path: initialPathForPage2, isEmpty: false, parent: page1._id });
  985. expect(page1).toBeTruthy();
  986. expect(page2).toBeTruthy();
  987. const newParentalPath = '/v5_pageForRename17/v5_pageForRename18';
  988. const newPath = newParentalPath + page1.path;
  989. await renamePage(page1, newPath, dummyUser1, {});
  990. const renamedPage = await Page.findOne({ path: newParentalPath + initialPathForPage1 });
  991. const renamedPageChild = await Page.findOne({ path: newParentalPath + initialPathForPage2 });
  992. const newlyCreatedEmptyPage1 = await Page.findOne({ path: '/v5_pageForRename17' });
  993. const newlyCreatedEmptyPage2 = await Page.findOne({ path: '/v5_pageForRename17/v5_pageForRename18' });
  994. expect(renamedPage).toBeTruthy();
  995. expect(renamedPageChild).toBeTruthy();
  996. expect(newlyCreatedEmptyPage1).toBeTruthy();
  997. expect(newlyCreatedEmptyPage2).toBeTruthy();
  998. // check parent
  999. expect(newlyCreatedEmptyPage1.parent).toStrictEqual(rootPage._id);
  1000. expect(newlyCreatedEmptyPage2.parent).toStrictEqual(newlyCreatedEmptyPage1._id);
  1001. expect(renamedPage.parent).toStrictEqual(newlyCreatedEmptyPage2._id);
  1002. expect(renamedPageChild.parent).toStrictEqual(renamedPage._id);
  1003. // check isEmpty
  1004. expect(newlyCreatedEmptyPage1.isEmpty).toBeTruthy();
  1005. expect(newlyCreatedEmptyPage2.isEmpty).toBeTruthy();
  1006. expect(renamedPage.isEmpty).toBe(false);
  1007. expect(renamedPageChild.isEmpty).toBe(false);
  1008. });
  1009. test('Rename empty page path to its descendant non-empty page path', async() => {
  1010. const initialPathForPage1 = '/v5_pageForRename19';
  1011. const initialPathForPage2 = '/v5_pageForRename19/v5_pageForRename20';
  1012. const page1 = await Page.findOne({ path: initialPathForPage1, isEmpty: true });
  1013. const page2 = await Page.findOne({ path: initialPathForPage2, isEmpty: false, parent: page1._id });
  1014. expect(page1).toBeTruthy();
  1015. expect(page2).toBeTruthy();
  1016. const newParentalPath = '/v5_pageForRename19/v5_pageForRename20';
  1017. const newPath = newParentalPath + page1.path;
  1018. await renamePage(page1, newPath, dummyUser1, {});
  1019. const renamedPage = await Page.findOne({ path: newParentalPath + initialPathForPage1 });
  1020. const renamedPageChild = await Page.findOne({ path: newParentalPath + initialPathForPage2 });
  1021. const newlyCreatedEmptyPage1 = await Page.findOne({ path: '/v5_pageForRename19' });
  1022. const newlyCreatedEmptyPage2 = await Page.findOne({ path: '/v5_pageForRename19/v5_pageForRename20' });
  1023. expect(renamedPage).toBeTruthy();
  1024. expect(renamedPageChild).toBeTruthy();
  1025. expect(newlyCreatedEmptyPage1).toBeTruthy();
  1026. expect(newlyCreatedEmptyPage2).toBeTruthy();
  1027. // check parent
  1028. expect(newlyCreatedEmptyPage1.parent).toStrictEqual(rootPage._id);
  1029. expect(newlyCreatedEmptyPage2.parent).toStrictEqual(newlyCreatedEmptyPage1._id);
  1030. expect(renamedPage.parent).toStrictEqual(newlyCreatedEmptyPage2._id);
  1031. expect(renamedPageChild.parent).toStrictEqual(renamedPage._id);
  1032. // check isEmpty
  1033. expect(newlyCreatedEmptyPage1.isEmpty).toBeTruthy();
  1034. expect(newlyCreatedEmptyPage2.isEmpty).toBeTruthy();
  1035. expect(renamedPage.isEmpty).toBeTruthy();
  1036. expect(renamedPageChild.isEmpty).toBe(false);
  1037. });
  1038. test('Rename the path of a non-empty page to its grandchild page path that has an empty parent', async() => {
  1039. const initialPathForPage1 = '/v5_pageForRename21';
  1040. const initialPathForPage2 = '/v5_pageForRename21/v5_pageForRename22';
  1041. const initialPathForPage3 = '/v5_pageForRename21/v5_pageForRename22/v5_pageForRename23';
  1042. const page1 = await Page.findOne({ path: initialPathForPage1, isEmpty: false });
  1043. const page2 = await Page.findOne({ path: initialPathForPage2, isEmpty: true, parent: page1._id });
  1044. const page3 = await Page.findOne({ path: initialPathForPage3, isEmpty: false, parent: page2._id });
  1045. expect(page1).toBeTruthy();
  1046. expect(page2).toBeTruthy();
  1047. expect(page3).toBeTruthy();
  1048. const newParentalPath = '/v5_pageForRename21/v5_pageForRename22/v5_pageForRename23';
  1049. const newPath = newParentalPath + page1.path;
  1050. await renamePage(page1, newPath, dummyUser1, {});
  1051. const renamedPage = await Page.findOne({ path: newParentalPath + initialPathForPage1 });
  1052. const renamedPageChild = await Page.findOne({ path: newParentalPath + initialPathForPage2 });
  1053. const renamedPageGrandchild = await Page.findOne({ path: newParentalPath + initialPathForPage3 });
  1054. const newlyCreatedEmptyPage1 = await Page.findOne({ path: '/v5_pageForRename21' });
  1055. const newlyCreatedEmptyPage2 = await Page.findOne({ path: '/v5_pageForRename21/v5_pageForRename22' });
  1056. const newlyCreatedEmptyPage3 = await Page.findOne({ path: '/v5_pageForRename21/v5_pageForRename22/v5_pageForRename23' });
  1057. expect(renamedPage).toBeTruthy();
  1058. expect(renamedPageChild).toBeTruthy();
  1059. expect(renamedPageGrandchild).toBeTruthy();
  1060. expect(newlyCreatedEmptyPage1).toBeTruthy();
  1061. expect(newlyCreatedEmptyPage2).toBeTruthy();
  1062. expect(newlyCreatedEmptyPage3).toBeTruthy();
  1063. // check parent
  1064. expect(newlyCreatedEmptyPage1.parent).toStrictEqual(rootPage._id);
  1065. expect(newlyCreatedEmptyPage2.parent).toStrictEqual(newlyCreatedEmptyPage1._id);
  1066. expect(newlyCreatedEmptyPage3.parent).toStrictEqual(newlyCreatedEmptyPage2._id);
  1067. expect(renamedPage.parent).toStrictEqual(newlyCreatedEmptyPage3._id);
  1068. expect(renamedPageChild.parent).toStrictEqual(renamedPage._id);
  1069. expect(renamedPageGrandchild.parent).toStrictEqual(renamedPageChild._id);
  1070. // check isEmpty
  1071. expect(newlyCreatedEmptyPage1.isEmpty).toBeTruthy();
  1072. expect(newlyCreatedEmptyPage2.isEmpty).toBeTruthy();
  1073. expect(newlyCreatedEmptyPage3.isEmpty).toBeTruthy();
  1074. expect(renamedPage.isEmpty).toBe(false);
  1075. expect(renamedPageChild.isEmpty).toBeTruthy();
  1076. expect(renamedPageGrandchild.isEmpty).toBe(false);
  1077. });
  1078. });
  1079. describe('Duplicate', () => {
  1080. const duplicate = async(page, newPagePath, user, isRecursively) => {
  1081. // mock return value
  1082. const mockedDuplicateRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'duplicateRecursivelyMainOperation').mockReturnValue(null);
  1083. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1084. const duplicatedPage = await crowi.pageService.duplicate(page, newPagePath, user, isRecursively);
  1085. // retrieve the arguments passed when calling method duplicateRecursivelyMainOperation inside duplicate method
  1086. const argsForDuplicateRecursivelyMainOperation = mockedDuplicateRecursivelyMainOperation.mock.calls[0];
  1087. // restores the original implementation
  1088. mockedDuplicateRecursivelyMainOperation.mockRestore();
  1089. mockedCreateAndSendNotifications.mockRestore();
  1090. // duplicate descendants
  1091. if (isRecursively) {
  1092. await crowi.pageService.duplicateRecursivelyMainOperation(...argsForDuplicateRecursivelyMainOperation);
  1093. }
  1094. return duplicatedPage;
  1095. };
  1096. test('Should duplicate single page', async() => {
  1097. const page = await Page.findOne({ path: '/v5_PageForDuplicate1' });
  1098. expect(page).toBeTruthy();
  1099. const newPagePath = '/duplicatedv5PageForDuplicate1';
  1100. const duplicatedPage = await duplicate(page, newPagePath, dummyUser1, false);
  1101. const duplicatedRevision = await Revision.findOne({ pageId: duplicatedPage._id });
  1102. const baseRevision = await Revision.findOne({ pageId: page._id });
  1103. // new path
  1104. expect(xssSpy).toHaveBeenCalled();
  1105. expect(duplicatedPage.path).toBe(newPagePath);
  1106. expect(duplicatedPage._id).not.toStrictEqual(page._id);
  1107. expect(duplicatedPage.revision).toStrictEqual(duplicatedRevision._id);
  1108. expect(duplicatedRevision.body).toEqual(baseRevision.body);
  1109. });
  1110. test('Should NOT duplicate single empty page', async() => {
  1111. const page = await Page.findOne({ path: '/v5_PageForDuplicate2' });
  1112. expect(page).toBeTruthy();
  1113. let isThrown;
  1114. let duplicatedPage;
  1115. try {
  1116. const newPagePath = '/duplicatedv5PageForDuplicate2';
  1117. duplicatedPage = await duplicate(page, newPagePath, dummyUser1, false);
  1118. }
  1119. catch (err) {
  1120. isThrown = true;
  1121. }
  1122. expect(duplicatedPage).toBeUndefined();
  1123. expect(isThrown).toBe(true);
  1124. });
  1125. test('Should duplicate multiple pages', async() => {
  1126. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate3' });
  1127. const revision = await Revision.findOne({ pageId: basePage._id });
  1128. const childPage1 = await Page.findOne({ path: '/v5_PageForDuplicate3/v5_Child_1_ForDuplicate3' }).populate({ path: 'revision', model: 'Revision' });
  1129. const childPage2 = await Page.findOne({ path: '/v5_PageForDuplicate3/v5_Child_2_ForDuplicate3' }).populate({ path: 'revision', model: 'Revision' });
  1130. const revisionForChild1 = childPage1.revision;
  1131. const revisionForChild2 = childPage2.revision;
  1132. expect(basePage).toBeTruthy();
  1133. expect(revision).toBeTruthy();
  1134. expect(childPage1).toBeTruthy();
  1135. expect(childPage2).toBeTruthy();
  1136. expect(revisionForChild1).toBeTruthy();
  1137. expect(revisionForChild2).toBeTruthy();
  1138. const newPagePath = '/duplicatedv5PageForDuplicate3';
  1139. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, true);
  1140. const duplicatedChildPage1 = await Page.findOne({ parent: duplicatedPage._id, path: '/duplicatedv5PageForDuplicate3/v5_Child_1_ForDuplicate3' })
  1141. .populate({ path: 'revision', model: 'Revision' });
  1142. const duplicatedChildPage2 = await Page.findOne({ parent: duplicatedPage._id, path: '/duplicatedv5PageForDuplicate3/v5_Child_2_ForDuplicate3' })
  1143. .populate({ path: 'revision', model: 'Revision' });
  1144. const revisionForDuplicatedPage = await Revision.findOne({ pageId: duplicatedPage._id });
  1145. const revisionBodyForDupChild1 = duplicatedChildPage1.revision;
  1146. const revisionBodyForDupChild2 = duplicatedChildPage2.revision;
  1147. expect(duplicatedPage).toBeTruthy();
  1148. expect(duplicatedChildPage1).toBeTruthy();
  1149. expect(duplicatedChildPage2).toBeTruthy();
  1150. expect(revisionForDuplicatedPage).toBeTruthy();
  1151. expect(revisionBodyForDupChild1).toBeTruthy();
  1152. expect(revisionBodyForDupChild2).toBeTruthy();
  1153. expect(xssSpy).toHaveBeenCalled();
  1154. expect(duplicatedPage.path).toBe(newPagePath);
  1155. expect(duplicatedChildPage1.path).toBe('/duplicatedv5PageForDuplicate3/v5_Child_1_ForDuplicate3');
  1156. expect(duplicatedChildPage2.path).toBe('/duplicatedv5PageForDuplicate3/v5_Child_2_ForDuplicate3');
  1157. });
  1158. test('Should duplicate multiple pages with empty child in it', async() => {
  1159. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate4' });
  1160. const baseChild = await Page.findOne({ parent: basePage._id, isEmpty: true });
  1161. const baseGrandchild = await Page.findOne({ parent: baseChild._id });
  1162. expect(basePage).toBeTruthy();
  1163. expect(baseChild).toBeTruthy();
  1164. expect(baseGrandchild).toBeTruthy();
  1165. const newPagePath = '/duplicatedv5PageForDuplicate4';
  1166. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, true);
  1167. const duplicatedChild = await Page.findOne({ parent: duplicatedPage._id });
  1168. const duplicatedGrandchild = await Page.findOne({ parent: duplicatedChild._id });
  1169. expect(xssSpy).toHaveBeenCalled();
  1170. expect(duplicatedPage).toBeTruthy();
  1171. expect(duplicatedGrandchild).toBeTruthy();
  1172. expect(duplicatedPage.path).toBe(newPagePath);
  1173. expect(duplicatedChild.path).toBe('/duplicatedv5PageForDuplicate4/v5_empty_PageForDuplicate4');
  1174. expect(duplicatedGrandchild.path).toBe('/duplicatedv5PageForDuplicate4/v5_empty_PageForDuplicate4/v5_grandchild_PageForDuplicate4');
  1175. expect(duplicatedChild.isEmpty).toBe(true);
  1176. expect(duplicatedGrandchild.parent).toStrictEqual(duplicatedChild._id);
  1177. expect(duplicatedChild.parent).toStrictEqual(duplicatedPage._id);
  1178. });
  1179. test('Should duplicate tags', async() => {
  1180. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate5' });
  1181. const tag1 = await Tag.findOne({ name: 'duplicate_Tag1' });
  1182. const tag2 = await Tag.findOne({ name: 'duplicate_Tag2' });
  1183. const basePageTagRelation1 = await PageTagRelation.findOne({ relatedTag: tag1?._id });
  1184. const basePageTagRelation2 = await PageTagRelation.findOne({ relatedTag: tag2?._id });
  1185. expect(basePage).toBeTruthy();
  1186. expect(tag1).toBeTruthy();
  1187. expect(tag2).toBeTruthy();
  1188. expect(basePageTagRelation1).toBeTruthy();
  1189. expect(basePageTagRelation2).toBeTruthy();
  1190. const newPagePath = '/duplicatedv5PageForDuplicate5';
  1191. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, false);
  1192. const duplicatedTagRelations = await PageTagRelation.find({ relatedPage: duplicatedPage._id });
  1193. expect(xssSpy).toHaveBeenCalled();
  1194. expect(duplicatedPage.path).toBe(newPagePath);
  1195. expect(duplicatedTagRelations.length).toBeGreaterThanOrEqual(2);
  1196. });
  1197. test('Should NOT duplicate comments', async() => {
  1198. const basePage = await Page.findOne({ path: '/v5_PageForDuplicate6' });
  1199. const basePageComments = await Comment.find({ page: basePage._id });
  1200. expect(basePage).toBeTruthy();
  1201. expect(basePageComments.length).toBeGreaterThan(0); // length > 0
  1202. const newPagePath = '/duplicatedv5PageForDuplicate6';
  1203. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, false);
  1204. const duplicatedComments = await Comment.find({ page: duplicatedPage._id });
  1205. expect(xssSpy).toHaveBeenCalled();
  1206. expect(duplicatedPage.path).toBe(newPagePath);
  1207. expect(basePageComments.length).not.toBe(duplicatedComments.length);
  1208. });
  1209. test('Should duplicate empty page with descendants', async() => {
  1210. const basePage = await Page.findOne({ path: '/v5_empty_PageForDuplicate7' });
  1211. const basePageChild = await Page.findOne({ parent: basePage._id }).populate({ path: 'revision', model: 'Revision' });
  1212. const basePageGrandhild = await Page.findOne({ parent: basePageChild._id }).populate({ path: 'revision', model: 'Revision' });
  1213. expect(basePage).toBeTruthy();
  1214. expect(basePageChild).toBeTruthy();
  1215. expect(basePageGrandhild).toBeTruthy();
  1216. expect(basePageChild.revision).toBeTruthy();
  1217. expect(basePageGrandhild.revision).toBeTruthy();
  1218. const newPagePath = '/duplicatedv5EmptyPageForDuplicate7';
  1219. const duplicatedPage = await duplicate(basePage, newPagePath, dummyUser1, true);
  1220. const duplicatedChild = await Page.findOne({ parent: duplicatedPage._id }).populate({ path: 'revision', model: 'Revision' });
  1221. const duplicatedGrandchild = await Page.findOne({ parent: duplicatedChild._id }).populate({ path: 'revision', model: 'Revision' });
  1222. expect(duplicatedPage).toBeTruthy();
  1223. expect(duplicatedChild).toBeTruthy();
  1224. expect(duplicatedGrandchild).toBeTruthy();
  1225. expect(duplicatedChild.revision).toBeTruthy();
  1226. expect(duplicatedGrandchild.revision).toBeTruthy();
  1227. expect(xssSpy).toHaveBeenCalled();
  1228. expect(duplicatedPage.path).toBe(newPagePath);
  1229. expect(duplicatedPage.isEmpty).toBe(true);
  1230. expect(duplicatedChild.revision.body).toBe(basePageChild.revision.body);
  1231. expect(duplicatedGrandchild.revision.body).toBe(basePageGrandhild.revision.body);
  1232. expect(duplicatedChild.path).toBe('/duplicatedv5EmptyPageForDuplicate7/v5_child_PageForDuplicate7');
  1233. expect(duplicatedGrandchild.path).toBe('/duplicatedv5EmptyPageForDuplicate7/v5_child_PageForDuplicate7/v5_grandchild_PageForDuplicate7');
  1234. expect(duplicatedGrandchild.parent).toStrictEqual(duplicatedChild._id);
  1235. expect(duplicatedChild.parent).toStrictEqual(duplicatedPage._id);
  1236. });
  1237. });
  1238. describe('Delete', () => {
  1239. const deletePage = async(page, user, options, isRecursively) => {
  1240. const mockedDeleteRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteRecursivelyMainOperation').mockReturnValue(null);
  1241. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1242. const deletedPage = await crowi.pageService.deletePage(page, user, options, isRecursively);
  1243. const argsForDeleteRecursivelyMainOperation = mockedDeleteRecursivelyMainOperation.mock.calls[0];
  1244. mockedDeleteRecursivelyMainOperation.mockRestore();
  1245. mockedCreateAndSendNotifications.mockRestore();
  1246. if (isRecursively) {
  1247. await crowi.pageService.deleteRecursivelyMainOperation(...argsForDeleteRecursivelyMainOperation);
  1248. }
  1249. return deletedPage;
  1250. };
  1251. test('Should NOT delete root page', async() => {
  1252. let isThrown;
  1253. expect(rootPage).toBeTruthy();
  1254. try { await deletePage(rootPage, dummyUser1, {}, false) }
  1255. catch (err) { isThrown = true }
  1256. const page = await Page.findOne({ path: '/' });
  1257. expect(isThrown).toBe(true);
  1258. expect(page).toBeTruthy();
  1259. });
  1260. test('Should NOT delete trashed page', async() => {
  1261. const trashedPage = await Page.findOne({ path: '/trash/v5_PageForDelete1' });
  1262. expect(trashedPage).toBeTruthy();
  1263. let isThrown;
  1264. try { await deletePage(trashedPage, dummyUser1, {}, false) }
  1265. catch (err) { isThrown = true }
  1266. const page = await Page.findOne({ path: '/trash/v5_PageForDelete1' });
  1267. expect(page).toBeTruthy();
  1268. expect(isThrown).toBe(true);
  1269. });
  1270. test('Should NOT delete /user/hoge page', async() => {
  1271. const dummyUser1Page = await Page.findOne({ path: '/user/v5DummyUser1' });
  1272. expect(dummyUser1Page).toBeTruthy();
  1273. let isThrown;
  1274. try { await deletePage(dummyUser1Page, dummyUser1, {}, false) }
  1275. catch (err) { isThrown = true }
  1276. const page = await Page.findOne({ path: '/user/v5DummyUser1' });
  1277. expect(page).toBeTruthy();
  1278. expect(isThrown).toBe(true);
  1279. });
  1280. test('Should delete single page', async() => {
  1281. const pageToDelete = await Page.findOne({ path: '/v5_PageForDelete2' });
  1282. expect(pageToDelete).toBeTruthy();
  1283. const deletedPage = await deletePage(pageToDelete, dummyUser1, {}, false);
  1284. const page = await Page.findOne({ path: '/v5_PageForDelete2' });
  1285. expect(page).toBeNull();
  1286. expect(deletedPage.path).toBe(`/trash${pageToDelete.path}`);
  1287. expect(deletedPage.parent).toBeNull();
  1288. expect(deletedPage.status).toBe(Page.STATUS_DELETED);
  1289. });
  1290. test('Should delete multiple pages including empty child', async() => {
  1291. const parentPage = await Page.findOne({ path: '/v5_PageForDelete3' });
  1292. const childPage = await Page.findOne({ path: '/v5_PageForDelete3/v5_PageForDelete4' });
  1293. const grandchildPage = await Page.findOne({ path: '/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5' });
  1294. expect(parentPage).toBeTruthy();
  1295. expect(childPage).toBeTruthy();
  1296. expect(grandchildPage).toBeTruthy();
  1297. const deletedParentPage = await deletePage(parentPage, dummyUser1, {}, true);
  1298. const deletedChildPage = await Page.findOne({ path: '/trash/v5_PageForDelete3/v5_PageForDelete4' });
  1299. const deletedGrandchildPage = await Page.findOne({ path: '/trash/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5' });
  1300. // originally NOT empty page should exist with status 'deleted' and parent set null
  1301. expect(deletedParentPage._id).toStrictEqual(parentPage._id);
  1302. expect(deletedParentPage.status).toBe(Page.STATUS_DELETED);
  1303. expect(deletedParentPage.parent).toBeNull();
  1304. // originally empty page should NOT exist
  1305. expect(deletedChildPage).toBeNull();
  1306. // originally NOT empty page should exist with status 'deleted' and parent set null
  1307. expect(deletedGrandchildPage._id).toStrictEqual(grandchildPage._id);
  1308. expect(deletedGrandchildPage.status).toBe(Page.STATUS_DELETED);
  1309. expect(deletedGrandchildPage.parent).toBeNull();
  1310. });
  1311. test('Should delete page tag relation', async() => {
  1312. const pageToDelete = await Page.findOne({ path: '/v5_PageForDelete6' });
  1313. const tag1 = await Tag.findOne({ name: 'TagForDelete1' });
  1314. const tag2 = await Tag.findOne({ name: 'TagForDelete2' });
  1315. const pageRelation1 = await PageTagRelation.findOne({ relatedTag: tag1?._id });
  1316. const pageRelation2 = await PageTagRelation.findOne({ relatedTag: tag2?._id });
  1317. expect(pageToDelete).toBeTruthy();
  1318. expect(tag1).toBeTruthy();
  1319. expect(tag2).toBeTruthy();
  1320. expect(pageRelation1).toBeTruthy();
  1321. expect(pageRelation2).toBeTruthy();
  1322. const deletedPage = await deletePage(pageToDelete, dummyUser1, {}, false);
  1323. const page = await Page.findOne({ path: '/v5_PageForDelete6' });
  1324. const deletedTagRelation1 = await PageTagRelation.findOne({ _id: pageRelation1._id });
  1325. const deletedTagRelation2 = await PageTagRelation.findOne({ _id: pageRelation2._id });
  1326. expect(page).toBe(null);
  1327. expect(deletedPage.status).toBe(Page.STATUS_DELETED);
  1328. expect(deletedTagRelation1.isPageTrashed).toBe(true);
  1329. expect(deletedTagRelation2.isPageTrashed).toBe(true);
  1330. });
  1331. });
  1332. describe('Delete completely', () => {
  1333. const deleteCompletely = async(page, user, options = {}, isRecursively = false, preventEmitting = false) => {
  1334. const mockedDeleteCompletelyRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteCompletelyRecursivelyMainOperation').mockReturnValue(null);
  1335. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1336. await crowi.pageService.deleteCompletely(page, user, options, isRecursively, preventEmitting);
  1337. const argsForDeleteCompletelyRecursivelyMainOperation = mockedDeleteCompletelyRecursivelyMainOperation.mock.calls[0];
  1338. mockedDeleteCompletelyRecursivelyMainOperation.mockRestore();
  1339. mockedCreateAndSendNotifications.mockRestore();
  1340. if (isRecursively) {
  1341. await crowi.pageService.deleteCompletelyRecursivelyMainOperation(...argsForDeleteCompletelyRecursivelyMainOperation);
  1342. }
  1343. return;
  1344. };
  1345. test('Should NOT completely delete root page', async() => {
  1346. expect(rootPage).toBeTruthy();
  1347. let isThrown;
  1348. try { await deleteCompletely(rootPage, dummyUser1, {}, false) }
  1349. catch (err) { isThrown = true }
  1350. const page = await Page.findOne({ path: '/' });
  1351. expect(page).toBeTruthy();
  1352. expect(isThrown).toBe(true);
  1353. });
  1354. test('Should completely delete single page', async() => {
  1355. const page = await Page.findOne({ path: '/v5_PageForDeleteCompletely1' });
  1356. expect(page).toBeTruthy();
  1357. await deleteCompletely(page, dummyUser1, {}, false);
  1358. const deletedPage = await Page.findOne({ _id: page._id, path: '/v5_PageForDeleteCompletely1' });
  1359. expect(deletedPage).toBeNull();
  1360. });
  1361. test('Should completely delete multiple pages', async() => {
  1362. const parentPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely2' });
  1363. const childPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3' });
  1364. const grandchildPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely2/v5_PageForDeleteCompletely3/v5_PageForDeleteCompletely4' });
  1365. const tag1 = await Tag.findOne({ name: 'TagForDeleteCompletely1' });
  1366. const tag2 = await Tag.findOne({ name: 'TagForDeleteCompletely2' });
  1367. const pageTagRelation1 = await PageTagRelation.findOne({ relatedPage: parentPage._id });
  1368. const pageTagRelation2 = await PageTagRelation.findOne({ relatedPage: grandchildPage._id });
  1369. const bookmark = await Bookmark.findOne({ page: parentPage._id });
  1370. const comment = await Comment.findOne({ page: parentPage._id });
  1371. const pageRedirect1 = await PageRedirect.findOne({ toPath: parentPage.path });
  1372. const pageRedirect2 = await PageRedirect.findOne({ toPath: grandchildPage.path });
  1373. const shareLink1 = await ShareLink.findOne({ relatedPage: parentPage._id });
  1374. const shareLink2 = await ShareLink.findOne({ relatedPage: grandchildPage._id });
  1375. expect(parentPage).toBeTruthy();
  1376. expect(childPage).toBeTruthy();
  1377. expect(grandchildPage).toBeTruthy();
  1378. expect(tag1).toBeTruthy();
  1379. expect(tag2).toBeTruthy();
  1380. expect(pageTagRelation1).toBeTruthy();
  1381. expect(pageTagRelation2).toBeTruthy();
  1382. expect(bookmark).toBeTruthy();
  1383. expect(comment).toBeTruthy();
  1384. expect(pageRedirect1).toBeTruthy();
  1385. expect(pageRedirect2).toBeTruthy();
  1386. expect(shareLink1).toBeTruthy();
  1387. expect(shareLink2).toBeTruthy();
  1388. await deleteCompletely(parentPage, dummyUser1, {}, true);
  1389. const deletedPages = await Page.find({ _id: { $in: [parentPage._id, childPage._id, grandchildPage._id] } });
  1390. const deletedRevisions = await Revision.find({ pageId: { $in: [parentPage._id, grandchildPage._id] } });
  1391. const tags = await Tag.find({ _id: { $in: [tag1?._id, tag2?._id] } });
  1392. const deletedPageTagRelations = await PageTagRelation.find({ _id: { $in: [pageTagRelation1._id, pageTagRelation2._id] } });
  1393. const deletedBookmarks = await Bookmark.find({ _id: bookmark._id });
  1394. const deletedComments = await Comment.find({ _id: comment._id });
  1395. const deletedPageRedirects = await PageRedirect.find({ _id: { $in: [pageRedirect1._id, pageRedirect2._id] } });
  1396. const deletedShareLinks = await ShareLink.find({ _id: { $in: [shareLink1._id, shareLink2._id] } });
  1397. // page should be null
  1398. expect(deletedPages.length).toBe(0);
  1399. // revision should be null
  1400. expect(deletedRevisions.length).toBe(0);
  1401. // tag should be Truthy
  1402. expect(tags).toBeTruthy();
  1403. // pageTagRelation should be null
  1404. expect(deletedPageTagRelations.length).toBe(0);
  1405. // bookmark should be null
  1406. expect(deletedBookmarks.length).toBe(0);
  1407. // comment should be null
  1408. expect(deletedComments.length).toBe(0);
  1409. // pageRedirect should be null
  1410. expect(deletedPageRedirects.length).toBe(0);
  1411. // sharelink should be null
  1412. expect(deletedShareLinks.length).toBe(0);
  1413. });
  1414. test('Should completely delete trashed page', async() => {
  1415. const page = await Page.findOne({ path: '/trash/v5_PageForDeleteCompletely5' });
  1416. const revision = await Revision.findOne({ pageId: page._id });
  1417. expect(page).toBeTruthy();
  1418. expect(revision).toBeTruthy();
  1419. await deleteCompletely(page, dummyUser1, {}, false);
  1420. const deltedPage = await Page.findOne({ _id: page._id });
  1421. const deltedRevision = await Revision.findOne({ _id: revision._id });
  1422. expect(deltedPage).toBeNull();
  1423. expect(deltedRevision).toBeNull();
  1424. });
  1425. test('Should completely deleting page in the middle results in having an empty page', async() => {
  1426. const parentPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely6' });
  1427. const childPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7' });
  1428. const grandchildPage = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7/v5_PageForDeleteCompletely8' });
  1429. expect(parentPage).toBeTruthy();
  1430. expect(childPage).toBeTruthy();
  1431. expect(grandchildPage).toBeTruthy();
  1432. await deleteCompletely(childPage, dummyUser1, {}, false);
  1433. const parentPageAfterDelete = await Page.findOne({ path: '/v5_PageForDeleteCompletely6' });
  1434. const childPageAfterDelete = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7' });
  1435. const grandchildPageAfterDelete = await Page.findOne({ path: '/v5_PageForDeleteCompletely6/v5_PageForDeleteCompletely7/v5_PageForDeleteCompletely8' });
  1436. const childOfDeletedPage = await Page.findOne({ parent: childPageAfterDelete._id });
  1437. expect(parentPageAfterDelete).toBeTruthy();
  1438. expect(childPageAfterDelete).toBeTruthy();
  1439. expect(grandchildPageAfterDelete).toBeTruthy();
  1440. expect(childPageAfterDelete._id).not.toStrictEqual(childPage._id);
  1441. expect(childPageAfterDelete.isEmpty).toBe(true);
  1442. expect(childPageAfterDelete.parent).toStrictEqual(parentPage._id);
  1443. expect(childOfDeletedPage._id).toStrictEqual(grandchildPage._id);
  1444. });
  1445. });
  1446. describe('revert', () => {
  1447. const revertDeletedPage = async(page, user, options = {}, isRecursively = false) => {
  1448. // mock return value
  1449. const mockedRevertRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'revertRecursivelyMainOperation').mockReturnValue(null);
  1450. const revertedPage = await crowi.pageService.revertDeletedPage(page, user, options, isRecursively);
  1451. const argsForRecursivelyMainOperation = mockedRevertRecursivelyMainOperation.mock.calls[0];
  1452. // restores the original implementation
  1453. mockedRevertRecursivelyMainOperation.mockRestore();
  1454. if (isRecursively) {
  1455. await crowi.pageService.revertRecursivelyMainOperation(...argsForRecursivelyMainOperation);
  1456. }
  1457. return revertedPage;
  1458. };
  1459. test('revert single deleted page', async() => {
  1460. const deletedPage = await Page.findOne({ path: '/trash/v5_revert1', status: Page.STATUS_DELETED });
  1461. const revision = await Revision.findOne({ pageId: deletedPage._id });
  1462. const tag = await Tag.findOne({ name: 'revertTag1' });
  1463. const deletedPageTagRelation = await PageTagRelation.findOne({ relatedPage: deletedPage._id, relatedTag: tag?._id, isPageTrashed: true });
  1464. expect(deletedPage).toBeTruthy();
  1465. expect(revision).toBeTruthy();
  1466. expect(tag).toBeTruthy();
  1467. expect(deletedPageTagRelation).toBeTruthy();
  1468. const revertedPage = await revertDeletedPage(deletedPage, dummyUser1, {}, false);
  1469. const pageTagRelation = await PageTagRelation.findOne({ relatedPage: deletedPage._id, relatedTag: tag?._id });
  1470. expect(revertedPage.parent).toStrictEqual(rootPage._id);
  1471. expect(revertedPage.path).toBe('/v5_revert1');
  1472. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1473. expect(pageTagRelation.isPageTrashed).toBe(false);
  1474. });
  1475. test('revert multiple deleted page (has non existent page in the middle)', async() => {
  1476. const deletedPage1 = await Page.findOne({ path: '/trash/v5_revert2', status: Page.STATUS_DELETED });
  1477. const deletedPage2 = await Page.findOne({ path: '/trash/v5_revert2/v5_revert3/v5_revert4', status: Page.STATUS_DELETED });
  1478. const revision1 = await Revision.findOne({ pageId: deletedPage1._id });
  1479. const revision2 = await Revision.findOne({ pageId: deletedPage2._id });
  1480. expect(deletedPage1).toBeTruthy();
  1481. expect(deletedPage2).toBeTruthy();
  1482. expect(revision1).toBeTruthy();
  1483. expect(revision2).toBeTruthy();
  1484. const revertedPage1 = await revertDeletedPage(deletedPage1, dummyUser1, {}, true);
  1485. const revertedPage2 = await Page.findOne({ _id: deletedPage2._id });
  1486. const newlyCreatedPage = await Page.findOne({ path: '/v5_revert2/v5_revert3' });
  1487. expect(revertedPage1).toBeTruthy();
  1488. expect(revertedPage2).toBeTruthy();
  1489. expect(newlyCreatedPage).toBeTruthy();
  1490. expect(revertedPage1.parent).toStrictEqual(rootPage._id);
  1491. expect(revertedPage1.path).toBe('/v5_revert2');
  1492. expect(revertedPage2.path).toBe('/v5_revert2/v5_revert3/v5_revert4');
  1493. expect(newlyCreatedPage.parent).toStrictEqual(revertedPage1._id);
  1494. expect(revertedPage2.parent).toStrictEqual(newlyCreatedPage._id);
  1495. expect(revertedPage1.status).toBe(Page.STATUS_PUBLISHED);
  1496. expect(revertedPage2.status).toBe(Page.STATUS_PUBLISHED);
  1497. expect(newlyCreatedPage.status).toBe(Page.STATUS_PUBLISHED);
  1498. });
  1499. });
  1500. });