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

refactor Uploader as AbstractFileUploader

Yuki Takei 2 лет назад
Родитель
Сommit
9039ac68fd

+ 46 - 12
apps/app/src/server/service/file-uploader/aws.ts

@@ -13,6 +13,10 @@ import urljoin from 'url-join';
 
 import loggerFactory from '~/utils/logger';
 
+import { configManager } from '../config-manager';
+
+import { AbstractFileUploader, SaveFileParam } from './file-uploader';
+
 
 const logger = loggerFactory('growi:service:fileUploaderAws');
 
@@ -37,10 +41,40 @@ type AwsConfig = {
   forcePathStyle?: boolean
 }
 
+class AwsFileUploader extends AbstractFileUploader {
+
+  /**
+   * @inheritdoc
+   */
+  override isValidUploadSettings(): boolean {
+    throw new Error('Method not implemented.');
+  }
+
+  /**
+   * @inheritdoc
+   */
+  override saveFile(param: SaveFileParam) {
+    throw new Error('Method not implemented.');
+  }
+
+  /**
+   * @inheritdoc
+   */
+  override deleteFiles() {
+    throw new Error('Method not implemented.');
+  }
+
+  /**
+   * @inheritdoc
+   */
+  override respond(res: Response, attachment: Response): void {
+    throw new Error('Method not implemented.');
+  }
+
+}
+
 module.exports = (crowi) => {
-  const Uploader = require('./uploader');
-  const { configManager } = crowi;
-  const lib = new Uploader(crowi);
+  const lib = new AwsFileUploader(crowi);
 
   const getAwsConfig = (): AwsConfig => {
     return {
@@ -100,7 +134,7 @@ module.exports = (crowi) => {
     return !configManager.getConfig('crowi', 'aws:referenceFileWithRelayMode');
   };
 
-  lib.respond = async function(res, attachment) {
+  (lib as any).respond = async function(res, attachment) {
     if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
@@ -134,12 +168,12 @@ module.exports = (crowi) => {
 
   };
 
-  lib.deleteFile = async function(attachment) {
+  (lib as any).deleteFile = async function(attachment) {
     const filePath = getFilePathOnStorage(attachment);
-    return lib.deleteFileByFilePath(filePath);
+    return (lib as any).deleteFileByFilePath(filePath);
   };
 
-  lib.deleteFiles = async function(attachments) {
+  (lib as any).deleteFiles = async function(attachments) {
     if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
@@ -157,7 +191,7 @@ module.exports = (crowi) => {
     return s3.send(new DeleteObjectsCommand(totalParams));
   };
 
-  lib.deleteFileByFilePath = async function(filePath) {
+  (lib as any).deleteFileByFilePath = async function(filePath) {
     if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
@@ -179,7 +213,7 @@ module.exports = (crowi) => {
     return s3.send(new DeleteObjectCommand(params));
   };
 
-  lib.uploadAttachment = async function(fileStream, attachment) {
+  (lib as any).uploadAttachment = async function(fileStream, attachment) {
     if (!lib.getIsUploadable()) {
       throw new Error('AWS is not configured.');
     }
@@ -216,7 +250,7 @@ module.exports = (crowi) => {
     return s3.send(new PutObjectCommand(params));
   };
 
-  lib.findDeliveryFile = async function(attachment) {
+  (lib as any).findDeliveryFile = async function(attachment) {
     if (!lib.getIsReadable()) {
       throw new Error('AWS is not configured.');
     }
@@ -249,7 +283,7 @@ module.exports = (crowi) => {
     return stream;
   };
 
-  lib.checkLimit = async function(uploadFileSize) {
+  (lib as any).checkLimit = async function(uploadFileSize) {
     const maxFileSize = configManager.getConfig('crowi', 'app:maxFileSize');
     const totalLimit = configManager.getConfig('crowi', 'app:fileUploadTotalLimit');
     return lib.doCheckLimit(uploadFileSize, maxFileSize, totalLimit);
@@ -258,7 +292,7 @@ module.exports = (crowi) => {
   /**
    * List files in storage
    */
-  lib.listFiles = async function() {
+  (lib as any).listFiles = async function() {
     if (!lib.getIsReadable()) {
       throw new Error('AWS is not configured.');
     }

+ 43 - 31
apps/app/src/server/service/file-uploader/file-uploader.ts

@@ -2,20 +2,47 @@ import { randomUUID } from 'crypto';
 
 import loggerFactory from '~/utils/logger';
 
+import { configManager } from '../config-manager';
+
 const logger = loggerFactory('growi:service:fileUploader');
 
-// file uploader virtual class
-// 各アップローダーで共通のメソッドはここで定義する
 
-class Uploader {
+export type SaveFileParam = {
+  filePath: string,
+  contentType: string,
+  data,
+}
+
+export type CheckLimitResult = {
+  isUploadable: boolean,
+  errorMessage?: string,
+}
+
+export interface FileUploader {
+  getIsUploadable(): boolean,
+  isWritable(): Promise<boolean>,
+  getIsReadable(): boolean,
+  isValidUploadSettings(): boolean,
+  getFileUploadEnabled(): boolean,
+  saveFile(param: SaveFileParam): Promise<any>,
+  deleteFiles(): void,
+  getFileUploadTotalLimit(): number,
+  getTotalFileSize(): Promise<number>,
+  doCheckLimit(uploadFileSize: number, maxFileSize: number, totalLimit: number): Promise<CheckLimitResult>,
+  canRespond(): boolean
+  respond(res: Response, attachment: Response): void,
+}
+
+export abstract class AbstractFileUploader implements FileUploader {
+
+  private crowi;
 
   constructor(crowi) {
     this.crowi = crowi;
-    this.configManager = crowi.configManager;
   }
 
   getIsUploadable() {
-    return !this.configManager.getConfig('crowi', 'app:fileUploadDisabled') && this.isValidUploadSettings();
+    return !configManager.getConfig('crowi', 'app:fileUploadDisabled') && this.isValidUploadSettings();
   }
 
   /**
@@ -47,21 +74,19 @@ class Uploader {
     return this.isValidUploadSettings();
   }
 
-  isValidUploadSettings() {
-    throw new Error('Implement this');
-  }
+  abstract isValidUploadSettings(): boolean;
 
   getFileUploadEnabled() {
     if (!this.getIsUploadable()) {
       return false;
     }
 
-    return !!this.configManager.getConfig('crowi', 'app:fileUpload');
+    return !!configManager.getConfig('crowi', 'app:fileUpload');
   }
 
-  deleteFiles() {
-    throw new Error('Implemnt this');
-  }
+  abstract saveFile(param: SaveFileParam);
+
+  abstract deleteFiles();
 
   /**
    * Returns file upload total limit in bytes.
@@ -70,12 +95,10 @@ class Uploader {
    * @returns file upload total limit in bytes
    */
   getFileUploadTotalLimit() {
-    const { getConfig } = this.configManager;
-
-    const fileUploadTotalLimit = getConfig('crowi', 'app:fileUploadType') === 'mongodb'
+    const fileUploadTotalLimit = configManager.getConfig('crowi', 'app:fileUploadType') === 'mongodb'
       // Use app:fileUploadTotalLimit if gridfs:totalLimit is null (default for gridfs:totalLimit is null)
-      ? getConfig('crowi', 'gridfs:totalLimit') ?? getConfig('crowi', 'app:fileUploadTotalLimit')
-      : getConfig('crowi', 'app:fileUploadTotalLimit');
+      ? configManager.getConfig('crowi', 'gridfs:totalLimit') ?? configManager.getConfig('crowi', 'app:fileUploadTotalLimit')
+      : configManager.getConfig('crowi', 'app:fileUploadTotalLimit');
     return fileUploadTotalLimit;
   }
 
@@ -99,13 +122,8 @@ class Uploader {
   /**
    * Check files size limits for all uploaders
    *
-   * @param {*} uploadFileSize
-   * @param {*} maxFileSize
-   * @param {*} totalLimit
-   * @returns
-   * @memberof Uploader
    */
-  async doCheckLimit(uploadFileSize, maxFileSize, totalLimit) {
+  async doCheckLimit(uploadFileSize: number, maxFileSize: number, totalLimit: number): Promise<CheckLimitResult> {
     if (uploadFileSize > maxFileSize) {
       return { isUploadable: false, errorMessage: 'File size exceeds the size limit per file' };
     }
@@ -121,19 +139,13 @@ class Uploader {
   /**
    * Checks if Uploader can respond to the HTTP request.
    */
-  canRespond() {
+  canRespond(): boolean {
     return false;
   }
 
   /**
    * Respond to the HTTP request.
-   * @param {Response} res
-   * @param {Response} attachment
    */
-  respond(res, attachment) {
-    throw new Error('Implement this');
-  }
+  abstract respond(res: Response, attachment: Response): void;
 
 }
-
-module.exports = Uploader;

+ 3 - 2
apps/app/src/server/service/file-uploader/gcs.js

@@ -1,5 +1,7 @@
 import loggerFactory from '~/utils/logger';
 
+import { AbstractFileUploader } from './file-uploader';
+
 const logger = loggerFactory('growi:service:fileUploaderAws');
 
 const { Storage } = require('@google-cloud/storage');
@@ -9,9 +11,8 @@ let _instance;
 
 
 module.exports = function(crowi) {
-  const Uploader = require('./uploader');
   const { configManager } = crowi;
-  const lib = new Uploader(crowi);
+  const lib = new AbstractFileUploader(crowi);
 
   function getGcsBucket() {
     return configManager.getConfig('crowi', 'gcs:bucket');

+ 5 - 3
apps/app/src/server/service/file-uploader/gridfs.js

@@ -2,15 +2,17 @@ import { Readable } from 'stream';
 
 import loggerFactory from '~/utils/logger';
 
+import { configManager } from '../config-manager';
+
+import { AbstractFileUploader } from './file-uploader';
+
 const logger = loggerFactory('growi:service:fileUploaderGridfs');
 const util = require('util');
 
 const mongoose = require('mongoose');
 
 module.exports = function(crowi) {
-  const Uploader = require('./uploader');
-  const { configManager } = crowi;
-  const lib = new Uploader(crowi);
+  const lib = new AbstractFileUploader(crowi);
   const COLLECTION_NAME = 'attachmentFiles';
   const CHUNK_COLLECTION_NAME = `${COLLECTION_NAME}.chunks`;
 

+ 3 - 2
apps/app/src/server/service/file-uploader/local.js

@@ -2,6 +2,8 @@ import { Readable } from 'stream';
 
 import loggerFactory from '~/utils/logger';
 
+import { AbstractFileUploader } from './file-uploader';
+
 const logger = loggerFactory('growi:service:fileUploaderLocal');
 
 const fs = require('fs');
@@ -13,9 +15,8 @@ const streamToPromise = require('stream-to-promise');
 const urljoin = require('url-join');
 
 module.exports = function(crowi) {
-  const Uploader = require('./uploader');
   const { configManager } = crowi;
-  const lib = new Uploader(crowi);
+  const lib = new AbstractFileUploader(crowi);
   const basePath = path.posix.join(crowi.publicDir, 'uploads');
 
   function getFilePathOnStorage(attachment) {

+ 3 - 2
apps/app/src/server/service/file-uploader/none.js

@@ -1,9 +1,10 @@
 // crowi-fileupload-none
 
+const { AbstractFileUploader } = require('./file-uploader');
+
 module.exports = function(crowi) {
   const debug = require('debug')('growi:service:fileUploaderNone');
-  const Uploader = require('./uploader');
-  const lib = new Uploader(crowi);
+  const lib = new AbstractFileUploader(crowi);
 
   lib.getIsUploadable = function() {
     return false;