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