diff --git a/README.md b/README.md index 204c7a3..775b792 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,23 @@ jquery-file-upload-middleware ============================= +Fork from: [jquery-file-upload-middleware](https://github.com/aguidrevitch/jquery-file-upload-middleware) + +Initial support for s3 file uploads. + jQuery-File-Upload Express.js middleware. Based on the server code of [jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload) Installation: ``` - $ npm install jquery-file-upload-middleware + $ npm install jquery-cloud-file-upload-middleware ``` Usage: ```javascript var express = require("express"), - upload = require('jquery-file-upload-middleware'); + upload = require('jquery-cloud-file-upload-middleware'); var app = express(); @@ -26,6 +30,15 @@ Usage: width: 80, height: 80 } + }, + s3Bucket: function () { + return s3Bucket; + }, + s3Region: function () { + return varS3Region; + }, + s3Url: function () { + return dirs.default_s3_url; } }); diff --git a/examples/app.js b/examples/app.js index 429526d..b6f3310 100644 --- a/examples/app.js +++ b/examples/app.js @@ -8,7 +8,8 @@ * */ var express = require('express'), http = require('http'), - upload = require('../'); + upload = require('../'), + AWS = require('aws-sdk'); var swig = require('swig'); @@ -29,6 +30,13 @@ swig.setDefaults({ cache: false // default 'memory' }); +var varS3Region = 'THE REGION FROM AMAZON', + s3Bucket = 'YOUR BUCKET NAME'; +AWS.config.update({ + "accessKeyId" : "YOUR ACCESS KEY ID", + "secretAccessKey": "YOUR SECRET ACCESS KEY", + "region" : varS3Region +}); // jquery-file-upload helper app.use('/upload/default', function (req, res, next) { @@ -36,7 +44,16 @@ app.use('/upload/default', function (req, res, next) { tmpDir: dirs.temp, uploadDir: __dirname + dirs.default, uploadUrl: dirs.default_url, - imageVersions: resizeConf.default + imageVersions: resizeConf.default, + s3Bucket: function () { + return s3Bucket; + }, + s3Region: function () { + return varS3Region; + }, + s3Url: function () { + return dirs.default_s3_url; + } })(req, res, next); }); @@ -44,7 +61,16 @@ app.use('/upload/location', upload.fileHandler({ tmpDir: dirs.temp, uploadDir: __dirname + dirs.location, uploadUrl: dirs.location_url, - imageVersions: resizeConf.location + imageVersions: resizeConf.location, + s3Bucket: function () { + return s3Bucket; + }, + s3Region: function () { + return varS3Region; + }, + s3Url: function () { + return dirs.default_s3_url; + } })); app.use('/upload/location/list', function (req, res, next) { diff --git a/examples/config.js b/examples/config.js index b4138cc..7270c86 100644 --- a/examples/config.js +++ b/examples/config.js @@ -50,6 +50,7 @@ exports.directors = { default: '/public/uploads/default', default_url: '/uploads/default', + default_s3_url: '/uploads', location: '/public/uploads/location', location_url: '/uploads/location' diff --git a/examples/public/uploads/location/28071_10151274648580240_1606415380_n.jpg b/examples/public/uploads/location/28071_10151274648580240_1606415380_n.jpg new file mode 100644 index 0000000..3e80882 Binary files /dev/null and b/examples/public/uploads/location/28071_10151274648580240_1606415380_n.jpg differ diff --git a/examples/public/uploads/location/large/28071_10151274648580240_1606415380_n.jpg b/examples/public/uploads/location/large/28071_10151274648580240_1606415380_n.jpg new file mode 100644 index 0000000..9b6ca32 Binary files /dev/null and b/examples/public/uploads/location/large/28071_10151274648580240_1606415380_n.jpg differ diff --git a/examples/public/uploads/location/medium/28071_10151274648580240_1606415380_n.jpg b/examples/public/uploads/location/medium/28071_10151274648580240_1606415380_n.jpg new file mode 100644 index 0000000..5e1151e Binary files /dev/null and b/examples/public/uploads/location/medium/28071_10151274648580240_1606415380_n.jpg differ diff --git a/examples/public/uploads/location/small/28071_10151274648580240_1606415380_n.jpg b/examples/public/uploads/location/small/28071_10151274648580240_1606415380_n.jpg new file mode 100644 index 0000000..a634b24 Binary files /dev/null and b/examples/public/uploads/location/small/28071_10151274648580240_1606415380_n.jpg differ diff --git a/examples/public/uploads/location/thumbnail/28071_10151274648580240_1606415380_n.jpg b/examples/public/uploads/location/thumbnail/28071_10151274648580240_1606415380_n.jpg new file mode 100644 index 0000000..d270c46 Binary files /dev/null and b/examples/public/uploads/location/thumbnail/28071_10151274648580240_1606415380_n.jpg differ diff --git a/lib/uploadhandler.js b/lib/uploadhandler.js index 070f018..473ad77 100644 --- a/lib/uploadhandler.js +++ b/lib/uploadhandler.js @@ -5,10 +5,13 @@ var EventEmitter = require('events').EventEmitter, imageMagick = require('imagemagick'), mkdirp = require('mkdirp'), _ = require('lodash'), - async = require('async'); + async = require('async'), + AWS = require('aws-sdk'); module.exports = function (options) { + var s3 = new AWS.S3(); + var FileInfo = require('./fileinfo')( _.extend({ baseDir: options.uploadDir @@ -57,7 +60,7 @@ module.exports = function (options) { else cb(err); }, this)); }, this), - _.bind(function(err) { + _.bind(function(err) { this.callback({files: files}); }, this)); }, this)); @@ -74,12 +77,13 @@ module.exports = function (options) { finish = _.bind(function () { if (!--counter) { async.each(files, _.bind(function(fileInfo, cb) { + this.moveToS3(fileInfo); this.initUrls(fileInfo, _.bind(function(err) { this.emit('end', fileInfo); cb(err); }, this)); }, this), - _.bind(function(err) { + _.bind(function(err) { this.callback({files: files}, redirect); }, this)); } @@ -89,92 +93,92 @@ module.exports = function (options) { form.uploadDir = options.tmpDir; form - .on('fileBegin', function (name, file) { - tmpFiles.push(file.path); - var fileInfo = new FileInfo(file); - fileInfo.safeName(); - map[path.basename(file.path)] = fileInfo; - files.push(fileInfo); - self.emit('begin', fileInfo); - }) - .on('field', function (name, value) { - if (name === 'redirect') { - redirect = value; - } - if ( !self.req.fields ) - self.req.fields = {}; - self.req.fields[name] = value; - }) - .on('file', function (name, file) { - counter++; - var fileInfo = map[path.basename(file.path)]; - fs.exists(file.path, function(exists) { - if (exists) { - fileInfo.size = file.size; - if (!fileInfo.validate()) { - fs.unlink(file.path); - finish(); - return; - } + .on('fileBegin', function (name, file) { + tmpFiles.push(file.path); + var fileInfo = new FileInfo(file); + fileInfo.safeName(); + map[path.basename(file.path)] = fileInfo; + files.push(fileInfo); + self.emit('begin', fileInfo); + }) + .on('field', function (name, value) { + if (name === 'redirect') { + redirect = value; + } + if ( !self.req.fields ) + self.req.fields = {}; + self.req.fields[name] = value; + }) + .on('file', function (name, file) { + counter++; + var fileInfo = map[path.basename(file.path)]; + fs.exists(file.path, function(exists) { + if (exists) { + fileInfo.size = file.size; + if (!fileInfo.validate()) { + fs.unlink(file.path); + finish(); + return; + } - var generatePreviews = function () { - if (options.imageTypes.test(fileInfo.name)) { - _.each(options.imageVersions, function (value, version) { - counter++; - // creating directory recursive - mkdirp(options.uploadDir() + '/' + version + '/', function (err, made) { - var opts = options.imageVersions[version]; - imageMagick.resize({ - width: opts.width, - height: opts.height, - srcPath: options.uploadDir() + '/' + fileInfo.name, - dstPath: options.uploadDir() + '/' + version + '/' + fileInfo.name, - customArgs: opts.imageArgs || ['-auto-orient'] - }, finish); - }); + var generatePreviews = function () { + if (options.imageTypes.test(fileInfo.name)) { + _.each(options.imageVersions, function (value, version) { + counter++; + // creating directory recursive + mkdirp(options.uploadDir() + '/' + version + '/', function (err, made) { + var opts = options.imageVersions[version]; + imageMagick.resize({ + width: opts.width, + height: opts.height, + srcPath: options.uploadDir() + '/' + fileInfo.name, + dstPath: options.uploadDir() + '/' + version + '/' + fileInfo.name, + customArgs: opts.imageArgs || ['-auto-orient'] + }, finish); }); - } + }); } + } - mkdirp(options.uploadDir() + '/', function(err, made) { - fs.rename(file.path, options.uploadDir() + '/' + fileInfo.name, function (err) { - if (!err) { - generatePreviews(); + mkdirp(options.uploadDir() + '/', function(err, made) { + fs.rename(file.path, options.uploadDir() + '/' + fileInfo.name, function (err) { + if (!err) { + generatePreviews(); + finish(); + } else { + var is = fs.createReadStream(file.path); + var os = fs.createWriteStream(options.uploadDir() + '/' + fileInfo.name); + is.on('end', function (err) { + if (!err) { + fs.unlink(file.path); + generatePreviews(); + } finish(); - } else { - var is = fs.createReadStream(file.path); - var os = fs.createWriteStream(options.uploadDir() + '/' + fileInfo.name); - is.on('end', function (err) { - if (!err) { - fs.unlink(file.path); - generatePreviews(); - } - finish(); - }); - is.pipe(os); - } - }); + }); + is.pipe(os); + } }); - } - else finish(); - }); - }) - .on('aborted', function () { - _.each(tmpFiles, function (file) { - var fileInfo = map[path.basename(file)]; - self.emit('abort', fileInfo); - fs.unlink(file); - }); - }) - .on('error', function (e) { - self.emit('error', e); - }) - .on('progress', function (bytesReceived, bytesExpected) { - if (bytesReceived > options.maxPostSize) - self.req.connection.destroy(); - }) - .on('end', finish) - .parse(self.req); + }); + } + else finish(); + }); + }) + .on('aborted', function () { + _.each(tmpFiles, function (file) { + var fileInfo = map[path.basename(file)]; + self.emit('abort', fileInfo); + fs.unlink(file); + }); + }) + .on('error', function (e) { + self.emit('error', e); + }) + .on('progress', function (bytesReceived, bytesExpected) { + if (bytesReceived > options.maxPostSize) + self.req.connection.destroy(); + }) + .on('end', finish) + .parse(self.req); }; UploadHandler.prototype.destroy = function () { @@ -197,16 +201,64 @@ module.exports = function (options) { }; UploadHandler.prototype.initUrls = function (fileInfo, cb) { - var baseUrl = (options.ssl ? 'https:' : 'http:') + '//' + (options.hostname || this.req.get('Host')); - fileInfo.setUrl(null, baseUrl + options.uploadUrl()); - fileInfo.setUrl('delete', baseUrl + this.req.originalUrl); - async.each(Object.keys(options.imageVersions), function(version, cb) { - fs.exists(options.uploadDir() + '/' + version + '/' + fileInfo.name, function(exists) { - if (exists) fileInfo.setUrl(version, baseUrl + options.uploadUrl() + '/' + version); - cb(null); - }) - }, - cb); + //http://<>.s3-<>.amazonaws.com + var baseUrl = (options.ssl ? 'https:' : 'http:') + '//' + options.s3Bucket() + '.s3-' + options.s3Region() + '.amazonaws.com/'; + fileInfo.setUrl(null, baseUrl + options.s3Url()); + fileInfo.setUrl('delete', baseUrl + options.s3Url()); + async.each(Object.keys(options.imageVersions), _.bind(function(version, cb) { + //fs.exists(options.uploadDir() + '/' + version + '/' + fileInfo.name, function(exists) { + /*if (exists)*/ fileInfo.setUrl(version, baseUrl + this.removeExtraSlashes(options.s3Url() + '/' + version)); + cb(null); + //}) + }, this), cb); + }; + + UploadHandler.prototype.moveToS3 = function(fileInfo) { + var fileName = options.uploadDir() + '/' + fileInfo.name; + fs.readFile(fileName, _.bind(function(err, data) { + if(!err) { + this.uploadToS3(this.removeExtraSlashes(options.s3Url() + '/' + fileInfo.name), data); + + async.each(Object.keys(options.imageVersions), _.bind(function(version) { + fileName = options.uploadDir() + '/' + version + '/' + fileInfo.name; + fs.readFile(fileName, _.bind(function(err, data) { + if(!err) { + this.uploadToS3(this.removeExtraSlashes(options.s3Url() + '/' + version + '/' + fileInfo.name), data); + } + }, this)); + }, this)); + } + }, this)); + }; + + UploadHandler.prototype.removeExtraSlashes = function(filePath) { + if(filePath.indexOf('//') !== -1) { + filePath = filePath.replace('//', '/'); + filePath = this.removeExtraSlashes(filePath); + } + + return filePath; + }; + + UploadHandler.prototype.uploadToS3 = function(fileName, data) { + fs.unlink(fileName, _.bind(function(err){ + this.emit('error', err); + }, this)); + + var bucket = options.s3Bucket(); + s3.createBucket({Bucket: bucket}, _.bind(function() { + var params = { + Bucket: bucket, + Key: fileName, + Body: data,ACL:'public-read' + }; + s3.putObject(params, _.bind(function(err, data) { + console.log(err); + if (err) { + this.emit('error', err); + } + }, this)); + }, this)); }; return UploadHandler; diff --git a/package.json b/package.json index dc11e0c..9fde29b 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,28 @@ { - "name": "jquery-file-upload-middleware", - "author": "Aleksandr Guidrevitch ", - "description": "jQuery-File-Upload Express.js Middleware", + "name": "jquery-cloud-file-upload-middleware", + "author": "Manuel Gutierrez @drginm", + "description": "jQuery-Cloud-File-Upload Express.js Middleware S3 Aws", "keywords": [ "jquery", "upload", "express", "middleware" ], - "version": "0.1.7", + "version": "0.0.4", "dependencies": { + "async": "*", + "aws-sdk": "^2.0.17", "formidable": ">=1.0.11", "imagemagick": ">=0.1.2", "lodash": ">= 0.9.2", - "mkdirp": ">= 0.3.4", - "async": "*" + "mkdirp": ">= 0.3.4" }, "engines": { "node": ">= 0.8.8" }, "repository": { "type": "git", - "url": "git://github.com/aguidrevitch/jquery-file-upload-middleware.git" + "url": "git@github.com:drginm/jquery-cloud-file-upload-middleware.git" }, "main": "./index.js", "readmeFilename": "README.md", @@ -29,6 +30,6 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "_id": "jquery-file-upload-middleware@0.1.7", + "_id": "jquery-cloud-file-upload-middleware@0.0.4", "license": "MIT" }