Просмотр исходного кода

Merge branch 'imprv/refacter-recursively' into imprv/4685-4990-impl-test-for-deleteDescendants

itizawa 5 лет назад
Родитель
Сommit
eb94f82041
2 измененных файлов с 158 добавлено и 16 удалено
  1. 5 3
      src/server/service/page.js
  2. 153 13
      src/test/service/page.test.js

+ 5 - 3
src/server/service/page.js

@@ -232,6 +232,8 @@ class PageService {
     options.grantUserGroupId = page.grantedGroup;
     options.grantedUsers = page.grantedUsers;
 
+    newPagePath = this.crowi.xss.process(newPagePath); // eslint-disable-line no-param-reassign
+
     const createdPage = await Page.create(
       newPagePath, page.revision.body, user, options,
     );
@@ -594,7 +596,7 @@ class PageService {
       .pipe(writeStream);
   }
 
-  async revertDeletedPages(pages, user) {
+  async revertDeletedDescendants(pages, user) {
     const Page = this.crowi.model('Page');
     const pageCollection = mongoose.connection.collection('pages');
     const revisionCollection = mongoose.connection.collection('revisions');
@@ -692,14 +694,14 @@ class PageService {
       .lean()
       .cursor();
 
-    const revertDeletedPages = this.revertDeletedPages.bind(this);
+    const revertDeletedDescendants = this.revertDeletedDescendants.bind(this);
     let count = 0;
     const writeStream = new Writable({
       objectMode: true,
       async write(batch, encoding, callback) {
         try {
           count += batch.length;
-          revertDeletedPages(batch, user);
+          revertDeletedDescendants(batch, user);
           logger.debug(`Reverting pages progressing: (count=${count})`);
         }
         catch (err) {

+ 153 - 13
src/test/service/page.test.js

@@ -25,10 +25,13 @@ let parentForDelete2;
 let childForDelete;
 
 let parentForDeleteCompletely;
-let parentForRevert;
+
+let parentForRevert1;
+let parentForRevert2;
 
 let childForDuplicate;
 let childForDeleteCompletely;
+
 let childForRevert;
 
 describe('PageService', () => {
@@ -39,6 +42,7 @@ describe('PageService', () => {
   let User;
   let Tag;
   let PageTagRelation;
+  let xssSpy;
 
   beforeAll(async(done) => {
     crowi = await getInstance();
@@ -105,6 +109,7 @@ describe('PageService', () => {
         grant: Page.GRANT_PUBLIC,
         creator: testUser1,
         lastUpdateUser: testUser1,
+        revision: '600d395667536503354cbe91',
       },
       {
         path: '/parentForDuplicate/child',
@@ -143,13 +148,22 @@ describe('PageService', () => {
         lastUpdateUser: testUser1,
       },
       {
-        path: '/parentForRevert',
+        path: '/trash/parentForRevert1',
+        status: Page.STATUS_DELETED,
+        grant: Page.GRANT_PUBLIC,
+        creator: testUser1,
+        lastUpdateUser: testUser1,
+      },
+      {
+        path: '/trash/parentForRevert2',
+        status: Page.STATUS_DELETED,
         grant: Page.GRANT_PUBLIC,
         creator: testUser1,
         lastUpdateUser: testUser1,
       },
       {
-        path: '/parentForRevert/child',
+        path: '/trash/parentForRevert/child',
+        status: Page.STATUS_DELETED,
         grant: Page.GRANT_PUBLIC,
         creator: testUser1,
         lastUpdateUser: testUser1,
@@ -167,7 +181,8 @@ describe('PageService', () => {
     parentForDelete2 = await Page.findOne({ path: '/parentForDelete2' });
 
     parentForDeleteCompletely = await Page.findOne({ path: '/parentForDeleteCompletely' });
-    parentForRevert = await Page.findOne({ path: '/parentForRevert' });
+    parentForRevert1 = await Page.findOne({ path: '/trash/parentForRevert1' });
+    parentForRevert2 = await Page.findOne({ path: '/trash/parentForRevert2' });
 
     childForRename1 = await Page.findOne({ path: '/parentForRename1/child' });
     childForRename2 = await Page.findOne({ path: '/parentForRename2/child' });
@@ -176,7 +191,7 @@ describe('PageService', () => {
     childForDuplicate = await Page.findOne({ path: '/parentForDuplicate/child' });
     childForDelete = await Page.findOne({ path: '/parentForDelete/child' });
     childForDeleteCompletely = await Page.findOne({ path: '/parentForDeleteCompletely/child' });
-    childForRevert = await Page.findOne({ path: '/parentForRevert/child' });
+    childForRevert = await Page.findOne({ path: '/trash/parentForRevert/child' });
 
 
     await Tag.insertMany([
@@ -192,11 +207,21 @@ describe('PageService', () => {
       { relatedPage: childForDuplicate, relatedTag: childTag },
     ]);
 
+    await Revision.insertMany([
+      {
+        _id: '600d395667536503354cbe91',
+        path: parentForDuplicate,
+        body: 'duplicateBody',
+      },
+    ]);
+
+    xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
+
+
     done();
   });
 
   describe('rename page', () => {
-    let xssSpy;
     let pageEventSpy;
     let renameDescendantsWithStreamSpy;
     const dateToUse = new Date('2000-01-01');
@@ -204,7 +229,6 @@ describe('PageService', () => {
 
     beforeEach(async(done) => {
       jest.spyOn(global.Date, 'now').mockImplementation(() => dateToUse);
-      xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
       pageEventSpy = jest.spyOn(crowi.pageService.pageEvent, 'emit').mockImplementation();
       renameDescendantsWithStreamSpy = jest.spyOn(crowi.pageService, 'renameDescendantsWithStream').mockImplementation();
       done();
@@ -363,8 +387,55 @@ describe('PageService', () => {
 
 
   describe('duplicate page', () => {
-    test('duplicate()', () => {
-      expect(3).toBe(3);
+    let duplicateDescendantsWithStreamSpy;
+
+    jest.mock('../../server/models/serializers/page-serializer');
+    const { serializePageSecurely } = require('../../server/models/serializers/page-serializer');
+    serializePageSecurely.mockImplementation(page => page);
+
+    beforeEach(async(done) => {
+      duplicateDescendantsWithStreamSpy = jest.spyOn(crowi.pageService, 'duplicateDescendantsWithStream').mockImplementation();
+      done();
+    });
+
+    test('duplicate page (isRecursively: false)', async() => {
+      const dummyId = '600d395667536503354c9999';
+      crowi.models.Page.findRelatedTagsById = jest.fn().mockImplementation(() => { return parentTag });
+      const originTagsMock = jest.spyOn(Page, 'findRelatedTagsById').mockImplementation(() => { return parentTag });
+      jest.spyOn(PageTagRelation, 'updatePageTags').mockImplementation(() => { return [dummyId, parentTag.name] });
+      jest.spyOn(PageTagRelation, 'listTagNamesByPage').mockImplementation(() => { return [parentTag.name] });
+
+      const resultPage = await crowi.pageService.duplicate(parentForDuplicate, '/newParentDuplicate', testUser2, false);
+      const duplicatedToPageRevision = await Revision.findOne({ path: '/newParentDuplicate' });
+
+      expect(xssSpy).toHaveBeenCalled();
+      expect(duplicateDescendantsWithStreamSpy).not.toHaveBeenCalled();
+      expect(serializePageSecurely).toHaveBeenCalled();
+      expect(resultPage.path).toBe('/newParentDuplicate');
+      expect(resultPage.lastUpdateUser._id).toEqual(testUser2._id);
+      expect(duplicatedToPageRevision._id).not.toEqual(parentForDuplicate.revision._id);
+      expect(resultPage.grant).toEqual(parentForDuplicate.grant);
+      expect(resultPage.tags).toEqual([originTagsMock().name]);
+    });
+
+    test('duplicate page (isRecursively: true)', async() => {
+      const dummyId = '600d395667536503354c9999';
+      crowi.models.Page.findRelatedTagsById = jest.fn().mockImplementation(() => { return parentTag });
+      const originTagsMock = jest.spyOn(Page, 'findRelatedTagsById').mockImplementation(() => { return parentTag });
+      jest.spyOn(PageTagRelation, 'updatePageTags').mockImplementation(() => { return [dummyId, parentTag.name] });
+      jest.spyOn(PageTagRelation, 'listTagNamesByPage').mockImplementation(() => { return [parentTag.name] });
+
+      const resultPageRecursivly = await crowi.pageService.duplicate(parentForDuplicate, '/newParentDuplicateRecursively', testUser2, true);
+      const duplicatedRecursivelyToPageRevision = await Revision.findOne({ path: '/newParentDuplicateRecursively' });
+
+      expect(xssSpy).toHaveBeenCalled();
+      expect(duplicateDescendantsWithStreamSpy).toHaveBeenCalled();
+      expect(serializePageSecurely).toHaveBeenCalled();
+      expect(resultPageRecursivly.path).toBe('/newParentDuplicateRecursively');
+      expect(resultPageRecursivly.lastUpdateUser._id).toEqual(testUser2._id);
+      expect(duplicatedRecursivelyToPageRevision._id).not.toEqual(parentForDuplicate.revision._id);
+      expect(resultPageRecursivly.grant).toEqual(parentForDuplicate.grant);
+      expect(resultPageRecursivly.tags).toEqual([originTagsMock().name]);
     });
 
     test('duplicateDescendants()', () => {
@@ -482,12 +553,81 @@ describe('PageService', () => {
   });
 
   describe('revert page', () => {
-    test('revertDeletedPage()', () => {
-      expect(3).toBe(3);
+    let getRevertDeletedPageNameSpy;
+    let findByPathSpy;
+    let findSpy;
+    let deleteCompletelySpy;
+    let revertDeletedDescendantsWithStreamSpy;
+
+    beforeEach(async(done) => {
+      getRevertDeletedPageNameSpy = jest.spyOn(Page, 'getRevertDeletedPageName');
+      deleteCompletelySpy = jest.spyOn(crowi.pageService, 'deleteCompletely').mockImplementation();
+      revertDeletedDescendantsWithStreamSpy = jest.spyOn(crowi.pageService, 'revertDeletedDescendantsWithStream').mockImplementation();
+      done();
     });
 
-    test('revertDeletedPages()', () => {
-      expect(3).toBe(3);
+    test('revert deleted page when the redirect from page exists', async() => {
+
+      findByPathSpy = jest.spyOn(Page, 'findByPath').mockImplementation(() => {
+        return { redirectTo: '/trash/parentForRevert1' };
+      });
+
+      const resultPage = await crowi.pageService.revertDeletedPage(parentForRevert1, testUser2);
+
+      expect(getRevertDeletedPageNameSpy).toHaveBeenCalledWith(parentForRevert1.path);
+      expect(findByPathSpy).toHaveBeenCalledWith('/parentForRevert1');
+      expect(deleteCompletelySpy).toHaveBeenCalled();
+      expect(revertDeletedDescendantsWithStreamSpy).not.toHaveBeenCalled();
+
+      expect(resultPage.path).toBe('/parentForRevert1');
+      expect(resultPage.lastUpdateUser._id).toEqual(testUser2._id);
+      expect(resultPage.status).toBe(Page.STATUS_PUBLISHED);
+      expect(resultPage.deleteUser).toBeNull();
+      expect(resultPage.deletedAt).toBeNull();
+    });
+
+    test('revert deleted page when the redirect from page does not exist', async() => {
+
+      findByPathSpy = jest.spyOn(Page, 'findByPath').mockImplementation(() => {
+        return null;
+      });
+
+      const resultPage = await crowi.pageService.revertDeletedPage(parentForRevert2, testUser2, {}, true);
+
+      expect(getRevertDeletedPageNameSpy).toHaveBeenCalledWith(parentForRevert2.path);
+      expect(findByPathSpy).toHaveBeenCalledWith('/parentForRevert2');
+      expect(deleteCompletelySpy).not.toHaveBeenCalled();
+      expect(revertDeletedDescendantsWithStreamSpy).toHaveBeenCalled();
+
+      expect(resultPage.path).toBe('/parentForRevert2');
+      expect(resultPage.lastUpdateUser._id).toEqual(testUser2._id);
+      expect(resultPage.status).toBe(Page.STATUS_PUBLISHED);
+      expect(resultPage.deleteUser).toBeNull();
+      expect(resultPage.deletedAt).toBeNull();
+    });
+
+    test('revert deleted descendants', async() => {
+
+      findSpy = jest.spyOn(Page, 'find').mockImplementation(() => {
+        return [{ path: '/parentForRevert/child', redirectTo: '/trash/parentForRevert/child' }];
+      });
+
+      await crowi.pageService.revertDeletedDescendants([childForRevert], testUser2);
+      const resultPage = await Page.findOne({ path: '/parentForRevert/child' });
+      const revrtedFromPage = await Page.findOne({ path: '/trash/parentForRevert/child' });
+      const revrtedFromPageRevision = await Revision.findOne({ path: '/trash/parentForRevert/child' });
+
+      expect(getRevertDeletedPageNameSpy).toHaveBeenCalledWith(childForRevert.path);
+      expect(findSpy).toHaveBeenCalledWith({ path: { $in: ['/parentForRevert/child'] } });
+
+      expect(resultPage.path).toBe('/parentForRevert/child');
+      expect(resultPage.lastUpdateUser._id).toEqual(testUser2._id);
+      expect(resultPage.status).toBe(Page.STATUS_PUBLISHED);
+      expect(resultPage.deleteUser).toBeNull();
+      expect(resultPage.deletedAt).toBeNull();
+
+      expect(revrtedFromPage).toBeNull();
+      expect(revrtedFromPageRevision).toBeNull();
     });
   });