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

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