v5.page.test.js 67 KB

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