v5.non-public-page.test.ts 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448
  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 non-public pages', () => {
  7. let dummyUser1;
  8. let dummyUser2;
  9. let npDummyUser1;
  10. let npDummyUser2;
  11. let npDummyUser3;
  12. let groupIdIsolate;
  13. let groupIdA;
  14. let groupIdB;
  15. let groupIdC;
  16. let crowi;
  17. let Page;
  18. let Revision;
  19. let User;
  20. let UserGroup;
  21. let UserGroupRelation;
  22. let PageTagRelation;
  23. let Bookmark;
  24. let Comment;
  25. let ShareLink;
  26. let PageRedirect;
  27. let xssSpy;
  28. let rootPage;
  29. /**
  30. * Rename
  31. */
  32. const pageIdRename1 = new mongoose.Types.ObjectId();
  33. const pageIdRename2 = new mongoose.Types.ObjectId();
  34. const pageIdRename3 = new mongoose.Types.ObjectId();
  35. const pageIdRename4 = new mongoose.Types.ObjectId();
  36. const pageIdRename5 = new mongoose.Types.ObjectId();
  37. const pageIdRename6 = new mongoose.Types.ObjectId();
  38. const pageIdRename7 = new mongoose.Types.ObjectId();
  39. const pageIdRename8 = new mongoose.Types.ObjectId();
  40. const pageIdRename9 = new mongoose.Types.ObjectId();
  41. /**
  42. * Duplicate
  43. */
  44. // page id
  45. const pageIdDuplicate1 = new mongoose.Types.ObjectId();
  46. const pageIdDuplicate2 = new mongoose.Types.ObjectId();
  47. const pageIdDuplicate3 = new mongoose.Types.ObjectId();
  48. const pageIdDuplicate4 = new mongoose.Types.ObjectId();
  49. const pageIdDuplicate5 = new mongoose.Types.ObjectId();
  50. const pageIdDuplicate6 = new mongoose.Types.ObjectId();
  51. // revision id
  52. const revisionIdDuplicate1 = new mongoose.Types.ObjectId();
  53. const revisionIdDuplicate2 = new mongoose.Types.ObjectId();
  54. const revisionIdDuplicate3 = new mongoose.Types.ObjectId();
  55. const revisionIdDuplicate4 = new mongoose.Types.ObjectId();
  56. const revisionIdDuplicate5 = new mongoose.Types.ObjectId();
  57. const revisionIdDuplicate6 = new mongoose.Types.ObjectId();
  58. /**
  59. * Revert
  60. */
  61. // page id
  62. const pageIdRevert1 = new mongoose.Types.ObjectId();
  63. const pageIdRevert2 = new mongoose.Types.ObjectId();
  64. const pageIdRevert3 = new mongoose.Types.ObjectId();
  65. const pageIdRevert4 = new mongoose.Types.ObjectId();
  66. const pageIdRevert5 = new mongoose.Types.ObjectId();
  67. const pageIdRevert6 = new mongoose.Types.ObjectId();
  68. // revision id
  69. const revisionIdRevert1 = new mongoose.Types.ObjectId();
  70. const revisionIdRevert2 = new mongoose.Types.ObjectId();
  71. const revisionIdRevert3 = new mongoose.Types.ObjectId();
  72. const revisionIdRevert4 = new mongoose.Types.ObjectId();
  73. const revisionIdRevert5 = new mongoose.Types.ObjectId();
  74. const revisionIdRevert6 = new mongoose.Types.ObjectId();
  75. // tag id
  76. const tagIdRevert1 = new mongoose.Types.ObjectId();
  77. const tagIdRevert2 = new mongoose.Types.ObjectId();
  78. beforeAll(async() => {
  79. crowi = await getInstance();
  80. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  81. User = mongoose.model('User');
  82. UserGroup = mongoose.model('UserGroup');
  83. UserGroupRelation = mongoose.model('UserGroupRelation');
  84. Page = mongoose.model('Page');
  85. Revision = mongoose.model('Revision');
  86. PageTagRelation = mongoose.model('PageTagRelation');
  87. Bookmark = mongoose.model('Bookmark');
  88. Comment = mongoose.model('Comment');
  89. ShareLink = mongoose.model('ShareLink');
  90. PageRedirect = mongoose.model('PageRedirect');
  91. UserGroup = mongoose.model('UserGroup');
  92. UserGroupRelation = mongoose.model('UserGroupRelation');
  93. /*
  94. * Common
  95. */
  96. const npUserId1 = new mongoose.Types.ObjectId();
  97. const npUserId2 = new mongoose.Types.ObjectId();
  98. const npUserId3 = new mongoose.Types.ObjectId();
  99. await User.insertMany([
  100. {
  101. _id: npUserId1, name: 'npUser1', username: 'npUser1', email: 'npUser1@example.com',
  102. },
  103. {
  104. _id: npUserId2, name: 'npUser2', username: 'npUser2', email: 'npUser2@example.com',
  105. },
  106. {
  107. _id: npUserId3, name: 'npUser3', username: 'npUser3', email: 'npUser3@example.com',
  108. },
  109. ]);
  110. groupIdIsolate = new mongoose.Types.ObjectId();
  111. groupIdA = new mongoose.Types.ObjectId();
  112. groupIdB = new mongoose.Types.ObjectId();
  113. groupIdC = new mongoose.Types.ObjectId();
  114. await UserGroup.insertMany([
  115. {
  116. _id: groupIdIsolate,
  117. name: 'np_groupIsolate',
  118. },
  119. {
  120. _id: groupIdA,
  121. name: 'np_groupA',
  122. },
  123. {
  124. _id: groupIdB,
  125. name: 'np_groupB',
  126. parent: groupIdA,
  127. },
  128. {
  129. _id: groupIdC,
  130. name: 'np_groupC',
  131. parent: groupIdB,
  132. },
  133. ]);
  134. await UserGroupRelation.insertMany([
  135. {
  136. relatedGroup: groupIdIsolate,
  137. relatedUser: npUserId1,
  138. createdAt: new Date(),
  139. },
  140. {
  141. relatedGroup: groupIdIsolate,
  142. relatedUser: npUserId2,
  143. createdAt: new Date(),
  144. },
  145. {
  146. relatedGroup: groupIdA,
  147. relatedUser: npUserId1,
  148. createdAt: new Date(),
  149. },
  150. {
  151. relatedGroup: groupIdA,
  152. relatedUser: npUserId2,
  153. createdAt: new Date(),
  154. },
  155. {
  156. relatedGroup: groupIdA,
  157. relatedUser: npUserId3,
  158. createdAt: new Date(),
  159. },
  160. {
  161. relatedGroup: groupIdB,
  162. relatedUser: npUserId2,
  163. createdAt: new Date(),
  164. },
  165. {
  166. relatedGroup: groupIdB,
  167. relatedUser: npUserId3,
  168. createdAt: new Date(),
  169. },
  170. {
  171. relatedGroup: groupIdC,
  172. relatedUser: npUserId3,
  173. createdAt: new Date(),
  174. },
  175. ]);
  176. xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
  177. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  178. dummyUser2 = await User.findOne({ username: 'v5DummyUser2' });
  179. npDummyUser1 = await User.findOne({ username: 'npUser1' });
  180. npDummyUser2 = await User.findOne({ username: 'npUser2' });
  181. npDummyUser3 = await User.findOne({ username: 'npUser3' });
  182. rootPage = await Page.findOne({ path: '/' });
  183. if (rootPage == null) {
  184. const pages = await Page.insertMany([{ path: '/', grant: Page.GRANT_PUBLIC }]);
  185. rootPage = pages[0];
  186. }
  187. /**
  188. * create
  189. * mc_ => model create
  190. * emp => empty => page with isEmpty: true
  191. * pub => public => GRANT_PUBLIC
  192. */
  193. const pageIdCreate1 = new mongoose.Types.ObjectId();
  194. const pageIdCreate2 = new mongoose.Types.ObjectId();
  195. const pageIdCreate3 = new mongoose.Types.ObjectId();
  196. await Page.insertMany([
  197. {
  198. _id: pageIdCreate1,
  199. path: '/mc4_top/mc1_emp',
  200. grant: Page.GRANT_PUBLIC,
  201. creator: dummyUser1,
  202. lastUpdateUser: dummyUser1._id,
  203. parent: rootPage._id,
  204. isEmpty: true,
  205. },
  206. {
  207. path: '/mc4_top/mc1_emp/mc2_pub',
  208. grant: Page.GRANT_PUBLIC,
  209. creator: dummyUser1,
  210. lastUpdateUser: dummyUser1._id,
  211. parent: pageIdCreate1,
  212. isEmpty: false,
  213. },
  214. {
  215. path: '/mc5_top/mc3_awl',
  216. grant: Page.GRANT_RESTRICTED,
  217. creator: dummyUser1,
  218. lastUpdateUser: dummyUser1._id,
  219. isEmpty: false,
  220. },
  221. {
  222. _id: pageIdCreate2,
  223. path: '/mc4_top',
  224. grant: Page.GRANT_PUBLIC,
  225. creator: dummyUser1,
  226. lastUpdateUser: dummyUser1._id,
  227. isEmpty: false,
  228. parent: rootPage._id,
  229. descendantCount: 1,
  230. },
  231. {
  232. _id: pageIdCreate3,
  233. path: '/mc5_top',
  234. grant: Page.GRANT_PUBLIC,
  235. creator: dummyUser1,
  236. lastUpdateUser: dummyUser1._id,
  237. isEmpty: false,
  238. parent: rootPage._id,
  239. descendantCount: 0,
  240. },
  241. ]);
  242. /**
  243. * create
  244. * mc_ => model create
  245. * emp => empty => page with isEmpty: true
  246. * pub => public => GRANT_PUBLIC
  247. */
  248. const pageIdCreateBySystem1 = new mongoose.Types.ObjectId();
  249. const pageIdCreateBySystem2 = new mongoose.Types.ObjectId();
  250. const pageIdCreateBySystem3 = new mongoose.Types.ObjectId();
  251. await Page.insertMany([
  252. {
  253. _id: pageIdCreateBySystem1,
  254. path: '/mc4_top_by_system/mc1_emp_by_system',
  255. grant: Page.GRANT_PUBLIC,
  256. creator: dummyUser1,
  257. lastUpdateUser: dummyUser1._id,
  258. parent: rootPage._id,
  259. isEmpty: true,
  260. },
  261. {
  262. path: '/mc4_top_by_system/mc1_emp_by_system/mc2_pub_by_system',
  263. grant: Page.GRANT_PUBLIC,
  264. creator: dummyUser1,
  265. lastUpdateUser: dummyUser1._id,
  266. parent: pageIdCreateBySystem1,
  267. isEmpty: false,
  268. },
  269. {
  270. path: '/mc5_top_by_system/mc3_awl_by_system',
  271. grant: Page.GRANT_RESTRICTED,
  272. creator: dummyUser1,
  273. lastUpdateUser: dummyUser1._id,
  274. isEmpty: false,
  275. },
  276. {
  277. _id: pageIdCreateBySystem2,
  278. path: '/mc4_top_by_system',
  279. grant: Page.GRANT_PUBLIC,
  280. creator: dummyUser1,
  281. lastUpdateUser: dummyUser1._id,
  282. isEmpty: false,
  283. parent: rootPage._id,
  284. descendantCount: 1,
  285. },
  286. {
  287. _id: pageIdCreateBySystem3,
  288. path: '/mc5_top_by_system',
  289. grant: Page.GRANT_PUBLIC,
  290. creator: dummyUser1,
  291. lastUpdateUser: dummyUser1._id,
  292. isEmpty: false,
  293. parent: rootPage._id,
  294. descendantCount: 0,
  295. },
  296. ]);
  297. /*
  298. * Rename
  299. */
  300. await Page.insertMany([
  301. {
  302. _id: pageIdRename1,
  303. path: '/np_rename1_destination',
  304. grant: Page.GRANT_PUBLIC,
  305. creator: dummyUser1._id,
  306. lastUpdateUser: dummyUser1._id,
  307. parent: rootPage._id,
  308. },
  309. {
  310. _id: pageIdRename2,
  311. path: '/np_rename2',
  312. grant: Page.GRANT_USER_GROUP,
  313. grantedGroup: groupIdB,
  314. creator: npDummyUser2._id,
  315. lastUpdateUser: npDummyUser2._id,
  316. parent: rootPage._id,
  317. },
  318. {
  319. _id: pageIdRename3,
  320. path: '/np_rename2/np_rename3',
  321. grant: Page.GRANT_USER_GROUP,
  322. grantedGroup: groupIdC,
  323. creator: npDummyUser3._id,
  324. lastUpdateUser: npDummyUser3._id,
  325. parent: pageIdRename2._id,
  326. },
  327. {
  328. _id: pageIdRename4,
  329. path: '/np_rename4_destination',
  330. grant: Page.GRANT_USER_GROUP,
  331. grantedGroup: groupIdIsolate,
  332. creator: npDummyUser3._id,
  333. lastUpdateUser: npDummyUser3._id,
  334. parent: rootPage._id,
  335. },
  336. {
  337. _id: pageIdRename5,
  338. path: '/np_rename5',
  339. grant: Page.GRANT_USER_GROUP,
  340. grantedGroup: groupIdB,
  341. creator: npDummyUser2._id,
  342. lastUpdateUser: npDummyUser2._id,
  343. parent: rootPage._id,
  344. },
  345. {
  346. _id: pageIdRename6,
  347. path: '/np_rename5/np_rename6',
  348. grant: Page.GRANT_USER_GROUP,
  349. grantedGroup: groupIdB,
  350. creator: npDummyUser2._id,
  351. lastUpdateUser: npDummyUser2._id,
  352. parent: pageIdRename5,
  353. },
  354. {
  355. _id: pageIdRename7,
  356. path: '/np_rename7_destination',
  357. grant: Page.GRANT_USER_GROUP,
  358. grantedGroup: groupIdIsolate,
  359. creator: npDummyUser2._id,
  360. lastUpdateUser: npDummyUser2._id,
  361. parent: pageIdRename5,
  362. },
  363. {
  364. _id: pageIdRename8,
  365. path: '/np_rename8',
  366. grant: Page.GRANT_RESTRICTED,
  367. creator: dummyUser1._id,
  368. lastUpdateUser: dummyUser1._id,
  369. },
  370. {
  371. _id: pageIdRename9,
  372. path: '/np_rename8/np_rename9',
  373. grant: Page.GRANT_RESTRICTED,
  374. creator: dummyUser2._id,
  375. lastUpdateUser: dummyUser2._id,
  376. },
  377. ]);
  378. /*
  379. * Duplicate
  380. */
  381. await Page.insertMany([
  382. {
  383. _id: pageIdDuplicate1,
  384. path: '/np_duplicate1',
  385. grant: Page.GRANT_RESTRICTED,
  386. creator: dummyUser1._id,
  387. lastUpdateUser: dummyUser1._id,
  388. revision: revisionIdDuplicate1,
  389. },
  390. {
  391. _id: pageIdDuplicate2,
  392. path: '/np_duplicate2',
  393. grant: Page.GRANT_USER_GROUP,
  394. grantedGroup: groupIdA,
  395. creator: npDummyUser1._id,
  396. lastUpdateUser: npDummyUser1._id,
  397. revision: revisionIdDuplicate2,
  398. parent: rootPage._id,
  399. },
  400. {
  401. _id: pageIdDuplicate3,
  402. path: '/np_duplicate2/np_duplicate3',
  403. grant: Page.GRANT_USER_GROUP,
  404. grantedGroup: groupIdB,
  405. creator: npDummyUser2._id,
  406. lastUpdateUser: npDummyUser2._id,
  407. revision: revisionIdDuplicate3,
  408. parent: pageIdDuplicate2,
  409. },
  410. {
  411. _id: pageIdDuplicate4,
  412. path: '/np_duplicate4',
  413. grant: Page.GRANT_PUBLIC,
  414. creator: npDummyUser1._id,
  415. lastUpdateUser: npDummyUser1._id,
  416. revision: revisionIdDuplicate4,
  417. parent: rootPage._id,
  418. },
  419. {
  420. _id: pageIdDuplicate5,
  421. path: '/np_duplicate4/np_duplicate5',
  422. grant: Page.GRANT_RESTRICTED,
  423. creator: npDummyUser1._id,
  424. lastUpdateUser: npDummyUser1._id,
  425. revision: revisionIdDuplicate5,
  426. },
  427. {
  428. _id: pageIdDuplicate6,
  429. path: '/np_duplicate4/np_duplicate6',
  430. grant: Page.GRANT_PUBLIC,
  431. creator: npDummyUser1._id,
  432. lastUpdateUser: npDummyUser1._id,
  433. parent: pageIdDuplicate4,
  434. revision: revisionIdDuplicate6,
  435. },
  436. ]);
  437. await Revision.insertMany([
  438. {
  439. _id: revisionIdDuplicate1,
  440. body: 'np_duplicate1',
  441. format: 'markdown',
  442. pageId: pageIdDuplicate1,
  443. author: npDummyUser1._id,
  444. },
  445. {
  446. _id: revisionIdDuplicate2,
  447. body: 'np_duplicate2',
  448. format: 'markdown',
  449. pageId: pageIdDuplicate2,
  450. author: npDummyUser2._id,
  451. },
  452. {
  453. _id: revisionIdDuplicate3,
  454. body: 'np_duplicate3',
  455. format: 'markdown',
  456. pageId: pageIdDuplicate3,
  457. author: npDummyUser2._id,
  458. },
  459. {
  460. _id: revisionIdDuplicate4,
  461. body: 'np_duplicate4',
  462. format: 'markdown',
  463. pageId: pageIdDuplicate4,
  464. author: npDummyUser2._id,
  465. },
  466. {
  467. _id: revisionIdDuplicate5,
  468. body: 'np_duplicate5',
  469. format: 'markdown',
  470. pageId: pageIdDuplicate5,
  471. author: npDummyUser2._id,
  472. },
  473. {
  474. _id: revisionIdDuplicate6,
  475. body: 'np_duplicate6',
  476. format: 'markdown',
  477. pageId: pageIdDuplicate6,
  478. author: npDummyUser1._id,
  479. },
  480. ]);
  481. /**
  482. * Delete
  483. */
  484. const pageIdDelete1 = new mongoose.Types.ObjectId();
  485. const pageIdDelete2 = new mongoose.Types.ObjectId();
  486. const pageIdDelete3 = new mongoose.Types.ObjectId();
  487. const pageIdDelete4 = new mongoose.Types.ObjectId();
  488. await Page.insertMany([
  489. {
  490. _id: pageIdDelete1,
  491. path: '/npdel1_awl',
  492. grant: Page.GRANT_RESTRICTED,
  493. status: Page.STATUS_PUBLISHED,
  494. isEmpty: false,
  495. },
  496. {
  497. _id: pageIdDelete2,
  498. path: '/npdel2_ug',
  499. grant: Page.GRANT_USER_GROUP,
  500. grantedGroup: groupIdA,
  501. status: Page.STATUS_PUBLISHED,
  502. isEmpty: false,
  503. parent: rootPage._id,
  504. descendantCount: 0,
  505. },
  506. {
  507. _id: pageIdDelete3,
  508. path: '/npdel3_top',
  509. grant: Page.GRANT_USER_GROUP,
  510. grantedGroup: groupIdA,
  511. status: Page.STATUS_PUBLISHED,
  512. isEmpty: false,
  513. parent: rootPage._id,
  514. descendantCount: 2,
  515. },
  516. {
  517. _id: pageIdDelete4,
  518. path: '/npdel3_top/npdel4_ug',
  519. grant: Page.GRANT_USER_GROUP,
  520. grantedGroup: groupIdB,
  521. status: Page.STATUS_PUBLISHED,
  522. isEmpty: false,
  523. parent: pageIdDelete3._id,
  524. descendantCount: 1,
  525. },
  526. {
  527. path: '/npdel3_top/npdel4_ug',
  528. grant: Page.GRANT_RESTRICTED,
  529. status: Page.STATUS_PUBLISHED,
  530. isEmpty: false,
  531. },
  532. {
  533. path: '/npdel3_top/npdel4_ug/npdel5_ug',
  534. grant: Page.GRANT_USER_GROUP,
  535. grantedGroup: groupIdC,
  536. status: Page.STATUS_PUBLISHED,
  537. isEmpty: false,
  538. parent: pageIdDelete4._id,
  539. descendantCount: 0,
  540. },
  541. ]);
  542. /**
  543. * Delete completely
  544. */
  545. const pageIdDeleteComp1 = new mongoose.Types.ObjectId();
  546. const pageIdDeleteComp2 = new mongoose.Types.ObjectId();
  547. await Page.insertMany([
  548. {
  549. path: '/npdc1_awl',
  550. grant: Page.GRANT_RESTRICTED,
  551. status: Page.STATUS_PUBLISHED,
  552. isEmpty: false,
  553. },
  554. {
  555. path: '/npdc2_ug',
  556. grant: Page.GRANT_USER_GROUP,
  557. grantedGroup: groupIdA,
  558. status: Page.STATUS_PUBLISHED,
  559. isEmpty: false,
  560. parent: rootPage._id,
  561. },
  562. {
  563. _id: pageIdDeleteComp1,
  564. path: '/npdc3_ug',
  565. grant: Page.GRANT_USER_GROUP,
  566. grantedGroup: groupIdA,
  567. status: Page.STATUS_PUBLISHED,
  568. isEmpty: false,
  569. parent: rootPage._id,
  570. },
  571. {
  572. _id: pageIdDeleteComp2,
  573. path: '/npdc3_ug/npdc4_ug',
  574. grant: Page.GRANT_USER_GROUP,
  575. grantedGroup: groupIdB,
  576. status: Page.STATUS_PUBLISHED,
  577. isEmpty: false,
  578. parent: pageIdDeleteComp1,
  579. },
  580. {
  581. path: '/npdc3_ug/npdc4_ug/npdc5_ug',
  582. grant: Page.GRANT_USER_GROUP,
  583. grantedGroup: groupIdC,
  584. status: Page.STATUS_PUBLISHED,
  585. isEmpty: false,
  586. parent: pageIdDeleteComp2,
  587. },
  588. {
  589. path: '/npdc3_ug/npdc4_ug',
  590. grant: Page.GRANT_RESTRICTED,
  591. status: Page.STATUS_PUBLISHED,
  592. isEmpty: false,
  593. },
  594. ]);
  595. /**
  596. * Revert
  597. */
  598. await Page.insertMany([
  599. {
  600. _id: pageIdRevert1,
  601. path: '/trash/np_revert1',
  602. grant: Page.GRANT_RESTRICTED,
  603. revision: revisionIdRevert1,
  604. status: Page.STATUS_DELETED,
  605. },
  606. {
  607. _id: pageIdRevert2,
  608. path: '/trash/np_revert2',
  609. grant: Page.GRANT_USER_GROUP,
  610. grantedGroup: groupIdA,
  611. revision: revisionIdRevert2,
  612. status: Page.STATUS_DELETED,
  613. },
  614. {
  615. _id: pageIdRevert3,
  616. path: '/trash/np_revert3',
  617. revision: revisionIdRevert3,
  618. status: Page.STATUS_DELETED,
  619. parent: rootPage._id,
  620. },
  621. {
  622. _id: pageIdRevert4,
  623. path: '/trash/np_revert3/middle/np_revert4',
  624. grant: Page.GRANT_RESTRICTED,
  625. revision: revisionIdRevert4,
  626. status: Page.STATUS_DELETED,
  627. },
  628. {
  629. _id: pageIdRevert5,
  630. path: '/trash/np_revert5',
  631. grant: Page.GRANT_USER_GROUP,
  632. grantedGroup: groupIdA,
  633. revision: revisionIdRevert5,
  634. status: Page.STATUS_DELETED,
  635. },
  636. {
  637. _id: pageIdRevert6,
  638. path: '/trash/np_revert5/middle/np_revert6',
  639. grant: Page.GRANT_USER_GROUP,
  640. grantedGroup: groupIdB,
  641. revision: revisionIdRevert6,
  642. status: Page.STATUS_DELETED,
  643. },
  644. ]);
  645. await Revision.insertMany([
  646. {
  647. _id: revisionIdRevert1,
  648. pageId: pageIdRevert1,
  649. body: 'np_revert1',
  650. format: 'markdown',
  651. author: dummyUser1._id,
  652. },
  653. {
  654. _id: revisionIdRevert2,
  655. pageId: pageIdRevert2,
  656. body: 'np_revert2',
  657. format: 'markdown',
  658. author: npDummyUser1,
  659. },
  660. {
  661. _id: revisionIdRevert3,
  662. pageId: pageIdRevert3,
  663. body: 'np_revert3',
  664. format: 'markdown',
  665. author: npDummyUser1,
  666. },
  667. {
  668. _id: revisionIdRevert4,
  669. pageId: pageIdRevert4,
  670. body: 'np_revert4',
  671. format: 'markdown',
  672. author: npDummyUser1,
  673. },
  674. {
  675. _id: revisionIdRevert5,
  676. pageId: pageIdRevert5,
  677. body: 'np_revert5',
  678. format: 'markdown',
  679. author: npDummyUser1,
  680. },
  681. {
  682. _id: revisionIdRevert6,
  683. pageId: pageIdRevert6,
  684. body: 'np_revert6',
  685. format: 'markdown',
  686. author: npDummyUser1,
  687. },
  688. ]);
  689. await Tag.insertMany([
  690. { _id: tagIdRevert1, name: 'np_revertTag1' },
  691. { _id: tagIdRevert2, name: 'np_revertTag2' },
  692. ]);
  693. await PageTagRelation.insertMany([
  694. {
  695. relatedPage: pageIdRevert1,
  696. relatedTag: tagIdRevert1,
  697. isPageTrashed: true,
  698. },
  699. {
  700. relatedPage: pageIdRevert2,
  701. relatedTag: tagIdRevert2,
  702. isPageTrashed: true,
  703. },
  704. ]);
  705. });
  706. describe('create', () => {
  707. describe('Creating a page using existing path', () => {
  708. test('with grant RESTRICTED should only create the page and change nothing else', async() => {
  709. const isGrantNormalizedSpy = jest.spyOn(crowi.pageGrantService, 'isGrantNormalized');
  710. const pathT = '/mc4_top';
  711. const path1 = '/mc4_top/mc1_emp';
  712. const path2 = '/mc4_top/mc1_emp/mc2_pub';
  713. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  714. const page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  715. const page2 = await Page.findOne({ path: path2 });
  716. const page3 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  717. expect(pageT).toBeTruthy();
  718. expect(page1).toBeTruthy();
  719. expect(page2).toBeTruthy();
  720. expect(page3).toBeNull();
  721. // use existing path
  722. await crowi.pageService.create(path1, 'new body', dummyUser1, { grant: Page.GRANT_RESTRICTED });
  723. const _pageT = await Page.findOne({ path: pathT });
  724. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  725. const _page2 = await Page.findOne({ path: path2 });
  726. const _page3 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  727. expect(_pageT).toBeTruthy();
  728. expect(_page1).toBeTruthy();
  729. expect(_page2).toBeTruthy();
  730. expect(_page3).toBeTruthy();
  731. expect(_pageT.descendantCount).toBe(1);
  732. // isGrantNormalized is not called when GRANT RESTRICTED
  733. expect(isGrantNormalizedSpy).toBeCalledTimes(0);
  734. });
  735. });
  736. describe('Creating a page under a page with grant RESTRICTED', () => {
  737. test('will create a new empty page with the same path as the grant RESTRECTED page and become a parent', async() => {
  738. const isGrantNormalizedSpy = jest.spyOn(crowi.pageGrantService, 'isGrantNormalized');
  739. const pathT = '/mc5_top';
  740. const path1 = '/mc5_top/mc3_awl';
  741. const pathN = '/mc5_top/mc3_awl/mc4_pub'; // used to create
  742. const pageT = await Page.findOne({ path: pathT });
  743. const page1 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  744. const page2 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  745. expect(pageT).toBeTruthy();
  746. expect(page1).toBeTruthy();
  747. expect(page2).toBeNull();
  748. await crowi.pageService.create(pathN, 'new body', dummyUser1, { grant: Page.GRANT_PUBLIC });
  749. const _pageT = await Page.findOne({ path: pathT });
  750. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  751. const _page2 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC, isEmpty: true });
  752. const _pageN = await Page.findOne({ path: pathN, grant: Page.GRANT_PUBLIC }); // newly crated
  753. expect(_pageT).toBeTruthy();
  754. expect(_page1).toBeTruthy();
  755. expect(_page2).toBeTruthy();
  756. expect(_pageN).toBeTruthy();
  757. expect(_pageN.parent).toStrictEqual(_page2._id);
  758. expect(_pageT.descendantCount).toStrictEqual(1);
  759. // isGrantNormalized is called when GRANT PUBLIC
  760. expect(isGrantNormalizedSpy).toBeCalledTimes(1);
  761. });
  762. });
  763. });
  764. describe('create by system', () => {
  765. describe('Creating a page using existing path', () => {
  766. test('with grant RESTRICTED should only create the page and change nothing else', async() => {
  767. const isGrantNormalizedSpy = jest.spyOn(crowi.pageGrantService, 'isGrantNormalized');
  768. const pathT = '/mc4_top_by_system';
  769. const path1 = '/mc4_top_by_system/mc1_emp_by_system';
  770. const path2 = '/mc4_top_by_system/mc1_emp_by_system/mc2_pub_by_system';
  771. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  772. const page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  773. const page2 = await Page.findOne({ path: path2 });
  774. const page3 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  775. expect(pageT).toBeTruthy();
  776. expect(page1).toBeTruthy();
  777. expect(page2).toBeTruthy();
  778. expect(page3).toBeNull();
  779. // use existing path
  780. await crowi.pageService.forceCreateBySystem(path1, 'new body', { grant: Page.GRANT_RESTRICTED });
  781. const _pageT = await Page.findOne({ path: pathT });
  782. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  783. const _page2 = await Page.findOne({ path: path2 });
  784. const _page3 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  785. expect(_pageT).toBeTruthy();
  786. expect(_page1).toBeTruthy();
  787. expect(_page2).toBeTruthy();
  788. expect(_page3).toBeTruthy();
  789. expect(_pageT.descendantCount).toBe(1);
  790. // isGrantNormalized is not called when create by ststem
  791. expect(isGrantNormalizedSpy).toBeCalledTimes(0);
  792. });
  793. });
  794. describe('Creating a page under a page with grant RESTRICTED', () => {
  795. test('will create a new empty page with the same path as the grant RESTRECTED page and become a parent', async() => {
  796. const isGrantNormalizedSpy = jest.spyOn(crowi.pageGrantService, 'isGrantNormalized');
  797. const pathT = '/mc5_top_by_system';
  798. const path1 = '/mc5_top_by_system/mc3_awl_by_system';
  799. const pathN = '/mc5_top_by_system/mc3_awl_by_system/mc4_pub_by_system'; // used to create
  800. const pageT = await Page.findOne({ path: pathT });
  801. const page1 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  802. const page2 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  803. expect(pageT).toBeTruthy();
  804. expect(page1).toBeTruthy();
  805. expect(page2).toBeNull();
  806. await crowi.pageService.forceCreateBySystem(pathN, 'new body', { grant: Page.GRANT_PUBLIC });
  807. const _pageT = await Page.findOne({ path: pathT });
  808. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  809. const _page2 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC, isEmpty: true });
  810. const _pageN = await Page.findOne({ path: pathN, grant: Page.GRANT_PUBLIC }); // newly crated
  811. expect(_pageT).toBeTruthy();
  812. expect(_page1).toBeTruthy();
  813. expect(_page2).toBeTruthy();
  814. expect(_pageN).toBeTruthy();
  815. expect(_pageN.parent).toStrictEqual(_page2._id);
  816. expect(_pageT.descendantCount).toStrictEqual(1);
  817. // isGrantNormalized is not called when create by ststem
  818. expect(isGrantNormalizedSpy).toBeCalledTimes(0);
  819. });
  820. });
  821. });
  822. describe('Rename', () => {
  823. const renamePage = async(page, newPagePath, user, options, activityParameters?) => {
  824. // mock return value
  825. const mockedRenameSubOperation = jest.spyOn(crowi.pageService, 'renameSubOperation').mockReturnValue(null);
  826. const renamedPage = await crowi.pageService.renamePage(page, newPagePath, user, options, activityParameters);
  827. // retrieve the arguments passed when calling method renameSubOperation inside renamePage method
  828. const argsForRenameSubOperation = mockedRenameSubOperation.mock.calls[0];
  829. // restores the original implementation
  830. mockedRenameSubOperation.mockRestore();
  831. // rename descendants
  832. if (page.grant !== Page.GRANT_RESTRICTED) {
  833. await crowi.pageService.renameSubOperation(...argsForRenameSubOperation);
  834. }
  835. return renamedPage;
  836. };
  837. test('Should rename/move with descendants with grant normalized pages', async() => {
  838. const _pathD = '/np_rename1_destination';
  839. const _path2 = '/np_rename2';
  840. const _path3 = '/np_rename2/np_rename3';
  841. const _propertiesD = { grant: Page.GRANT_PUBLIC };
  842. const _properties2 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB };
  843. const _properties3 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC };
  844. const _pageD = await Page.findOne({ path: _pathD, ..._propertiesD });
  845. const _page2 = await Page.findOne({ path: _path2, ..._properties2 });
  846. const _page3 = await Page.findOne({ path: _path3, ..._properties3, parent: _page2._id });
  847. expect(_pageD).toBeTruthy();
  848. expect(_page2).toBeTruthy();
  849. expect(_page3).toBeTruthy();
  850. const newPathForPage2 = '/np_rename1_destination/np_rename2';
  851. const newPathForPage3 = '/np_rename1_destination/np_rename2/np_rename3';
  852. await renamePage(_page2, newPathForPage2, npDummyUser2, {}, {
  853. ip: '::ffff:127.0.0.1',
  854. endpoint: '/_api/v3/pages/rename',
  855. activityId: '62e291bc10e0ab61bd691794',
  856. });
  857. const pageD = await Page.findOne({ path: _pathD, ..._propertiesD });
  858. const page2 = await Page.findOne({ path: _path2, ..._properties2 }); // not exist
  859. const page3 = await Page.findOne({ path: _path3, ..._properties3, parent: _page2._id }); // not exist
  860. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // renamed
  861. const page3Renamed = await Page.findOne({ path: newPathForPage3 }); // renamed
  862. expect(pageD).toBeTruthy();
  863. expect(page2).toBeNull();
  864. expect(page3).toBeNull();
  865. expect(page2Renamed).toBeTruthy();
  866. expect(page3Renamed).toBeTruthy();
  867. expect(page2Renamed.parent).toStrictEqual(_pageD._id);
  868. expect(page3Renamed.parent).toStrictEqual(page2Renamed._id);
  869. expect(page2Renamed.grantedGroup).toStrictEqual(_page2.grantedGroup);
  870. expect(page3Renamed.grantedGroup).toStrictEqual(_page3.grantedGroup);
  871. expect(xssSpy).toHaveBeenCalled();
  872. });
  873. test('Should throw with NOT grant normalized pages', async() => {
  874. const _pathD = '/np_rename4_destination';
  875. const _path2 = '/np_rename5';
  876. const _path3 = '/np_rename5/np_rename6';
  877. const _propertiesD = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdIsolate };
  878. const _properties2 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB };
  879. const _properties3 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB };
  880. const _pageD = await Page.findOne({ path: _pathD, ..._propertiesD });// isolate
  881. const _page2 = await Page.findOne({ path: _path2, ..._properties2 });// groupIdB
  882. const _page3 = await Page.findOne({ path: _path3, ..._properties3, parent: _page2 });// groupIdB
  883. expect(_pageD).toBeTruthy();
  884. expect(_page2).toBeTruthy();
  885. expect(_page3).toBeTruthy();
  886. const newPathForPage2 = '/np_rename4_destination/np_rename5';
  887. const newPathForPage3 = '/np_rename4_destination/np_rename5/np_rename6';
  888. let isThrown = false;
  889. try {
  890. await renamePage(_page2, newPathForPage2, dummyUser1, {}, {
  891. ip: '::ffff:127.0.0.1',
  892. endpoint: '/_api/v3/pages/rename',
  893. activityId: '62e291bc10e0ab61bd691794',
  894. });
  895. }
  896. catch (err) {
  897. isThrown = true;
  898. }
  899. expect(isThrown).toBe(true);
  900. const page2 = await Page.findOne({ path: _path2 }); // not renamed thus exist
  901. const page3 = await Page.findOne({ path: _path3 }); // not renamed thus exist
  902. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // not exist
  903. const page3Renamed = await Page.findOne({ path: newPathForPage3 }); // not exist
  904. expect(page2).toBeTruthy();
  905. expect(page3).toBeTruthy();
  906. expect(page2Renamed).toBeNull();
  907. expect(page3Renamed).toBeNull();
  908. });
  909. test('Should rename/move multiple pages: child page with GRANT_RESTRICTED should NOT be renamed.', async() => {
  910. const _pathD = '/np_rename7_destination';
  911. const _path2 = '/np_rename8';
  912. const _path3 = '/np_rename8/np_rename9';
  913. const _pageD = await Page.findOne({ path: _pathD, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdIsolate });
  914. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED });
  915. const _page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_RESTRICTED });
  916. expect(_pageD).toBeTruthy();
  917. expect(_page2).toBeTruthy();
  918. expect(_page3).toBeTruthy();
  919. const newPathForPage2 = '/np_rename7_destination/np_rename8';
  920. const newpathForPage3 = '/np_rename7_destination/np_rename8/np_rename9';
  921. await renamePage(_page2, newPathForPage2, npDummyUser1, { isRecursively: true }, {
  922. ip: '::ffff:127.0.0.1',
  923. endpoint: '/_api/v3/pages/rename',
  924. activityId: '62e291bc10e0ab61bd691794',
  925. });
  926. const page2 = await Page.findOne({ path: _path2 }); // not exist
  927. const page3 = await Page.findOne({ path: _path3 }); // not renamed thus exist
  928. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // exist
  929. const page3Renamed = await Page.findOne({ path: newpathForPage3 }); // not exist
  930. expect(page2).toBeNull();
  931. expect(page3).toBeTruthy();
  932. expect(page2Renamed).toBeTruthy();
  933. expect(page3Renamed).toBeNull();
  934. expect(page2Renamed.parent).toBeNull();
  935. expect(xssSpy).toHaveBeenCalled();
  936. });
  937. });
  938. describe('Duplicate', () => {
  939. const duplicate = async(page, newPagePath, user, isRecursively) => {
  940. // mock return value
  941. const mockedDuplicateRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'duplicateRecursivelyMainOperation').mockReturnValue(null);
  942. const duplicatedPage = await crowi.pageService.duplicate(page, newPagePath, user, isRecursively);
  943. // retrieve the arguments passed when calling method duplicateRecursivelyMainOperation inside duplicate method
  944. const argsForDuplicateRecursivelyMainOperation = mockedDuplicateRecursivelyMainOperation.mock.calls[0];
  945. // restores the original implementation
  946. mockedDuplicateRecursivelyMainOperation.mockRestore();
  947. // duplicate descendants
  948. if (page.grant !== Page.GRANT_RESTRICTED && isRecursively) {
  949. await crowi.pageService.duplicateRecursivelyMainOperation(...argsForDuplicateRecursivelyMainOperation);
  950. }
  951. return duplicatedPage;
  952. };
  953. test('Duplicate single page with GRANT_RESTRICTED', async() => {
  954. const _page = await Page.findOne({ path: '/np_duplicate1', grant: Page.GRANT_RESTRICTED }).populate({ path: 'revision', model: 'Revision' });
  955. const _revision = _page.revision;
  956. expect(_page).toBeTruthy();
  957. expect(_revision).toBeTruthy();
  958. const newPagePath = '/dup_np_duplicate1';
  959. await duplicate(_page, newPagePath, npDummyUser1, false);
  960. const duplicatedPage = await Page.findOne({ path: newPagePath });
  961. const duplicatedRevision = await Revision.findOne({ pageId: duplicatedPage._id });
  962. expect(xssSpy).toHaveBeenCalled();
  963. expect(duplicatedPage).toBeTruthy();
  964. expect(duplicatedPage._id).not.toStrictEqual(_page._id);
  965. expect(duplicatedPage.grant).toBe(_page.grant);
  966. expect(duplicatedPage.parent).toBeNull();
  967. expect(duplicatedPage.parent).toStrictEqual(_page.parent);
  968. expect(duplicatedPage.revision).toStrictEqual(duplicatedRevision._id);
  969. expect(duplicatedRevision.body).toBe(_revision.body);
  970. });
  971. test('Should duplicate multiple pages with GRANT_USER_GROUP', async() => {
  972. const _path1 = '/np_duplicate2';
  973. const _path2 = '/np_duplicate2/np_duplicate3';
  974. const _page1 = await Page.findOne({ path: _path1, parent: rootPage._id, grantedGroup: groupIdA })
  975. .populate({ path: 'revision', model: 'Revision', grantedPage: groupIdA._id });
  976. const _page2 = await Page.findOne({ path: _path2, parent: _page1._id, grantedGroup: groupIdB })
  977. .populate({ path: 'revision', model: 'Revision', grantedPage: groupIdB._id });
  978. const _revision1 = _page1.revision;
  979. const _revision2 = _page2.revision;
  980. expect(_page1).toBeTruthy();
  981. expect(_page2).toBeTruthy();
  982. expect(_revision1).toBeTruthy();
  983. expect(_revision2).toBeTruthy();
  984. const newPagePath = '/dup_np_duplicate2';
  985. await duplicate(_page1, newPagePath, npDummyUser2, true);
  986. const duplicatedPage1 = await Page.findOne({ path: newPagePath }).populate({ path: 'revision', model: 'Revision' });
  987. const duplicatedPage2 = await Page.findOne({ path: '/dup_np_duplicate2/np_duplicate3' }).populate({ path: 'revision', model: 'Revision' });
  988. const duplicatedRevision1 = duplicatedPage1.revision;
  989. const duplicatedRevision2 = duplicatedPage2.revision;
  990. expect(xssSpy).toHaveBeenCalled();
  991. expect(duplicatedPage1).toBeTruthy();
  992. expect(duplicatedPage2).toBeTruthy();
  993. expect(duplicatedRevision1).toBeTruthy();
  994. expect(duplicatedRevision2).toBeTruthy();
  995. expect(duplicatedPage1.grantedGroup).toStrictEqual(groupIdA._id);
  996. expect(duplicatedPage2.grantedGroup).toStrictEqual(groupIdB._id);
  997. expect(duplicatedPage1.parent).toStrictEqual(_page1.parent);
  998. expect(duplicatedPage2.parent).toStrictEqual(duplicatedPage1._id);
  999. expect(duplicatedRevision1.body).toBe(_revision1.body);
  1000. expect(duplicatedRevision2.body).toBe(_revision2.body);
  1001. expect(duplicatedRevision1.pageId).toStrictEqual(duplicatedPage1._id);
  1002. expect(duplicatedRevision2.pageId).toStrictEqual(duplicatedPage2._id);
  1003. });
  1004. test('Should duplicate multiple pages. Page with GRANT_RESTRICTED should NOT be duplicated', async() => {
  1005. const _path1 = '/np_duplicate4';
  1006. const _path2 = '/np_duplicate4/np_duplicate5';
  1007. const _path3 = '/np_duplicate4/np_duplicate6';
  1008. const _page1 = await Page.findOne({ path: _path1, parent: rootPage._id, grant: Page.GRANT_PUBLIC })
  1009. .populate({ path: 'revision', model: 'Revision' });
  1010. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED }).populate({ path: 'revision', model: 'Revision' });
  1011. const _page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_PUBLIC }).populate({ path: 'revision', model: 'Revision' });
  1012. const baseRevision1 = _page1.revision;
  1013. const baseRevision2 = _page2.revision;
  1014. const baseRevision3 = _page3.revision;
  1015. expect(_page1).toBeTruthy();
  1016. expect(_page2).toBeTruthy();
  1017. expect(_page3).toBeTruthy();
  1018. expect(baseRevision1).toBeTruthy();
  1019. expect(baseRevision2).toBeTruthy();
  1020. const newPagePath = '/dup_np_duplicate4';
  1021. await duplicate(_page1, newPagePath, npDummyUser1, true);
  1022. const duplicatedPage1 = await Page.findOne({ path: newPagePath }).populate({ path: 'revision', model: 'Revision' });
  1023. const duplicatedPage2 = await Page.findOne({ path: '/dup_np_duplicate4/np_duplicate5' }).populate({ path: 'revision', model: 'Revision' });
  1024. const duplicatedPage3 = await Page.findOne({ path: '/dup_np_duplicate4/np_duplicate6' }).populate({ path: 'revision', model: 'Revision' });
  1025. const duplicatedRevision1 = duplicatedPage1.revision;
  1026. const duplicatedRevision3 = duplicatedPage3.revision;
  1027. expect(xssSpy).toHaveBeenCalled();
  1028. expect(duplicatedPage1).toBeTruthy();
  1029. expect(duplicatedPage2).toBeNull();
  1030. expect(duplicatedPage3).toBeTruthy();
  1031. expect(duplicatedRevision1).toBeTruthy();
  1032. expect(duplicatedRevision3).toBeTruthy();
  1033. expect(duplicatedPage1.grant).toStrictEqual(Page.GRANT_PUBLIC);
  1034. expect(duplicatedPage3.grant).toStrictEqual(Page.GRANT_PUBLIC);
  1035. expect(duplicatedPage1.parent).toStrictEqual(_page1.parent);
  1036. expect(duplicatedPage3.parent).toStrictEqual(duplicatedPage1._id);
  1037. expect(duplicatedRevision1.body).toBe(baseRevision1.body);
  1038. expect(duplicatedRevision3.body).toBe(baseRevision3.body);
  1039. expect(duplicatedRevision1.pageId).toStrictEqual(duplicatedPage1._id);
  1040. expect(duplicatedRevision3.pageId).toStrictEqual(duplicatedPage3._id);
  1041. });
  1042. });
  1043. describe('Delete', () => {
  1044. const deletePage = async(page, user, options, isRecursively, activityParameters?) => {
  1045. const mockedDeleteRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteRecursivelyMainOperation').mockReturnValue(null);
  1046. const deletedPage = await crowi.pageService.deletePage(page, user, options, isRecursively, activityParameters);
  1047. const argsForDeleteRecursivelyMainOperation = mockedDeleteRecursivelyMainOperation.mock.calls[0];
  1048. mockedDeleteRecursivelyMainOperation.mockRestore();
  1049. if (isRecursively) {
  1050. await crowi.pageService.deleteRecursivelyMainOperation(...argsForDeleteRecursivelyMainOperation);
  1051. }
  1052. return deletedPage;
  1053. };
  1054. describe('Delete single page with grant RESTRICTED', () => {
  1055. test('should be able to delete', async() => {
  1056. const _pathT = '/npdel1_awl';
  1057. const _pageT = await Page.findOne({ path: _pathT, grant: Page.GRANT_RESTRICTED });
  1058. expect(_pageT).toBeTruthy();
  1059. const isRecursively = false;
  1060. await deletePage(_pageT, dummyUser1, {}, isRecursively, {
  1061. ip: '::ffff:127.0.0.1',
  1062. endpoint: '/_api/v3/pages/rename',
  1063. });
  1064. const pageT = await Page.findOne({ path: `/trash${_pathT}` });
  1065. const pageN = await Page.findOne({ path: _pathT }); // should not exist
  1066. expect(pageT).toBeTruthy();
  1067. expect(pageN).toBeNull();
  1068. expect(pageT.grant).toBe(Page.GRANT_RESTRICTED);
  1069. expect(pageT.status).toBe(Page.STATUS_DELETED);
  1070. });
  1071. });
  1072. describe('Delete single page with grant USER_GROUP', () => {
  1073. test('should be able to delete', async() => {
  1074. const _path = '/npdel2_ug';
  1075. const _page1 = await Page.findOne({ path: _path, grantedGroup: groupIdA });
  1076. expect(_page1).toBeTruthy();
  1077. const isRecursively = false;
  1078. await deletePage(_page1, npDummyUser1, {}, isRecursively, {
  1079. ip: '::ffff:127.0.0.1',
  1080. endpoint: '/_api/v3/pages/rename',
  1081. });
  1082. const pageN = await Page.findOne({ path: _path, grantedGroup: groupIdA });
  1083. const page1 = await Page.findOne({ path: `/trash${_path}`, grantedGroup: groupIdA });
  1084. expect(pageN).toBeNull();
  1085. expect(page1).toBeTruthy();
  1086. expect(page1.status).toBe(Page.STATUS_DELETED);
  1087. expect(page1.descendantCount).toBe(0);
  1088. expect(page1.parent).toBeNull();
  1089. });
  1090. });
  1091. describe('Delete multiple pages with grant USER_GROUP', () => {
  1092. test('should be able to delete all descendants except page with GRANT_RESTRICTED', async() => {
  1093. const _pathT = '/npdel3_top';
  1094. const _path1 = '/npdel3_top/npdel4_ug';
  1095. const _path2 = '/npdel3_top/npdel4_ug/npdel5_ug';
  1096. const _pageT = await Page.findOne({ path: _pathT, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA }); // A
  1097. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB }); // B
  1098. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC }); // C
  1099. const _pageR = await Page.findOne({ path: _path1, grant: Page.GRANT_RESTRICTED }); // Restricted
  1100. expect(_pageT).toBeTruthy();
  1101. expect(_page1).toBeTruthy();
  1102. expect(_page2).toBeTruthy();
  1103. expect(_pageR).toBeTruthy();
  1104. const isRecursively = true;
  1105. await deletePage(_pageT, npDummyUser1, {}, isRecursively, {
  1106. ip: '::ffff:127.0.0.1',
  1107. endpoint: '/_api/v3/pages/rename',
  1108. });
  1109. const pageTNotExist = await Page.findOne({ path: _pathT, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA }); // A should not exist
  1110. const page1NotExist = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB }); // B should not exist
  1111. const page2NotExist = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC }); // C should not exist
  1112. const pageT = await Page.findOne({ path: `/trash${_pathT}`, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA }); // A
  1113. const page1 = await Page.findOne({ path: `/trash${_path1}`, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB }); // B
  1114. const page2 = await Page.findOne({ path: `/trash${_path2}`, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC }); // C
  1115. const pageR = await Page.findOne({ path: _path1, grant: Page.GRANT_RESTRICTED }); // Restricted
  1116. expect(page1NotExist).toBeNull();
  1117. expect(pageTNotExist).toBeNull();
  1118. expect(page2NotExist).toBeNull();
  1119. expect(pageT).toBeTruthy();
  1120. expect(page1).toBeTruthy();
  1121. expect(page2).toBeTruthy();
  1122. expect(pageR).toBeTruthy();
  1123. expect(pageT.status).toBe(Page.STATUS_DELETED);
  1124. expect(pageT.status).toBe(Page.STATUS_DELETED);
  1125. expect(page1.status).toBe(Page.STATUS_DELETED);
  1126. expect(page1.descendantCount).toBe(0);
  1127. expect(page2.descendantCount).toBe(0);
  1128. expect(page2.descendantCount).toBe(0);
  1129. expect(pageT.parent).toBeNull();
  1130. expect(page1.parent).toBeNull();
  1131. expect(page2.parent).toBeNull();
  1132. });
  1133. });
  1134. });
  1135. describe('Delete completely', () => {
  1136. const deleteCompletely = async(page, user, options = {}, isRecursively = false, preventEmitting = false, activityParameters?) => {
  1137. const mockedDeleteCompletelyRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteCompletelyRecursivelyMainOperation').mockReturnValue(null);
  1138. await crowi.pageService.deleteCompletely(page, user, options, isRecursively, preventEmitting, activityParameters);
  1139. const argsForDeleteCompletelyRecursivelyMainOperation = mockedDeleteCompletelyRecursivelyMainOperation.mock.calls[0];
  1140. mockedDeleteCompletelyRecursivelyMainOperation.mockRestore();
  1141. if (isRecursively) {
  1142. await crowi.pageService.deleteCompletelyRecursivelyMainOperation(...argsForDeleteCompletelyRecursivelyMainOperation);
  1143. }
  1144. return;
  1145. };
  1146. describe('Delete single page with grant RESTRICTED', () => {
  1147. test('should be able to delete completely', async() => {
  1148. const _path = '/npdc1_awl';
  1149. const _page = await Page.findOne({ path: _path, grant: Page.GRANT_RESTRICTED });
  1150. expect(_page).toBeTruthy();
  1151. await deleteCompletely(_page, dummyUser1, {}, false, false, {
  1152. ip: '::ffff:127.0.0.1',
  1153. endpoint: '/_api/v3/pages/rename',
  1154. });
  1155. const page = await Page.findOne({ path: _path, grant: Page.GRANT_RESTRICTED });
  1156. expect(page).toBeNull();
  1157. });
  1158. });
  1159. describe('Delete single page with grant USER_GROUP', () => {
  1160. test('should be able to delete completely', async() => {
  1161. const _path = '/npdc2_ug';
  1162. const _page = await Page.findOne({ path: _path, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1163. expect(_page).toBeTruthy();
  1164. await deleteCompletely(_page, npDummyUser1, {}, false, false, {
  1165. ip: '::ffff:127.0.0.1',
  1166. endpoint: '/_api/v3/pages/rename',
  1167. });
  1168. const page = await Page.findOne({ path: _path, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1169. expect(page).toBeNull();
  1170. });
  1171. });
  1172. describe('Delete multiple pages with grant USER_GROUP', () => {
  1173. test('should be able to delete all descendants completely except page with GRANT_RESTRICTED', async() => {
  1174. const _path1 = '/npdc3_ug';
  1175. const _path2 = '/npdc3_ug/npdc4_ug';
  1176. const _path3 = '/npdc3_ug/npdc4_ug/npdc5_ug';
  1177. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1178. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB });
  1179. const _page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC });
  1180. const _page4 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED });
  1181. expect(_page1).toBeTruthy();
  1182. expect(_page2).toBeTruthy();
  1183. expect(_page3).toBeTruthy();
  1184. expect(_page4).toBeTruthy();
  1185. await deleteCompletely(_page1, npDummyUser1, {}, true, false, {
  1186. ip: '::ffff:127.0.0.1',
  1187. endpoint: '/_api/v3/pages/rename',
  1188. });
  1189. const page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1190. const page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB });
  1191. const page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC });
  1192. const page4 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED });
  1193. expect(page1).toBeNull();
  1194. expect(page2).toBeNull();
  1195. expect(page3).toBeNull();
  1196. expect(page4).toBeTruthy();
  1197. });
  1198. });
  1199. });
  1200. describe('revert', () => {
  1201. const revertDeletedPage = async(page, user, options = {}, isRecursively = false, activityParameters?) => {
  1202. // mock return value
  1203. const mockedRevertRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'revertRecursivelyMainOperation').mockReturnValue(null);
  1204. const revertedPage = await crowi.pageService.revertDeletedPage(page, user, options, isRecursively, activityParameters);
  1205. const argsForRecursivelyMainOperation = mockedRevertRecursivelyMainOperation.mock.calls[0];
  1206. // restores the original implementation
  1207. mockedRevertRecursivelyMainOperation.mockRestore();
  1208. if (isRecursively) {
  1209. await crowi.pageService.revertRecursivelyMainOperation(...argsForRecursivelyMainOperation);
  1210. }
  1211. return revertedPage;
  1212. };
  1213. test('should revert single deleted page with GRANT_RESTRICTED', async() => {
  1214. const trashedPage = await Page.findOne({ path: '/trash/np_revert1', status: Page.STATUS_DELETED, grant: Page.GRANT_RESTRICTED });
  1215. const revision = await Revision.findOne({ pageId: trashedPage._id });
  1216. const tag = await Tag.findOne({ name: 'np_revertTag1' });
  1217. const deletedPageTagRelation = await PageTagRelation.findOne({ relatedPage: trashedPage._id, relatedTag: tag?._id, isPageTrashed: true });
  1218. expect(trashedPage).toBeTruthy();
  1219. expect(revision).toBeTruthy();
  1220. expect(tag).toBeTruthy();
  1221. expect(deletedPageTagRelation).toBeTruthy();
  1222. await revertDeletedPage(trashedPage, dummyUser1, {}, false, {
  1223. ip: '::ffff:127.0.0.1',
  1224. endpoint: '/_api/v3/pages/rename',
  1225. });
  1226. const revertedPage = await Page.findOne({ path: '/np_revert1' });
  1227. const deltedPageBeforeRevert = await Page.findOne({ path: '/trash/np_revert1' });
  1228. const pageTagRelation = await PageTagRelation.findOne({ relatedPage: revertedPage._id, relatedTag: tag?._id });
  1229. expect(revertedPage).toBeTruthy();
  1230. expect(pageTagRelation).toBeTruthy();
  1231. expect(deltedPageBeforeRevert).toBeNull();
  1232. // page with GRANT_RESTRICTED does not have parent
  1233. expect(revertedPage.parent).toBeNull();
  1234. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1235. expect(revertedPage.grant).toBe(Page.GRANT_RESTRICTED);
  1236. expect(pageTagRelation.isPageTrashed).toBe(false);
  1237. });
  1238. test('should revert single deleted page with GRANT_USER_GROUP', async() => {
  1239. const beforeRevertPath = '/trash/np_revert2';
  1240. const user1 = await User.findOne({ name: 'npUser1' });
  1241. const trashedPage = await Page.findOne({ path: beforeRevertPath, status: Page.STATUS_DELETED, grant: Page.GRANT_USER_GROUP });
  1242. const revision = await Revision.findOne({ pageId: trashedPage._id });
  1243. const tag = await Tag.findOne({ name: 'np_revertTag2' });
  1244. const deletedPageTagRelation = await PageTagRelation.findOne({ relatedPage: trashedPage._id, relatedTag: tag?._id, isPageTrashed: true });
  1245. expect(trashedPage).toBeTruthy();
  1246. expect(revision).toBeTruthy();
  1247. expect(tag).toBeTruthy();
  1248. expect(deletedPageTagRelation).toBeTruthy();
  1249. await revertDeletedPage(trashedPage, user1, {}, false, {
  1250. ip: '::ffff:127.0.0.1',
  1251. endpoint: '/_api/v3/pages/revert',
  1252. });
  1253. const revertedPage = await Page.findOne({ path: '/np_revert2' });
  1254. const trashedPageBR = await Page.findOne({ path: beforeRevertPath });
  1255. const pageTagRelation = await PageTagRelation.findOne({ relatedPage: revertedPage._id, relatedTag: tag?._id });
  1256. expect(revertedPage).toBeTruthy();
  1257. expect(pageTagRelation).toBeTruthy();
  1258. expect(trashedPageBR).toBeNull();
  1259. expect(revertedPage.parent).toStrictEqual(rootPage._id);
  1260. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1261. expect(revertedPage.grant).toBe(Page.GRANT_USER_GROUP);
  1262. expect(revertedPage.grantedGroup).toStrictEqual(groupIdA);
  1263. expect(pageTagRelation.isPageTrashed).toBe(false);
  1264. });
  1265. test(`revert multiple pages: only target page should be reverted.
  1266. Non-existant middle page and leaf page with GRANT_RESTRICTED shoud not be reverted`, async() => {
  1267. const beforeRevertPath1 = '/trash/np_revert3';
  1268. const beforeRevertPath2 = '/trash/np_revert3/middle/np_revert4';
  1269. const trashedPage1 = await Page.findOne({ path: beforeRevertPath1, status: Page.STATUS_DELETED, grant: Page.GRANT_PUBLIC });
  1270. const trashedPage2 = await Page.findOne({ path: beforeRevertPath2, status: Page.STATUS_DELETED, grant: Page.GRANT_RESTRICTED });
  1271. const revision1 = await Revision.findOne({ pageId: trashedPage1._id });
  1272. const revision2 = await Revision.findOne({ pageId: trashedPage2._id });
  1273. expect(trashedPage1).toBeTruthy();
  1274. expect(trashedPage2).toBeTruthy();
  1275. expect(revision1).toBeTruthy();
  1276. expect(revision2).toBeTruthy();
  1277. await revertDeletedPage(trashedPage1, npDummyUser2, {}, true, {
  1278. ip: '::ffff:127.0.0.1',
  1279. endpoint: '/_api/v3/pages/revert',
  1280. });
  1281. const revertedPage = await Page.findOne({ path: '/np_revert3' });
  1282. const middlePage = await Page.findOne({ path: '/np_revert3/middle' });
  1283. const notRestrictedPage = await Page.findOne({ path: '/np_revert3/middle/np_revert4' });
  1284. // AR => After Revert
  1285. const trashedPage1AR = await Page.findOne({ path: beforeRevertPath1 });
  1286. const trashedPage2AR = await Page.findOne({ path: beforeRevertPath2 });
  1287. const revision1AR = await Revision.findOne({ pageId: revertedPage._id });
  1288. const revision2AR = await Revision.findOne({ pageId: trashedPage2AR._id });
  1289. expect(revertedPage).toBeTruthy();
  1290. expect(trashedPage2AR).toBeTruthy();
  1291. expect(revision1AR).toBeTruthy();
  1292. expect(revision2AR).toBeTruthy();
  1293. expect(trashedPage1AR).toBeNull();
  1294. expect(notRestrictedPage).toBeNull();
  1295. expect(middlePage).toBeNull();
  1296. expect(revertedPage.parent).toStrictEqual(rootPage._id);
  1297. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1298. expect(revertedPage.grant).toBe(Page.GRANT_PUBLIC);
  1299. });
  1300. test('revert multiple pages: target page, initially non-existant page and leaf page with GRANT_USER_GROUP shoud be reverted', async() => {
  1301. const user = await User.findOne({ _id: npDummyUser3 });
  1302. const beforeRevertPath1 = '/trash/np_revert5';
  1303. const beforeRevertPath2 = '/trash/np_revert5/middle/np_revert6';
  1304. const beforeRevertPath3 = '/trash/np_revert5/middle';
  1305. const trashedPage1 = await Page.findOne({ path: beforeRevertPath1, status: Page.STATUS_DELETED, grantedGroup: groupIdA });
  1306. const trashedPage2 = await Page.findOne({ path: beforeRevertPath2, status: Page.STATUS_DELETED, grantedGroup: groupIdB });
  1307. const nonExistantPage3 = await Page.findOne({ path: beforeRevertPath3 }); // not exist
  1308. const revision1 = await Revision.findOne({ pageId: trashedPage1._id });
  1309. const revision2 = await Revision.findOne({ pageId: trashedPage2._id });
  1310. expect(trashedPage1).toBeTruthy();
  1311. expect(trashedPage2).toBeTruthy();
  1312. expect(revision1).toBeTruthy();
  1313. expect(revision2).toBeTruthy();
  1314. expect(user).toBeTruthy();
  1315. expect(nonExistantPage3).toBeNull();
  1316. await revertDeletedPage(trashedPage1, user, {}, true, {
  1317. ip: '::ffff:127.0.0.1',
  1318. endpoint: '/_api/v3/pages/revert',
  1319. });
  1320. const revertedPage1 = await Page.findOne({ path: '/np_revert5' });
  1321. const newlyCreatedPage = await Page.findOne({ path: '/np_revert5/middle' });
  1322. const revertedPage2 = await Page.findOne({ path: '/np_revert5/middle/np_revert6' });
  1323. // // AR => After Revert
  1324. const trashedPage1AR = await Page.findOne({ path: beforeRevertPath1 });
  1325. const trashedPage2AR = await Page.findOne({ path: beforeRevertPath2 });
  1326. expect(revertedPage1).toBeTruthy();
  1327. expect(newlyCreatedPage).toBeTruthy();
  1328. expect(revertedPage2).toBeTruthy();
  1329. expect(trashedPage1AR).toBeNull();
  1330. expect(trashedPage2AR).toBeNull();
  1331. expect(newlyCreatedPage.isEmpty).toBe(true);
  1332. expect(revertedPage1.parent).toStrictEqual(rootPage._id);
  1333. expect(revertedPage2.parent).toStrictEqual(newlyCreatedPage._id);
  1334. expect(newlyCreatedPage.parent).toStrictEqual(revertedPage1._id);
  1335. expect(revertedPage1.status).toBe(Page.STATUS_PUBLISHED);
  1336. expect(revertedPage2.status).toBe(Page.STATUS_PUBLISHED);
  1337. expect(newlyCreatedPage.status).toBe(Page.STATUS_PUBLISHED);
  1338. expect(revertedPage1.grantedGroup).toStrictEqual(groupIdA);
  1339. expect(revertedPage2.grantedGroup).toStrictEqual(groupIdB);
  1340. expect(newlyCreatedPage.grant).toBe(Page.GRANT_PUBLIC);
  1341. });
  1342. });
  1343. });