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

Merge pull request #3165 from weseek/feat/gw-4274

feat/gw-4274
takeru0001 5 лет назад
Родитель
Сommit
eede3fbc1a

+ 1 - 1
src/client/js/components/PageDuplicateModal.jsx

@@ -107,7 +107,7 @@ const PageDuplicateModal = (props) => {
     setErrs(null);
 
     try {
-      await appContainer.apiv3Post('/pages/duplicate', { pageId, pageNameInput, isDuplicateRecursively });
+      await appContainer.apiv3Post('/pages/duplicate', { pageId, pageNameInput, isRecursively: isDuplicateRecursively });
       window.location.href = encodeURI(`${pageNameInput}?duplicated=${path}`);
     }
     catch (err) {

+ 2 - 1
src/client/js/services/PageContainer.js

@@ -524,7 +524,7 @@ export default class PageContainer extends Container {
 
   rename(newPagePath, isRecursively, isRenameRedirect, isRemainMetadata) {
     const socketIoContainer = this.appContainer.getContainer('SocketIoContainer');
-    const { pageId, revisionId } = this.state;
+    const { pageId, revisionId, path } = this.state;
 
     return this.appContainer.apiv3Put('/pages/rename', {
       revisionId,
@@ -533,6 +533,7 @@ export default class PageContainer extends Container {
       isRenameRedirect,
       isRemainMetadata,
       newPagePath,
+      path,
       socketClientId: socketIoContainer.getSocketClientId(),
     });
   }

+ 5 - 2
src/server/models/page.js

@@ -1295,13 +1295,16 @@ module.exports = function(crowi) {
     const pages = await this.findManageableListWithDescendants(targetPage, user, options);
 
     // TODO GW-4634 use stream
-    await Promise.allSettled(pages.map((page) => {
+    const promise = pages.map((page) => {
       const newPagePath = page.path.replace(pathRegExp, newPagePathPrefix);
       return this.rename(page, newPagePath, user, options);
-    }));
+    });
+
+    await Promise.allSettled(promise);
 
     targetPage.path = newPagePathPrefix;
     return targetPage;
+
   };
 
   pageSchema.statics.findListByPathsArray = async function(paths) {

+ 16 - 50
src/server/routes/apiv3/pages.js

@@ -3,7 +3,6 @@ const loggerFactory = require('@alias/logger');
 const logger = loggerFactory('growi:routes:apiv3:pages'); // eslint-disable-line no-unused-vars
 const express = require('express');
 const pathUtils = require('growi-commons').pathUtils;
-const escapeStringRegexp = require('escape-string-regexp');
 
 const { body } = require('express-validator/check');
 const { query } = require('express-validator');
@@ -474,49 +473,6 @@ module.exports = (crowi) => {
       return res.apiv3Err(err, 500);
     }
   });
-  async function duplicatePage(page, newPagePath, user) {
-    // populate
-    await page.populate({ path: 'revision', model: 'Revision', select: 'body' }).execPopulate();
-
-    // create option
-    const options = { page };
-    options.grant = page.grant;
-    options.grantUserGroupId = page.grantedGroup;
-    options.grantedUsers = page.grantedUsers;
-
-    const createdPage = await createPageAction({
-      path: newPagePath, user, body: page.revision.body, options,
-    });
-
-    const originTags = await page.findRelatedTagsById();
-    const savedTags = await saveTagsAction({ page, createdPage, pageTags: originTags });
-
-    try {
-      // global notification
-      await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_CREATE, createdPage, user);
-    }
-    catch (err) {
-      logger.error('Create grobal notification failed', err);
-    }
-
-    return { page: serializePageSecurely(createdPage), tags: savedTags };
-  }
-
-  async function duplicatePageRecursively(page, newPagePath, user) {
-    const newPagePathPrefix = newPagePath;
-    const pathRegExp = new RegExp(`^${escapeStringRegexp(page.path)}`, 'i');
-
-    const pages = await Page.findManageableListWithDescendants(page, user);
-
-    const promise = pages.map(async(page) => {
-      const newPagePath = page.path.replace(pathRegExp, newPagePathPrefix);
-      return duplicatePage(page, newPagePath, user);
-    });
-
-    // TODO GW-4634 use stream
-    return Promise.allSettled(promise);
-  }
-
 
   /**
    * @swagger
@@ -557,7 +513,7 @@ module.exports = (crowi) => {
    *            description: Internal server error.
    */
   router.post('/duplicate', accessTokenParser, loginRequiredStrictly, csrf, validator.duplicatePage, apiV3FormValidator, async(req, res) => {
-    const { pageId, isDuplicateRecursively } = req.body;
+    const { pageId, isRecursively } = req.body;
 
     const newPagePath = pathUtils.normalizePath(req.body.pageNameInput);
 
@@ -576,16 +532,26 @@ module.exports = (crowi) => {
       return res.apiv3Err(new ErrorV3('Not Founded the page', 'notfound_or_forbidden'), 404);
     }
 
-    let result;
+    let newParentPage;
 
-    if (isDuplicateRecursively) {
-      result = await duplicatePageRecursively(page, newPagePath, req.user);
+    if (isRecursively) {
+      newParentPage = await crowi.pageService.duplicateRecursively(page, newPagePath, req.user);
     }
     else {
-      result = await duplicatePage(page, newPagePath, req.user);
+      newParentPage = await crowi.pageService.duplicate(page, newPagePath, req.user);
+    }
+
+    const result = { page: serializePageSecurely(newParentPage) };
+
+    page.path = newPagePath;
+    try {
+      await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_CREATE, page, req.user);
+    }
+    catch (err) {
+      logger.error('Create grobal notification failed', err);
     }
 
-    return res.apiv3({ result });
+    return res.apiv3(result);
   });
 
   /**

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

@@ -1,3 +1,7 @@
+const mongoose = require('mongoose');
+const escapeStringRegexp = require('escape-string-regexp');
+const { serializePageSecurely } = require('../models/serializers/page-serializer');
+
 class PageService {
 
   constructor(crowi) {
@@ -38,6 +42,58 @@ class PageService {
     return Promise.all(promises);
   }
 
+  async duplicate(page, newPagePath, user) {
+    const Page = this.crowi.model('Page');
+    const PageTagRelation = mongoose.model('PageTagRelation');
+    // populate
+    await page.populate({ path: 'revision', model: 'Revision', select: 'body' }).execPopulate();
+
+    // create option
+    const options = { page };
+    options.grant = page.grant;
+    options.grantUserGroupId = page.grantedGroup;
+    options.grantedUsers = page.grantedUsers;
+
+    const createdPage = await Page.create(
+      newPagePath, page.revision.body, user, options,
+    );
+
+    // take over tags
+    const originTags = await page.findRelatedTagsById();
+    let savedTags = [];
+    if (originTags != null) {
+      await PageTagRelation.updatePageTags(createdPage.id, originTags);
+      savedTags = await PageTagRelation.listTagNamesByPage(createdPage.id);
+    }
+
+    const result = serializePageSecurely(createdPage);
+    result.tags = savedTags;
+
+    return result;
+  }
+
+  async duplicateRecursively(page, newPagePath, user) {
+    const Page = this.crowi.model('Page');
+    const newPagePathPrefix = newPagePath;
+    const pathRegExp = new RegExp(`^${escapeStringRegexp(page.path)}`, 'i');
+
+    const pages = await Page.findManageableListWithDescendants(page, user);
+
+    const promise = pages.map(async(page) => {
+      const newPagePath = page.path.replace(pathRegExp, newPagePathPrefix);
+      return this.duplicate(page, newPagePath, user);
+    });
+
+    const newPath = page.path.replace(pathRegExp, newPagePathPrefix);
+
+    await Promise.allSettled(promise);
+
+    const newParentpage = await Page.findByPath(newPath);
+
+    // TODO GW-4634 use stream
+    return newParentpage;
+  }
+
 
 }