v5.page.test.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. import mongoose from 'mongoose';
  2. import { getInstance } from '../setup-crowi';
  3. describe('Page', () => {
  4. let crowi;
  5. let Page;
  6. let Revision;
  7. let User;
  8. let Tag;
  9. let PageTagRelation;
  10. let Bookmark;
  11. let Comment;
  12. let ShareLink;
  13. let PageRedirect;
  14. let xssSpy;
  15. let rootPage;
  16. let dummyUser1;
  17. // pass unless the data is one of [false, 0, '', null, undefined, NaN]
  18. const expectAllToBeTruthy = (dataList) => {
  19. dataList.forEach((data, i) => {
  20. if (data == null) { console.log(`index: ${i}`) }
  21. expect(data).toBeTruthy();
  22. });
  23. };
  24. beforeAll(async() => {
  25. crowi = await getInstance();
  26. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  27. jest.restoreAllMocks();
  28. User = mongoose.model('User');
  29. Page = mongoose.model('Page');
  30. Revision = mongoose.model('Revision');
  31. Tag = mongoose.model('Tag');
  32. PageTagRelation = mongoose.model('PageTagRelation');
  33. Bookmark = mongoose.model('Bookmark');
  34. Comment = mongoose.model('Comment');
  35. ShareLink = mongoose.model('ShareLink');
  36. PageRedirect = mongoose.model('PageRedirect');
  37. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  38. rootPage = await Page.findOne({ path: '/' });
  39. const pageIdCreate1 = new mongoose.Types.ObjectId();
  40. const pageIdCreate2 = new mongoose.Types.ObjectId();
  41. const pageIdCreate3 = new mongoose.Types.ObjectId();
  42. const pageIdCreate4 = new mongoose.Types.ObjectId();
  43. /**
  44. * create
  45. * mc_ => model create
  46. * emp => empty => page with isEmpty: true
  47. * pub => public => GRANT_PUBLIC
  48. */
  49. await Page.insertMany([
  50. {
  51. _id: pageIdCreate1,
  52. path: '/v5_empty_create_4',
  53. grant: Page.GRANT_PUBLIC,
  54. parent: rootPage._id,
  55. isEmpty: true,
  56. },
  57. {
  58. path: '/v5_empty_create_4/v5_create_5',
  59. grant: Page.GRANT_PUBLIC,
  60. creator: dummyUser1,
  61. lastUpdateUser: dummyUser1._id,
  62. parent: pageIdCreate1,
  63. isEmpty: false,
  64. },
  65. {
  66. _id: pageIdCreate2,
  67. path: '/mc4_top/mc1_emp',
  68. grant: Page.GRANT_PUBLIC,
  69. creator: dummyUser1,
  70. lastUpdateUser: dummyUser1._id,
  71. parent: rootPage._id,
  72. isEmpty: true,
  73. },
  74. {
  75. path: '/mc4_top/mc1_emp/mc2_pub',
  76. grant: Page.GRANT_PUBLIC,
  77. creator: dummyUser1,
  78. lastUpdateUser: dummyUser1._id,
  79. parent: pageIdCreate2,
  80. isEmpty: false,
  81. },
  82. {
  83. path: '/mc5_top/mc3_awl',
  84. grant: Page.GRANT_RESTRICTED,
  85. creator: dummyUser1,
  86. lastUpdateUser: dummyUser1._id,
  87. isEmpty: false,
  88. },
  89. {
  90. _id: pageIdCreate3,
  91. path: '/mc4_top',
  92. grant: Page.GRANT_PUBLIC,
  93. creator: dummyUser1,
  94. lastUpdateUser: dummyUser1._id,
  95. isEmpty: false,
  96. parent: rootPage._id,
  97. descendantCount: 1,
  98. },
  99. {
  100. _id: pageIdCreate4,
  101. path: '/mc5_top',
  102. grant: Page.GRANT_PUBLIC,
  103. creator: dummyUser1,
  104. lastUpdateUser: dummyUser1._id,
  105. isEmpty: false,
  106. parent: rootPage._id,
  107. descendantCount: 0,
  108. },
  109. ]);
  110. /**
  111. * update
  112. * mup_ => model update
  113. * emp => empty => page with isEmpty: true
  114. * pub => public => GRANT_PUBLIC
  115. * awl => Anyone with the link => GRANT_RESTRICTED
  116. */
  117. const pageIdUpd1 = new mongoose.Types.ObjectId();
  118. const pageIdUpd2 = new mongoose.Types.ObjectId();
  119. const pageIdUpd3 = new mongoose.Types.ObjectId();
  120. const pageIdUpd4 = new mongoose.Types.ObjectId();
  121. const pageIdUpd5 = new mongoose.Types.ObjectId();
  122. const pageIdUpd6 = new mongoose.Types.ObjectId();
  123. const pageIdUpd7 = new mongoose.Types.ObjectId();
  124. const pageIdUpd8 = new mongoose.Types.ObjectId();
  125. const pageIdUpd9 = new mongoose.Types.ObjectId();
  126. const pageIdUpd10 = new mongoose.Types.ObjectId();
  127. const pageIdUpd11 = new mongoose.Types.ObjectId();
  128. const pageIdUpd12 = new mongoose.Types.ObjectId();
  129. await Page.insertMany([
  130. {
  131. _id: pageIdUpd1,
  132. path: '/mup13_top/mup1_emp',
  133. grant: Page.GRANT_PUBLIC,
  134. parent: pageIdUpd8._id,
  135. isEmpty: true,
  136. },
  137. {
  138. _id: pageIdUpd2,
  139. path: '/mup13_top/mup1_emp/mup2_pub',
  140. grant: Page.GRANT_PUBLIC,
  141. parent: pageIdUpd1._id,
  142. creator: dummyUser1,
  143. lastUpdateUser: dummyUser1._id,
  144. isEmpty: false,
  145. },
  146. {
  147. _id: pageIdUpd3,
  148. path: '/mup14_top/mup6_pub',
  149. grant: Page.GRANT_PUBLIC,
  150. creator: dummyUser1,
  151. lastUpdateUser: dummyUser1._id,
  152. parent: pageIdUpd9,
  153. isEmpty: false,
  154. descendantCount: 1,
  155. },
  156. {
  157. path: '/mup14_top/mup6_pub/mup7_pub',
  158. grant: Page.GRANT_PUBLIC,
  159. creator: dummyUser1,
  160. lastUpdateUser: dummyUser1._id,
  161. parent: pageIdUpd3,
  162. isEmpty: false,
  163. descendantCount: 0,
  164. },
  165. {
  166. _id: pageIdUpd4,
  167. path: '/mup15_top/mup8_pub',
  168. grant: Page.GRANT_PUBLIC,
  169. creator: dummyUser1,
  170. lastUpdateUser: dummyUser1._id,
  171. parent: pageIdUpd10._id,
  172. isEmpty: false,
  173. },
  174. {
  175. _id: pageIdUpd5,
  176. path: '/mup16_top/mup9_pub/mup10_pub/mup11_awl',
  177. grant: Page.GRANT_RESTRICTED,
  178. creator: dummyUser1,
  179. lastUpdateUser: dummyUser1._id,
  180. isEmpty: false,
  181. },
  182. {
  183. _id: pageIdUpd6,
  184. path: '/mup17_top/mup12_emp',
  185. isEmpty: true,
  186. parent: pageIdUpd12._id,
  187. },
  188. {
  189. _id: pageIdUpd7,
  190. path: '/mup17_top/mup12_emp',
  191. grant: Page.GRANT_RESTRICTED,
  192. creator: dummyUser1,
  193. lastUpdateUser: dummyUser1._id,
  194. isEmpty: false,
  195. },
  196. {
  197. _id: pageIdUpd8,
  198. path: '/mup13_top',
  199. grant: Page.GRANT_PUBLIC,
  200. creator: dummyUser1,
  201. lastUpdateUser: dummyUser1._id,
  202. isEmpty: false,
  203. parent: rootPage._id,
  204. descendantCount: 2,
  205. },
  206. {
  207. _id: pageIdUpd9,
  208. path: '/mup14_top',
  209. grant: Page.GRANT_PUBLIC,
  210. creator: dummyUser1,
  211. lastUpdateUser: dummyUser1._id,
  212. isEmpty: false,
  213. parent: rootPage._id,
  214. descendantCount: 2,
  215. },
  216. {
  217. _id: pageIdUpd10,
  218. path: '/mup15_top',
  219. grant: Page.GRANT_PUBLIC,
  220. creator: dummyUser1,
  221. lastUpdateUser: dummyUser1._id,
  222. isEmpty: false,
  223. parent: rootPage._id,
  224. descendantCount: 1,
  225. },
  226. {
  227. _id: pageIdUpd11,
  228. path: '/mup16_top',
  229. grant: Page.GRANT_PUBLIC,
  230. creator: dummyUser1,
  231. lastUpdateUser: dummyUser1._id,
  232. isEmpty: false,
  233. parent: rootPage._id,
  234. descendantCount: 0,
  235. },
  236. {
  237. _id: pageIdUpd12,
  238. path: '/mup17_top',
  239. grant: Page.GRANT_PUBLIC,
  240. creator: dummyUser1,
  241. lastUpdateUser: dummyUser1._id,
  242. isEmpty: false,
  243. parent: rootPage._id,
  244. descendantCount: 0,
  245. },
  246. ]);
  247. });
  248. describe('create', () => {
  249. test('Should create single page', async() => {
  250. const page = await Page.create('/v5_create1', 'create1', dummyUser1, {});
  251. expect(page).toBeTruthy();
  252. expect(page.parent).toStrictEqual(rootPage._id);
  253. });
  254. test('Should create empty-child and non-empty grandchild', async() => {
  255. const grandchildPage = await Page.create('/v5_empty_create2/v5_create_3', 'grandchild', dummyUser1, {});
  256. const childPage = await Page.findOne({ path: '/v5_empty_create2' });
  257. expect(childPage.isEmpty).toBe(true);
  258. expect(grandchildPage).toBeTruthy();
  259. expect(childPage).toBeTruthy();
  260. expect(childPage.parent).toStrictEqual(rootPage._id);
  261. expect(grandchildPage.parent).toStrictEqual(childPage._id);
  262. });
  263. test('Should create on empty page', async() => {
  264. const beforeCreatePage = await Page.findOne({ path: '/v5_empty_create_4' });
  265. expect(beforeCreatePage.isEmpty).toBe(true);
  266. const childPage = await Page.create('/v5_empty_create_4', 'body', dummyUser1, {});
  267. const grandchildPage = await Page.findOne({ parent: childPage._id });
  268. expect(childPage).toBeTruthy();
  269. expect(childPage.isEmpty).toBe(false);
  270. expect(childPage.revision.body).toBe('body');
  271. expect(grandchildPage).toBeTruthy();
  272. expect(childPage.parent).toStrictEqual(rootPage._id);
  273. expect(grandchildPage.parent).toStrictEqual(childPage._id);
  274. });
  275. describe('Creating a page using existing path', () => {
  276. test('with grant RESTRICTED should only create the page and change nothing else', async() => {
  277. const top = await Page.findOne({ path: '/mc4_top', descendantCount: 1 });
  278. const page1 = await Page.findOne({ path: '/mc4_top/mc1_emp' });
  279. const page2 = await Page.findOne({ path: '/mc4_top/mc1_emp/mc2_pub' });
  280. const count = await Page.count({ path: '/mc4_top/mc1_emp' });
  281. expectAllToBeTruthy([top, page1, page2]);
  282. expect(count).toBe(1);
  283. await Page.create('/mc4_top/mc1_emp', 'new body', dummyUser1, { grant: Page.GRANT_RESTRICTED });
  284. // AF => After Create
  285. const topAF = await Page.findOne({ _id: top._id });
  286. const page1AF = await Page.findOne({ _id: page1._id });
  287. const page2AF = await Page.findOne({ _id: page2._id });
  288. const countAF = await Page.count({ path: '/mc4_top/mc1_emp' });
  289. const newPage = await Page.find({ path: '/mc4_top/mc1_emp', grant: Page.GRANT_RESTRICTED });
  290. expectAllToBeTruthy([topAF, page1AF, page2AF, newPage]);
  291. expect(countAF).toBe(2);
  292. expect(topAF.descendantCount).toBe(1);
  293. });
  294. });
  295. describe('Creating a page under a page with grant RESTRICTED', () => {
  296. test('will create a new empty page with the same path as the grant RESTRECTED page and become a parent', async() => {
  297. const top = await Page.findOne({ path: '/mc5_top' });
  298. const page1 = await Page.findOne({ path: '/mc5_top/mc3_awl', grant: Page.GRANT_RESTRICTED });
  299. const count = await Page.count({ path: '/mc5_top/mc3_awl' });
  300. expectAllToBeTruthy([top, page1]);
  301. expect(count).toBe(1);
  302. await Page.create('/mc5_top/mc3_awl/mc4_pub', 'new body', dummyUser1, { grant: Page.GRANT_PUBLIC });
  303. // AF => After Create
  304. const topAF = await Page.findOne({ _id: top._id });
  305. const page1AF = await Page.findOne({ path: '/mc5_top/mc3_awl', grant: Page.GRANT_RESTRICTED });
  306. const countAF = await Page.count({ path: '/mc5_top/mc3_awl' });
  307. const createdPage = await Page.findOne({ path: '/mc5_top/mc3_awl/mc4_pub', grant: Page.GRANT_PUBLIC });
  308. const createdPageParent = await Page.findOne({ path: '/mc5_top/mc3_awl', grant: Page.GRANT_PUBLIC, isEmpty: true });
  309. expectAllToBeTruthy([page1AF, createdPageParent, createdPage]);
  310. expect(countAF).toBe(2);
  311. expect(createdPage.parent).toStrictEqual(createdPageParent._id);
  312. expect(createdPageParent.parent).toStrictEqual(topAF._id);
  313. expect(topAF.descendantCount).toStrictEqual(1);
  314. });
  315. });
  316. });
  317. describe('update', () => {
  318. describe('Changing grant from PUBLIC to RESTRICTED of', () => {
  319. test('an only-child page will delete its empty parent page', async() => {
  320. const top = await Page.findOne({ path: '/mup13_top', descendantCount: 2 });
  321. const page1 = await Page.findOne({ path: '/mup13_top/mup1_emp', isEmpty: true });
  322. const page2 = await Page.findOne({ path: '/mup13_top/mup1_emp/mup2_pub' });
  323. const options = { grant: 2, grantUserGroupId: null };
  324. expectAllToBeTruthy([top, page1, page2]);
  325. await Page.updatePage(page2, 'newRevisionBody', 'oldRevisionBody', dummyUser1, options);
  326. // AU => After Update
  327. const topAF = await Page.findOne({ _id: top._id });
  328. const page1AU = await Page.findOne({ _id: page1._id });
  329. const page2AU = await Page.findOne({ _id: page2._id });
  330. expect(page2AU).toBeTruthy();
  331. expect(page1AU).toBeNull();
  332. expect(topAF.descendantCount).toBe(1);
  333. });
  334. test('a page that has children will create an empty page with the same path and it becomes a new parent', async() => {
  335. const top = await Page.findOne({ path: '/mup14_top', descendantCount: 2 });
  336. const page1 = await Page.findOne({ path: '/mup14_top/mup6_pub', grant: Page.GRANT_PUBLIC });
  337. const page2 = await Page.findOne({ path: '/mup14_top/mup6_pub/mup7_pub', grant: Page.GRANT_PUBLIC });
  338. const count = await Page.count({ path: '/mup14_top/mup6_pub' });
  339. expectAllToBeTruthy([top, page1, page2]);
  340. expect(count).toBe(1);
  341. await Page.updatePage(page1, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: 2 });
  342. // AU => After Update
  343. const topAF = await Page.findOne({ _id: top._id });
  344. const page1AF = await Page.findOne({ _id: page1._id });
  345. const page2AF = await Page.findOne({ _id: page2._id });
  346. const newlyCreatedPage = await Page.findOne({ _id: { $ne: page1._id }, path: '/mup14_top/mup6_pub' });
  347. const countAF = await Page.count({ path: '/mup14_top/mup6_pub' });
  348. expectAllToBeTruthy([page1AF, page2AF, newlyCreatedPage]);
  349. expect(countAF).toBe(2);
  350. expect(page1AF.grant).toBe(Page.GRANT_RESTRICTED);
  351. expect(page1AF.parent).toBeNull();
  352. expect(page2AF.grant).toBe(Page.GRANT_PUBLIC);
  353. expect(page2AF.parent).toStrictEqual(newlyCreatedPage._id);
  354. expect(newlyCreatedPage.isEmpty).toBe(true);
  355. expect(newlyCreatedPage.grant).toBe(Page.GRANT_PUBLIC);
  356. expect(newlyCreatedPage.parent).toStrictEqual(top._id);
  357. expect(topAF.descendantCount).toBe(1);
  358. });
  359. test('of a leaf page will NOT have an empty page with the same path', async() => {
  360. const top = await Page.findOne({ path: '/mup15_top', descendantCount: 1 });
  361. const page = await Page.findOne({ path: '/mup15_top/mup8_pub', grant: Page.GRANT_PUBLIC });
  362. const count = await Page.count({ path: '/mup15_top/mup8_pub' });
  363. expectAllToBeTruthy([top, page]);
  364. expect(count).toBe(1);
  365. await Page.updatePage(page, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: 2 });
  366. // AU => After Update
  367. const topAF = await Page.findOne({ _id: top._id });
  368. const pageAF = await Page.findOne({ _id: page._id });
  369. const emptyPage = await Page.findOne({ path: '/mup15_top/mup8_pub', isEmpty: true });
  370. const countAF = await Page.count({ path: '/mup15_top/mup8_pub' });
  371. expectAllToBeTruthy([pageAF]);
  372. expect(countAF).toBe(1);
  373. expect(emptyPage).toBeNull();
  374. expect(pageAF.grant).toBe(Page.GRANT_RESTRICTED);
  375. expect(topAF.descendantCount).toBe(0);
  376. });
  377. });
  378. describe('Changing grant from RESTRICTED to PUBLIC of', () => {
  379. test('a page will create ancestors if they do not exist', async() => {
  380. const top = await Page.findOne({ path: '/mup16_top' });
  381. const page = await Page.findOne({ path: '/mup16_top/mup9_pub/mup10_pub/mup11_awl', grant: Page.GRANT_RESTRICTED });
  382. const page1 = await Page.findOne({ path: '/mup16_top/mup9_pub' });
  383. const page2 = await Page.findOne({ path: '/mup16_top/mup9_pub/mup10_pub' });
  384. expectAllToBeTruthy([top, page]);
  385. expect(page1).toBeNull();
  386. expect(page2).toBeNull();
  387. await Page.updatePage(page, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: 1 });
  388. const topAF = await Page.findOne({ path: '/mup16_top' });
  389. const pageAF = await Page.findOne({ _id: page._id });
  390. const page1AF = await Page.findOne({ path: '/mup16_top/mup9_pub' });
  391. const page2AF = await Page.findOne({ path: '/mup16_top/mup9_pub/mup10_pub' });
  392. expectAllToBeTruthy([pageAF, page1AF, page2AF]);
  393. expect(pageAF.grant).toBe(Page.GRANT_PUBLIC);
  394. expect(pageAF.parent).toStrictEqual(page2AF._id);
  395. expect(page1AF.isEmpty).toBe(true);
  396. expect(page1AF.parent).toStrictEqual(top._id);
  397. expect(page2AF.isEmpty).toBe(true);
  398. expect(page2AF.parent).toStrictEqual(page1AF._id);
  399. expect(topAF.descendantCount).toBe(1);
  400. });
  401. test('a page will replace an empty page with the same path if any', async() => {
  402. const top = await Page.findOne({ path: '/mup17_top', descendantCount: 0 });
  403. const page1 = await Page.findOne({ path: '/mup17_top/mup12_emp', isEmpty: true });
  404. const page2 = await Page.findOne({ path: '/mup17_top/mup12_emp', grant: Page.GRANT_RESTRICTED, isEmpty: false });
  405. expectAllToBeTruthy([top, page1, page2]);
  406. await Page.updatePage(page2, 'newRevisionBody', 'oldRevisionBody', dummyUser1, { grant: 1 });
  407. const topAF = await Page.findOne({ _id: top._id });
  408. const page1AF = await Page.findOne({ _id: page1._id });
  409. const page2AF = await Page.findOne({ _id: page2._id });
  410. expect(page1AF).toBeNull();
  411. expect(page2AF).toBeTruthy();
  412. expect(page2AF.grant).toBe(Page.GRANT_PUBLIC);
  413. expect(page2AF.parent).toStrictEqual(topAF._id);
  414. expect(topAF.descendantCount).toBe(1);
  415. });
  416. });
  417. });
  418. });