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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414
  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) => {
  824. // mock return value
  825. const mockedRenameSubOperation = jest.spyOn(crowi.pageService, 'renameSubOperation').mockReturnValue(null);
  826. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  827. const renamedPage = await crowi.pageService.renamePage(page, newPagePath, user, options);
  828. // retrieve the arguments passed when calling method renameSubOperation inside renamePage method
  829. const argsForRenameSubOperation = mockedRenameSubOperation.mock.calls[0];
  830. // restores the original implementation
  831. mockedRenameSubOperation.mockRestore();
  832. mockedCreateAndSendNotifications.mockRestore();
  833. // rename descendants
  834. if (page.grant !== Page.GRANT_RESTRICTED) {
  835. await crowi.pageService.renameSubOperation(...argsForRenameSubOperation);
  836. }
  837. return renamedPage;
  838. };
  839. test('Should rename/move with descendants with grant normalized pages', async() => {
  840. const _pathD = '/np_rename1_destination';
  841. const _path2 = '/np_rename2';
  842. const _path3 = '/np_rename2/np_rename3';
  843. const _propertiesD = { grant: Page.GRANT_PUBLIC };
  844. const _properties2 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB };
  845. const _properties3 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC };
  846. const _pageD = await Page.findOne({ path: _pathD, ..._propertiesD });
  847. const _page2 = await Page.findOne({ path: _path2, ..._properties2 });
  848. const _page3 = await Page.findOne({ path: _path3, ..._properties3, parent: _page2._id });
  849. expect(_pageD).toBeTruthy();
  850. expect(_page2).toBeTruthy();
  851. expect(_page3).toBeTruthy();
  852. const newPathForPage2 = '/np_rename1_destination/np_rename2';
  853. const newPathForPage3 = '/np_rename1_destination/np_rename2/np_rename3';
  854. await renamePage(_page2, newPathForPage2, npDummyUser2, {});
  855. const pageD = await Page.findOne({ path: _pathD, ..._propertiesD });
  856. const page2 = await Page.findOne({ path: _path2, ..._properties2 }); // not exist
  857. const page3 = await Page.findOne({ path: _path3, ..._properties3, parent: _page2._id }); // not exist
  858. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // renamed
  859. const page3Renamed = await Page.findOne({ path: newPathForPage3 }); // renamed
  860. expect(pageD).toBeTruthy();
  861. expect(page2).toBeNull();
  862. expect(page3).toBeNull();
  863. expect(page2Renamed).toBeTruthy();
  864. expect(page3Renamed).toBeTruthy();
  865. expect(page2Renamed.parent).toStrictEqual(_pageD._id);
  866. expect(page3Renamed.parent).toStrictEqual(page2Renamed._id);
  867. expect(page2Renamed.grantedGroup).toStrictEqual(_page2.grantedGroup);
  868. expect(page3Renamed.grantedGroup).toStrictEqual(_page3.grantedGroup);
  869. expect(xssSpy).toHaveBeenCalled();
  870. });
  871. test('Should throw with NOT grant normalized pages', async() => {
  872. const _pathD = '/np_rename4_destination';
  873. const _path2 = '/np_rename5';
  874. const _path3 = '/np_rename5/np_rename6';
  875. const _propertiesD = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdIsolate };
  876. const _properties2 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB };
  877. const _properties3 = { grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB };
  878. const _pageD = await Page.findOne({ path: _pathD, ..._propertiesD });// isolate
  879. const _page2 = await Page.findOne({ path: _path2, ..._properties2 });// groupIdB
  880. const _page3 = await Page.findOne({ path: _path3, ..._properties3, parent: _page2 });// groupIdB
  881. expect(_pageD).toBeTruthy();
  882. expect(_page2).toBeTruthy();
  883. expect(_page3).toBeTruthy();
  884. const newPathForPage2 = '/np_rename4_destination/np_rename5';
  885. const newPathForPage3 = '/np_rename4_destination/np_rename5/np_rename6';
  886. let isThrown = false;
  887. try {
  888. await renamePage(_page2, newPathForPage2, dummyUser1, {});
  889. }
  890. catch (err) {
  891. isThrown = true;
  892. }
  893. expect(isThrown).toBe(true);
  894. const page2 = await Page.findOne({ path: _path2 }); // not renamed thus exist
  895. const page3 = await Page.findOne({ path: _path3 }); // not renamed thus exist
  896. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // not exist
  897. const page3Renamed = await Page.findOne({ path: newPathForPage3 }); // not exist
  898. expect(page2).toBeTruthy();
  899. expect(page3).toBeTruthy();
  900. expect(page2Renamed).toBeNull();
  901. expect(page3Renamed).toBeNull();
  902. });
  903. test('Should rename/move multiple pages: child page with GRANT_RESTRICTED should NOT be renamed.', async() => {
  904. const _pathD = '/np_rename7_destination';
  905. const _path2 = '/np_rename8';
  906. const _path3 = '/np_rename8/np_rename9';
  907. const _pageD = await Page.findOne({ path: _pathD, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdIsolate });
  908. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED });
  909. const _page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_RESTRICTED });
  910. expect(_pageD).toBeTruthy();
  911. expect(_page2).toBeTruthy();
  912. expect(_page3).toBeTruthy();
  913. const newPathForPage2 = '/np_rename7_destination/np_rename8';
  914. const newpathForPage3 = '/np_rename7_destination/np_rename8/np_rename9';
  915. await renamePage(_page2, newPathForPage2, npDummyUser1, { isRecursively: true });
  916. const page2 = await Page.findOne({ path: _path2 }); // not exist
  917. const page3 = await Page.findOne({ path: _path3 }); // not renamed thus exist
  918. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // exist
  919. const page3Renamed = await Page.findOne({ path: newpathForPage3 }); // not exist
  920. expect(page2).toBeNull();
  921. expect(page3).toBeTruthy();
  922. expect(page2Renamed).toBeTruthy();
  923. expect(page3Renamed).toBeNull();
  924. expect(page2Renamed.parent).toBeNull();
  925. expect(xssSpy).toHaveBeenCalled();
  926. });
  927. });
  928. describe('Duplicate', () => {
  929. const duplicate = async(page, newPagePath, user, isRecursively) => {
  930. // mock return value
  931. const mockedDuplicateRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'duplicateRecursivelyMainOperation').mockReturnValue(null);
  932. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  933. const duplicatedPage = await crowi.pageService.duplicate(page, newPagePath, user, isRecursively);
  934. // retrieve the arguments passed when calling method duplicateRecursivelyMainOperation inside duplicate method
  935. const argsForDuplicateRecursivelyMainOperation = mockedDuplicateRecursivelyMainOperation.mock.calls[0];
  936. // restores the original implementation
  937. mockedDuplicateRecursivelyMainOperation.mockRestore();
  938. mockedCreateAndSendNotifications.mockRestore();
  939. // duplicate descendants
  940. if (page.grant !== Page.GRANT_RESTRICTED && isRecursively) {
  941. await crowi.pageService.duplicateRecursivelyMainOperation(...argsForDuplicateRecursivelyMainOperation);
  942. }
  943. return duplicatedPage;
  944. };
  945. test('Duplicate single page with GRANT_RESTRICTED', async() => {
  946. const _page = await Page.findOne({ path: '/np_duplicate1', grant: Page.GRANT_RESTRICTED }).populate({ path: 'revision', model: 'Revision' });
  947. const _revision = _page.revision;
  948. expect(_page).toBeTruthy();
  949. expect(_revision).toBeTruthy();
  950. const newPagePath = '/dup_np_duplicate1';
  951. await duplicate(_page, newPagePath, npDummyUser1, false);
  952. const duplicatedPage = await Page.findOne({ path: newPagePath });
  953. const duplicatedRevision = await Revision.findOne({ pageId: duplicatedPage._id });
  954. expect(xssSpy).toHaveBeenCalled();
  955. expect(duplicatedPage).toBeTruthy();
  956. expect(duplicatedPage._id).not.toStrictEqual(_page._id);
  957. expect(duplicatedPage.grant).toBe(_page.grant);
  958. expect(duplicatedPage.parent).toBeNull();
  959. expect(duplicatedPage.parent).toStrictEqual(_page.parent);
  960. expect(duplicatedPage.revision).toStrictEqual(duplicatedRevision._id);
  961. expect(duplicatedRevision.body).toBe(_revision.body);
  962. });
  963. test('Should duplicate multiple pages with GRANT_USER_GROUP', async() => {
  964. const _path1 = '/np_duplicate2';
  965. const _path2 = '/np_duplicate2/np_duplicate3';
  966. const _page1 = await Page.findOne({ path: _path1, parent: rootPage._id, grantedGroup: groupIdA })
  967. .populate({ path: 'revision', model: 'Revision', grantedPage: groupIdA._id });
  968. const _page2 = await Page.findOne({ path: _path2, parent: _page1._id, grantedGroup: groupIdB })
  969. .populate({ path: 'revision', model: 'Revision', grantedPage: groupIdB._id });
  970. const _revision1 = _page1.revision;
  971. const _revision2 = _page2.revision;
  972. expect(_page1).toBeTruthy();
  973. expect(_page2).toBeTruthy();
  974. expect(_revision1).toBeTruthy();
  975. expect(_revision2).toBeTruthy();
  976. const newPagePath = '/dup_np_duplicate2';
  977. await duplicate(_page1, newPagePath, npDummyUser2, true);
  978. const duplicatedPage1 = await Page.findOne({ path: newPagePath }).populate({ path: 'revision', model: 'Revision' });
  979. const duplicatedPage2 = await Page.findOne({ path: '/dup_np_duplicate2/np_duplicate3' }).populate({ path: 'revision', model: 'Revision' });
  980. const duplicatedRevision1 = duplicatedPage1.revision;
  981. const duplicatedRevision2 = duplicatedPage2.revision;
  982. expect(xssSpy).toHaveBeenCalled();
  983. expect(duplicatedPage1).toBeTruthy();
  984. expect(duplicatedPage2).toBeTruthy();
  985. expect(duplicatedRevision1).toBeTruthy();
  986. expect(duplicatedRevision2).toBeTruthy();
  987. expect(duplicatedPage1.grantedGroup).toStrictEqual(groupIdA._id);
  988. expect(duplicatedPage2.grantedGroup).toStrictEqual(groupIdB._id);
  989. expect(duplicatedPage1.parent).toStrictEqual(_page1.parent);
  990. expect(duplicatedPage2.parent).toStrictEqual(duplicatedPage1._id);
  991. expect(duplicatedRevision1.body).toBe(_revision1.body);
  992. expect(duplicatedRevision2.body).toBe(_revision2.body);
  993. expect(duplicatedRevision1.pageId).toStrictEqual(duplicatedPage1._id);
  994. expect(duplicatedRevision2.pageId).toStrictEqual(duplicatedPage2._id);
  995. });
  996. test('Should duplicate multiple pages. Page with GRANT_RESTRICTED should NOT be duplicated', async() => {
  997. const _path1 = '/np_duplicate4';
  998. const _path2 = '/np_duplicate4/np_duplicate5';
  999. const _path3 = '/np_duplicate4/np_duplicate6';
  1000. const _page1 = await Page.findOne({ path: _path1, parent: rootPage._id, grant: Page.GRANT_PUBLIC })
  1001. .populate({ path: 'revision', model: 'Revision' });
  1002. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED }).populate({ path: 'revision', model: 'Revision' });
  1003. const _page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_PUBLIC }).populate({ path: 'revision', model: 'Revision' });
  1004. const baseRevision1 = _page1.revision;
  1005. const baseRevision2 = _page2.revision;
  1006. const baseRevision3 = _page3.revision;
  1007. expect(_page1).toBeTruthy();
  1008. expect(_page2).toBeTruthy();
  1009. expect(_page3).toBeTruthy();
  1010. expect(baseRevision1).toBeTruthy();
  1011. expect(baseRevision2).toBeTruthy();
  1012. const newPagePath = '/dup_np_duplicate4';
  1013. await duplicate(_page1, newPagePath, npDummyUser1, true);
  1014. const duplicatedPage1 = await Page.findOne({ path: newPagePath }).populate({ path: 'revision', model: 'Revision' });
  1015. const duplicatedPage2 = await Page.findOne({ path: '/dup_np_duplicate4/np_duplicate5' }).populate({ path: 'revision', model: 'Revision' });
  1016. const duplicatedPage3 = await Page.findOne({ path: '/dup_np_duplicate4/np_duplicate6' }).populate({ path: 'revision', model: 'Revision' });
  1017. const duplicatedRevision1 = duplicatedPage1.revision;
  1018. const duplicatedRevision3 = duplicatedPage3.revision;
  1019. expect(xssSpy).toHaveBeenCalled();
  1020. expect(duplicatedPage1).toBeTruthy();
  1021. expect(duplicatedPage2).toBeNull();
  1022. expect(duplicatedPage3).toBeTruthy();
  1023. expect(duplicatedRevision1).toBeTruthy();
  1024. expect(duplicatedRevision3).toBeTruthy();
  1025. expect(duplicatedPage1.grant).toStrictEqual(Page.GRANT_PUBLIC);
  1026. expect(duplicatedPage3.grant).toStrictEqual(Page.GRANT_PUBLIC);
  1027. expect(duplicatedPage1.parent).toStrictEqual(_page1.parent);
  1028. expect(duplicatedPage3.parent).toStrictEqual(duplicatedPage1._id);
  1029. expect(duplicatedRevision1.body).toBe(baseRevision1.body);
  1030. expect(duplicatedRevision3.body).toBe(baseRevision3.body);
  1031. expect(duplicatedRevision1.pageId).toStrictEqual(duplicatedPage1._id);
  1032. expect(duplicatedRevision3.pageId).toStrictEqual(duplicatedPage3._id);
  1033. });
  1034. });
  1035. describe('Delete', () => {
  1036. const deletePage = async(page, user, options, isRecursively) => {
  1037. const mockedDeleteRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteRecursivelyMainOperation').mockReturnValue(null);
  1038. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1039. const deletedPage = await crowi.pageService.deletePage(page, user, options, isRecursively);
  1040. const argsForDeleteRecursivelyMainOperation = mockedDeleteRecursivelyMainOperation.mock.calls[0];
  1041. mockedDeleteRecursivelyMainOperation.mockRestore();
  1042. mockedCreateAndSendNotifications.mockRestore();
  1043. if (isRecursively) {
  1044. await crowi.pageService.deleteRecursivelyMainOperation(...argsForDeleteRecursivelyMainOperation);
  1045. }
  1046. return deletedPage;
  1047. };
  1048. describe('Delete single page with grant RESTRICTED', () => {
  1049. test('should be able to delete', async() => {
  1050. const _pathT = '/npdel1_awl';
  1051. const _pageT = await Page.findOne({ path: _pathT, grant: Page.GRANT_RESTRICTED });
  1052. expect(_pageT).toBeTruthy();
  1053. const isRecursively = false;
  1054. await deletePage(_pageT, dummyUser1, {}, isRecursively);
  1055. const pageT = await Page.findOne({ path: `/trash${_pathT}` });
  1056. const pageN = await Page.findOne({ path: _pathT }); // should not exist
  1057. expect(pageT).toBeTruthy();
  1058. expect(pageN).toBeNull();
  1059. expect(pageT.grant).toBe(Page.GRANT_RESTRICTED);
  1060. expect(pageT.status).toBe(Page.STATUS_DELETED);
  1061. });
  1062. });
  1063. describe('Delete single page with grant USER_GROUP', () => {
  1064. test('should be able to delete', async() => {
  1065. const _path = '/npdel2_ug';
  1066. const _page1 = await Page.findOne({ path: _path, grantedGroup: groupIdA });
  1067. expect(_page1).toBeTruthy();
  1068. const isRecursively = false;
  1069. await deletePage(_page1, npDummyUser1, {}, isRecursively);
  1070. const pageN = await Page.findOne({ path: _path, grantedGroup: groupIdA });
  1071. const page1 = await Page.findOne({ path: `/trash${_path}`, grantedGroup: groupIdA });
  1072. expect(pageN).toBeNull();
  1073. expect(page1).toBeTruthy();
  1074. expect(page1.status).toBe(Page.STATUS_DELETED);
  1075. expect(page1.descendantCount).toBe(0);
  1076. expect(page1.parent).toBeNull();
  1077. });
  1078. });
  1079. describe('Delete multiple pages with grant USER_GROUP', () => {
  1080. test('should be able to delete all descendants except page with GRANT_RESTRICTED', async() => {
  1081. const _pathT = '/npdel3_top';
  1082. const _path1 = '/npdel3_top/npdel4_ug';
  1083. const _path2 = '/npdel3_top/npdel4_ug/npdel5_ug';
  1084. const _pageT = await Page.findOne({ path: _pathT, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA }); // A
  1085. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB }); // B
  1086. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC }); // C
  1087. const _pageR = await Page.findOne({ path: _path1, grant: Page.GRANT_RESTRICTED }); // Restricted
  1088. expect(_pageT).toBeTruthy();
  1089. expect(_page1).toBeTruthy();
  1090. expect(_page2).toBeTruthy();
  1091. expect(_pageR).toBeTruthy();
  1092. const isRecursively = true;
  1093. await deletePage(_pageT, npDummyUser1, {}, isRecursively);
  1094. const pageTNotExist = await Page.findOne({ path: _pathT, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA }); // A should not exist
  1095. const page1NotExist = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB }); // B should not exist
  1096. const page2NotExist = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC }); // C should not exist
  1097. const pageT = await Page.findOne({ path: `/trash${_pathT}`, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA }); // A
  1098. const page1 = await Page.findOne({ path: `/trash${_path1}`, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB }); // B
  1099. const page2 = await Page.findOne({ path: `/trash${_path2}`, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC }); // C
  1100. const pageR = await Page.findOne({ path: _path1, grant: Page.GRANT_RESTRICTED }); // Restricted
  1101. expect(page1NotExist).toBeNull();
  1102. expect(pageTNotExist).toBeNull();
  1103. expect(page2NotExist).toBeNull();
  1104. expect(pageT).toBeTruthy();
  1105. expect(page1).toBeTruthy();
  1106. expect(page2).toBeTruthy();
  1107. expect(pageR).toBeTruthy();
  1108. expect(pageT.status).toBe(Page.STATUS_DELETED);
  1109. expect(pageT.status).toBe(Page.STATUS_DELETED);
  1110. expect(page1.status).toBe(Page.STATUS_DELETED);
  1111. expect(page1.descendantCount).toBe(0);
  1112. expect(page2.descendantCount).toBe(0);
  1113. expect(page2.descendantCount).toBe(0);
  1114. expect(pageT.parent).toBeNull();
  1115. expect(page1.parent).toBeNull();
  1116. expect(page2.parent).toBeNull();
  1117. });
  1118. });
  1119. });
  1120. describe('Delete completely', () => {
  1121. const deleteCompletely = async(page, user, options = {}, isRecursively = false, preventEmitting = false) => {
  1122. const mockedDeleteCompletelyRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'deleteCompletelyRecursivelyMainOperation').mockReturnValue(null);
  1123. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  1124. await crowi.pageService.deleteCompletely(page, user, options, isRecursively, preventEmitting);
  1125. const argsForDeleteCompletelyRecursivelyMainOperation = mockedDeleteCompletelyRecursivelyMainOperation.mock.calls[0];
  1126. mockedDeleteCompletelyRecursivelyMainOperation.mockRestore();
  1127. mockedCreateAndSendNotifications.mockRestore();
  1128. if (isRecursively) {
  1129. await crowi.pageService.deleteCompletelyRecursivelyMainOperation(...argsForDeleteCompletelyRecursivelyMainOperation);
  1130. }
  1131. return;
  1132. };
  1133. describe('Delete single page with grant RESTRICTED', () => {
  1134. test('should be able to delete completely', async() => {
  1135. const _path = '/npdc1_awl';
  1136. const _page = await Page.findOne({ path: _path, grant: Page.GRANT_RESTRICTED });
  1137. expect(_page).toBeTruthy();
  1138. await deleteCompletely(_page, dummyUser1, {}, false);
  1139. const page = await Page.findOne({ path: _path, grant: Page.GRANT_RESTRICTED });
  1140. expect(page).toBeNull();
  1141. });
  1142. });
  1143. describe('Delete single page with grant USER_GROUP', () => {
  1144. test('should be able to delete completely', async() => {
  1145. const _path = '/npdc2_ug';
  1146. const _page = await Page.findOne({ path: _path, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1147. expect(_page).toBeTruthy();
  1148. await deleteCompletely(_page, npDummyUser1, {}, false);
  1149. const page = await Page.findOne({ path: _path, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1150. expect(page).toBeNull();
  1151. });
  1152. });
  1153. describe('Delete multiple pages with grant USER_GROUP', () => {
  1154. test('should be able to delete all descendants completely except page with GRANT_RESTRICTED', async() => {
  1155. const _path1 = '/npdc3_ug';
  1156. const _path2 = '/npdc3_ug/npdc4_ug';
  1157. const _path3 = '/npdc3_ug/npdc4_ug/npdc5_ug';
  1158. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1159. const _page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB });
  1160. const _page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC });
  1161. const _page4 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED });
  1162. expect(_page1).toBeTruthy();
  1163. expect(_page2).toBeTruthy();
  1164. expect(_page3).toBeTruthy();
  1165. expect(_page4).toBeTruthy();
  1166. await deleteCompletely(_page1, npDummyUser1, {}, true);
  1167. const page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdA });
  1168. const page2 = await Page.findOne({ path: _path2, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdB });
  1169. const page3 = await Page.findOne({ path: _path3, grant: Page.GRANT_USER_GROUP, grantedGroup: groupIdC });
  1170. const page4 = await Page.findOne({ path: _path2, grant: Page.GRANT_RESTRICTED });
  1171. expect(page1).toBeNull();
  1172. expect(page2).toBeNull();
  1173. expect(page3).toBeNull();
  1174. expect(page4).toBeTruthy();
  1175. });
  1176. });
  1177. });
  1178. describe('revert', () => {
  1179. const revertDeletedPage = async(page, user, options = {}, isRecursively = false) => {
  1180. // mock return value
  1181. const mockedRevertRecursivelyMainOperation = jest.spyOn(crowi.pageService, 'revertRecursivelyMainOperation').mockReturnValue(null);
  1182. const revertedPage = await crowi.pageService.revertDeletedPage(page, user, options, isRecursively);
  1183. const argsForRecursivelyMainOperation = mockedRevertRecursivelyMainOperation.mock.calls[0];
  1184. // restores the original implementation
  1185. mockedRevertRecursivelyMainOperation.mockRestore();
  1186. if (isRecursively) {
  1187. await crowi.pageService.revertRecursivelyMainOperation(...argsForRecursivelyMainOperation);
  1188. }
  1189. return revertedPage;
  1190. };
  1191. test('should revert single deleted page with GRANT_RESTRICTED', async() => {
  1192. const trashedPage = await Page.findOne({ path: '/trash/np_revert1', status: Page.STATUS_DELETED, grant: Page.GRANT_RESTRICTED });
  1193. const revision = await Revision.findOne({ pageId: trashedPage._id });
  1194. const tag = await Tag.findOne({ name: 'np_revertTag1' });
  1195. const deletedPageTagRelation = await PageTagRelation.findOne({ relatedPage: trashedPage._id, relatedTag: tag?._id, isPageTrashed: true });
  1196. expect(trashedPage).toBeTruthy();
  1197. expect(revision).toBeTruthy();
  1198. expect(tag).toBeTruthy();
  1199. expect(deletedPageTagRelation).toBeTruthy();
  1200. await revertDeletedPage(trashedPage, dummyUser1, {}, false);
  1201. const revertedPage = await Page.findOne({ path: '/np_revert1' });
  1202. const deltedPageBeforeRevert = await Page.findOne({ path: '/trash/np_revert1' });
  1203. const pageTagRelation = await PageTagRelation.findOne({ relatedPage: revertedPage._id, relatedTag: tag?._id });
  1204. expect(revertedPage).toBeTruthy();
  1205. expect(pageTagRelation).toBeTruthy();
  1206. expect(deltedPageBeforeRevert).toBeNull();
  1207. // page with GRANT_RESTRICTED does not have parent
  1208. expect(revertedPage.parent).toBeNull();
  1209. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1210. expect(revertedPage.grant).toBe(Page.GRANT_RESTRICTED);
  1211. expect(pageTagRelation.isPageTrashed).toBe(false);
  1212. });
  1213. test('should revert single deleted page with GRANT_USER_GROUP', async() => {
  1214. const beforeRevertPath = '/trash/np_revert2';
  1215. const user1 = await User.findOne({ name: 'npUser1' });
  1216. const trashedPage = await Page.findOne({ path: beforeRevertPath, status: Page.STATUS_DELETED, grant: Page.GRANT_USER_GROUP });
  1217. const revision = await Revision.findOne({ pageId: trashedPage._id });
  1218. const tag = await Tag.findOne({ name: 'np_revertTag2' });
  1219. const deletedPageTagRelation = await PageTagRelation.findOne({ relatedPage: trashedPage._id, relatedTag: tag?._id, isPageTrashed: true });
  1220. expect(trashedPage).toBeTruthy();
  1221. expect(revision).toBeTruthy();
  1222. expect(tag).toBeTruthy();
  1223. expect(deletedPageTagRelation).toBeTruthy();
  1224. await revertDeletedPage(trashedPage, user1, {}, false);
  1225. const revertedPage = await Page.findOne({ path: '/np_revert2' });
  1226. const trashedPageBR = await Page.findOne({ path: beforeRevertPath });
  1227. const pageTagRelation = await PageTagRelation.findOne({ relatedPage: revertedPage._id, relatedTag: tag?._id });
  1228. expect(revertedPage).toBeTruthy();
  1229. expect(pageTagRelation).toBeTruthy();
  1230. expect(trashedPageBR).toBeNull();
  1231. expect(revertedPage.parent).toStrictEqual(rootPage._id);
  1232. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1233. expect(revertedPage.grant).toBe(Page.GRANT_USER_GROUP);
  1234. expect(revertedPage.grantedGroup).toStrictEqual(groupIdA);
  1235. expect(pageTagRelation.isPageTrashed).toBe(false);
  1236. });
  1237. test(`revert multiple pages: only target page should be reverted.
  1238. Non-existant middle page and leaf page with GRANT_RESTRICTED shoud not be reverted`, async() => {
  1239. const beforeRevertPath1 = '/trash/np_revert3';
  1240. const beforeRevertPath2 = '/trash/np_revert3/middle/np_revert4';
  1241. const trashedPage1 = await Page.findOne({ path: beforeRevertPath1, status: Page.STATUS_DELETED, grant: Page.GRANT_PUBLIC });
  1242. const trashedPage2 = await Page.findOne({ path: beforeRevertPath2, status: Page.STATUS_DELETED, grant: Page.GRANT_RESTRICTED });
  1243. const revision1 = await Revision.findOne({ pageId: trashedPage1._id });
  1244. const revision2 = await Revision.findOne({ pageId: trashedPage2._id });
  1245. expect(trashedPage1).toBeTruthy();
  1246. expect(trashedPage2).toBeTruthy();
  1247. expect(revision1).toBeTruthy();
  1248. expect(revision2).toBeTruthy();
  1249. await revertDeletedPage(trashedPage1, npDummyUser2, {}, true);
  1250. const revertedPage = await Page.findOne({ path: '/np_revert3' });
  1251. const middlePage = await Page.findOne({ path: '/np_revert3/middle' });
  1252. const notRestrictedPage = await Page.findOne({ path: '/np_revert3/middle/np_revert4' });
  1253. // AR => After Revert
  1254. const trashedPage1AR = await Page.findOne({ path: beforeRevertPath1 });
  1255. const trashedPage2AR = await Page.findOne({ path: beforeRevertPath2 });
  1256. const revision1AR = await Revision.findOne({ pageId: revertedPage._id });
  1257. const revision2AR = await Revision.findOne({ pageId: trashedPage2AR._id });
  1258. expect(revertedPage).toBeTruthy();
  1259. expect(trashedPage2AR).toBeTruthy();
  1260. expect(revision1AR).toBeTruthy();
  1261. expect(revision2AR).toBeTruthy();
  1262. expect(trashedPage1AR).toBeNull();
  1263. expect(notRestrictedPage).toBeNull();
  1264. expect(middlePage).toBeNull();
  1265. expect(revertedPage.parent).toStrictEqual(rootPage._id);
  1266. expect(revertedPage.status).toBe(Page.STATUS_PUBLISHED);
  1267. expect(revertedPage.grant).toBe(Page.GRANT_PUBLIC);
  1268. });
  1269. test('revert multiple pages: target page, initially non-existant page and leaf page with GRANT_USER_GROUP shoud be reverted', async() => {
  1270. const user = await User.findOne({ _id: npDummyUser3 });
  1271. const beforeRevertPath1 = '/trash/np_revert5';
  1272. const beforeRevertPath2 = '/trash/np_revert5/middle/np_revert6';
  1273. const beforeRevertPath3 = '/trash/np_revert5/middle';
  1274. const trashedPage1 = await Page.findOne({ path: beforeRevertPath1, status: Page.STATUS_DELETED, grantedGroup: groupIdA });
  1275. const trashedPage2 = await Page.findOne({ path: beforeRevertPath2, status: Page.STATUS_DELETED, grantedGroup: groupIdB });
  1276. const nonExistantPage3 = await Page.findOne({ path: beforeRevertPath3 }); // not exist
  1277. const revision1 = await Revision.findOne({ pageId: trashedPage1._id });
  1278. const revision2 = await Revision.findOne({ pageId: trashedPage2._id });
  1279. expect(trashedPage1).toBeTruthy();
  1280. expect(trashedPage2).toBeTruthy();
  1281. expect(revision1).toBeTruthy();
  1282. expect(revision2).toBeTruthy();
  1283. expect(user).toBeTruthy();
  1284. expect(nonExistantPage3).toBeNull();
  1285. await revertDeletedPage(trashedPage1, user, {}, true);
  1286. const revertedPage1 = await Page.findOne({ path: '/np_revert5' });
  1287. const newlyCreatedPage = await Page.findOne({ path: '/np_revert5/middle' });
  1288. const revertedPage2 = await Page.findOne({ path: '/np_revert5/middle/np_revert6' });
  1289. // // AR => After Revert
  1290. const trashedPage1AR = await Page.findOne({ path: beforeRevertPath1 });
  1291. const trashedPage2AR = await Page.findOne({ path: beforeRevertPath2 });
  1292. expect(revertedPage1).toBeTruthy();
  1293. expect(newlyCreatedPage).toBeTruthy();
  1294. expect(revertedPage2).toBeTruthy();
  1295. expect(trashedPage1AR).toBeNull();
  1296. expect(trashedPage2AR).toBeNull();
  1297. expect(newlyCreatedPage.isEmpty).toBe(true);
  1298. expect(revertedPage1.parent).toStrictEqual(rootPage._id);
  1299. expect(revertedPage2.parent).toStrictEqual(newlyCreatedPage._id);
  1300. expect(newlyCreatedPage.parent).toStrictEqual(revertedPage1._id);
  1301. expect(revertedPage1.status).toBe(Page.STATUS_PUBLISHED);
  1302. expect(revertedPage2.status).toBe(Page.STATUS_PUBLISHED);
  1303. expect(newlyCreatedPage.status).toBe(Page.STATUS_PUBLISHED);
  1304. expect(revertedPage1.grantedGroup).toStrictEqual(groupIdA);
  1305. expect(revertedPage2.grantedGroup).toStrictEqual(groupIdB);
  1306. expect(newlyCreatedPage.grant).toBe(Page.GRANT_PUBLIC);
  1307. });
  1308. });
  1309. });