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

Merge pull request #6014 from weseek/feat/resume-rename-on-server-boot

feat: Resume rename on server boot
Yohei Shiina 3 лет назад
Родитель
Сommit
d187b566e8

+ 13 - 1
packages/app/src/server/crowi/index.js

@@ -148,6 +148,16 @@ Crowi.prototype.init = async function() {
   await this.autoInstall();
 };
 
+/**
+ * Execute functions that should be run after the express server is ready.
+ */
+Crowi.prototype.asyncAfterExpressServerReady = async function() {
+  if (this.pageOperationService != null) {
+    await this.pageOperationService.afterExpressServerReady();
+  }
+};
+
+
 Crowi.prototype.isPageId = function(pageId) {
   if (!pageId) {
     return false;
@@ -464,6 +474,9 @@ Crowi.prototype.start = async function() {
   // setup Global Error Handlers
   this.setupGlobalErrorHandlers();
 
+  // Execute this asynchronously after the express server is ready so it does not block the ongoing process
+  this.asyncAfterExpressServerReady();
+
   return serverListening;
 };
 
@@ -682,7 +695,6 @@ Crowi.prototype.setupPageService = async function() {
   }
   if (this.pageOperationService == null) {
     this.pageOperationService = new PageOperationService(this);
-    // TODO: Remove this code when resuming feature is implemented
     await this.pageOperationService.init();
   }
 };

+ 49 - 6
packages/app/src/server/service/page-operation.ts

@@ -1,13 +1,20 @@
 import { pagePathUtils } from '@growi/core';
 
 import { IPageOperationProcessInfo, IPageOperationProcessData } from '~/interfaces/page-operation';
-import PageOperation, { PageActionType, PageOperationDocument } from '~/server/models/page-operation';
+import PageOperation, { PageActionType, PageActionStage, PageOperationDocument } from '~/server/models/page-operation';
+import loggerFactory from '~/utils/logger';
 
 import { ObjectIdLike } from '../interfaces/mongoose-utils';
 
+const logger = loggerFactory('growi:services:page-operation');
+
 const { isEitherOfPathAreaOverlap, isPathAreaOverlap, isTrashPage } = pagePathUtils;
 const AUTO_UPDATE_INTERVAL_SEC = 5;
 
+const {
+  Duplicate, Delete, DeleteCompletely, Revert, NormalizeParent,
+} = PageActionType;
+
 class PageOperationService {
 
   crowi: any;
@@ -16,15 +23,51 @@ class PageOperationService {
     this.crowi = crowi;
   }
 
-  // TODO: Remove this code when resuming feature is implemented
-  async init() {
-    const {
-      Duplicate, Delete, DeleteCompletely, Revert, NormalizeParent,
-    } = PageActionType;
+  async init(): Promise<void> {
+    // cleanup PageOperation documents except ones with actionType: Rename
     const types = [Duplicate, Delete, DeleteCompletely, Revert, NormalizeParent];
     await PageOperation.deleteByActionTypes(types);
   }
 
+  /**
+   * Execute functions that should be run after the express server is ready.
+   */
+  async afterExpressServerReady(): Promise<void> {
+    try {
+      // execute rename operation
+      await this.executeAllRenameOperationBySystem();
+    }
+    catch (err) {
+      logger.error(err);
+    }
+  }
+
+  /**
+   * Execute renameSubOperation on every page operation for rename ordered by createdAt ASC
+   */
+  private async executeAllRenameOperationBySystem(): Promise<void> {
+    const Page = this.crowi.model('Page');
+
+    const pageOps = await PageOperation.find({ actionType: PageActionType.Rename, actionStage: PageActionStage.Sub })
+      .sort({ createdAt: 'asc' });
+    if (pageOps.length === 0) return;
+
+    for await (const pageOp of pageOps) {
+      const {
+        page, toPath, options, user,
+      } = pageOp;
+
+      const renamedPage = await Page.findById(pageOp.page._id);
+      if (renamedPage == null) {
+        logger.warn('operating page is not found');
+        continue;
+      }
+
+      // rename
+      await this.crowi.pageService.renameSubOperation(page, toPath, user, options, renamedPage, pageOp._id);
+    }
+  }
+
   /**
    * Check if the operation is operatable
    * @param isRecursively Boolean that determines whether the operation is recursive or not