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

Merge pull request #3241 from weseek/imprv/refactoring-page.js-delete-action

Imprv/refactoring page.js delete action
Sizma yosimaz 5 лет назад
Родитель
Сommit
890316f9da

+ 1 - 87
src/server/models/page.js

@@ -1141,30 +1141,6 @@ module.exports = function(crowi) {
     }));
   };
 
-  // TODO: transplant to service/page.js because page deletion affects various models data
-  pageSchema.statics.revertDeletedPage = async function(page, user, options = {}) {
-    const newPath = this.getRevertDeletedPageName(page.path);
-
-    const originPage = await this.findByPath(newPath);
-    if (originPage != null) {
-      // 削除時、元ページの path には必ず redirectTo 付きで、ページが作成される。
-      // そのため、そいつは削除してOK
-      // が、redirectTo ではないページが存在している場合それは何かがおかしい。(データ補正が必要)
-      if (originPage.redirectTo !== page.path) {
-        throw new Error('The new page of to revert is exists and the redirect path of the page is not the deleted page.');
-      }
-
-      await this.completelyDeletePage(originPage, options);
-    }
-
-    page.status = STATUS_PUBLISHED;
-    page.lastUpdateUser = user;
-    debug('Revert deleted the page', page, newPath);
-    const updatedPage = await this.rename(page, newPath, user, {});
-
-    return updatedPage;
-  };
-
   pageSchema.statics.revertDeletedPageRecursively = async function(targetPage, user, options = {}) {
     const findOpts = { includeTrashed: true };
     const pages = await this.findManageableListWithDescendants(targetPage, user, findOpts);
@@ -1172,7 +1148,7 @@ module.exports = function(crowi) {
     let updatedPage = null;
     await Promise.all(pages.map((page) => {
       const isParent = (page.path === targetPage.path);
-      const p = this.revertDeletedPage(page, user, options);
+      const p = crowi.pageService.revertDeletedPage(page, user, options);
       if (isParent) {
         updatedPage = p;
       }
@@ -1182,41 +1158,6 @@ module.exports = function(crowi) {
     return updatedPage;
   };
 
-  /**
-   * This is danger.
-   */
-  // TODO: transplant to service/page.js because page deletion affects various models data
-  pageSchema.statics.completelyDeletePage = async function(pageData, user, options = {}) {
-    validateCrowi();
-
-    const { _id, path } = pageData;
-    const socketClientId = options.socketClientId || null;
-
-    logger.debug('Deleting completely', path);
-
-    await crowi.pageService.deleteCompletely(_id, path);
-
-    if (socketClientId != null) {
-      pageEvent.emit('delete', pageData, user, socketClientId); // update as renamed page
-    }
-    return pageData;
-  };
-
-  /**
-   * Delete Bookmarks, Attachments, Revisions, Pages and emit delete
-   */
-  // TODO: transplant to service/page.js because page deletion affects various models data
-  pageSchema.statics.completelyDeletePageRecursively = async function(targetPage, user, options = {}) {
-    const findOpts = { includeTrashed: true };
-
-    // find manageable descendants (this array does not include GRANT_RESTRICTED)
-    const pages = await this.findManageableListWithDescendants(targetPage, user, findOpts);
-
-    await Promise.all(pages.map((page) => {
-      return this.completelyDeletePage(page, user, options);
-    }));
-  };
-
   pageSchema.statics.removeByPath = function(path) {
     if (path == null) {
       throw new Error('path is required');
@@ -1314,33 +1255,6 @@ module.exports = function(crowi) {
     return await queryBuilder.query.exec();
   };
 
-  // TODO: transplant to service/page.js because page deletion affects various models data
-  pageSchema.statics.handlePrivatePagesForDeletedGroup = async function(deletedGroup, action, transferToUserGroupId) {
-    const Page = mongoose.model('Page');
-
-    const pages = await this.find({ grantedGroup: deletedGroup });
-
-    switch (action) {
-      case 'public':
-        await Promise.all(pages.map((page) => {
-          return Page.publicizePage(page);
-        }));
-        break;
-      case 'delete':
-        await Promise.all(pages.map((page) => {
-          return Page.completelyDeletePage(page);
-        }));
-        break;
-      case 'transfer':
-        await Promise.all(pages.map((page) => {
-          return Page.transferPageToGroup(page, transferToUserGroupId);
-        }));
-        break;
-      default:
-        throw new Error('Unknown action for private pages');
-    }
-  };
-
   pageSchema.statics.publicizePage = async function(page) {
     page.grantedGroup = null;
     page.grant = GRANT_PUBLIC;

+ 1 - 2
src/server/models/user-group.js

@@ -92,7 +92,6 @@ class UserGroup {
   // グループの完全削除
   static async removeCompletelyById(deleteGroupId, action, transferToUserGroupId) {
     const UserGroupRelation = mongoose.model('UserGroupRelation');
-    const Page = mongoose.model('Page');
 
     const groupToDelete = await this.findById(deleteGroupId);
     if (groupToDelete == null) {
@@ -102,7 +101,7 @@ class UserGroup {
 
     await Promise.all([
       UserGroupRelation.removeAllByUserGroup(deletedGroup),
-      Page.handlePrivatePagesForDeletedGroup(deletedGroup, action, transferToUserGroupId),
+      UserGroup.crowi.pageService.handlePrivatePagesForDeletedGroup(deletedGroup, action, transferToUserGroupId),
     ]);
 
     return deletedGroup;

+ 1 - 1
src/server/routes/apiv3/pages.js

@@ -432,7 +432,7 @@ module.exports = (crowi) => {
    */
   router.delete('/empty-trash', loginRequired, adminRequired, csrf, async(req, res) => {
     try {
-      const pages = await Page.completelyDeletePageRecursively({ path: '/trash' }, req.user);
+      const pages = await crowi.pageService.completelyDeletePageRecursively({ path: '/trash' }, req.user);
       return res.apiv3({ pages });
     }
     catch (err) {

+ 3 - 3
src/server/routes/page.js

@@ -1194,10 +1194,10 @@ module.exports = function(crowi, app) {
           return res.json(ApiResponse.error('You can not delete completely', 'user_not_admin'));
         }
         if (isRecursively) {
-          await Page.completelyDeletePageRecursively(page, req.user, options);
+          await crowi.pageService.completelyDeletePageRecursively(page, req.user, options);
         }
         else {
-          await Page.completelyDeletePage(page, req.user, options);
+          await crowi.pageService.completelyDeletePage(page, req.user, options);
         }
       }
       else {
@@ -1258,7 +1258,7 @@ module.exports = function(crowi, app) {
         page = await Page.revertDeletedPageRecursively(page, req.user, { socketClientId });
       }
       else {
-        page = await Page.revertDeletedPage(page, req.user, { socketClientId });
+        page = await crowi.pageService.revertDeletedPage(page, req.user, { socketClientId });
       }
     }
     catch (err) {

+ 95 - 0
src/server/service/page.js

@@ -1,7 +1,11 @@
 const mongoose = require('mongoose');
 const escapeStringRegexp = require('escape-string-regexp');
+const logger = require('@alias/logger')('growi:models:page');
+const debug = require('debug')('growi:models:page');
 const { serializePageSecurely } = require('../models/serializers/page-serializer');
 
+const STATUS_PUBLISHED = 'published';
+
 class PageService {
 
   constructor(crowi) {
@@ -95,6 +99,97 @@ class PageService {
   }
 
 
+  async completelyDeletePage(pageData, user, options = {}) {
+    this.validateCrowi();
+    let pageEvent;
+    // init event
+    if (this.crowi != null) {
+      pageEvent = this.crowi.event('page');
+      pageEvent.on('create', pageEvent.onCreate);
+      pageEvent.on('update', pageEvent.onUpdate);
+    }
+
+    const { _id, path } = pageData;
+    const socketClientId = options.socketClientId || null;
+
+    logger.debug('Deleting completely', path);
+
+    await this.deleteCompletely(_id, path);
+
+    if (socketClientId != null) {
+      pageEvent.emit('delete', pageData, user, socketClientId); // update as renamed page
+    }
+    return pageData;
+  }
+
+  /**
+   * Delete Bookmarks, Attachments, Revisions, Pages and emit delete
+   */
+  async completelyDeletePageRecursively(targetPage, user, options = {}) {
+    const findOpts = { includeTrashed: true };
+    const Page = this.crowi.model('Page');
+
+    // find manageable descendants (this array does not include GRANT_RESTRICTED)
+    const pages = await Page.findManageableListWithDescendants(targetPage, user, findOpts);
+
+    await Promise.all(pages.map((page) => {
+      return this.completelyDeletePage(page, user, options);
+    }));
+  }
+
+
+  async revertDeletedPage(page, user, options = {}) {
+    const Page = this.crowi.model('Page');
+    const newPath = Page.getRevertDeletedPageName(page.path);
+    const originPage = await Page.findByPath(newPath);
+    if (originPage != null) {
+      // When the page is deleted, it will always be created with "redirectTo" in the path of the original page.
+      // So, it's ok to delete the page
+      // However, If a page exists that is not "redirectTo", something is wrong. (Data correction is needed).
+      if (originPage.redirectTo !== page.path) {
+        throw new Error('The new page of to revert is exists and the redirect path of the page is not the deleted page.');
+      }
+      await this.completelyDeletePage(originPage, options);
+    }
+
+    page.status = STATUS_PUBLISHED;
+    page.lastUpdateUser = user;
+    debug('Revert deleted the page', page, newPath);
+    const updatedPage = await Page.rename(page, newPath, user, {});
+    return updatedPage;
+  }
+
+  async handlePrivatePagesForDeletedGroup(deletedGroup, action, transferToUserGroupId) {
+    const Page = this.crowi.model('Page');
+    const pages = await Page.find({ grantedGroup: deletedGroup });
+
+    switch (action) {
+      case 'public':
+        await Promise.all(pages.map((page) => {
+          return Page.publicizePage(page);
+        }));
+        break;
+      case 'delete':
+        await Promise.all(pages.map((page) => {
+          return this.completelyDeletePage(page);
+        }));
+        break;
+      case 'transfer':
+        await Promise.all(pages.map((page) => {
+          return Page.transferPageToGroup(page, transferToUserGroupId);
+        }));
+        break;
+      default:
+        throw new Error('Unknown action for private pages');
+    }
+  }
+
+  validateCrowi() {
+    if (this.crowi == null) {
+      throw new Error('"crowi" is null. Init User model with "crowi" argument first.');
+    }
+  }
+
 }
 
 module.exports = PageService;