فهرست منبع

modularized fileupload, add support: local storage

Keisuke SATO 10 سال پیش
والد
کامیت
95ecee087b

+ 1 - 0
.gitignore

@@ -3,3 +3,4 @@ node_modules/
 bower_components/
 bower_components/
 public/js/*
 public/js/*
 public/css/*
 public/css/*
+public/uploads/*

+ 1 - 0
README.md

@@ -57,6 +57,7 @@ $ PASSWORD_SEED=somesecretstring MONGO_URI=mongodb://username:password@localhost
 * `REDIS_URL`: URI to connect Redis (to session store). This parameter is also by `REDISTOGO_URL`.
 * `REDIS_URL`: URI to connect Redis (to session store). This parameter is also by `REDISTOGO_URL`.
 * `PASSWORD_SEED`: A password seed is used by password hash generator.
 * `PASSWORD_SEED`: A password seed is used by password hash generator.
 * `SECRET_TOKEN`: A secret key for verifying the integrity of signed cookies.
 * `SECRET_TOKEN`: A secret key for verifying the integrity of signed cookies.
+* `FILE_UPLOAD`: `aws` (default), `local`, `none`
 
 
 
 
 License
 License

+ 9 - 0
lib/models/attachment.js

@@ -3,6 +3,7 @@ module.exports = function(crowi) {
     , mongoose = require('mongoose')
     , mongoose = require('mongoose')
     , ObjectId = mongoose.Schema.Types.ObjectId
     , ObjectId = mongoose.Schema.Types.ObjectId
     , Promise = require('bluebird')
     , Promise = require('bluebird')
+    , fileUploader = require('../util/fileUploader')(crowi)
   ;
   ;
 
 
   function generateFileHash (fileName) {
   function generateFileHash (fileName) {
@@ -21,6 +22,14 @@ module.exports = function(crowi) {
     fileFormat: { type: String, required: true },
     fileFormat: { type: String, required: true },
     fileSize: { type: Number, default: 0 },
     fileSize: { type: Number, default: 0 },
     createdAt: { type: Date, default: Date.now }
     createdAt: { type: Date, default: Date.now }
+  }, {
+    toJSON: {
+      virtuals: true
+    }
+  });
+
+  attachmentSchema.virtual('fileUrl').get(function() {
+    return fileUploader.generateUrl(this.filePath);
   });
   });
 
 
   attachmentSchema.statics.getListByPageId = function(id) {
   attachmentSchema.statics.getListByPageId = function(id) {

+ 4 - 3
lib/models/config.js

@@ -166,14 +166,15 @@ module.exports = function(crowi) {
 
 
   configSchema.statics.isUploadable = function(config)
   configSchema.statics.isUploadable = function(config)
   {
   {
-    if (!config.crowi['aws:accessKeyId'] ||
+    if (crowi.env.FILE_UPLOAD == 'aws' && (
+        !config.crowi['aws:accessKeyId'] ||
         !config.crowi['aws:secretAccessKey'] ||
         !config.crowi['aws:secretAccessKey'] ||
         !config.crowi['aws:region'] ||
         !config.crowi['aws:region'] ||
-        !config.crowi['aws:bucket']) {
+        !config.crowi['aws:bucket'])) {
       return false;
       return false;
     }
     }
 
 
-    return true;
+    return crowi.env.FILE_UPLOAD != 'none';
   };
   };
 
 
   /*
   /*

+ 1 - 1
lib/models/user.js

@@ -55,7 +55,7 @@ module.exports = function(crowi) {
 
 
   function generatePassword (password) {
   function generatePassword (password) {
     var hasher = crypto.createHash('sha256');
     var hasher = crypto.createHash('sha256');
-    hasher.update(process.env.PASSWORD_SEED + password);
+    hasher.update(crowi.env.PASSWORD_SEED + password);
 
 
     return hasher.digest('hex');
     return hasher.digest('hex');
   }
   }

+ 2 - 3
lib/routes/attachment.js

@@ -8,6 +8,7 @@ module.exports = function(crowi, app) {
     , Promise = require('bluebird')
     , Promise = require('bluebird')
     , config = crowi.getConfig()
     , config = crowi.getConfig()
     , fs = require('fs')
     , fs = require('fs')
+    , fileUploader = require('../util/fileUploader')(crowi, app)
     , actions = {}
     , actions = {}
     , api = {};
     , api = {};
 
 
@@ -21,7 +22,6 @@ module.exports = function(crowi, app) {
       res.json({
       res.json({
         status: true,
         status: true,
         data: {
         data: {
-          fileBaseUrl: 'https://' + config.crowi['aws:bucket'] +'.s3.amazonaws.com/', // FIXME: ベタ書きよくない
           attachments: attachments
           attachments: attachments
         }
         }
       });
       });
@@ -39,7 +39,6 @@ module.exports = function(crowi, app) {
 
 
     debug('id and path are: ', id, path);
     debug('id and path are: ', id, path);
 
 
-    var fileUploader = require('../util/fileUploader')(crowi, app);
     var tmpFile = req.files.file || null;
     var tmpFile = req.files.file || null;
     debug('Uploaded tmpFile: ', tmpFile);
     debug('Uploaded tmpFile: ', tmpFile);
     if (!tmpFile) {
     if (!tmpFile) {
@@ -88,7 +87,7 @@ module.exports = function(crowi, app) {
           // TODO size
           // TODO size
           return Attachment.create(id, req.user, filePath, originalName, fileName, fileType, fileSize);
           return Attachment.create(id, req.user, filePath, originalName, fileName, fileType, fileSize);
         }).then(function(data) {
         }).then(function(data) {
-          var imageUrl = fileUploader.generateS3FileUrl(data.filePath);
+          var imageUrl = fileUploader.generateUrl(data.filePath);
           return res.json({
           return res.json({
             status: true,
             status: true,
             filename: imageUrl,
             filename: imageUrl,

+ 1 - 1
lib/routes/me.js

@@ -50,7 +50,7 @@ module.exports = function(crowi, app) {
 
 
     fileUploader.uploadFile(filePath, tmpFile.mimetype, tmpFileStream, {})
     fileUploader.uploadFile(filePath, tmpFile.mimetype, tmpFileStream, {})
     .then(function(data) {
     .then(function(data) {
-      var imageUrl = fileUploader.generateS3FileUrl(filePath);
+      var imageUrl = fileUploader.generateUrl(filePath);
       req.user.updateImage(imageUrl, function(err, data) {
       req.user.updateImage(imageUrl, function(err, data) {
         fs.unlink(tmpPath, function (err) {
         fs.unlink(tmpPath, function (err) {
           // エラー自体は無視
           // エラー自体は無視

+ 4 - 61
lib/util/fileUploader.js

@@ -2,69 +2,12 @@
  * fileUploader
  * fileUploader
  */
  */
 
 
-
 module.exports = function(crowi) {
 module.exports = function(crowi) {
   'use strict';
   'use strict';
 
 
-  var aws = require('aws-sdk')
-    , debug = require('debug')('crowi:lib:fileUploader')
-    , Promise = require('bluebird')
-    , Config = crowi.model('Config')
-    , config = crowi.getConfig()
-    , lib = {}
-    ;
-
-  lib.getAwsConfig = function()
-  {
-    return {
-      accessKeyId: config.crowi['aws:accessKeyId'],
-      secretAccessKey: config.crowi['aws:secretAccessKey'],
-      region: config.crowi['aws:region'],
-      bucket: config.crowi['aws:bucket']
-    };
-  };
-
-  // lib.deleteFile = function(filePath, callback) {
-  //   // TODO 実装する
-  // };
-  //
-
-  lib.uploadFile = function(filePath, contentType, fileStream, options) {
-    var awsConfig = lib.getAwsConfig();
-    if (!Config.isUploadable(config)) {
-      return new Promise.reject(new Error('AWS is not configured.'));
-    }
-
-    aws.config.update({
-      accessKeyId: awsConfig.accessKeyId,
-      secretAccessKey: awsConfig.secretAccessKey,
-      region: awsConfig.region
-    });
-    var s3 = new aws.S3();
-
-    var params = {Bucket: awsConfig.bucket};
-    params.ContentType = contentType;
-    params.Key = filePath;
-    params.Body = fileStream;
-    params.ACL = 'public-read';
-
-    return new Promise(function(resolve, reject) {
-      s3.putObject(params, function(err, data) {
-        if (err) {
-          return reject(err);
-        }
-
-        return resolve(data);
-      });
-    });
-  };
-
-  lib.generateS3FileUrl = function(filePath) {
-    var awsConfig = lib.getAwsConfig();
-    var url = 'https://' + awsConfig.bucket +'.s3.amazonaws.com/' + filePath;
-
-    return url;
-  };
+  var debug = require('debug')('crowi:lib:fileUploader')
+    , method = crowi.env.FILE_UPLOAD || 'aws'
+    , lib = '../../local_modules/crowi-fileupload-' + method;
 
 
-  return lib;
+  return require(lib)(crowi);
 };
 };

+ 67 - 0
local_modules/crowi-fileupload-aws/index.js

@@ -0,0 +1,67 @@
+// crowi-fileupload-aws
+
+module.exports = function(crowi) {
+  'use strict';
+
+  var aws = require('aws-sdk')
+    , debug = require('debug')('crowi:lib:fileUploaderAws')
+    , Promise = require('bluebird')
+    , Config = crowi.model('Config')
+    , config = crowi.getConfig()
+    , lib = {}
+    , getAwsConfig = function() {
+        return {
+          accessKeyId: config.crowi['aws:accessKeyId'],
+          secretAccessKey: config.crowi['aws:secretAccessKey'],
+          region: config.crowi['aws:region'],
+          bucket: config.crowi['aws:bucket']
+        };
+      };
+
+  lib.deleteFile = function(filePath) {
+    return new Promise(function(resolve, reject) {
+      debug('Unsupported file deletion.');
+      resolve('TODO: ...');
+    });
+  };
+
+  lib.uploadFile = function(filePath, contentType, fileStream, options) {
+    var awsConfig = lib.getAwsConfig();
+    if (!Config.isUploadable(config)) {
+      return new Promise.reject(new Error('AWS is not configured.'));
+    }
+
+    aws.config.update({
+      accessKeyId: awsConfig.accessKeyId,
+      secretAccessKey: awsConfig.secretAccessKey,
+      region: awsConfig.region
+    });
+    var s3 = new aws.S3();
+
+    var params = {Bucket: awsConfig.bucket};
+    params.ContentType = contentType;
+    params.Key = filePath;
+    params.Body = fileStream;
+    params.ACL = 'public-read';
+
+    return new Promise(function(resolve, reject) {
+      s3.putObject(params, function(err, data) {
+        if (err) {
+          return reject(err);
+        }
+
+        return resolve(data);
+      });
+    });
+  };
+
+  lib.generateUrl = function(filePath) {
+    var awsConfig = lib.getAwsConfig()
+      , url = 'https://' + awsConfig.bucket +'.s3.amazonaws.com/' + filePath;
+
+    return url;
+  };
+
+  return lib;
+};
+

+ 61 - 0
local_modules/crowi-fileupload-local/index.js

@@ -0,0 +1,61 @@
+// crowi-fileupload-local
+
+module.exports = function(crowi) {
+  'use strict';
+
+  var debug = require('debug')('crowi:lib:fileUploaderLocal')
+    , fs = require('fs')
+    , path = require('path')
+    , mkdir = require('mkdirp')
+    , Promise = require('bluebird')
+    , Config = crowi.model('Config')
+    , config = crowi.getConfig()
+    , lib = {}
+    , basePath = path.join(crowi.publicDir, 'uploads'); // TODO: to configurable
+
+  lib.deleteFile = function(filePath) {
+    debug('File deletion: ' + filePath);
+    return new Promise(function(resolve, reject) {
+      fs.unlink(path.join(basePath, filePath), function(err) {
+        if (err) {
+          debug(err);
+          return reject(err);
+        }
+
+        resolve();
+      });
+    });
+  };
+
+  lib.uploadFile = function(filePath, contentType, fileStream, options) {
+    debug('File uploading: ' + filePath);
+    return new Promise(function(resolve, reject) {
+      var localFilePath = path.join(basePath, filePath)
+        , dirpath = path.dirname(localFilePath);
+
+      mkdir(dirpath, function(err) {
+        if (err) {
+          return reject(err);
+        }
+
+        var writer = fs.createWriteStream(localFilePath);
+
+        writer.on('error', function(err) {
+          reject(err);
+        }).on('finish', function() {
+          resolve();
+        });
+
+        fileStream.pipe(writer);
+      });
+    });
+  };
+
+  lib.generateUrl = function(filePath) {
+    return path.join('/uploads', filePath);
+  };
+
+  return lib;
+};
+
+

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 25 - 0
local_modules/crowi-fileupload-none/index.js


+ 1 - 0
package.json

@@ -65,6 +65,7 @@
     "kerberos": "0.0.17",
     "kerberos": "0.0.17",
     "marked": "~0.3.5",
     "marked": "~0.3.5",
     "method-override": "~2.3.1",
     "method-override": "~2.3.1",
+    "mkdirp": "^0.5.1",
     "mongoose": "4.2.5",
     "mongoose": "4.2.5",
     "mongoose-paginate": "4.2.0",
     "mongoose-paginate": "4.2.0",
     "morgan": "~1.5.1",
     "morgan": "~1.5.1",

+ 1 - 2
resource/js/crowi.js

@@ -380,11 +380,10 @@ $(function() {
     var $pageAttachmentList = $('.page-attachments ul');
     var $pageAttachmentList = $('.page-attachments ul');
     $.get('/_api/attachment/page/' + pageId, function(res) {
     $.get('/_api/attachment/page/' + pageId, function(res) {
       var attachments = res.data.attachments;
       var attachments = res.data.attachments;
-      var urlBase = res.data.fileBaseUrl;
       if (attachments.length > 0) {
       if (attachments.length > 0) {
         $.each(attachments, function(i, file) {
         $.each(attachments, function(i, file) {
           $pageAttachmentList.append(
           $pageAttachmentList.append(
-          '<li><a href="' + urlBase + file.filePath + '">' + (file.originalName || file.fileName) + '</a> <span class="label label-default">' + file.fileFormat + '</span></li>'
+          '<li><a href="' + file.fileUrl + '">' + (file.originalName || file.fileName) + '</a> <span class="label label-default">' + file.fileFormat + '</span></li>'
           );
           );
         })
         })
       } else {
       } else {

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است