v5.page.test.js 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699
  1. import { PageGrant, GroupType, getIdForRef } from '@growi/core';
  2. import mongoose from 'mongoose';
  3. import { ExternalGroupProviderType } from '../../../src/features/external-user-group/interfaces/external-user-group';
  4. import ExternalUserGroup from '../../../src/features/external-user-group/server/models/external-user-group';
  5. import ExternalUserGroupRelation from '../../../src/features/external-user-group/server/models/external-user-group-relation';
  6. import UserGroup from '../../../src/server/models/user-group';
  7. import UserGroupRelation from '../../../src/server/models/user-group-relation';
  8. import { getInstance } from '../setup-crowi';
  9. describe('Page', () => {
  10. let crowi;
  11. let pageGrantService;
  12. let pageService;
  13. let Page;
  14. let Revision;
  15. let User;
  16. let PageTagRelation;
  17. let Bookmark;
  18. let Comment;
  19. let ShareLink;
  20. let PageRedirect;
  21. let xssSpy;
  22. let rootPage;
  23. let dummyUser1;
  24. let pModelUser1;
  25. let pModelUser2;
  26. let pModelUser3;
  27. let userGroupIdPModelIsolate;
  28. let userGroupIdPModelA;
  29. let userGroupIdPModelB;
  30. let userGroupIdPModelC;
  31. let externalUserGroupIdPModelIsolate;
  32. let externalUserGroupIdPModelA;
  33. let externalUserGroupIdPModelB;
  34. let externalUserGroupIdPModelC;
  35. // To test updatePage overwriting descendants (prefix `upod`)
  36. let upodUserA;
  37. let upodUserB;
  38. let upodUserC;
  39. let upodGroupAB;
  40. let upodGroupA;
  41. let upodGroupAIsolated;
  42. let upodGroupB;
  43. let upodGroupC;
  44. const upodUserGroupIdA = new mongoose.Types.ObjectId();
  45. const upodUserGroupIdAIsolated = new mongoose.Types.ObjectId();
  46. const upodUserGroupIdB = new mongoose.Types.ObjectId();
  47. const upodUserGroupIdC = new mongoose.Types.ObjectId();
  48. const upodUserGroupIdAB = new mongoose.Types.ObjectId();
  49. const upodExternalUserGroupIdA = new mongoose.Types.ObjectId();
  50. const upodExternalUserGroupIdAIsolated = new mongoose.Types.ObjectId();
  51. const upodExternalUserGroupIdB = new mongoose.Types.ObjectId();
  52. const upodExternalUserGroupIdC = new mongoose.Types.ObjectId();
  53. const upodExternalUserGroupIdAB = new mongoose.Types.ObjectId();
  54. const upodPageIdgAB1 = new mongoose.Types.ObjectId();
  55. const upodPageIdPublic2 = new mongoose.Types.ObjectId();
  56. const upodPageIdPublic3 = new mongoose.Types.ObjectId();
  57. const upodPageIdPublic4 = new mongoose.Types.ObjectId();
  58. const upodPageIdPublic5 = new mongoose.Types.ObjectId();
  59. const upodPageIdPublic6 = new mongoose.Types.ObjectId();
  60. // Since updatePageSubOperation is asyncronously called from updatePageSubOperation,
  61. // mock it inside updatePageSubOperation, and later call it independently to await for it's execution.
  62. const updatePage = async(page, newRevisionBody, oldRevisionBody, user, options = {}) => {
  63. const mockedUpdatePageSubOperation = jest.spyOn(pageService, 'updatePageSubOperation').mockReturnValue(null);
  64. const savedPage = await pageService.updatePage(page, newRevisionBody, oldRevisionBody, user, options);
  65. const argsForUpdatePageSubOperation = mockedUpdatePageSubOperation.mock.calls[0];
  66. mockedUpdatePageSubOperation.mockRestore();
  67. await pageService.updatePageSubOperation(...argsForUpdatePageSubOperation);
  68. return savedPage;
  69. };
  70. const createDocumentsToTestUpdatePageOverwritingDescendants = async() => {
  71. // Users
  72. await User.insertMany([
  73. { name: 'upodUserA', username: 'upodUserA', email: 'upoduserA@example.com' },
  74. { name: 'upodUserB', username: 'upodUserB', email: 'upoduserB@example.com' },
  75. { name: 'upodUserC', username: 'upodUserC', email: 'upodUserC@example.com' },
  76. ]);
  77. upodUserA = await User.findOne({ username: 'upodUserA' });
  78. upodUserB = await User.findOne({ username: 'upodUserB' });
  79. upodUserC = await User.findOne({ username: 'upodUserC' });
  80. await UserGroup.insertMany([
  81. {
  82. _id: upodUserGroupIdAB,
  83. name: 'upodGroupAB',
  84. parent: null,
  85. },
  86. {
  87. _id: upodUserGroupIdA,
  88. name: 'upodGroupA',
  89. parent: upodUserGroupIdAB,
  90. },
  91. {
  92. _id: upodUserGroupIdAIsolated,
  93. name: 'upodGroupAIsolated',
  94. parent: null,
  95. },
  96. {
  97. _id: upodUserGroupIdB,
  98. name: 'upodGroupB',
  99. parent: upodUserGroupIdAB,
  100. },
  101. {
  102. _id: upodUserGroupIdC,
  103. name: 'upodGroupC',
  104. parent: null,
  105. },
  106. ]);
  107. upodGroupAB = await UserGroup.findOne({ name: 'upodGroupAB' });
  108. upodGroupA = await UserGroup.findOne({ name: 'upodGroupA' });
  109. upodGroupAIsolated = await UserGroup.findOne({ name: 'upodGroupAIsolated' });
  110. upodGroupB = await UserGroup.findOne({ name: 'upodGroupB' });
  111. upodGroupC = await UserGroup.findOne({ name: 'upodGroupC' });
  112. // UserGroupRelations
  113. await UserGroupRelation.insertMany([
  114. {
  115. relatedGroup: upodUserGroupIdAB,
  116. relatedUser: upodUserA._id,
  117. },
  118. {
  119. relatedGroup: upodUserGroupIdAB,
  120. relatedUser: upodUserB._id,
  121. },
  122. {
  123. relatedGroup: upodUserGroupIdA,
  124. relatedUser: upodUserA._id,
  125. },
  126. {
  127. relatedGroup: upodUserGroupIdAIsolated,
  128. relatedUser: upodUserA._id,
  129. },
  130. {
  131. relatedGroup: upodUserGroupIdB,
  132. relatedUser: upodUserB._id,
  133. },
  134. {
  135. relatedGroup: upodUserGroupIdC,
  136. relatedUser: upodUserC._id,
  137. },
  138. ]);
  139. // Insert ExternalUserGroups with the same group structure as UserGroups
  140. // Use to test
  141. // - ExternalUserGroup
  142. // - Case of multiple grantedGroups for Page
  143. await ExternalUserGroup.insertMany([
  144. {
  145. _id: upodExternalUserGroupIdAB,
  146. name: 'upodExternalGroupAB',
  147. parent: null,
  148. externalId: 'upodExternalGroupAB',
  149. provider: ExternalGroupProviderType.ldap,
  150. },
  151. {
  152. _id: upodExternalUserGroupIdA,
  153. name: 'upodExternalGroupA',
  154. parent: upodExternalUserGroupIdAB,
  155. externalId: 'upodExternalGroupA',
  156. provider: ExternalGroupProviderType.ldap,
  157. },
  158. {
  159. _id: upodExternalUserGroupIdAIsolated,
  160. name: 'upodExternalGroupAIsolated',
  161. parent: null,
  162. externalId: 'upodExternalGroupAIsolated',
  163. provider: ExternalGroupProviderType.ldap,
  164. },
  165. {
  166. _id: upodExternalUserGroupIdB,
  167. name: 'upodExternalGroupB',
  168. parent: upodExternalUserGroupIdAB,
  169. externalId: 'upodExternalGroupB',
  170. provider: ExternalGroupProviderType.ldap,
  171. },
  172. {
  173. _id: upodExternalUserGroupIdC,
  174. name: 'upodExternalGroupC',
  175. parent: null,
  176. externalId: 'upodExternalGroupC',
  177. provider: ExternalGroupProviderType.ldap,
  178. },
  179. ]);
  180. // ExternalUserGroupRelations
  181. await ExternalUserGroupRelation.insertMany([
  182. {
  183. relatedGroup: upodExternalUserGroupIdAB,
  184. relatedUser: upodUserA._id,
  185. },
  186. {
  187. relatedGroup: upodExternalUserGroupIdAB,
  188. relatedUser: upodUserB._id,
  189. },
  190. {
  191. relatedGroup: upodExternalUserGroupIdA,
  192. relatedUser: upodUserA._id,
  193. },
  194. {
  195. relatedGroup: upodExternalUserGroupIdAIsolated,
  196. relatedUser: upodUserA._id,
  197. },
  198. {
  199. relatedGroup: upodExternalUserGroupIdB,
  200. relatedUser: upodUserB._id,
  201. },
  202. {
  203. relatedGroup: upodExternalUserGroupIdC,
  204. relatedUser: upodUserC._id,
  205. },
  206. ]);
  207. // Pages
  208. await Page.insertMany([
  209. // case 1
  210. {
  211. _id: upodPageIdgAB1,
  212. path: '/gAB_upod_1', // to GRANT_PUBLIC
  213. grant: PageGrant.GRANT_USER_GROUP,
  214. creator: upodUserA,
  215. lastUpdateUser: upodUserA,
  216. grantedUsers: null,
  217. grantedGroups: [
  218. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  219. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  220. ],
  221. parent: rootPage._id,
  222. },
  223. {
  224. path: '/gAB_upod_1/gB_upod_1',
  225. grant: PageGrant.GRANT_USER_GROUP,
  226. creator: upodUserB,
  227. lastUpdateUser: upodUserB,
  228. grantedUsers: null,
  229. grantedGroups: [
  230. { item: upodUserGroupIdB, type: GroupType.userGroup },
  231. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  232. ],
  233. parent: upodPageIdgAB1,
  234. },
  235. {
  236. path: '/gAB_upod_1/onlyB_upod_1',
  237. grant: PageGrant.GRANT_OWNER,
  238. creator: upodUserB,
  239. lastUpdateUser: upodUserB,
  240. grantedUsers: [upodUserB._id],
  241. grantedGroups: null,
  242. parent: upodPageIdgAB1,
  243. },
  244. // case 2
  245. {
  246. _id: upodPageIdPublic2,
  247. path: '/public_upod_2', // to Anything
  248. grant: PageGrant.GRANT_PUBLIC,
  249. creator: upodUserA,
  250. lastUpdateUser: upodUserA,
  251. grantedUsers: null,
  252. grantedGroups: null,
  253. parent: rootPage._id,
  254. },
  255. {
  256. path: '/public_upod_2/gA_upod_2',
  257. grant: PageGrant.GRANT_USER_GROUP,
  258. creator: upodUserA,
  259. lastUpdateUser: upodUserA,
  260. grantedUsers: null,
  261. grantedGroups: [
  262. { item: upodUserGroupIdA, type: GroupType.userGroup },
  263. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  264. ],
  265. parent: upodPageIdPublic2,
  266. },
  267. {
  268. path: '/public_upod_2/gAIsolated_upod_2',
  269. grant: PageGrant.GRANT_USER_GROUP,
  270. creator: upodUserA,
  271. lastUpdateUser: upodUserA,
  272. grantedUsers: null,
  273. grantedGroups: [
  274. { item: upodUserGroupIdAIsolated, type: GroupType.userGroup },
  275. { item: upodExternalUserGroupIdAIsolated, type: GroupType.externalUserGroup },
  276. ],
  277. parent: upodPageIdPublic2,
  278. },
  279. {
  280. path: '/public_upod_2/onlyA_upod_2',
  281. grant: PageGrant.GRANT_OWNER,
  282. creator: upodUserA,
  283. lastUpdateUser: upodUserA,
  284. grantedUsers: [upodUserA._id],
  285. grantedGroups: null,
  286. parent: upodPageIdPublic2,
  287. },
  288. // case 3
  289. {
  290. _id: upodPageIdPublic3,
  291. path: '/public_upod_3', // to GRANT_USER_GROUP with upodGroupAB
  292. grant: PageGrant.GRANT_PUBLIC,
  293. creator: upodUserA,
  294. lastUpdateUser: upodUserA,
  295. grantedUsers: null,
  296. grantedGroups: null,
  297. parent: rootPage._id,
  298. },
  299. // grant user A and B with a single group
  300. // (external group is extra for testing external groups)
  301. {
  302. path: '/public_upod_3/gAB_upod_3',
  303. grant: PageGrant.GRANT_USER_GROUP,
  304. creator: upodUserA,
  305. lastUpdateUser: upodUserA,
  306. grantedUsers: null,
  307. grantedGroups: [
  308. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  309. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  310. ],
  311. parent: upodPageIdPublic3,
  312. },
  313. // grant user A and B with independent groups
  314. {
  315. path: '/public_upod_3/gA_gB_upod_3',
  316. grant: PageGrant.GRANT_USER_GROUP,
  317. creator: upodUserA,
  318. lastUpdateUser: upodUserA,
  319. grantedUsers: null,
  320. grantedGroups: [
  321. { item: upodUserGroupIdA, type: GroupType.userGroup },
  322. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  323. { item: upodUserGroupIdB, type: GroupType.userGroup },
  324. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  325. ],
  326. parent: upodPageIdPublic3,
  327. },
  328. {
  329. path: '/public_upod_3/gB_upod_3',
  330. grant: PageGrant.GRANT_USER_GROUP,
  331. creator: upodUserB,
  332. lastUpdateUser: upodUserB,
  333. grantedUsers: null,
  334. grantedGroups: [
  335. { item: upodUserGroupIdB, type: GroupType.userGroup },
  336. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  337. ],
  338. parent: upodPageIdPublic3,
  339. },
  340. {
  341. path: '/public_upod_3/onlyB_upod_3',
  342. grant: PageGrant.GRANT_OWNER,
  343. creator: upodUserB,
  344. lastUpdateUser: upodUserB,
  345. grantedUsers: [upodUserB._id],
  346. grantedGroups: null,
  347. parent: upodPageIdPublic3,
  348. },
  349. // case 4
  350. {
  351. _id: upodPageIdPublic4,
  352. path: '/public_upod_4', // to GRANT_USER_GROUP with upodGroupAB
  353. grant: PageGrant.GRANT_PUBLIC,
  354. creator: upodUserA,
  355. lastUpdateUser: upodUserA,
  356. grantedUsers: null,
  357. grantedGroups: null,
  358. parent: rootPage._id,
  359. },
  360. {
  361. path: '/public_upod_4/gA_upod_4',
  362. grant: PageGrant.GRANT_USER_GROUP,
  363. creator: upodUserA,
  364. lastUpdateUser: upodUserA,
  365. grantedUsers: null,
  366. grantedGroups: [
  367. { item: upodUserGroupIdA, type: GroupType.userGroup },
  368. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  369. ],
  370. parent: upodPageIdPublic4,
  371. },
  372. {
  373. path: '/public_upod_4/gC_upod_4',
  374. grant: PageGrant.GRANT_USER_GROUP,
  375. creator: upodUserC,
  376. lastUpdateUser: upodUserC,
  377. grantedUsers: null,
  378. grantedGroups: [
  379. { item: upodUserGroupIdC, type: GroupType.userGroup },
  380. { item: upodExternalUserGroupIdC, type: GroupType.externalUserGroup },
  381. ],
  382. parent: upodPageIdPublic4,
  383. },
  384. // case 5
  385. {
  386. _id: upodPageIdPublic5,
  387. path: '/public_upod_5', // to GRANT_USER_GROUP with upodGroupAB
  388. grant: PageGrant.GRANT_PUBLIC,
  389. creator: upodUserA,
  390. lastUpdateUser: upodUserA,
  391. grantedUsers: null,
  392. grantedGroups: null,
  393. parent: rootPage._id,
  394. },
  395. {
  396. path: '/public_upod_5/gA_upod_5',
  397. grant: PageGrant.GRANT_USER_GROUP,
  398. creator: upodUserA,
  399. lastUpdateUser: upodUserA,
  400. grantedUsers: null,
  401. grantedGroups: [
  402. { item: upodUserGroupIdA, type: GroupType.userGroup },
  403. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  404. ],
  405. parent: upodPageIdPublic5,
  406. },
  407. {
  408. path: '/public_upod_5/onlyC_upod_5',
  409. grant: PageGrant.GRANT_OWNER,
  410. creator: upodUserC,
  411. lastUpdateUser: upodUserC,
  412. grantedUsers: [upodUserC._id],
  413. grantedGroups: null,
  414. parent: upodPageIdPublic5,
  415. },
  416. // case 6
  417. {
  418. _id: upodPageIdPublic6,
  419. path: '/public_upod_6', // to GRANT_USER_GROUP with upodGroupAB
  420. grant: PageGrant.GRANT_PUBLIC,
  421. creator: upodUserA,
  422. lastUpdateUser: upodUserA,
  423. grantedUsers: null,
  424. grantedGroups: null,
  425. parent: rootPage._id,
  426. },
  427. {
  428. path: '/public_upod_6/onlyC_upod_6',
  429. grant: PageGrant.GRANT_OWNER,
  430. creator: upodUserC,
  431. lastUpdateUser: upodUserC,
  432. grantedUsers: [upodUserC._id],
  433. grantedGroups: null,
  434. parent: upodPageIdPublic6,
  435. },
  436. ]);
  437. };
  438. // normalize for result comparison
  439. const normalizeGrantedGroups = (grantedGroups) => {
  440. return grantedGroups.map((group) => {
  441. return { item: getIdForRef(group.item), type: group.type };
  442. });
  443. };
  444. beforeAll(async() => {
  445. crowi = await getInstance();
  446. pageGrantService = crowi.pageGrantService;
  447. pageService = crowi.pageService;
  448. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  449. jest.restoreAllMocks();
  450. User = mongoose.model('User');
  451. Page = mongoose.model('Page');
  452. Revision = mongoose.model('Revision');
  453. PageTagRelation = mongoose.model('PageTagRelation');
  454. Bookmark = mongoose.model('Bookmark');
  455. Comment = mongoose.model('Comment');
  456. ShareLink = mongoose.model('ShareLink');
  457. PageRedirect = mongoose.model('PageRedirect');
  458. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  459. rootPage = await Page.findOne({ path: '/' });
  460. const pModelUserId1 = new mongoose.Types.ObjectId();
  461. const pModelUserId2 = new mongoose.Types.ObjectId();
  462. const pModelUserId3 = new mongoose.Types.ObjectId();
  463. await User.insertMany([
  464. {
  465. _id: pModelUserId1,
  466. name: 'pmodelUser1',
  467. username: 'pmodelUser1',
  468. email: 'pmodelUser1@example.com',
  469. },
  470. {
  471. _id: pModelUserId2,
  472. name: 'pmodelUser2',
  473. username: 'pmodelUser2',
  474. email: 'pmodelUser2@example.com',
  475. },
  476. {
  477. _id: pModelUserId3,
  478. name: 'pModelUser3',
  479. username: 'pModelUser3',
  480. email: 'pModelUser3@example.com',
  481. },
  482. ]);
  483. pModelUser1 = await User.findOne({ _id: pModelUserId1 });
  484. pModelUser2 = await User.findOne({ _id: pModelUserId2 });
  485. pModelUser3 = await User.findOne({ _id: pModelUserId3 });
  486. userGroupIdPModelIsolate = new mongoose.Types.ObjectId();
  487. userGroupIdPModelA = new mongoose.Types.ObjectId();
  488. userGroupIdPModelB = new mongoose.Types.ObjectId();
  489. userGroupIdPModelC = new mongoose.Types.ObjectId();
  490. await UserGroup.insertMany([
  491. {
  492. _id: userGroupIdPModelIsolate,
  493. name: 'pModel_groupIsolate',
  494. },
  495. {
  496. _id: userGroupIdPModelA,
  497. name: 'pModel_groupA',
  498. },
  499. {
  500. _id: userGroupIdPModelB,
  501. name: 'pModel_groupB',
  502. parent: userGroupIdPModelA,
  503. },
  504. {
  505. _id: userGroupIdPModelC,
  506. name: 'pModel_groupC',
  507. parent: userGroupIdPModelB,
  508. },
  509. ]);
  510. await UserGroupRelation.insertMany([
  511. {
  512. relatedGroup: userGroupIdPModelIsolate,
  513. relatedUser: pModelUserId1,
  514. createdAt: new Date(),
  515. },
  516. {
  517. relatedGroup: userGroupIdPModelIsolate,
  518. relatedUser: pModelUserId2,
  519. createdAt: new Date(),
  520. },
  521. {
  522. relatedGroup: userGroupIdPModelA,
  523. relatedUser: pModelUserId1,
  524. createdAt: new Date(),
  525. },
  526. {
  527. relatedGroup: userGroupIdPModelA,
  528. relatedUser: pModelUserId2,
  529. createdAt: new Date(),
  530. },
  531. {
  532. relatedGroup: userGroupIdPModelA,
  533. relatedUser: pModelUserId3,
  534. createdAt: new Date(),
  535. },
  536. {
  537. relatedGroup: userGroupIdPModelB,
  538. relatedUser: pModelUserId2,
  539. createdAt: new Date(),
  540. },
  541. {
  542. relatedGroup: userGroupIdPModelB,
  543. relatedUser: pModelUserId3,
  544. createdAt: new Date(),
  545. },
  546. {
  547. relatedGroup: userGroupIdPModelC,
  548. relatedUser: pModelUserId3,
  549. createdAt: new Date(),
  550. },
  551. ]);
  552. // Insert ExternalUserGroups with the same group structure as UserGroups
  553. // Use to test
  554. // - ExternalUserGroup
  555. // - Case of multiple grantedGroups for Page
  556. externalUserGroupIdPModelIsolate = new mongoose.Types.ObjectId();
  557. externalUserGroupIdPModelA = new mongoose.Types.ObjectId();
  558. externalUserGroupIdPModelB = new mongoose.Types.ObjectId();
  559. externalUserGroupIdPModelC = new mongoose.Types.ObjectId();
  560. await ExternalUserGroup.insertMany([
  561. {
  562. _id: externalUserGroupIdPModelIsolate,
  563. name: 'pModel_externalGroupIsolate',
  564. externalId: 'pModel_externalGroupIsolate',
  565. provider: ExternalGroupProviderType.ldap,
  566. },
  567. {
  568. _id: externalUserGroupIdPModelA,
  569. name: 'pModel_externalGroupA',
  570. externalId: 'pModel_externalGroupA',
  571. provider: ExternalGroupProviderType.ldap,
  572. },
  573. {
  574. _id: externalUserGroupIdPModelB,
  575. name: 'pModel_externalGroupB',
  576. parent: externalUserGroupIdPModelA,
  577. externalId: 'pModel_externalGroupB',
  578. provider: ExternalGroupProviderType.ldap,
  579. },
  580. {
  581. _id: externalUserGroupIdPModelC,
  582. name: 'pModel_externalGroupC',
  583. parent: externalUserGroupIdPModelB,
  584. externalId: 'pModel_externalGroupC',
  585. provider: ExternalGroupProviderType.ldap,
  586. },
  587. ]);
  588. await ExternalUserGroupRelation.insertMany([
  589. {
  590. relatedGroup: externalUserGroupIdPModelIsolate,
  591. relatedUser: pModelUserId1,
  592. createdAt: new Date(),
  593. },
  594. {
  595. relatedGroup: externalUserGroupIdPModelIsolate,
  596. relatedUser: pModelUserId2,
  597. createdAt: new Date(),
  598. },
  599. {
  600. relatedGroup: externalUserGroupIdPModelA,
  601. relatedUser: pModelUserId1,
  602. createdAt: new Date(),
  603. },
  604. {
  605. relatedGroup: externalUserGroupIdPModelA,
  606. relatedUser: pModelUserId2,
  607. createdAt: new Date(),
  608. },
  609. {
  610. relatedGroup: externalUserGroupIdPModelA,
  611. relatedUser: pModelUserId3,
  612. createdAt: new Date(),
  613. },
  614. {
  615. relatedGroup: externalUserGroupIdPModelB,
  616. relatedUser: pModelUserId2,
  617. createdAt: new Date(),
  618. },
  619. {
  620. relatedGroup: externalUserGroupIdPModelB,
  621. relatedUser: pModelUserId3,
  622. createdAt: new Date(),
  623. },
  624. {
  625. relatedGroup: externalUserGroupIdPModelC,
  626. relatedUser: pModelUserId3,
  627. createdAt: new Date(),
  628. },
  629. ]);
  630. /**
  631. * update
  632. * mup_ => model update
  633. * emp => empty => page with isEmpty: true
  634. * pub => public => GRANT_PUBLIC
  635. * awl => Anyone with the link => GRANT_RESTRICTED
  636. */
  637. const pageIdUpd1 = new mongoose.Types.ObjectId();
  638. const pageIdUpd2 = new mongoose.Types.ObjectId();
  639. const pageIdUpd3 = new mongoose.Types.ObjectId();
  640. const pageIdUpd4 = new mongoose.Types.ObjectId();
  641. const pageIdUpd5 = new mongoose.Types.ObjectId();
  642. const pageIdUpd6 = new mongoose.Types.ObjectId();
  643. const pageIdUpd7 = new mongoose.Types.ObjectId();
  644. const pageIdUpd8 = new mongoose.Types.ObjectId();
  645. const pageIdUpd9 = new mongoose.Types.ObjectId();
  646. const pageIdUpd10 = new mongoose.Types.ObjectId();
  647. const pageIdUpd11 = new mongoose.Types.ObjectId();
  648. const pageIdUpd12 = new mongoose.Types.ObjectId();
  649. const pageIdUpd13 = new mongoose.Types.ObjectId();
  650. const pageIdUpd14 = new mongoose.Types.ObjectId();
  651. const pageIdUpd15 = new mongoose.Types.ObjectId();
  652. const pageIdUpd16 = new mongoose.Types.ObjectId();
  653. const pageIdUpd17 = new mongoose.Types.ObjectId();
  654. const pageIdUpd18 = new mongoose.Types.ObjectId();
  655. const pageIdUpd19 = new mongoose.Types.ObjectId();
  656. await Page.insertMany([
  657. {
  658. _id: pageIdUpd1,
  659. path: '/mup13_top/mup1_emp',
  660. grant: Page.GRANT_PUBLIC,
  661. parent: pageIdUpd8._id,
  662. isEmpty: true,
  663. },
  664. {
  665. _id: pageIdUpd2,
  666. path: '/mup13_top/mup1_emp/mup2_pub',
  667. grant: Page.GRANT_PUBLIC,
  668. parent: pageIdUpd1._id,
  669. creator: dummyUser1,
  670. lastUpdateUser: dummyUser1._id,
  671. isEmpty: false,
  672. },
  673. {
  674. _id: pageIdUpd3,
  675. path: '/mup14_top/mup6_pub',
  676. grant: Page.GRANT_PUBLIC,
  677. creator: dummyUser1,
  678. lastUpdateUser: dummyUser1._id,
  679. parent: pageIdUpd9,
  680. isEmpty: false,
  681. descendantCount: 1,
  682. },
  683. {
  684. path: '/mup14_top/mup6_pub/mup7_pub',
  685. grant: Page.GRANT_PUBLIC,
  686. creator: dummyUser1,
  687. lastUpdateUser: dummyUser1._id,
  688. parent: pageIdUpd3,
  689. isEmpty: false,
  690. descendantCount: 0,
  691. },
  692. {
  693. _id: pageIdUpd4,
  694. path: '/mup15_top/mup8_pub',
  695. grant: Page.GRANT_PUBLIC,
  696. creator: dummyUser1,
  697. lastUpdateUser: dummyUser1._id,
  698. parent: pageIdUpd10._id,
  699. isEmpty: false,
  700. },
  701. {
  702. _id: pageIdUpd5,
  703. path: '/mup16_top/mup9_pub/mup10_pub/mup11_awl',
  704. grant: Page.GRANT_RESTRICTED,
  705. creator: dummyUser1,
  706. lastUpdateUser: dummyUser1._id,
  707. isEmpty: false,
  708. },
  709. {
  710. _id: pageIdUpd6,
  711. path: '/mup17_top/mup12_emp',
  712. isEmpty: true,
  713. parent: pageIdUpd12._id,
  714. descendantCount: 1,
  715. },
  716. {
  717. _id: pageIdUpd7,
  718. path: '/mup17_top/mup12_emp',
  719. grant: Page.GRANT_RESTRICTED,
  720. creator: dummyUser1,
  721. lastUpdateUser: dummyUser1._id,
  722. isEmpty: false,
  723. },
  724. {
  725. path: '/mup17_top/mup12_emp/mup18_pub',
  726. isEmpty: false,
  727. creator: dummyUser1,
  728. lastUpdateUser: dummyUser1._id,
  729. parent: pageIdUpd6._id,
  730. },
  731. {
  732. _id: pageIdUpd8,
  733. path: '/mup13_top',
  734. grant: Page.GRANT_PUBLIC,
  735. creator: dummyUser1,
  736. lastUpdateUser: dummyUser1._id,
  737. isEmpty: false,
  738. parent: rootPage._id,
  739. descendantCount: 2,
  740. },
  741. {
  742. _id: pageIdUpd9,
  743. path: '/mup14_top',
  744. grant: Page.GRANT_PUBLIC,
  745. creator: dummyUser1,
  746. lastUpdateUser: dummyUser1._id,
  747. isEmpty: false,
  748. parent: rootPage._id,
  749. descendantCount: 2,
  750. },
  751. {
  752. _id: pageIdUpd10,
  753. path: '/mup15_top',
  754. grant: Page.GRANT_PUBLIC,
  755. creator: dummyUser1,
  756. lastUpdateUser: dummyUser1._id,
  757. isEmpty: false,
  758. parent: rootPage._id,
  759. descendantCount: 1,
  760. },
  761. {
  762. _id: pageIdUpd11,
  763. path: '/mup16_top',
  764. grant: Page.GRANT_PUBLIC,
  765. creator: dummyUser1,
  766. lastUpdateUser: dummyUser1._id,
  767. isEmpty: false,
  768. parent: rootPage._id,
  769. descendantCount: 0,
  770. },
  771. {
  772. _id: pageIdUpd12,
  773. path: '/mup17_top',
  774. grant: Page.GRANT_PUBLIC,
  775. creator: dummyUser1,
  776. lastUpdateUser: dummyUser1._id,
  777. isEmpty: false,
  778. parent: rootPage._id,
  779. descendantCount: 1,
  780. },
  781. {
  782. path: '/mup19',
  783. grant: Page.GRANT_PUBLIC,
  784. creator: dummyUser1,
  785. lastUpdateUser: dummyUser1._id,
  786. isEmpty: false,
  787. parent: rootPage._id,
  788. descendantCount: 0,
  789. },
  790. {
  791. path: '/mup20',
  792. grant: Page.GRANT_USER_GROUP,
  793. grantedGroups: [
  794. { item: userGroupIdPModelA, type: GroupType.userGroup },
  795. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  796. ],
  797. creator: pModelUserId1,
  798. lastUpdateUser: pModelUserId1,
  799. isEmpty: false,
  800. parent: rootPage._id,
  801. descendantCount: 0,
  802. },
  803. {
  804. path: '/mup21',
  805. grant: Page.GRANT_RESTRICTED,
  806. creator: dummyUser1,
  807. lastUpdateUser: dummyUser1._id,
  808. isEmpty: false,
  809. descendantCount: 0,
  810. },
  811. {
  812. _id: pageIdUpd13,
  813. path: '/mup22',
  814. grant: Page.GRANT_PUBLIC,
  815. creator: pModelUser1,
  816. lastUpdateUser: pModelUser1._id,
  817. isEmpty: false,
  818. parent: rootPage._id,
  819. descendantCount: 1,
  820. },
  821. {
  822. path: '/mup22/mup23',
  823. grant: Page.GRANT_USER_GROUP,
  824. grantedGroups: [
  825. { item: userGroupIdPModelA, type: GroupType.userGroup },
  826. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  827. ],
  828. creator: pModelUserId1,
  829. lastUpdateUser: pModelUserId1,
  830. isEmpty: false,
  831. parent: pageIdUpd13,
  832. descendantCount: 0,
  833. },
  834. {
  835. _id: pageIdUpd14,
  836. path: '/mup24_pub',
  837. grant: Page.GRANT_PUBLIC,
  838. creator: pModelUserId1,
  839. lastUpdateUser: pModelUserId1,
  840. isEmpty: false,
  841. parent: rootPage,
  842. descendantCount: 1,
  843. },
  844. {
  845. path: '/mup24_pub/mup25_pub',
  846. grant: Page.GRANT_PUBLIC,
  847. creator: pModelUserId1,
  848. lastUpdateUser: pModelUserId1,
  849. isEmpty: false,
  850. parent: pageIdUpd14,
  851. descendantCount: 0,
  852. },
  853. {
  854. path: '/mup26_awl',
  855. grant: Page.GRANT_RESTRICTED,
  856. creator: pModelUserId1,
  857. lastUpdateUser: pModelUserId1,
  858. isEmpty: false,
  859. descendantCount: 0,
  860. },
  861. {
  862. _id: pageIdUpd15,
  863. path: '/mup27_pub',
  864. grant: Page.GRANT_PUBLIC,
  865. creator: pModelUserId1,
  866. lastUpdateUser: pModelUserId1,
  867. isEmpty: false,
  868. parent: rootPage,
  869. descendantCount: 1,
  870. },
  871. {
  872. path: '/mup27_pub/mup28_owner',
  873. grant: Page.GRANT_OWNER,
  874. creator: pModelUserId1,
  875. lastUpdateUser: pModelUserId1,
  876. isEmpty: false,
  877. parent: pageIdUpd15,
  878. grantedUsers: [pModelUserId1],
  879. descendantCount: 0,
  880. },
  881. {
  882. _id: pageIdUpd16,
  883. path: '/mup29_A',
  884. grant: Page.GRANT_USER_GROUP,
  885. grantedGroups: [
  886. { item: userGroupIdPModelA, type: GroupType.userGroup },
  887. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  888. ],
  889. creator: pModelUserId1,
  890. lastUpdateUser: pModelUserId1,
  891. isEmpty: false,
  892. parent: rootPage,
  893. descendantCount: 1,
  894. },
  895. {
  896. path: '/mup29_A/mup30_owner',
  897. grant: Page.GRANT_OWNER,
  898. grantedUsers: [pModelUserId1],
  899. creator: pModelUserId1,
  900. lastUpdateUser: pModelUserId1,
  901. isEmpty: false,
  902. parent: pageIdUpd16,
  903. descendantCount: 0,
  904. },
  905. {
  906. _id: pageIdUpd17,
  907. path: '/mup31_A',
  908. grant: Page.GRANT_USER_GROUP,
  909. grantedGroups: [
  910. { item: userGroupIdPModelA, type: GroupType.userGroup },
  911. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  912. ],
  913. creator: pModelUserId1,
  914. lastUpdateUser: pModelUserId1,
  915. isEmpty: false,
  916. parent: rootPage,
  917. descendantCount: 1,
  918. },
  919. {
  920. path: '/mup31_A/mup32_owner',
  921. grant: Page.GRANT_OWNER,
  922. grantedUsers: [pModelUserId1],
  923. creator: pModelUserId1,
  924. lastUpdateUser: pModelUserId1,
  925. isEmpty: false,
  926. parent: pageIdUpd17,
  927. descendantCount: 0,
  928. },
  929. {
  930. _id: pageIdUpd18,
  931. path: '/mup33_C',
  932. grant: Page.GRANT_USER_GROUP,
  933. grantedGroups: [
  934. { item: userGroupIdPModelC, type: GroupType.userGroup },
  935. { item: externalUserGroupIdPModelC, type: GroupType.externalUserGroup },
  936. ],
  937. creator: pModelUserId3,
  938. lastUpdateUser: pModelUserId3,
  939. isEmpty: false,
  940. parent: rootPage,
  941. descendantCount: 1,
  942. },
  943. {
  944. path: '/mup33_C/mup34_owner',
  945. grant: Page.GRANT_OWNER,
  946. grantedUsers: [pModelUserId3],
  947. creator: pModelUserId3,
  948. lastUpdateUser: pModelUserId3,
  949. isEmpty: false,
  950. parent: pageIdUpd18,
  951. descendantCount: 0,
  952. },
  953. {
  954. _id: pageIdUpd19,
  955. path: '/mup35_owner',
  956. grant: Page.GRANT_OWNER,
  957. grantedUsers: [pModelUserId1],
  958. creator: pModelUserId1,
  959. lastUpdateUser: pModelUserId1,
  960. isEmpty: false,
  961. parent: rootPage,
  962. descendantCount: 1,
  963. },
  964. {
  965. path: '/mup35_owner/mup36_owner',
  966. grant: Page.GRANT_OWNER,
  967. grantedUsers: [pModelUserId1],
  968. creator: pModelUserId1,
  969. lastUpdateUser: pModelUserId1,
  970. isEmpty: false,
  971. parent: pageIdUpd19,
  972. descendantCount: 0,
  973. },
  974. {
  975. path: '/mup40', // used this number to resolve conflict
  976. grant: Page.GRANT_OWNER,
  977. grantedUsers: [dummyUser1._id],
  978. creator: dummyUser1,
  979. lastUpdateUser: dummyUser1._id,
  980. isEmpty: false,
  981. parent: rootPage._id,
  982. descendantCount: 0,
  983. },
  984. ]);
  985. await createDocumentsToTestUpdatePageOverwritingDescendants();
  986. });
  987. describe('updatePage with overwriteScopesOfDescendants false', () => {
  988. describe('Changing grant from PUBLIC to RESTRICTED of', () => {
  989. test('an only-child page will delete its empty parent page', async() => {
  990. const pathT = '/mup13_top';
  991. const path1 = '/mup13_top/mup1_emp';
  992. const path2 = '/mup13_top/mup1_emp/mup2_pub';
  993. const pageT = await Page.findOne({ path: pathT, descendantCount: 2 });
  994. const page1 = await Page.findOne({ path: path1, isEmpty: true });
  995. const page2 = await Page.findOne({ path: path2, grant: Page.GRANT_PUBLIC });
  996. expect(pageT).toBeTruthy();
  997. expect(page1).toBeTruthy();
  998. expect(page2).toBeTruthy();
  999. const options = { grant: Page.GRANT_RESTRICTED, grantUserGroupIds: null };
  1000. await updatePage(page2, 'newRevisionBody', 'oldRevisionBody', dummyUser1, options);
  1001. const _pageT = await Page.findOne({ path: pathT });
  1002. const _page1 = await Page.findOne({ path: path1 });
  1003. const _page2 = await Page.findOne({ path: path2, grant: Page.GRANT_RESTRICTED });
  1004. expect(_pageT).toBeTruthy();
  1005. expect(_page1).toBeNull();
  1006. expect(_page2).toBeTruthy();
  1007. expect(_pageT.descendantCount).toBe(1);
  1008. });
  1009. test('a page that has children will create an empty page with the same path and it becomes a new parent', async() => {
  1010. const pathT = '/mup14_top';
  1011. const path1 = '/mup14_top/mup6_pub';
  1012. const path2 = '/mup14_top/mup6_pub/mup7_pub';
  1013. const top = await Page.findOne({ path: pathT, descendantCount: 2 });
  1014. const page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  1015. const page2 = await Page.findOne({ path: path2, grant: Page.GRANT_PUBLIC });
  1016. expect(top).toBeTruthy();
  1017. expect(page1).toBeTruthy();
  1018. expect(page2).toBeTruthy();
  1019. await updatePage(page1, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_RESTRICTED });
  1020. const _top = await Page.findOne({ path: pathT });
  1021. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  1022. const _page2 = await Page.findOne({ path: path2 });
  1023. const _pageN = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  1024. expect(_page1).toBeTruthy();
  1025. expect(_page2).toBeTruthy();
  1026. expect(_pageN).toBeTruthy();
  1027. expect(_page1.parent).toBeNull();
  1028. expect(_page2.parent).toStrictEqual(_pageN._id);
  1029. expect(_pageN.parent).toStrictEqual(top._id);
  1030. expect(_pageN.isEmpty).toBe(true);
  1031. expect(_pageN.descendantCount).toBe(1);
  1032. expect(_top.descendantCount).toBe(1);
  1033. });
  1034. test('of a leaf page will NOT have an empty page with the same path', async() => {
  1035. const pathT = '/mup15_top';
  1036. const path1 = '/mup15_top/mup8_pub';
  1037. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  1038. const page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  1039. const count = await Page.count({ path: path1 });
  1040. expect(pageT).toBeTruthy();
  1041. expect(page1).toBeTruthy();
  1042. expect(count).toBe(1);
  1043. await updatePage(page1, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_RESTRICTED });
  1044. const _pageT = await Page.findOne({ path: pathT });
  1045. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED });
  1046. const _pageNotExist = await Page.findOne({ path: path1, isEmpty: true });
  1047. expect(_pageT).toBeTruthy();
  1048. expect(_page1).toBeTruthy();
  1049. expect(_pageNotExist).toBeNull();
  1050. expect(_pageT.descendantCount).toBe(0);
  1051. });
  1052. });
  1053. describe('Changing grant to GRANT_RESTRICTED', () => {
  1054. test('successfully change to GRANT_RESTRICTED from GRANT_OWNER', async() => {
  1055. const path = '/mup40';
  1056. const _page = await Page.findOne({ path, grant: Page.GRANT_OWNER, grantedUsers: [dummyUser1._id] });
  1057. expect(_page).toBeTruthy();
  1058. await updatePage(_page, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_RESTRICTED });
  1059. const page = await Page.findOne({ path });
  1060. expect(page).toBeTruthy();
  1061. expect(page.grant).toBe(Page.GRANT_RESTRICTED);
  1062. expect(page.grantedUsers).toStrictEqual([]);
  1063. });
  1064. });
  1065. describe('Changing grant from RESTRICTED to PUBLIC of', () => {
  1066. test('a page will create ancestors if they do not exist', async() => {
  1067. const pathT = '/mup16_top';
  1068. const path1 = '/mup16_top/mup9_pub';
  1069. const path2 = '/mup16_top/mup9_pub/mup10_pub';
  1070. const path3 = '/mup16_top/mup9_pub/mup10_pub/mup11_awl';
  1071. const top = await Page.findOne({ path: pathT });
  1072. const page1 = await Page.findOne({ path: path1 });
  1073. const page2 = await Page.findOne({ path: path2 });
  1074. const page3 = await Page.findOne({ path: path3, grant: Page.GRANT_RESTRICTED });
  1075. expect(top).toBeTruthy();
  1076. expect(page3).toBeTruthy();
  1077. expect(page1).toBeNull();
  1078. expect(page2).toBeNull();
  1079. await updatePage(page3, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_PUBLIC });
  1080. const _pageT = await Page.findOne({ path: pathT });
  1081. const _page1 = await Page.findOne({ path: path1, isEmpty: true });
  1082. const _page2 = await Page.findOne({ path: path2, isEmpty: true });
  1083. const _page3 = await Page.findOne({ path: path3, grant: Page.GRANT_PUBLIC });
  1084. expect(_page1).toBeTruthy();
  1085. expect(_page2).toBeTruthy();
  1086. expect(_page3).toBeTruthy();
  1087. expect(_page1.parent).toStrictEqual(top._id);
  1088. expect(_page2.parent).toStrictEqual(_page1._id);
  1089. expect(_page3.parent).toStrictEqual(_page2._id);
  1090. expect(_pageT.descendantCount).toBe(1);
  1091. });
  1092. test('a page will replace an empty page with the same path if any', async() => {
  1093. const pathT = '/mup17_top';
  1094. const path1 = '/mup17_top/mup12_emp';
  1095. const path2 = '/mup17_top/mup12_emp/mup18_pub';
  1096. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  1097. const page1 = await Page.findOne({ path: path1, isEmpty: true });
  1098. const page2 = await Page.findOne({ path: path1, grant: Page.GRANT_RESTRICTED, isEmpty: false });
  1099. const page3 = await Page.findOne({ path: path2 });
  1100. expect(pageT).toBeTruthy();
  1101. expect(page1).toBeTruthy();
  1102. expect(page2).toBeTruthy();
  1103. expect(page3).toBeTruthy();
  1104. await updatePage(page2, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_PUBLIC });
  1105. const _pageT = await Page.findOne({ path: pathT });
  1106. const _page1 = await Page.findOne({ path: path1, isEmpty: true }); // should be replaced
  1107. const _page2 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  1108. const _page3 = await Page.findOne({ path: path2 });
  1109. expect(_pageT).toBeTruthy();
  1110. expect(_page1).toBeNull();
  1111. expect(_page2).toBeTruthy();
  1112. expect(_page3).toBeTruthy();
  1113. expect(_page2.grant).toBe(Page.GRANT_PUBLIC);
  1114. expect(_page2.parent).toStrictEqual(_pageT._id);
  1115. expect(_page3.parent).toStrictEqual(_page2._id);
  1116. expect(_pageT.descendantCount).toBe(2);
  1117. });
  1118. });
  1119. describe('Changing grant to GRANT_OWNER(onlyme)', () => {
  1120. test('successfully change to GRANT_OWNER from GRANT_PUBLIC', async() => {
  1121. const path = '/mup19';
  1122. const _page = await Page.findOne({ path, grant: Page.GRANT_PUBLIC });
  1123. expect(_page).toBeTruthy();
  1124. await updatePage(_page, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_OWNER });
  1125. const page = await Page.findOne({ path });
  1126. expect(page.grant).toBe(Page.GRANT_OWNER);
  1127. expect(page.grantedUsers).toStrictEqual([dummyUser1._id]);
  1128. });
  1129. test('successfully change to GRANT_OWNER from GRANT_USER_GROUP', async() => {
  1130. const path = '/mup20';
  1131. const _page = await Page.findOne({ path, grant: Page.GRANT_USER_GROUP, grantedGroups: { $elemMatch: { item: userGroupIdPModelA } } });
  1132. expect(_page).toBeTruthy();
  1133. await updatePage(_page, 'newRevisionBody', 'oldRevisionBody', pModelUser1, { grant: Page.GRANT_OWNER });
  1134. const page = await Page.findOne({ path });
  1135. expect(page.grant).toBe(Page.GRANT_OWNER);
  1136. expect(page.grantedUsers).toStrictEqual([pModelUser1._id]);
  1137. expect(page.grantedGroups.length).toBe(0);
  1138. });
  1139. test('successfully change to GRANT_OWNER from GRANT_RESTRICTED', async() => {
  1140. const path = '/mup21';
  1141. const _page = await Page.findOne({ path, grant: Page.GRANT_RESTRICTED });
  1142. expect(_page).toBeTruthy();
  1143. await updatePage(_page, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_OWNER });
  1144. const page = await Page.findOne({ path });
  1145. expect(page.grant).toBe(Page.GRANT_OWNER);
  1146. expect(page.grantedUsers).toStrictEqual([dummyUser1._id]);
  1147. });
  1148. test('Failed to change to GRANT_OWNER if one of the ancestors is GRANT_USER_GROUP page', async() => {
  1149. const path1 = '/mup22';
  1150. const path2 = '/mup22/mup23';
  1151. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC });
  1152. const _page2 = await Page.findOne({ path: path2, grant: Page.GRANT_USER_GROUP, grantedGroups: { $elemMatch: { item: userGroupIdPModelA } } });
  1153. expect(_page1).toBeTruthy();
  1154. expect(_page2).toBeTruthy();
  1155. await expect(updatePage(_page1, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: Page.GRANT_OWNER }))
  1156. .rejects.toThrow(new Error('The selected grant or grantedGroup is not assignable to this page.'));
  1157. const page1 = await Page.findOne({ path1 });
  1158. expect(page1).toBeTruthy();
  1159. expect(page1.grant).toBe(Page.GRANT_PUBLIC);
  1160. expect(page1.grantedUsers).not.toStrictEqual([dummyUser1._id]);
  1161. });
  1162. });
  1163. describe('Changing grant to GRANT_USER_GROUP', () => {
  1164. describe('update grant of a page under a page with GRANT_PUBLIC', () => {
  1165. test('successfully change to GRANT_USER_GROUP from GRANT_PUBLIC if parent page is GRANT_PUBLIC', async() => {
  1166. // path
  1167. const path1 = '/mup24_pub';
  1168. const path2 = '/mup24_pub/mup25_pub';
  1169. // page
  1170. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC }); // out of update scope
  1171. const _page2 = await Page.findOne({ path: path2, grant: Page.GRANT_PUBLIC, parent: _page1._id }); // update target
  1172. expect(_page1).toBeTruthy();
  1173. expect(_page2).toBeTruthy();
  1174. const newGrantedGroups = [
  1175. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1176. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  1177. ];
  1178. const options = {
  1179. grant: Page.GRANT_USER_GROUP,
  1180. grantUserGroupIds: newGrantedGroups,
  1181. };
  1182. const updatedPage = await updatePage(_page2, 'new', 'old', pModelUser1, options); // from GRANT_PUBLIC to GRANT_USER_GROUP(userGroupIdPModelA)
  1183. const page1 = await Page.findById(_page1._id);
  1184. const page2 = await Page.findById(_page2._id);
  1185. expect(page1).toBeTruthy();
  1186. expect(page2).toBeTruthy();
  1187. expect(updatedPage).toBeTruthy();
  1188. expect(updatedPage._id).toStrictEqual(page2._id);
  1189. // check page2 grant and group
  1190. expect(page2.grant).toBe(Page.GRANT_USER_GROUP);
  1191. expect(normalizeGrantedGroups(page2.grantedGroups)).toStrictEqual(newGrantedGroups);
  1192. });
  1193. test('successfully change to GRANT_USER_GROUP from GRANT_RESTRICTED if parent page is GRANT_PUBLIC', async() => {
  1194. // path
  1195. const _path1 = '/mup26_awl';
  1196. // page
  1197. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_RESTRICTED });
  1198. expect(_page1).toBeTruthy();
  1199. const newGrantedGroups = [
  1200. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1201. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  1202. ];
  1203. const options = {
  1204. grant: Page.GRANT_USER_GROUP,
  1205. grantUserGroupIds: newGrantedGroups,
  1206. };
  1207. const updatedPage = await updatePage(_page1, 'new', 'old', pModelUser1, options); // from GRANT_RESTRICTED to GRANT_USER_GROUP(userGroupIdPModelA)
  1208. const page1 = await Page.findById(_page1._id);
  1209. expect(page1).toBeTruthy();
  1210. expect(updatedPage).toBeTruthy();
  1211. expect(updatedPage._id).toStrictEqual(page1._id);
  1212. // updated page
  1213. expect(page1.grant).toBe(Page.GRANT_USER_GROUP);
  1214. expect(normalizeGrantedGroups(page1.grantedGroups)).toStrictEqual(newGrantedGroups);
  1215. // parent's grant check
  1216. const parent = await Page.findById(page1.parent);
  1217. expect(parent.grant).toBe(Page.GRANT_PUBLIC);
  1218. });
  1219. test('successfully change to GRANT_USER_GROUP from GRANT_OWNER if parent page is GRANT_PUBLIC', async() => {
  1220. // path
  1221. const path1 = '/mup27_pub';
  1222. const path2 = '/mup27_pub/mup28_owner';
  1223. // page
  1224. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_PUBLIC }); // out of update scope
  1225. const _page2 = await Page.findOne({
  1226. path: path2, grant: Page.GRANT_OWNER, grantedUsers: [pModelUser1], parent: _page1._id,
  1227. }); // update target
  1228. expect(_page1).toBeTruthy();
  1229. expect(_page2).toBeTruthy();
  1230. const newGrantedGroups = [
  1231. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1232. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  1233. ];
  1234. const options = {
  1235. grant: Page.GRANT_USER_GROUP,
  1236. grantUserGroupIds: newGrantedGroups,
  1237. };
  1238. const updatedPage = await updatePage(_page2, 'new', 'old', pModelUser1, options); // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelA)
  1239. const page1 = await Page.findById(_page1._id);
  1240. const page2 = await Page.findById(_page2._id);
  1241. expect(page1).toBeTruthy();
  1242. expect(page2).toBeTruthy();
  1243. expect(updatedPage).toBeTruthy();
  1244. expect(updatedPage._id).toStrictEqual(page2._id);
  1245. // grant check
  1246. expect(page2.grant).toBe(Page.GRANT_USER_GROUP);
  1247. expect(normalizeGrantedGroups(page2.grantedGroups)).toStrictEqual(newGrantedGroups);
  1248. expect(page2.grantedUsers.length).toBe(0);
  1249. });
  1250. });
  1251. describe('update grant of a page under a page with GRANT_USER_GROUP', () => {
  1252. test('successfully change to GRANT_USER_GROUP if the group to set is the child or descendant of the parent page group', async() => {
  1253. // path
  1254. const _path1 = '/mup29_A';
  1255. const _path2 = '/mup29_A/mup30_owner';
  1256. // page
  1257. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroups: { $elemMatch: { item: userGroupIdPModelA } } }); // out of update scope
  1258. const _page2 = await Page.findOne({ // update target
  1259. path: _path2, grant: Page.GRANT_OWNER, grantedUsers: [pModelUser1], parent: _page1._id,
  1260. });
  1261. expect(_page1).toBeTruthy();
  1262. expect(_page2).toBeTruthy();
  1263. // First round
  1264. // Group relation(parent -> child): userGroupIdPModelA -> userGroupIdPModelB -> userGroupIdPModelC
  1265. const newGrantedGroups = [
  1266. { item: userGroupIdPModelB, type: GroupType.userGroup },
  1267. { item: externalUserGroupIdPModelB, type: GroupType.externalUserGroup },
  1268. ];
  1269. const options = {
  1270. grant: Page.GRANT_USER_GROUP,
  1271. grantUserGroupIds: newGrantedGroups,
  1272. };
  1273. const updatedPage = await updatePage(_page2, 'new', 'old', pModelUser3, options); // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelB)
  1274. const page1 = await Page.findById(_page1._id);
  1275. const page2 = await Page.findById(_page2._id);
  1276. expect(page1).toBeTruthy();
  1277. expect(page2).toBeTruthy();
  1278. expect(updatedPage).toBeTruthy();
  1279. expect(updatedPage._id).toStrictEqual(page2._id);
  1280. expect(page2.grant).toBe(Page.GRANT_USER_GROUP);
  1281. expect(normalizeGrantedGroups(page2.grantedGroups)).toStrictEqual(newGrantedGroups);
  1282. expect(page2.grantedUsers.length).toBe(0);
  1283. // Second round
  1284. // Update group to groupC which is a grandchild from pageA's point of view
  1285. const secondRoundNewGrantedGroups = [
  1286. { item: userGroupIdPModelC, type: GroupType.userGroup },
  1287. { item: externalUserGroupIdPModelC, type: GroupType.externalUserGroup },
  1288. ];
  1289. const secondRoundOptions = { grant: Page.GRANT_USER_GROUP, grantUserGroupIds: secondRoundNewGrantedGroups }; // from GRANT_USER_GROUP(userGroupIdPModelB) to GRANT_USER_GROUP(userGroupIdPModelC)
  1290. // undo grantedGroups populate to prevent Page.hydrate error
  1291. _page2.grantedGroups.forEach((group) => {
  1292. group.item = group.item._id;
  1293. });
  1294. const secondRoundUpdatedPage = await updatePage(_page2, 'new', 'new', pModelUser3, secondRoundOptions);
  1295. expect(secondRoundUpdatedPage).toBeTruthy();
  1296. expect(secondRoundUpdatedPage.grant).toBe(Page.GRANT_USER_GROUP);
  1297. expect(normalizeGrantedGroups(secondRoundUpdatedPage.grantedGroups)).toStrictEqual(secondRoundNewGrantedGroups);
  1298. });
  1299. test('Fail to change to GRANT_USER_GROUP if the group to set is NOT the child or descendant of the parent page group', async() => {
  1300. // path
  1301. const _path1 = '/mup31_A';
  1302. const _path2 = '/mup31_A/mup32_owner';
  1303. // page
  1304. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroups: { $elemMatch: { item: userGroupIdPModelA } } });
  1305. const _page2 = await Page.findOne({ // update target
  1306. path: _path2, grant: Page.GRANT_OWNER, grantedUsers: [pModelUser1._id], parent: _page1._id,
  1307. });
  1308. expect(_page1).toBeTruthy();
  1309. expect(_page2).toBeTruthy();
  1310. // group
  1311. const _groupIsolated = await UserGroup.findById(userGroupIdPModelIsolate);
  1312. expect(_groupIsolated).toBeTruthy();
  1313. // group parent check
  1314. expect(_groupIsolated.parent).toBeUndefined(); // should have no parent
  1315. const options = {
  1316. grant: Page.GRANT_USER_GROUP,
  1317. grantUserGroupIds: [
  1318. { item: userGroupIdPModelIsolate, type: GroupType.userGroup },
  1319. { item: externalUserGroupIdPModelIsolate, type: GroupType.externalUserGroup },
  1320. ],
  1321. };
  1322. await expect(updatePage(_page2, 'new', 'old', pModelUser1, options)) // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelIsolate)
  1323. .rejects.toThrow(new Error('The selected grant or grantedGroup is not assignable to this page.'));
  1324. const page1 = await Page.findById(_page1._id);
  1325. const page2 = await Page.findById(_page2._id);
  1326. expect(page1).toBeTruthy();
  1327. expect(page1).toBeTruthy();
  1328. expect(page2.grant).toBe(Page.GRANT_OWNER); // should be the same before the update
  1329. expect(page2.grantedUsers).toStrictEqual([pModelUser1._id]); // should be the same before the update
  1330. expect(page2.grantedGroups.length).toBe(0); // no group should be set
  1331. });
  1332. test('Fail to change to GRANT_USER_GROUP if the group to set is an ancestor of the parent page group', async() => {
  1333. // path
  1334. const _path1 = '/mup33_C';
  1335. const _path2 = '/mup33_C/mup34_owner';
  1336. // page
  1337. const _page1 = await Page.findOne({ path: _path1, grant: Page.GRANT_USER_GROUP, grantedGroups: { $elemMatch: { item: userGroupIdPModelC } } }); // groupC
  1338. const _page2 = await Page.findOne({ // update target
  1339. path: _path2, grant: Page.GRANT_OWNER, grantedUsers: [pModelUser3], parent: _page1._id,
  1340. });
  1341. expect(_page1).toBeTruthy();
  1342. expect(_page2).toBeTruthy();
  1343. const options = {
  1344. grant: Page.GRANT_USER_GROUP,
  1345. grantUserGroupIds: [
  1346. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1347. { item: externalUserGroupIdPModelA, type: GroupType.externalUserGroup },
  1348. ],
  1349. };
  1350. // Group relation(parent -> child): userGroupIdPModelA -> userGroupIdPModelB -> userGroupIdPModelC
  1351. // this should fail because the groupC is a descendant of groupA
  1352. await expect(updatePage(_page2, 'new', 'old', pModelUser3, options)) // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelA)
  1353. .rejects.toThrow(new Error('The selected grant or grantedGroup is not assignable to this page.'));
  1354. const page1 = await Page.findById(_page1._id);
  1355. const page2 = await Page.findById(_page2._id);
  1356. expect(page1).toBeTruthy();
  1357. expect(page2).toBeTruthy();
  1358. expect(page2.grant).toBe(Page.GRANT_OWNER); // should be the same before the update
  1359. expect(page2.grantedUsers).toStrictEqual([pModelUser3._id]); // should be the same before the update
  1360. expect(page2.grantedGroups.length).toBe(0); // no group should be set
  1361. });
  1362. });
  1363. describe('update grant of a page under a page with GRANT_OWNER', () => {
  1364. test('Fail to change from GRNAT_OWNER', async() => {
  1365. // path
  1366. const path1 = '/mup35_owner';
  1367. const path2 = '/mup35_owner/mup36_owner';
  1368. // page
  1369. const _page1 = await Page.findOne({ path: path1, grant: Page.GRANT_OWNER, grantedUsers: [pModelUser1] });
  1370. const _page2 = await Page.findOne({ // update target
  1371. path: path2, grant: Page.GRANT_OWNER, grantedUsers: [pModelUser1], parent: _page1._id,
  1372. });
  1373. expect(_page1).toBeTruthy();
  1374. expect(_page2).toBeTruthy();
  1375. const options = { grant: Page.GRANT_USER_GROUP, grantUserGroupIds: [{ item: userGroupIdPModelA, type: GroupType.userGroup }] };
  1376. await expect(updatePage(_page2, 'new', 'old', pModelUser1, options)) // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelA)
  1377. .rejects.toThrow(new Error('The selected grant or grantedGroup is not assignable to this page.'));
  1378. const page1 = await Page.findById(_page1.id);
  1379. const page2 = await Page.findById(_page2.id);
  1380. expect(page1).toBeTruthy();
  1381. expect(page2).toBeTruthy();
  1382. expect(page2.grant).toBe(Page.GRANT_OWNER); // should be the same before the update
  1383. expect(page2.grantedUsers).toStrictEqual([pModelUser1._id]); // should be the same before the update
  1384. expect(page2.grantedGroups.length).toBe(0); // no group should be set
  1385. });
  1386. });
  1387. });
  1388. });
  1389. // see: https://dev.growi.org/635a314eac6bcd85cbf359fc about the specification
  1390. describe('updatePage with overwriteScopesOfDescendants true', () => {
  1391. test('(case 1) it should update all granted descendant pages when update grant is GRANT_PUBLIC', async() => {
  1392. const upodPagegAB = await Page.findOne({ path: '/gAB_upod_1' });
  1393. const upodPagegB = await Page.findOne({ path: '/gAB_upod_1/gB_upod_1' });
  1394. const upodPageonlyB = await Page.findOne({ path: '/gAB_upod_1/onlyB_upod_1' });
  1395. expect(upodPagegAB).not.toBeNull();
  1396. expect(upodPagegB).not.toBeNull();
  1397. expect(upodPageonlyB).not.toBeNull();
  1398. expect(upodPagegAB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1399. expect(upodPagegB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1400. expect(upodPageonlyB.grant).toBe(PageGrant.GRANT_OWNER);
  1401. // Update
  1402. const options = {
  1403. grant: PageGrant.GRANT_PUBLIC,
  1404. overwriteScopesOfDescendants: true,
  1405. };
  1406. const updatedPage = await updatePage(upodPagegAB, 'newRevisionBody', 'oldRevisionBody', upodUserA, options);
  1407. const upodPagegBUpdated = await Page.findOne({ path: '/gAB_upod_1/gB_upod_1' });
  1408. const upodPageonlyBUpdated = await Page.findOne({ path: '/gAB_upod_1/onlyB_upod_1' });
  1409. // Changed
  1410. const newGrant = PageGrant.GRANT_PUBLIC;
  1411. expect(updatedPage.grant).toBe(newGrant);
  1412. // Not changed
  1413. expect(upodPagegBUpdated.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1414. expect(upodPagegBUpdated.grantedGroups).toStrictEqual(upodPagegB.grantedGroups);
  1415. expect(upodPageonlyBUpdated.grant).toBe(PageGrant.GRANT_OWNER);
  1416. expect(upodPageonlyBUpdated.grantedUsers).toStrictEqual(upodPageonlyB.grantedUsers);
  1417. });
  1418. test('(case 2) it should update all granted descendant pages when all descendant pages are granted by the operator', async() => {
  1419. const upodPagePublic = await Page.findOne({ path: '/public_upod_2' });
  1420. const upodPagegA = await Page.findOne({ path: '/public_upod_2/gA_upod_2' });
  1421. const upodPagegAIsolated = await Page.findOne({ path: '/public_upod_2/gAIsolated_upod_2' });
  1422. const upodPageonlyA = await Page.findOne({ path: '/public_upod_2/onlyA_upod_2' });
  1423. expect(upodPagePublic).not.toBeNull();
  1424. expect(upodPagegA).not.toBeNull();
  1425. expect(upodPagegAIsolated).not.toBeNull();
  1426. expect(upodPageonlyA).not.toBeNull();
  1427. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1428. expect(upodPagegA.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1429. expect(upodPagegAIsolated.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1430. expect(upodPageonlyA.grant).toBe(PageGrant.GRANT_OWNER);
  1431. // Update
  1432. const options = {
  1433. grant: PageGrant.GRANT_OWNER,
  1434. overwriteScopesOfDescendants: true,
  1435. };
  1436. const updatedPage = await updatePage(upodPagePublic, 'newRevisionBody', 'oldRevisionBody', upodUserA, options);
  1437. const upodPagegAUpdated = await Page.findOne({ path: '/public_upod_2/gA_upod_2' });
  1438. const upodPagegAIsolatedUpdated = await Page.findOne({ path: '/public_upod_2/gAIsolated_upod_2' });
  1439. const upodPageonlyAUpdated = await Page.findOne({ path: '/public_upod_2/onlyA_upod_2' });
  1440. // Changed
  1441. const newGrant = PageGrant.GRANT_OWNER;
  1442. const newGrantedUsers = [upodUserA._id];
  1443. expect(updatedPage.grant).toBe(newGrant);
  1444. expect(updatedPage.grantedUsers).toStrictEqual(newGrantedUsers);
  1445. expect(upodPagegAUpdated.grant).toBe(newGrant);
  1446. expect(upodPagegAUpdated.grantedUsers).toStrictEqual(newGrantedUsers);
  1447. expect(upodPagegAIsolatedUpdated.grant).toBe(newGrant);
  1448. expect(upodPagegAIsolatedUpdated.grantedUsers).toStrictEqual(newGrantedUsers);
  1449. expect(upodPageonlyAUpdated.grant).toBe(newGrant);
  1450. expect(upodPageonlyAUpdated.grantedUsers).toStrictEqual(newGrantedUsers);
  1451. });
  1452. test(`(case 3) it should update all granted descendant pages when update grant is GRANT_USER_GROUP
  1453. , all user groups of descendants are the children or itself of the update user group
  1454. , and all users of descendants belong to the update user group`, async() => {
  1455. const upodPagePublic = await Page.findOne({ path: '/public_upod_3' });
  1456. const upodPagegAB = await Page.findOne({ path: '/public_upod_3/gAB_upod_3' });
  1457. const upodPagegAgB = await Page.findOne({ path: '/public_upod_3/gA_gB_upod_3' });
  1458. const upodPagegB = await Page.findOne({ path: '/public_upod_3/gB_upod_3' });
  1459. const upodPageonlyB = await Page.findOne({ path: '/public_upod_3/onlyB_upod_3' });
  1460. expect(upodPagePublic).not.toBeNull();
  1461. expect(upodPagegAB).not.toBeNull();
  1462. expect(upodPagegAgB).not.toBeNull();
  1463. expect(upodPagegB).not.toBeNull();
  1464. expect(upodPageonlyB).not.toBeNull();
  1465. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1466. expect(upodPagegAB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1467. expect(upodPagegAgB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1468. expect(upodPagegB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1469. expect(upodPageonlyB.grant).toBe(PageGrant.GRANT_OWNER);
  1470. // Update
  1471. const options = {
  1472. grant: PageGrant.GRANT_USER_GROUP,
  1473. grantUserGroupIds: [
  1474. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1475. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  1476. ],
  1477. overwriteScopesOfDescendants: true,
  1478. };
  1479. const updatedPage = await updatePage(upodPagePublic, 'newRevisionBody', 'oldRevisionBody', upodUserA, options);
  1480. const upodPagegABUpdated = await Page.findOne({ path: '/public_upod_3/gAB_upod_3' });
  1481. const upodPagegAgBUpdated = await Page.findOne({ path: '/public_upod_3/gA_gB_upod_3' });
  1482. const upodPagegBUpdated = await Page.findOne({ path: '/public_upod_3/gB_upod_3' });
  1483. const upodPageonlyBUpdated = await Page.findOne({ path: '/public_upod_3/onlyB_upod_3' });
  1484. // Changed
  1485. const newGrant = PageGrant.GRANT_USER_GROUP;
  1486. const newGrantedGroups = [
  1487. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1488. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  1489. ];
  1490. expect(updatedPage.grant).toBe(newGrant);
  1491. expect(normalizeGrantedGroups(updatedPage.grantedGroups)).toStrictEqual(newGrantedGroups);
  1492. expect(upodPagegABUpdated.grant).toBe(newGrant);
  1493. expect(normalizeGrantedGroups(upodPagegABUpdated.grantedGroups)).toStrictEqual(newGrantedGroups);
  1494. expect(upodPagegAgBUpdated.grant).toBe(newGrant);
  1495. // For multi group granted pages, the grant update will only add/remove groups that the user belongs to,
  1496. // and groups that the user doesn't belong to will stay as it was before the update.
  1497. expect(normalizeGrantedGroups(upodPagegAgBUpdated.grantedGroups)).toEqual(expect.arrayContaining([
  1498. ...newGrantedGroups,
  1499. { item: upodUserGroupIdB, type: GroupType.userGroup },
  1500. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  1501. ]));
  1502. // Not changed
  1503. expect(upodPagegBUpdated.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1504. expect(upodPagegBUpdated.grantedGroups).toStrictEqual(upodPagegB.grantedGroups);
  1505. expect(upodPageonlyBUpdated.grant).toBe(PageGrant.GRANT_OWNER);
  1506. expect(upodPageonlyBUpdated.grantedUsers).toStrictEqual(upodPageonlyB.grantedUsers);
  1507. });
  1508. test(`(case 4) it should throw when some of descendants is not granted
  1509. , update grant is GRANT_USER_GROUP
  1510. , and some of user groups of descendants are not children or itself of the update user group`, async() => {
  1511. const upodPagePublic = await Page.findOne({ path: '/public_upod_4' });
  1512. const upodPagegA = await Page.findOne({ path: '/public_upod_4/gA_upod_4' });
  1513. const upodPagegC = await Page.findOne({ path: '/public_upod_4/gC_upod_4' });
  1514. expect(upodPagePublic).not.toBeNull();
  1515. expect(upodPagegA).not.toBeNull();
  1516. expect(upodPagegC).not.toBeNull();
  1517. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1518. expect(upodPagegA.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1519. expect(upodPagegC.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1520. // Update
  1521. const options = {
  1522. grant: PageGrant.GRANT_USER_GROUP,
  1523. grantUserGroupIds: [
  1524. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1525. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  1526. ],
  1527. overwriteScopesOfDescendants: true,
  1528. };
  1529. const updatedPagePromise = updatePage(upodPagePublic, 'newRevisionBody', 'oldRevisionBody', upodUserA, options);
  1530. await expect(updatedPagePromise).rejects.toThrowError();
  1531. });
  1532. test(`(case 5) it should throw when some of descendants is not granted
  1533. , update grant is GRANT_USER_GROUP
  1534. , and some of users of descendants does NOT belong to the update user group`, async() => {
  1535. const upodPagePublic = await Page.findOne({ path: '/public_upod_5' });
  1536. const upodPagegA = await Page.findOne({ path: '/public_upod_5/gA_upod_5' });
  1537. const upodPageonlyC = await Page.findOne({ path: '/public_upod_5/onlyC_upod_5' });
  1538. expect(upodPagePublic).not.toBeNull();
  1539. expect(upodPagegA).not.toBeNull();
  1540. expect(upodPageonlyC).not.toBeNull();
  1541. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1542. expect(upodPagegA.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1543. expect(upodPageonlyC.grant).toBe(PageGrant.GRANT_OWNER);
  1544. // Update
  1545. const options = {
  1546. grant: PageGrant.GRANT_USER_GROUP,
  1547. grantUserGroupIds: [
  1548. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1549. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  1550. ],
  1551. overwriteScopesOfDescendants: true,
  1552. };
  1553. const updatedPagePromise = updatePage(upodPagePublic, 'newRevisionBody', 'oldRevisionBody', upodUserA, options);
  1554. await expect(updatedPagePromise).rejects.toThrowError();
  1555. });
  1556. test('(case 6) it should throw when some of descendants is not granted and update grant is GRANT_OWNER', async() => {
  1557. const upodPagePublic = await Page.findOne({ path: '/public_upod_6' });
  1558. const upodPageonlyC = await Page.findOne({ path: '/public_upod_6/onlyC_upod_6' });
  1559. expect(upodPagePublic).not.toBeNull();
  1560. expect(upodPageonlyC).not.toBeNull();
  1561. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1562. expect(upodPageonlyC.grant).toBe(PageGrant.GRANT_OWNER);
  1563. // Update
  1564. const options = {
  1565. grant: PageGrant.GRANT_USER_GROUP,
  1566. grantUserGroupIds: [
  1567. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1568. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  1569. ],
  1570. overwriteScopesOfDescendants: true,
  1571. };
  1572. const updatedPagePromise = updatePage(upodPagePublic, 'newRevisionBody', 'oldRevisionBody', upodUserA, options);
  1573. await expect(updatedPagePromise).rejects.toThrowError();
  1574. });
  1575. });
  1576. });