v5.non-public-page.test.ts 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379
  1. /* eslint-disable no-unused-vars */
  2. import {
  3. GroupType,
  4. type IGrantedGroup,
  5. type IPage,
  6. type IRevision,
  7. } from '@growi/core';
  8. import mongoose from 'mongoose';
  9. import { ExternalGroupProviderType } from '../../../src/features/external-user-group/interfaces/external-user-group';
  10. import ExternalUserGroup from '../../../src/features/external-user-group/server/models/external-user-group';
  11. import ExternalUserGroupRelation from '../../../src/features/external-user-group/server/models/external-user-group-relation';
  12. import type { IPageTagRelation } from '../../../src/interfaces/page-tag-relation';
  13. import type Crowi from '../../../src/server/crowi';
  14. import type { PageDocument, PageModel } from '../../../src/server/models/page';
  15. import PageTagRelation from '../../../src/server/models/page-tag-relation';
  16. import type {
  17. IRevisionDocument,
  18. IRevisionModel,
  19. } from '../../../src/server/models/revision';
  20. import Tag from '../../../src/server/models/tag';
  21. import UserGroup from '../../../src/server/models/user-group';
  22. import UserGroupRelation from '../../../src/server/models/user-group-relation';
  23. import { generalXssFilter } from '../../../src/services/general-xss-filter';
  24. import { getInstance } from '../setup-crowi';
  25. describe('PageService page operations with non-public pages', () => {
  26. // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
  27. let dummyUser1;
  28. // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
  29. let dummyUser2;
  30. // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
  31. let npDummyUser1;
  32. // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
  33. let npDummyUser2;
  34. // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
  35. let npDummyUser3;
  36. let groupIdIsolate: mongoose.Types.ObjectId;
  37. let groupIdA: mongoose.Types.ObjectId;
  38. let groupIdB: mongoose.Types.ObjectId;
  39. let groupIdC: mongoose.Types.ObjectId;
  40. let externalGroupIdIsolate: mongoose.Types.ObjectId;
  41. let externalGroupIdA: mongoose.Types.ObjectId;
  42. let externalGroupIdB: mongoose.Types.ObjectId;
  43. let externalGroupIdC: mongoose.Types.ObjectId;
  44. let crowi: Crowi;
  45. let Page: PageModel;
  46. let Revision: IRevisionModel;
  47. // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
  48. let User;
  49. let generalXssFilterProcessSpy: jest.SpyInstance;
  50. let rootPage: PageDocument;
  51. /**
  52. * Rename
  53. */
  54. const pageIdRename1 = new mongoose.Types.ObjectId();
  55. const pageIdRename2 = new mongoose.Types.ObjectId();
  56. const pageIdRename3 = new mongoose.Types.ObjectId();
  57. const pageIdRename4 = new mongoose.Types.ObjectId();
  58. const pageIdRename5 = new mongoose.Types.ObjectId();
  59. const pageIdRename6 = new mongoose.Types.ObjectId();
  60. const pageIdRename7 = new mongoose.Types.ObjectId();
  61. const pageIdRename8 = new mongoose.Types.ObjectId();
  62. const pageIdRename9 = new mongoose.Types.ObjectId();
  63. /**
  64. * Duplicate
  65. */
  66. // page id
  67. const pageIdDuplicate1 = new mongoose.Types.ObjectId();
  68. const pageIdDuplicate2 = new mongoose.Types.ObjectId();
  69. const pageIdDuplicate3 = new mongoose.Types.ObjectId();
  70. const pageIdDuplicate4 = new mongoose.Types.ObjectId();
  71. const pageIdDuplicate5 = new mongoose.Types.ObjectId();
  72. const pageIdDuplicate6 = new mongoose.Types.ObjectId();
  73. const pageIdDuplicate7 = new mongoose.Types.ObjectId();
  74. const pageIdDuplicate8 = new mongoose.Types.ObjectId();
  75. const pageIdDuplicate9 = new mongoose.Types.ObjectId();
  76. // revision id
  77. const revisionIdDuplicate1 = new mongoose.Types.ObjectId();
  78. const revisionIdDuplicate2 = new mongoose.Types.ObjectId();
  79. const revisionIdDuplicate3 = new mongoose.Types.ObjectId();
  80. const revisionIdDuplicate4 = new mongoose.Types.ObjectId();
  81. const revisionIdDuplicate5 = new mongoose.Types.ObjectId();
  82. const revisionIdDuplicate6 = new mongoose.Types.ObjectId();
  83. const revisionIdDuplicate7 = new mongoose.Types.ObjectId();
  84. const revisionIdDuplicate8 = new mongoose.Types.ObjectId();
  85. const revisionIdDuplicate9 = new mongoose.Types.ObjectId();
  86. /**
  87. * Revert
  88. */
  89. // page id
  90. const pageIdRevert1 = new mongoose.Types.ObjectId();
  91. const pageIdRevert2 = new mongoose.Types.ObjectId();
  92. const pageIdRevert3 = new mongoose.Types.ObjectId();
  93. const pageIdRevert4 = new mongoose.Types.ObjectId();
  94. const pageIdRevert5 = new mongoose.Types.ObjectId();
  95. const pageIdRevert6 = new mongoose.Types.ObjectId();
  96. // revision id
  97. const revisionIdRevert1 = new mongoose.Types.ObjectId();
  98. const revisionIdRevert2 = new mongoose.Types.ObjectId();
  99. const revisionIdRevert3 = new mongoose.Types.ObjectId();
  100. const revisionIdRevert4 = new mongoose.Types.ObjectId();
  101. const revisionIdRevert5 = new mongoose.Types.ObjectId();
  102. const revisionIdRevert6 = new mongoose.Types.ObjectId();
  103. // tag id
  104. const tagIdRevert1 = new mongoose.Types.ObjectId();
  105. const tagIdRevert2 = new mongoose.Types.ObjectId();
  106. const create = async (path, body, user, options = {}) => {
  107. const mockedCreateSubOperation = jest
  108. .spyOn(crowi.pageService, 'createSubOperation')
  109. .mockReturnValue(null);
  110. const createdPage = await crowi.pageService.create(
  111. path,
  112. body,
  113. user,
  114. options,
  115. );
  116. const argsForCreateSubOperation = mockedCreateSubOperation.mock.calls[0];
  117. mockedCreateSubOperation.mockRestore();
  118. await crowi.pageService.createSubOperation(
  119. ...(argsForCreateSubOperation as Parameters<
  120. typeof crowi.pageService.createSubOperation
  121. >),
  122. );
  123. return createdPage;
  124. };
  125. // normalize for result comparison
  126. const normalizeGrantedGroups = (
  127. grantedGroups: IGrantedGroup[] | undefined,
  128. ) => {
  129. return grantedGroups?.map((group) => {
  130. const itemId =
  131. typeof group.item === 'string' ? group.item : group.item._id;
  132. return { item: itemId, type: group.type };
  133. });
  134. };
  135. beforeAll(async () => {
  136. crowi = await getInstance();
  137. await crowi.configManager.updateConfig('app:isV5Compatible', true);
  138. User = mongoose.model('User');
  139. Page = mongoose.model<IPage, PageModel>('Page');
  140. Revision = mongoose.model<IRevision, IRevisionModel>('Revision');
  141. /*
  142. * Common
  143. */
  144. const npUserId1 = new mongoose.Types.ObjectId();
  145. const npUserId2 = new mongoose.Types.ObjectId();
  146. const npUserId3 = new mongoose.Types.ObjectId();
  147. await User.insertMany([
  148. {
  149. _id: npUserId1,
  150. name: 'npUser1',
  151. username: 'npUser1',
  152. email: 'npUser1@example.com',
  153. },
  154. {
  155. _id: npUserId2,
  156. name: 'npUser2',
  157. username: 'npUser2',
  158. email: 'npUser2@example.com',
  159. },
  160. {
  161. _id: npUserId3,
  162. name: 'npUser3',
  163. username: 'npUser3',
  164. email: 'npUser3@example.com',
  165. },
  166. ]);
  167. groupIdIsolate = new mongoose.Types.ObjectId();
  168. groupIdA = new mongoose.Types.ObjectId();
  169. groupIdB = new mongoose.Types.ObjectId();
  170. groupIdC = new mongoose.Types.ObjectId();
  171. await UserGroup.insertMany([
  172. {
  173. _id: groupIdIsolate,
  174. name: 'np_groupIsolate',
  175. },
  176. {
  177. _id: groupIdA,
  178. name: 'np_groupA',
  179. },
  180. {
  181. _id: groupIdB,
  182. name: 'np_groupB',
  183. parent: groupIdA,
  184. },
  185. {
  186. _id: groupIdC,
  187. name: 'np_groupC',
  188. parent: groupIdB,
  189. },
  190. ]);
  191. await UserGroupRelation.insertMany([
  192. {
  193. relatedGroup: groupIdIsolate,
  194. relatedUser: npUserId1,
  195. createdAt: new Date(),
  196. },
  197. {
  198. relatedGroup: groupIdIsolate,
  199. relatedUser: npUserId2,
  200. createdAt: new Date(),
  201. },
  202. {
  203. relatedGroup: groupIdA,
  204. relatedUser: npUserId1,
  205. createdAt: new Date(),
  206. },
  207. {
  208. relatedGroup: groupIdA,
  209. relatedUser: npUserId2,
  210. createdAt: new Date(),
  211. },
  212. {
  213. relatedGroup: groupIdA,
  214. relatedUser: npUserId3,
  215. createdAt: new Date(),
  216. },
  217. {
  218. relatedGroup: groupIdB,
  219. relatedUser: npUserId2,
  220. createdAt: new Date(),
  221. },
  222. {
  223. relatedGroup: groupIdB,
  224. relatedUser: npUserId3,
  225. createdAt: new Date(),
  226. },
  227. {
  228. relatedGroup: groupIdC,
  229. relatedUser: npUserId3,
  230. createdAt: new Date(),
  231. },
  232. ]);
  233. // Insert ExternalUserGroups with the same group structure as UserGroups
  234. // Use to test
  235. // - ExternalUserGroup
  236. // - Case of multiple grantedGroups for Page
  237. externalGroupIdIsolate = new mongoose.Types.ObjectId();
  238. externalGroupIdA = new mongoose.Types.ObjectId();
  239. externalGroupIdB = new mongoose.Types.ObjectId();
  240. externalGroupIdC = new mongoose.Types.ObjectId();
  241. await ExternalUserGroup.insertMany([
  242. {
  243. _id: externalGroupIdIsolate,
  244. name: 'np_externalGroupIsolate',
  245. externalId: 'np_externalGroupIsolate',
  246. provider: ExternalGroupProviderType.ldap,
  247. },
  248. {
  249. _id: externalGroupIdA,
  250. name: 'np_externalGroupA',
  251. externalId: 'np_externalGroupA',
  252. provider: ExternalGroupProviderType.ldap,
  253. },
  254. {
  255. _id: externalGroupIdB,
  256. name: 'np_externalGroupB',
  257. externalId: 'np_externalGroupB',
  258. parent: externalGroupIdA,
  259. provider: ExternalGroupProviderType.ldap,
  260. },
  261. {
  262. _id: externalGroupIdC,
  263. name: 'np_externalGroupC',
  264. externalId: 'np_externalGroupC',
  265. parent: externalGroupIdB,
  266. provider: ExternalGroupProviderType.ldap,
  267. },
  268. ]);
  269. await ExternalUserGroupRelation.insertMany([
  270. {
  271. relatedGroup: externalGroupIdIsolate,
  272. relatedUser: npUserId1,
  273. createdAt: new Date(),
  274. },
  275. {
  276. relatedGroup: externalGroupIdIsolate,
  277. relatedUser: npUserId2,
  278. createdAt: new Date(),
  279. },
  280. {
  281. relatedGroup: externalGroupIdA,
  282. relatedUser: npUserId1,
  283. createdAt: new Date(),
  284. },
  285. {
  286. relatedGroup: externalGroupIdA,
  287. relatedUser: npUserId2,
  288. createdAt: new Date(),
  289. },
  290. {
  291. relatedGroup: externalGroupIdA,
  292. relatedUser: npUserId3,
  293. createdAt: new Date(),
  294. },
  295. {
  296. relatedGroup: externalGroupIdB,
  297. relatedUser: npUserId2,
  298. createdAt: new Date(),
  299. },
  300. {
  301. relatedGroup: externalGroupIdB,
  302. relatedUser: npUserId3,
  303. createdAt: new Date(),
  304. },
  305. {
  306. relatedGroup: externalGroupIdC,
  307. relatedUser: npUserId3,
  308. createdAt: new Date(),
  309. },
  310. ]);
  311. generalXssFilterProcessSpy = jest.spyOn(generalXssFilter, 'process');
  312. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  313. dummyUser2 = await User.findOne({ username: 'v5DummyUser2' });
  314. npDummyUser1 = await User.findOne({ username: 'npUser1' });
  315. npDummyUser2 = await User.findOne({ username: 'npUser2' });
  316. npDummyUser3 = await User.findOne({ username: 'npUser3' });
  317. rootPage = (await Page.findOne({ path: '/' }))!;
  318. if (rootPage == null) {
  319. const pages = await Page.insertMany([
  320. { path: '/', grant: Page.GRANT_PUBLIC },
  321. ]);
  322. rootPage = pages[0];
  323. }
  324. /**
  325. * create
  326. * mc_ => model create
  327. * emp => empty => page with isEmpty: true
  328. * pub => public => GRANT_PUBLIC
  329. */
  330. const pageIdCreate1 = new mongoose.Types.ObjectId();
  331. const pageIdCreate2 = new mongoose.Types.ObjectId();
  332. const pageIdCreate3 = new mongoose.Types.ObjectId();
  333. await Page.insertMany([
  334. {
  335. _id: pageIdCreate1,
  336. path: '/mc4_top/mc1_emp',
  337. grant: Page.GRANT_PUBLIC,
  338. creator: dummyUser1,
  339. lastUpdateUser: dummyUser1._id,
  340. parent: rootPage._id,
  341. isEmpty: true,
  342. },
  343. {
  344. path: '/mc4_top/mc1_emp/mc2_pub',
  345. grant: Page.GRANT_PUBLIC,
  346. creator: dummyUser1,
  347. lastUpdateUser: dummyUser1._id,
  348. parent: pageIdCreate1,
  349. isEmpty: false,
  350. },
  351. {
  352. path: '/mc5_top/mc3_awl',
  353. grant: Page.GRANT_RESTRICTED,
  354. creator: dummyUser1,
  355. lastUpdateUser: dummyUser1._id,
  356. isEmpty: false,
  357. },
  358. {
  359. _id: pageIdCreate2,
  360. path: '/mc4_top',
  361. grant: Page.GRANT_PUBLIC,
  362. creator: dummyUser1,
  363. lastUpdateUser: dummyUser1._id,
  364. isEmpty: false,
  365. parent: rootPage._id,
  366. descendantCount: 1,
  367. },
  368. {
  369. _id: pageIdCreate3,
  370. path: '/mc5_top',
  371. grant: Page.GRANT_PUBLIC,
  372. creator: dummyUser1,
  373. lastUpdateUser: dummyUser1._id,
  374. isEmpty: false,
  375. parent: rootPage._id,
  376. descendantCount: 0,
  377. },
  378. {
  379. path: '/mc6_top',
  380. grant: Page.GRANT_USER_GROUP,
  381. creator: dummyUser1,
  382. lastUpdateUser: dummyUser1._id,
  383. isEmpty: false,
  384. parent: rootPage._id,
  385. descendantCount: 0,
  386. grantedGroups: [
  387. { item: groupIdIsolate, type: GroupType.userGroup },
  388. { item: groupIdB, type: GroupType.userGroup },
  389. ],
  390. },
  391. ]);
  392. /**
  393. * create
  394. * mc_ => model create
  395. * emp => empty => page with isEmpty: true
  396. * pub => public => GRANT_PUBLIC
  397. */
  398. const pageIdCreateBySystem1 = new mongoose.Types.ObjectId();
  399. const pageIdCreateBySystem2 = new mongoose.Types.ObjectId();
  400. const pageIdCreateBySystem3 = new mongoose.Types.ObjectId();
  401. await Page.insertMany([
  402. {
  403. _id: pageIdCreateBySystem1,
  404. path: '/mc4_top_by_system/mc1_emp_by_system',
  405. grant: Page.GRANT_PUBLIC,
  406. creator: dummyUser1,
  407. lastUpdateUser: dummyUser1._id,
  408. parent: rootPage._id,
  409. isEmpty: true,
  410. },
  411. {
  412. path: '/mc4_top_by_system/mc1_emp_by_system/mc2_pub_by_system',
  413. grant: Page.GRANT_PUBLIC,
  414. creator: dummyUser1,
  415. lastUpdateUser: dummyUser1._id,
  416. parent: pageIdCreateBySystem1,
  417. isEmpty: false,
  418. },
  419. {
  420. path: '/mc5_top_by_system/mc3_awl_by_system',
  421. grant: Page.GRANT_RESTRICTED,
  422. creator: dummyUser1,
  423. lastUpdateUser: dummyUser1._id,
  424. isEmpty: false,
  425. },
  426. {
  427. _id: pageIdCreateBySystem2,
  428. path: '/mc4_top_by_system',
  429. grant: Page.GRANT_PUBLIC,
  430. creator: dummyUser1,
  431. lastUpdateUser: dummyUser1._id,
  432. isEmpty: false,
  433. parent: rootPage._id,
  434. descendantCount: 1,
  435. },
  436. {
  437. _id: pageIdCreateBySystem3,
  438. path: '/mc5_top_by_system',
  439. grant: Page.GRANT_PUBLIC,
  440. creator: dummyUser1,
  441. lastUpdateUser: dummyUser1._id,
  442. isEmpty: false,
  443. parent: rootPage._id,
  444. descendantCount: 0,
  445. },
  446. ]);
  447. /*
  448. * Rename
  449. */
  450. await Page.insertMany([
  451. {
  452. _id: pageIdRename1,
  453. path: '/np_rename1_destination',
  454. grant: Page.GRANT_PUBLIC,
  455. creator: dummyUser1._id,
  456. lastUpdateUser: dummyUser1._id,
  457. parent: rootPage._id,
  458. },
  459. {
  460. _id: pageIdRename2,
  461. path: '/np_rename2',
  462. grant: Page.GRANT_USER_GROUP,
  463. grantedGroups: [
  464. { item: groupIdB, type: GroupType.userGroup },
  465. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  466. ],
  467. creator: npDummyUser2._id,
  468. lastUpdateUser: npDummyUser2._id,
  469. parent: rootPage._id,
  470. },
  471. {
  472. _id: pageIdRename3,
  473. path: '/np_rename2/np_rename3',
  474. grant: Page.GRANT_USER_GROUP,
  475. grantedGroups: [
  476. { item: groupIdC, type: GroupType.userGroup },
  477. { item: externalGroupIdC, type: GroupType.externalUserGroup },
  478. ],
  479. creator: npDummyUser3._id,
  480. lastUpdateUser: npDummyUser3._id,
  481. parent: pageIdRename2._id,
  482. },
  483. {
  484. _id: pageIdRename4,
  485. path: '/np_rename4_destination',
  486. grant: Page.GRANT_USER_GROUP,
  487. grantedGroups: [
  488. { item: groupIdIsolate, type: GroupType.userGroup },
  489. { item: externalGroupIdIsolate, type: GroupType.externalUserGroup },
  490. ],
  491. creator: npDummyUser3._id,
  492. lastUpdateUser: npDummyUser3._id,
  493. parent: rootPage._id,
  494. },
  495. {
  496. _id: pageIdRename5,
  497. path: '/np_rename5',
  498. grant: Page.GRANT_USER_GROUP,
  499. grantedGroups: [
  500. { item: groupIdB, type: GroupType.userGroup },
  501. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  502. ],
  503. creator: npDummyUser2._id,
  504. lastUpdateUser: npDummyUser2._id,
  505. parent: rootPage._id,
  506. },
  507. {
  508. _id: pageIdRename6,
  509. path: '/np_rename5/np_rename6',
  510. grant: Page.GRANT_USER_GROUP,
  511. grantedGroups: [
  512. { item: groupIdB, type: GroupType.userGroup },
  513. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  514. ],
  515. creator: npDummyUser2._id,
  516. lastUpdateUser: npDummyUser2._id,
  517. parent: pageIdRename5,
  518. },
  519. {
  520. _id: pageIdRename7,
  521. path: '/np_rename7_destination',
  522. grant: Page.GRANT_USER_GROUP,
  523. grantedGroups: [
  524. { item: groupIdIsolate, type: GroupType.userGroup },
  525. { item: externalGroupIdIsolate, type: GroupType.externalUserGroup },
  526. ],
  527. creator: npDummyUser2._id,
  528. lastUpdateUser: npDummyUser2._id,
  529. parent: pageIdRename5,
  530. },
  531. {
  532. _id: pageIdRename8,
  533. path: '/np_rename8',
  534. grant: Page.GRANT_RESTRICTED,
  535. creator: dummyUser1._id,
  536. lastUpdateUser: dummyUser1._id,
  537. },
  538. {
  539. _id: pageIdRename9,
  540. path: '/np_rename8/np_rename9',
  541. grant: Page.GRANT_RESTRICTED,
  542. creator: dummyUser2._id,
  543. lastUpdateUser: dummyUser2._id,
  544. },
  545. ]);
  546. /*
  547. * Duplicate
  548. */
  549. await Page.insertMany([
  550. {
  551. _id: pageIdDuplicate1,
  552. path: '/np_duplicate1',
  553. grant: Page.GRANT_RESTRICTED,
  554. creator: dummyUser1._id,
  555. lastUpdateUser: dummyUser1._id,
  556. revision: revisionIdDuplicate1,
  557. },
  558. {
  559. _id: pageIdDuplicate2,
  560. path: '/np_duplicate2',
  561. grant: Page.GRANT_USER_GROUP,
  562. grantedGroups: [
  563. { item: groupIdA, type: GroupType.userGroup },
  564. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  565. ],
  566. creator: npDummyUser1._id,
  567. lastUpdateUser: npDummyUser1._id,
  568. revision: revisionIdDuplicate2,
  569. parent: rootPage._id,
  570. },
  571. {
  572. _id: pageIdDuplicate3,
  573. path: '/np_duplicate2/np_duplicate3',
  574. grant: Page.GRANT_USER_GROUP,
  575. grantedGroups: [
  576. { item: groupIdB, type: GroupType.userGroup },
  577. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  578. ],
  579. creator: npDummyUser2._id,
  580. lastUpdateUser: npDummyUser2._id,
  581. revision: revisionIdDuplicate3,
  582. parent: pageIdDuplicate2,
  583. },
  584. {
  585. _id: pageIdDuplicate4,
  586. path: '/np_duplicate4',
  587. grant: Page.GRANT_PUBLIC,
  588. creator: npDummyUser1._id,
  589. lastUpdateUser: npDummyUser1._id,
  590. revision: revisionIdDuplicate4,
  591. parent: rootPage._id,
  592. },
  593. {
  594. _id: pageIdDuplicate5,
  595. path: '/np_duplicate4/np_duplicate5',
  596. grant: Page.GRANT_RESTRICTED,
  597. creator: npDummyUser1._id,
  598. lastUpdateUser: npDummyUser1._id,
  599. revision: revisionIdDuplicate5,
  600. },
  601. {
  602. _id: pageIdDuplicate6,
  603. path: '/np_duplicate4/np_duplicate6',
  604. grant: Page.GRANT_PUBLIC,
  605. creator: npDummyUser1._id,
  606. lastUpdateUser: npDummyUser1._id,
  607. parent: pageIdDuplicate4,
  608. revision: revisionIdDuplicate6,
  609. },
  610. {
  611. _id: pageIdDuplicate7,
  612. path: '/np_duplicate7',
  613. grant: Page.GRANT_USER_GROUP,
  614. creator: npDummyUser1._id,
  615. lastUpdateUser: npDummyUser1._id,
  616. parent: rootPage._id,
  617. revision: revisionIdDuplicate7,
  618. grantedGroups: [
  619. { item: groupIdA, type: GroupType.userGroup },
  620. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  621. { item: groupIdB, type: GroupType.userGroup },
  622. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  623. ],
  624. },
  625. {
  626. _id: pageIdDuplicate8,
  627. path: '/np_duplicate7/np_duplicate8',
  628. grant: Page.GRANT_USER_GROUP,
  629. creator: npDummyUser3._id,
  630. lastUpdateUser: npDummyUser3._id,
  631. parent: pageIdDuplicate7,
  632. revision: revisionIdDuplicate8,
  633. grantedGroups: [
  634. { item: groupIdC, type: GroupType.userGroup },
  635. { item: externalGroupIdC, type: GroupType.externalUserGroup },
  636. ],
  637. },
  638. {
  639. _id: pageIdDuplicate9,
  640. path: '/np_duplicate7/np_duplicate9',
  641. grant: Page.GRANT_OWNER,
  642. creator: npDummyUser2._id,
  643. lastUpdateUser: npDummyUser2._id,
  644. parent: pageIdDuplicate7,
  645. revision: revisionIdDuplicate9,
  646. grantedUsers: [npDummyUser2._id],
  647. },
  648. ]);
  649. await Revision.insertMany([
  650. {
  651. _id: revisionIdDuplicate1,
  652. body: 'np_duplicate1',
  653. format: 'markdown',
  654. pageId: pageIdDuplicate1,
  655. author: npDummyUser1._id,
  656. },
  657. {
  658. _id: revisionIdDuplicate2,
  659. body: 'np_duplicate2',
  660. format: 'markdown',
  661. pageId: pageIdDuplicate2,
  662. author: npDummyUser2._id,
  663. },
  664. {
  665. _id: revisionIdDuplicate3,
  666. body: 'np_duplicate3',
  667. format: 'markdown',
  668. pageId: pageIdDuplicate3,
  669. author: npDummyUser2._id,
  670. },
  671. {
  672. _id: revisionIdDuplicate4,
  673. body: 'np_duplicate4',
  674. format: 'markdown',
  675. pageId: pageIdDuplicate4,
  676. author: npDummyUser2._id,
  677. },
  678. {
  679. _id: revisionIdDuplicate5,
  680. body: 'np_duplicate5',
  681. format: 'markdown',
  682. pageId: pageIdDuplicate5,
  683. author: npDummyUser2._id,
  684. },
  685. {
  686. _id: revisionIdDuplicate6,
  687. body: 'np_duplicate6',
  688. format: 'markdown',
  689. pageId: pageIdDuplicate6,
  690. author: npDummyUser1._id,
  691. },
  692. {
  693. _id: revisionIdDuplicate7,
  694. body: 'np_duplicate7',
  695. format: 'markdown',
  696. pageId: pageIdDuplicate7,
  697. author: npDummyUser1._id,
  698. },
  699. {
  700. _id: revisionIdDuplicate8,
  701. body: 'np_duplicate8',
  702. format: 'markdown',
  703. pageId: pageIdDuplicate8,
  704. author: npDummyUser3._id,
  705. },
  706. {
  707. _id: revisionIdDuplicate9,
  708. body: 'np_duplicate9',
  709. format: 'markdown',
  710. pageId: pageIdDuplicate9,
  711. author: npDummyUser2._id,
  712. },
  713. ]);
  714. /**
  715. * Delete
  716. */
  717. const pageIdDelete1 = new mongoose.Types.ObjectId();
  718. const pageIdDelete2 = new mongoose.Types.ObjectId();
  719. const pageIdDelete3 = new mongoose.Types.ObjectId();
  720. const pageIdDelete4 = new mongoose.Types.ObjectId();
  721. await Page.insertMany([
  722. {
  723. _id: pageIdDelete1,
  724. path: '/npdel1_awl',
  725. grant: Page.GRANT_RESTRICTED,
  726. status: Page.STATUS_PUBLISHED,
  727. isEmpty: false,
  728. },
  729. {
  730. _id: pageIdDelete2,
  731. path: '/npdel2_ug',
  732. grant: Page.GRANT_USER_GROUP,
  733. grantedGroups: [
  734. { item: groupIdA, type: GroupType.userGroup },
  735. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  736. ],
  737. status: Page.STATUS_PUBLISHED,
  738. isEmpty: false,
  739. parent: rootPage._id,
  740. descendantCount: 0,
  741. },
  742. {
  743. _id: pageIdDelete3,
  744. path: '/npdel3_top',
  745. grant: Page.GRANT_USER_GROUP,
  746. grantedGroups: [
  747. { item: groupIdA, type: GroupType.userGroup },
  748. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  749. ],
  750. status: Page.STATUS_PUBLISHED,
  751. isEmpty: false,
  752. parent: rootPage._id,
  753. descendantCount: 2,
  754. },
  755. {
  756. _id: pageIdDelete4,
  757. path: '/npdel3_top/npdel4_ug',
  758. grant: Page.GRANT_USER_GROUP,
  759. grantedGroups: [
  760. { item: groupIdB, type: GroupType.userGroup },
  761. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  762. ],
  763. status: Page.STATUS_PUBLISHED,
  764. isEmpty: false,
  765. parent: pageIdDelete3._id,
  766. descendantCount: 1,
  767. },
  768. {
  769. path: '/npdel3_top/npdel4_ug',
  770. grant: Page.GRANT_RESTRICTED,
  771. status: Page.STATUS_PUBLISHED,
  772. isEmpty: false,
  773. },
  774. {
  775. path: '/npdel3_top/npdel4_ug/npdel5_ug',
  776. grant: Page.GRANT_USER_GROUP,
  777. grantedGroups: [
  778. { item: groupIdC, type: GroupType.userGroup },
  779. { item: externalGroupIdC, type: GroupType.externalUserGroup },
  780. ],
  781. status: Page.STATUS_PUBLISHED,
  782. isEmpty: false,
  783. parent: pageIdDelete4._id,
  784. descendantCount: 0,
  785. },
  786. ]);
  787. /**
  788. * Delete completely
  789. */
  790. const pageIdDeleteComp1 = new mongoose.Types.ObjectId();
  791. const pageIdDeleteComp2 = new mongoose.Types.ObjectId();
  792. await Page.insertMany([
  793. {
  794. path: '/npdc1_awl',
  795. grant: Page.GRANT_RESTRICTED,
  796. status: Page.STATUS_PUBLISHED,
  797. isEmpty: false,
  798. },
  799. {
  800. path: '/npdc2_ug',
  801. grant: Page.GRANT_USER_GROUP,
  802. grantedGroups: [
  803. { item: groupIdA, type: GroupType.userGroup },
  804. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  805. ],
  806. status: Page.STATUS_PUBLISHED,
  807. isEmpty: false,
  808. parent: rootPage._id,
  809. },
  810. {
  811. _id: pageIdDeleteComp1,
  812. path: '/npdc3_ug',
  813. grant: Page.GRANT_USER_GROUP,
  814. grantedGroups: [
  815. { item: groupIdA, type: GroupType.userGroup },
  816. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  817. ],
  818. status: Page.STATUS_PUBLISHED,
  819. isEmpty: false,
  820. parent: rootPage._id,
  821. },
  822. {
  823. _id: pageIdDeleteComp2,
  824. path: '/npdc3_ug/npdc4_ug',
  825. grant: Page.GRANT_USER_GROUP,
  826. grantedGroups: [
  827. { item: groupIdB, type: GroupType.userGroup },
  828. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  829. ],
  830. status: Page.STATUS_PUBLISHED,
  831. isEmpty: false,
  832. parent: pageIdDeleteComp1,
  833. },
  834. {
  835. path: '/npdc3_ug/npdc4_ug/npdc5_ug',
  836. grant: Page.GRANT_USER_GROUP,
  837. grantedGroups: [
  838. { item: groupIdC, type: GroupType.userGroup },
  839. { item: externalGroupIdC, type: GroupType.externalUserGroup },
  840. ],
  841. status: Page.STATUS_PUBLISHED,
  842. isEmpty: false,
  843. parent: pageIdDeleteComp2,
  844. },
  845. {
  846. path: '/npdc3_ug/npdc4_ug',
  847. grant: Page.GRANT_RESTRICTED,
  848. status: Page.STATUS_PUBLISHED,
  849. isEmpty: false,
  850. },
  851. ]);
  852. /**
  853. * Revert
  854. */
  855. await Page.insertMany([
  856. {
  857. _id: pageIdRevert1,
  858. path: '/trash/np_revert1',
  859. grant: Page.GRANT_RESTRICTED,
  860. revision: revisionIdRevert1,
  861. status: Page.STATUS_DELETED,
  862. },
  863. {
  864. _id: pageIdRevert2,
  865. path: '/trash/np_revert2',
  866. grant: Page.GRANT_USER_GROUP,
  867. grantedGroups: [
  868. { item: groupIdA, type: GroupType.userGroup },
  869. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  870. ],
  871. revision: revisionIdRevert2,
  872. status: Page.STATUS_DELETED,
  873. },
  874. {
  875. _id: pageIdRevert3,
  876. path: '/trash/np_revert3',
  877. revision: revisionIdRevert3,
  878. status: Page.STATUS_DELETED,
  879. parent: rootPage._id,
  880. },
  881. {
  882. _id: pageIdRevert4,
  883. path: '/trash/np_revert3/middle/np_revert4',
  884. grant: Page.GRANT_RESTRICTED,
  885. revision: revisionIdRevert4,
  886. status: Page.STATUS_DELETED,
  887. },
  888. {
  889. _id: pageIdRevert5,
  890. path: '/trash/np_revert5',
  891. grant: Page.GRANT_USER_GROUP,
  892. grantedGroups: [
  893. { item: groupIdA, type: GroupType.userGroup },
  894. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  895. ],
  896. revision: revisionIdRevert5,
  897. status: Page.STATUS_DELETED,
  898. },
  899. {
  900. _id: pageIdRevert6,
  901. path: '/trash/np_revert5/middle/np_revert6',
  902. grant: Page.GRANT_USER_GROUP,
  903. grantedGroups: [
  904. { item: groupIdB, type: GroupType.userGroup },
  905. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  906. ],
  907. revision: revisionIdRevert6,
  908. status: Page.STATUS_DELETED,
  909. },
  910. ]);
  911. await Revision.insertMany([
  912. {
  913. _id: revisionIdRevert1,
  914. pageId: pageIdRevert1,
  915. body: 'np_revert1',
  916. format: 'markdown',
  917. author: dummyUser1._id,
  918. },
  919. {
  920. _id: revisionIdRevert2,
  921. pageId: pageIdRevert2,
  922. body: 'np_revert2',
  923. format: 'markdown',
  924. author: npDummyUser1,
  925. },
  926. {
  927. _id: revisionIdRevert3,
  928. pageId: pageIdRevert3,
  929. body: 'np_revert3',
  930. format: 'markdown',
  931. author: npDummyUser1,
  932. },
  933. {
  934. _id: revisionIdRevert4,
  935. pageId: pageIdRevert4,
  936. body: 'np_revert4',
  937. format: 'markdown',
  938. author: npDummyUser1,
  939. },
  940. {
  941. _id: revisionIdRevert5,
  942. pageId: pageIdRevert5,
  943. body: 'np_revert5',
  944. format: 'markdown',
  945. author: npDummyUser1,
  946. },
  947. {
  948. _id: revisionIdRevert6,
  949. pageId: pageIdRevert6,
  950. body: 'np_revert6',
  951. format: 'markdown',
  952. author: npDummyUser1,
  953. },
  954. ]);
  955. await Tag.insertMany([
  956. { _id: tagIdRevert1, name: 'np_revertTag1' },
  957. { _id: tagIdRevert2, name: 'np_revertTag2' },
  958. ]);
  959. await PageTagRelation.insertMany([
  960. {
  961. relatedPage: pageIdRevert1,
  962. relatedTag: tagIdRevert1,
  963. isPageTrashed: true,
  964. },
  965. {
  966. relatedPage: pageIdRevert2,
  967. relatedTag: tagIdRevert2,
  968. isPageTrashed: true,
  969. },
  970. ]);
  971. });
  972. describe('create', () => {
  973. describe('Creating a page using existing path', () => {
  974. test('with grant RESTRICTED should only create the page and change nothing else', async () => {
  975. const isGrantNormalizedSpy = jest.spyOn(
  976. crowi.pageGrantService,
  977. 'isGrantNormalized',
  978. );
  979. const pathT = '/mc4_top';
  980. const path1 = '/mc4_top/mc1_emp';
  981. const path2 = '/mc4_top/mc1_emp/mc2_pub';
  982. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  983. const page1 = await Page.findOne({
  984. path: path1,
  985. grant: Page.GRANT_PUBLIC,
  986. });
  987. const page2 = await Page.findOne({ path: path2 });
  988. const page3 = await Page.findOne({
  989. path: path1,
  990. grant: Page.GRANT_RESTRICTED,
  991. });
  992. expect(pageT).toBeTruthy();
  993. expect(page1).toBeTruthy();
  994. expect(page2).toBeTruthy();
  995. expect(page3).toBeNull();
  996. // use existing path
  997. await create(path1, 'new body', dummyUser1, {
  998. grant: Page.GRANT_RESTRICTED,
  999. });
  1000. const _pageT = await Page.findOne({ path: pathT });
  1001. const _page1 = await Page.findOne({
  1002. path: path1,
  1003. grant: Page.GRANT_PUBLIC,
  1004. });
  1005. const _page2 = await Page.findOne({ path: path2 });
  1006. const _page3 = await Page.findOne({
  1007. path: path1,
  1008. grant: Page.GRANT_RESTRICTED,
  1009. });
  1010. expect(_pageT).toBeTruthy();
  1011. expect(_page1).toBeTruthy();
  1012. expect(_page2).toBeTruthy();
  1013. expect(_page3).toBeTruthy();
  1014. expect(_pageT?.descendantCount).toBe(1);
  1015. // isGrantNormalized is not called when GRANT RESTRICTED
  1016. expect(isGrantNormalizedSpy).toBeCalledTimes(0);
  1017. });
  1018. });
  1019. describe('Creating a page under a page with grant RESTRICTED', () => {
  1020. test('will create a new empty page with the same path as the grant RESTRECTED page and become a parent', async () => {
  1021. const isGrantNormalizedSpy = jest.spyOn(
  1022. crowi.pageGrantService,
  1023. 'isGrantNormalized',
  1024. );
  1025. const pathT = '/mc5_top';
  1026. const path1 = '/mc5_top/mc3_awl';
  1027. const pathN = '/mc5_top/mc3_awl/mc4_pub'; // used to create
  1028. const pageT = await Page.findOne({ path: pathT });
  1029. const page1 = await Page.findOne({
  1030. path: path1,
  1031. grant: Page.GRANT_RESTRICTED,
  1032. });
  1033. const page2 = await Page.findOne({
  1034. path: path1,
  1035. grant: Page.GRANT_PUBLIC,
  1036. });
  1037. expect(pageT).toBeTruthy();
  1038. expect(page1).toBeTruthy();
  1039. expect(page2).toBeNull();
  1040. await create(pathN, 'new body', dummyUser1, {
  1041. grant: Page.GRANT_PUBLIC,
  1042. });
  1043. const _pageT = await Page.findOne({ path: pathT });
  1044. const _page1 = await Page.findOne({
  1045. path: path1,
  1046. grant: Page.GRANT_RESTRICTED,
  1047. });
  1048. const _page2 = await Page.findOne({
  1049. path: path1,
  1050. grant: Page.GRANT_PUBLIC,
  1051. isEmpty: true,
  1052. });
  1053. const _pageN = await Page.findOne({
  1054. path: pathN,
  1055. grant: Page.GRANT_PUBLIC,
  1056. }); // newly crated
  1057. expect(_pageT).toBeTruthy();
  1058. expect(_page1).toBeTruthy();
  1059. expect(_page2).toBeTruthy();
  1060. expect(_pageN).toBeTruthy();
  1061. expect(_pageN?.parent).toStrictEqual(_page2?._id);
  1062. expect(_pageT?.descendantCount).toStrictEqual(1);
  1063. // isGrantNormalized is called when GRANT PUBLIC
  1064. expect(isGrantNormalizedSpy).toBeCalledTimes(1);
  1065. });
  1066. });
  1067. describe('Creating a page under a page with grant USER_GROUP', () => {
  1068. describe('When onlyInheritUserRelatedGrantedGroups is true', () => {
  1069. test('Only user related groups should be inherited', async () => {
  1070. const pathT = '/mc6_top';
  1071. const pageT = await Page.findOne({ path: pathT });
  1072. expect(pageT).toBeTruthy();
  1073. const pathN = '/mc6_top/onlyRelatedGroupsInherited'; // path to create
  1074. await create(pathN, 'new body', npDummyUser1, {
  1075. grant: Page.GRANT_USER_GROUP,
  1076. onlyInheritUserRelatedGrantedGroups: true,
  1077. });
  1078. const _pageT = await Page.findOne({ path: pathT });
  1079. const _pageN = await Page.findOne({
  1080. path: pathN,
  1081. grant: Page.GRANT_USER_GROUP,
  1082. }); // newly crated
  1083. expect(_pageT).toBeTruthy();
  1084. expect(_pageN).toBeTruthy();
  1085. expect(_pageN?.parent).toStrictEqual(_pageT?._id);
  1086. expect(_pageT?.descendantCount).toStrictEqual(1);
  1087. expect(normalizeGrantedGroups(_pageN?.grantedGroups)).toStrictEqual([
  1088. { item: groupIdIsolate, type: GroupType.userGroup },
  1089. ]);
  1090. });
  1091. });
  1092. describe('When onlyInheritUserRelatedGrantedGroups is false', () => {
  1093. test('All groups should be inherited', async () => {
  1094. const pathT = '/mc6_top';
  1095. const pageT = await Page.findOne({ path: pathT });
  1096. expect(pageT).toBeTruthy();
  1097. const pathN = '/mc6_top/allGroupsInherited'; // path to create
  1098. await create(pathN, 'new body', npDummyUser1, {
  1099. grant: Page.GRANT_USER_GROUP,
  1100. onlyInheritUserRelatedGrantedGroups: false,
  1101. });
  1102. const _pageT = await Page.findOne({ path: pathT });
  1103. const _pageN = await Page.findOne({
  1104. path: pathN,
  1105. grant: Page.GRANT_USER_GROUP,
  1106. }); // newly crated
  1107. expect(_pageT).toBeTruthy();
  1108. expect(_pageN).toBeTruthy();
  1109. expect(_pageN?.parent).toStrictEqual(_pageT?._id);
  1110. expect(_pageT?.descendantCount).toStrictEqual(2);
  1111. expect(normalizeGrantedGroups(_pageN?.grantedGroups)).toStrictEqual([
  1112. { item: groupIdIsolate, type: GroupType.userGroup },
  1113. { item: groupIdB, type: GroupType.userGroup },
  1114. ]);
  1115. });
  1116. });
  1117. });
  1118. });
  1119. describe('create by system', () => {
  1120. describe('Creating a page using existing path', () => {
  1121. test('with grant RESTRICTED should only create the page and change nothing else', async () => {
  1122. const isGrantNormalizedSpy = jest.spyOn(
  1123. crowi.pageGrantService,
  1124. 'isGrantNormalized',
  1125. );
  1126. const pathT = '/mc4_top_by_system';
  1127. const path1 = '/mc4_top_by_system/mc1_emp_by_system';
  1128. const path2 = '/mc4_top_by_system/mc1_emp_by_system/mc2_pub_by_system';
  1129. const pageT = await Page.findOne({ path: pathT, descendantCount: 1 });
  1130. const page1 = await Page.findOne({
  1131. path: path1,
  1132. grant: Page.GRANT_PUBLIC,
  1133. });
  1134. const page2 = await Page.findOne({ path: path2 });
  1135. const page3 = await Page.findOne({
  1136. path: path1,
  1137. grant: Page.GRANT_RESTRICTED,
  1138. });
  1139. expect(pageT).toBeTruthy();
  1140. expect(page1).toBeTruthy();
  1141. expect(page2).toBeTruthy();
  1142. expect(page3).toBeNull();
  1143. // use existing path
  1144. await crowi.pageService.forceCreateBySystem(path1, 'new body', {
  1145. grant: Page.GRANT_RESTRICTED,
  1146. });
  1147. const _pageT = await Page.findOne({ path: pathT });
  1148. const _page1 = await Page.findOne({
  1149. path: path1,
  1150. grant: Page.GRANT_PUBLIC,
  1151. });
  1152. const _page2 = await Page.findOne({ path: path2 });
  1153. const _page3 = await Page.findOne({
  1154. path: path1,
  1155. grant: Page.GRANT_RESTRICTED,
  1156. });
  1157. expect(_pageT).toBeTruthy();
  1158. expect(_page1).toBeTruthy();
  1159. expect(_page2).toBeTruthy();
  1160. expect(_page3).toBeTruthy();
  1161. expect(_pageT?.descendantCount).toBe(1);
  1162. // isGrantNormalized is not called when create by ststem
  1163. expect(isGrantNormalizedSpy).toBeCalledTimes(0);
  1164. });
  1165. });
  1166. describe('Creating a page under a page with grant RESTRICTED', () => {
  1167. test('will create a new empty page with the same path as the grant RESTRECTED page and become a parent', async () => {
  1168. const isGrantNormalizedSpy = jest.spyOn(
  1169. crowi.pageGrantService,
  1170. 'isGrantNormalized',
  1171. );
  1172. const pathT = '/mc5_top_by_system';
  1173. const path1 = '/mc5_top_by_system/mc3_awl_by_system';
  1174. const pathN = '/mc5_top_by_system/mc3_awl_by_system/mc4_pub_by_system'; // used to create
  1175. const pageT = await Page.findOne({ path: pathT });
  1176. const page1 = await Page.findOne({
  1177. path: path1,
  1178. grant: Page.GRANT_RESTRICTED,
  1179. });
  1180. const page2 = await Page.findOne({
  1181. path: path1,
  1182. grant: Page.GRANT_PUBLIC,
  1183. });
  1184. expect(pageT).toBeTruthy();
  1185. expect(page1).toBeTruthy();
  1186. expect(page2).toBeNull();
  1187. await crowi.pageService.forceCreateBySystem(pathN, 'new body', {
  1188. grant: Page.GRANT_PUBLIC,
  1189. });
  1190. const _pageT = await Page.findOne({ path: pathT });
  1191. const _page1 = await Page.findOne({
  1192. path: path1,
  1193. grant: Page.GRANT_RESTRICTED,
  1194. });
  1195. const _page2 = await Page.findOne({
  1196. path: path1,
  1197. grant: Page.GRANT_PUBLIC,
  1198. isEmpty: true,
  1199. });
  1200. const _pageN = await Page.findOne({
  1201. path: pathN,
  1202. grant: Page.GRANT_PUBLIC,
  1203. }); // newly crated
  1204. expect(_pageT).toBeTruthy();
  1205. expect(_page1).toBeTruthy();
  1206. expect(_page2).toBeTruthy();
  1207. expect(_pageN).toBeTruthy();
  1208. expect(_pageN?.parent).toStrictEqual(_page2?._id);
  1209. expect(_pageT?.descendantCount).toStrictEqual(1);
  1210. // isGrantNormalized is not called when create by ststem
  1211. expect(isGrantNormalizedSpy).toBeCalledTimes(0);
  1212. });
  1213. });
  1214. });
  1215. describe('Rename', () => {
  1216. const renamePage = async (
  1217. page,
  1218. newPagePath,
  1219. user,
  1220. options,
  1221. activityParameters?,
  1222. ) => {
  1223. // mock return value
  1224. const mockedRenameSubOperation = jest
  1225. .spyOn(crowi.pageService, 'renameSubOperation')
  1226. .mockReturnValue(null);
  1227. const renamedPage = await crowi.pageService.renamePage(
  1228. page,
  1229. newPagePath,
  1230. user,
  1231. options,
  1232. activityParameters,
  1233. );
  1234. // retrieve the arguments passed when calling method renameSubOperation inside renamePage method
  1235. const argsForRenameSubOperation = mockedRenameSubOperation.mock.calls[0];
  1236. // restores the original implementation
  1237. mockedRenameSubOperation.mockRestore();
  1238. // rename descendants
  1239. if (page.grant !== Page.GRANT_RESTRICTED) {
  1240. await crowi.pageService.renameSubOperation(
  1241. ...(argsForRenameSubOperation as Parameters<
  1242. typeof crowi.pageService.renameSubOperation
  1243. >),
  1244. );
  1245. }
  1246. return renamedPage;
  1247. };
  1248. test('Should rename/move with descendants with grant normalized pages', async () => {
  1249. const _pathD = '/np_rename1_destination';
  1250. const _path2 = '/np_rename2';
  1251. const _path3 = '/np_rename2/np_rename3';
  1252. const _propertiesD = { grant: Page.GRANT_PUBLIC };
  1253. const _properties2 = {
  1254. grant: Page.GRANT_USER_GROUP,
  1255. grantedGroups: { $elemMatch: { item: groupIdB } },
  1256. };
  1257. const _properties3 = {
  1258. grant: Page.GRANT_USER_GROUP,
  1259. grantedGroups: { $elemMatch: { item: groupIdC } },
  1260. };
  1261. const _pageD = await Page.findOne({ path: _pathD, ..._propertiesD });
  1262. const _page2 = await Page.findOne({ path: _path2, ..._properties2 });
  1263. const _page3 = await Page.findOne({
  1264. path: _path3,
  1265. ..._properties3,
  1266. parent: _page2?._id,
  1267. });
  1268. expect(_pageD).toBeTruthy();
  1269. expect(_page2).toBeTruthy();
  1270. expect(_page3).toBeTruthy();
  1271. const newPathForPage2 = '/np_rename1_destination/np_rename2';
  1272. const newPathForPage3 = '/np_rename1_destination/np_rename2/np_rename3';
  1273. await renamePage(
  1274. _page2,
  1275. newPathForPage2,
  1276. npDummyUser2,
  1277. {},
  1278. {
  1279. ip: '::ffff:127.0.0.1',
  1280. endpoint: '/_api/v3/pages/rename',
  1281. activityId: '62e291bc10e0ab61bd691794',
  1282. },
  1283. );
  1284. const pageD = await Page.findOne({ path: _pathD, ..._propertiesD });
  1285. const page2 = await Page.findOne({ path: _path2, ..._properties2 }); // not exist
  1286. const page3 = await Page.findOne({
  1287. path: _path3,
  1288. ..._properties3,
  1289. parent: _page2?._id,
  1290. }); // not exist
  1291. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // renamed
  1292. const page3Renamed = await Page.findOne({ path: newPathForPage3 }); // renamed
  1293. expect(pageD).toBeTruthy();
  1294. expect(page2).toBeNull();
  1295. expect(page3).toBeNull();
  1296. expect(page2Renamed).toBeTruthy();
  1297. expect(page3Renamed).toBeTruthy();
  1298. expect(page2Renamed?.parent).toStrictEqual(_pageD?._id);
  1299. expect(page3Renamed?.parent).toStrictEqual(page2Renamed?._id);
  1300. expect(normalizeGrantedGroups(page2Renamed?.grantedGroups)).toStrictEqual(
  1301. normalizeGrantedGroups(_page2?.grantedGroups),
  1302. );
  1303. expect(normalizeGrantedGroups(page3Renamed?.grantedGroups)).toStrictEqual(
  1304. normalizeGrantedGroups(_page3?.grantedGroups),
  1305. );
  1306. expect(generalXssFilterProcessSpy).toHaveBeenCalled();
  1307. });
  1308. test('Should throw with NOT grant normalized pages', async () => {
  1309. const _pathD = '/np_rename4_destination';
  1310. const _path2 = '/np_rename5';
  1311. const _path3 = '/np_rename5/np_rename6';
  1312. const _propertiesD = {
  1313. grant: Page.GRANT_USER_GROUP,
  1314. grantedGroups: { $elemMatch: { item: groupIdIsolate } },
  1315. };
  1316. const _properties2 = {
  1317. grant: Page.GRANT_USER_GROUP,
  1318. grantedGroups: { $elemMatch: { item: groupIdB } },
  1319. };
  1320. const _properties3 = {
  1321. grant: Page.GRANT_USER_GROUP,
  1322. grantedGroups: { $elemMatch: { item: groupIdB } },
  1323. };
  1324. const _pageD = await Page.findOne({ path: _pathD, ..._propertiesD }); // isolate
  1325. const _page2 = await Page.findOne({ path: _path2, ..._properties2 }); // groupIdB
  1326. const _page3 = await Page.findOne({
  1327. path: _path3,
  1328. ..._properties3,
  1329. parent: _page2,
  1330. }); // groupIdB
  1331. expect(_pageD).toBeTruthy();
  1332. expect(_page2).toBeTruthy();
  1333. expect(_page3).toBeTruthy();
  1334. const newPathForPage2 = '/np_rename4_destination/np_rename5';
  1335. const newPathForPage3 = '/np_rename4_destination/np_rename5/np_rename6';
  1336. let isThrown = false;
  1337. try {
  1338. await renamePage(
  1339. _page2,
  1340. newPathForPage2,
  1341. dummyUser1,
  1342. {},
  1343. {
  1344. ip: '::ffff:127.0.0.1',
  1345. endpoint: '/_api/v3/pages/rename',
  1346. activityId: '62e291bc10e0ab61bd691794',
  1347. },
  1348. );
  1349. } catch (err) {
  1350. isThrown = true;
  1351. }
  1352. expect(isThrown).toBe(true);
  1353. const page2 = await Page.findOne({ path: _path2 }); // not renamed thus exist
  1354. const page3 = await Page.findOne({ path: _path3 }); // not renamed thus exist
  1355. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // not exist
  1356. const page3Renamed = await Page.findOne({ path: newPathForPage3 }); // not exist
  1357. expect(page2).toBeTruthy();
  1358. expect(page3).toBeTruthy();
  1359. expect(page2Renamed).toBeNull();
  1360. expect(page3Renamed).toBeNull();
  1361. });
  1362. test('Should rename/move multiple pages: child page with GRANT_RESTRICTED should NOT be renamed.', async () => {
  1363. const _pathD = '/np_rename7_destination';
  1364. const _path2 = '/np_rename8';
  1365. const _path3 = '/np_rename8/np_rename9';
  1366. const _pageD = await Page.findOne({
  1367. path: _pathD,
  1368. grant: Page.GRANT_USER_GROUP,
  1369. grantedGroups: { $elemMatch: { item: groupIdIsolate } },
  1370. });
  1371. const _page2 = await Page.findOne({
  1372. path: _path2,
  1373. grant: Page.GRANT_RESTRICTED,
  1374. });
  1375. const _page3 = await Page.findOne({
  1376. path: _path3,
  1377. grant: Page.GRANT_RESTRICTED,
  1378. });
  1379. expect(_pageD).toBeTruthy();
  1380. expect(_page2).toBeTruthy();
  1381. expect(_page3).toBeTruthy();
  1382. const newPathForPage2 = '/np_rename7_destination/np_rename8';
  1383. const newpathForPage3 = '/np_rename7_destination/np_rename8/np_rename9';
  1384. await renamePage(
  1385. _page2,
  1386. newPathForPage2,
  1387. npDummyUser1,
  1388. { isRecursively: true },
  1389. {
  1390. ip: '::ffff:127.0.0.1',
  1391. endpoint: '/_api/v3/pages/rename',
  1392. activityId: '62e291bc10e0ab61bd691794',
  1393. },
  1394. );
  1395. const page2 = await Page.findOne({ path: _path2 }); // not exist
  1396. const page3 = await Page.findOne({ path: _path3 }); // not renamed thus exist
  1397. const page2Renamed = await Page.findOne({ path: newPathForPage2 }); // exist
  1398. const page3Renamed = await Page.findOne({ path: newpathForPage3 }); // not exist
  1399. expect(page2).toBeNull();
  1400. expect(page3).toBeTruthy();
  1401. expect(page2Renamed).toBeTruthy();
  1402. expect(page3Renamed).toBeNull();
  1403. expect(page2Renamed?.parent).toBeNull();
  1404. expect(generalXssFilterProcessSpy).toHaveBeenCalled();
  1405. });
  1406. });
  1407. describe('Duplicate', () => {
  1408. const duplicate = async (
  1409. page,
  1410. newPagePath: string,
  1411. user,
  1412. isRecursively: boolean,
  1413. onlyDuplicateUserRelatedResources: boolean,
  1414. ) => {
  1415. // mock return value
  1416. const mockedDuplicateRecursivelyMainOperation = jest
  1417. .spyOn(crowi.pageService, 'duplicateRecursivelyMainOperation')
  1418. .mockReturnValue(null);
  1419. const duplicatedPage = await crowi.pageService.duplicate(
  1420. page,
  1421. newPagePath,
  1422. user,
  1423. isRecursively,
  1424. onlyDuplicateUserRelatedResources,
  1425. );
  1426. // retrieve the arguments passed when calling method duplicateRecursivelyMainOperation inside duplicate method
  1427. const argsForDuplicateRecursivelyMainOperation =
  1428. mockedDuplicateRecursivelyMainOperation.mock.calls[0];
  1429. // restores the original implementation
  1430. mockedDuplicateRecursivelyMainOperation.mockRestore();
  1431. // duplicate descendants
  1432. if (page.grant !== Page.GRANT_RESTRICTED && isRecursively) {
  1433. await crowi.pageService.duplicateRecursivelyMainOperation(
  1434. ...(argsForDuplicateRecursivelyMainOperation as Parameters<
  1435. typeof crowi.pageService.duplicateRecursivelyMainOperation
  1436. >),
  1437. );
  1438. }
  1439. return duplicatedPage;
  1440. };
  1441. test('Duplicate single page with GRANT_RESTRICTED', async () => {
  1442. const _page = await Page.findOne({
  1443. path: '/np_duplicate1',
  1444. grant: Page.GRANT_RESTRICTED,
  1445. }).populate<{ revision: IRevisionDocument }>({
  1446. path: 'revision',
  1447. model: 'Revision',
  1448. });
  1449. const _revision = _page?.revision;
  1450. expect(_page).toBeTruthy();
  1451. expect(_revision).toBeTruthy();
  1452. const newPagePath = '/dup_np_duplicate1';
  1453. await duplicate(_page, newPagePath, npDummyUser1, false, false);
  1454. const duplicatedPage = await Page.findOne({ path: newPagePath });
  1455. const duplicatedRevision = await Revision.findOne({
  1456. pageId: duplicatedPage?._id,
  1457. });
  1458. expect(generalXssFilterProcessSpy).toHaveBeenCalled();
  1459. expect(duplicatedPage).toBeTruthy();
  1460. expect(duplicatedPage?._id).not.toStrictEqual(_page?._id);
  1461. expect(duplicatedPage?.grant).toBe(_page?.grant);
  1462. expect(duplicatedPage?.parent).toBeNull();
  1463. expect(duplicatedPage?.parent).toStrictEqual(_page?.parent);
  1464. expect(duplicatedPage?.revision).toStrictEqual(duplicatedRevision?._id);
  1465. expect(duplicatedRevision?.body).toBe(_revision?.body);
  1466. });
  1467. test('Should duplicate multiple pages with GRANT_USER_GROUP', async () => {
  1468. const _path1 = '/np_duplicate2';
  1469. const _path2 = '/np_duplicate2/np_duplicate3';
  1470. const _page1 = await Page.findOne({
  1471. path: _path1,
  1472. parent: rootPage._id,
  1473. grantedGroups: { $elemMatch: { item: groupIdA } },
  1474. }).populate<{ revision: IRevisionDocument }>({
  1475. path: 'revision',
  1476. model: 'Revision',
  1477. });
  1478. const _page2 = await Page.findOne({
  1479. path: _path2,
  1480. parent: _page1?._id,
  1481. grantedGroups: { $elemMatch: { item: groupIdB } },
  1482. }).populate<{ revision: IRevisionDocument }>({
  1483. path: 'revision',
  1484. model: 'Revision',
  1485. });
  1486. const _revision1 = _page1?.revision;
  1487. const _revision2 = _page2?.revision;
  1488. expect(_page1).toBeTruthy();
  1489. expect(_page2).toBeTruthy();
  1490. expect(_revision1).toBeTruthy();
  1491. expect(_revision2).toBeTruthy();
  1492. const newPagePath = '/dup_np_duplicate2';
  1493. await duplicate(_page1, newPagePath, npDummyUser2, true, false);
  1494. const duplicatedPage1 = await Page.findOne({
  1495. path: newPagePath,
  1496. }).populate<{ revision: IRevisionDocument }>({
  1497. path: 'revision',
  1498. model: 'Revision',
  1499. });
  1500. const duplicatedPage2 = await Page.findOne({
  1501. path: '/dup_np_duplicate2/np_duplicate3',
  1502. }).populate<{ revision: IRevisionDocument }>({
  1503. path: 'revision',
  1504. model: 'Revision',
  1505. });
  1506. const duplicatedRevision1 = duplicatedPage1?.revision;
  1507. const duplicatedRevision2 = duplicatedPage2?.revision;
  1508. expect(generalXssFilterProcessSpy).toHaveBeenCalled();
  1509. expect(duplicatedPage1).toBeTruthy();
  1510. expect(duplicatedPage2).toBeTruthy();
  1511. expect(duplicatedRevision1).toBeTruthy();
  1512. expect(duplicatedRevision2).toBeTruthy();
  1513. expect(
  1514. normalizeGrantedGroups(duplicatedPage1?.grantedGroups),
  1515. ).toStrictEqual([
  1516. { item: groupIdA, type: GroupType.userGroup },
  1517. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  1518. ]);
  1519. expect(
  1520. normalizeGrantedGroups(duplicatedPage2?.grantedGroups),
  1521. ).toStrictEqual([
  1522. { item: groupIdB, type: GroupType.userGroup },
  1523. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  1524. ]);
  1525. expect(duplicatedPage1?.parent).toStrictEqual(_page1?.parent);
  1526. expect(duplicatedPage2?.parent).toStrictEqual(duplicatedPage1?._id);
  1527. expect(duplicatedRevision1?.body).toBe(_revision1?.body);
  1528. expect(duplicatedRevision2?.body).toBe(_revision2?.body);
  1529. expect(duplicatedRevision1?.pageId).toStrictEqual(duplicatedPage1?._id);
  1530. expect(duplicatedRevision2?.pageId).toStrictEqual(duplicatedPage2?._id);
  1531. });
  1532. test('Should duplicate multiple pages. Page with GRANT_RESTRICTED should NOT be duplicated', async () => {
  1533. const _path1 = '/np_duplicate4';
  1534. const _path2 = '/np_duplicate4/np_duplicate5';
  1535. const _path3 = '/np_duplicate4/np_duplicate6';
  1536. const _page1 = await Page.findOne({
  1537. path: _path1,
  1538. parent: rootPage._id,
  1539. grant: Page.GRANT_PUBLIC,
  1540. }).populate<{ revision: IRevisionDocument }>({
  1541. path: 'revision',
  1542. model: 'Revision',
  1543. });
  1544. const _page2 = await Page.findOne({
  1545. path: _path2,
  1546. grant: Page.GRANT_RESTRICTED,
  1547. }).populate<{ revision: IRevisionDocument }>({
  1548. path: 'revision',
  1549. model: 'Revision',
  1550. });
  1551. const _page3 = await Page.findOne({
  1552. path: _path3,
  1553. grant: Page.GRANT_PUBLIC,
  1554. }).populate<{ revision: IRevisionDocument }>({
  1555. path: 'revision',
  1556. model: 'Revision',
  1557. });
  1558. const baseRevision1 = _page1?.revision;
  1559. const baseRevision2 = _page2?.revision;
  1560. const baseRevision3 = _page3?.revision;
  1561. expect(_page1).toBeTruthy();
  1562. expect(_page2).toBeTruthy();
  1563. expect(_page3).toBeTruthy();
  1564. expect(baseRevision1).toBeTruthy();
  1565. expect(baseRevision2).toBeTruthy();
  1566. const newPagePath = '/dup_np_duplicate4';
  1567. await duplicate(_page1, newPagePath, npDummyUser1, true, false);
  1568. const duplicatedPage1 = await Page.findOne({
  1569. path: newPagePath,
  1570. }).populate<{ revision: IRevisionDocument }>({
  1571. path: 'revision',
  1572. model: 'Revision',
  1573. });
  1574. const duplicatedPage2 = await Page.findOne({
  1575. path: '/dup_np_duplicate4/np_duplicate5',
  1576. }).populate<{ revision: IRevisionDocument }>({
  1577. path: 'revision',
  1578. model: 'Revision',
  1579. });
  1580. const duplicatedPage3 = await Page.findOne({
  1581. path: '/dup_np_duplicate4/np_duplicate6',
  1582. }).populate<{ revision: IRevisionDocument }>({
  1583. path: 'revision',
  1584. model: 'Revision',
  1585. });
  1586. const duplicatedRevision1 = duplicatedPage1?.revision;
  1587. const duplicatedRevision3 = duplicatedPage3?.revision;
  1588. expect(generalXssFilterProcessSpy).toHaveBeenCalled();
  1589. expect(duplicatedPage1).toBeTruthy();
  1590. expect(duplicatedPage2).toBeNull();
  1591. expect(duplicatedPage3).toBeTruthy();
  1592. expect(duplicatedRevision1).toBeTruthy();
  1593. expect(duplicatedRevision3).toBeTruthy();
  1594. expect(duplicatedPage1?.grant).toStrictEqual(Page.GRANT_PUBLIC);
  1595. expect(duplicatedPage3?.grant).toStrictEqual(Page.GRANT_PUBLIC);
  1596. expect(duplicatedPage1?.parent).toStrictEqual(_page1?.parent);
  1597. expect(duplicatedPage3?.parent).toStrictEqual(duplicatedPage1?._id);
  1598. expect(duplicatedRevision1?.body).toBe(baseRevision1?.body);
  1599. expect(duplicatedRevision3?.body).toBe(baseRevision3?.body);
  1600. expect(duplicatedRevision1?.pageId).toStrictEqual(duplicatedPage1?._id);
  1601. expect(duplicatedRevision3?.pageId).toStrictEqual(duplicatedPage3?._id);
  1602. });
  1603. test('Should duplicate only user related pages and granted groups when onlyDuplicateUserRelatedResources is true', async () => {
  1604. const _path1 = '/np_duplicate7';
  1605. const _path2 = '/np_duplicate7/np_duplicate8';
  1606. const _path3 = '/np_duplicate7/np_duplicate9';
  1607. const _page1 = await Page.findOne({
  1608. path: _path1,
  1609. parent: rootPage._id,
  1610. }).populate<{ revision: IRevisionDocument }>({
  1611. path: 'revision',
  1612. model: 'Revision',
  1613. });
  1614. const _page2 = await Page.findOne({ path: _path2, parent: _page1?._id });
  1615. const _page3 = await Page.findOne({ path: _path3, parent: _page1?._id });
  1616. const _revision1 = _page1?.revision;
  1617. expect(_page1).toBeTruthy();
  1618. expect(_page2).toBeTruthy();
  1619. expect(_page3).toBeTruthy();
  1620. expect(_revision1).toBeTruthy();
  1621. const newPagePath = '/dup_np_duplicate7';
  1622. await duplicate(_page1, newPagePath, npDummyUser1, true, true);
  1623. const duplicatedPage1 = await Page.findOne({
  1624. path: newPagePath,
  1625. }).populate<{ revision: IRevisionDocument }>({
  1626. path: 'revision',
  1627. model: 'Revision',
  1628. });
  1629. const duplicatedPage2 = await Page.findOne({
  1630. path: '/dup_np_duplicate7/np_duplicate8',
  1631. }).populate<{ revision: IRevisionDocument }>({
  1632. path: 'revision',
  1633. model: 'Revision',
  1634. });
  1635. const duplicatedPage3 = await Page.findOne({
  1636. path: '/dup_np_duplicate7/np_duplicate9',
  1637. }).populate<{ revision: IRevisionDocument }>({
  1638. path: 'revision',
  1639. model: 'Revision',
  1640. });
  1641. const duplicatedRevision1 = duplicatedPage1?.revision;
  1642. expect(generalXssFilterProcessSpy).toHaveBeenCalled();
  1643. expect(duplicatedPage1).toBeTruthy();
  1644. expect(duplicatedPage2).toBeFalsy();
  1645. expect(duplicatedPage3).toBeFalsy();
  1646. expect(duplicatedRevision1).toBeTruthy();
  1647. expect(
  1648. normalizeGrantedGroups(duplicatedPage1?.grantedGroups),
  1649. ).toStrictEqual([
  1650. { item: groupIdA, type: GroupType.userGroup },
  1651. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  1652. ]);
  1653. expect(duplicatedPage1?.parent).toStrictEqual(_page1?.parent);
  1654. expect(duplicatedRevision1?.body).toBe(_revision1?.body);
  1655. expect(duplicatedRevision1?.pageId).toStrictEqual(duplicatedPage1?._id);
  1656. });
  1657. test('Should duplicate all pages and granted groups when onlyDuplicateUserRelatedResources is false', async () => {
  1658. const _path1 = '/np_duplicate7';
  1659. const _path2 = '/np_duplicate7/np_duplicate8';
  1660. const _path3 = '/np_duplicate7/np_duplicate9';
  1661. const _page1 = await Page.findOne({
  1662. path: _path1,
  1663. parent: rootPage._id,
  1664. }).populate<{ revision: IRevisionDocument }>({
  1665. path: 'revision',
  1666. model: 'Revision',
  1667. });
  1668. const _page2 = await Page.findOne({
  1669. path: _path2,
  1670. parent: _page1?._id,
  1671. }).populate<{ revision: IRevisionDocument }>({
  1672. path: 'revision',
  1673. model: 'Revision',
  1674. });
  1675. const _page3 = await Page.findOne({
  1676. path: _path3,
  1677. parent: _page1?._id,
  1678. }).populate<{ revision: IRevisionDocument }>({
  1679. path: 'revision',
  1680. model: 'Revision',
  1681. });
  1682. const _revision1 = _page1?.revision;
  1683. const _revision2 = _page2?.revision;
  1684. const _revision3 = _page3?.revision;
  1685. expect(_page1).toBeTruthy();
  1686. expect(_page2).toBeTruthy();
  1687. expect(_page3).toBeTruthy();
  1688. expect(_revision1).toBeTruthy();
  1689. expect(_revision2).toBeTruthy();
  1690. expect(_revision3).toBeTruthy();
  1691. const newPagePath = '/dup2_np_duplicate7';
  1692. await duplicate(_page1, newPagePath, npDummyUser1, true, false);
  1693. const duplicatedPage1 = await Page.findOne({
  1694. path: newPagePath,
  1695. }).populate<{ revision: IRevisionDocument }>({
  1696. path: 'revision',
  1697. model: 'Revision',
  1698. });
  1699. const duplicatedPage2 = await Page.findOne({
  1700. path: '/dup2_np_duplicate7/np_duplicate8',
  1701. }).populate<{ revision: IRevisionDocument }>({
  1702. path: 'revision',
  1703. model: 'Revision',
  1704. });
  1705. const duplicatedPage3 = await Page.findOne({
  1706. path: '/dup2_np_duplicate7/np_duplicate9',
  1707. }).populate<{ revision: IRevisionDocument }>({
  1708. path: 'revision',
  1709. model: 'Revision',
  1710. });
  1711. const duplicatedRevision1 = duplicatedPage1?.revision;
  1712. const duplicatedRevision2 = duplicatedPage2?.revision;
  1713. const duplicatedRevision3 = duplicatedPage3?.revision;
  1714. expect(generalXssFilterProcessSpy).toHaveBeenCalled();
  1715. expect(duplicatedPage1).toBeTruthy();
  1716. expect(duplicatedPage2).toBeTruthy();
  1717. expect(duplicatedPage3).toBeTruthy();
  1718. expect(duplicatedRevision1).toBeTruthy();
  1719. expect(duplicatedRevision2).toBeTruthy();
  1720. expect(duplicatedRevision3).toBeTruthy();
  1721. expect(
  1722. normalizeGrantedGroups(duplicatedPage1?.grantedGroups),
  1723. ).toStrictEqual([
  1724. { item: groupIdA, type: GroupType.userGroup },
  1725. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  1726. { item: groupIdB, type: GroupType.userGroup },
  1727. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  1728. ]);
  1729. expect(duplicatedPage1?.parent).toStrictEqual(_page1?.parent);
  1730. expect(duplicatedRevision1?.body).toBe(_revision1?.body);
  1731. expect(duplicatedRevision1?.pageId).toStrictEqual(duplicatedPage1?._id);
  1732. expect(
  1733. normalizeGrantedGroups(duplicatedPage2?.grantedGroups),
  1734. ).toStrictEqual([
  1735. { item: groupIdC, type: GroupType.userGroup },
  1736. { item: externalGroupIdC, type: GroupType.externalUserGroup },
  1737. ]);
  1738. expect(duplicatedPage2?.parent).toStrictEqual(duplicatedPage1?._id);
  1739. expect(duplicatedRevision2?.body).toBe(_revision2?.body);
  1740. expect(duplicatedRevision2?.pageId).toStrictEqual(duplicatedPage2?._id);
  1741. expect(duplicatedPage3?.grantedUsers).toStrictEqual([npDummyUser2?._id]);
  1742. expect(duplicatedPage3?.parent).toStrictEqual(duplicatedPage1?._id);
  1743. expect(duplicatedRevision3?.body).toBe(_revision3?.body);
  1744. expect(duplicatedRevision3?.pageId).toStrictEqual(duplicatedPage3?._id);
  1745. });
  1746. });
  1747. describe('Delete', () => {
  1748. const deletePage = async (
  1749. page,
  1750. user,
  1751. options,
  1752. isRecursively,
  1753. activityParameters?,
  1754. ) => {
  1755. const mockedDeleteRecursivelyMainOperation = jest
  1756. .spyOn(crowi.pageService, 'deleteRecursivelyMainOperation')
  1757. .mockReturnValue(null);
  1758. const deletedPage = await crowi.pageService.deletePage(
  1759. page,
  1760. user,
  1761. options,
  1762. isRecursively,
  1763. activityParameters,
  1764. );
  1765. const argsForDeleteRecursivelyMainOperation =
  1766. mockedDeleteRecursivelyMainOperation.mock.calls[0];
  1767. mockedDeleteRecursivelyMainOperation.mockRestore();
  1768. if (isRecursively) {
  1769. await crowi.pageService.deleteRecursivelyMainOperation(
  1770. ...(argsForDeleteRecursivelyMainOperation as Parameters<
  1771. typeof crowi.pageService.deleteRecursivelyMainOperation
  1772. >),
  1773. );
  1774. }
  1775. return deletedPage;
  1776. };
  1777. describe('Delete single page with grant RESTRICTED', () => {
  1778. test('should be able to delete', async () => {
  1779. const _pathT = '/npdel1_awl';
  1780. const _pageT = await Page.findOne({
  1781. path: _pathT,
  1782. grant: Page.GRANT_RESTRICTED,
  1783. });
  1784. expect(_pageT).toBeTruthy();
  1785. const isRecursively = false;
  1786. await deletePage(_pageT, dummyUser1, {}, isRecursively, {
  1787. ip: '::ffff:127.0.0.1',
  1788. endpoint: '/_api/v3/pages/rename',
  1789. });
  1790. const pageT = await Page.findOne({ path: `/trash${_pathT}` });
  1791. const pageN = await Page.findOne({ path: _pathT }); // should not exist
  1792. expect(pageT).toBeTruthy();
  1793. expect(pageN).toBeNull();
  1794. expect(pageT?.grant).toBe(Page.GRANT_RESTRICTED);
  1795. expect(pageT?.status).toBe(Page.STATUS_DELETED);
  1796. });
  1797. });
  1798. describe('Delete single page with grant USER_GROUP', () => {
  1799. test('should be able to delete', async () => {
  1800. const _path = '/npdel2_ug';
  1801. const _page1 = await Page.findOne({
  1802. path: _path,
  1803. grantedGroups: { $elemMatch: { item: groupIdA } },
  1804. });
  1805. expect(_page1).toBeTruthy();
  1806. const isRecursively = false;
  1807. await deletePage(_page1, npDummyUser1, {}, isRecursively, {
  1808. ip: '::ffff:127.0.0.1',
  1809. endpoint: '/_api/v3/pages/rename',
  1810. });
  1811. const pageN = await Page.findOne({
  1812. path: _path,
  1813. grantedGroups: { $elemMatch: { item: groupIdA } },
  1814. });
  1815. const page1 = await Page.findOne({
  1816. path: `/trash${_path}`,
  1817. grantedGroups: { $elemMatch: { item: groupIdA } },
  1818. });
  1819. expect(pageN).toBeNull();
  1820. expect(page1).toBeTruthy();
  1821. expect(page1?.status).toBe(Page.STATUS_DELETED);
  1822. expect(page1?.descendantCount).toBe(0);
  1823. expect(page1?.parent).toBeNull();
  1824. });
  1825. });
  1826. describe('Delete multiple pages with grant USER_GROUP', () => {
  1827. test('should be able to delete all descendants except page with GRANT_RESTRICTED', async () => {
  1828. const _pathT = '/npdel3_top';
  1829. const _path1 = '/npdel3_top/npdel4_ug';
  1830. const _path2 = '/npdel3_top/npdel4_ug/npdel5_ug';
  1831. const _pageT = await Page.findOne({
  1832. path: _pathT,
  1833. grant: Page.GRANT_USER_GROUP,
  1834. grantedGroups: { $elemMatch: { item: groupIdA } },
  1835. }); // A
  1836. const _page1 = await Page.findOne({
  1837. path: _path1,
  1838. grant: Page.GRANT_USER_GROUP,
  1839. grantedGroups: { $elemMatch: { item: groupIdB } },
  1840. }); // B
  1841. const _page2 = await Page.findOne({
  1842. path: _path2,
  1843. grant: Page.GRANT_USER_GROUP,
  1844. grantedGroups: { $elemMatch: { item: groupIdC } },
  1845. }); // C
  1846. const _pageR = await Page.findOne({
  1847. path: _path1,
  1848. grant: Page.GRANT_RESTRICTED,
  1849. }); // Restricted
  1850. expect(_pageT).toBeTruthy();
  1851. expect(_page1).toBeTruthy();
  1852. expect(_page2).toBeTruthy();
  1853. expect(_pageR).toBeTruthy();
  1854. const isRecursively = true;
  1855. await deletePage(_pageT, npDummyUser1, {}, isRecursively, {
  1856. ip: '::ffff:127.0.0.1',
  1857. endpoint: '/_api/v3/pages/rename',
  1858. });
  1859. const pageTNotExist = await Page.findOne({
  1860. path: _pathT,
  1861. grant: Page.GRANT_USER_GROUP,
  1862. grantedGroups: { $elemMatch: { item: groupIdA } },
  1863. }); // A should not exist
  1864. const page1NotExist = await Page.findOne({
  1865. path: _path1,
  1866. grant: Page.GRANT_USER_GROUP,
  1867. grantedGroups: { $elemMatch: { item: groupIdB } },
  1868. }); // B should not exist
  1869. const page2NotExist = await Page.findOne({
  1870. path: _path2,
  1871. grant: Page.GRANT_USER_GROUP,
  1872. grantedGroups: { $elemMatch: { item: groupIdC } },
  1873. }); // C should not exist
  1874. const pageT = await Page.findOne({
  1875. path: `/trash${_pathT}`,
  1876. grant: Page.GRANT_USER_GROUP,
  1877. grantedGroups: { $elemMatch: { item: groupIdA } },
  1878. }); // A
  1879. const page1 = await Page.findOne({
  1880. path: `/trash${_path1}`,
  1881. grant: Page.GRANT_USER_GROUP,
  1882. grantedGroups: { $elemMatch: { item: groupIdB } },
  1883. }); // B
  1884. const page2 = await Page.findOne({
  1885. path: `/trash${_path2}`,
  1886. grant: Page.GRANT_USER_GROUP,
  1887. grantedGroups: { $elemMatch: { item: groupIdC } },
  1888. }); // C
  1889. const pageR = await Page.findOne({
  1890. path: _path1,
  1891. grant: Page.GRANT_RESTRICTED,
  1892. }); // Restricted
  1893. expect(page1NotExist).toBeNull();
  1894. expect(pageTNotExist).toBeNull();
  1895. expect(page2NotExist).toBeNull();
  1896. expect(pageT).toBeTruthy();
  1897. expect(page1).toBeTruthy();
  1898. expect(page2).toBeTruthy();
  1899. expect(pageR).toBeTruthy();
  1900. expect(pageT?.status).toBe(Page.STATUS_DELETED);
  1901. expect(pageT?.status).toBe(Page.STATUS_DELETED);
  1902. expect(page1?.status).toBe(Page.STATUS_DELETED);
  1903. expect(page1?.descendantCount).toBe(0);
  1904. expect(page2?.descendantCount).toBe(0);
  1905. expect(page2?.descendantCount).toBe(0);
  1906. expect(pageT?.parent).toBeNull();
  1907. expect(page1?.parent).toBeNull();
  1908. expect(page2?.parent).toBeNull();
  1909. });
  1910. });
  1911. });
  1912. describe('Delete completely', () => {
  1913. const deleteCompletely = async (
  1914. page,
  1915. user,
  1916. options = {},
  1917. isRecursively = false,
  1918. preventEmitting = false,
  1919. activityParameters?,
  1920. ) => {
  1921. const mockedDeleteCompletelyRecursivelyMainOperation = jest
  1922. .spyOn(crowi.pageService, 'deleteCompletelyRecursivelyMainOperation')
  1923. .mockReturnValue(null);
  1924. await crowi.pageService.deleteCompletely(
  1925. page,
  1926. user,
  1927. options,
  1928. isRecursively,
  1929. preventEmitting,
  1930. activityParameters,
  1931. );
  1932. const argsForDeleteCompletelyRecursivelyMainOperation =
  1933. mockedDeleteCompletelyRecursivelyMainOperation.mock.calls[0];
  1934. mockedDeleteCompletelyRecursivelyMainOperation.mockRestore();
  1935. if (isRecursively) {
  1936. await crowi.pageService.deleteCompletelyRecursivelyMainOperation(
  1937. ...(argsForDeleteCompletelyRecursivelyMainOperation as Parameters<
  1938. typeof crowi.pageService.deleteCompletelyRecursivelyMainOperation
  1939. >),
  1940. );
  1941. }
  1942. return;
  1943. };
  1944. describe('Delete single page with grant RESTRICTED', () => {
  1945. test('should be able to delete completely', async () => {
  1946. const _path = '/npdc1_awl';
  1947. const _page = await Page.findOne({
  1948. path: _path,
  1949. grant: Page.GRANT_RESTRICTED,
  1950. });
  1951. expect(_page).toBeTruthy();
  1952. await deleteCompletely(_page, dummyUser1, {}, false, false, {
  1953. ip: '::ffff:127.0.0.1',
  1954. endpoint: '/_api/v3/pages/rename',
  1955. });
  1956. const page = await Page.findOne({
  1957. path: _path,
  1958. grant: Page.GRANT_RESTRICTED,
  1959. });
  1960. expect(page).toBeNull();
  1961. });
  1962. });
  1963. describe('Delete single page with grant USER_GROUP', () => {
  1964. test('should be able to delete completely', async () => {
  1965. const _path = '/npdc2_ug';
  1966. const _page = await Page.findOne({
  1967. path: _path,
  1968. grant: Page.GRANT_USER_GROUP,
  1969. grantedGroups: { $elemMatch: { item: groupIdA } },
  1970. });
  1971. expect(_page).toBeTruthy();
  1972. await deleteCompletely(_page, npDummyUser1, {}, false, false, {
  1973. ip: '::ffff:127.0.0.1',
  1974. endpoint: '/_api/v3/pages/rename',
  1975. });
  1976. const page = await Page.findOne({
  1977. path: _path,
  1978. grant: Page.GRANT_USER_GROUP,
  1979. grantedGroups: { $elemMatch: { item: groupIdA } },
  1980. });
  1981. expect(page).toBeNull();
  1982. });
  1983. });
  1984. describe('Delete multiple pages with grant USER_GROUP', () => {
  1985. test('should be able to delete all descendants completely except page with GRANT_RESTRICTED', async () => {
  1986. const _path1 = '/npdc3_ug';
  1987. const _path2 = '/npdc3_ug/npdc4_ug';
  1988. const _path3 = '/npdc3_ug/npdc4_ug/npdc5_ug';
  1989. const _page1 = await Page.findOne({
  1990. path: _path1,
  1991. grant: Page.GRANT_USER_GROUP,
  1992. grantedGroups: { $elemMatch: { item: groupIdA } },
  1993. });
  1994. const _page2 = await Page.findOne({
  1995. path: _path2,
  1996. grant: Page.GRANT_USER_GROUP,
  1997. grantedGroups: { $elemMatch: { item: groupIdB } },
  1998. });
  1999. const _page3 = await Page.findOne({
  2000. path: _path3,
  2001. grant: Page.GRANT_USER_GROUP,
  2002. grantedGroups: { $elemMatch: { item: groupIdC } },
  2003. });
  2004. const _page4 = await Page.findOne({
  2005. path: _path2,
  2006. grant: Page.GRANT_RESTRICTED,
  2007. });
  2008. expect(_page1).toBeTruthy();
  2009. expect(_page2).toBeTruthy();
  2010. expect(_page3).toBeTruthy();
  2011. expect(_page4).toBeTruthy();
  2012. await deleteCompletely(_page1, npDummyUser1, {}, true, false, {
  2013. ip: '::ffff:127.0.0.1',
  2014. endpoint: '/_api/v3/pages/rename',
  2015. });
  2016. const page1 = await Page.findOne({
  2017. path: _path1,
  2018. grant: Page.GRANT_USER_GROUP,
  2019. grantedGroups: { $elemMatch: { item: groupIdA } },
  2020. });
  2021. const page2 = await Page.findOne({
  2022. path: _path2,
  2023. grant: Page.GRANT_USER_GROUP,
  2024. grantedGroups: { $elemMatch: { item: groupIdB } },
  2025. });
  2026. const page3 = await Page.findOne({
  2027. path: _path3,
  2028. grant: Page.GRANT_USER_GROUP,
  2029. grantedGroups: { $elemMatch: { item: groupIdC } },
  2030. });
  2031. const page4 = await Page.findOne({
  2032. path: _path2,
  2033. grant: Page.GRANT_RESTRICTED,
  2034. });
  2035. expect(page1).toBeNull();
  2036. expect(page2).toBeNull();
  2037. expect(page3).toBeNull();
  2038. expect(page4).toBeTruthy();
  2039. });
  2040. });
  2041. });
  2042. describe('revert', () => {
  2043. const revertDeletedPage = async (
  2044. page,
  2045. user,
  2046. options = {},
  2047. isRecursively = false,
  2048. activityParameters?,
  2049. ) => {
  2050. // mock return value
  2051. const mockedRevertRecursivelyMainOperation = jest
  2052. .spyOn(crowi.pageService, 'revertRecursivelyMainOperation')
  2053. .mockReturnValue(null);
  2054. const revertedPage = await crowi.pageService.revertDeletedPage(
  2055. page,
  2056. user,
  2057. options,
  2058. isRecursively,
  2059. activityParameters,
  2060. );
  2061. const argsForRecursivelyMainOperation =
  2062. mockedRevertRecursivelyMainOperation.mock.calls[0];
  2063. // restores the original implementation
  2064. mockedRevertRecursivelyMainOperation.mockRestore();
  2065. if (isRecursively) {
  2066. await crowi.pageService.revertRecursivelyMainOperation(
  2067. ...(argsForRecursivelyMainOperation as Parameters<
  2068. typeof crowi.pageService.revertRecursivelyMainOperation
  2069. >),
  2070. );
  2071. }
  2072. return revertedPage;
  2073. };
  2074. test('should revert single deleted page with GRANT_RESTRICTED', async () => {
  2075. const trashedPage = await Page.findOne({
  2076. path: '/trash/np_revert1',
  2077. status: Page.STATUS_DELETED,
  2078. grant: Page.GRANT_RESTRICTED,
  2079. });
  2080. const revision = await Revision.findOne({ pageId: trashedPage?._id });
  2081. const tag = await Tag.findOne({ name: 'np_revertTag1' });
  2082. const deletedPageTagRelation = await PageTagRelation.findOne({
  2083. relatedPage: trashedPage?._id,
  2084. relatedTag: tag?._id,
  2085. isPageTrashed: true,
  2086. });
  2087. expect(trashedPage).toBeTruthy();
  2088. expect(revision).toBeTruthy();
  2089. expect(tag).toBeTruthy();
  2090. expect(deletedPageTagRelation).toBeTruthy();
  2091. await revertDeletedPage(trashedPage, dummyUser1, {}, false, {
  2092. ip: '::ffff:127.0.0.1',
  2093. endpoint: '/_api/v3/pages/rename',
  2094. });
  2095. const revertedPage = await Page.findOne({ path: '/np_revert1' });
  2096. const deltedPageBeforeRevert = await Page.findOne({
  2097. path: '/trash/np_revert1',
  2098. });
  2099. const pageTagRelation = await PageTagRelation.findOne<IPageTagRelation>({
  2100. relatedPage: revertedPage?._id,
  2101. relatedTag: tag?._id,
  2102. });
  2103. expect(revertedPage).toBeTruthy();
  2104. expect(pageTagRelation).toBeTruthy();
  2105. expect(deltedPageBeforeRevert).toBeNull();
  2106. // page with GRANT_RESTRICTED does not have parent
  2107. expect(revertedPage?.parent).toBeNull();
  2108. expect(revertedPage?.status).toBe(Page.STATUS_PUBLISHED);
  2109. expect(revertedPage?.grant).toBe(Page.GRANT_RESTRICTED);
  2110. expect(pageTagRelation?.isPageTrashed).toBe(false);
  2111. });
  2112. test('should revert single deleted page with GRANT_USER_GROUP', async () => {
  2113. const beforeRevertPath = '/trash/np_revert2';
  2114. const user1 = await User.findOne({ name: 'npUser1' });
  2115. const trashedPage = await Page.findOne({
  2116. path: beforeRevertPath,
  2117. status: Page.STATUS_DELETED,
  2118. grant: Page.GRANT_USER_GROUP,
  2119. });
  2120. const revision = await Revision.findOne({ pageId: trashedPage?._id });
  2121. const tag = await Tag.findOne({ name: 'np_revertTag2' });
  2122. const deletedPageTagRelation = await PageTagRelation.findOne({
  2123. relatedPage: trashedPage?._id,
  2124. relatedTag: tag?._id,
  2125. isPageTrashed: true,
  2126. });
  2127. expect(trashedPage).toBeTruthy();
  2128. expect(revision).toBeTruthy();
  2129. expect(tag).toBeTruthy();
  2130. expect(deletedPageTagRelation).toBeTruthy();
  2131. await revertDeletedPage(trashedPage, user1, {}, false, {
  2132. ip: '::ffff:127.0.0.1',
  2133. endpoint: '/_api/v3/pages/revert',
  2134. });
  2135. const revertedPage = await Page.findOne({ path: '/np_revert2' });
  2136. const trashedPageBR = await Page.findOne({ path: beforeRevertPath });
  2137. const pageTagRelation = await PageTagRelation.findOne<IPageTagRelation>({
  2138. relatedPage: revertedPage?._id,
  2139. relatedTag: tag?._id,
  2140. });
  2141. expect(revertedPage).toBeTruthy();
  2142. expect(pageTagRelation).toBeTruthy();
  2143. expect(trashedPageBR).toBeNull();
  2144. expect(revertedPage?.parent).toStrictEqual(rootPage._id);
  2145. expect(revertedPage?.status).toBe(Page.STATUS_PUBLISHED);
  2146. expect(revertedPage?.grant).toBe(Page.GRANT_USER_GROUP);
  2147. expect(normalizeGrantedGroups(revertedPage?.grantedGroups)).toStrictEqual(
  2148. [
  2149. { item: groupIdA, type: GroupType.userGroup },
  2150. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  2151. ],
  2152. );
  2153. expect(pageTagRelation?.isPageTrashed).toBe(false);
  2154. });
  2155. test(`revert multiple pages: only target page should be reverted.
  2156. Non-existant middle page and leaf page with GRANT_RESTRICTED shoud not be reverted`, async () => {
  2157. const beforeRevertPath1 = '/trash/np_revert3';
  2158. const beforeRevertPath2 = '/trash/np_revert3/middle/np_revert4';
  2159. const trashedPage1 = await Page.findOne({
  2160. path: beforeRevertPath1,
  2161. status: Page.STATUS_DELETED,
  2162. grant: Page.GRANT_PUBLIC,
  2163. });
  2164. const trashedPage2 = await Page.findOne({
  2165. path: beforeRevertPath2,
  2166. status: Page.STATUS_DELETED,
  2167. grant: Page.GRANT_RESTRICTED,
  2168. });
  2169. const revision1 = await Revision.findOne({ pageId: trashedPage1?._id });
  2170. const revision2 = await Revision.findOne({ pageId: trashedPage2?._id });
  2171. expect(trashedPage1).toBeTruthy();
  2172. expect(trashedPage2).toBeTruthy();
  2173. expect(revision1).toBeTruthy();
  2174. expect(revision2).toBeTruthy();
  2175. await revertDeletedPage(trashedPage1, npDummyUser2, {}, true, {
  2176. ip: '::ffff:127.0.0.1',
  2177. endpoint: '/_api/v3/pages/revert',
  2178. });
  2179. const revertedPage = await Page.findOne({ path: '/np_revert3' });
  2180. const middlePage = await Page.findOne({ path: '/np_revert3/middle' });
  2181. const notRestrictedPage = await Page.findOne({
  2182. path: '/np_revert3/middle/np_revert4',
  2183. });
  2184. // AR => After Revert
  2185. const trashedPage1AR = await Page.findOne({ path: beforeRevertPath1 });
  2186. const trashedPage2AR = await Page.findOne({ path: beforeRevertPath2 });
  2187. const revision1AR = await Revision.findOne({ pageId: revertedPage?._id });
  2188. const revision2AR = await Revision.findOne({
  2189. pageId: trashedPage2AR?._id,
  2190. });
  2191. expect(revertedPage).toBeTruthy();
  2192. expect(trashedPage2AR).toBeTruthy();
  2193. expect(revision1AR).toBeTruthy();
  2194. expect(revision2AR).toBeTruthy();
  2195. expect(trashedPage1AR).toBeNull();
  2196. expect(notRestrictedPage).toBeNull();
  2197. expect(middlePage).toBeNull();
  2198. expect(revertedPage?.parent).toStrictEqual(rootPage._id);
  2199. expect(revertedPage?.status).toBe(Page.STATUS_PUBLISHED);
  2200. expect(revertedPage?.grant).toBe(Page.GRANT_PUBLIC);
  2201. });
  2202. test('revert multiple pages: target page, initially non-existant page and leaf page with GRANT_USER_GROUP shoud be reverted', async () => {
  2203. const user = await User.findOne({ _id: npDummyUser3 });
  2204. const beforeRevertPath1 = '/trash/np_revert5';
  2205. const beforeRevertPath2 = '/trash/np_revert5/middle/np_revert6';
  2206. const beforeRevertPath3 = '/trash/np_revert5/middle';
  2207. const trashedPage1 = await Page.findOne({
  2208. path: beforeRevertPath1,
  2209. status: Page.STATUS_DELETED,
  2210. grantedGroups: { $elemMatch: { item: groupIdA } },
  2211. });
  2212. const trashedPage2 = await Page.findOne({
  2213. path: beforeRevertPath2,
  2214. status: Page.STATUS_DELETED,
  2215. grantedGroups: { $elemMatch: { item: groupIdB } },
  2216. });
  2217. const nonExistantPage3 = await Page.findOne({ path: beforeRevertPath3 }); // not exist
  2218. const revision1 = await Revision.findOne({ pageId: trashedPage1?._id });
  2219. const revision2 = await Revision.findOne({ pageId: trashedPage2?._id });
  2220. expect(trashedPage1).toBeTruthy();
  2221. expect(trashedPage2).toBeTruthy();
  2222. expect(revision1).toBeTruthy();
  2223. expect(revision2).toBeTruthy();
  2224. expect(user).toBeTruthy();
  2225. expect(nonExistantPage3).toBeNull();
  2226. await revertDeletedPage(trashedPage1, user, {}, true, {
  2227. ip: '::ffff:127.0.0.1',
  2228. endpoint: '/_api/v3/pages/revert',
  2229. });
  2230. const revertedPage1 = await Page.findOne({ path: '/np_revert5' });
  2231. const newlyCreatedPage = await Page.findOne({
  2232. path: '/np_revert5/middle',
  2233. });
  2234. const revertedPage2 = await Page.findOne({
  2235. path: '/np_revert5/middle/np_revert6',
  2236. });
  2237. // // AR => After Revert
  2238. const trashedPage1AR = await Page.findOne({ path: beforeRevertPath1 });
  2239. const trashedPage2AR = await Page.findOne({ path: beforeRevertPath2 });
  2240. expect(revertedPage1).toBeTruthy();
  2241. expect(newlyCreatedPage).toBeTruthy();
  2242. expect(revertedPage2).toBeTruthy();
  2243. expect(trashedPage1AR).toBeNull();
  2244. expect(trashedPage2AR).toBeNull();
  2245. expect(newlyCreatedPage?.isEmpty).toBe(true);
  2246. expect(revertedPage1?.parent).toStrictEqual(rootPage._id);
  2247. expect(revertedPage2?.parent).toStrictEqual(newlyCreatedPage?._id);
  2248. expect(newlyCreatedPage?.parent).toStrictEqual(revertedPage1?._id);
  2249. expect(revertedPage1?.status).toBe(Page.STATUS_PUBLISHED);
  2250. expect(revertedPage2?.status).toBe(Page.STATUS_PUBLISHED);
  2251. expect(newlyCreatedPage?.status).toBe(Page.STATUS_PUBLISHED);
  2252. expect(
  2253. normalizeGrantedGroups(revertedPage1?.grantedGroups),
  2254. ).toStrictEqual([
  2255. { item: groupIdA, type: GroupType.userGroup },
  2256. { item: externalGroupIdA, type: GroupType.externalUserGroup },
  2257. ]);
  2258. expect(
  2259. normalizeGrantedGroups(revertedPage2?.grantedGroups),
  2260. ).toStrictEqual([
  2261. { item: groupIdB, type: GroupType.userGroup },
  2262. { item: externalGroupIdB, type: GroupType.externalUserGroup },
  2263. ]);
  2264. expect(newlyCreatedPage?.grant).toBe(Page.GRANT_PUBLIC);
  2265. });
  2266. });
  2267. });