Shun Miyazawa 2 лет назад
Родитель
Сommit
0da2a3cd72

+ 3 - 0
apps/app/src/server/crowi/index.js

@@ -25,6 +25,7 @@ import { aclService as aclServiceSingletonInstance } from '../service/acl';
 import AppService from '../service/app';
 import AppService from '../service/app';
 import AttachmentService from '../service/attachment';
 import AttachmentService from '../service/attachment';
 import { configManager as configManagerSingletonInstance } from '../service/config-manager';
 import { configManager as configManagerSingletonInstance } from '../service/config-manager';
+import { runDataConversion } from '../service/data-converter';
 import { instanciate as instanciateExternalAccountService } from '../service/external-account';
 import { instanciate as instanciateExternalAccountService } from '../service/external-account';
 import { FileUploader, getUploader } from '../service/file-uploader'; // eslint-disable-line no-unused-vars
 import { FileUploader, getUploader } from '../service/file-uploader'; // eslint-disable-line no-unused-vars
 import { G2GTransferPusherService, G2GTransferReceiverService } from '../service/g2g-transfer';
 import { G2GTransferPusherService, G2GTransferReceiverService } from '../service/g2g-transfer';
@@ -173,6 +174,8 @@ Crowi.prototype.init = async function() {
   ]);
   ]);
 
 
   await this.autoInstall();
   await this.autoInstall();
+
+  await runDataConversion();
 };
 };
 
 
 /**
 /**

+ 8 - 0
apps/app/src/server/service/data-converter/index.ts

@@ -0,0 +1,8 @@
+import { renameDuplicateRootPages } from './rename-duplicate-root-pages';
+
+
+export const runDataConversion = async(): Promise<void> => {
+  await renameDuplicateRootPages();
+
+  return;
+};

+ 40 - 0
apps/app/src/server/service/data-converter/rename-duplicate-root-pages.ts

@@ -0,0 +1,40 @@
+// issue: https://github.com/weseek/growi/issues/8337
+
+import { type IPageHasId } from '@growi/core';
+import mongoose from 'mongoose';
+
+import { type PageModel } from '~/server/models/page';
+
+const now = new Date();
+const PARENT_PAGE_PATH_AFTER_RENAMING = `/renamed_at_${now.getTime()}`;
+
+export const renameDuplicateRootPages = async(): Promise<void> => {
+  const Page = mongoose.model('Page') as PageModel;
+  const rootPages = await Page.find({ path: '/' }).sort({ createdAt: 1 }) as Array<IPageHasId>;
+
+  if (rootPages.length <= 1) {
+    return;
+  }
+
+  // Create parent page
+  const rootPage = rootPages[0];
+  const descedantCount = rootPages.length - 1;
+  const parentPageAfterRenaming = await Page.createEmptyPage(PARENT_PAGE_PATH_AFTER_RENAMING, rootPage, descedantCount);
+
+  // Rename duplicate root pages
+  const duplicatedRootPages = rootPages.slice(1);
+  const requests = duplicatedRootPages.map((page) => {
+    return {
+      updateOne: {
+        filter: { _id: page._id },
+        update: {
+          $set: {
+            parent: parentPageAfterRenaming,
+            path: `${PARENT_PAGE_PATH_AFTER_RENAMING}/${page._id.toString().slice(-10)}`,
+          },
+        },
+      },
+    };
+  });
+  await Page.bulkWrite(requests);
+};