v5.migration.test.js 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668
  1. const mongoose = require('mongoose');
  2. const { getInstance } = require('../setup-crowi');
  3. describe('V5 page migration', () => {
  4. let crowi;
  5. let Page;
  6. let User;
  7. let UserGroup;
  8. let UserGroupRelation;
  9. let testUser1;
  10. let rootUser;
  11. let rootPage;
  12. const rootUserGroupId = new mongoose.Types.ObjectId();
  13. const testUser1GroupId = new mongoose.Types.ObjectId();
  14. const groupIdIsolate = new mongoose.Types.ObjectId();
  15. const groupIdA = new mongoose.Types.ObjectId();
  16. const groupIdB = new mongoose.Types.ObjectId();
  17. const groupIdC = new mongoose.Types.ObjectId();
  18. const pageId1 = new mongoose.Types.ObjectId();
  19. const pageId2 = new mongoose.Types.ObjectId();
  20. const pageId3 = new mongoose.Types.ObjectId();
  21. const pageId4 = new mongoose.Types.ObjectId();
  22. const pageId5 = new mongoose.Types.ObjectId();
  23. const pageId6 = new mongoose.Types.ObjectId();
  24. const pageId7 = new mongoose.Types.ObjectId();
  25. const pageId8 = new mongoose.Types.ObjectId();
  26. const pageId9 = new mongoose.Types.ObjectId();
  27. const pageId10 = new mongoose.Types.ObjectId();
  28. const pageId11 = new mongoose.Types.ObjectId();
  29. const onlyPublic = (filter) => ({ grant: Page.GRANT_PUBLIC, ...filter });
  30. const ownedByTestUser1 = (filter) => ({
  31. grant: Page.GRANT_OWNER,
  32. grantedUsers: [testUser1._id],
  33. ...filter,
  34. });
  35. const root = (filter) => ({ grantedUsers: [rootUser._id], ...filter });
  36. const rootUserGroup = (filter) => ({
  37. grantedGroups: {
  38. $elemMatch: {
  39. item: rootUserGroupId,
  40. },
  41. },
  42. ...filter,
  43. });
  44. const testUser1Group = (filter) => ({
  45. grantedGroups: {
  46. $elemMatch: {
  47. item: testUser1GroupId,
  48. },
  49. },
  50. ...filter,
  51. });
  52. const normalized = { parent: { $ne: null } };
  53. const notNormalized = { parent: null };
  54. const empty = { isEmpty: true };
  55. beforeAll(async () => {
  56. jest.restoreAllMocks();
  57. crowi = await getInstance();
  58. Page = mongoose.model('Page');
  59. User = mongoose.model('User');
  60. UserGroup = mongoose.model('UserGroup');
  61. UserGroupRelation = mongoose.model('UserGroupRelation');
  62. await crowi.configManager.updateConfig('app:isV5Compatible', true);
  63. await User.insertMany([
  64. { name: 'rootUser', username: 'rootUser', email: 'rootUser@example.com' },
  65. {
  66. name: 'testUser1',
  67. username: 'testUser1',
  68. email: 'testUser1@example.com',
  69. },
  70. ]);
  71. rootUser = await User.findOne({ username: 'rootUser' });
  72. testUser1 = await User.findOne({ username: 'testUser1' });
  73. rootPage = await Page.findOne({ path: '/' });
  74. await UserGroup.insertMany([
  75. {
  76. _id: rootUserGroupId,
  77. name: 'rootUserGroup',
  78. },
  79. {
  80. _id: testUser1GroupId,
  81. name: 'testUser1Group',
  82. },
  83. {
  84. _id: groupIdIsolate,
  85. name: 'groupIsolate',
  86. },
  87. {
  88. _id: groupIdA,
  89. name: 'groupA',
  90. },
  91. {
  92. _id: groupIdB,
  93. name: 'groupB',
  94. parent: groupIdA,
  95. },
  96. {
  97. _id: groupIdC,
  98. name: 'groupC',
  99. parent: groupIdB,
  100. },
  101. ]);
  102. await UserGroupRelation.insertMany([
  103. {
  104. relatedGroup: rootUserGroupId,
  105. relatedUser: rootUser._id,
  106. },
  107. {
  108. relatedGroup: testUser1GroupId,
  109. relatedUser: testUser1._id,
  110. },
  111. {
  112. relatedGroup: groupIdIsolate,
  113. relatedUser: testUser1._id,
  114. },
  115. {
  116. relatedGroup: groupIdA,
  117. relatedUser: testUser1._id,
  118. },
  119. {
  120. relatedGroup: groupIdB,
  121. relatedUser: testUser1._id,
  122. },
  123. {
  124. relatedGroup: groupIdC,
  125. relatedUser: testUser1._id,
  126. },
  127. ]);
  128. await Page.insertMany([
  129. {
  130. path: '/private1',
  131. grant: Page.GRANT_OWNER,
  132. creator: testUser1,
  133. lastUpdateUser: testUser1,
  134. grantedUsers: [testUser1._id],
  135. },
  136. {
  137. path: '/dummyParent/private1',
  138. grant: Page.GRANT_OWNER,
  139. creator: testUser1,
  140. lastUpdateUser: testUser1,
  141. grantedUsers: [testUser1._id],
  142. },
  143. {
  144. path: '/dummyParent/private1/private2',
  145. grant: Page.GRANT_OWNER,
  146. creator: testUser1,
  147. lastUpdateUser: testUser1,
  148. grantedUsers: [testUser1._id],
  149. },
  150. {
  151. path: '/dummyParent/private1/private3',
  152. grant: Page.GRANT_OWNER,
  153. creator: testUser1,
  154. lastUpdateUser: testUser1,
  155. grantedUsers: [testUser1._id],
  156. },
  157. {
  158. _id: pageId1,
  159. path: '/normalize_1',
  160. parent: rootPage._id,
  161. grant: Page.GRANT_PUBLIC,
  162. isEmpty: true,
  163. },
  164. {
  165. _id: pageId2,
  166. path: '/normalize_1/normalize_2',
  167. parent: pageId1,
  168. grant: Page.GRANT_USER_GROUP,
  169. grantedGroups: [{ item: groupIdB, type: 'UserGroup' }],
  170. grantedUsers: [testUser1._id],
  171. },
  172. {
  173. _id: pageId3,
  174. path: '/normalize_1',
  175. grant: Page.GRANT_USER_GROUP,
  176. grantedGroups: [{ item: groupIdA, type: 'UserGroup' }],
  177. grantedUsers: [testUser1._id],
  178. },
  179. {
  180. _id: pageId4,
  181. path: '/normalize_4',
  182. parent: rootPage._id,
  183. grant: Page.GRANT_PUBLIC,
  184. isEmpty: true,
  185. },
  186. {
  187. _id: pageId5,
  188. path: '/normalize_4/normalize_5',
  189. parent: pageId4,
  190. grant: Page.GRANT_USER_GROUP,
  191. grantedGroups: [{ item: groupIdA, type: 'UserGroup' }],
  192. grantedUsers: [testUser1._id],
  193. },
  194. {
  195. _id: pageId6,
  196. path: '/normalize_4',
  197. grant: Page.GRANT_USER_GROUP,
  198. grantedGroups: [{ item: groupIdIsolate, type: 'UserGroup' }],
  199. grantedUsers: [testUser1._id],
  200. },
  201. {
  202. path: '/normalize_7/normalize_8_gA',
  203. grant: Page.GRANT_USER_GROUP,
  204. creator: testUser1,
  205. grantedGroups: [{ item: groupIdA, type: 'UserGroup' }],
  206. grantedUsers: [testUser1._id],
  207. },
  208. {
  209. path: '/normalize_7/normalize_8_gA/normalize_9_gB',
  210. grant: Page.GRANT_USER_GROUP,
  211. creator: testUser1,
  212. grantedGroups: [{ item: groupIdB, type: 'UserGroup' }],
  213. grantedUsers: [testUser1._id],
  214. },
  215. {
  216. path: '/normalize_7/normalize_8_gC',
  217. grant: Page.GRANT_USER_GROUP,
  218. grantedGroups: [{ item: groupIdC, type: 'UserGroup' }],
  219. grantedUsers: [testUser1._id],
  220. },
  221. {
  222. _id: pageId7,
  223. path: '/normalize_10',
  224. grant: Page.GRANT_PUBLIC,
  225. isEmpty: true,
  226. parent: rootPage._id,
  227. descendantCount: 3,
  228. },
  229. {
  230. _id: pageId8,
  231. path: '/normalize_10/normalize_11_gA',
  232. isEmpty: true,
  233. parent: pageId7,
  234. descendantCount: 1,
  235. },
  236. {
  237. _id: pageId9, // not v5
  238. path: '/normalize_10/normalize_11_gA',
  239. grant: Page.GRANT_USER_GROUP,
  240. grantedGroups: [{ item: groupIdA, type: 'UserGroup' }],
  241. },
  242. {
  243. _id: pageId10,
  244. path: '/normalize_10/normalize_11_gA/normalize_11_gB',
  245. grant: Page.GRANT_USER_GROUP,
  246. grantedGroups: [{ item: groupIdB, type: 'UserGroup' }],
  247. parent: pageId8,
  248. descendantCount: 0,
  249. },
  250. {
  251. _id: pageId11,
  252. path: '/normalize_10/normalize_12_gC',
  253. grant: Page.GRANT_USER_GROUP,
  254. grantedGroups: [{ item: groupIdC, type: 'UserGroup' }],
  255. grantedUsers: [testUser1._id],
  256. parent: pageId7,
  257. descendantCount: 0,
  258. },
  259. ]);
  260. });
  261. const normalizeParentRecursivelyByPages = async (pages, user) => {
  262. return crowi.pageService.normalizeParentRecursivelyByPages(pages, user);
  263. };
  264. const normalizeParentByPage = async (page, user) => {
  265. return crowi.pageService.normalizeParentByPage(page, user);
  266. };
  267. describe('normalizeParentRecursivelyByPages()', () => {
  268. test('should migrate all pages specified by pageIds', async () => {
  269. jest.restoreAllMocks();
  270. const pagesToRun = await Page.find({
  271. path: { $in: ['/private1', '/dummyParent/private1'] },
  272. });
  273. // migrate
  274. await normalizeParentRecursivelyByPages(pagesToRun, testUser1);
  275. const migratedPages = await Page.find({
  276. path: {
  277. $in: [
  278. '/private1',
  279. '/dummyParent',
  280. '/dummyParent/private1',
  281. '/dummyParent/private1/private2',
  282. '/dummyParent/private1/private3',
  283. ],
  284. },
  285. });
  286. const migratedPagePaths = migratedPages
  287. .filter((doc) => doc.parent != null)
  288. .map((doc) => doc.path);
  289. const expected = [
  290. '/private1',
  291. '/dummyParent',
  292. '/dummyParent/private1',
  293. '/dummyParent/private1/private2',
  294. '/dummyParent/private1/private3',
  295. ];
  296. expect(migratedPagePaths.sort()).toStrictEqual(expected.sort());
  297. });
  298. test('should change all v4 pages with usergroup to v5 compatible and create new parent page', async () => {
  299. const page8 = await Page.findOne({ path: '/normalize_7/normalize_8_gA' });
  300. const page9 = await Page.findOne({
  301. path: '/normalize_7/normalize_8_gA/normalize_9_gB',
  302. });
  303. const page10 = await Page.findOne({
  304. path: '/normalize_7/normalize_8_gC',
  305. });
  306. const page11 = await Page.findOne({ path: '/normalize_7' });
  307. expect(page8).toBeTruthy();
  308. expect(page9).toBeTruthy();
  309. expect(page10).toBeTruthy();
  310. expect(page11).toBeNull();
  311. await normalizeParentRecursivelyByPages(
  312. [page8, page9, page10],
  313. testUser1,
  314. );
  315. // AM => After Migration
  316. const page7 = await Page.findOne({ path: '/normalize_7' });
  317. const page8AM = await Page.findOne({
  318. path: '/normalize_7/normalize_8_gA',
  319. });
  320. const page9AM = await Page.findOne({
  321. path: '/normalize_7/normalize_8_gA/normalize_9_gB',
  322. });
  323. const page10AM = await Page.findOne({
  324. path: '/normalize_7/normalize_8_gC',
  325. });
  326. expect(page7).toBeTruthy();
  327. expect(page8AM).toBeTruthy();
  328. expect(page9AM).toBeTruthy();
  329. expect(page10AM).toBeTruthy();
  330. expect(page7.isEmpty).toBe(true);
  331. expect(page7.parent).toStrictEqual(rootPage._id);
  332. expect(page8AM.parent).toStrictEqual(page7._id);
  333. expect(page9AM.parent).toStrictEqual(page8AM._id);
  334. expect(page10AM.parent).toStrictEqual(page7._id);
  335. });
  336. test("should replace empty page with same path with new non-empty page and update all related children's parent", async () => {
  337. const page1 = await Page.findOne({
  338. path: '/normalize_10',
  339. isEmpty: true,
  340. parent: { $ne: null },
  341. });
  342. const page2 = await Page.findOne({
  343. path: '/normalize_10/normalize_11_gA',
  344. _id: pageId8,
  345. isEmpty: true,
  346. parent: { $ne: null },
  347. });
  348. const page3 = await Page.findOne({
  349. path: '/normalize_10/normalize_11_gA',
  350. _id: pageId9,
  351. parent: null,
  352. }); // not v5
  353. const page4 = await Page.findOne({
  354. path: '/normalize_10/normalize_11_gA/normalize_11_gB',
  355. parent: { $ne: null },
  356. });
  357. const page5 = await Page.findOne({
  358. path: '/normalize_10/normalize_12_gC',
  359. parent: { $ne: null },
  360. });
  361. expect(page1).toBeTruthy();
  362. expect(page2).toBeTruthy();
  363. expect(page3).toBeTruthy();
  364. expect(page4).toBeTruthy();
  365. expect(page5).toBeTruthy();
  366. await normalizeParentRecursivelyByPages([page3], testUser1);
  367. // AM => After Migration
  368. const page1AM = await Page.findOne({ path: '/normalize_10' });
  369. const page2AM = await Page.findOne({
  370. path: '/normalize_10/normalize_11_gA',
  371. _id: pageId8,
  372. });
  373. const page3AM = await Page.findOne({
  374. path: '/normalize_10/normalize_11_gA',
  375. _id: pageId9,
  376. });
  377. const page4AM = await Page.findOne({
  378. path: '/normalize_10/normalize_11_gA/normalize_11_gB',
  379. });
  380. const page5AM = await Page.findOne({
  381. path: '/normalize_10/normalize_12_gC',
  382. });
  383. expect(page1AM).toBeTruthy();
  384. expect(page3AM).toBeTruthy();
  385. expect(page4AM).toBeTruthy();
  386. expect(page5AM).toBeTruthy();
  387. expect(page2AM).toBeNull();
  388. expect(page1AM.isEmpty).toBeTruthy();
  389. expect(page3AM.parent).toStrictEqual(page1AM._id);
  390. expect(page4AM.parent).toStrictEqual(page3AM._id);
  391. expect(page5AM.parent).toStrictEqual(page1AM._id);
  392. expect(page3AM.isEmpty).toBe(false);
  393. });
  394. });
  395. describe('should normalize only selected pages recursively (while observing the page permission rule)', () => {
  396. /*
  397. * # Test flow 1
  398. * - Existing pages
  399. * - v5 compatible pages
  400. * - /normalize_a (empty)
  401. * - /normalize_a/normalize_b (public)
  402. * - v4 pages
  403. * - /normalize_a (user group)
  404. * - /normalize_c (user group)
  405. *
  406. * - Normalize /normalize_a (user group)
  407. * - Expect
  408. * - Error should be thrown
  409. *
  410. *
  411. * # Test flow 2
  412. * - Existing pages
  413. * - v5 compatible pages
  414. * - /normalize_d (empty)
  415. * - /normalize_d/normalize_e (user group)
  416. * - v4 pages
  417. * - /normalize_d (user group)
  418. * - /normalize_f (user group)
  419. *
  420. * - Normalize /normalize_d (user group)
  421. * - Expect
  422. * - Normalization succeeds
  423. * - /normalize_f (user group) remains in v4 schema
  424. *
  425. *
  426. * # Test flow 3 (should replace all unnecessary empty pages)
  427. * - Existing pages
  428. * - v5 compatible pages
  429. * - / (root)
  430. * - /normalize_g (public)
  431. * - v4 pages
  432. * - /normalize_g/normalize_h (only me)
  433. * - /normalize_g/normalize_i (only me)
  434. * - /normalize_g/normalize_h/normalize_j (only me)
  435. * - /normalize_g/normalize_i/normalize_k (only me)
  436. *
  437. * - Normalize /normalize_g/normalize_h/normalize_j (only me) & /normalize_g/normalize_i/normalize_k (only me)
  438. * - Expect
  439. * - /normalize_g/normalize_h (empty)
  440. * - parent is /normalize_g (public)
  441. * - /normalize_g/normalize_i (empty)
  442. * - parent is /normalize_g (public)
  443. * - /normalize_g/normalize_h/normalize_j (only me) is normalized
  444. * - /normalize_g/normalize_i/normalize_k (only me) is normalized
  445. */
  446. beforeAll(async () => {
  447. // Prepare data
  448. const id1 = new mongoose.Types.ObjectId();
  449. const id2 = new mongoose.Types.ObjectId();
  450. const id3 = new mongoose.Types.ObjectId();
  451. const id4 = new mongoose.Types.ObjectId();
  452. await Page.insertMany([
  453. // 1
  454. {
  455. _id: id3,
  456. path: '/deep_path',
  457. grant: Page.GRANT_PUBLIC,
  458. parent: rootPage._id,
  459. },
  460. {
  461. _id: id1,
  462. path: '/deep_path/normalize_a',
  463. isEmpty: true,
  464. parent: id3,
  465. },
  466. {
  467. path: '/deep_path/normalize_a/normalize_b',
  468. grant: Page.GRANT_PUBLIC,
  469. parent: id1,
  470. },
  471. {
  472. path: '/deep_path/normalize_a',
  473. grant: Page.GRANT_USER_GROUP,
  474. grantedGroups: [{ item: testUser1GroupId, type: 'UserGroup' }],
  475. parent: null,
  476. },
  477. {
  478. path: '/deep_path/normalize_c',
  479. grant: Page.GRANT_USER_GROUP,
  480. grantedGroups: [{ item: testUser1GroupId, type: 'UserGroup' }],
  481. parent: null,
  482. },
  483. // 2
  484. {
  485. _id: id2,
  486. path: '/normalize_d',
  487. isEmpty: true,
  488. parent: rootPage._id,
  489. },
  490. {
  491. path: '/normalize_d',
  492. grant: Page.GRANT_USER_GROUP,
  493. grantedGroups: [{ item: testUser1GroupId, type: 'UserGroup' }],
  494. parent: null,
  495. },
  496. {
  497. path: '/normalize_d/normalize_e',
  498. grant: Page.GRANT_USER_GROUP,
  499. grantedGroups: [{ item: testUser1GroupId, type: 'UserGroup' }],
  500. parent: id2,
  501. },
  502. {
  503. path: '/normalize_f',
  504. grant: Page.GRANT_USER_GROUP,
  505. grantedGroups: [{ item: testUser1GroupId, type: 'UserGroup' }],
  506. parent: null,
  507. },
  508. // 3
  509. {
  510. _id: id4,
  511. path: '/normalize_g',
  512. parent: rootPage._id,
  513. },
  514. {
  515. path: '/normalize_g/normalize_h',
  516. grant: Page.GRANT_OWNER,
  517. grantedUsers: [testUser1._id],
  518. parent: null,
  519. },
  520. {
  521. path: '/normalize_g/normalize_i',
  522. grant: Page.GRANT_OWNER,
  523. grantedUsers: [testUser1._id],
  524. parent: null,
  525. },
  526. {
  527. path: '/normalize_g/normalize_h/normalize_j',
  528. grant: Page.GRANT_OWNER,
  529. grantedUsers: [testUser1._id],
  530. parent: null,
  531. },
  532. {
  533. path: '/normalize_g/normalize_i/normalize_k',
  534. grant: Page.GRANT_OWNER,
  535. grantedUsers: [testUser1._id],
  536. parent: null,
  537. },
  538. ]);
  539. });
  540. test('should not run normalization when the target page is GRANT_USER_GROUP surrounded by public pages', async () => {
  541. const mockMainOperation = jest
  542. .spyOn(crowi.pageService, 'normalizeParentRecursivelyMainOperation')
  543. .mockImplementation((v) => v);
  544. const _page1 = await Page.findOne(
  545. onlyPublic({ path: '/deep_path/normalize_a', ...empty }),
  546. );
  547. const _page2 = await Page.findOne(
  548. onlyPublic({
  549. path: '/deep_path/normalize_a/normalize_b',
  550. ...normalized,
  551. }),
  552. );
  553. const _page3 = await Page.findOne(
  554. testUser1Group({ path: '/deep_path/normalize_a', ...notNormalized }),
  555. );
  556. const _page4 = await Page.findOne(
  557. testUser1Group({ path: '/deep_path/normalize_c', ...notNormalized }),
  558. );
  559. expect(_page1).not.toBeNull();
  560. expect(_page2).not.toBeNull();
  561. expect(_page3).not.toBeNull();
  562. expect(_page4).not.toBeNull();
  563. // Normalize
  564. await normalizeParentRecursivelyByPages([_page3], testUser1);
  565. expect(mockMainOperation).not.toHaveBeenCalled();
  566. mockMainOperation.mockRestore();
  567. });
  568. test('should not include siblings', async () => {
  569. const _page1 = await Page.findOne(
  570. onlyPublic({ path: '/normalize_d', ...empty }),
  571. );
  572. const _page2 = await Page.findOne(
  573. testUser1Group({ path: '/normalize_d/normalize_e', ...normalized }),
  574. );
  575. const _page3 = await Page.findOne(
  576. testUser1Group({ path: '/normalize_d', ...notNormalized }),
  577. );
  578. const _page4 = await Page.findOne(
  579. testUser1Group({ path: '/normalize_f', ...notNormalized }),
  580. );
  581. expect(_page1).not.toBeNull();
  582. expect(_page2).not.toBeNull();
  583. expect(_page3).not.toBeNull();
  584. expect(_page4).not.toBeNull();
  585. // Normalize
  586. await normalizeParentRecursivelyByPages([_page3], testUser1);
  587. const page1 = await Page.findOne(
  588. testUser1Group({ path: '/normalize_d/normalize_e' }),
  589. );
  590. const page2 = await Page.findOne(
  591. testUser1Group({ path: '/normalize_d' }),
  592. );
  593. const page3 = await Page.findOne(
  594. testUser1Group({ path: '/normalize_f' }),
  595. );
  596. const empty4 = await Page.findOne(
  597. onlyPublic({ path: '/normalize_d', ...empty }),
  598. );
  599. expect(page1).not.toBeNull();
  600. expect(page2).not.toBeNull();
  601. expect(page3).not.toBeNull();
  602. expect(empty4).toBeNull(); // empty page should be removed
  603. // Check parent
  604. expect(page1.parent).toStrictEqual(page2._id);
  605. expect(page2.parent).toStrictEqual(rootPage._id);
  606. expect(page3.parent).toBeNull(); // should not be normalized
  607. // Check descendantCount
  608. expect(page1.descendantCount).toBe(0);
  609. expect(page2.descendantCount).toBe(1);
  610. expect(page3.descendantCount).toBe(0); // should not be normalized
  611. });
  612. test('should replace all unnecessary empty pages and normalization succeeds', async () => {
  613. const _pageG = await Page.findOne(
  614. onlyPublic({ path: '/normalize_g', ...normalized }),
  615. );
  616. const _pageGH = await Page.findOne(
  617. ownedByTestUser1({
  618. path: '/normalize_g/normalize_h',
  619. ...notNormalized,
  620. }),
  621. );
  622. const _pageGI = await Page.findOne(
  623. ownedByTestUser1({
  624. path: '/normalize_g/normalize_i',
  625. ...notNormalized,
  626. }),
  627. );
  628. const _pageGHJ = await Page.findOne(
  629. ownedByTestUser1({
  630. path: '/normalize_g/normalize_h/normalize_j',
  631. ...notNormalized,
  632. }),
  633. );
  634. const _pageGIK = await Page.findOne(
  635. ownedByTestUser1({
  636. path: '/normalize_g/normalize_i/normalize_k',
  637. ...notNormalized,
  638. }),
  639. );
  640. expect(_pageG).not.toBeNull();
  641. expect(_pageGH).not.toBeNull();
  642. expect(_pageGI).not.toBeNull();
  643. expect(_pageGHJ).not.toBeNull();
  644. expect(_pageGIK).not.toBeNull();
  645. // Normalize
  646. await normalizeParentRecursivelyByPages([_pageGHJ, _pageGIK], testUser1);
  647. const countG = await Page.count({ path: '/normalize_g' });
  648. const countGH = await Page.count({ path: '/normalize_g/normalize_h' });
  649. const countGI = await Page.count({ path: '/normalize_g/normalize_i' });
  650. const countGHJ = await Page.count({
  651. path: '/normalize_g/normalize_h/normalize_j',
  652. });
  653. const countGIK = await Page.count({
  654. path: '/normalize_g/normalize_i/normalize_k',
  655. });
  656. expect(countG).toBe(1);
  657. expect(countGH).toBe(2);
  658. expect(countGI).toBe(2);
  659. expect(countGHJ).toBe(1);
  660. expect(countGIK).toBe(1);
  661. // -- normalized pages
  662. const pageG = await Page.findOne(onlyPublic({ path: '/normalize_g' }));
  663. const emptyGH = await Page.findOne({
  664. path: '/normalize_g/normalize_h',
  665. ...empty,
  666. });
  667. const emptyGI = await Page.findOne({
  668. path: '/normalize_g/normalize_i',
  669. ...empty,
  670. });
  671. const pageGHJ = await Page.findOne({
  672. path: '/normalize_g/normalize_h/normalize_j',
  673. });
  674. const pageGIK = await Page.findOne({
  675. path: '/normalize_g/normalize_i/normalize_k',
  676. });
  677. // Check existence
  678. expect(pageG).not.toBeNull();
  679. expect(pageGHJ).not.toBeNull();
  680. expect(pageGIK).not.toBeNull();
  681. expect(emptyGH).not.toBeNull();
  682. expect(emptyGI).not.toBeNull();
  683. // Check parent
  684. expect(pageG.parent).toStrictEqual(rootPage._id);
  685. expect(emptyGH.parent).toStrictEqual(pageG._id);
  686. expect(emptyGI.parent).toStrictEqual(pageG._id);
  687. expect(pageGHJ.parent).toStrictEqual(emptyGH._id);
  688. expect(pageGIK.parent).toStrictEqual(emptyGI._id);
  689. // Check descendantCount
  690. expect(pageG.descendantCount).toStrictEqual(2);
  691. expect(emptyGH.descendantCount).toStrictEqual(1);
  692. expect(emptyGI.descendantCount).toStrictEqual(1);
  693. expect(pageGHJ.descendantCount).toStrictEqual(0);
  694. expect(pageGIK.descendantCount).toStrictEqual(0);
  695. // -- not normalized pages
  696. const pageGH = await Page.findOne(
  697. ownedByTestUser1({ path: '/normalize_g/normalize_h' }),
  698. );
  699. const pageGI = await Page.findOne(
  700. ownedByTestUser1({ path: '/normalize_g/normalize_i' }),
  701. );
  702. // Check existence
  703. expect(pageGH).not.toBeNull();
  704. expect(pageGI).not.toBeNull();
  705. // Check parent
  706. expect(pageGH.parent).toBeNull(); // should not be normalized
  707. expect(pageGI.parent).toBeNull(); // should not be normalized
  708. // Check descendantCount
  709. expect(pageGH.descendantCount).toStrictEqual(0); // should not be normalized
  710. expect(pageGI.descendantCount).toStrictEqual(0); // should not be normalized
  711. });
  712. });
  713. describe('should normalize only selected pages recursively (especially should NOT normalize non-selected ancestors)', () => {
  714. /*
  715. * # Test flow
  716. * - Existing pages
  717. * - All pages are NOT normalized
  718. * - A, B, C, and D are owned by "testUser1"
  719. * A. /normalize_A_owned
  720. * B. /normalize_A_owned/normalize_B_owned
  721. * C. /normalize_A_owned/normalize_B_owned/normalize_C_owned
  722. * D. /normalize_A_owned/normalize_B_owned/normalize_C_owned/normalize_D_owned
  723. * E. /normalize_A_owned/normalize_B_owned/normalize_C_owned/normalize_D_root
  724. * - Owned by "rootUser"
  725. * F. /normalize_A_owned/normalize_B_owned/normalize_C_owned/normalize_D_group
  726. * - Owned by the userGroup "groupIdIsolate"
  727. *
  728. * 1. Normalize A and B one by one.
  729. * - Expect
  730. * - A and B are normalized
  731. * - C and D are NOT normalized
  732. * - E and F are NOT normalized
  733. * 2. Recursively normalize D.
  734. * - Expect
  735. * - A, B, and D are normalized
  736. * - C is NOT normalized
  737. * - C is substituted by an empty page whose path is "/normalize_A_owned/normalize_B_owned/normalize_C_owned"
  738. * - E and F are NOT normalized
  739. * 3. Recursively normalize C.
  740. * - Expect
  741. * - A, B, C, and D are normalized
  742. * - An empty page at "/normalize_A_owned/normalize_B_owned/normalize_C_owned" does NOT exist (removed)
  743. * - E and F are NOT normalized
  744. */
  745. beforeAll(async () => {
  746. // Prepare data
  747. const id17 = new mongoose.Types.ObjectId();
  748. const id21 = new mongoose.Types.ObjectId();
  749. const id22 = new mongoose.Types.ObjectId();
  750. const id23 = new mongoose.Types.ObjectId();
  751. await Page.insertMany([
  752. // 1
  753. {
  754. path: '/normalize_13_owned',
  755. grant: Page.GRANT_OWNER,
  756. grantedUsers: [testUser1._id],
  757. },
  758. {
  759. path: '/normalize_13_owned/normalize_14_owned',
  760. grant: Page.GRANT_OWNER,
  761. grantedUsers: [testUser1._id],
  762. },
  763. {
  764. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned',
  765. grant: Page.GRANT_OWNER,
  766. grantedUsers: [testUser1._id],
  767. },
  768. {
  769. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_owned',
  770. grant: Page.GRANT_OWNER,
  771. grantedUsers: [testUser1._id],
  772. },
  773. {
  774. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_root',
  775. grant: Page.GRANT_OWNER,
  776. grantedUsers: [rootUser._id],
  777. },
  778. {
  779. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_group',
  780. grant: Page.GRANT_USER_GROUP,
  781. grantedGroups: [{ item: testUser1GroupId, type: 'UserGroup' }],
  782. },
  783. // 2
  784. {
  785. _id: id17,
  786. path: '/normalize_17_owned',
  787. grant: Page.GRANT_OWNER,
  788. grantedUsers: [testUser1._id],
  789. parent: rootPage._id,
  790. },
  791. {
  792. path: '/normalize_17_owned/normalize_18_owned',
  793. grant: Page.GRANT_OWNER,
  794. grantedUsers: [testUser1._id],
  795. parent: id17,
  796. },
  797. {
  798. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned',
  799. grant: Page.GRANT_OWNER,
  800. grantedUsers: [testUser1._id],
  801. },
  802. {
  803. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_owned',
  804. grant: Page.GRANT_OWNER,
  805. grantedUsers: [testUser1._id],
  806. },
  807. {
  808. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_root',
  809. grant: Page.GRANT_OWNER,
  810. grantedUsers: [rootUser._id],
  811. },
  812. {
  813. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_group',
  814. grant: Page.GRANT_USER_GROUP,
  815. grantedGroups: [{ item: rootUserGroupId, type: 'UserGroup' }],
  816. },
  817. // 3
  818. {
  819. _id: id21,
  820. path: '/normalize_21_owned',
  821. grant: Page.GRANT_OWNER,
  822. grantedUsers: [testUser1._id],
  823. parent: rootPage._id,
  824. },
  825. {
  826. _id: id22,
  827. path: '/normalize_21_owned/normalize_22_owned',
  828. grant: Page.GRANT_OWNER,
  829. grantedUsers: [testUser1._id],
  830. parent: id21,
  831. },
  832. {
  833. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned',
  834. grant: Page.GRANT_OWNER,
  835. grantedUsers: [testUser1._id],
  836. parent: null,
  837. },
  838. {
  839. _id: id23,
  840. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned',
  841. isEmpty: true,
  842. parent: id22,
  843. },
  844. {
  845. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_owned',
  846. grant: Page.GRANT_OWNER,
  847. grantedUsers: [testUser1._id],
  848. parent: id23,
  849. },
  850. {
  851. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_root',
  852. grant: Page.GRANT_OWNER,
  853. grantedUsers: [rootUser._id],
  854. },
  855. {
  856. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_rootGroup',
  857. grant: Page.GRANT_USER_GROUP,
  858. grantedGroups: [{ item: rootUserGroupId, type: 'UserGroup' }],
  859. },
  860. ]);
  861. });
  862. test('Should normalize a single page without including other pages', async () => {
  863. const _owned13 = await Page.findOne(
  864. ownedByTestUser1({ path: '/normalize_13_owned', ...notNormalized }),
  865. );
  866. const _owned14 = await Page.findOne(
  867. ownedByTestUser1({
  868. path: '/normalize_13_owned/normalize_14_owned',
  869. ...notNormalized,
  870. }),
  871. );
  872. const _owned15 = await Page.findOne(
  873. ownedByTestUser1({
  874. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned',
  875. ...notNormalized,
  876. }),
  877. );
  878. const _owned16 = await Page.findOne(
  879. ownedByTestUser1({
  880. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_owned',
  881. ...notNormalized,
  882. }),
  883. );
  884. const _root16 = await Page.findOne(
  885. root({
  886. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_root',
  887. ...notNormalized,
  888. }),
  889. );
  890. const _group16 = await Page.findOne(
  891. testUser1Group({
  892. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_group',
  893. ...notNormalized,
  894. }),
  895. );
  896. expect(_owned13).not.toBeNull();
  897. expect(_owned14).not.toBeNull();
  898. expect(_owned15).not.toBeNull();
  899. expect(_owned16).not.toBeNull();
  900. expect(_root16).not.toBeNull();
  901. expect(_group16).not.toBeNull();
  902. // Normalize
  903. await normalizeParentByPage(_owned14, testUser1);
  904. const owned13 = await Page.findOne({ path: '/normalize_13_owned' });
  905. const empty13 = await Page.findOne({
  906. path: '/normalize_13_owned',
  907. ...empty,
  908. });
  909. const owned14 = await Page.findOne({
  910. path: '/normalize_13_owned/normalize_14_owned',
  911. });
  912. const owned15 = await Page.findOne({
  913. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned',
  914. });
  915. const owned16 = await Page.findOne({
  916. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_owned',
  917. });
  918. const root16 = await Page.findOne(
  919. root({
  920. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_root',
  921. }),
  922. );
  923. const group16 = await Page.findOne(
  924. testUser1Group({
  925. path: '/normalize_13_owned/normalize_14_owned/normalize_15_owned/normalize_16_group',
  926. }),
  927. );
  928. expect(owned13).not.toBeNull();
  929. expect(empty13).not.toBeNull();
  930. expect(owned14).not.toBeNull();
  931. expect(owned15).not.toBeNull();
  932. expect(owned16).not.toBeNull();
  933. expect(root16).not.toBeNull();
  934. expect(group16).not.toBeNull();
  935. // Check parent
  936. expect(owned13.parent).toBeNull();
  937. expect(empty13.parent).toStrictEqual(rootPage._id);
  938. expect(owned14.parent).toStrictEqual(empty13._id);
  939. expect(owned15.parent).toBeNull();
  940. expect(owned16.parent).toBeNull();
  941. expect(root16.parent).toBeNull();
  942. expect(group16.parent).toBeNull();
  943. // Check descendantCount
  944. expect(owned13.descendantCount).toBe(0);
  945. expect(empty13.descendantCount).toBe(1);
  946. expect(owned14.descendantCount).toBe(0);
  947. });
  948. test('Should normalize pages recursively excluding the pages not selected', async () => {
  949. const _owned17 = await Page.findOne(
  950. ownedByTestUser1({ path: '/normalize_17_owned', ...normalized }),
  951. );
  952. const _owned18 = await Page.findOne(
  953. ownedByTestUser1({
  954. path: '/normalize_17_owned/normalize_18_owned',
  955. ...normalized,
  956. }),
  957. );
  958. const _owned19 = await Page.findOne(
  959. ownedByTestUser1({
  960. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned',
  961. ...notNormalized,
  962. }),
  963. );
  964. const _owned20 = await Page.findOne(
  965. ownedByTestUser1({
  966. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_owned',
  967. ...notNormalized,
  968. }),
  969. );
  970. const _root20 = await Page.findOne(
  971. root({
  972. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_root',
  973. ...notNormalized,
  974. }),
  975. );
  976. const _group20 = await Page.findOne(
  977. rootUserGroup({
  978. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_group',
  979. ...notNormalized,
  980. }),
  981. );
  982. expect(_owned17).not.toBeNull();
  983. expect(_owned18).not.toBeNull();
  984. expect(_owned19).not.toBeNull();
  985. expect(_owned20).not.toBeNull();
  986. expect(_root20).not.toBeNull();
  987. expect(_group20).not.toBeNull();
  988. // Normalize
  989. await normalizeParentRecursivelyByPages([_owned20], testUser1);
  990. const owned17 = await Page.findOne({ path: '/normalize_17_owned' });
  991. const owned18 = await Page.findOne({
  992. path: '/normalize_17_owned/normalize_18_owned',
  993. });
  994. const owned19 = await Page.findOne({
  995. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned',
  996. });
  997. const empty19 = await Page.findOne({
  998. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned',
  999. ...empty,
  1000. });
  1001. const owned20 = await Page.findOne({
  1002. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_owned',
  1003. });
  1004. const root20 = await Page.findOne(
  1005. root({
  1006. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_root',
  1007. }),
  1008. );
  1009. const group20 = await Page.findOne(
  1010. rootUserGroup({
  1011. path: '/normalize_17_owned/normalize_18_owned/normalize_19_owned/normalize_20_group',
  1012. }),
  1013. );
  1014. expect(owned17).not.toBeNull();
  1015. expect(owned18).not.toBeNull();
  1016. expect(owned19).not.toBeNull();
  1017. expect(empty19).not.toBeNull();
  1018. expect(owned20).not.toBeNull();
  1019. expect(root20).not.toBeNull();
  1020. expect(group20).not.toBeNull();
  1021. // Check parent
  1022. expect(owned17.parent).toStrictEqual(rootPage._id);
  1023. expect(owned18.parent).toStrictEqual(owned17._id);
  1024. expect(owned19.parent).toBeNull();
  1025. expect(empty19.parent).toStrictEqual(owned18._id);
  1026. expect(owned20.parent).toStrictEqual(empty19._id);
  1027. expect(root20.parent).toBeNull();
  1028. expect(group20.parent).toBeNull();
  1029. // Check isEmpty
  1030. expect(owned17.isEmpty).toBe(false);
  1031. expect(owned18.isEmpty).toBe(false);
  1032. });
  1033. test("Should normalize pages recursively excluding the pages of not user's & Should delete unnecessary empty pages", async () => {
  1034. const _owned21 = await Page.findOne(
  1035. ownedByTestUser1({ path: '/normalize_21_owned', ...normalized }),
  1036. );
  1037. const _owned22 = await Page.findOne(
  1038. ownedByTestUser1({
  1039. path: '/normalize_21_owned/normalize_22_owned',
  1040. ...normalized,
  1041. }),
  1042. );
  1043. const _owned23 = await Page.findOne(
  1044. ownedByTestUser1({
  1045. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned',
  1046. ...notNormalized,
  1047. }),
  1048. );
  1049. const _empty23 = await Page.findOne({
  1050. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned',
  1051. ...normalized,
  1052. ...empty,
  1053. });
  1054. const _owned24 = await Page.findOne(
  1055. ownedByTestUser1({
  1056. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_owned',
  1057. ...normalized,
  1058. }),
  1059. );
  1060. const _root24 = await Page.findOne(
  1061. root({
  1062. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_root',
  1063. ...notNormalized,
  1064. }),
  1065. );
  1066. const _rootGroup24 = await Page.findOne(
  1067. rootUserGroup({
  1068. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_rootGroup',
  1069. ...notNormalized,
  1070. }),
  1071. );
  1072. expect(_owned21).not.toBeNull();
  1073. expect(_owned22).not.toBeNull();
  1074. expect(_owned23).not.toBeNull();
  1075. expect(_empty23).not.toBeNull();
  1076. expect(_owned24).not.toBeNull();
  1077. expect(_root24).not.toBeNull();
  1078. expect(_rootGroup24).not.toBeNull();
  1079. // Normalize
  1080. await normalizeParentRecursivelyByPages([_owned23], testUser1);
  1081. const owned21 = await Page.findOne({ path: '/normalize_21_owned' });
  1082. const owned22 = await Page.findOne({
  1083. path: '/normalize_21_owned/normalize_22_owned',
  1084. });
  1085. const owned23 = await Page.findOne({
  1086. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned',
  1087. });
  1088. const empty23 = await Page.findOne({
  1089. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned',
  1090. ...empty,
  1091. });
  1092. const owned24 = await Page.findOne({
  1093. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_owned',
  1094. });
  1095. const root24 = await Page.findOne(
  1096. root({
  1097. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_root',
  1098. }),
  1099. );
  1100. const rootGroup24 = await Page.findOne(
  1101. rootUserGroup({
  1102. path: '/normalize_21_owned/normalize_22_owned/normalize_23_owned/normalize_24_rootGroup',
  1103. }),
  1104. );
  1105. expect(owned21).not.toBeNull();
  1106. expect(owned22).not.toBeNull();
  1107. expect(owned23).not.toBeNull();
  1108. expect(empty23).toBeNull(); // removed
  1109. expect(owned24).not.toBeNull();
  1110. expect(root24).not.toBeNull();
  1111. expect(rootGroup24).not.toBeNull();
  1112. // Check parent
  1113. expect(owned21.parent).toStrictEqual(rootPage._id);
  1114. expect(owned22.parent).toStrictEqual(owned21._id);
  1115. expect(owned23.parent).toStrictEqual(owned22._id);
  1116. expect(owned24.parent).toStrictEqual(owned23._id); // not empty23._id
  1117. expect(root24.parent).toBeNull();
  1118. expect(rootGroup24.parent).toBeNull(); // excluded from the pages to be normalized
  1119. // Check isEmpty
  1120. expect(owned21.isEmpty).toBe(false);
  1121. expect(owned22.isEmpty).toBe(false);
  1122. expect(owned23.isEmpty).toBe(false);
  1123. });
  1124. });
  1125. describe('normalizeAllPublicPages()', () => {
  1126. jest.setTimeout(60000);
  1127. let createPagePaths;
  1128. let allPossiblePagePaths;
  1129. beforeAll(async () => {
  1130. createPagePaths = [
  1131. '/publicA',
  1132. '/publicA/privateB',
  1133. '/publicA/privateB/publicC',
  1134. '/parenthesis/(a)[b]{c}d',
  1135. '/parenthesis/(a)[b]{c}d/public',
  1136. '/migratedD',
  1137. ];
  1138. allPossiblePagePaths = [...createPagePaths, '/parenthesis', '/'];
  1139. // initialize pages for test
  1140. await Page.insertMany([
  1141. {
  1142. path: '/publicA',
  1143. grant: Page.GRANT_PUBLIC,
  1144. creator: testUser1,
  1145. lastUpdateUser: testUser1,
  1146. },
  1147. {
  1148. path: '/publicA/privateB',
  1149. grant: Page.GRANT_OWNER,
  1150. creator: testUser1,
  1151. lastUpdateUser: testUser1,
  1152. grantedUsers: [testUser1._id],
  1153. },
  1154. {
  1155. path: '/publicA/privateB/publicC',
  1156. grant: Page.GRANT_PUBLIC,
  1157. creator: testUser1,
  1158. lastUpdateUser: testUser1,
  1159. },
  1160. {
  1161. path: '/parenthesis/(a)[b]{c}d',
  1162. grant: Page.GRANT_PUBLIC,
  1163. creator: testUser1,
  1164. lastUpdateUser: testUser1,
  1165. },
  1166. {
  1167. path: '/parenthesis/(a)[b]{c}d/public',
  1168. grant: Page.GRANT_PUBLIC,
  1169. creator: testUser1,
  1170. lastUpdateUser: testUser1,
  1171. },
  1172. ]);
  1173. const parent = await Page.find({ path: '/' });
  1174. await Page.insertMany([
  1175. {
  1176. path: '/migratedD',
  1177. grant: Page.GRANT_PUBLIC,
  1178. creator: testUser1,
  1179. lastUpdateUser: testUser1,
  1180. parent: parent._id,
  1181. },
  1182. ]);
  1183. // migrate
  1184. await crowi.pageService.normalizeAllPublicPages(Page.GRANT_PUBLIC);
  1185. jest.setTimeout(30000);
  1186. });
  1187. test('should migrate all public pages', async () => {
  1188. const migratedPages = await Page.find({
  1189. path: {
  1190. $in: allPossiblePagePaths,
  1191. },
  1192. parent: { $ne: null },
  1193. });
  1194. const migratedEmptyPages = await Page.find({
  1195. path: {
  1196. $in: allPossiblePagePaths,
  1197. },
  1198. isEmpty: true,
  1199. parent: { $ne: null },
  1200. });
  1201. const nonMigratedPages = await Page.find({
  1202. path: {
  1203. $in: allPossiblePagePaths,
  1204. },
  1205. parent: null,
  1206. });
  1207. const migratedPaths = migratedPages.map((page) => page.path).sort();
  1208. const migratedEmptyPaths = migratedEmptyPages
  1209. .map((page) => page.path)
  1210. .sort();
  1211. const nonMigratedPaths = nonMigratedPages.map((page) => page.path).sort();
  1212. const expectedMigratedPaths = allPossiblePagePaths
  1213. .filter((path) => path !== '/')
  1214. .sort();
  1215. const expectedMigratedEmptyPaths = [
  1216. '/publicA/privateB',
  1217. '/parenthesis',
  1218. ].sort();
  1219. const expectedNonMigratedPaths = ['/publicA/privateB', '/'].sort();
  1220. expect(migratedPaths).toStrictEqual(expectedMigratedPaths);
  1221. expect(migratedEmptyPaths).toStrictEqual(expectedMigratedEmptyPaths);
  1222. expect(nonMigratedPaths).toStrictEqual(expectedNonMigratedPaths);
  1223. });
  1224. });
  1225. describe('normalizeParentByPage()', () => {
  1226. test('it should normalize not v5 page with usergroup that has parent group', async () => {
  1227. const page1 = await Page.findOne({
  1228. _id: pageId1,
  1229. path: '/normalize_1',
  1230. isEmpty: true,
  1231. });
  1232. const page2 = await Page.findOne({
  1233. _id: pageId2,
  1234. path: '/normalize_1/normalize_2',
  1235. parent: page1._id,
  1236. });
  1237. const page3 = await Page.findOne({ _id: pageId3, path: '/normalize_1' }); // NOT v5
  1238. expect(page1).toBeTruthy();
  1239. expect(page2).toBeTruthy();
  1240. expect(page3).toBeTruthy();
  1241. await normalizeParentByPage(page3, testUser1);
  1242. // AM => After Migration
  1243. const page1AM = await Page.findOne({
  1244. _id: pageId1,
  1245. path: '/normalize_1',
  1246. isEmpty: true,
  1247. });
  1248. const page2AM = await Page.findOne({
  1249. _id: pageId2,
  1250. path: '/normalize_1/normalize_2',
  1251. });
  1252. const page3AM = await Page.findOne({
  1253. _id: pageId3,
  1254. path: '/normalize_1',
  1255. }); // v5 compatible
  1256. expect(page2AM).toBeTruthy();
  1257. expect(page3AM).toBeTruthy();
  1258. expect(page1AM).toBeNull();
  1259. expect(page2AM.parent).toStrictEqual(page3AM._id);
  1260. expect(page3AM.parent).toStrictEqual(rootPage._id);
  1261. });
  1262. test('should throw error if a page with isolated group becomes the parent of other page with different group after normalizing', async () => {
  1263. const page4 = await Page.findOne({
  1264. _id: pageId4,
  1265. path: '/normalize_4',
  1266. isEmpty: true,
  1267. });
  1268. const page5 = await Page.findOne({
  1269. _id: pageId5,
  1270. path: '/normalize_4/normalize_5',
  1271. parent: page4._id,
  1272. });
  1273. const page6 = await Page.findOne({ _id: pageId6, path: '/normalize_4' }); // NOT v5
  1274. expect(page4).toBeTruthy();
  1275. expect(page5).toBeTruthy();
  1276. expect(page6).toBeTruthy();
  1277. let isThrown;
  1278. try {
  1279. await normalizeParentByPage(page6, testUser1);
  1280. } catch (err) {
  1281. isThrown = true;
  1282. }
  1283. // AM => After Migration
  1284. const page4AM = await Page.findOne({
  1285. _id: pageId4,
  1286. path: '/normalize_4',
  1287. isEmpty: true,
  1288. });
  1289. const page5AM = await Page.findOne({
  1290. _id: pageId5,
  1291. path: '/normalize_4/normalize_5',
  1292. parent: page4._id,
  1293. });
  1294. const page6AM = await Page.findOne({
  1295. _id: pageId6,
  1296. path: '/normalize_4',
  1297. }); // NOT v5
  1298. expect(isThrown).toBe(true);
  1299. expect(page4AM).toBeTruthy();
  1300. expect(page5AM).toBeTruthy();
  1301. expect(page6AM).toBeTruthy();
  1302. expect(page4AM).toStrictEqual(page4);
  1303. expect(page5AM).toStrictEqual(page5);
  1304. expect(page6AM).toStrictEqual(page6);
  1305. });
  1306. });
  1307. test('replace private parents with empty pages', async () => {
  1308. const replacedPathPages = await Page.find({ path: '/publicA/privateB' }); // ex-private page
  1309. const _newEmptyPage = replacedPathPages.filter(
  1310. (page) => page.parent != null,
  1311. )[0];
  1312. const newEmptyPage = {
  1313. path: _newEmptyPage.path,
  1314. grant: _newEmptyPage.grant,
  1315. isEmpty: _newEmptyPage.isEmpty,
  1316. };
  1317. const expectedNewEmptyPage = {
  1318. path: '/publicA/privateB',
  1319. grant: Page.GRANT_PUBLIC,
  1320. isEmpty: true,
  1321. };
  1322. const _privatePage = replacedPathPages.filter(
  1323. (page) => page.parent == null,
  1324. )[0];
  1325. const privatePage = {
  1326. path: _privatePage.path,
  1327. grant: _privatePage.grant,
  1328. isEmpty: _privatePage.isEmpty,
  1329. };
  1330. const expectedPrivatePage = {
  1331. path: '/publicA/privateB',
  1332. grant: Page.GRANT_OWNER,
  1333. isEmpty: false,
  1334. };
  1335. expect(replacedPathPages.length).toBe(2);
  1336. expect(newEmptyPage).toStrictEqual(expectedNewEmptyPage);
  1337. expect(privatePage).toStrictEqual(expectedPrivatePage);
  1338. });
  1339. describe('normalizeParentByPath', () => {
  1340. const normalizeParentByPath = async (path, user) => {
  1341. const mock = jest
  1342. .spyOn(crowi.pageService, 'normalizeParentRecursivelyMainOperation')
  1343. .mockReturnValue(null);
  1344. const result = await crowi.pageService.normalizeParentByPath(path, user);
  1345. const args = mock.mock.calls[0];
  1346. mock.mockRestore();
  1347. await crowi.pageService.normalizeParentRecursivelyMainOperation(...args);
  1348. return result;
  1349. };
  1350. beforeAll(async () => {
  1351. const pageIdD = new mongoose.Types.ObjectId();
  1352. const pageIdG = new mongoose.Types.ObjectId();
  1353. await Page.insertMany([
  1354. {
  1355. path: '/norm_parent_by_path_A',
  1356. grant: Page.GRANT_OWNER,
  1357. grantedUsers: [testUser1._id],
  1358. creator: testUser1._id,
  1359. lastUpdateUser: testUser1._id,
  1360. parent: rootPage._id,
  1361. },
  1362. {
  1363. path: '/norm_parent_by_path_B/norm_parent_by_path_C',
  1364. grant: Page.GRANT_OWNER,
  1365. grantedUsers: [rootUser._id],
  1366. creator: rootUser._id,
  1367. lastUpdateUser: rootUser._id,
  1368. },
  1369. {
  1370. _id: pageIdD,
  1371. path: '/norm_parent_by_path_D',
  1372. isEmpty: true,
  1373. parent: rootPage._id,
  1374. descendantCount: 1,
  1375. },
  1376. {
  1377. path: '/norm_parent_by_path_D/norm_parent_by_path_E',
  1378. grant: Page.GRANT_PUBLIC,
  1379. creator: rootUser._id,
  1380. lastUpdateUser: rootUser._id,
  1381. parent: pageIdD,
  1382. },
  1383. {
  1384. path: '/norm_parent_by_path_D/norm_parent_by_path_F',
  1385. grant: Page.GRANT_OWNER,
  1386. grantedUsers: [rootUser._id],
  1387. creator: rootUser._id,
  1388. lastUpdateUser: rootUser._id,
  1389. },
  1390. {
  1391. _id: pageIdG,
  1392. path: '/norm_parent_by_path_G',
  1393. grant: Page.GRANT_PUBLIC,
  1394. creator: rootUser._id,
  1395. lastUpdateUser: rootUser._id,
  1396. parent: rootPage._id,
  1397. descendantCount: 1,
  1398. },
  1399. {
  1400. path: '/norm_parent_by_path_G/norm_parent_by_path_H',
  1401. grant: Page.GRANT_PUBLIC,
  1402. creator: rootUser._id,
  1403. lastUpdateUser: rootUser._id,
  1404. parent: pageIdG,
  1405. },
  1406. {
  1407. path: '/norm_parent_by_path_G/norm_parent_by_path_I',
  1408. grant: Page.GRANT_OWNER,
  1409. grantedUsers: [rootUser._id],
  1410. creator: rootUser._id,
  1411. lastUpdateUser: rootUser._id,
  1412. },
  1413. ]);
  1414. });
  1415. test('should fail when the user is not allowed to edit the target page found by path', async () => {
  1416. const pageTestUser1 = await Page.findOne(
  1417. ownedByTestUser1({ path: '/norm_parent_by_path_A' }),
  1418. );
  1419. expect(pageTestUser1).not.toBeNull();
  1420. await expect(
  1421. normalizeParentByPath('/norm_parent_by_path_A', rootUser),
  1422. ).rejects.toThrowError();
  1423. });
  1424. test('should normalize all granted pages under the path when no page exists at the path', async () => {
  1425. const _pageB = await Page.findOne({ path: '/norm_parent_by_path_B' });
  1426. const _pageBC = await Page.findOne(
  1427. root({ path: '/norm_parent_by_path_B/norm_parent_by_path_C' }),
  1428. );
  1429. expect(_pageB).toBeNull();
  1430. expect(_pageBC).not.toBeNull();
  1431. await normalizeParentByPath('/norm_parent_by_path_B', rootUser);
  1432. const pagesB = await Page.find({ path: '/norm_parent_by_path_B' }); // did not exist before running normalizeParentByPath
  1433. const pageBC = await Page.findById(_pageBC._id);
  1434. // -- check count
  1435. expect(pagesB.length).toBe(1);
  1436. const pageB = pagesB[0];
  1437. // -- check existance
  1438. expect(pageB.path).toBe('/norm_parent_by_path_B');
  1439. expect(pageBC.path).toBe('/norm_parent_by_path_B/norm_parent_by_path_C');
  1440. // -- check parent
  1441. expect(pageB.parent).toStrictEqual(rootPage._id);
  1442. expect(pageBC.parent).toStrictEqual(pageB._id);
  1443. // -- check descendantCount
  1444. expect(pageB.descendantCount).toBe(1);
  1445. expect(pageBC.descendantCount).toBe(0);
  1446. });
  1447. test('should normalize all granted pages under the path when an empty page exists at the path', async () => {
  1448. const _emptyD = await Page.findOne({
  1449. path: '/norm_parent_by_path_D',
  1450. ...empty,
  1451. ...normalized,
  1452. });
  1453. const _pageDE = await Page.findOne(
  1454. onlyPublic({
  1455. path: '/norm_parent_by_path_D/norm_parent_by_path_E',
  1456. ...normalized,
  1457. }),
  1458. );
  1459. const _pageDF = await Page.findOne(
  1460. root({
  1461. path: '/norm_parent_by_path_D/norm_parent_by_path_F',
  1462. ...notNormalized,
  1463. }),
  1464. );
  1465. expect(_emptyD).not.toBeNull();
  1466. expect(_pageDE).not.toBeNull();
  1467. expect(_pageDF).not.toBeNull();
  1468. await normalizeParentByPath('/norm_parent_by_path_D', rootUser);
  1469. const countD = await Page.count({ path: '/norm_parent_by_path_D' });
  1470. // -- check count
  1471. expect(countD).toBe(1);
  1472. const pageD = await Page.findById(_emptyD._id);
  1473. const pageDE = await Page.findById(_pageDE._id);
  1474. const pageDF = await Page.findById(_pageDF._id);
  1475. // -- check existance
  1476. expect(pageD.path).toBe('/norm_parent_by_path_D');
  1477. expect(pageDE.path).toBe('/norm_parent_by_path_D/norm_parent_by_path_E');
  1478. expect(pageDF.path).toBe('/norm_parent_by_path_D/norm_parent_by_path_F');
  1479. // -- check isEmpty of pageD
  1480. // pageD should not be empty because growi system will create a non-empty page while running normalizeParentByPath
  1481. expect(pageD.isEmpty).toBe(false);
  1482. // -- check parent
  1483. expect(pageD.parent).toStrictEqual(rootPage._id);
  1484. expect(pageDE.parent).toStrictEqual(pageD._id);
  1485. expect(pageDF.parent).toStrictEqual(pageD._id);
  1486. // -- check descendantCount
  1487. expect(pageD.descendantCount).toBe(2);
  1488. expect(pageDE.descendantCount).toBe(0);
  1489. expect(pageDF.descendantCount).toBe(0);
  1490. });
  1491. test('should normalize all granted pages under the path when a non-empty page exists at the path', async () => {
  1492. const _pageG = await Page.findOne(
  1493. onlyPublic({ path: '/norm_parent_by_path_G', ...normalized }),
  1494. );
  1495. const _pageGH = await Page.findOne(
  1496. onlyPublic({
  1497. path: '/norm_parent_by_path_G/norm_parent_by_path_H',
  1498. ...normalized,
  1499. }),
  1500. );
  1501. const _pageGI = await Page.findOne(
  1502. root({
  1503. path: '/norm_parent_by_path_G/norm_parent_by_path_I',
  1504. ...notNormalized,
  1505. }),
  1506. );
  1507. expect(_pageG).not.toBeNull();
  1508. expect(_pageGH).not.toBeNull();
  1509. expect(_pageGI).not.toBeNull();
  1510. await normalizeParentByPath('/norm_parent_by_path_G', rootUser);
  1511. const countG = await Page.count({ path: '/norm_parent_by_path_G' });
  1512. // -- check count
  1513. expect(countG).toBe(1);
  1514. const pageG = await Page.findById(_pageG._id);
  1515. const pageGH = await Page.findById(_pageGH._id);
  1516. const pageGI = await Page.findById(_pageGI._id);
  1517. // -- check existance
  1518. expect(pageG.path).toBe('/norm_parent_by_path_G');
  1519. expect(pageGH.path).toBe('/norm_parent_by_path_G/norm_parent_by_path_H');
  1520. expect(pageGI.path).toBe('/norm_parent_by_path_G/norm_parent_by_path_I');
  1521. // -- check parent
  1522. expect(pageG.parent).toStrictEqual(rootPage._id);
  1523. expect(pageGH.parent).toStrictEqual(pageG._id);
  1524. expect(pageGI.parent).toStrictEqual(pageG._id);
  1525. // -- check descendantCount
  1526. expect(pageG.descendantCount).toBe(2);
  1527. expect(pageGH.descendantCount).toBe(0);
  1528. expect(pageGI.descendantCount).toBe(0);
  1529. });
  1530. });
  1531. });