Jelajahi Sumber

Merge pull request #7247 from mizozobu/feat/fileuploadtype-none

feat: fileuploadtype none
Syunsuke Komma 3 tahun lalu
induk
melakukan
93306049d6

+ 2 - 2
packages/app/public/static/locales/en_US/admin.json

@@ -526,7 +526,7 @@
       "upload": "Upload",
       "upload": "Upload",
       "discard": "Discard uploaded data",
       "discard": "Discard uploaded data",
       "errors": {
       "errors": {
-        "different_versions": "This growi and the uploaded data versions are not met",
+        "different_versions": "The version of this GROWI and the uploaded data are not the same",
         "at_least_one": "Select one or more collections.",
         "at_least_one": "Select one or more collections.",
         "page_and_revision": "'Pages' and 'Revisions' must be imported both.",
         "page_and_revision": "'Pages' and 'Revisions' must be imported both.",
         "depends": "'{{target}}' must be selected when '{{condition}}' is selected."
         "depends": "'{{target}}' must be selected when '{{condition}}' is selected."
@@ -1033,7 +1033,7 @@
   "g2g": {
   "g2g": {
     "transfer_success": "Completed GROWI to GROWI transfer successfully",
     "transfer_success": "Completed GROWI to GROWI transfer successfully",
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
-    "error_send_growi_archive": "Failed to send GROWI archive file to new GROWI"
+    "error_send_growi_archive": "Failed to send GROWI archive file to the destination GROWI"
   },
   },
   "toaster": {
   "toaster": {
     "give_user_admin": "Succeeded to give {{username}} admin",
     "give_user_admin": "Succeeded to give {{username}} admin",

+ 1 - 1
packages/app/public/static/locales/en_US/commons.json

@@ -100,7 +100,7 @@
 
 
   "g2g_data_transfer": {
   "g2g_data_transfer": {
     "tab": "Data transfer",
     "tab": "Data transfer",
-    "data_transfer": "Growi To Growi Data Transfer",
+    "data_transfer": "GROWI To GROWI Data Transfer",
     "transfer_data_to_this_growi": "Transfer data from another GROWI to this GROWI",
     "transfer_data_to_this_growi": "Transfer data from another GROWI to this GROWI",
     "publish_transfer_key": "Publish transfer key",
     "publish_transfer_key": "Publish transfer key",
     "transfer_key_limit": "Transfer keys are valid for 1 hour after issuance.",
     "transfer_key_limit": "Transfer keys are valid for 1 hour after issuance.",

+ 2 - 2
packages/app/public/static/locales/zh_CN/admin.json

@@ -534,7 +534,7 @@
       "upload": "Upload",
       "upload": "Upload",
       "discard": "Discard uploaded data",
       "discard": "Discard uploaded data",
       "errors": {
       "errors": {
-        "versions_not_met": "this growi and the uploaded data versions are not met",
+        "different_versions": "The version of this GROWI and the uploaded data are not the same",
         "at_least_one": "Select one or more collections.",
         "at_least_one": "Select one or more collections.",
         "page_and_revision": "'Pages' and 'Revisions' must be imported both.",
         "page_and_revision": "'Pages' and 'Revisions' must be imported both.",
         "depends": "'{{target}}' must be selected when '{{condition}}' is selected."
         "depends": "'{{target}}' must be selected when '{{condition}}' is selected."
@@ -1041,7 +1041,7 @@
   "g2g": {
   "g2g": {
     "transfer_success": "Completed GROWI to GROWI transfer successfully",
     "transfer_success": "Completed GROWI to GROWI transfer successfully",
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
-    "error_send_growi_archive": "Failed to send GROWI archive file to new GROWI"
+    "error_send_growi_archive": "Failed to send GROWI archive file to the destination GROWI"
   },
   },
   "toaster": {
   "toaster": {
     "give_user_admin": "Succeeded to give {{username}} admin",
     "give_user_admin": "Succeeded to give {{username}} admin",

+ 6 - 0
packages/app/src/components/Admin/G2GDataTransferStatusIcon.tsx

@@ -31,6 +31,12 @@ const G2GDataTransferStatusIcon = ({ status, className, ...props }: Props): JSX.
     );
     );
   }
   }
 
 
+  if (status === G2G_PROGRESS_STATUS.SKIPPED) {
+    return (
+      <i className={`fa fa-ban fa-fw ${className}`} aria-label="skipped" {...props} />
+    );
+  }
+
   return <i className={`fa fa-circle-o fa-fw ${className}`} aria-label="pending" {...props} />;
   return <i className={`fa fa-circle-o fa-fw ${className}`} aria-label="pending" {...props} />;
 };
 };
 
 

+ 1 - 0
packages/app/src/interfaces/g2g-transfer.ts

@@ -6,6 +6,7 @@ export const G2G_PROGRESS_STATUS = {
   IN_PROGRESS: 'IN_PROGRESS',
   IN_PROGRESS: 'IN_PROGRESS',
   COMPLETED: 'COMPLETED',
   COMPLETED: 'COMPLETED',
   ERROR: 'ERROR',
   ERROR: 'ERROR',
+  SKIPPED: 'SKIPPED',
 } as const;
 } as const;
 
 
 /**
 /**

+ 8 - 8
packages/app/src/server/routes/apiv3/g2g-transfer.ts

@@ -184,7 +184,7 @@ module.exports = (crowi: Crowi): Router => {
       logger.error(err);
       logger.error(err);
       return res.apiv3Err(
       return res.apiv3Err(
         new ErrorV3(
         new ErrorV3(
-          'the version of this growi and the growi that exported the data are not met',
+          'The version of this GROWI and the uploaded GROWI data are not the same',
           'version_incompatible',
           'version_incompatible',
         ),
         ),
         500,
         500,
@@ -200,7 +200,7 @@ module.exports = (crowi: Crowi): Router => {
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);
-      return res.apiv3Err(new ErrorV3('Import settings invalid. See growi docs about details.', 'import_settings_invalid'));
+      return res.apiv3Err(new ErrorV3('Import settings are invalid. See GROWI docs about details.', 'import_settings_invalid'));
     }
     }
 
 
     try {
     try {
@@ -252,7 +252,7 @@ module.exports = (crowi: Crowi): Router => {
       logger.error(err);
       logger.error(err);
 
 
       if (!isG2GTransferError(err)) {
       if (!isG2GTransferError(err)) {
-        return res.apiv3Err(new ErrorV3('Failed to prepare growi info', 'failed_to_prepare_growi_info'), 500);
+        return res.apiv3Err(new ErrorV3('Failed to prepare GROWI info', 'failed_to_prepare_growi_info'), 500);
       }
       }
 
 
       return res.apiv3Err(new ErrorV3(err.message, err.code), 500);
       return res.apiv3Err(new ErrorV3(err.message, err.code), 500);
@@ -302,17 +302,17 @@ module.exports = (crowi: Crowi): Router => {
     }
     }
 
 
     // get growi info
     // get growi info
-    let toGROWIInfo: IDataGROWIInfo;
+    let destGROWIInfo: IDataGROWIInfo;
     try {
     try {
-      toGROWIInfo = await g2gTransferPusherService.askGROWIInfo(tk);
+      destGROWIInfo = await g2gTransferPusherService.askGROWIInfo(tk);
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);
-      return res.apiv3Err(new ErrorV3('Error occurred while asking GROWI growi info.', 'failed_to_ask_growi_info'));
+      return res.apiv3Err(new ErrorV3('Error occurred while asking GROWI info.', 'failed_to_ask_growi_info'));
     }
     }
 
 
     // Check if can transfer
     // Check if can transfer
-    const transferability = await g2gTransferPusherService.getTransferability(toGROWIInfo);
+    const transferability = await g2gTransferPusherService.getTransferability(destGROWIInfo);
     if (!transferability.canTransfer) {
     if (!transferability.canTransfer) {
       return res.apiv3Err(new ErrorV3(transferability.reason, 'growi_incompatible_to_transfer'));
       return res.apiv3Err(new ErrorV3(transferability.reason, 'growi_incompatible_to_transfer'));
     }
     }
@@ -320,7 +320,7 @@ module.exports = (crowi: Crowi): Router => {
     // Start transfer
     // Start transfer
     // DO NOT "await". Let it run in the background.
     // DO NOT "await". Let it run in the background.
     // Errors should be emitted through websocket.
     // Errors should be emitted through websocket.
-    g2gTransferPusherService.startTransfer(tk, req.user, collections, optionsMap);
+    g2gTransferPusherService.startTransfer(tk, req.user, collections, optionsMap, destGROWIInfo);
 
 
     return res.apiv3({ message: 'Successfully requested auto transfer.' });
     return res.apiv3({ message: 'Successfully requested auto transfer.' });
   });
   });

+ 3 - 3
packages/app/src/server/routes/apiv3/import.js

@@ -356,9 +356,9 @@ export default function route(crowi) {
       return res.apiv3(data);
       return res.apiv3(data);
     }
     }
     catch {
     catch {
-      const msg = 'the version of this growi and the growi that exported the data are not met';
-      const varidationErr = 'versions-are-not-met';
-      return res.apiv3Err(new ErrorV3(msg, varidationErr), 500);
+      const msg = 'The version of this GROWI and the uploaded GROWI data are not the same';
+      const validationErr = 'versions-are-not-met';
+      return res.apiv3Err(new ErrorV3(msg, validationErr), 500);
     }
     }
   });
   });
 
 

+ 1 - 1
packages/app/src/server/service/export.js

@@ -355,7 +355,7 @@ class ExportService {
 
 
     await streamToPromise(archive);
     await streamToPromise(archive);
 
 
-    logger.info(`zipped growi data into ${zipFile} (${archive.pointer()} bytes)`);
+    logger.info(`zipped GROWI data into ${zipFile} (${archive.pointer()} bytes)`);
 
 
     // delete json files
     // delete json files
     for (const { from } of configs) {
     for (const { from } of configs) {

+ 44 - 25
packages/app/src/server/service/g2g-transfer.ts

@@ -100,22 +100,22 @@ interface Pusher {
    */
    */
   generateAxiosConfig(tk: TransferKey, config: AxiosRequestConfig): AxiosRequestConfig
   generateAxiosConfig(tk: TransferKey, config: AxiosRequestConfig): AxiosRequestConfig
   /**
   /**
-   * Send to-growi a request to get growi info
+   * Send to-growi a request to get GROWI info
    * @param {TransferKey} tk Transfer key
    * @param {TransferKey} tk Transfer key
    */
    */
   askGROWIInfo(tk: TransferKey): Promise<IDataGROWIInfo>
   askGROWIInfo(tk: TransferKey): Promise<IDataGROWIInfo>
   /**
   /**
    * Check if transfering is proceedable
    * Check if transfering is proceedable
-   * @param {IDataGROWIInfo} fromGROWIInfo
+   * @param {IDataGROWIInfo} destGROWIInfo GROWI info from dest GROWI
    */
    */
-  getTransferability(fromGROWIInfo: IDataGROWIInfo): Promise<Transferability>
+  getTransferability(destGROWIInfo: IDataGROWIInfo): Promise<Transferability>
   /**
   /**
    * List files in the storage
    * List files in the storage
    * @param {TransferKey} tk Transfer key
    * @param {TransferKey} tk Transfer key
    */
    */
   listFilesInStorage(tk: TransferKey): Promise<FileMeta[]>
   listFilesInStorage(tk: TransferKey): Promise<FileMeta[]>
   /**
   /**
-   * Transfer all Attachment data to destination GROWI
+   * Transfer all Attachment data to dest GROWI
    * @param {TransferKey} tk Transfer key
    * @param {TransferKey} tk Transfer key
    */
    */
   transferAttachments(tk: TransferKey): Promise<void>
   transferAttachments(tk: TransferKey): Promise<void>
@@ -123,7 +123,7 @@ interface Pusher {
    * Start transfer data between GROWIs
    * Start transfer data between GROWIs
    * @param {TransferKey} tk TransferKey object
    * @param {TransferKey} tk TransferKey object
    * @param {any} user User operating g2g transfer
    * @param {any} user User operating g2g transfer
-   * @param {IDataGROWIInfo} toGROWIInfo GROWI info of new GROWI
+   * @param {IDataGROWIInfo} destGROWIInfo GROWI info of dest GROWI
    * @param {string[]} collections Collection name string array
    * @param {string[]} collections Collection name string array
    * @param {any} optionsMap Options map
    * @param {any} optionsMap Options map
    */
    */
@@ -132,6 +132,7 @@ interface Pusher {
     user: any,
     user: any,
     collections: string[],
     collections: string[],
     optionsMap: any,
     optionsMap: any,
+    destGROWIInfo: IDataGROWIInfo,
   ): Promise<void>
   ): Promise<void>
 }
 }
 
 
@@ -231,54 +232,64 @@ export class G2GTransferPusherService implements Pusher {
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);
-      throw new G2GTransferError('Failed to retrieve growi info.', G2GTransferErrorCode.FAILED_TO_RETRIEVE_GROWI_INFO);
+      throw new G2GTransferError('Failed to retrieve GROWI info.', G2GTransferErrorCode.FAILED_TO_RETRIEVE_GROWI_INFO);
     }
     }
   }
   }
 
 
-  public async getTransferability(toGROWIInfo: IDataGROWIInfo): Promise<Transferability> {
-    const { fileUploadService } = this.crowi;
+  public async getTransferability(destGROWIInfo: IDataGROWIInfo): Promise<Transferability> {
+    const { fileUploadService, configManager } = this.crowi;
 
 
     const version = this.crowi.version;
     const version = this.crowi.version;
-    if (version !== toGROWIInfo.version) {
+    if (version !== destGROWIInfo.version) {
       return {
       return {
         canTransfer: false,
         canTransfer: false,
         // TODO: i18n for reason
         // TODO: i18n for reason
-        reason: `Growi versions mismatch. This Growi: ${version} / new Growi: ${toGROWIInfo.version}.`,
+        reason: `GROWI versions mismatch. src GROWI: ${version} / dest GROWI: ${destGROWIInfo.version}.`,
       };
       };
     }
     }
 
 
     const activeUserCount = await this.crowi.model('User').countActiveUsers();
     const activeUserCount = await this.crowi.model('User').countActiveUsers();
-    if ((toGROWIInfo.userUpperLimit ?? Infinity) < activeUserCount) {
+    if ((destGROWIInfo.userUpperLimit ?? Infinity) < activeUserCount) {
       return {
       return {
         canTransfer: false,
         canTransfer: false,
         // TODO: i18n for reason
         // TODO: i18n for reason
-        reason: `The number of active users (${activeUserCount} users) exceeds the limit of new Growi (to up ${toGROWIInfo.userUpperLimit} users).`,
+        // eslint-disable-next-line max-len
+        reason: `The number of active users (${activeUserCount} users) exceeds the limit of the destination GROWI (up to ${destGROWIInfo.userUpperLimit} users).`,
       };
       };
     }
     }
 
 
-    if (toGROWIInfo.fileUploadDisabled) {
+    if (destGROWIInfo.fileUploadDisabled) {
       return {
       return {
         canTransfer: false,
         canTransfer: false,
         // TODO: i18n for reason
         // TODO: i18n for reason
-        reason: 'File upload is disabled in new Growi.',
+        reason: 'The file upload setting is disabled in the destination GROWI.',
       };
       };
     }
     }
 
 
-    if (!toGROWIInfo.attachmentInfo.writable) {
+    if (configManager.getConfig('crowi', 'app:fileUploadType') === 'none') {
       return {
       return {
         canTransfer: false,
         canTransfer: false,
         // TODO: i18n for reason
         // TODO: i18n for reason
-        reason: 'The storage of new Growi is not writable.',
+        reason: 'File upload is not configured for src GROWI.',
+      };
+    }
+
+    const shouldUseFileUploadTypeOfDestGROWI = destGROWIInfo.attachmentInfo.type !== 'none';
+    if (shouldUseFileUploadTypeOfDestGROWI && !destGROWIInfo.attachmentInfo.writable) {
+      return {
+        canTransfer: false,
+        // TODO: i18n for reason
+        reason: 'The storage of the destination GROWI is not writable.',
       };
       };
     }
     }
 
 
     const totalFileSize = await fileUploadService.getTotalFileSize();
     const totalFileSize = await fileUploadService.getTotalFileSize();
-    if ((toGROWIInfo.fileUploadTotalLimit ?? Infinity) < totalFileSize) {
+    if ((destGROWIInfo.fileUploadTotalLimit ?? Infinity) < totalFileSize) {
       return {
       return {
         canTransfer: false,
         canTransfer: false,
         // TODO: i18n for reason
         // TODO: i18n for reason
         // eslint-disable-next-line max-len
         // eslint-disable-next-line max-len
-        reason: `Total file size exceeds file upload limit of new Growi. Requires ${totalFileSize.toLocaleString()} bytes, but got ${(toGROWIInfo.fileUploadTotalLimit ?? Infinity).toLocaleString()} bytes.`,
+        reason: `The total file size of attachments exceeds the file upload limit of the destination GROWI. Requires ${totalFileSize.toLocaleString()} bytes, but got ${(destGROWIInfo.fileUploadTotalLimit as number).toLocaleString()} bytes.`,
       };
       };
     }
     }
 
 
@@ -301,7 +312,7 @@ export class G2GTransferPusherService implements Pusher {
     const { fileUploadService, socketIoService } = this.crowi;
     const { fileUploadService, socketIoService } = this.crowi;
     const socket = socketIoService.getAdminSocket();
     const socket = socketIoService.getAdminSocket();
     const Attachment = this.crowi.model('Attachment');
     const Attachment = this.crowi.model('Attachment');
-    const filesFromNewGrowi = await this.listFilesInStorage(tk);
+    const filesFromSrcGROWI = await this.listFilesInStorage(tk);
 
 
     /**
     /**
      * Given these documents,
      * Given these documents,
@@ -344,8 +355,8 @@ export class G2GTransferPusherService implements Pusher {
      * | c.png | 1024 |
      * | c.png | 1024 |
      * | d.png | 2048 |
      * | d.png | 2048 |
      */
      */
-    const filter = filesFromNewGrowi.length > 0 ? {
-      $and: filesFromNewGrowi.map(({ name, size }) => ({
+    const filter = filesFromSrcGROWI.length > 0 ? {
+      $and: filesFromSrcGROWI.map(({ name, size }) => ({
         $or: [
         $or: [
           { fileName: { $ne: basename(name) } },
           { fileName: { $ne: basename(name) } },
           { fileSize: { $ne: size } },
           { fileSize: { $ne: size } },
@@ -391,7 +402,7 @@ export class G2GTransferPusherService implements Pusher {
   }
   }
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  public async startTransfer(tk: TransferKey, user: any, collections: string[], optionsMap: any): Promise<void> {
+  public async startTransfer(tk: TransferKey, user: any, collections: string[], optionsMap: any, destGROWIInfo: IDataGROWIInfo): Promise<void> {
     const socket = this.crowi.socketIoService.getAdminSocket();
     const socket = this.crowi.socketIoService.getAdminSocket();
 
 
     socket.emit('admin:g2gProgress', {
     socket.emit('admin:g2gProgress', {
@@ -422,7 +433,7 @@ export class G2GTransferPusherService implements Pusher {
       throw err;
       throw err;
     }
     }
 
 
-    // Send a zip file to other growi via axios
+    // Send a zip file to other GROWI via axios
     try {
     try {
       // Use FormData to immitate browser's form data object
       // Use FormData to immitate browser's form data object
       const form = new FormData();
       const form = new FormData();
@@ -441,7 +452,7 @@ export class G2GTransferPusherService implements Pusher {
         mongo: G2G_PROGRESS_STATUS.ERROR,
         mongo: G2G_PROGRESS_STATUS.ERROR,
         attachments: G2G_PROGRESS_STATUS.PENDING,
         attachments: G2G_PROGRESS_STATUS.PENDING,
       });
       });
-      socket.emit('admin:g2gError', { message: 'Failed to send GROWI archive file to new GROWI', key: 'admin:g2g:error_send_growi_archive' });
+      socket.emit('admin:g2gError', { message: 'Failed to send GROWI archive file to the destination GROWI', key: 'admin:g2g:error_send_growi_archive' });
       throw err;
       throw err;
     }
     }
 
 
@@ -450,6 +461,14 @@ export class G2GTransferPusherService implements Pusher {
       attachments: G2G_PROGRESS_STATUS.IN_PROGRESS,
       attachments: G2G_PROGRESS_STATUS.IN_PROGRESS,
     });
     });
 
 
+    if (destGROWIInfo.attachmentInfo.type === 'none' && ['aws', 'gcs'].includes(this.crowi.configManager.getConfig('crowi', 'app:fileUploadType'))) {
+      socket.emit('admin:g2gProgress', {
+        mongo: G2G_PROGRESS_STATUS.COMPLETED,
+        attachments: G2G_PROGRESS_STATUS.SKIPPED,
+      });
+      return;
+    }
+
     try {
     try {
       await this.transferAttachments(tk);
       await this.transferAttachments(tk);
     }
     }
@@ -470,7 +489,7 @@ export class G2GTransferPusherService implements Pusher {
   }
   }
 
 
   /**
   /**
-   * Transfer attachment to destination GROWI
+   * Transfer attachment to dest GROWI
    * @param {TransferKey} tk Transfer key
    * @param {TransferKey} tk Transfer key
    * @param {any} attachment Attachment model instance
    * @param {any} attachment Attachment model instance
    * @param {Readable} fileStream Attachment data(loaded from storage)
    * @param {Readable} fileStream Attachment data(loaded from storage)

+ 2 - 2
packages/app/src/server/service/import.js

@@ -507,14 +507,14 @@ class ImportService {
   /**
   /**
    * validate using meta.json
    * validate using meta.json
    * to pass validation, all the criteria must be met
    * to pass validation, all the criteria must be met
-   *   - ${version of this growi} === ${version of growi that exported data}
+   *   - ${version of this GROWI} === ${version of GROWI that exported data}
    *
    *
    * @memberOf ImportService
    * @memberOf ImportService
    * @param {object} meta meta data from meta.json
    * @param {object} meta meta data from meta.json
    */
    */
   validate(meta) {
   validate(meta) {
     if (meta.version !== this.crowi.version) {
     if (meta.version !== this.crowi.version) {
-      throw new Error('the version of this growi and the growi that exported the data are not met');
+      throw new Error('The version of this GROWI and the uploaded GROWI data are not the same');
     }
     }
 
 
     // TODO: check if all migrations are completed
     // TODO: check if all migrations are completed

+ 2 - 2
packages/app/src/server/util/createGrowiPagesFromImports.js

@@ -36,10 +36,10 @@ module.exports = (crowi) => {
       }
       }
       else {
       else {
         if (!isCreatableName) {
         if (!isCreatableName) {
-          errors.push(new Error(`${path} is not a creatable name in Growi`));
+          errors.push(new Error(`${path} is not a creatable name in GROWI`));
         }
         }
         if (isPageNameTaken) {
         if (isPageNameTaken) {
-          errors.push(new Error(`${path} already exists in Growi`));
+          errors.push(new Error(`${path} already exists in GROWI`));
         }
         }
       }
       }
     }
     }