Compare commits

..

No commits in common. "master" and "v3.5.0" have entirely different histories.

25 changed files with 133 additions and 618 deletions

37
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,37 @@
<!--
Questions:
https://groups.google.com/forum/#!forum/loopbackjs
https://gitter.im/strongloop/loopback
Immediate support:
https://strongloop.com/api-connect-faqs/
https://strongloop.com/node-js/subscription-plans/
-->
# Description/Steps to reproduce
<!--
If feature: A description of the feature
If bug: Steps to reproduce
-->
# Link to reproduction sandbox
<!--
Link to an app sandbox for reproduction
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
# Expected result
<!--
Also include actual results if bug
-->
# Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->

View File

@ -1,50 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
labels: bug
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
HELP US HELP YOU, PLEASE
- Do a quick search to avoid duplicate issues
- Provide as much information as possible (reproduction sandbox, use case for features, etc.)
- Consider using a more suitable venue for questions such as Stack Overflow, Gitter, etc.
Please fill in the *entire* template below.
-->
## Steps to reproduce
<!-- Describe how to reproduce the issue -->
## Current Behavior
<!-- Describe the observed result -->
## Expected Behavior
<!-- Describe what did you expect instead, what is the desired outcome? -->
## Link to reproduction sandbox
<!--
See https://loopback.io/doc/en/contrib/Reporting-issues.html#loopback-3x-bugs
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
## Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->
## Related Issues
<!-- Did you find other bugs that looked similar? -->
_See [Reporting Issues](http://loopback.io/doc/en/contrib/Reporting-issues.html) for more tips on writing good issues_

View File

@ -1,25 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
labels: feature
---
## Suggestion
<!-- A summary of what you'd like to see added or changed -->
## Use Cases
<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->
## Examples
<!-- Show how this would be used and what the behavior would be -->
## Acceptance criteria
TBD - will be filled by the team.

View File

@ -1,27 +0,0 @@
---
name: Question
about: The issue tracker is not for questions. Please use Stack Overflow or other resources for help.
labels: question
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
THE ISSUE TRACKER IS NOT FOR QUESTIONS.
DO NOT CREATE A NEW ISSUE TO ASK A QUESTION.
Please use one of the following resources for help:
**Questions**
- https://stackoverflow.com/tags/loopbackjs
- https://groups.google.com/forum/#!forum/loopbackjs
- https://gitter.im/strongloop/loopback
**Immediate support**
- https://strongloop.com/api-connect-faqs/
- https://strongloop.com/node-js/subscription-plans/
-->

View File

@ -1,11 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://loopback.io/doc/en/contrib/Reporting-issues.html#security-issues
about: Do not report security vulnerabilities using GitHub issues. Please send an email to `reachsl@us.ibm.com` instead.
- name: Get help on StackOverflow
url: https://stackoverflow.com/tags/loopbackjs
about: Please ask and answer questions on StackOverflow.
- name: Join our mailing list
url: https://groups.google.com/forum/#!forum/loopbackjs
about: You can also post your question to our mailing list.

View File

@ -1,18 +1,25 @@
### Description
#### Related issues
<!--
Please provide a high-level description of the changes made by your pull request.
Please use the following link syntaxes:
Include references to all related GitHub issues and other pull requests, for example:
Fixes #123
Implements #254
See also #23
- connect to #49 (to reference issues in the current repository)
- connect to strongloop/loopback#49 (to reference issues in another repository)
-->
## Checklist
- connect to <link_to_referenced_issue>
👉 [Read and sign the CLA (Contributor License Agreement)](https://cla.strongloop.com/agreements/strongloop/loopback-component-storage) 👈
### Checklist
<!--
- Please mark your choice with an "x" (i.e. [x], see
https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments)
- PR's without test coverage will be closed.
-->
- [ ] `npm test` passes on your machine
- [ ] New tests added or existing tests modified to cover all changes
- [ ] Code conforms with the [style guide](https://loopback.io/doc/en/contrib/style-guide-es6.html)
- [ ] Commit messages are following our [guidelines](https://loopback.io/doc/en/contrib/git-commit-messages.html)
- [ ] Code conforms with the [style
guide](http://loopback.io/doc/en/contrib/style-guide.html)

1
.npmrc
View File

@ -1 +0,0 @@
package-lock=false

View File

@ -1,5 +1,5 @@
language: node_js
node_js:
- "6"
- "8"
- "10"
- "12"

View File

@ -1,52 +1,4 @@
2020-03-06, Version 3.7.0
=========================
* Update LTS status in README (Miroslav Bajtoš)
* chore: update copyright year (Diana Lau)
* Update README.md (Shaun)
* chore: improve issue and PR templates (Nora)
* chore: drop Node.js 6 and add Node.js 12 to travis (Nora)
2019-07-25, Version 3.6.3
=========================
* Rannig from other paths. Property files to array. (Diego A. Zapata Häntsch)
2019-07-12, Version 3.6.2
=========================
* chore: update CODEOWNERS (Diana Lau)
* Upgrade pkgcloud version (Diego A. Zapata Häntsch)
2019-05-23, Version 3.6.1
=========================
* update pkgcloud and use version 2.x (Anis)
* chore: update copyrights years (Agnes Lin)
2019-03-28, Version 3.6.0
=========================
* Pass through AWS/S3 specific options (Alex Owen)
* add support to promise (Matteo Padovano)
* style: fix linting (virkt25)
* {download,upload}Stream: removed callback from doc (Youcef Mammar)
2018-07-09, Version 3.5.0
2018-07-10, Version 3.5.0
=========================
* [WebFM] cs/pl/ru translation (candytangnb)

View File

@ -1,9 +1,6 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners,
# the last matching pattern has the most precedence.
# Alumni members
# @kjdelisle @loay @ssh24 @virkt25
# the last matching pattern has the most precendence.
# Core team members from IBM
* @jannyHou @b-admike @dhmlau @hacksparrow
* @kjdelisle @jannyHou @loay @b-admike @ssh24 @virkt25 @dhmlau

View File

@ -1,15 +1,6 @@
# LoopBack Storage Component
**⚠️ LoopBack 3 is in Maintenance LTS mode, only critical bugs and critical
security fixes will be provided. (See
[Module Long Term Support Policy](#module-long-term-support-policy) below.)**
We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as
soon as possible. Refer to our
[Migration Guide](https://loopback.io/doc/en/lb4/migration-overview.html)
for more information on how to upgrade.
## Overview
**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 file contents
using pluggable storage providers, such as local file systems, Amazon S3, or
@ -22,22 +13,10 @@ storage services including:
- Openstack
- Rackspace
> Please see the [Storage Service Documentation](http://loopback.io/doc/en/lb3/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/).
## Examples
See https://github.com/strongloop/loopback-example-storage.
## Module Long Term Support Policy
This module adopts the [
Module Long Term Support (LTS)](http://github.com/CloudNativeJS/ModuleLTS) policy,
with the following End Of Life (EOL) dates:
| Version | Status | Published | EOL |
| ------- | --------------- | --------- | -------- |
| 3.x | Maintenance LTS | Dec 2016 | Dec 2020 |
Learn more about our LTS plan in [docs](https://loopback.io/doc/en/contrib/Long-term-support.html).

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var SG = require('strong-globalize');

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2014. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var pkgcloud = require('pkgcloud');

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2014. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var base = require('pkgcloud').storage;

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2014. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var base = require('pkgcloud').storage;

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2015. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
// Globalization
@ -19,8 +18,6 @@ var fs = require('fs'),
File = require('./file').File,
Container = require('./container').Container;
var utils = require('./../../utils');
module.exports.storage = module.exports; // To make it consistent with pkgcloud
module.exports.File = File;
@ -32,12 +29,6 @@ module.exports.createClient = function(options) {
function FileSystemProvider(options) {
options = options || {};
if (!path.isAbsolute(options.root)) {
var basePath = path.dirname(path.dirname(require.main.filename));
options.root = path.join(basePath, options.root);
}
this.root = options.root;
var exists = fs.existsSync(this.root);
if (!exists) {
@ -104,17 +95,10 @@ function populateMetadata(stat, props) {
}
FileSystemProvider.prototype.getContainers = function(cb) {
cb = cb || utils.createPromiseCallback();
var self = this;
fs.readdir(self.root, function(err, files) {
var containers = [];
var tasks = [];
if (!files) {
files = [];
}
files.forEach(function(f) {
tasks.push(fs.stat.bind(fs, path.join(self.root, f)));
});
@ -135,20 +119,15 @@ FileSystemProvider.prototype.getContainers = function(cb) {
}
});
});
return cb.promise;
};
FileSystemProvider.prototype.createContainer = function(options, cb) {
cb = cb || utils.createPromiseCallback();
var self = this;
var name = options.name;
var dir = path.join(this.root, name);
validateName(name, cb) && fs.mkdir(dir, options, function(err) {
if (err) {
cb && cb(err);
return;
return cb && cb(err);
}
fs.stat(dir, function(err, stat) {
var container = null;
@ -160,13 +139,9 @@ FileSystemProvider.prototype.createContainer = function(options, cb) {
cb && cb(err, container);
});
});
return cb.promise;
};
FileSystemProvider.prototype.destroyContainer = function(containerName, cb) {
cb = cb || utils.createPromiseCallback();
if (!validateName(containerName, cb)) return;
var dir = path.join(this.root, containerName);
@ -185,13 +160,9 @@ FileSystemProvider.prototype.destroyContainer = function(containerName, cb) {
}
});
});
return cb.promise;
};
FileSystemProvider.prototype.getContainer = function(containerName, cb) {
cb = cb || utils.createPromiseCallback();
var self = this;
if (!validateName(containerName, cb)) return;
var dir = path.join(this.root, containerName);
@ -204,8 +175,6 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) {
}
cb && cb(err, container);
});
return cb.promise;
};
// File related functions
@ -283,9 +252,6 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) {
cb = options;
options = false;
}
cb = cb || utils.createPromiseCallback();
var self = this;
if (!validateName(container, cb)) return;
var dir = path.join(this.root, container);
@ -312,13 +278,9 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) {
}
});
});
return cb.promise;
};
FileSystemProvider.prototype.getFile = function(container, file, cb) {
cb = cb || utils.createPromiseCallback();
var self = this;
if (!validateName(container, cb)) return;
if (!validateName(file, cb)) return;
@ -332,8 +294,6 @@ FileSystemProvider.prototype.getFile = function(container, file, cb) {
}
cb && cb(err, f);
});
return cb.promise;
};
FileSystemProvider.prototype.getUrl = function(options) {
@ -343,13 +303,9 @@ FileSystemProvider.prototype.getUrl = function(options) {
};
FileSystemProvider.prototype.removeFile = function(container, file, cb) {
cb = cb || utils.createPromiseCallback();
if (!validateName(container, cb)) return;
if (!validateName(file, cb)) return;
var filePath = path.join(this.root, container, file);
fs.unlink(filePath, cb);
return cb.promise;
};

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2014. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var StorageService = require('./storage-service');

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2015. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
// Globalization
@ -53,11 +52,9 @@ exports.upload = function(provider, req, res, options, cb) {
self._fieldsSize += buffer.length;
if (self._fieldsSize > self.maxFieldsSize) {
self._error(new Error(
g.f(
'{{maxFieldsSize}} exceeded, received %s bytes of field data',
g.f('{{maxFieldsSize}} exceeded, received %s bytes of field data',
self._fieldsSize
)
));
)));
return;
}
value += decoder.write(buffer);
@ -107,12 +104,10 @@ exports.upload = function(provider, req, res, options, cb) {
if (Array.isArray(allowedContentTypes) && allowedContentTypes.length !== 0) {
if (allowedContentTypes.indexOf(file.type) === -1) {
self._error(new Error(
g.f(
'{{contentType}} "%s" is not allowed (Must be in [%s])',
g.f('{{contentType}} "%s" is not allowed (Must be in [%s])',
file.type,
allowedContentTypes.join(', ')
)
));
)));
return;
}
}
@ -148,21 +143,28 @@ exports.upload = function(provider, req, res, options, cb) {
uploadParams.acl = file.acl;
}
// AWS specific options
// add AWS specific options
// See http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property
const awsOptionNames = [
'StorageClass',
'CacheControl',
'ServerSideEncryption',
'SSEKMSKeyId',
'SSECustomerAlgorithm',
'SSECustomerKey',
'SSECustomerKeyMD5',
];
for (const awsOption of awsOptionNames) {
if (typeof options[awsOption] !== 'undefined') {
uploadParams[awsOption] = options[awsOption];
}
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);
@ -201,12 +203,10 @@ exports.upload = function(provider, req, res, options, cb) {
// - s3-upload-stream doesn't provide a way to do this in it's public interface
// - We could call provider.delete file but it would not delete multipart data
self._error(new Error(
g.f(
'{{maxFileSize}} exceeded, received %s bytes of field data (max is %s)',
g.f('{{maxFileSize}} exceeded, received %s bytes of field data (max is %s)',
fileSize,
maxFileSize
)
));
)));
return;
}
});

View File

@ -1,13 +1,11 @@
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var factory = require('./factory');
var handler = require('./storage-handler');
var utils = require('./utils');
var storage = require('pkgcloud').storage;
var debug = require('debug')('loopback:storage:service');
@ -55,22 +53,6 @@ function StorageService(options) {
if (options.maxFieldsSize) {
this.maxFieldsSize = options.maxFieldsSize;
}
// AWS specific options
// See http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property
const awsOptionNames = [
'StorageClass',
'CacheControl',
'ServerSideEncryption',
'SSEKMSKeyId',
'SSECustomerAlgorithm',
'SSECustomerKey',
'SSECustomerKeyMD5',
];
for (const awsOption of awsOptionNames) {
if (typeof options[awsOption] !== 'undefined') {
this[awsOption] = options[awsOption];
}
}
}
function map(obj) {
@ -82,11 +64,8 @@ function map(obj) {
* @callback {Function} callback Callback function
* @param {Object|String} err Error string or object
* @param {Object[]} containers An array of container metadata objects
* @promise
*/
StorageService.prototype.getContainers = function(cb) {
cb = cb || utils.createPromiseCallback();
this.client.getContainers(function(err, containers) {
if (err) {
cb(err, containers);
@ -96,8 +75,6 @@ StorageService.prototype.getContainers = function(cb) {
}));
}
});
return cb.promise;
};
/**
@ -108,24 +85,19 @@ StorageService.prototype.getContainers = function(cb) {
* @callback {Function} cb Callback function
* @param {Object|String} err Error string or object
* @param {Object} container Container metadata object
* @promise
*/
StorageService.prototype.createContainer = function(options, cb) {
options = options || {};
cb = cb || utils.createPromiseCallback();
if ('object' === typeof options && !(options instanceof storage.Container)) {
options.Name = options.name; // Amazon expects Name
var Container = factory.getProvider(this.provider).storage.Container;
options = new Container(this.client, options);
}
debug('Creating container with options %o', options);
this.client.createContainer(options, function(err, container) {
return this.client.createContainer(options, function(err, container) {
return cb(err, map(container));
});
return cb.promise;
};
/**
@ -133,13 +105,9 @@ StorageService.prototype.createContainer = function(options, cb) {
* @param {String} container Container name.
* @callback {Function} callback Callback function.
* @param {Object|String} err Error string or object
* @promise
*/
StorageService.prototype.destroyContainer = function(container, cb) {
cb = cb || utils.createPromiseCallback();
this.client.destroyContainer(container, cb);
return cb.promise;
return this.client.destroyContainer(container, cb);
};
/**
@ -148,20 +116,15 @@ StorageService.prototype.destroyContainer = function(container, cb) {
* @callback {Function} callback Callback function.
* @param {Object|String} err Error string or object
* @param {Object} container Container metadata object
* @promise
*/
StorageService.prototype.getContainer = function(container, cb) {
cb = cb || utils.createPromiseCallback();
this.client.getContainer(container, function(err, container) {
return this.client.getContainer(container, function(err, container) {
if (err && err.code === 'ENOENT') {
err.statusCode = err.status = 404;
return cb(err);
}
return cb(err, map(container));
});
return cb.promise;
};
/**
@ -169,6 +132,8 @@ StorageService.prototype.getContainer = function(container, cb) {
* @param {String} container Container name
* @param {String} file File name
* @options {Object} [options] Options for uploading
* @callback callback Callback function
* @param {String|Object} err Error string or object
* @returns {Stream} Stream for uploading
*/
StorageService.prototype.uploadStream = function(container, file, options) {
@ -191,6 +156,8 @@ StorageService.prototype.uploadStream = function(container, file, options) {
* @param {String} container Container name.
* @param {String} file File name.
* @options {Object} options Options for downloading
* @callback {Function} callback Callback function
* @param {String|Object} err Error string or object
* @returns {Stream} Stream for downloading
*/
StorageService.prototype.downloadStream = function(container, file, options) {
@ -215,7 +182,6 @@ StorageService.prototype.downloadStream = function(container, file, options) {
* @callback {Function} cb Callback function
* @param {Object|String} err Error string or object
* @param {Object[]} files An array of file metadata objects
* @promise
*/
StorageService.prototype.getFiles = function(container, options, cb) {
if (typeof options === 'function' && !cb) {
@ -223,10 +189,7 @@ StorageService.prototype.getFiles = function(container, options, cb) {
cb = options;
options = {};
}
cb = cb || utils.createPromiseCallback();
this.client.getFiles(container, options, function(err, files) {
return this.client.getFiles(container, options, function(err, files) {
if (err) {
cb(err, files);
} else {
@ -235,8 +198,6 @@ StorageService.prototype.getFiles = function(container, options, cb) {
}));
}
});
return cb.promise;
};
/**
@ -246,20 +207,15 @@ StorageService.prototype.getFiles = function(container, options, cb) {
* @callback {Function} cb Callback function
* @param {Object|String} err Error string or object
* @param {Object} file File metadata object
* @promise
*/
StorageService.prototype.getFile = function(container, file, cb) {
cb = cb || utils.createPromiseCallback();
this.client.getFile(container, file, function(err, f) {
return this.client.getFile(container, file, function(err, f) {
if (err && err.code === 'ENOENT') {
err.statusCode = err.status = 404;
return cb(err);
}
return cb(err, map(f));
});
return cb.promise;
};
/**
@ -268,13 +224,9 @@ StorageService.prototype.getFile = function(container, file, cb) {
* @param {String} file File name
* @callback {Function} cb Callback function
* @param {Object|String} err Error string or object
* @promise
*/
StorageService.prototype.removeFile = function(container, file, cb) {
cb = cb || utils.createPromiseCallback();
this.client.removeFile(container, file, cb);
return cb.promise;
return this.client.removeFile(container, file, cb);
};
/**
@ -284,7 +236,6 @@ StorageService.prototype.removeFile = function(container, file, cb) {
* @param {Response} res Response object
* @param {Object} [options] Options for upload
* @param {Function} cb Callback function
* @promise
*/
StorageService.prototype.upload = function(container, req, res, options, cb) {
debug('Configuring upload with options %o', options);
@ -300,9 +251,6 @@ StorageService.prototype.upload = function(container, req, res, options, cb) {
cb = options;
options = {};
}
cb = cb || utils.createPromiseCallback();
if (this.getFilename && !options.getFilename) {
options.getFilename = this.getFilename;
}
@ -321,32 +269,11 @@ StorageService.prototype.upload = function(container, req, res, options, cb) {
if (this.maxFieldsSize && !options.maxFieldsSize) {
options.maxFieldsSize = this.maxFieldsSize;
}
// AWS specific options
// See http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property
const awsOptionNames = [
'StorageClass',
'CacheControl',
'ServerSideEncryption',
'SSEKMSKeyId',
'SSECustomerAlgorithm',
'SSECustomerKey',
'SSECustomerKeyMD5',
];
for (const awsOption of awsOptionNames) {
if (this[awsOption] && !options[awsOption]) {
options[awsOption] = this[awsOption];
}
}
if (typeof container === 'string') {
options.container = container;
}
debug('Upload configured with options %o', options);
handler.upload(this.client, req, res, options, cb);
return cb.promise;
return handler.upload(this.client, req, res, options, cb);
};
/**
@ -356,13 +283,9 @@ StorageService.prototype.upload = function(container, req, res, options, cb) {
* @param {Request} req HTTP request
* @param {Response} res HTTP response
* @param {Function} cb Callback function
* @promise
*/
StorageService.prototype.download = function(container, file, req, res, cb) {
cb = cb || utils.createPromiseCallback();
handler.download(this.client, req, res, container, file, cb);
return cb.promise;
return handler.download(this.client, req, res, container, file, cb);
};
StorageService.modelName = 'storage';

View File

@ -1,20 +0,0 @@
// Copyright IBM Corp. 2018,2019. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
exports.createPromiseCallback = createPromiseCallback;
function createPromiseCallback() {
var cb;
var promise = new Promise(function(resolve, reject) {
cb = function(err, data) {
if (err) return reject(err);
return resolve(data);
};
});
cb.promise = promise;
return cb;
}

View File

@ -2,9 +2,9 @@
"name": "loopback-component-storage",
"description": "Loopback Storage Service",
"engines": {
"node": ">=8"
"node": ">=6"
},
"version": "3.7.0",
"version": "3.5.0",
"main": "index.js",
"scripts": {
"lint": "eslint .",
@ -15,15 +15,15 @@
"async": "^2.6.1",
"debug": "^3.1.0",
"formidable": "^1.2.1",
"pkgcloud": "^2.1.1",
"pkgcloud": "^1.5.0",
"strong-globalize": "^4.1.1",
"uuid": "^3.2.1"
},
"devDependencies": {
"eslint": "^5.4.0",
"eslint-config-loopback": "^11.0.0",
"eslint": "^4.19.1",
"eslint-config-loopback": "^10.0.0",
"express": "^4.16.3",
"loopback": "^3.22.1",
"loopback": "^3.20.0",
"mkdirp": "^0.5.1",
"mocha": "^5.2.0",
"supertest": "^3.1.0",
@ -33,6 +33,5 @@
"type": "git",
"url": "https://github.com/strongloop/loopback-component-storage.git"
},
"license": "Artistic-2.0",
"author": "IBM Corp."
"license": "Artistic-2.0"
}

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Copyright IBM Corp. 2016. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var loopback = require('loopback');

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2014. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var FileSystemProvider = require('../lib/providers/filesystem/index.js').Client;
@ -31,21 +30,6 @@ describe('FileSystem based storage provider', function() {
process.nextTick(done);
});
it('should work even it is ran from other path', function(done) {
process.chdir('../../../');
try {
console.log(`running from ${process.cwd()}`);
client = new FileSystemProvider({
root: path.join(__dirname, 'storage'),
});
process.nextTick(done);
} catch (error) {
process.nextTick(done(error));
}
});
it('should complain if the root directory doesn\'t exist', function(done) {
try {
client = new FileSystemProvider({
@ -61,20 +45,11 @@ describe('FileSystem based storage provider', function() {
it('should return an empty list of containers', function(done) {
client.getContainers(function(err, containers) {
assert(!err);
assert.equal(containers.length, 0);
assert.equal(0, containers.length);
done(err, containers);
});
});
it('should return an empty list of containers - promise', function(done) {
client.getContainers()
.then(function(containers) {
assert.equal(containers.length, 0);
done();
})
.catch(done);
});
it('should create a new container', function(done) {
client.createContainer({name: 'c1'}, function(err, container) {
assert(!err);
@ -83,15 +58,6 @@ describe('FileSystem based storage provider', function() {
});
});
it('should create a new container - promise', function(done) {
client.createContainer({name: 'c3'})
.then(function(container) {
verifyMetadata(container, 'c3');
done();
})
.catch(done);
});
it('should get a container c1', function(done) {
client.getContainer('c1', function(err, container) {
assert(!err);
@ -100,15 +66,6 @@ describe('FileSystem based storage provider', function() {
});
});
it('should get a container c1 - promise', function(done) {
client.getContainer('c1')
.then(function(container) {
verifyMetadata(container, 'c1');
done();
})
.catch(done);
});
it('should not get a container c2', function(done) {
client.getContainer('c2', function(err, container) {
assert(err);
@ -116,18 +73,10 @@ describe('FileSystem based storage provider', function() {
});
});
it('should destroy a container c3 - promise', function(done) {
client.destroyContainer('c3')
.then(function(container) {
done(null, container);
})
.catch(done);
});
it('should return one container', function(done) {
client.getContainers(function(err, containers) {
assert(!err);
assert.equal(containers.length, 1);
assert.equal(1, containers.length);
done(err, containers);
});
});
@ -218,20 +167,11 @@ describe('FileSystem based storage provider', function() {
it('should get files for a container', function(done) {
client.getFiles('c1', function(err, files) {
assert(!err);
assert.equal(files.length, 1);
assert.equal(1, files.length);
done(err, files);
});
});
it('should get files for a container - promise', function(done) {
client.getFiles('c1')
.then(function(files) {
assert.equal(files.length, 1);
done();
})
.catch(done);
});
it('should get a file', function(done) {
client.getFile('c1', 'f1.txt', function(err, f) {
assert(!err);
@ -241,16 +181,6 @@ describe('FileSystem based storage provider', function() {
});
});
it('should get a file - promise', function(done) {
client.getFile('c1', 'f1.txt')
.then(function(f) {
assert.ok(f);
verifyMetadata(f, 'f1.txt');
done();
})
.catch(done);
});
it('should remove a file', function(done) {
client.removeFile('c1', 'f1.txt', function(err) {
assert(!err);
@ -258,67 +188,29 @@ describe('FileSystem based storage provider', function() {
});
});
it('should remove a file - promise', function(done) {
createFile('c1', 'f1.txt').then(function() {
return client.removeFile('c1', 'f1.txt')
.then(function() {
done();
});
})
.catch(done);
});
it('should get no files from a container', function(done) {
client.getFiles('c1', function(err, files) {
assert(!err);
assert.equal(files.length, 0);
assert.equal(0, files.length);
done(err, files);
});
});
it('should get no files from a container - promise', function(done) {
client.getFiles('c1')
.then(function(files) {
assert.equal(files.length, 0);
done();
})
.catch(done);
});
it('should not get a file from a container', function(done) {
client.getFile('c1', 'f2.txt', function(err, f) {
assert(err);
assert.equal(err.code, 'ENOENT');
assert.equal('ENOENT', err.code);
assert(!f);
done();
});
});
it('should not get a file from a container - promise', function(done) {
client.getFile('c1', 'f2.txt')
.then(function() {
throw new Error('should not be throw');
})
.catch(function(err) {
assert.equal(err.code, 'ENOENT');
done();
});
});
it('should destroy a container c1', function(done) {
client.destroyContainer('c1', function(err, container) {
// console.error(err);
assert(!err);
done(err, container);
});
});
function createFile(container, file) {
return new Promise(function(resolve, reject) {
var writer = client.upload({container: container, remote: file});
fs.createReadStream(path.join(__dirname, 'files/f1.txt')).pipe(writer);
writer.on('finish', resolve);
writer.on('error', reject);
});
}
});
});

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Copyright IBM Corp. 2013,2015. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var StorageService = require('../lib/storage-service.js');
@ -20,20 +19,11 @@ describe('Storage service', function() {
it('should return an empty list of containers', function(done) {
storageService.getContainers(function(err, containers) {
assert(!err);
assert.equal(containers.length, 0);
assert.equal(0, containers.length);
done(err, containers);
});
});
it('should return an empty list of containers - promise', function(done) {
storageService.getContainers()
.then(function(containers) {
assert.equal(containers.length, 0);
done();
})
.catch(done);
});
it('should create a new container', function(done) {
storageService.createContainer({name: 'c1'}, function(err, container) {
assert(!err);
@ -42,15 +32,6 @@ describe('Storage service', function() {
});
});
it('should create a new container - promise', function(done) {
storageService.createContainer({name: 'c3'})
.then(function(container) {
assert(container.getMetadata());
done();
})
.catch(done);
});
it('should get a container c1', function(done) {
storageService.getContainer('c1', function(err, container) {
assert(!err);
@ -59,15 +40,6 @@ describe('Storage service', function() {
});
});
it('should get a container c1 - promise', function(done) {
storageService.getContainer('c1')
.then(function(container) {
assert(container.getMetadata());
done();
})
.catch(done);
});
it('should not get a container c2', function(done) {
storageService.getContainer('c2', function(err, container) {
assert(err);
@ -75,18 +47,10 @@ describe('Storage service', function() {
});
});
it('should destroy a container c3 - promise', function(done) {
storageService.destroyContainer('c3')
.then(function(container) {
done(null, container);
})
.catch(done);
});
it('should return one container', function(done) {
storageService.getContainers(function(err, containers) {
assert(!err);
assert.equal(containers.length, 1);
assert.equal(1, containers.length);
done(err, containers);
});
});
@ -140,20 +104,11 @@ describe('Storage service', function() {
it('should get files for a container', function(done) {
storageService.getFiles('c1', function(err, files) {
assert(!err);
assert.equal(files.length, 1);
assert.equal(1, files.length);
done(err, files);
});
});
it('should get files for a container - promise', function(done) {
storageService.getFiles('c1')
.then(function(files) {
assert.equal(files.length, 1);
done();
})
.catch(done);
});
it('should get a file', function(done) {
storageService.getFile('c1', 'f1.txt', function(err, f) {
assert(!err);
@ -163,16 +118,6 @@ describe('Storage service', function() {
});
});
it('should get a file - promise', function(done) {
storageService.getFile('c1', 'f1.txt')
.then(function(f) {
assert.ok(f);
assert(f.getMetadata());
done();
})
.catch(done);
});
it('should remove a file', function(done) {
storageService.removeFile('c1', 'f1.txt', function(err) {
assert(!err);
@ -180,21 +125,10 @@ describe('Storage service', function() {
});
});
it('should remove a file - promise', function(done) {
createFile('c1', 'f1.txt')
.then(function() {
return storageService.removeFile('c1', 'f1.txt')
.then(function() {
done();
});
})
.catch(done);
});
it('should get no files from a container', function(done) {
storageService.getFiles('c1', function(err, files) {
assert(!err);
assert.equal(files.length, 0);
assert.equal(0, files.length);
done(err, files);
});
});
@ -202,39 +136,19 @@ describe('Storage service', function() {
it('should not get a file from a container', function(done) {
storageService.getFile('c1', 'f1.txt', function(err, f) {
assert(err);
assert.equal(err.code, 'ENOENT');
assert.equal(err.status, 404);
assert.equal('ENOENT', err.code);
assert.equal(404, err.status);
assert(!f);
done();
});
});
it('should not get a file from a container - promise', function(done) {
storageService.getFile('c1', 'f1.txt')
.then(function() {
throw new Error('should not be throw');
})
.catch(function(err) {
assert.equal(err.code, 'ENOENT');
assert.equal(err.status, 404);
done();
});
});
it('should destroy a container c1', function(done) {
storageService.destroyContainer('c1', function(err, container) {
// console.error(err);
assert(!err);
done(err, container);
});
});
function createFile(container, file) {
return new Promise(function(resolve, reject) {
var writer = storageService.uploadStream(container, file);
fs.createReadStream(path.join(__dirname, 'files/f1.txt')).pipe(writer);
writer.on('finish', resolve);
writer.on('error', reject);
});
}
});
});

View File

@ -1,8 +1,7 @@
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
'use strict';
var request = require('supertest');