Compare commits

..

33 Commits

Author SHA1 Message Date
Miroslav Bajtoš 3b1b432b13
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)
2020-03-06 17:21:12 +01:00
Miroslav Bajtoš 11a3caf2d3
Merge pull request #288 from strongloop/feat/maintenance-lts
Update LTS status in README
2020-03-06 17:19:31 +01:00
Miroslav Bajtoš 479800e419
Update LTS status in README 2020-03-06 10:07:12 +01:00
Agnes Lin 3ada3ddf4e
Merge pull request #287 from strongloop/copyright
chore: update copyright year
2020-02-10 14:08:11 -05:00
Diana Lau 5668fe31f4 chore: update copyright year 2020-02-10 13:57:12 -05:00
Diana Lau c8f3b24141
Merge pull request #286 from syntheticgoo/patch-1
Update README.md
2020-01-29 22:08:03 -05:00
Shaun fd1a2527f2
Update README.md 2020-01-29 19:21:42 +00:00
Nora d020a178c4
Merge pull request #281 from strongloop/chore/improve-issue-templates
chore: improve issue and PR templates
2019-11-21 09:48:27 -05:00
Nora 6a18af7774 chore: improve issue and PR templates 2019-11-19 15:42:35 -05:00
Nora fee0855137
Merge pull request #282 from strongloop/drop-node-6
chore: drop Node.js 6 and add Node.js 12 to travis
2019-11-19 15:42:04 -05:00
Nora 02569bd3b5 chore: drop Node.js 6 and add Node.js 12 to travis 2019-11-19 15:19:39 -05:00
Diana Lau 60963c4415 3.6.3
* Rannig from other paths. Property files to array. (Diego A. Zapata Häntsch)
2019-07-25 13:37:24 -04:00
Diana Lau 963f334ee7
Merge pull request #279 from diegoazh/master
Fixes in PRs 252 and 242
2019-07-20 17:32:08 -04:00
Diego A. Zapata Häntsch 9205c9f079 Rannig from other paths. Property files to array. 2019-07-20 01:27:37 -03:00
Diana Lau 5608021675 3.6.2
* chore: update CODEOWNERS (Diana Lau)
 * Upgrade pkgcloud version (Diego A. Zapata Häntsch)
2019-07-12 11:30:47 -04:00
Diana Lau 351c3e8ebb
Merge pull request #277 from strongloop/codeowner
chore: update CODEOWNERS
2019-07-10 15:09:47 -04:00
Diana Lau 5c10529445 chore: update CODEOWNERS 2019-07-10 15:04:41 -04:00
Diana Lau 6ff4f2b234
Merge pull request #276 from diegoazh/master
Upgrade pkgcloud version
2019-07-10 14:56:40 -04:00
Diego A. Zapata Häntsch 3516cf642d Upgrade pkgcloud version
This upgrade fix the bug uploading files to google cloud storage.
This change solves the problem explained in issue #273.
2019-07-09 20:48:49 -03:00
Diana Lau 609b63c474 3.6.1
* update pkgcloud and use version 2.x (Anis)
 * chore: update copyrights years (Agnes Lin)
2019-05-23 15:56:37 -04:00
Diana Lau d2352bdc4c
Merge pull request #271 from rachedanis/update-pkgcloud-version
update pkgcloud and use version 2.x
2019-05-23 15:51:31 -04:00
Anis 1dc5a4dc81 update pkgcloud and use version 2.x 2019-05-14 10:33:15 +02:00
Agnes Lin a3c8509adf
Merge pull request #270 from strongloop/copyrights
chore: update copyrights years
2019-05-07 14:46:34 -04:00
Agnes Lin 6f8e4284f5 chore: update copyrights years 2019-05-07 09:41:29 -04:00
Diana Lau d8b7ebcd14 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)
2019-03-28 09:33:56 -04:00
Diana Lau 4eaec69fce
Merge pull request #267 from AlexOwen/master
Pass through AWS/S3 specific options
2019-03-28 09:31:37 -04:00
Alex Owen 30e8ee0a09 Pass through AWS/S3 specific options 2019-03-28 08:52:48 +00:00
Raymond Feng 00092b5129
Merge pull request #260 from mrbatista/feat/promise
add support to promise
2019-03-20 07:34:48 -07:00
Matteo Padovano 83a28273d4 add support to promise 2019-01-12 00:23:37 +01:00
Taranveer Virk e76d571a8c
Merge pull request #257 from strongloop/fix-linting
style: fix linting
2018-08-23 22:40:08 -04:00
virkt25 47002dceff style: fix linting 2018-08-23 22:09:45 -04:00
Taranveer Virk 7b4cf0b236
Merge pull request #255 from tkrugg/downloadStream
{download,upload}Stream: removed callback from doc
2018-08-23 21:57:32 -04:00
Youcef Mammar 0562cd03d4 {download,upload}Stream: removed callback from doc
closes #254
2018-08-23 06:27:33 +02:00
25 changed files with 618 additions and 133 deletions

View File

@ -1,37 +0,0 @@
<!--
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
-->

50
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@ -0,0 +1,50 @@
---
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

@ -0,0 +1,25 @@
---
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.

27
.github/ISSUE_TEMPLATE/Question.md vendored Normal file
View File

@ -0,0 +1,27 @@
---
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/
-->

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,11 @@
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,25 +1,18 @@
### Description
#### Related issues
<!-- <!--
Please use the following link syntaxes: Please provide a high-level description of the changes made by your pull request.
- connect to #49 (to reference issues in the current repository) Include references to all related GitHub issues and other pull requests, for example:
- connect to strongloop/loopback#49 (to reference issues in another repository)
Fixes #123
Implements #254
See also #23
--> -->
- connect to <link_to_referenced_issue> ## Checklist
### Checklist 👉 [Read and sign the CLA (Contributor License Agreement)](https://cla.strongloop.com/agreements/strongloop/loopback-component-storage) 👈
<!--
- 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 - [ ] New tests added or existing tests modified to cover all changes
- [ ] Code conforms with the [style - [ ] Code conforms with the [style guide](https://loopback.io/doc/en/contrib/style-guide-es6.html)
guide](http://loopback.io/doc/en/contrib/style-guide.html) - [ ] Commit messages are following our [guidelines](https://loopback.io/doc/en/contrib/git-commit-messages.html)

1
.npmrc Normal file
View File

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

View File

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

View File

@ -1,4 +1,52 @@
2018-07-10, Version 3.5.0 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
========================= =========================
* [WebFM] cs/pl/ru translation (candytangnb) * [WebFM] cs/pl/ru translation (candytangnb)

View File

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

View File

@ -1,6 +1,15 @@
# LoopBack Storage Component # LoopBack Storage Component
**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 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
LoopBack storage component provides Node.js and REST APIs to manage binary file 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 using pluggable storage providers, such as local file systems, Amazon S3, or
@ -13,10 +22,22 @@ storage services including:
- Openstack - Openstack
- Rackspace - Rackspace
> Please see the [Storage Service Documentaion](http://loopback.io/doc/en/lb3/Storage-component.html). > Please see the [Storage Service Documentation](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/). 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 ## Examples
See https://github.com/strongloop/loopback-example-storage. 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,7 +1,8 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved. // Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-component-storage // Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0. // This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0 // License text available at https://opensource.org/licenses/Artistic-2.0
'use strict'; 'use strict';
var SG = require('strong-globalize'); var SG = require('strong-globalize');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

20
lib/utils.js Normal file
View File

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

View File

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

View File

@ -1,7 +1,8 @@
// Copyright IBM Corp. 2013,2014. All Rights Reserved. // Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback-component-storage // Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0. // This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0 // License text available at https://opensource.org/licenses/Artistic-2.0
'use strict'; 'use strict';
var FileSystemProvider = require('../lib/providers/filesystem/index.js').Client; var FileSystemProvider = require('../lib/providers/filesystem/index.js').Client;
@ -30,6 +31,21 @@ describe('FileSystem based storage provider', function() {
process.nextTick(done); 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) { it('should complain if the root directory doesn\'t exist', function(done) {
try { try {
client = new FileSystemProvider({ client = new FileSystemProvider({
@ -45,11 +61,20 @@ describe('FileSystem based storage provider', function() {
it('should return an empty list of containers', function(done) { it('should return an empty list of containers', function(done) {
client.getContainers(function(err, containers) { client.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(0, containers.length); assert.equal(containers.length, 0);
done(err, containers); 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) { it('should create a new container', function(done) {
client.createContainer({name: 'c1'}, function(err, container) { client.createContainer({name: 'c1'}, function(err, container) {
assert(!err); assert(!err);
@ -58,6 +83,15 @@ 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) { it('should get a container c1', function(done) {
client.getContainer('c1', function(err, container) { client.getContainer('c1', function(err, container) {
assert(!err); assert(!err);
@ -66,6 +100,15 @@ 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) { it('should not get a container c2', function(done) {
client.getContainer('c2', function(err, container) { client.getContainer('c2', function(err, container) {
assert(err); assert(err);
@ -73,10 +116,18 @@ 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) { it('should return one container', function(done) {
client.getContainers(function(err, containers) { client.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(1, containers.length); assert.equal(containers.length, 1);
done(err, containers); done(err, containers);
}); });
}); });
@ -167,11 +218,20 @@ describe('FileSystem based storage provider', function() {
it('should get files for a container', function(done) { it('should get files for a container', function(done) {
client.getFiles('c1', function(err, files) { client.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(1, files.length); assert.equal(files.length, 1);
done(err, files); 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) { it('should get a file', function(done) {
client.getFile('c1', 'f1.txt', function(err, f) { client.getFile('c1', 'f1.txt', function(err, f) {
assert(!err); assert(!err);
@ -181,6 +241,16 @@ 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) { it('should remove a file', function(done) {
client.removeFile('c1', 'f1.txt', function(err) { client.removeFile('c1', 'f1.txt', function(err) {
assert(!err); assert(!err);
@ -188,29 +258,67 @@ 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) { it('should get no files from a container', function(done) {
client.getFiles('c1', function(err, files) { client.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(0, files.length); assert.equal(files.length, 0);
done(err, files); 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) { it('should not get a file from a container', function(done) {
client.getFile('c1', 'f2.txt', function(err, f) { client.getFile('c1', 'f2.txt', function(err, f) {
assert(err); assert(err);
assert.equal('ENOENT', err.code); assert.equal(err.code, 'ENOENT');
assert(!f); assert(!f);
done(); 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) { it('should destroy a container c1', function(done) {
client.destroyContainer('c1', function(err, container) { client.destroyContainer('c1', function(err, container) {
// console.error(err);
assert(!err); assert(!err);
done(err, container); 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,7 +1,8 @@
// Copyright IBM Corp. 2013,2015. All Rights Reserved. // Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback-component-storage // Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0. // This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0 // License text available at https://opensource.org/licenses/Artistic-2.0
'use strict'; 'use strict';
var StorageService = require('../lib/storage-service.js'); var StorageService = require('../lib/storage-service.js');
@ -19,11 +20,20 @@ describe('Storage service', function() {
it('should return an empty list of containers', function(done) { it('should return an empty list of containers', function(done) {
storageService.getContainers(function(err, containers) { storageService.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(0, containers.length); assert.equal(containers.length, 0);
done(err, containers); 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) { it('should create a new container', function(done) {
storageService.createContainer({name: 'c1'}, function(err, container) { storageService.createContainer({name: 'c1'}, function(err, container) {
assert(!err); assert(!err);
@ -32,6 +42,15 @@ 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) { it('should get a container c1', function(done) {
storageService.getContainer('c1', function(err, container) { storageService.getContainer('c1', function(err, container) {
assert(!err); assert(!err);
@ -40,6 +59,15 @@ 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) { it('should not get a container c2', function(done) {
storageService.getContainer('c2', function(err, container) { storageService.getContainer('c2', function(err, container) {
assert(err); assert(err);
@ -47,10 +75,18 @@ 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) { it('should return one container', function(done) {
storageService.getContainers(function(err, containers) { storageService.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(1, containers.length); assert.equal(containers.length, 1);
done(err, containers); done(err, containers);
}); });
}); });
@ -104,11 +140,20 @@ describe('Storage service', function() {
it('should get files for a container', function(done) { it('should get files for a container', function(done) {
storageService.getFiles('c1', function(err, files) { storageService.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(1, files.length); assert.equal(files.length, 1);
done(err, files); 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) { it('should get a file', function(done) {
storageService.getFile('c1', 'f1.txt', function(err, f) { storageService.getFile('c1', 'f1.txt', function(err, f) {
assert(!err); assert(!err);
@ -118,6 +163,16 @@ 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) { it('should remove a file', function(done) {
storageService.removeFile('c1', 'f1.txt', function(err) { storageService.removeFile('c1', 'f1.txt', function(err) {
assert(!err); assert(!err);
@ -125,10 +180,21 @@ 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) { it('should get no files from a container', function(done) {
storageService.getFiles('c1', function(err, files) { storageService.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(0, files.length); assert.equal(files.length, 0);
done(err, files); done(err, files);
}); });
}); });
@ -136,19 +202,39 @@ describe('Storage service', function() {
it('should not get a file from a container', function(done) { it('should not get a file from a container', function(done) {
storageService.getFile('c1', 'f1.txt', function(err, f) { storageService.getFile('c1', 'f1.txt', function(err, f) {
assert(err); assert(err);
assert.equal('ENOENT', err.code); assert.equal(err.code, 'ENOENT');
assert.equal(404, err.status); assert.equal(err.status, 404);
assert(!f); assert(!f);
done(); 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) { it('should destroy a container c1', function(done) {
storageService.destroyContainer('c1', function(err, container) { storageService.destroyContainer('c1', function(err, container) {
// console.error(err);
assert(!err); assert(!err);
done(err, container); 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,7 +1,8 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved. // Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-component-storage // Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0. // This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0 // License text available at https://opensource.org/licenses/Artistic-2.0
'use strict'; 'use strict';
var request = require('supertest'); var request = require('supertest');