Merge branch 'master' of github.com:strongloop/loopback-component-storage

This commit is contained in:
Miguel González Aravena 2018-01-06 21:59:52 -03:00
commit e6e49cf954
9 changed files with 138 additions and 19 deletions

23
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,23 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- critical
- p1
- major
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been closed due to continued inactivity. Thank you for your understanding.
If you believe this to be in error, please contact one of the code owners,
listed in the `CODEOWNERS` file at the top-level of this repository.

View File

@ -1,3 +1,27 @@
2017-08-30, Version 3.3.1
=========================
* Declare container parameter for swagger spec (Raymond Feng)
2017-08-30, Version 3.3.0
=========================
* Mark HTTP path parameters as required (Miroslav Bajtoš)
* Add stalebot configuration (Kevin Delisle)
* Create Issue and PR Templates (#218) (Sakib Hasan)
* Update translated strings Q3 2017 (Allen Boone)
* Add CODEOWNER file (Diana Lau)
* update messages.json (Diana Lau)
* add .travis.yml (Diana Lau)
2017-03-09, Version 3.2.0
=========================

View File

@ -1,4 +1,4 @@
Copyright (c) IBM Corp. 2013,2016. All Rights Reserved.
Copyright (c) IBM Corp. 2013,2017. All Rights Reserved.
Node module: loopback-component-storage
This project is licensed under the Artistic License 2.0, full text below.

View File

@ -2,19 +2,20 @@
**NOTE: The loopback-component-storage module supersedes [loopback-storage-service](https://www.npmjs.org/package/loopback-storage-service). Please update your package.json accordingly.**
LoopBack storage component provides Node.js and REST APIs to manage binary contents
LoopBack storage component provides Node.js and REST APIs to manage binary file contents
using pluggable storage providers, such as local file systems, Amazon S3, or
Rackspace cloud files. We use [pkgcloud](https://github.com/pkgcloud/pkgcloud) to support the cloud based
Rackspace cloud files. It uses [pkgcloud](https://github.com/pkgcloud/pkgcloud) to support cloud-based
storage services including:
- Amazon
- Rackspace
- Openstack
- Azure
- Google Cloud
- Openstack
- Rackspace
> Please see the [Storage Service Documentaion](http://loopback.io/doc/en/lb2/Storage-component.html).
> Please see the [Storage Service Documentaion](http://loopback.io/doc/en/lb3/Storage-component.html).
For more details on the architecture of the module, please see the introduction section of the [blog post](https://strongloop.com/strongblog/managing-nodejs-loopback-storage-service-provider/) written up its launch.
For more details on the architecture of the module, please see the introduction section of the [blog post](https://strongloop.com/strongblog/managing-nodejs-loopback-storage-service-provider/).
## Use
Now you can use Container's name with slash! If you want to create a directory, like `this/isMy/newContainer`, you have to use the char `%2F` instead of `/`, so your Container's name going to be `this%2FisMy%2FnewContainer`.

View File

@ -166,6 +166,30 @@ exports.upload = function(provider, req, res, options, cb) {
uploadParams.acl = file.acl;
}
// add AWS specific options
// See http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property
if (options.StorageClass) {
uploadParams.StorageClass = options.StorageClass;
}
if (options.CacheControl) {
uploadParams.CacheControl = options.CacheControl;
}
if (options.ServerSideEncryption) {
uploadParams.ServerSideEncryption = options.ServerSideEncryption;
}
if (options.SSEKMSKeyId) {
uploadParams.SSEKMSKeyId = options.SSEKMSKeyId;
}
if (options.SSECustomerAlgorithm) {
uploadParams.SSECustomerAlgorithm = options.SSECustomerAlgorithm;
}
if (options.SSECustomerKey) {
uploadParams.SSECustomerKey = options.SSECustomerKey;
}
if (options.SSECustomerKeyMD5) {
uploadParams.SSECustomerKeyMD5 = options.SSECustomerKeyMD5;
}
var writer = provider.upload(uploadParams);
writer.on('error', function(err) {

View File

@ -225,12 +225,21 @@ StorageService.prototype.removeFile = function(container, file, cb) {
/**
* Upload middleware for the HTTP request/response <!-- Should this be documented? -->
* @param {String} [container] Container name
* @param {Request} req Request object
* @param {Response} res Response object
* @param {Object} [options] Options for upload
* @param {Function} cb Callback function
*/
StorageService.prototype.upload = function(req, res, options, cb) {
StorageService.prototype.upload = function(container, req, res, options, cb) {
// Test if container is req for backward compatibility
if (typeof container === 'object' && container.url && container.method) {
// First argument is req, shift all args
cb = options;
options = res;
res = req;
req = container;
}
if (!cb && 'function' === typeof options) {
cb = options;
options = {};
@ -253,6 +262,9 @@ StorageService.prototype.upload = function(req, res, options, cb) {
if (this.maxFieldsSize && !options.maxFieldsSize) {
options.maxFieldsSize = this.maxFieldsSize;
}
if (typeof container === 'string') {
options.container = container;
}
return handler.upload(this.client, req, res, options, cb);
};
@ -282,7 +294,7 @@ StorageService.prototype.getContainers.http =
StorageService.prototype.getContainer.shared = true;
StorageService.prototype.getContainer.accepts = [
{arg: 'container', type: 'string'},
{arg: 'container', type: 'string', required: true, 'http': {source: 'path'}},
];
StorageService.prototype.getContainer.returns = {
arg: 'container',
@ -304,7 +316,7 @@ StorageService.prototype.createContainer.http =
StorageService.prototype.destroyContainer.shared = true;
StorageService.prototype.destroyContainer.accepts = [
{arg: 'container', type: 'string'},
{arg: 'container', type: 'string', required: true, 'http': {source: 'path'}},
];
StorageService.prototype.destroyContainer.returns = {};
StorageService.prototype.destroyContainer.http =
@ -312,7 +324,7 @@ StorageService.prototype.destroyContainer.http =
StorageService.prototype.getFiles.shared = true;
StorageService.prototype.getFiles.accepts = [
{arg: 'container', type: 'string'},
{arg: 'container', type: 'string', required: true, 'http': {source: 'path'}},
];
StorageService.prototype.getFiles.returns = {arg: 'files', type: 'array', root: true};
StorageService.prototype.getFiles.http =
@ -320,8 +332,8 @@ StorageService.prototype.getFiles.http =
StorageService.prototype.getFile.shared = true;
StorageService.prototype.getFile.accepts = [
{arg: 'container', type: 'string'},
{arg: 'file', type: 'string'},
{arg: 'container', type: 'string', required: true, 'http': {source: 'path'}},
{arg: 'file', type: 'string', required: true, 'http': {source: 'path'}},
];
StorageService.prototype.getFile.returns = {arg: 'file', type: 'object', root: true};
StorageService.prototype.getFile.http =
@ -329,8 +341,8 @@ StorageService.prototype.getFile.http =
StorageService.prototype.removeFile.shared = true;
StorageService.prototype.removeFile.accepts = [
{arg: 'container', type: 'string'},
{arg: 'file', type: 'string'},
{arg: 'container', type: 'string', required: true, 'http': {source: 'path'}},
{arg: 'file', type: 'string', required: true, 'http': {source: 'path'}},
];
StorageService.prototype.removeFile.returns = {};
StorageService.prototype.removeFile.http =
@ -338,6 +350,7 @@ StorageService.prototype.removeFile.http =
StorageService.prototype.upload.shared = true;
StorageService.prototype.upload.accepts = [
{arg: 'container', type: 'string', required: true, 'http': {source: 'path'}},
{arg: 'req', type: 'object', 'http': {source: 'req'}},
{arg: 'res', type: 'object', 'http': {source: 'res'}},
];
@ -347,8 +360,8 @@ StorageService.prototype.upload.http =
StorageService.prototype.download.shared = true;
StorageService.prototype.download.accepts = [
{arg: 'container', type: 'string', 'http': {source: 'path'}},
{arg: 'file', type: 'string', 'http': {source: 'path'}},
{arg: 'container', type: 'string', required: true, 'http': {source: 'path'}},
{arg: 'file', type: 'string', required: true, 'http': {source: 'path'}},
{arg: 'req', type: 'object', 'http': {source: 'req'}},
{arg: 'res', type: 'object', 'http': {source: 'res'}},
];

View File

@ -4,7 +4,7 @@
"engines": {
"node": ">=4"
},
"version": "3.2.0",
"version": "3.3.1",
"main": "index.js",
"scripts": {
"lint": "eslint .",

View File

@ -1,3 +1,4 @@
test.jpg
image-*.jpg
customimagefield_test.jpg
customimagefield_test.jpg
customimagefield1_test.jpg

View File

@ -32,6 +32,23 @@ app.post('/custom/upload', function(req, res, next) {
});
});
// custom route with renamer
app.post('/custom/uploadWithContainer', function(req, res, next) {
var options = {
getFilename: function(file, req, res) {
return file.field + '_' + file.name;
},
};
ds.connector.upload('album1', req, res, options, function(err, result) {
if (!err) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send({result: result});
} else {
res.status(500).send(err);
}
});
});
// expose a rest api
app.use(loopback.rest());
@ -420,4 +437,20 @@ describe('storage service', function() {
done();
});
});
it('should upload a file with container param', function(done) {
request('http://localhost:' + app.get('port'))
.post('/custom/uploadWithContainer')
.attach('customimagefield1', path.join(__dirname, './fixtures/test.jpg'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, function(err, res) {
assert.deepEqual(res.body, {'result': {'files': {'customimagefield1': [
{'container': 'album1', 'name': 'customimagefield1_test.jpg',
'originalFilename': 'test.jpg', 'type': 'image/jpeg',
'field': 'customimagefield1', 'size': 60475},
]}, 'fields': {}}});
done();
});
});
});