Taichi Masuyama 4 лет назад
Родитель
Сommit
4b4a67074c

+ 8 - 11
packages/app/src/server/routes/apiv3/pages.js

@@ -737,22 +737,14 @@ module.exports = (crowi) => {
       return res.apiv3Err(new ErrorV3('Failed to find pages to delete.'));
     }
 
+    let pagesCanBeDeleted;
+
     /*
      * Delete Completely
      */
     if (isCompletely) {
       try {
-        const pagesCanBeDeleted = crowi.pageService.filterPagesByCanDeleteCompletely(pagesToDelete, req.user);
-
-        // recursive
-        if (isRecursively) {
-
-        }
-
-        // non-recursive
-        else {
-
-        }
+        pagesCanBeDeleted = crowi.pageService.filterPagesByCanDeleteCompletely(pagesToDelete, req.user);
       }
       catch (err) {
         const msg = 'Failed to process completely delete pages.';
@@ -782,6 +774,11 @@ module.exports = (crowi) => {
         return res.apiv3Err(new ErrorV3(msg), 500);
       }
     }
+
+    // run delete
+    crowi.pageService.deleteMultiplePages(pagesCanBeDeleted, req.user, isCompletely, isRecursively);
+
+    return res.apiv3({});
   });
 
   router.post('/v5-schema-migration', accessTokenParser, loginRequired, adminRequired, csrf, async(req, res) => {

+ 22 - 3
packages/app/src/server/service/page.ts

@@ -26,10 +26,11 @@ const debug = require('debug')('growi:services:page');
 
 const logger = loggerFactory('growi:services:page');
 const {
-  isCreatablePage, isTrashPage, isTopPage, omitDuplicateAreaPathFromPaths,
+  isCreatablePage, isTrashPage, isTopPage, omitDuplicateAreaPathFromPaths, omitDuplicateAreaPageFromPages,
 } = pagePathUtils;
 
 const BULK_REINDEX_SIZE = 100;
+const LIMIT_FOR_MULTIPLE_PAGE_OP = 20;
 
 // TODO: improve type
 class PageCursorsForDescendantsFactory {
@@ -1430,8 +1431,26 @@ class PageService {
     return nDeletedNonEmptyPages;
   }
 
-  async deleteMultiplePages(pagesToDelete, isCompletely: boolean, isRecursively: boolean): Promise<void> {
-    return;
+  async deleteMultiplePages(pagesToDelete, user, isCompletely: boolean, isRecursively: boolean): Promise<void> {
+    if (pagesToDelete.length > LIMIT_FOR_MULTIPLE_PAGE_OP) {
+      throw Error(`The maximum number of pages is ${LIMIT_FOR_MULTIPLE_PAGE_OP}.`);
+    }
+
+    // omit duplicate paths if isRecursively true
+    const pages = isRecursively ? omitDuplicateAreaPageFromPages(pagesToDelete) : pagesToDelete;
+
+    // TODO: insertMany PageOperationBlock
+
+    if (isCompletely) {
+      for await (const page of pages) {
+        await this.deleteCompletely(page, user, {}, isRecursively);
+      }
+    }
+    else {
+      for await (const page of pages) {
+        await this.deletePage(page, user, {}, isRecursively);
+      }
+    }
   }
 
   // use the same process in both v4 and v5

+ 13 - 0
packages/core/src/utils/page-path-utils.ts

@@ -175,3 +175,16 @@ export const omitDuplicateAreaPathFromPaths = (paths: string[]): string[] => {
     return !isDuplicate;
   });
 };
+
+/**
+ * return pages with path without duplicate area of regexp /^${path}\/.+/i
+ * @param paths paths to be tested
+ * @returns omitted paths
+ */
+export const omitDuplicateAreaPageFromPages = (pages: any[]): any[] => {
+  return pages.filter((page) => {
+    const isDuplicate = pages.filter(p => (new RegExp(`^${p.path}\\/.+`, 'i')).test(page.path)).length > 0;
+
+    return !isDuplicate;
+  });
+};