Add support for saving files to AWS S3
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
// Adapter classes must implement the following functions:
|
// Adapter classes must implement the following functions:
|
||||||
// * create(config, filename, data)
|
// * create(config, filename, data)
|
||||||
// * get(config, filename)
|
// * get(config, filename)
|
||||||
|
// * location(config, req, filename)
|
||||||
//
|
//
|
||||||
// Default is GridStoreAdapter, which requires mongo
|
// Default is GridStoreAdapter, which requires mongo
|
||||||
// and for the API server to be using the ExportAdapter
|
// and for the API server to be using the ExportAdapter
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
// Requires the database adapter to be based on mongoclient
|
// Requires the database adapter to be based on mongoclient
|
||||||
|
|
||||||
var GridStore = require('mongodb').GridStore;
|
var GridStore = require('mongodb').GridStore;
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
// For a given config object, filename, and data, store a file
|
// For a given config object, filename, and data, store a file
|
||||||
// Returns a promise
|
// Returns a promise
|
||||||
@@ -32,7 +33,16 @@ function get(config, filename) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generates and returns the location of a file stored in GridStore for the
|
||||||
|
// given request and filename
|
||||||
|
function location(config, req, filename) {
|
||||||
|
return (req.protocol + '://' + req.get('host') +
|
||||||
|
path.dirname(req.originalUrl) + '/' + req.config.applicationId +
|
||||||
|
'/' + encodeURIComponent(filename));
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
create: create,
|
create: create,
|
||||||
get: get
|
get: get,
|
||||||
|
location: location
|
||||||
};
|
};
|
||||||
|
|||||||
79
S3Adapter.js
Normal file
79
S3Adapter.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// S3Adapter
|
||||||
|
//
|
||||||
|
// Stores Parse files in AWS S3.
|
||||||
|
|
||||||
|
var AWS = require('aws-sdk');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var DEFAULT_REGION = "us-east-1";
|
||||||
|
var DEFAULT_BUCKET = "parse-files";
|
||||||
|
|
||||||
|
// Creates an S3 session.
|
||||||
|
// Providing AWS access and secret keys is mandatory
|
||||||
|
// Region and bucket will use sane defaults if omitted
|
||||||
|
function S3Adapter(accessKey, secretKey, options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
this.region = options.region || DEFAULT_REGION;
|
||||||
|
this.bucket = options.bucket || DEFAULT_BUCKET;
|
||||||
|
this.bucketPrefix = options.bucketPrefix || "";
|
||||||
|
this.directAccess = options.directAccess || false;
|
||||||
|
|
||||||
|
s3Options = {
|
||||||
|
accessKeyId: accessKey,
|
||||||
|
secretAccessKey: secretKey,
|
||||||
|
params: {Bucket: this.bucket}
|
||||||
|
};
|
||||||
|
AWS.config.region = this.region;
|
||||||
|
this.s3 = new AWS.S3(s3Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For a given config object, filename, and data, store a file in S3
|
||||||
|
// Returns a promise containing the S3 object creation response
|
||||||
|
S3Adapter.prototype.create = function(config, filename, data) {
|
||||||
|
var self = this;
|
||||||
|
var params = {
|
||||||
|
Key: self.bucketPrefix + filename,
|
||||||
|
Body: data,
|
||||||
|
};
|
||||||
|
if (self.directAccess) {
|
||||||
|
params.ACL = "public-read"
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
self.s3.upload(params, function(err, data) {
|
||||||
|
if (err !== null) return reject(err);
|
||||||
|
resolve(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for and return a file if found by filename
|
||||||
|
// Returns a promise that succeeds with the buffer result from S3
|
||||||
|
S3Adapter.prototype.get = function(config, filename) {
|
||||||
|
var self = this;
|
||||||
|
var params = {Key: self.bucketPrefix + filename};
|
||||||
|
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
self.s3.getObject(params, function(err, data) {
|
||||||
|
if (err !== null) return reject(err);
|
||||||
|
resolve(data.Body);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates and returns the location of a file stored in S3 for the given request and
|
||||||
|
// filename
|
||||||
|
// The location is the direct S3 link if the option is set, otherwise we serve
|
||||||
|
// the file through parse-server
|
||||||
|
S3Adapter.prototype.location = function(config, req, filename) {
|
||||||
|
if (this.directAccess) {
|
||||||
|
return ('https://' + this.bucket + '.s3.amazonaws.com' + '/' +
|
||||||
|
this.bucketPrefix + filename);
|
||||||
|
}
|
||||||
|
return (req.protocol + '://' + req.get('host') +
|
||||||
|
path.dirname(req.originalUrl) + '/' + req.config.applicationId +
|
||||||
|
'/' + encodeURIComponent(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = S3Adapter;
|
||||||
6
files.js
6
files.js
@@ -7,7 +7,6 @@ var bodyParser = require('body-parser'),
|
|||||||
middlewares = require('./middlewares.js'),
|
middlewares = require('./middlewares.js'),
|
||||||
mime = require('mime'),
|
mime = require('mime'),
|
||||||
Parse = require('parse/node').Parse,
|
Parse = require('parse/node').Parse,
|
||||||
path = require('path'),
|
|
||||||
rack = require('hat').rack();
|
rack = require('hat').rack();
|
||||||
|
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
@@ -44,10 +43,7 @@ var processCreate = function(req, res, next) {
|
|||||||
FilesAdapter.getAdapter().create(req.config, filename, req.body)
|
FilesAdapter.getAdapter().create(req.config, filename, req.body)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
res.status(201);
|
res.status(201);
|
||||||
var location = (req.protocol + '://' + req.get('host') +
|
var location = FilesAdapter.getAdapter().location(req.config, req, filename);
|
||||||
path.dirname(req.originalUrl) + '/' +
|
|
||||||
req.config.applicationId + '/' +
|
|
||||||
encodeURIComponent(filename));
|
|
||||||
res.set('Location', location);
|
res.set('Location', location);
|
||||||
res.json({ url: location, name: filename });
|
res.json({ url: location, name: filename });
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
},
|
},
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"aws-sdk": "~2.2.33",
|
||||||
"bcrypt-nodejs": "0.0.3",
|
"bcrypt-nodejs": "0.0.3",
|
||||||
"body-parser": "~1.12.4",
|
"body-parser": "~1.12.4",
|
||||||
"deepcopy": "^0.5.0",
|
"deepcopy": "^0.5.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user