v5.page.test.js 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195
  1. import { GroupType, getIdForRef, PageGrant } 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 (
  62. page,
  63. newRevisionBody,
  64. oldRevisionBody,
  65. user,
  66. options = {},
  67. ) => {
  68. const mockedUpdatePageSubOperation = jest
  69. .spyOn(pageService, 'updatePageSubOperation')
  70. .mockReturnValue(null);
  71. const savedPage = await pageService.updatePage(
  72. page,
  73. newRevisionBody,
  74. oldRevisionBody,
  75. user,
  76. options,
  77. );
  78. const argsForUpdatePageSubOperation =
  79. mockedUpdatePageSubOperation.mock.calls[0];
  80. mockedUpdatePageSubOperation.mockRestore();
  81. await pageService.updatePageSubOperation(...argsForUpdatePageSubOperation);
  82. return savedPage;
  83. };
  84. const createDocumentsToTestUpdatePageOverwritingDescendants = async () => {
  85. // Users
  86. await User.insertMany([
  87. {
  88. name: 'upodUserA',
  89. username: 'upodUserA',
  90. email: 'upoduserA@example.com',
  91. },
  92. {
  93. name: 'upodUserB',
  94. username: 'upodUserB',
  95. email: 'upoduserB@example.com',
  96. },
  97. {
  98. name: 'upodUserC',
  99. username: 'upodUserC',
  100. email: 'upodUserC@example.com',
  101. },
  102. ]);
  103. upodUserA = await User.findOne({ username: 'upodUserA' });
  104. upodUserB = await User.findOne({ username: 'upodUserB' });
  105. upodUserC = await User.findOne({ username: 'upodUserC' });
  106. await UserGroup.insertMany([
  107. {
  108. _id: upodUserGroupIdAB,
  109. name: 'upodGroupAB',
  110. parent: null,
  111. },
  112. {
  113. _id: upodUserGroupIdA,
  114. name: 'upodGroupA',
  115. parent: upodUserGroupIdAB,
  116. },
  117. {
  118. _id: upodUserGroupIdAIsolated,
  119. name: 'upodGroupAIsolated',
  120. parent: null,
  121. },
  122. {
  123. _id: upodUserGroupIdB,
  124. name: 'upodGroupB',
  125. parent: upodUserGroupIdAB,
  126. },
  127. {
  128. _id: upodUserGroupIdC,
  129. name: 'upodGroupC',
  130. parent: null,
  131. },
  132. ]);
  133. upodGroupAB = await UserGroup.findOne({ name: 'upodGroupAB' });
  134. upodGroupA = await UserGroup.findOne({ name: 'upodGroupA' });
  135. upodGroupAIsolated = await UserGroup.findOne({
  136. name: 'upodGroupAIsolated',
  137. });
  138. upodGroupB = await UserGroup.findOne({ name: 'upodGroupB' });
  139. upodGroupC = await UserGroup.findOne({ name: 'upodGroupC' });
  140. // UserGroupRelations
  141. await UserGroupRelation.insertMany([
  142. {
  143. relatedGroup: upodUserGroupIdAB,
  144. relatedUser: upodUserA._id,
  145. },
  146. {
  147. relatedGroup: upodUserGroupIdAB,
  148. relatedUser: upodUserB._id,
  149. },
  150. {
  151. relatedGroup: upodUserGroupIdA,
  152. relatedUser: upodUserA._id,
  153. },
  154. {
  155. relatedGroup: upodUserGroupIdAIsolated,
  156. relatedUser: upodUserA._id,
  157. },
  158. {
  159. relatedGroup: upodUserGroupIdB,
  160. relatedUser: upodUserB._id,
  161. },
  162. {
  163. relatedGroup: upodUserGroupIdC,
  164. relatedUser: upodUserC._id,
  165. },
  166. ]);
  167. // Insert ExternalUserGroups with the same group structure as UserGroups
  168. // Use to test
  169. // - ExternalUserGroup
  170. // - Case of multiple grantedGroups for Page
  171. await ExternalUserGroup.insertMany([
  172. {
  173. _id: upodExternalUserGroupIdAB,
  174. name: 'upodExternalGroupAB',
  175. parent: null,
  176. externalId: 'upodExternalGroupAB',
  177. provider: ExternalGroupProviderType.ldap,
  178. },
  179. {
  180. _id: upodExternalUserGroupIdA,
  181. name: 'upodExternalGroupA',
  182. parent: upodExternalUserGroupIdAB,
  183. externalId: 'upodExternalGroupA',
  184. provider: ExternalGroupProviderType.ldap,
  185. },
  186. {
  187. _id: upodExternalUserGroupIdAIsolated,
  188. name: 'upodExternalGroupAIsolated',
  189. parent: null,
  190. externalId: 'upodExternalGroupAIsolated',
  191. provider: ExternalGroupProviderType.ldap,
  192. },
  193. {
  194. _id: upodExternalUserGroupIdB,
  195. name: 'upodExternalGroupB',
  196. parent: upodExternalUserGroupIdAB,
  197. externalId: 'upodExternalGroupB',
  198. provider: ExternalGroupProviderType.ldap,
  199. },
  200. {
  201. _id: upodExternalUserGroupIdC,
  202. name: 'upodExternalGroupC',
  203. parent: null,
  204. externalId: 'upodExternalGroupC',
  205. provider: ExternalGroupProviderType.ldap,
  206. },
  207. ]);
  208. // ExternalUserGroupRelations
  209. await ExternalUserGroupRelation.insertMany([
  210. {
  211. relatedGroup: upodExternalUserGroupIdAB,
  212. relatedUser: upodUserA._id,
  213. },
  214. {
  215. relatedGroup: upodExternalUserGroupIdAB,
  216. relatedUser: upodUserB._id,
  217. },
  218. {
  219. relatedGroup: upodExternalUserGroupIdA,
  220. relatedUser: upodUserA._id,
  221. },
  222. {
  223. relatedGroup: upodExternalUserGroupIdAIsolated,
  224. relatedUser: upodUserA._id,
  225. },
  226. {
  227. relatedGroup: upodExternalUserGroupIdB,
  228. relatedUser: upodUserB._id,
  229. },
  230. {
  231. relatedGroup: upodExternalUserGroupIdC,
  232. relatedUser: upodUserC._id,
  233. },
  234. ]);
  235. // Pages
  236. await Page.insertMany([
  237. // case 1
  238. {
  239. _id: upodPageIdgAB1,
  240. path: '/gAB_upod_1', // to GRANT_PUBLIC
  241. grant: PageGrant.GRANT_USER_GROUP,
  242. creator: upodUserA,
  243. lastUpdateUser: upodUserA,
  244. grantedUsers: null,
  245. grantedGroups: [
  246. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  247. {
  248. item: upodExternalUserGroupIdAB,
  249. type: GroupType.externalUserGroup,
  250. },
  251. ],
  252. parent: rootPage._id,
  253. },
  254. {
  255. path: '/gAB_upod_1/gB_upod_1',
  256. grant: PageGrant.GRANT_USER_GROUP,
  257. creator: upodUserB,
  258. lastUpdateUser: upodUserB,
  259. grantedUsers: null,
  260. grantedGroups: [
  261. { item: upodUserGroupIdB, type: GroupType.userGroup },
  262. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  263. ],
  264. parent: upodPageIdgAB1,
  265. },
  266. {
  267. path: '/gAB_upod_1/onlyB_upod_1',
  268. grant: PageGrant.GRANT_OWNER,
  269. creator: upodUserB,
  270. lastUpdateUser: upodUserB,
  271. grantedUsers: [upodUserB._id],
  272. grantedGroups: [],
  273. parent: upodPageIdgAB1,
  274. },
  275. // grant user A and B with independent groups
  276. {
  277. path: '/gAB_upod_1/gA_gB_upod_1',
  278. grant: PageGrant.GRANT_USER_GROUP,
  279. creator: upodUserA,
  280. lastUpdateUser: upodUserA,
  281. grantedUsers: null,
  282. grantedGroups: [
  283. { item: upodUserGroupIdA, type: GroupType.userGroup },
  284. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  285. { item: upodUserGroupIdB, type: GroupType.userGroup },
  286. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  287. ],
  288. parent: upodPageIdgAB1,
  289. },
  290. // case 2
  291. {
  292. _id: upodPageIdPublic2,
  293. path: '/public_upod_2', // to Anything
  294. grant: PageGrant.GRANT_PUBLIC,
  295. creator: upodUserA,
  296. lastUpdateUser: upodUserA,
  297. grantedUsers: null,
  298. grantedGroups: [],
  299. parent: rootPage._id,
  300. },
  301. {
  302. path: '/public_upod_2/gA_upod_2',
  303. grant: PageGrant.GRANT_USER_GROUP,
  304. creator: upodUserA,
  305. lastUpdateUser: upodUserA,
  306. grantedUsers: null,
  307. grantedGroups: [
  308. { item: upodUserGroupIdA, type: GroupType.userGroup },
  309. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  310. ],
  311. parent: upodPageIdPublic2,
  312. },
  313. {
  314. path: '/public_upod_2/gAIsolated_upod_2',
  315. grant: PageGrant.GRANT_USER_GROUP,
  316. creator: upodUserA,
  317. lastUpdateUser: upodUserA,
  318. grantedUsers: null,
  319. grantedGroups: [
  320. { item: upodUserGroupIdAIsolated, type: GroupType.userGroup },
  321. {
  322. item: upodExternalUserGroupIdAIsolated,
  323. type: GroupType.externalUserGroup,
  324. },
  325. ],
  326. parent: upodPageIdPublic2,
  327. },
  328. {
  329. path: '/public_upod_2/onlyA_upod_2',
  330. grant: PageGrant.GRANT_OWNER,
  331. creator: upodUserA,
  332. lastUpdateUser: upodUserA,
  333. grantedUsers: [upodUserA._id],
  334. grantedGroups: [],
  335. parent: upodPageIdPublic2,
  336. },
  337. // case 3
  338. {
  339. _id: upodPageIdPublic3,
  340. path: '/public_upod_3', // to GRANT_USER_GROUP with upodGroupAB
  341. grant: PageGrant.GRANT_PUBLIC,
  342. creator: upodUserA,
  343. lastUpdateUser: upodUserA,
  344. grantedUsers: null,
  345. grantedGroups: [],
  346. parent: rootPage._id,
  347. },
  348. // grant user A and B with a single group
  349. // (external group is extra for testing external groups)
  350. {
  351. path: '/public_upod_3/gAB_upod_3',
  352. grant: PageGrant.GRANT_USER_GROUP,
  353. creator: upodUserA,
  354. lastUpdateUser: upodUserA,
  355. grantedUsers: null,
  356. grantedGroups: [
  357. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  358. {
  359. item: upodExternalUserGroupIdAB,
  360. type: GroupType.externalUserGroup,
  361. },
  362. ],
  363. parent: upodPageIdPublic3,
  364. },
  365. // grant user A and B with independent groups
  366. {
  367. path: '/public_upod_3/gA_gB_upod_3',
  368. grant: PageGrant.GRANT_USER_GROUP,
  369. creator: upodUserA,
  370. lastUpdateUser: upodUserA,
  371. grantedUsers: null,
  372. grantedGroups: [
  373. { item: upodUserGroupIdA, type: GroupType.userGroup },
  374. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  375. { item: upodUserGroupIdB, type: GroupType.userGroup },
  376. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  377. ],
  378. parent: upodPageIdPublic3,
  379. },
  380. {
  381. path: '/public_upod_3/gB_upod_3',
  382. grant: PageGrant.GRANT_USER_GROUP,
  383. creator: upodUserB,
  384. lastUpdateUser: upodUserB,
  385. grantedUsers: null,
  386. grantedGroups: [
  387. { item: upodUserGroupIdB, type: GroupType.userGroup },
  388. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  389. ],
  390. parent: upodPageIdPublic3,
  391. },
  392. {
  393. path: '/public_upod_3/onlyB_upod_3',
  394. grant: PageGrant.GRANT_OWNER,
  395. creator: upodUserB,
  396. lastUpdateUser: upodUserB,
  397. grantedUsers: [upodUserB._id],
  398. grantedGroups: [],
  399. parent: upodPageIdPublic3,
  400. },
  401. // case 4
  402. {
  403. _id: upodPageIdPublic4,
  404. path: '/public_upod_4', // to GRANT_USER_GROUP with upodGroupAB
  405. grant: PageGrant.GRANT_PUBLIC,
  406. creator: upodUserA,
  407. lastUpdateUser: upodUserA,
  408. grantedUsers: null,
  409. grantedGroups: [],
  410. parent: rootPage._id,
  411. },
  412. {
  413. path: '/public_upod_4/gA_upod_4',
  414. grant: PageGrant.GRANT_USER_GROUP,
  415. creator: upodUserA,
  416. lastUpdateUser: upodUserA,
  417. grantedUsers: null,
  418. grantedGroups: [
  419. { item: upodUserGroupIdA, type: GroupType.userGroup },
  420. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  421. ],
  422. parent: upodPageIdPublic4,
  423. },
  424. {
  425. path: '/public_upod_4/gC_upod_4',
  426. grant: PageGrant.GRANT_USER_GROUP,
  427. creator: upodUserC,
  428. lastUpdateUser: upodUserC,
  429. grantedUsers: null,
  430. grantedGroups: [
  431. { item: upodUserGroupIdC, type: GroupType.userGroup },
  432. { item: upodExternalUserGroupIdC, type: GroupType.externalUserGroup },
  433. ],
  434. parent: upodPageIdPublic4,
  435. },
  436. // case 5
  437. {
  438. _id: upodPageIdPublic5,
  439. path: '/public_upod_5', // to GRANT_USER_GROUP with upodGroupAB
  440. grant: PageGrant.GRANT_PUBLIC,
  441. creator: upodUserA,
  442. lastUpdateUser: upodUserA,
  443. grantedUsers: null,
  444. grantedGroups: [],
  445. parent: rootPage._id,
  446. },
  447. {
  448. path: '/public_upod_5/gA_upod_5',
  449. grant: PageGrant.GRANT_USER_GROUP,
  450. creator: upodUserA,
  451. lastUpdateUser: upodUserA,
  452. grantedUsers: null,
  453. grantedGroups: [
  454. { item: upodUserGroupIdA, type: GroupType.userGroup },
  455. { item: upodExternalUserGroupIdA, type: GroupType.externalUserGroup },
  456. ],
  457. parent: upodPageIdPublic5,
  458. },
  459. {
  460. path: '/public_upod_5/onlyC_upod_5',
  461. grant: PageGrant.GRANT_OWNER,
  462. creator: upodUserC,
  463. lastUpdateUser: upodUserC,
  464. grantedUsers: [upodUserC._id],
  465. grantedGroups: [],
  466. parent: upodPageIdPublic5,
  467. },
  468. // case 6
  469. {
  470. _id: upodPageIdPublic6,
  471. path: '/public_upod_6', // to GRANT_USER_GROUP with upodGroupAB
  472. grant: PageGrant.GRANT_PUBLIC,
  473. creator: upodUserA,
  474. lastUpdateUser: upodUserA,
  475. grantedUsers: null,
  476. grantedGroups: [],
  477. parent: rootPage._id,
  478. },
  479. {
  480. path: '/public_upod_6/onlyC_upod_6',
  481. grant: PageGrant.GRANT_OWNER,
  482. creator: upodUserC,
  483. lastUpdateUser: upodUserC,
  484. grantedUsers: [upodUserC._id],
  485. grantedGroups: [],
  486. parent: upodPageIdPublic6,
  487. },
  488. ]);
  489. };
  490. // normalize for result comparison
  491. const normalizeGrantedGroups = (grantedGroups) => {
  492. return grantedGroups.map((group) => {
  493. return { item: getIdForRef(group.item), type: group.type };
  494. });
  495. };
  496. beforeAll(async () => {
  497. crowi = await getInstance();
  498. pageGrantService = crowi.pageGrantService;
  499. pageService = crowi.pageService;
  500. await crowi.configManager.updateConfig('app:isV5Compatible', true);
  501. jest.restoreAllMocks();
  502. User = mongoose.model('User');
  503. Page = mongoose.model('Page');
  504. Revision = mongoose.model('Revision');
  505. Bookmark = mongoose.model('Bookmark');
  506. Comment = mongoose.model('Comment');
  507. ShareLink = mongoose.model('ShareLink');
  508. PageRedirect = mongoose.model('PageRedirect');
  509. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  510. rootPage = await Page.findOne({ path: '/' });
  511. const pModelUserId1 = new mongoose.Types.ObjectId();
  512. const pModelUserId2 = new mongoose.Types.ObjectId();
  513. const pModelUserId3 = new mongoose.Types.ObjectId();
  514. await User.insertMany([
  515. {
  516. _id: pModelUserId1,
  517. name: 'pmodelUser1',
  518. username: 'pmodelUser1',
  519. email: 'pmodelUser1@example.com',
  520. },
  521. {
  522. _id: pModelUserId2,
  523. name: 'pmodelUser2',
  524. username: 'pmodelUser2',
  525. email: 'pmodelUser2@example.com',
  526. },
  527. {
  528. _id: pModelUserId3,
  529. name: 'pModelUser3',
  530. username: 'pModelUser3',
  531. email: 'pModelUser3@example.com',
  532. },
  533. ]);
  534. pModelUser1 = await User.findOne({ _id: pModelUserId1 });
  535. pModelUser2 = await User.findOne({ _id: pModelUserId2 });
  536. pModelUser3 = await User.findOne({ _id: pModelUserId3 });
  537. userGroupIdPModelIsolate = new mongoose.Types.ObjectId();
  538. userGroupIdPModelA = new mongoose.Types.ObjectId();
  539. userGroupIdPModelB = new mongoose.Types.ObjectId();
  540. userGroupIdPModelC = new mongoose.Types.ObjectId();
  541. await UserGroup.insertMany([
  542. {
  543. _id: userGroupIdPModelIsolate,
  544. name: 'pModel_groupIsolate',
  545. },
  546. {
  547. _id: userGroupIdPModelA,
  548. name: 'pModel_groupA',
  549. },
  550. {
  551. _id: userGroupIdPModelB,
  552. name: 'pModel_groupB',
  553. parent: userGroupIdPModelA,
  554. },
  555. {
  556. _id: userGroupIdPModelC,
  557. name: 'pModel_groupC',
  558. parent: userGroupIdPModelB,
  559. },
  560. ]);
  561. await UserGroupRelation.insertMany([
  562. {
  563. relatedGroup: userGroupIdPModelIsolate,
  564. relatedUser: pModelUserId1,
  565. createdAt: new Date(),
  566. },
  567. {
  568. relatedGroup: userGroupIdPModelIsolate,
  569. relatedUser: pModelUserId2,
  570. createdAt: new Date(),
  571. },
  572. {
  573. relatedGroup: userGroupIdPModelA,
  574. relatedUser: pModelUserId1,
  575. createdAt: new Date(),
  576. },
  577. {
  578. relatedGroup: userGroupIdPModelA,
  579. relatedUser: pModelUserId2,
  580. createdAt: new Date(),
  581. },
  582. {
  583. relatedGroup: userGroupIdPModelA,
  584. relatedUser: pModelUserId3,
  585. createdAt: new Date(),
  586. },
  587. {
  588. relatedGroup: userGroupIdPModelB,
  589. relatedUser: pModelUserId2,
  590. createdAt: new Date(),
  591. },
  592. {
  593. relatedGroup: userGroupIdPModelB,
  594. relatedUser: pModelUserId3,
  595. createdAt: new Date(),
  596. },
  597. {
  598. relatedGroup: userGroupIdPModelC,
  599. relatedUser: pModelUserId3,
  600. createdAt: new Date(),
  601. },
  602. ]);
  603. // Insert ExternalUserGroups with the same group structure as UserGroups
  604. // Use to test
  605. // - ExternalUserGroup
  606. // - Case of multiple grantedGroups for Page
  607. externalUserGroupIdPModelIsolate = new mongoose.Types.ObjectId();
  608. externalUserGroupIdPModelA = new mongoose.Types.ObjectId();
  609. externalUserGroupIdPModelB = new mongoose.Types.ObjectId();
  610. externalUserGroupIdPModelC = new mongoose.Types.ObjectId();
  611. await ExternalUserGroup.insertMany([
  612. {
  613. _id: externalUserGroupIdPModelIsolate,
  614. name: 'pModel_externalGroupIsolate',
  615. externalId: 'pModel_externalGroupIsolate',
  616. provider: ExternalGroupProviderType.ldap,
  617. },
  618. {
  619. _id: externalUserGroupIdPModelA,
  620. name: 'pModel_externalGroupA',
  621. externalId: 'pModel_externalGroupA',
  622. provider: ExternalGroupProviderType.ldap,
  623. },
  624. {
  625. _id: externalUserGroupIdPModelB,
  626. name: 'pModel_externalGroupB',
  627. parent: externalUserGroupIdPModelA,
  628. externalId: 'pModel_externalGroupB',
  629. provider: ExternalGroupProviderType.ldap,
  630. },
  631. {
  632. _id: externalUserGroupIdPModelC,
  633. name: 'pModel_externalGroupC',
  634. parent: externalUserGroupIdPModelB,
  635. externalId: 'pModel_externalGroupC',
  636. provider: ExternalGroupProviderType.ldap,
  637. },
  638. ]);
  639. await ExternalUserGroupRelation.insertMany([
  640. {
  641. relatedGroup: externalUserGroupIdPModelIsolate,
  642. relatedUser: pModelUserId1,
  643. createdAt: new Date(),
  644. },
  645. {
  646. relatedGroup: externalUserGroupIdPModelIsolate,
  647. relatedUser: pModelUserId2,
  648. createdAt: new Date(),
  649. },
  650. {
  651. relatedGroup: externalUserGroupIdPModelA,
  652. relatedUser: pModelUserId1,
  653. createdAt: new Date(),
  654. },
  655. {
  656. relatedGroup: externalUserGroupIdPModelA,
  657. relatedUser: pModelUserId2,
  658. createdAt: new Date(),
  659. },
  660. {
  661. relatedGroup: externalUserGroupIdPModelA,
  662. relatedUser: pModelUserId3,
  663. createdAt: new Date(),
  664. },
  665. {
  666. relatedGroup: externalUserGroupIdPModelB,
  667. relatedUser: pModelUserId2,
  668. createdAt: new Date(),
  669. },
  670. {
  671. relatedGroup: externalUserGroupIdPModelB,
  672. relatedUser: pModelUserId3,
  673. createdAt: new Date(),
  674. },
  675. {
  676. relatedGroup: externalUserGroupIdPModelC,
  677. relatedUser: pModelUserId3,
  678. createdAt: new Date(),
  679. },
  680. ]);
  681. /**
  682. * update
  683. * mup_ => model update
  684. * emp => empty => page with isEmpty: true
  685. * pub => public => GRANT_PUBLIC
  686. * awl => Anyone with the link => GRANT_RESTRICTED
  687. */
  688. const pageIdUpd1 = new mongoose.Types.ObjectId();
  689. const pageIdUpd2 = new mongoose.Types.ObjectId();
  690. const pageIdUpd3 = new mongoose.Types.ObjectId();
  691. const pageIdUpd4 = new mongoose.Types.ObjectId();
  692. const pageIdUpd5 = new mongoose.Types.ObjectId();
  693. const pageIdUpd6 = new mongoose.Types.ObjectId();
  694. const pageIdUpd7 = new mongoose.Types.ObjectId();
  695. const pageIdUpd8 = new mongoose.Types.ObjectId();
  696. const pageIdUpd9 = new mongoose.Types.ObjectId();
  697. const pageIdUpd10 = new mongoose.Types.ObjectId();
  698. const pageIdUpd11 = new mongoose.Types.ObjectId();
  699. const pageIdUpd12 = new mongoose.Types.ObjectId();
  700. const pageIdUpd13 = new mongoose.Types.ObjectId();
  701. const pageIdUpd14 = new mongoose.Types.ObjectId();
  702. const pageIdUpd15 = new mongoose.Types.ObjectId();
  703. const pageIdUpd16 = new mongoose.Types.ObjectId();
  704. const pageIdUpd17 = new mongoose.Types.ObjectId();
  705. const pageIdUpd18 = new mongoose.Types.ObjectId();
  706. const pageIdUpd19 = new mongoose.Types.ObjectId();
  707. await Page.insertMany([
  708. {
  709. _id: pageIdUpd1,
  710. path: '/mup13_top/mup1_emp',
  711. grant: Page.GRANT_PUBLIC,
  712. parent: pageIdUpd8._id,
  713. isEmpty: true,
  714. },
  715. {
  716. _id: pageIdUpd2,
  717. path: '/mup13_top/mup1_emp/mup2_pub',
  718. grant: Page.GRANT_PUBLIC,
  719. parent: pageIdUpd1._id,
  720. creator: dummyUser1,
  721. lastUpdateUser: dummyUser1._id,
  722. isEmpty: false,
  723. },
  724. {
  725. _id: pageIdUpd3,
  726. path: '/mup14_top/mup6_pub',
  727. grant: Page.GRANT_PUBLIC,
  728. creator: dummyUser1,
  729. lastUpdateUser: dummyUser1._id,
  730. parent: pageIdUpd9,
  731. isEmpty: false,
  732. descendantCount: 1,
  733. },
  734. {
  735. path: '/mup14_top/mup6_pub/mup7_pub',
  736. grant: Page.GRANT_PUBLIC,
  737. creator: dummyUser1,
  738. lastUpdateUser: dummyUser1._id,
  739. parent: pageIdUpd3,
  740. isEmpty: false,
  741. descendantCount: 0,
  742. },
  743. {
  744. _id: pageIdUpd4,
  745. path: '/mup15_top/mup8_pub',
  746. grant: Page.GRANT_PUBLIC,
  747. creator: dummyUser1,
  748. lastUpdateUser: dummyUser1._id,
  749. parent: pageIdUpd10._id,
  750. isEmpty: false,
  751. },
  752. {
  753. _id: pageIdUpd5,
  754. path: '/mup16_top/mup9_pub/mup10_pub/mup11_awl',
  755. grant: Page.GRANT_RESTRICTED,
  756. creator: dummyUser1,
  757. lastUpdateUser: dummyUser1._id,
  758. isEmpty: false,
  759. },
  760. {
  761. _id: pageIdUpd6,
  762. path: '/mup17_top/mup12_emp',
  763. isEmpty: true,
  764. parent: pageIdUpd12._id,
  765. descendantCount: 1,
  766. },
  767. {
  768. _id: pageIdUpd7,
  769. path: '/mup17_top/mup12_emp',
  770. grant: Page.GRANT_RESTRICTED,
  771. creator: dummyUser1,
  772. lastUpdateUser: dummyUser1._id,
  773. isEmpty: false,
  774. },
  775. {
  776. path: '/mup17_top/mup12_emp/mup18_pub',
  777. isEmpty: false,
  778. creator: dummyUser1,
  779. lastUpdateUser: dummyUser1._id,
  780. parent: pageIdUpd6._id,
  781. },
  782. {
  783. _id: pageIdUpd8,
  784. path: '/mup13_top',
  785. grant: Page.GRANT_PUBLIC,
  786. creator: dummyUser1,
  787. lastUpdateUser: dummyUser1._id,
  788. isEmpty: false,
  789. parent: rootPage._id,
  790. descendantCount: 2,
  791. },
  792. {
  793. _id: pageIdUpd9,
  794. path: '/mup14_top',
  795. grant: Page.GRANT_PUBLIC,
  796. creator: dummyUser1,
  797. lastUpdateUser: dummyUser1._id,
  798. isEmpty: false,
  799. parent: rootPage._id,
  800. descendantCount: 2,
  801. },
  802. {
  803. _id: pageIdUpd10,
  804. path: '/mup15_top',
  805. grant: Page.GRANT_PUBLIC,
  806. creator: dummyUser1,
  807. lastUpdateUser: dummyUser1._id,
  808. isEmpty: false,
  809. parent: rootPage._id,
  810. descendantCount: 1,
  811. },
  812. {
  813. _id: pageIdUpd11,
  814. path: '/mup16_top',
  815. grant: Page.GRANT_PUBLIC,
  816. creator: dummyUser1,
  817. lastUpdateUser: dummyUser1._id,
  818. isEmpty: false,
  819. parent: rootPage._id,
  820. descendantCount: 0,
  821. },
  822. {
  823. _id: pageIdUpd12,
  824. path: '/mup17_top',
  825. grant: Page.GRANT_PUBLIC,
  826. creator: dummyUser1,
  827. lastUpdateUser: dummyUser1._id,
  828. isEmpty: false,
  829. parent: rootPage._id,
  830. descendantCount: 1,
  831. },
  832. {
  833. path: '/mup19',
  834. grant: Page.GRANT_PUBLIC,
  835. creator: dummyUser1,
  836. lastUpdateUser: dummyUser1._id,
  837. isEmpty: false,
  838. parent: rootPage._id,
  839. descendantCount: 0,
  840. },
  841. {
  842. path: '/mup20',
  843. grant: Page.GRANT_USER_GROUP,
  844. grantedGroups: [
  845. { item: userGroupIdPModelA, type: GroupType.userGroup },
  846. {
  847. item: externalUserGroupIdPModelA,
  848. type: GroupType.externalUserGroup,
  849. },
  850. ],
  851. creator: pModelUserId1,
  852. lastUpdateUser: pModelUserId1,
  853. isEmpty: false,
  854. parent: rootPage._id,
  855. descendantCount: 0,
  856. },
  857. {
  858. path: '/mup21',
  859. grant: Page.GRANT_RESTRICTED,
  860. creator: dummyUser1,
  861. lastUpdateUser: dummyUser1._id,
  862. isEmpty: false,
  863. descendantCount: 0,
  864. },
  865. {
  866. _id: pageIdUpd13,
  867. path: '/mup22',
  868. grant: Page.GRANT_PUBLIC,
  869. creator: pModelUser1,
  870. lastUpdateUser: pModelUser1._id,
  871. isEmpty: false,
  872. parent: rootPage._id,
  873. descendantCount: 1,
  874. },
  875. {
  876. path: '/mup22/mup23',
  877. grant: Page.GRANT_USER_GROUP,
  878. grantedGroups: [
  879. { item: userGroupIdPModelA, type: GroupType.userGroup },
  880. {
  881. item: externalUserGroupIdPModelA,
  882. type: GroupType.externalUserGroup,
  883. },
  884. ],
  885. creator: pModelUserId1,
  886. lastUpdateUser: pModelUserId1,
  887. isEmpty: false,
  888. parent: pageIdUpd13,
  889. descendantCount: 0,
  890. },
  891. {
  892. _id: pageIdUpd14,
  893. path: '/mup24_pub',
  894. grant: Page.GRANT_PUBLIC,
  895. creator: pModelUserId1,
  896. lastUpdateUser: pModelUserId1,
  897. isEmpty: false,
  898. parent: rootPage,
  899. descendantCount: 1,
  900. },
  901. {
  902. path: '/mup24_pub/mup25_pub',
  903. grant: Page.GRANT_PUBLIC,
  904. creator: pModelUserId1,
  905. lastUpdateUser: pModelUserId1,
  906. isEmpty: false,
  907. parent: pageIdUpd14,
  908. descendantCount: 0,
  909. },
  910. {
  911. path: '/mup26_awl',
  912. grant: Page.GRANT_RESTRICTED,
  913. creator: pModelUserId1,
  914. lastUpdateUser: pModelUserId1,
  915. isEmpty: false,
  916. descendantCount: 0,
  917. },
  918. {
  919. _id: pageIdUpd15,
  920. path: '/mup27_pub',
  921. grant: Page.GRANT_PUBLIC,
  922. creator: pModelUserId1,
  923. lastUpdateUser: pModelUserId1,
  924. isEmpty: false,
  925. parent: rootPage,
  926. descendantCount: 1,
  927. },
  928. {
  929. path: '/mup27_pub/mup28_owner',
  930. grant: Page.GRANT_OWNER,
  931. creator: pModelUserId1,
  932. lastUpdateUser: pModelUserId1,
  933. isEmpty: false,
  934. parent: pageIdUpd15,
  935. grantedUsers: [pModelUserId1],
  936. descendantCount: 0,
  937. },
  938. {
  939. _id: pageIdUpd16,
  940. path: '/mup29_A',
  941. grant: Page.GRANT_USER_GROUP,
  942. grantedGroups: [
  943. { item: userGroupIdPModelA, type: GroupType.userGroup },
  944. {
  945. item: externalUserGroupIdPModelA,
  946. type: GroupType.externalUserGroup,
  947. },
  948. ],
  949. creator: pModelUserId1,
  950. lastUpdateUser: pModelUserId1,
  951. isEmpty: false,
  952. parent: rootPage,
  953. descendantCount: 1,
  954. },
  955. {
  956. path: '/mup29_A/mup30_owner',
  957. grant: Page.GRANT_OWNER,
  958. grantedUsers: [pModelUserId1],
  959. creator: pModelUserId1,
  960. lastUpdateUser: pModelUserId1,
  961. isEmpty: false,
  962. parent: pageIdUpd16,
  963. descendantCount: 0,
  964. },
  965. {
  966. _id: pageIdUpd17,
  967. path: '/mup31_A',
  968. grant: Page.GRANT_USER_GROUP,
  969. grantedGroups: [
  970. { item: userGroupIdPModelA, type: GroupType.userGroup },
  971. {
  972. item: externalUserGroupIdPModelA,
  973. type: GroupType.externalUserGroup,
  974. },
  975. ],
  976. creator: pModelUserId1,
  977. lastUpdateUser: pModelUserId1,
  978. isEmpty: false,
  979. parent: rootPage,
  980. descendantCount: 1,
  981. },
  982. {
  983. path: '/mup31_A/mup32_owner',
  984. grant: Page.GRANT_OWNER,
  985. grantedUsers: [pModelUserId1],
  986. creator: pModelUserId1,
  987. lastUpdateUser: pModelUserId1,
  988. isEmpty: false,
  989. parent: pageIdUpd17,
  990. descendantCount: 0,
  991. },
  992. {
  993. _id: pageIdUpd18,
  994. path: '/mup33_C',
  995. grant: Page.GRANT_USER_GROUP,
  996. grantedGroups: [
  997. { item: userGroupIdPModelC, type: GroupType.userGroup },
  998. {
  999. item: externalUserGroupIdPModelC,
  1000. type: GroupType.externalUserGroup,
  1001. },
  1002. ],
  1003. creator: pModelUserId3,
  1004. lastUpdateUser: pModelUserId3,
  1005. isEmpty: false,
  1006. parent: rootPage,
  1007. descendantCount: 1,
  1008. },
  1009. {
  1010. path: '/mup33_C/mup34_owner',
  1011. grant: Page.GRANT_OWNER,
  1012. grantedUsers: [pModelUserId3],
  1013. creator: pModelUserId3,
  1014. lastUpdateUser: pModelUserId3,
  1015. isEmpty: false,
  1016. parent: pageIdUpd18,
  1017. descendantCount: 0,
  1018. },
  1019. {
  1020. _id: pageIdUpd19,
  1021. path: '/mup35_owner',
  1022. grant: Page.GRANT_OWNER,
  1023. grantedUsers: [pModelUserId1],
  1024. creator: pModelUserId1,
  1025. lastUpdateUser: pModelUserId1,
  1026. isEmpty: false,
  1027. parent: rootPage,
  1028. descendantCount: 1,
  1029. },
  1030. {
  1031. path: '/mup35_owner/mup36_owner',
  1032. grant: Page.GRANT_OWNER,
  1033. grantedUsers: [pModelUserId1],
  1034. creator: pModelUserId1,
  1035. lastUpdateUser: pModelUserId1,
  1036. isEmpty: false,
  1037. parent: pageIdUpd19,
  1038. descendantCount: 0,
  1039. },
  1040. {
  1041. path: '/mup40', // used this number to resolve conflict
  1042. grant: Page.GRANT_OWNER,
  1043. grantedUsers: [dummyUser1._id],
  1044. creator: dummyUser1,
  1045. lastUpdateUser: dummyUser1._id,
  1046. isEmpty: false,
  1047. parent: rootPage._id,
  1048. descendantCount: 0,
  1049. },
  1050. {
  1051. path: '/with_multiple_individual_granted_groups',
  1052. grant: Page.GRANT_USER_GROUP,
  1053. grantedGroups: [
  1054. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1055. { item: userGroupIdPModelB, type: GroupType.userGroup },
  1056. ],
  1057. creator: pModelUserId1,
  1058. lastUpdateUser: pModelUserId1,
  1059. isEmpty: false,
  1060. parent: rootPage,
  1061. },
  1062. ]);
  1063. await createDocumentsToTestUpdatePageOverwritingDescendants();
  1064. });
  1065. describe('updatePage with overwriteScopesOfDescendants false', () => {
  1066. describe('Changing grant from PUBLIC to RESTRICTED of', () => {
  1067. test('an only-child page will delete its empty parent page', async () => {
  1068. const pathT = '/mup13_top';
  1069. const path1 = '/mup13_top/mup1_emp';
  1070. const path2 = '/mup13_top/mup1_emp/mup2_pub';
  1071. const pageT = await Page.findOne({ path: pathT, descendantCount: 2 });
  1072. const page1 = await Page.findOne({ path: path1, isEmpty: true });
  1073. const page2 = await Page.findOne({
  1074. path: path2,
  1075. grant: Page.GRANT_PUBLIC,
  1076. });
  1077. expect(pageT).toBeTruthy();
  1078. expect(page1).toBeTruthy();
  1079. expect(page2).toBeTruthy();
  1080. const options = {
  1081. grant: Page.GRANT_RESTRICTED,
  1082. userRelatedGrantUserGroupIds: null,
  1083. };
  1084. await updatePage(
  1085. page2,
  1086. 'newRevisionBody',
  1087. 'oldRevisionBody',
  1088. dummyUser1,
  1089. options,
  1090. );
  1091. const _pageT = await Page.findOne({ path: pathT });
  1092. const _page1 = await Page.findOne({ path: path1 });
  1093. const _page2 = await Page.findOne({
  1094. path: path2,
  1095. grant: Page.GRANT_RESTRICTED,
  1096. });
  1097. expect(_pageT).toBeTruthy();
  1098. expect(_page1).toBeNull();
  1099. expect(_page2).toBeTruthy();
  1100. expect(_pageT.descendantCount).toBe(1);
  1101. });
  1102. test('a page that has children will create an empty page with the same path and it becomes a new parent', async () => {
  1103. const pathT = '/mup14_top';
  1104. const path1 = '/mup14_top/mup6_pub';
  1105. const path2 = '/mup14_top/mup6_pub/mup7_pub';
  1106. const top = await Page.findOne({ path: pathT, descendantCount: 2 });
  1107. const page1 = await Page.findOne({
  1108. path: path1,
  1109. grant: Page.GRANT_PUBLIC,
  1110. });
  1111. const page2 = await Page.findOne({
  1112. path: path2,
  1113. grant: Page.GRANT_PUBLIC,
  1114. });
  1115. expect(top).toBeTruthy();
  1116. expect(page1).toBeTruthy();
  1117. expect(page2).toBeTruthy();
  1118. await updatePage(
  1119. page1,
  1120. 'newRevisionBody',
  1121. 'oldRevisionBody',
  1122. dummyUser1,
  1123. { grant: Page.GRANT_RESTRICTED },
  1124. );
  1125. const _top = await Page.findOne({ path: pathT });
  1126. const _page1 = await Page.findOne({
  1127. path: path1,
  1128. grant: Page.GRANT_RESTRICTED,
  1129. });
  1130. const _page2 = await Page.findOne({ path: path2 });
  1131. const _pageN = await Page.findOne({
  1132. path: path1,
  1133. grant: Page.GRANT_PUBLIC,
  1134. });
  1135. expect(_page1).toBeTruthy();
  1136. expect(_page2).toBeTruthy();
  1137. expect(_pageN).toBeTruthy();
  1138. expect(_page1.parent).toBeNull();
  1139. expect(_page2.parent).toStrictEqual(_pageN._id);
  1140. expect(_pageN.parent).toStrictEqual(top._id);
  1141. expect(_pageN.isEmpty).toBe(true);
  1142. expect(_pageN.descendantCount).toBe(1);
  1143. expect(_top.descendantCount).toBe(1);
  1144. });
  1145. test('of a leaf page will NOT have an empty page with the same path', async () => {
  1146. const pathT = '/mup15_top';
  1147. const path1 = '/mup15_top/mup8_pub';
  1148. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  1149. const page1 = await Page.findOne({
  1150. path: path1,
  1151. grant: Page.GRANT_PUBLIC,
  1152. });
  1153. const count = await Page.count({ path: path1 });
  1154. expect(pageT).toBeTruthy();
  1155. expect(page1).toBeTruthy();
  1156. expect(count).toBe(1);
  1157. await updatePage(
  1158. page1,
  1159. 'newRevisionBody',
  1160. 'oldRevisionBody',
  1161. dummyUser1,
  1162. { grant: Page.GRANT_RESTRICTED },
  1163. );
  1164. const _pageT = await Page.findOne({ path: pathT });
  1165. const _page1 = await Page.findOne({
  1166. path: path1,
  1167. grant: Page.GRANT_RESTRICTED,
  1168. });
  1169. const _pageNotExist = await Page.findOne({
  1170. path: path1,
  1171. isEmpty: true,
  1172. });
  1173. expect(_pageT).toBeTruthy();
  1174. expect(_page1).toBeTruthy();
  1175. expect(_pageNotExist).toBeNull();
  1176. expect(_pageT.descendantCount).toBe(0);
  1177. });
  1178. });
  1179. describe('Changing grant to GRANT_RESTRICTED', () => {
  1180. test('successfully change to GRANT_RESTRICTED from GRANT_OWNER', async () => {
  1181. const path = '/mup40';
  1182. const _page = await Page.findOne({
  1183. path,
  1184. grant: Page.GRANT_OWNER,
  1185. grantedUsers: [dummyUser1._id],
  1186. });
  1187. expect(_page).toBeTruthy();
  1188. await updatePage(
  1189. _page,
  1190. 'newRevisionBody',
  1191. 'oldRevisionBody',
  1192. dummyUser1,
  1193. { grant: Page.GRANT_RESTRICTED },
  1194. );
  1195. const page = await Page.findOne({ path });
  1196. expect(page).toBeTruthy();
  1197. expect(page.grant).toBe(Page.GRANT_RESTRICTED);
  1198. expect(page.grantedUsers).toStrictEqual([]);
  1199. });
  1200. });
  1201. describe('Changing grant from RESTRICTED to PUBLIC of', () => {
  1202. test('a page will create ancestors if they do not exist', async () => {
  1203. const pathT = '/mup16_top';
  1204. const path1 = '/mup16_top/mup9_pub';
  1205. const path2 = '/mup16_top/mup9_pub/mup10_pub';
  1206. const path3 = '/mup16_top/mup9_pub/mup10_pub/mup11_awl';
  1207. const top = await Page.findOne({ path: pathT });
  1208. const page1 = await Page.findOne({ path: path1 });
  1209. const page2 = await Page.findOne({ path: path2 });
  1210. const page3 = await Page.findOne({
  1211. path: path3,
  1212. grant: Page.GRANT_RESTRICTED,
  1213. });
  1214. expect(top).toBeTruthy();
  1215. expect(page3).toBeTruthy();
  1216. expect(page1).toBeNull();
  1217. expect(page2).toBeNull();
  1218. await updatePage(
  1219. page3,
  1220. 'newRevisionBody',
  1221. 'oldRevisionBody',
  1222. dummyUser1,
  1223. { grant: Page.GRANT_PUBLIC },
  1224. );
  1225. const _pageT = await Page.findOne({ path: pathT });
  1226. const _page1 = await Page.findOne({ path: path1, isEmpty: true });
  1227. const _page2 = await Page.findOne({ path: path2, isEmpty: true });
  1228. const _page3 = await Page.findOne({
  1229. path: path3,
  1230. grant: Page.GRANT_PUBLIC,
  1231. });
  1232. expect(_page1).toBeTruthy();
  1233. expect(_page2).toBeTruthy();
  1234. expect(_page3).toBeTruthy();
  1235. expect(_page1.parent).toStrictEqual(top._id);
  1236. expect(_page2.parent).toStrictEqual(_page1._id);
  1237. expect(_page3.parent).toStrictEqual(_page2._id);
  1238. expect(_pageT.descendantCount).toBe(1);
  1239. });
  1240. test('a page will replace an empty page with the same path if any', async () => {
  1241. const pathT = '/mup17_top';
  1242. const path1 = '/mup17_top/mup12_emp';
  1243. const path2 = '/mup17_top/mup12_emp/mup18_pub';
  1244. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  1245. const page1 = await Page.findOne({ path: path1, isEmpty: true });
  1246. const page2 = await Page.findOne({
  1247. path: path1,
  1248. grant: Page.GRANT_RESTRICTED,
  1249. isEmpty: false,
  1250. });
  1251. const page3 = await Page.findOne({ path: path2 });
  1252. expect(pageT).toBeTruthy();
  1253. expect(page1).toBeTruthy();
  1254. expect(page2).toBeTruthy();
  1255. expect(page3).toBeTruthy();
  1256. await updatePage(
  1257. page2,
  1258. 'newRevisionBody',
  1259. 'oldRevisionBody',
  1260. dummyUser1,
  1261. { grant: Page.GRANT_PUBLIC },
  1262. );
  1263. const _pageT = await Page.findOne({ path: pathT });
  1264. const _page1 = await Page.findOne({ path: path1, isEmpty: true }); // should be replaced
  1265. const _page2 = await Page.findOne({
  1266. path: path1,
  1267. grant: Page.GRANT_PUBLIC,
  1268. });
  1269. const _page3 = await Page.findOne({ path: path2 });
  1270. expect(_pageT).toBeTruthy();
  1271. expect(_page1).toBeNull();
  1272. expect(_page2).toBeTruthy();
  1273. expect(_page3).toBeTruthy();
  1274. expect(_page2.grant).toBe(Page.GRANT_PUBLIC);
  1275. expect(_page2.parent).toStrictEqual(_pageT._id);
  1276. expect(_page3.parent).toStrictEqual(_page2._id);
  1277. expect(_pageT.descendantCount).toBe(2);
  1278. });
  1279. });
  1280. describe('Changing grant to GRANT_OWNER(onlyme)', () => {
  1281. test('successfully change to GRANT_OWNER from GRANT_PUBLIC', async () => {
  1282. const path = '/mup19';
  1283. const _page = await Page.findOne({ path, grant: Page.GRANT_PUBLIC });
  1284. expect(_page).toBeTruthy();
  1285. await updatePage(
  1286. _page,
  1287. 'newRevisionBody',
  1288. 'oldRevisionBody',
  1289. dummyUser1,
  1290. { grant: Page.GRANT_OWNER },
  1291. );
  1292. const page = await Page.findOne({ path });
  1293. expect(page.grant).toBe(Page.GRANT_OWNER);
  1294. expect(page.grantedUsers).toStrictEqual([dummyUser1._id]);
  1295. });
  1296. test('successfully change to GRANT_OWNER from GRANT_USER_GROUP', async () => {
  1297. const path = '/mup20';
  1298. const _page = await Page.findOne({
  1299. path,
  1300. grant: Page.GRANT_USER_GROUP,
  1301. grantedGroups: { $elemMatch: { item: userGroupIdPModelA } },
  1302. });
  1303. expect(_page).toBeTruthy();
  1304. await updatePage(
  1305. _page,
  1306. 'newRevisionBody',
  1307. 'oldRevisionBody',
  1308. pModelUser1,
  1309. { grant: Page.GRANT_OWNER },
  1310. );
  1311. const page = await Page.findOne({ path });
  1312. expect(page.grant).toBe(Page.GRANT_OWNER);
  1313. expect(page.grantedUsers).toStrictEqual([pModelUser1._id]);
  1314. expect(page.grantedGroups.length).toBe(0);
  1315. });
  1316. test('successfully change to GRANT_OWNER from GRANT_RESTRICTED', async () => {
  1317. const path = '/mup21';
  1318. const _page = await Page.findOne({
  1319. path,
  1320. grant: Page.GRANT_RESTRICTED,
  1321. });
  1322. expect(_page).toBeTruthy();
  1323. await updatePage(
  1324. _page,
  1325. 'newRevisionBody',
  1326. 'oldRevisionBody',
  1327. dummyUser1,
  1328. { grant: Page.GRANT_OWNER },
  1329. );
  1330. const page = await Page.findOne({ path });
  1331. expect(page.grant).toBe(Page.GRANT_OWNER);
  1332. expect(page.grantedUsers).toStrictEqual([dummyUser1._id]);
  1333. });
  1334. test('Failed to change to GRANT_OWNER if one of the ancestors is GRANT_USER_GROUP page', async () => {
  1335. const path1 = '/mup22';
  1336. const path2 = '/mup22/mup23';
  1337. const _page1 = await Page.findOne({
  1338. path: path1,
  1339. grant: Page.GRANT_PUBLIC,
  1340. });
  1341. const _page2 = await Page.findOne({
  1342. path: path2,
  1343. grant: Page.GRANT_USER_GROUP,
  1344. grantedGroups: { $elemMatch: { item: userGroupIdPModelA } },
  1345. });
  1346. expect(_page1).toBeTruthy();
  1347. expect(_page2).toBeTruthy();
  1348. await expect(
  1349. updatePage(_page1, 'newRevisionBody', 'oldRevisionBody', dummyUser1, {
  1350. grant: Page.GRANT_OWNER,
  1351. }),
  1352. ).rejects.toThrow(
  1353. new Error(
  1354. 'The selected grant or grantedGroup is not assignable to this page.',
  1355. ),
  1356. );
  1357. const page1 = await Page.findOne({ path1 });
  1358. expect(page1).toBeTruthy();
  1359. expect(page1.grant).toBe(Page.GRANT_PUBLIC);
  1360. expect(page1.grantedUsers).not.toStrictEqual([dummyUser1._id]);
  1361. });
  1362. });
  1363. describe('Changing grant to GRANT_USER_GROUP', () => {
  1364. describe('update grant of a page under a page with GRANT_PUBLIC', () => {
  1365. test('successfully change to GRANT_USER_GROUP from GRANT_PUBLIC if parent page is GRANT_PUBLIC', async () => {
  1366. // path
  1367. const path1 = '/mup24_pub';
  1368. const path2 = '/mup24_pub/mup25_pub';
  1369. // page
  1370. const _page1 = await Page.findOne({
  1371. path: path1,
  1372. grant: Page.GRANT_PUBLIC,
  1373. }); // out of update scope
  1374. const _page2 = await Page.findOne({
  1375. path: path2,
  1376. grant: Page.GRANT_PUBLIC,
  1377. parent: _page1._id,
  1378. }); // update target
  1379. expect(_page1).toBeTruthy();
  1380. expect(_page2).toBeTruthy();
  1381. const newGrantedGroups = [
  1382. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1383. {
  1384. item: externalUserGroupIdPModelA,
  1385. type: GroupType.externalUserGroup,
  1386. },
  1387. ];
  1388. const options = {
  1389. grant: Page.GRANT_USER_GROUP,
  1390. userRelatedGrantUserGroupIds: newGrantedGroups,
  1391. };
  1392. const updatedPage = await updatePage(
  1393. _page2,
  1394. 'new',
  1395. 'old',
  1396. pModelUser1,
  1397. options,
  1398. ); // from GRANT_PUBLIC to GRANT_USER_GROUP(userGroupIdPModelA)
  1399. const page1 = await Page.findById(_page1._id);
  1400. const page2 = await Page.findById(_page2._id);
  1401. expect(page1).toBeTruthy();
  1402. expect(page2).toBeTruthy();
  1403. expect(updatedPage).toBeTruthy();
  1404. expect(updatedPage._id).toStrictEqual(page2._id);
  1405. // check page2 grant and group
  1406. expect(page2.grant).toBe(Page.GRANT_USER_GROUP);
  1407. expect(normalizeGrantedGroups(page2.grantedGroups)).toStrictEqual(
  1408. newGrantedGroups,
  1409. );
  1410. });
  1411. test('successfully change to GRANT_USER_GROUP from GRANT_RESTRICTED if parent page is GRANT_PUBLIC', async () => {
  1412. // path
  1413. const _path1 = '/mup26_awl';
  1414. // page
  1415. const _page1 = await Page.findOne({
  1416. path: _path1,
  1417. grant: Page.GRANT_RESTRICTED,
  1418. });
  1419. expect(_page1).toBeTruthy();
  1420. const newGrantedGroups = [
  1421. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1422. {
  1423. item: externalUserGroupIdPModelA,
  1424. type: GroupType.externalUserGroup,
  1425. },
  1426. ];
  1427. const options = {
  1428. grant: Page.GRANT_USER_GROUP,
  1429. userRelatedGrantUserGroupIds: newGrantedGroups,
  1430. };
  1431. const updatedPage = await updatePage(
  1432. _page1,
  1433. 'new',
  1434. 'old',
  1435. pModelUser1,
  1436. options,
  1437. ); // from GRANT_RESTRICTED to GRANT_USER_GROUP(userGroupIdPModelA)
  1438. const page1 = await Page.findById(_page1._id);
  1439. expect(page1).toBeTruthy();
  1440. expect(updatedPage).toBeTruthy();
  1441. expect(updatedPage._id).toStrictEqual(page1._id);
  1442. // updated page
  1443. expect(page1.grant).toBe(Page.GRANT_USER_GROUP);
  1444. expect(normalizeGrantedGroups(page1.grantedGroups)).toStrictEqual(
  1445. newGrantedGroups,
  1446. );
  1447. // parent's grant check
  1448. const parent = await Page.findById(page1.parent);
  1449. expect(parent.grant).toBe(Page.GRANT_PUBLIC);
  1450. });
  1451. test('successfully change to GRANT_USER_GROUP from GRANT_OWNER if parent page is GRANT_PUBLIC', async () => {
  1452. // path
  1453. const path1 = '/mup27_pub';
  1454. const path2 = '/mup27_pub/mup28_owner';
  1455. // page
  1456. const _page1 = await Page.findOne({
  1457. path: path1,
  1458. grant: Page.GRANT_PUBLIC,
  1459. }); // out of update scope
  1460. const _page2 = await Page.findOne({
  1461. path: path2,
  1462. grant: Page.GRANT_OWNER,
  1463. grantedUsers: [pModelUser1],
  1464. parent: _page1._id,
  1465. }); // update target
  1466. expect(_page1).toBeTruthy();
  1467. expect(_page2).toBeTruthy();
  1468. const newGrantedGroups = [
  1469. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1470. {
  1471. item: externalUserGroupIdPModelA,
  1472. type: GroupType.externalUserGroup,
  1473. },
  1474. ];
  1475. const options = {
  1476. grant: Page.GRANT_USER_GROUP,
  1477. userRelatedGrantUserGroupIds: newGrantedGroups,
  1478. };
  1479. const updatedPage = await updatePage(
  1480. _page2,
  1481. 'new',
  1482. 'old',
  1483. pModelUser1,
  1484. options,
  1485. ); // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelA)
  1486. const page1 = await Page.findById(_page1._id);
  1487. const page2 = await Page.findById(_page2._id);
  1488. expect(page1).toBeTruthy();
  1489. expect(page2).toBeTruthy();
  1490. expect(updatedPage).toBeTruthy();
  1491. expect(updatedPage._id).toStrictEqual(page2._id);
  1492. // grant check
  1493. expect(page2.grant).toBe(Page.GRANT_USER_GROUP);
  1494. expect(normalizeGrantedGroups(page2.grantedGroups)).toStrictEqual(
  1495. newGrantedGroups,
  1496. );
  1497. expect(page2.grantedUsers.length).toBe(0);
  1498. });
  1499. });
  1500. describe('update grant of a page under a page with GRANT_USER_GROUP', () => {
  1501. test('successfully change to GRANT_USER_GROUP if the group to set is the child or descendant of the parent page group', async () => {
  1502. // path
  1503. const _path1 = '/mup29_A';
  1504. const _path2 = '/mup29_A/mup30_owner';
  1505. // page
  1506. const _page1 = await Page.findOne({
  1507. path: _path1,
  1508. grant: Page.GRANT_USER_GROUP,
  1509. grantedGroups: { $elemMatch: { item: userGroupIdPModelA } },
  1510. }); // out of update scope
  1511. const _page2 = await Page.findOne({
  1512. // update target
  1513. path: _path2,
  1514. grant: Page.GRANT_OWNER,
  1515. grantedUsers: [pModelUser1],
  1516. parent: _page1._id,
  1517. });
  1518. expect(_page1).toBeTruthy();
  1519. expect(_page2).toBeTruthy();
  1520. // First round
  1521. // Group relation(parent -> child): userGroupIdPModelA -> userGroupIdPModelB -> userGroupIdPModelC
  1522. const newGrantedGroups = [
  1523. { item: userGroupIdPModelB, type: GroupType.userGroup },
  1524. {
  1525. item: externalUserGroupIdPModelB,
  1526. type: GroupType.externalUserGroup,
  1527. },
  1528. ];
  1529. const options = {
  1530. grant: Page.GRANT_USER_GROUP,
  1531. userRelatedGrantUserGroupIds: newGrantedGroups,
  1532. };
  1533. const updatedPage = await updatePage(
  1534. _page2,
  1535. 'new',
  1536. 'old',
  1537. pModelUser3,
  1538. options,
  1539. ); // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelB)
  1540. const page1 = await Page.findById(_page1._id);
  1541. const page2 = await Page.findById(_page2._id);
  1542. expect(page1).toBeTruthy();
  1543. expect(page2).toBeTruthy();
  1544. expect(updatedPage).toBeTruthy();
  1545. expect(updatedPage._id).toStrictEqual(page2._id);
  1546. expect(page2.grant).toBe(Page.GRANT_USER_GROUP);
  1547. expect(normalizeGrantedGroups(page2.grantedGroups)).toStrictEqual(
  1548. newGrantedGroups,
  1549. );
  1550. expect(page2.grantedUsers.length).toBe(0);
  1551. // Second round
  1552. // Update group to groupC which is a grandchild from pageA's point of view
  1553. const secondRoundNewGrantedGroups = [
  1554. { item: userGroupIdPModelC, type: GroupType.userGroup },
  1555. {
  1556. item: externalUserGroupIdPModelC,
  1557. type: GroupType.externalUserGroup,
  1558. },
  1559. ];
  1560. const secondRoundOptions = {
  1561. grant: Page.GRANT_USER_GROUP,
  1562. userRelatedGrantUserGroupIds: secondRoundNewGrantedGroups,
  1563. }; // from GRANT_USER_GROUP(userGroupIdPModelB) to GRANT_USER_GROUP(userGroupIdPModelC)
  1564. // undo grantedGroups populate to prevent Page.hydrate error
  1565. _page2.grantedGroups.forEach((group) => {
  1566. group.item = group.item._id;
  1567. });
  1568. const secondRoundUpdatedPage = await updatePage(
  1569. _page2,
  1570. 'new',
  1571. 'new',
  1572. pModelUser3,
  1573. secondRoundOptions,
  1574. );
  1575. expect(secondRoundUpdatedPage).toBeTruthy();
  1576. expect(secondRoundUpdatedPage.grant).toBe(Page.GRANT_USER_GROUP);
  1577. expect(
  1578. normalizeGrantedGroups(secondRoundUpdatedPage.grantedGroups),
  1579. ).toStrictEqual(secondRoundNewGrantedGroups);
  1580. });
  1581. 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 () => {
  1582. // path
  1583. const _path1 = '/mup31_A';
  1584. const _path2 = '/mup31_A/mup32_owner';
  1585. // page
  1586. const _page1 = await Page.findOne({
  1587. path: _path1,
  1588. grant: Page.GRANT_USER_GROUP,
  1589. grantedGroups: { $elemMatch: { item: userGroupIdPModelA } },
  1590. });
  1591. const _page2 = await Page.findOne({
  1592. // update target
  1593. path: _path2,
  1594. grant: Page.GRANT_OWNER,
  1595. grantedUsers: [pModelUser1._id],
  1596. parent: _page1._id,
  1597. });
  1598. expect(_page1).toBeTruthy();
  1599. expect(_page2).toBeTruthy();
  1600. // group
  1601. const _groupIsolated = await UserGroup.findById(
  1602. userGroupIdPModelIsolate,
  1603. );
  1604. expect(_groupIsolated).toBeTruthy();
  1605. // group parent check
  1606. expect(_groupIsolated.parent).toBeUndefined(); // should have no parent
  1607. const options = {
  1608. grant: Page.GRANT_USER_GROUP,
  1609. userRelatedGrantUserGroupIds: [
  1610. { item: userGroupIdPModelIsolate, type: GroupType.userGroup },
  1611. {
  1612. item: externalUserGroupIdPModelIsolate,
  1613. type: GroupType.externalUserGroup,
  1614. },
  1615. ],
  1616. };
  1617. await expect(updatePage(_page2, 'new', 'old', pModelUser1, options)) // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelIsolate)
  1618. .rejects.toThrow(
  1619. new Error(
  1620. 'The selected grant or grantedGroup is not assignable to this page.',
  1621. ),
  1622. );
  1623. const page1 = await Page.findById(_page1._id);
  1624. const page2 = await Page.findById(_page2._id);
  1625. expect(page1).toBeTruthy();
  1626. expect(page1).toBeTruthy();
  1627. expect(page2.grant).toBe(Page.GRANT_OWNER); // should be the same before the update
  1628. expect(page2.grantedUsers).toStrictEqual([pModelUser1._id]); // should be the same before the update
  1629. expect(page2.grantedGroups.length).toBe(0); // no group should be set
  1630. });
  1631. test('Fail to change to GRANT_USER_GROUP if the group to set is an ancestor of the parent page group', async () => {
  1632. // path
  1633. const _path1 = '/mup33_C';
  1634. const _path2 = '/mup33_C/mup34_owner';
  1635. // page
  1636. const _page1 = await Page.findOne({
  1637. path: _path1,
  1638. grant: Page.GRANT_USER_GROUP,
  1639. grantedGroups: { $elemMatch: { item: userGroupIdPModelC } },
  1640. }); // groupC
  1641. const _page2 = await Page.findOne({
  1642. // update target
  1643. path: _path2,
  1644. grant: Page.GRANT_OWNER,
  1645. grantedUsers: [pModelUser3],
  1646. parent: _page1._id,
  1647. });
  1648. expect(_page1).toBeTruthy();
  1649. expect(_page2).toBeTruthy();
  1650. const options = {
  1651. grant: Page.GRANT_USER_GROUP,
  1652. userRelatedGrantUserGroupIds: [
  1653. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1654. {
  1655. item: externalUserGroupIdPModelA,
  1656. type: GroupType.externalUserGroup,
  1657. },
  1658. ],
  1659. };
  1660. // Group relation(parent -> child): userGroupIdPModelA -> userGroupIdPModelB -> userGroupIdPModelC
  1661. // this should fail because the groupC is a descendant of groupA
  1662. await expect(updatePage(_page2, 'new', 'old', pModelUser3, options)) // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelA)
  1663. .rejects.toThrow(
  1664. new Error(
  1665. 'The selected grant or grantedGroup is not assignable to this page.',
  1666. ),
  1667. );
  1668. const page1 = await Page.findById(_page1._id);
  1669. const page2 = await Page.findById(_page2._id);
  1670. expect(page1).toBeTruthy();
  1671. expect(page2).toBeTruthy();
  1672. expect(page2.grant).toBe(Page.GRANT_OWNER); // should be the same before the update
  1673. expect(page2.grantedUsers).toStrictEqual([pModelUser3._id]); // should be the same before the update
  1674. expect(page2.grantedGroups.length).toBe(0); // no group should be set
  1675. });
  1676. });
  1677. describe('update grant of a page under a page with GRANT_OWNER', () => {
  1678. test('Fail to change from GRNAT_OWNER', async () => {
  1679. // path
  1680. const path1 = '/mup35_owner';
  1681. const path2 = '/mup35_owner/mup36_owner';
  1682. // page
  1683. const _page1 = await Page.findOne({
  1684. path: path1,
  1685. grant: Page.GRANT_OWNER,
  1686. grantedUsers: [pModelUser1],
  1687. });
  1688. const _page2 = await Page.findOne({
  1689. // update target
  1690. path: path2,
  1691. grant: Page.GRANT_OWNER,
  1692. grantedUsers: [pModelUser1],
  1693. parent: _page1._id,
  1694. });
  1695. expect(_page1).toBeTruthy();
  1696. expect(_page2).toBeTruthy();
  1697. const options = {
  1698. grant: Page.GRANT_USER_GROUP,
  1699. userRelatedGrantUserGroupIds: [
  1700. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1701. ],
  1702. };
  1703. await expect(updatePage(_page2, 'new', 'old', pModelUser1, options)) // from GRANT_OWNER to GRANT_USER_GROUP(userGroupIdPModelA)
  1704. .rejects.toThrow(
  1705. new Error(
  1706. 'The selected grant or grantedGroup is not assignable to this page.',
  1707. ),
  1708. );
  1709. const page1 = await Page.findById(_page1.id);
  1710. const page2 = await Page.findById(_page2.id);
  1711. expect(page1).toBeTruthy();
  1712. expect(page2).toBeTruthy();
  1713. expect(page2.grant).toBe(Page.GRANT_OWNER); // should be the same before the update
  1714. expect(page2.grantedUsers).toStrictEqual([pModelUser1._id]); // should be the same before the update
  1715. expect(page2.grantedGroups.length).toBe(0); // no group should be set
  1716. });
  1717. });
  1718. describe('update grant of a page from GRANT_USER_GROUP to GRANT_USER_GROUP', () => {
  1719. test('successfully change the granted groups, with the previous groups wich user is not related to remaining', async () => {
  1720. // path
  1721. const path = '/with_multiple_individual_granted_groups';
  1722. // page
  1723. const _page = await Page.findOne({
  1724. path,
  1725. grant: Page.GRANT_USER_GROUP,
  1726. });
  1727. expect(_page).toBeTruthy();
  1728. const newUserRelatedGrantedGroups = [
  1729. { item: userGroupIdPModelA, type: GroupType.userGroup },
  1730. {
  1731. item: externalUserGroupIdPModelA,
  1732. type: GroupType.externalUserGroup,
  1733. },
  1734. ];
  1735. const options = {
  1736. grant: Page.GRANT_USER_GROUP,
  1737. userRelatedGrantUserGroupIds: newUserRelatedGrantedGroups,
  1738. };
  1739. const updatedPage = await updatePage(
  1740. _page,
  1741. 'new',
  1742. 'old',
  1743. pModelUser1,
  1744. options,
  1745. ); // from GRANT_PUBLIC to GRANT_USER_GROUP(userGroupIdPModelA)
  1746. const page = await Page.findById(_page._id);
  1747. expect(page).toBeTruthy();
  1748. expect(updatedPage).toBeTruthy();
  1749. expect(updatedPage._id).toStrictEqual(page._id);
  1750. // check page grant and group
  1751. expect(page.grant).toBe(Page.GRANT_USER_GROUP);
  1752. expect(normalizeGrantedGroups(page.grantedGroups)).toEqual(
  1753. expect.arrayContaining([
  1754. ...newUserRelatedGrantedGroups,
  1755. // userB group remains, although options does not include it
  1756. { item: userGroupIdPModelB, type: GroupType.userGroup },
  1757. ]),
  1758. );
  1759. expect(normalizeGrantedGroups(page.grantedGroups).length).toBe(3);
  1760. });
  1761. });
  1762. });
  1763. });
  1764. // see: https://dev.growi.org/635a314eac6bcd85cbf359fc about the specification
  1765. describe('updatePage with overwriteScopesOfDescendants true', () => {
  1766. test('(case 1) it should update all granted descendant pages when update grant is GRANT_PUBLIC', async () => {
  1767. const upodPagegAB = await Page.findOne({ path: '/gAB_upod_1' });
  1768. const upodPagegB = await Page.findOne({ path: '/gAB_upod_1/gB_upod_1' });
  1769. const upodPageonlyB = await Page.findOne({
  1770. path: '/gAB_upod_1/onlyB_upod_1',
  1771. });
  1772. const upodPagegAgB = await Page.findOne({
  1773. path: '/gAB_upod_1/gA_gB_upod_1',
  1774. });
  1775. expect(upodPagegAB).not.toBeNull();
  1776. expect(upodPagegB).not.toBeNull();
  1777. expect(upodPageonlyB).not.toBeNull();
  1778. expect(upodPagegAgB).not.toBeNull();
  1779. expect(upodPagegAB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1780. expect(upodPagegB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1781. expect(upodPageonlyB.grant).toBe(PageGrant.GRANT_OWNER);
  1782. expect(upodPagegAgB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1783. // Update
  1784. const options = {
  1785. grant: PageGrant.GRANT_PUBLIC,
  1786. overwriteScopesOfDescendants: true,
  1787. };
  1788. const updatedPage = await updatePage(
  1789. upodPagegAB,
  1790. 'newRevisionBody',
  1791. 'oldRevisionBody',
  1792. upodUserA,
  1793. options,
  1794. );
  1795. const upodPagegBUpdated = await Page.findOne({
  1796. path: '/gAB_upod_1/gB_upod_1',
  1797. });
  1798. const upodPageonlyBUpdated = await Page.findOne({
  1799. path: '/gAB_upod_1/onlyB_upod_1',
  1800. });
  1801. const upodPagegAgBUpdated = await Page.findOne({
  1802. path: '/gAB_upod_1/gA_gB_upod_1',
  1803. });
  1804. // Changed
  1805. const newGrant = PageGrant.GRANT_PUBLIC;
  1806. expect(updatedPage.grant).toBe(newGrant);
  1807. // Not changed
  1808. expect(upodPagegBUpdated.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1809. expect(upodPagegBUpdated.grantedGroups).toStrictEqual(
  1810. upodPagegB.grantedGroups,
  1811. );
  1812. expect(upodPageonlyBUpdated.grant).toBe(PageGrant.GRANT_OWNER);
  1813. expect(upodPageonlyBUpdated.grantedUsers).toStrictEqual(
  1814. upodPageonlyB.grantedUsers,
  1815. );
  1816. expect(upodPagegAgBUpdated.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1817. expect(upodPagegAgBUpdated.grantedGroups).toStrictEqual(
  1818. upodPagegAgB.grantedGroups,
  1819. );
  1820. });
  1821. test('(case 2) it should update all granted descendant pages when all descendant pages are granted to the operator', async () => {
  1822. const upodPagePublic = await Page.findOne({ path: '/public_upod_2' });
  1823. const upodPagegA = await Page.findOne({
  1824. path: '/public_upod_2/gA_upod_2',
  1825. });
  1826. const upodPagegAIsolated = await Page.findOne({
  1827. path: '/public_upod_2/gAIsolated_upod_2',
  1828. });
  1829. const upodPageonlyA = await Page.findOne({
  1830. path: '/public_upod_2/onlyA_upod_2',
  1831. });
  1832. expect(upodPagePublic).not.toBeNull();
  1833. expect(upodPagegA).not.toBeNull();
  1834. expect(upodPagegAIsolated).not.toBeNull();
  1835. expect(upodPageonlyA).not.toBeNull();
  1836. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1837. expect(upodPagegA.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1838. expect(upodPagegAIsolated.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1839. expect(upodPageonlyA.grant).toBe(PageGrant.GRANT_OWNER);
  1840. // Update
  1841. const options = {
  1842. grant: PageGrant.GRANT_OWNER,
  1843. overwriteScopesOfDescendants: true,
  1844. };
  1845. const updatedPage = await updatePage(
  1846. upodPagePublic,
  1847. 'newRevisionBody',
  1848. 'oldRevisionBody',
  1849. upodUserA,
  1850. options,
  1851. );
  1852. const upodPagegAUpdated = await Page.findOne({
  1853. path: '/public_upod_2/gA_upod_2',
  1854. });
  1855. const upodPagegAIsolatedUpdated = await Page.findOne({
  1856. path: '/public_upod_2/gAIsolated_upod_2',
  1857. });
  1858. const upodPageonlyAUpdated = await Page.findOne({
  1859. path: '/public_upod_2/onlyA_upod_2',
  1860. });
  1861. // Changed
  1862. const newGrant = PageGrant.GRANT_OWNER;
  1863. const newGrantedUsers = [upodUserA._id];
  1864. expect(updatedPage.grant).toBe(newGrant);
  1865. expect(updatedPage.grantedUsers).toStrictEqual(newGrantedUsers);
  1866. expect(upodPagegAUpdated.grant).toBe(newGrant);
  1867. expect(upodPagegAUpdated.grantedUsers).toStrictEqual(newGrantedUsers);
  1868. expect(upodPagegAIsolatedUpdated.grant).toBe(newGrant);
  1869. expect(upodPagegAIsolatedUpdated.grantedUsers).toStrictEqual(
  1870. newGrantedUsers,
  1871. );
  1872. expect(upodPageonlyAUpdated.grant).toBe(newGrant);
  1873. expect(upodPageonlyAUpdated.grantedUsers).toStrictEqual(newGrantedUsers);
  1874. });
  1875. test(`(case 3) it should update all granted descendant pages when update grant is GRANT_USER_GROUP
  1876. , all user groups of descendants are the children or itself of the update user group
  1877. , and all users of descendants belong to the update user group`, async () => {
  1878. const upodPagePublic = await Page.findOne({ path: '/public_upod_3' });
  1879. const upodPagegAB = await Page.findOne({
  1880. path: '/public_upod_3/gAB_upod_3',
  1881. });
  1882. const upodPagegAgB = await Page.findOne({
  1883. path: '/public_upod_3/gA_gB_upod_3',
  1884. });
  1885. const upodPagegB = await Page.findOne({
  1886. path: '/public_upod_3/gB_upod_3',
  1887. });
  1888. const upodPageonlyB = await Page.findOne({
  1889. path: '/public_upod_3/onlyB_upod_3',
  1890. });
  1891. expect(upodPagePublic).not.toBeNull();
  1892. expect(upodPagegAB).not.toBeNull();
  1893. expect(upodPagegAgB).not.toBeNull();
  1894. expect(upodPagegB).not.toBeNull();
  1895. expect(upodPageonlyB).not.toBeNull();
  1896. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1897. expect(upodPagegAB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1898. expect(upodPagegAgB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1899. expect(upodPagegB.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1900. expect(upodPageonlyB.grant).toBe(PageGrant.GRANT_OWNER);
  1901. // Update
  1902. const options = {
  1903. grant: PageGrant.GRANT_USER_GROUP,
  1904. userRelatedGrantUserGroupIds: [
  1905. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1906. {
  1907. item: upodExternalUserGroupIdAB,
  1908. type: GroupType.externalUserGroup,
  1909. },
  1910. ],
  1911. overwriteScopesOfDescendants: true,
  1912. };
  1913. const updatedPage = await updatePage(
  1914. upodPagePublic,
  1915. 'newRevisionBody',
  1916. 'oldRevisionBody',
  1917. upodUserA,
  1918. options,
  1919. );
  1920. const upodPagegABUpdated = await Page.findOne({
  1921. path: '/public_upod_3/gAB_upod_3',
  1922. });
  1923. const upodPagegAgBUpdated = await Page.findOne({
  1924. path: '/public_upod_3/gA_gB_upod_3',
  1925. });
  1926. const upodPagegBUpdated = await Page.findOne({
  1927. path: '/public_upod_3/gB_upod_3',
  1928. });
  1929. const upodPageonlyBUpdated = await Page.findOne({
  1930. path: '/public_upod_3/onlyB_upod_3',
  1931. });
  1932. // Changed
  1933. const newGrant = PageGrant.GRANT_USER_GROUP;
  1934. const newGrantedGroups = [
  1935. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1936. { item: upodExternalUserGroupIdAB, type: GroupType.externalUserGroup },
  1937. ];
  1938. expect(updatedPage.grant).toBe(newGrant);
  1939. expect(normalizeGrantedGroups(updatedPage.grantedGroups)).toStrictEqual(
  1940. newGrantedGroups,
  1941. );
  1942. expect(upodPagegABUpdated.grant).toBe(newGrant);
  1943. expect(
  1944. normalizeGrantedGroups(upodPagegABUpdated.grantedGroups),
  1945. ).toStrictEqual(newGrantedGroups);
  1946. expect(upodPagegAgBUpdated.grant).toBe(newGrant);
  1947. // For multi group granted pages, the grant update will only add/remove groups that the user belongs to,
  1948. // and groups that the user doesn't belong to will stay as it was before the update.
  1949. expect(normalizeGrantedGroups(upodPagegAgBUpdated.grantedGroups)).toEqual(
  1950. expect.arrayContaining([
  1951. ...newGrantedGroups,
  1952. { item: upodUserGroupIdB, type: GroupType.userGroup },
  1953. { item: upodExternalUserGroupIdB, type: GroupType.externalUserGroup },
  1954. ]),
  1955. );
  1956. expect(
  1957. normalizeGrantedGroups(upodPagegAgBUpdated.grantedGroups).length,
  1958. ).toBe(4);
  1959. // Not changed
  1960. expect(upodPagegBUpdated.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1961. expect(upodPagegBUpdated.grantedGroups).toStrictEqual(
  1962. upodPagegB.grantedGroups,
  1963. );
  1964. expect(upodPageonlyBUpdated.grant).toBe(PageGrant.GRANT_OWNER);
  1965. expect(upodPageonlyBUpdated.grantedUsers).toStrictEqual(
  1966. upodPageonlyB.grantedUsers,
  1967. );
  1968. });
  1969. test(`(case 4) it should throw when some of descendants is not granted
  1970. , update grant is GRANT_USER_GROUP
  1971. , and some of user groups of descendants are not children or itself of the update user group`, async () => {
  1972. const upodPagePublic = await Page.findOne({ path: '/public_upod_4' });
  1973. const upodPagegA = await Page.findOne({
  1974. path: '/public_upod_4/gA_upod_4',
  1975. });
  1976. const upodPagegC = await Page.findOne({
  1977. path: '/public_upod_4/gC_upod_4',
  1978. });
  1979. expect(upodPagePublic).not.toBeNull();
  1980. expect(upodPagegA).not.toBeNull();
  1981. expect(upodPagegC).not.toBeNull();
  1982. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  1983. expect(upodPagegA.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1984. expect(upodPagegC.grant).toBe(PageGrant.GRANT_USER_GROUP);
  1985. // Update
  1986. const options = {
  1987. grant: PageGrant.GRANT_USER_GROUP,
  1988. userRelatedGrantUserGroupIds: [
  1989. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  1990. {
  1991. item: upodExternalUserGroupIdAB,
  1992. type: GroupType.externalUserGroup,
  1993. },
  1994. ],
  1995. overwriteScopesOfDescendants: true,
  1996. };
  1997. const updatedPagePromise = updatePage(
  1998. upodPagePublic,
  1999. 'newRevisionBody',
  2000. 'oldRevisionBody',
  2001. upodUserA,
  2002. options,
  2003. );
  2004. await expect(updatedPagePromise).rejects.toThrowError();
  2005. });
  2006. test(`(case 5) it should throw when some of descendants is not granted
  2007. , update grant is GRANT_USER_GROUP
  2008. , and some of users of descendants does NOT belong to the update user group`, async () => {
  2009. const upodPagePublic = await Page.findOne({ path: '/public_upod_5' });
  2010. const upodPagegA = await Page.findOne({
  2011. path: '/public_upod_5/gA_upod_5',
  2012. });
  2013. const upodPageonlyC = await Page.findOne({
  2014. path: '/public_upod_5/onlyC_upod_5',
  2015. });
  2016. expect(upodPagePublic).not.toBeNull();
  2017. expect(upodPagegA).not.toBeNull();
  2018. expect(upodPageonlyC).not.toBeNull();
  2019. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  2020. expect(upodPagegA.grant).toBe(PageGrant.GRANT_USER_GROUP);
  2021. expect(upodPageonlyC.grant).toBe(PageGrant.GRANT_OWNER);
  2022. // Update
  2023. const options = {
  2024. grant: PageGrant.GRANT_USER_GROUP,
  2025. userRelatedGrantUserGroupIds: [
  2026. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  2027. {
  2028. item: upodExternalUserGroupIdAB,
  2029. type: GroupType.externalUserGroup,
  2030. },
  2031. ],
  2032. overwriteScopesOfDescendants: true,
  2033. };
  2034. const updatedPagePromise = updatePage(
  2035. upodPagePublic,
  2036. 'newRevisionBody',
  2037. 'oldRevisionBody',
  2038. upodUserA,
  2039. options,
  2040. );
  2041. await expect(updatedPagePromise).rejects.toThrowError();
  2042. });
  2043. test('(case 6) it should throw when some of descendants is not granted and update grant is GRANT_OWNER', async () => {
  2044. const upodPagePublic = await Page.findOne({ path: '/public_upod_6' });
  2045. const upodPageonlyC = await Page.findOne({
  2046. path: '/public_upod_6/onlyC_upod_6',
  2047. });
  2048. expect(upodPagePublic).not.toBeNull();
  2049. expect(upodPageonlyC).not.toBeNull();
  2050. expect(upodPagePublic.grant).toBe(PageGrant.GRANT_PUBLIC);
  2051. expect(upodPageonlyC.grant).toBe(PageGrant.GRANT_OWNER);
  2052. // Update
  2053. const options = {
  2054. grant: PageGrant.GRANT_USER_GROUP,
  2055. userRelatedGrantUserGroupIds: [
  2056. { item: upodUserGroupIdAB, type: GroupType.userGroup },
  2057. {
  2058. item: upodExternalUserGroupIdAB,
  2059. type: GroupType.externalUserGroup,
  2060. },
  2061. ],
  2062. overwriteScopesOfDescendants: true,
  2063. };
  2064. const updatedPagePromise = updatePage(
  2065. upodPagePublic,
  2066. 'newRevisionBody',
  2067. 'oldRevisionBody',
  2068. upodUserA,
  2069. options,
  2070. );
  2071. await expect(updatedPagePromise).rejects.toThrowError();
  2072. });
  2073. });
  2074. });