2
0

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

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