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

remove single collection export, zip, and download

mizozobu 6 лет назад
Родитель
Сommit
552c18e625

+ 0 - 21
src/client/js/components/Admin/Export/ExportAsZip.jsx

@@ -18,7 +18,6 @@ class ExportPage extends React.Component {
     };
 
     this.toggleCheckbox = this.toggleCheckbox.bind(this);
-    this.exportSingle = this.exportSingle.bind(this);
     this.exportMultiple = this.exportMultiple.bind(this);
     this.deleteZipFile = this.deleteZipFile.bind(this);
   }
@@ -46,20 +45,6 @@ class ExportPage extends React.Component {
     });
   }
 
-  async exportSingle(collection) {
-    // TODO use appContainer.apiv3.post
-    const res = await this.props.appContainer.apiPost(`/v3/export/${collection}`, {});
-    // TODO toastSuccess, toastError
-    this.setState((prevState) => {
-      return {
-        files: {
-          ...prevState.files,
-          [res.collection]: res.file,
-        },
-      };
-    });
-  }
-
   async exportMultiple() {
     // TODO use appContainer.apiv3.post
     const res = await this.props.appContainer.apiPost('/v3/export', { collections: Array.from(this.state.collections) });
@@ -104,12 +89,6 @@ class ExportPage extends React.Component {
                 <label className={`form-check-label ml-3 ${disabled ? 'text-muted' : ''}`} htmlFor={collectionName}>
                   {collectionName} ({stat.name || 'not found'}) ({stat.mtime ? format(new Date(stat.mtime), 'yyyy/MM/dd HH:mm:ss') : ''})
                 </label>
-                <button type="button" className="btn btn-sm btn-primary" onClick={() => this.exportSingle(collectionName)} disabled={disabled}>
-                  Create zip file
-                </button>
-                <a href={`/_api/v3/export/${collectionName}`}>
-                  <button type="button" className="btn btn-sm btn-primary ml-2">Download</button>
-                </a>
               </div>
             );
           })}

+ 15 - 0
src/lib/util/toArrayIfNot.js

@@ -0,0 +1,15 @@
+// converts non-array item to array
+
+const toArrayIfNot = (item) => {
+  if (item == null) {
+    return [];
+  }
+
+  if (Array.isArray(item)) {
+    return item;
+  }
+
+  return [item];
+};
+
+module.exports = toArrayIfNot;

+ 3 - 94
src/server/routes/apiv3/export.js

@@ -71,91 +71,6 @@ module.exports = (crowi) => {
     }
   });
 
-  /**
-   * @swagger
-   *
-   *  /export/:collectionName:
-   *    get:
-   *      tags: [Export]
-   *      description: download a zipped json for a single collection
-   *      produces:
-   *        - application/json
-   *      parameters:
-   *        - name: collectionName
-   *          in: path
-   *          description: collection name
-   *          schema:
-   *            type: string
-   *      responses:
-   *        200:
-   *          description: a zip file
-   *          content:
-   *            application/zip:
-   */
-  router.get('/:collectionName', async(req, res) => {
-    // TODO: add express validator
-    try {
-      const { collectionName } = req.params;
-      // get model for collection
-      const Model = exportService.getModelFromCollectionName(collectionName);
-      // get zip file path
-      const zipFile = exportService.getZipFile(Model);
-
-      return res.download(zipFile);
-    }
-    catch (err) {
-      // TODO: use ApiV3Error
-      logger.error(err);
-      return res.status(500).send({ status: 'ERROR' });
-    }
-  });
-
-  /**
-   * @swagger
-   *
-   *  /export/:collectionName:
-   *    post:
-   *      tags: [Export]
-   *      description: generate a zipped json for a single collection
-   *      produces:
-   *        - application/json
-   *      parameters:
-   *        - name: collectionName
-   *          in: path
-   *          description: collection name
-   *          schema:
-   *            type: string
-   *      responses:
-   *        200:
-   *          description: a zip file is generated
-   *          content:
-   *            application/json:
-   */
-  router.post('/:collectionName', async(req, res) => {
-    // TODO: add express validator
-    try {
-      const { collectionName } = req.params;
-      // get model for collection
-      const Model = exportService.getModelFromCollectionName(collectionName);
-      // export into json
-      const jsonFile = await exportService.exportCollectionToJson(Model);
-      // zip json
-      const zipFile = await exportService.zipSingleFile(jsonFile);
-
-      // TODO: use res.apiv3
-      return res.status(200).json({
-        ok: true,
-        collection: [Model.collection.collectionName],
-        file: path.basename(zipFile),
-      });
-    }
-    catch (err) {
-      // TODO: use ApiV3Error
-      logger.error(err);
-      return res.status(500).send({ status: 'ERROR' });
-    }
-  });
-
   /**
    * @swagger
    *
@@ -181,7 +96,7 @@ module.exports = (crowi) => {
       const jsonFiles = await exportService.exportMultipleCollectionsToJsons(models);
       // zip json
       const configs = jsonFiles.map((jsonFile) => { return { from: jsonFile, as: path.basename(jsonFile) } });
-      const zipFile = await exportService.zipMultipleFiles(configs);
+      const zipFile = await exportService.zipFiles(configs);
 
       // TODO: use res.apiv3
       return res.status(200).json({
@@ -200,25 +115,19 @@ module.exports = (crowi) => {
   /**
    * @swagger
    *
-   *  /export/:collectionName:
+   *  /export:
    *    delete:
    *      tags: [Export]
    *      description: unlink a json and zip file for a single collection
    *      produces:
    *        - application/json
-   *      parameters:
-   *        - name: collectionName
-   *          in: path
-   *          description: collection name
-   *          schema:
-   *            type: string
    *      responses:
    *        200:
    *          description: the json and zip file are removed
    *          content:
    *            application/json:
    */
-  // router.delete('/:collectionName', async(req, res) => {
+  // router.delete('/', async(req, res) => {
   //   // TODO: add express validator
   //   try {
   //     const { collectionName } = req.params;

+ 7 - 46
src/server/service/export.js

@@ -3,6 +3,7 @@ const fs = require('fs');
 const path = require('path');
 const streamToPromise = require('stream-to-promise');
 const archiver = require('archiver');
+const toArrayIfNot = require('../../lib/util/toArrayIfNot');
 
 class ExportService {
 
@@ -154,60 +155,18 @@ class ExportService {
   }
 
   /**
-   * zip a file
+   * zip files into one zip file
    *
    * @memberOf ExportService
-   * @param {string} from path to input file
-   * @param {string} [to=`${path.join(path.dirname(from), `${path.basename(from, path.extname(from))}.zip`)}`] path to output file
-   * @param {string} [as=path.basename(from)] file name after unzipped
+   * @param {object|array<object>} configs array of object { from: "path to source file", as: "file name after unzipped" }
    * @return {string} path to zip file
    * @see https://www.archiverjs.com/#quick-start
    */
-  async zipSingleFile(from, to = this.replaceExtension(from, 'zip'), as = path.basename(from)) {
+  async zipFiles(_configs) {
+    const configs = toArrayIfNot(_configs);
     const archive = archiver('zip', {
       zlib: { level: this.zlibLevel },
     });
-    const input = fs.createReadStream(from);
-    const output = fs.createWriteStream(to);
-
-    // good practice to catch warnings (ie stat failures and other non-blocking errors)
-    archive.on('warning', (err) => {
-      if (err.code === 'ENOENT') logger.error(err);
-      else throw err;
-    });
-
-    // good practice to catch this error explicitly
-    archive.on('error', (err) => { throw err });
-
-    // append a file from stream
-    archive.append(input, { name: as });
-
-    // pipe archive data to the file
-    archive.pipe(output);
-
-    // finalize the archive (ie we are done appending files but streams have to finish yet)
-    // 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
-    archive.finalize();
-
-    await streamToPromise(archive);
-
-    logger.debug(`zipped ${from} into ${to} (${archive.pointer()} bytes)`);
-
-    return to;
-  }
-
-  /**
-   * zip a file
-   *
-   * @memberOf ExportService
-   * @param {array} configs array of object { from: "path to source file", as: "file name appears after unzipped" }
-   * @return {string} path to zip file
-   */
-  async zipMultipleFiles(configs) {
-    const archive = archiver('zip', {
-      zlib: { level: this.zlibLevel },
-    });
-    const output = fs.createWriteStream(this.zipFile);
 
     // good practice to catch warnings (ie stat failures and other non-blocking errors)
     archive.on('warning', (err) => {
@@ -225,6 +184,8 @@ class ExportService {
       archive.append(input, { name: as });
     }
 
+    const output = fs.createWriteStream(this.zipFile);
+
     // pipe archive data to the file
     archive.pipe(output);