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

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