v5.migration.test.js 53 KB

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