├── example ├── storage │ ├── container1 │ │ ├── f1.txt │ │ └── f1_downloaded.txt │ └── container2 │ │ └── f2.txt ├── test.jpg ├── providers.json ├── app.js ├── app-cloud.js ├── upload.js ├── upload-amazon.js └── public │ ├── controllers.js │ ├── index.html │ ├── angular-file-upload.min.js │ ├── angular-file-upload.min.map │ └── angular-file-upload.js ├── example-2.0 ├── server │ ├── storage │ │ ├── container1 │ │ │ ├── f1.txt │ │ │ ├── uploadTest.txt │ │ │ ├── f1_downloaded.txt │ │ │ └── lb.png │ │ └── container2 │ │ │ └── f2.txt │ ├── component-config.json │ ├── config.json │ ├── models │ │ ├── container.json │ │ └── container.js │ ├── providers.json │ ├── datasources.json │ ├── boot │ │ └── authentication.js │ ├── middleware.json │ ├── model-config.json │ └── server.js ├── .jshintignore ├── client │ ├── README.md │ ├── controllers.js │ ├── index.html │ ├── angular-file-upload.min.js │ └── angular-file-upload.js ├── .npmignore ├── .editorconfig ├── .jshintrc └── package.json ├── example-3.0 ├── server │ ├── storage │ │ ├── container1 │ │ │ ├── f1.txt │ │ │ ├── uploadTest.txt │ │ │ ├── f1_downloaded.txt │ │ │ └── lb.png │ │ └── container2 │ │ │ └── f2.txt │ ├── component-config.json │ ├── models │ │ ├── container.js │ │ └── container.json │ ├── middleware.development.json │ ├── providers.json │ ├── datasources.json │ ├── boot │ │ └── authentication.js │ ├── config.json │ ├── model-config.json │ ├── middleware.json │ └── server.js ├── .jshintignore ├── client │ ├── README.md │ ├── controllers.js │ ├── index.html │ ├── angular-file-upload.min.js │ └── angular-file-upload.js ├── .npmignore ├── .editorconfig ├── .jshintrc └── package.json ├── CODEOWNERS ├── .gitignore ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE.md └── stale.yml ├── README.md ├── CONTRIBUTING.md └── LICENSE.md /example/storage/container1/f1.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example/storage/container2/f2.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example-2.0/server/storage/container1/f1.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example-2.0/server/storage/container2/f2.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example-3.0/server/storage/container1/f1.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example-3.0/server/storage/container2/f2.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example/storage/container1/f1_downloaded.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example-2.0/.jshintignore: -------------------------------------------------------------------------------- 1 | /client/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /example-3.0/.jshintignore: -------------------------------------------------------------------------------- 1 | /client/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /example-2.0/server/storage/container1/uploadTest.txt: -------------------------------------------------------------------------------- 1 | Upload test -------------------------------------------------------------------------------- /example-3.0/server/storage/container1/uploadTest.txt: -------------------------------------------------------------------------------- 1 | Upload test -------------------------------------------------------------------------------- /example-2.0/server/storage/container1/f1_downloaded.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example-3.0/server/storage/container1/f1_downloaded.txt: -------------------------------------------------------------------------------- 1 | Hello.... -------------------------------------------------------------------------------- /example/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback-example-storage/HEAD/example/test.jpg -------------------------------------------------------------------------------- /example-2.0/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /example-3.0/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /example-2.0/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /example-3.0/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /example-2.0/server/storage/container1/lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback-example-storage/HEAD/example-2.0/server/storage/container1/lb.png -------------------------------------------------------------------------------- /example-3.0/server/storage/container1/lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/loopback-example-storage/HEAD/example-3.0/server/storage/container1/lb.png -------------------------------------------------------------------------------- /example-2.0/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "legacyExplorer": false, 3 | "restApiRoot": "/api", 4 | "host": "0.0.0.0", 5 | "port": 3000, 6 | "url": "http://localhost:3000/" 7 | } 8 | -------------------------------------------------------------------------------- /example-3.0/server/models/container.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | 4 | module.exports = function(Container) { 5 | 6 | }; 7 | -------------------------------------------------------------------------------- /example-2.0/.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .project 3 | *.sublime-* 4 | .DS_Store 5 | *.seed 6 | *.log 7 | *.csv 8 | *.dat 9 | *.out 10 | *.pid 11 | *.swp 12 | *.swo 13 | node_modules 14 | coverage 15 | *.tgz 16 | *.xml 17 | -------------------------------------------------------------------------------- /example-2.0/server/models/container.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "container", 3 | "base": "Model", 4 | "properties": {}, 5 | "validations": [], 6 | "relations": {}, 7 | "acls": [], 8 | "methods": [] 9 | } 10 | -------------------------------------------------------------------------------- /example-3.0/.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .project 3 | *.sublime-* 4 | .DS_Store 5 | *.seed 6 | *.log 7 | *.csv 8 | *.dat 9 | *.out 10 | *.pid 11 | *.swp 12 | *.swo 13 | node_modules 14 | coverage 15 | *.tgz 16 | *.xml 17 | -------------------------------------------------------------------------------- /example-3.0/server/models/container.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "container", 3 | "base": "Model", 4 | "properties": {}, 5 | "validations": [], 6 | "relations": {}, 7 | "acls": [], 8 | "methods": [] 9 | } 10 | -------------------------------------------------------------------------------- /example-3.0/server/middleware.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "strong-error-handler": { 4 | "params": { 5 | "debug": true, 6 | "log": true 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners, 3 | # the last matching pattern has the most precendence. 4 | 5 | # Core team members from IBM 6 | * @kjdelisle @jannyHou @loay @b-admike @ssh24 @virkt25 @dhmlau 7 | -------------------------------------------------------------------------------- /example/providers.json: -------------------------------------------------------------------------------- 1 | { 2 | "rackspace": { 3 | "username": "your-rackspace-username", 4 | "apiKey": "your-rackspace-api-key", 5 | "region": "DFW" 6 | }, 7 | "amazon": { 8 | "key": "your-amazon-key", 9 | "keyId": "your-amazon-key-id" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example-2.0/server/providers.json: -------------------------------------------------------------------------------- 1 | { 2 | "rackspace": { 3 | "username": "your-rackspace-username", 4 | "apiKey": "your-rackspace-api-key", 5 | "region": "DFW" 6 | }, 7 | "amazon": { 8 | "key": "your-amazon-key", 9 | "keyId": "your-amazon-key-id" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example-3.0/server/providers.json: -------------------------------------------------------------------------------- 1 | { 2 | "rackspace": { 3 | "username": "your-rackspace-username", 4 | "apiKey": "your-rackspace-api-key", 5 | "region": "DFW" 6 | }, 7 | "amazon": { 8 | "key": "your-amazon-key", 9 | "keyId": "your-amazon-key-id" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example-2.0/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | }, 6 | "storage": { 7 | "name": "storage", 8 | "connector": "loopback-component-storage", 9 | "provider": "filesystem", 10 | "root": "./server/storage" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example-3.0/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db", 4 | "connector": "memory" 5 | }, 6 | "storage": { 7 | "name": "storage", 8 | "connector": "loopback-component-storage", 9 | "provider": "filesystem", 10 | "root": "./server/storage" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example-2.0/server/models/container.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | module.exports = function(Container) { 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /example-2.0/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /example-3.0/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /example-2.0/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | module.exports = function enableAuthentication(server) { 7 | // enable authentication 8 | server.enableAuth(); 9 | }; 10 | -------------------------------------------------------------------------------- /example-3.0/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | module.exports = function enableAuthentication(server) { 7 | // enable authentication 8 | server.enableAuth(); 9 | }; 10 | -------------------------------------------------------------------------------- /example-2.0/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": "nofunc", 11 | "newcap": true, 12 | "nonew": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "trailing": true, 19 | "sub": true, 20 | "maxlen": 80 21 | } 22 | -------------------------------------------------------------------------------- /example-3.0/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": "nofunc", 11 | "newcap": true, 12 | "nonew": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "trailing": true, 19 | "sub": true, 20 | "maxlen": 80 21 | } 22 | -------------------------------------------------------------------------------- /example-3.0/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "rest": { 7 | "normalizeHttpPath": false, 8 | "xml": false 9 | }, 10 | "json": { 11 | "strict": false, 12 | "limit": "100kb" 13 | }, 14 | "urlencoded": { 15 | "extended": true, 16 | "limit": "100kb" 17 | }, 18 | "cors": false, 19 | "handleErrors": false 20 | }, 21 | "legacyExplorer": false 22 | } 23 | -------------------------------------------------------------------------------- /example-2.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "loopback-example-storage", 3 | "version": "0.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "pretest": "jshint ." 7 | }, 8 | "dependencies": { 9 | "compression": "^1.0.3", 10 | "errorhandler": "^1.1.1", 11 | "loopback": "^2.0.0", 12 | "loopback-boot": "^2.0.0", 13 | "loopback-component-explorer": "^2.1.0", 14 | "loopback-component-storage": "^1.5.0", 15 | "loopback-datasource-juggler": "^2.7.0", 16 | "serve-favicon": "^2.0.1" 17 | }, 18 | "license": "Artistic-2.0", 19 | "author": "IBM Corp." 20 | } 21 | -------------------------------------------------------------------------------- /example-2.0/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {}, 4 | "loopback#compress": {} 5 | }, 6 | "initial": { 7 | "compression": {} 8 | }, 9 | "session": { 10 | }, 11 | "auth": { 12 | }, 13 | "parse": { 14 | }, 15 | "routes": { 16 | "loopback#rest": { 17 | "paths": ["${restApiRoot}"] 18 | } 19 | }, 20 | "files": { 21 | "loopback#static": { 22 | "params": "$!../client" 23 | } 24 | }, 25 | "final": { 26 | "loopback#urlNotFound": {} 27 | }, 28 | "final:after": { 29 | "errorhandler": {} 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /example-3.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "loopback-example-storage", 3 | "version": "0.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "pretest": "jshint ." 7 | }, 8 | "dependencies": { 9 | "compression": "^1.0.3", 10 | "errorhandler": "^1.1.1", 11 | "loopback": "^3.0.0", 12 | "cors": "^2.8.1", 13 | "loopback-boot": "^2.0.0", 14 | "loopback-component-explorer": "^2.1.0", 15 | "loopback-component-storage": "^3.0.0", 16 | "serve-favicon": "^2.0.1", 17 | "strong-error-handler": "^1.1.0" 18 | }, 19 | "license": "Artistic-2.0", 20 | "author": "IBM Corp." 21 | } 22 | -------------------------------------------------------------------------------- /example-2.0/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "../common/models", 5 | "./models" 6 | ] 7 | }, 8 | "User": { 9 | "dataSource": "db" 10 | }, 11 | "AccessToken": { 12 | "dataSource": "db", 13 | "public": false 14 | }, 15 | "ACL": { 16 | "dataSource": "db", 17 | "public": false 18 | }, 19 | "RoleMapping": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "Role": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "container": { 28 | "dataSource": "storage", 29 | "public": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /example-3.0/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "../common/models", 5 | "./models" 6 | ] 7 | }, 8 | "User": { 9 | "dataSource": "db" 10 | }, 11 | "AccessToken": { 12 | "dataSource": "db", 13 | "public": false 14 | }, 15 | "ACL": { 16 | "dataSource": "db", 17 | "public": false 18 | }, 19 | "RoleMapping": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "Role": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "container": { 28 | "dataSource": "storage", 29 | "public": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | -------------------------------------------------------------------------------- /example-3.0/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | } 14 | }, 15 | "session": { 16 | }, 17 | "auth": { 18 | }, 19 | "parse": { 20 | }, 21 | "routes": { 22 | "loopback#rest": { 23 | "paths": ["${restApiRoot}"] 24 | } 25 | }, 26 | "files": { 27 | "loopback#static": { 28 | "params": "$!../client" 29 | } 30 | }, 31 | "final": { 32 | "loopback#urlNotFound": {} 33 | }, 34 | "final:after": { 35 | "strong-error-handler": {} 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | 4 | #### Related issues 5 | 6 | 12 | 13 | - connect to 14 | 15 | ### Checklist 16 | 17 | 22 | 23 | - [ ] New tests added or existing tests modified to cover all changes 24 | - [ ] Code conforms with the [style 25 | guide](http://loopback.io/doc/en/contrib/style-guide.html) 26 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | var loopback = require('loopback') 7 | , app = module.exports = loopback(); 8 | 9 | var path = require('path'); 10 | 11 | // expose a rest api 12 | app.use('/api', loopback.rest()); 13 | 14 | app.use(loopback.static(path.join(__dirname, 'public'))); 15 | 16 | app.set('port', process.env.PORT || 3000); 17 | 18 | var ds = loopback.createDataSource({ 19 | connector: require('../index'), 20 | provider: 'filesystem', 21 | root: path.join(__dirname, 'storage') 22 | }); 23 | 24 | var container = ds.createModel('container'); 25 | 26 | app.model(container); 27 | 28 | app.listen(app.get('port')); 29 | console.log('http://127.0.0.1:' + app.get('port')); 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # Description/Steps to reproduce 11 | 12 | 16 | 17 | # Link to reproduction sandbox 18 | 19 | 24 | 25 | # Expected result 26 | 27 | 30 | 31 | # Additional information 32 | 33 | 38 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 14 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - critical 10 | - p1 11 | - major 12 | # Label to use when marking an issue as stale 13 | staleLabel: stale 14 | # Comment to post when marking an issue as stale. Set to `false` to disable 15 | markComment: > 16 | This issue has been automatically marked as stale because it has not had 17 | recent activity. It will be closed if no further activity occurs. Thank you 18 | for your contributions. 19 | # Comment to post when closing a stale issue. Set to `false` to disable 20 | closeComment: > 21 | This issue has been closed due to continued inactivity. Thank you for your understanding. 22 | If you believe this to be in error, please contact one of the code owners, 23 | listed in the `CODEOWNERS` file at the top-level of this repository. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # loopback-example-storage 2 | 3 | **⚠️ This LoopBack 3 example project is no longer maintained. Please refer to [LoopBack 4 Examples](https://loopback.io/doc/en/lb4/Examples.html) instead. ⚠️** 4 | 5 | Example for [loopback-component-storage](https://github.com/strongloop/loopback-component-storage). 6 | 7 | This repository contains three directories: 8 | 9 | - `example-3.0` - the LoopBack 3.0 app. Use this if you're using the current version (3.x) of LoopBack. 10 | - `example-2.0` - the legacy LoopBack 2.x app. 11 | - `example` - the legacy LoopBack 1.x app. 12 | 13 | Follow these steps to run the example: 14 | 15 | ``` 16 | $ git clone https://github.com/strongloop/loopback-example-storage.git 17 | $ cd loopback-example-storage/example-3.0 18 | $ npm install 19 | $ node . 20 | ``` 21 | 22 | Then load in your browser. 23 | 24 | See the documentation for the LoopBack [storage component](http://loopback.io/doc/en/lb3/Storage-component.html). 25 | 26 | --- 27 | 28 | [More LoopBack examples and tutorials](https://loopback.io/doc/en/lb3/Tutorials-and-examples.html) 29 | -------------------------------------------------------------------------------- /example-2.0/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | var loopback = require('loopback'); 7 | var boot = require('loopback-boot'); 8 | 9 | var app = module.exports = loopback(); 10 | 11 | app.start = function() { 12 | // start the web server 13 | return app.listen(function() { 14 | app.emit('started'); 15 | var baseUrl = app.get('url').replace(/\/$/, ''); 16 | console.log('Web server listening at: %s', baseUrl); 17 | if (app.get('loopback-component-explorer')) { 18 | var explorerPath = app.get('loopback-component-explorer').mountPath; 19 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath); 20 | } 21 | }); 22 | }; 23 | 24 | // Bootstrap the application, configure models, datasources and middleware. 25 | // Sub-apps like REST API are mounted via boot scripts. 26 | boot(app, __dirname, function(err) { 27 | if (err) throw err; 28 | 29 | // start the server if `$ node server.js` 30 | if (require.main === module) 31 | app.start(); 32 | }); 33 | -------------------------------------------------------------------------------- /example-3.0/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | var boot = require('loopback-boot'); 7 | var compression = require('compression'); 8 | var loopback = require('loopback'); 9 | 10 | var app = module.exports = loopback(); 11 | 12 | app.start = function() { 13 | // start the web server 14 | return app.listen(function() { 15 | app.emit('started'); 16 | var baseUrl = app.get('url').replace(/\/$/, ''); 17 | console.log('Web server listening at: %s', baseUrl); 18 | if (app.get('loopback-component-explorer')) { 19 | var explorerPath = app.get('loopback-component-explorer').mountPath; 20 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath); 21 | } 22 | }); 23 | }; 24 | 25 | // Bootstrap the application, configure models, datasources and middleware. 26 | // Sub-apps like REST API are mounted via boot scripts. 27 | boot(app, __dirname, function(err) { 28 | if (err) throw err; 29 | 30 | // start the server if `$ node server.js` 31 | if (require.main === module) 32 | app.start(); 33 | }); 34 | -------------------------------------------------------------------------------- /example/app-cloud.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | var StorageService = require('../').StorageService; 7 | var path = require('path'); 8 | var providers = null; 9 | try { 10 | providers = require('./providers-private.json'); 11 | } catch(err) { 12 | providers = require('./providers.json'); 13 | } 14 | 15 | function listContainersAndFiles(ss) { 16 | ss.getContainers(function (err, containers) { 17 | if (err) { 18 | console.error(err); 19 | return; 20 | } 21 | console.log('----------- %s (%d) ---------------', ss.provider, containers.length); 22 | containers.forEach(function (c) { 23 | console.log('[%s] %s/', ss.provider, c.name); 24 | c.getFiles(function (err, files) { 25 | files.forEach(function (f) { 26 | console.log('[%s] ... %s', ss.provider, f.name); 27 | }); 28 | }); 29 | }); 30 | }); 31 | } 32 | 33 | var rs = new StorageService({ 34 | provider: 'rackspace', 35 | username: providers.rackspace.username, 36 | apiKey: providers.rackspace.apiKey, 37 | region: providers.rackspace.region 38 | }); 39 | 40 | listContainersAndFiles(rs); 41 | 42 | var s3 = new StorageService({ 43 | provider: 'amazon', 44 | key: providers.amazon.key, 45 | keyId: providers.amazon.keyId 46 | }); 47 | 48 | listContainersAndFiles(s3); 49 | 50 | 51 | var fs = require('fs'); 52 | var path = require('path'); 53 | var stream = s3.uploadStream('con1', 'test.jpg'); 54 | fs.createReadStream(path.join(__dirname, 'test.jpg')).pipe(stream); 55 | 56 | var local = StorageService({ 57 | provider: 'filesystem', 58 | root: path.join(__dirname, 'storage') 59 | }); 60 | 61 | listContainersAndFiles(local); 62 | 63 | -------------------------------------------------------------------------------- /example/upload.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | var StorageService = require('../').StorageService; 7 | 8 | var express = require('express'); 9 | var app = express(); 10 | 11 | app.set('port', process.env.PORT || 3000); 12 | app.set('views', __dirname + '/views'); 13 | app.set('view engine', 'ejs'); 14 | 15 | // Create the container 16 | var mkdirp = require('mkdirp'); 17 | mkdirp.sync('/tmp/storage/con1'); 18 | 19 | var handler = new StorageService({provider: 'filesystem', root: '/tmp/storage'}); 20 | 21 | app.get('/', function(req, res, next) { 22 | res.setHeader('Content-Type', 'text/html'); 23 | var form = "

Storage Service Demo

" + 24 | "List all containers

" + 25 | "Upload to container con1:

" + 26 | "

" 27 | + "File to upload:
" 28 | + "Notes about the file:
" 29 | + "
" + 30 | ""; 31 | res.send(form); 32 | res.end(); 33 | }); 34 | 35 | app.post('/upload/:container', function(req, res, next) { 36 | handler.upload(req, res, function(err, result) { 37 | if (!err) { 38 | res.setHeader('Content-Type', 'application/json'); 39 | res.status(200).send(result); 40 | } else { 41 | res.status(500).send(err); 42 | } 43 | }); 44 | }); 45 | 46 | app.get('/download', function(req, res, next) { 47 | handler.getContainers(function(err, containers) { 48 | var html = "

Containers

Home

"; 53 | res.status(200).send(html); 54 | }); 55 | }); 56 | 57 | app.get('/download/:container', function(req, res, next) { 58 | handler.getFiles(req.params.container, function(err, files) { 59 | var html = "

Files in container " + req.params.container + "

Home

"; 64 | res.status(200).send(html); 65 | }); 66 | }); 67 | 68 | app.get('/download/:container/:file', function(req, res, next) { 69 | handler.download(req.params.container, req.params.file, res, function(err, result) { 70 | if (err) { 71 | res.status(500).send(err); 72 | } 73 | }); 74 | }); 75 | 76 | app.listen(app.get('port')); 77 | console.log('http://127.0.0.1:' + app.get('port')); 78 | -------------------------------------------------------------------------------- /example/upload-amazon.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | var StorageService = require('../').StorageService; 7 | var providers = null; 8 | try { 9 | providers = require('./providers-private.json'); 10 | } catch(err) { 11 | providers = require('./providers.json'); 12 | } 13 | var express = require('express'); 14 | var app = express(); 15 | 16 | app.set('port', process.env.PORT || 3000); 17 | app.set('views', __dirname + '/views'); 18 | app.set('view engine', 'ejs'); 19 | 20 | var handler = new StorageService( 21 | { 22 | provider: 'amazon', 23 | key: providers.amazon.key, 24 | keyId: providers.amazon.keyId 25 | }); 26 | 27 | app.get('/', function(req, res, next) { 28 | res.setHeader('Content-Type', 'text/html'); 29 | var form = "

Storage Service Demo

" + 30 | "List all containers

" + 31 | "Upload to container con1:

" + 32 | "

" 33 | + "File to upload:
" 34 | + "Notes about the file:
" 35 | + "
" + 36 | ""; 37 | res.send(form); 38 | res.end(); 39 | }); 40 | 41 | app.post('/upload/:container', function(req, res, next) { 42 | handler.upload(req, res, function(err, result) { 43 | if (!err) { 44 | res.setHeader('Content-Type', 'application/json'); 45 | res.status(200).send(result); 46 | } else { 47 | res.status(500).send(err); 48 | } 49 | }); 50 | }); 51 | 52 | app.get('/download', function(req, res, next) { 53 | handler.getContainers(function(err, containers) { 54 | var html = "

Containers

Home

"; 59 | res.status(200).send(html); 60 | }); 61 | }); 62 | 63 | app.get('/download/:container', function(req, res, next) { 64 | handler.getFiles(req.params.container, function(err, files) { 65 | var html = "

Files in container " + req.params.container + "

Home

"; 70 | res.status(200).send(html); 71 | }); 72 | }); 73 | 74 | app.get('/download/:container/:file', function(req, res, next) { 75 | handler.download(req.params.container, req.params.file, res, function(err, result) { 76 | if (err) { 77 | res.status(500).send(err); 78 | } 79 | }); 80 | }); 81 | 82 | app.listen(app.get('port')); 83 | console.log('http://127.0.0.1:' + app.get('port')); 84 | -------------------------------------------------------------------------------- /example/public/controllers.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | angular.module('app', ['angularFileUpload']) 7 | 8 | // The example of the full functionality 9 | .controller('TestController',function ($scope, $fileUploader) { 10 | 'use strict'; 11 | 12 | // create a uploader with options 13 | var uploader = $scope.uploader = $fileUploader.create({ 14 | scope: $scope, // to automatically update the html. Default: $rootScope 15 | url: '/api/containers/container1/upload', 16 | formData: [ 17 | { key: 'value' } 18 | ], 19 | filters: [ 20 | function (item) { // first user filter 21 | console.info('filter1'); 22 | return true; 23 | } 24 | ] 25 | }); 26 | 27 | // ADDING FILTERS 28 | 29 | uploader.filters.push(function (item) { // second user filter 30 | console.info('filter2'); 31 | return true; 32 | }); 33 | 34 | // REGISTER HANDLERS 35 | 36 | uploader.bind('afteraddingfile', function (event, item) { 37 | console.info('After adding a file', item); 38 | }); 39 | 40 | uploader.bind('whenaddingfilefailed', function (event, item) { 41 | console.info('When adding a file failed', item); 42 | }); 43 | 44 | uploader.bind('afteraddingall', function (event, items) { 45 | console.info('After adding all files', items); 46 | }); 47 | 48 | uploader.bind('beforeupload', function (event, item) { 49 | console.info('Before upload', item); 50 | }); 51 | 52 | uploader.bind('progress', function (event, item, progress) { 53 | console.info('Progress: ' + progress, item); 54 | }); 55 | 56 | uploader.bind('success', function (event, xhr, item, response) { 57 | console.info('Success', xhr, item, response); 58 | $scope.$broadcast('uploadCompleted', item); 59 | }); 60 | 61 | uploader.bind('cancel', function (event, xhr, item) { 62 | console.info('Cancel', xhr, item); 63 | }); 64 | 65 | uploader.bind('error', function (event, xhr, item, response) { 66 | console.info('Error', xhr, item, response); 67 | }); 68 | 69 | uploader.bind('complete', function (event, xhr, item, response) { 70 | console.info('Complete', xhr, item, response); 71 | }); 72 | 73 | uploader.bind('progressall', function (event, progress) { 74 | console.info('Total progress: ' + progress); 75 | }); 76 | 77 | uploader.bind('completeall', function (event, items) { 78 | console.info('Complete all', items); 79 | }); 80 | 81 | } 82 | ).controller('FilesController', function ($scope, $http) { 83 | 84 | $scope.load = function () { 85 | $http.get('/api/containers/container1/files').success(function (data) { 86 | console.log(data); 87 | $scope.files = data; 88 | }); 89 | }; 90 | 91 | $scope.delete = function (index, id) { 92 | $http.delete('/api/containers/container1/files/' + encodeURIComponent(id)).success(function (data, status, headers) { 93 | $scope.files.splice(index, 1); 94 | }); 95 | }; 96 | 97 | $scope.$on('uploadCompleted', function(event) { 98 | console.log('uploadCompleted event received'); 99 | $scope.load(); 100 | }); 101 | 102 | }); 103 | -------------------------------------------------------------------------------- /example-2.0/client/controllers.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | angular.module('app', ['angularFileUpload']) 7 | 8 | // The example of the full functionality 9 | .controller('TestController',function ($scope, FileUploader) { 10 | 'use strict'; 11 | 12 | // create a uploader with options 13 | 14 | var uploader = $scope.uploader = new FileUploader({ 15 | scope: $scope, // to automatically update the html. Default: $rootScope 16 | url: '/api/containers/container1/upload', 17 | formData: [ 18 | { key: 'value' } 19 | ] 20 | }); 21 | 22 | // ADDING FILTERS 23 | uploader.filters.push({ 24 | name: 'filterName', 25 | fn: function (item, options) { // second user filter 26 | console.info('filter2'); 27 | return true; 28 | } 29 | }); 30 | 31 | // REGISTER HANDLERS 32 | // -------------------- 33 | uploader.onAfterAddingFile = function(item) { 34 | console.info('After adding a file', item); 35 | }; 36 | // -------------------- 37 | uploader.onAfterAddingAll = function(items) { 38 | console.info('After adding all files', items); 39 | }; 40 | // -------------------- 41 | uploader.onWhenAddingFileFailed = function(item, filter, options) { 42 | console.info('When adding a file failed', item); 43 | }; 44 | // -------------------- 45 | uploader.onBeforeUploadItem = function(item) { 46 | console.info('Before upload', item); 47 | }; 48 | // -------------------- 49 | uploader.onProgressItem = function(item, progress) { 50 | console.info('Progress: ' + progress, item); 51 | }; 52 | // -------------------- 53 | uploader.onProgressAll = function(progress) { 54 | console.info('Total progress: ' + progress); 55 | }; 56 | // -------------------- 57 | uploader.onSuccessItem = function(item, response, status, headers) { 58 | console.info('Success', response, status, headers); 59 | $scope.$broadcast('uploadCompleted', item); 60 | }; 61 | // -------------------- 62 | uploader.onErrorItem = function(item, response, status, headers) { 63 | console.info('Error', response, status, headers); 64 | }; 65 | // -------------------- 66 | uploader.onCancelItem = function(item, response, status, headers) { 67 | console.info('Cancel', response, status); 68 | }; 69 | // -------------------- 70 | uploader.onCompleteItem = function(item, response, status, headers) { 71 | console.info('Complete', response, status, headers); 72 | }; 73 | // -------------------- 74 | uploader.onCompleteAll = function() { 75 | console.info('Complete all'); 76 | }; 77 | // -------------------- 78 | } 79 | ).controller('FilesController', function ($scope, $http) { 80 | 81 | $scope.load = function () { 82 | $http.get('/api/containers/container1/files').success(function (data) { 83 | console.log(data); 84 | $scope.files = data; 85 | }); 86 | }; 87 | 88 | $scope.delete = function (index, id) { 89 | $http.delete('/api/containers/container1/files/' + encodeURIComponent(id)).success(function (data, status, headers) { 90 | $scope.files.splice(index, 1); 91 | }); 92 | }; 93 | 94 | $scope.$on('uploadCompleted', function(event) { 95 | console.log('uploadCompleted event received'); 96 | $scope.load(); 97 | }); 98 | 99 | }); 100 | -------------------------------------------------------------------------------- /example-3.0/client/controllers.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | angular.module('app', ['angularFileUpload']) 7 | 8 | // The example of the full functionality 9 | .controller('TestController',function ($scope, FileUploader) { 10 | 'use strict'; 11 | 12 | // create a uploader with options 13 | 14 | var uploader = $scope.uploader = new FileUploader({ 15 | scope: $scope, // to automatically update the html. Default: $rootScope 16 | url: '/api/containers/container1/upload', 17 | formData: [ 18 | { key: 'value' } 19 | ] 20 | }); 21 | 22 | // ADDING FILTERS 23 | uploader.filters.push({ 24 | name: 'filterName', 25 | fn: function (item, options) { // second user filter 26 | console.info('filter2'); 27 | return true; 28 | } 29 | }); 30 | 31 | // REGISTER HANDLERS 32 | // -------------------- 33 | uploader.onAfterAddingFile = function(item) { 34 | console.info('After adding a file', item); 35 | }; 36 | // -------------------- 37 | uploader.onAfterAddingAll = function(items) { 38 | console.info('After adding all files', items); 39 | }; 40 | // -------------------- 41 | uploader.onWhenAddingFileFailed = function(item, filter, options) { 42 | console.info('When adding a file failed', item); 43 | }; 44 | // -------------------- 45 | uploader.onBeforeUploadItem = function(item) { 46 | console.info('Before upload', item); 47 | }; 48 | // -------------------- 49 | uploader.onProgressItem = function(item, progress) { 50 | console.info('Progress: ' + progress, item); 51 | }; 52 | // -------------------- 53 | uploader.onProgressAll = function(progress) { 54 | console.info('Total progress: ' + progress); 55 | }; 56 | // -------------------- 57 | uploader.onSuccessItem = function(item, response, status, headers) { 58 | console.info('Success', response, status, headers); 59 | $scope.$broadcast('uploadCompleted', item); 60 | }; 61 | // -------------------- 62 | uploader.onErrorItem = function(item, response, status, headers) { 63 | console.info('Error', response, status, headers); 64 | }; 65 | // -------------------- 66 | uploader.onCancelItem = function(item, response, status, headers) { 67 | console.info('Cancel', response, status); 68 | }; 69 | // -------------------- 70 | uploader.onCompleteItem = function(item, response, status, headers) { 71 | console.info('Complete', response, status, headers); 72 | }; 73 | // -------------------- 74 | uploader.onCompleteAll = function() { 75 | console.info('Complete all'); 76 | }; 77 | // -------------------- 78 | } 79 | ).controller('FilesController', function ($scope, $http) { 80 | 81 | $scope.load = function () { 82 | $http.get('/api/containers/container1/files').success(function (data) { 83 | console.log(data); 84 | $scope.files = data; 85 | }); 86 | }; 87 | 88 | $scope.delete = function (index, id) { 89 | $http.delete('/api/containers/container1/files/' + encodeURIComponent(id)).success(function (data, status, headers) { 90 | $scope.files.splice(index, 1); 91 | }); 92 | }; 93 | 94 | $scope.$on('uploadCompleted', function(event) { 95 | console.log('uploadCompleted event received'); 96 | $scope.load(); 97 | }); 98 | 99 | }); 100 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Contributing ### 2 | 3 | Thank you for your interest in `loopback-component-storage`, an open source project 4 | administered by StrongLoop. 5 | 6 | Contributing to `loopback-component-storage` is easy. In a few simple steps: 7 | 8 | * Ensure that your effort is aligned with the project's roadmap by 9 | talking to the maintainers, especially if you are going to spend a 10 | lot of time on it. 11 | 12 | * Make something better or fix a bug. 13 | 14 | * Adhere to code style outlined in the [Google C++ Style Guide][] and 15 | [Google Javascript Style Guide][]. 16 | 17 | * Sign the [Contributor License Agreement](https://cla.strongloop.com/agreements/strongloop/loopback-component-storage) 18 | 19 | * Submit a pull request through Github. 20 | 21 | 22 | ### Contributor License Agreement ### 23 | 24 | ``` 25 | Individual Contributor License Agreement 26 | 27 | By signing this Individual Contributor License Agreement 28 | ("Agreement"), and making a Contribution (as defined below) to 29 | StrongLoop, Inc. ("StrongLoop"), You (as defined below) accept and 30 | agree to the following terms and conditions for Your present and 31 | future Contributions submitted to StrongLoop. Except for the license 32 | granted in this Agreement to StrongLoop and recipients of software 33 | distributed by StrongLoop, You reserve all right, title, and interest 34 | in and to Your Contributions. 35 | 36 | 1. Definitions 37 | 38 | "You" or "Your" shall mean the copyright owner or the individual 39 | authorized by the copyright owner that is entering into this 40 | Agreement with StrongLoop. 41 | 42 | "Contribution" shall mean any original work of authorship, 43 | including any modifications or additions to an existing work, that 44 | is intentionally submitted by You to StrongLoop for inclusion in, 45 | or documentation of, any of the products owned or managed by 46 | StrongLoop ("Work"). For purposes of this definition, "submitted" 47 | means any form of electronic, verbal, or written communication 48 | sent to StrongLoop or its representatives, including but not 49 | limited to communication or electronic mailing lists, source code 50 | control systems, and issue tracking systems that are managed by, 51 | or on behalf of, StrongLoop for the purpose of discussing and 52 | improving the Work, but excluding communication that is 53 | conspicuously marked or otherwise designated in writing by You as 54 | "Not a Contribution." 55 | 56 | 2. You Grant a Copyright License to StrongLoop 57 | 58 | Subject to the terms and conditions of this Agreement, You hereby 59 | grant to StrongLoop and recipients of software distributed by 60 | StrongLoop, a perpetual, worldwide, non-exclusive, no-charge, 61 | royalty-free, irrevocable copyright license to reproduce, prepare 62 | derivative works of, publicly display, publicly perform, 63 | sublicense, and distribute Your Contributions and such derivative 64 | works under any license and without any restrictions. 65 | 66 | 3. You Grant a Patent License to StrongLoop 67 | 68 | Subject to the terms and conditions of this Agreement, You hereby 69 | grant to StrongLoop and to recipients of software distributed by 70 | StrongLoop a perpetual, worldwide, non-exclusive, no-charge, 71 | royalty-free, irrevocable (except as stated in this Section) 72 | patent license to make, have made, use, offer to sell, sell, 73 | import, and otherwise transfer the Work under any license and 74 | without any restrictions. The patent license You grant to 75 | StrongLoop under this Section applies only to those patent claims 76 | licensable by You that are necessarily infringed by Your 77 | Contributions(s) alone or by combination of Your Contributions(s) 78 | with the Work to which such Contribution(s) was submitted. If any 79 | entity institutes a patent litigation against You or any other 80 | entity (including a cross-claim or counterclaim in a lawsuit) 81 | alleging that Your Contribution, or the Work to which You have 82 | contributed, constitutes direct or contributory patent 83 | infringement, any patent licenses granted to that entity under 84 | this Agreement for that Contribution or Work shall terminate as 85 | of the date such litigation is filed. 86 | 87 | 4. You Have the Right to Grant Licenses to StrongLoop 88 | 89 | You represent that You are legally entitled to grant the licenses 90 | in this Agreement. 91 | 92 | If Your employer(s) has rights to intellectual property that You 93 | create, You represent that You have received permission to make 94 | the Contributions on behalf of that employer, that Your employer 95 | has waived such rights for Your Contributions, or that Your 96 | employer has executed a separate Corporate Contributor License 97 | Agreement with StrongLoop. 98 | 99 | 5. The Contributions Are Your Original Work 100 | 101 | You represent that each of Your Contributions are Your original 102 | works of authorship (see Section 8 (Submissions on Behalf of 103 | Others) for submission on behalf of others). You represent that to 104 | Your knowledge, no other person claims, or has the right to claim, 105 | any right in any intellectual property right related to Your 106 | Contributions. 107 | 108 | You also represent that You are not legally obligated, whether by 109 | entering into an agreement or otherwise, in any way that conflicts 110 | with the terms of this Agreement. 111 | 112 | You represent that Your Contribution submissions include complete 113 | details of any third-party license or other restriction (including, 114 | but not limited to, related patents and trademarks) of which You 115 | are personally aware and which are associated with any part of 116 | Your Contributions. 117 | 118 | 6. You Don't Have an Obligation to Provide Support for Your Contributions 119 | 120 | You are not expected to provide support for Your Contributions, 121 | except to the extent You desire to provide support. You may provide 122 | support for free, for a fee, or not at all. 123 | 124 | 6. No Warranties or Conditions 125 | 126 | StrongLoop acknowledges that unless required by applicable law or 127 | agreed to in writing, You provide Your Contributions on an "AS IS" 128 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 129 | EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES 130 | OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR 131 | FITNESS FOR A PARTICULAR PURPOSE. 132 | 133 | 7. Submission on Behalf of Others 134 | 135 | If You wish to submit work that is not Your original creation, You 136 | may submit it to StrongLoop separately from any Contribution, 137 | identifying the complete details of its source and of any license 138 | or other restriction (including, but not limited to, related 139 | patents, trademarks, and license agreements) of which You are 140 | personally aware, and conspicuously marking the work as 141 | "Submitted on Behalf of a Third-Party: [named here]". 142 | 143 | 8. Agree to Notify of Change of Circumstances 144 | 145 | You agree to notify StrongLoop of any facts or circumstances of 146 | which You become aware that would make these representations 147 | inaccurate in any respect. Email us at callback@strongloop.com. 148 | ``` 149 | 150 | [Google C++ Style Guide]: https://google.github.io/styleguide/cppguide.html 151 | [Google Javascript Style Guide]: https://google.github.io/styleguide/javascriptguide.xml 152 | -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LoopBack Storage Service Demo 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 | 52 | 53 |
54 | 55 |
56 | 57 |

Select files

58 | 59 |
60 | 61 |
62 | Base drop zone 63 |
64 | 65 | 66 |
68 | Another drop zone with its own settings 69 |
70 |
71 | 72 | 73 | Multiple 74 |
75 | 76 | Single 77 | 78 |
79 | 80 |
81 | 82 |

Upload queue

83 | 84 |

Queue length: {{ uploader.queue.length }}

85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 102 | 108 | 116 | 135 | 136 | 137 |
NameSizeProgressStatusActions
{{ item.file.name }}{{ 100 | item.file.size/1024/1024|number:2 }} MB 101 | 103 |
104 |
106 |
107 |
109 | 111 | 113 | 115 | 117 | 123 | 129 | 134 |
138 | 139 |
140 |

141 | Queue progress: 142 | 143 |

144 |
146 |
147 |

148 | 153 | 159 | 164 |
165 | 166 |
167 | 168 |
170 | 171 |

Files in the container

172 | 173 | 174 | 175 | 176 | 177 | 180 | 190 | 191 | 192 | 193 | 194 |
178 | {{ 179 | file.name }} 181 | 182 | 188 | 189 |
195 |
196 | 197 |
198 | 199 |
200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /example-2.0/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LoopBack Storage Service Demo 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 | 52 | 53 | 54 |
55 | 56 |
57 | 58 | 59 | 60 |

Select files

61 | 62 |
63 | 64 |
65 | Base drop zone 66 |
67 | 68 | 69 |
71 | Another drop zone with its own settings 72 |
73 |
74 | 75 | 76 | Multiple 77 |
78 | 79 | Single 80 | 81 |
82 | 83 |
84 | 85 |

Upload queue

86 | 87 |

Queue length: {{ uploader.queue.length }}

88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 105 | 111 | 119 | 138 | 139 | 140 |
NameSizeProgressStatusActions
{{ item.file.name }}{{ 103 | item.file.size/1024/1024|number:2 }} MB 104 | 106 |
107 |
109 |
110 |
112 | 114 | 116 | 118 | 120 | 126 | 132 | 137 |
141 | 142 |
143 |

144 | Queue progress: 145 | 146 |

147 |
149 |
150 |

151 | 156 | 162 | 167 |
168 | 169 |
170 | 171 |
173 | 174 |

Files in the container

175 | 176 | 177 | 178 | 179 | 180 | 183 | 193 | 194 | 195 | 196 | 197 |
181 | {{ 182 | file.name }} 184 | 185 | 191 | 192 |
198 |
199 | 200 |
201 | 202 | 203 |
204 | 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /example-3.0/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LoopBack Storage Service Demo 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 | 52 | 53 | 54 |
55 | 56 |
57 | 58 | 59 | 60 |

Select files

61 | 62 |
63 | 64 |
65 | Base drop zone 66 |
67 | 68 | 69 |
71 | Another drop zone with its own settings 72 |
73 |
74 | 75 | 76 | Multiple 77 |
78 | 79 | Single 80 | 81 |
82 | 83 |
84 | 85 |

Upload queue

86 | 87 |

Queue length: {{ uploader.queue.length }}

88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 105 | 111 | 119 | 138 | 139 | 140 |
NameSizeProgressStatusActions
{{ item.file.name }}{{ 103 | item.file.size/1024/1024|number:2 }} MB 104 | 106 |
107 |
109 |
110 |
112 | 114 | 116 | 118 | 120 | 126 | 132 | 137 |
141 | 142 |
143 |

144 | Queue progress: 145 | 146 |

147 |
149 |
150 |

151 | 156 | 162 | 167 |
168 | 169 |
170 | 171 |
173 | 174 |

Files in the container

175 | 176 | 177 | 178 | 179 | 180 | 183 | 193 | 194 | 195 | 196 | 197 |
181 | {{ 182 | file.name }} 184 | 185 | 191 | 192 |
198 |
199 | 200 |
201 | 202 | 203 |
204 | 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /example/public/angular-file-upload.min.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2016. All Rights Reserved. 2 | // Node module: loopback-example-storage 3 | // This file is licensed under the Artistic License 2.0. 4 | // License text available at https://opensource.org/licenses/Artistic-2.0 5 | 6 | /* 7 | Angular File Upload v0.3.3.1 8 | https://github.com/nervgh/angular-file-upload 9 | */ 10 | !function(a,b){return"function"==typeof define&&define.amd?(define("angular-file-upload",["angular"],function(a){return b(a)}),void 0):b(a)}(angular||null,function(a){var b=a.module("angularFileUpload",[]);return b.directive("ngFileDrop",["$fileUploader",function(b){"use strict";return{link:b.isHTML5?function(a,b,c){b.bind("drop",function(b){var d=b.dataTransfer?b.dataTransfer:b.originalEvent.dataTransfer;d&&(b.preventDefault(),b.stopPropagation(),a.$broadcast("file:removeoverclass"),a.$emit("file:add",d.files,a.$eval(c.ngFileDrop)))}).bind("dragover",function(b){var c=b.dataTransfer?b.dataTransfer:b.originalEvent.dataTransfer;b.preventDefault(),b.stopPropagation(),c.dropEffect="copy",a.$broadcast("file:addoverclass")}).bind("dragleave",function(){a.$broadcast("file:removeoverclass")})}:a.noop}}]),b.directive("ngFileOver",function(){"use strict";return{link:function(a,b,c){a.$on("file:addoverclass",function(){b.addClass(c.ngFileOver||"ng-file-over")}),a.$on("file:removeoverclass",function(){b.removeClass(c.ngFileOver||"ng-file-over")})}}}),b.directive("ngFileSelect",["$fileUploader",function(a){"use strict";return{link:function(b,c,d){a.isHTML5||c.removeAttr("multiple"),c.bind("change",function(){b.$emit("file:add",a.isHTML5?this.files:this,b.$eval(d.ngFileSelect)),a.isHTML5&&c.attr("multiple")&&c.prop("value",null)}),c.prop("value",null)}}}]),b.factory("$fileUploader",["$compile","$rootScope","$http","$window",function(b,c,d,e){"use strict";function f(b){a.extend(this,{scope:c,url:"/",alias:"file",queue:[],headers:{},progress:null,autoUpload:!1,removeAfterUpload:!1,method:"POST",filters:[],formData:[],isUploading:!1,_nextIndex:0,_timestamp:Date.now()},b),this.filters.unshift(this._filter),this.scope.$on("file:add",function(a,b,c){a.stopPropagation(),this.addToQueue(b,c)}.bind(this)),this.bind("beforeupload",g.prototype._beforeupload),this.bind("in:progress",g.prototype._progress),this.bind("in:success",g.prototype._success),this.bind("in:cancel",g.prototype._cancel),this.bind("in:error",g.prototype._error),this.bind("in:complete",g.prototype._complete),this.bind("in:progress",this._progress),this.bind("in:complete",this._complete)}function g(c){if(!f.prototype.isHTML5){var d=a.element(c.file),e=b(d.clone())(c.uploader.scope),g=d.val();c.file={lastModifiedDate:null,size:null,type:"like/"+g.slice(g.lastIndexOf(".")+1).toLowerCase(),name:g.slice(g.lastIndexOf("/")+g.lastIndexOf("\\")+2)},c._input=d,e.prop("value",null),d.css("display","none").after(e)}a.extend(this,{isReady:!1,isUploading:!1,isUploaded:!1,isSuccess:!1,isCancel:!1,isError:!1,progress:null,index:null},c)}return f.prototype={constructor:f,_filter:function(b){return a.isElement(b)?!0:!!b.size},bind:function(a,b){return this.scope.$on(this._timestamp+":"+a,b.bind(this))},trigger:function(a){arguments[0]=this._timestamp+":"+a,this.scope.$broadcast.apply(this.scope,arguments)},isHTML5:!(!e.File||!e.FormData),addToQueue:function(b,c){var d=this.queue.length,e="length"in b?b:[b];a.forEach(e,function(b){var d=this.filters.length?this.filters.every(function(a){return a.call(this,b)},this):!0,e=new g(a.extend({url:this.url,alias:this.alias,headers:a.copy(this.headers),formData:a.copy(this.formData),removeAfterUpload:this.removeAfterUpload,method:this.method,uploader:this,file:b},c));d?(this.queue.push(e),this.trigger("afteraddingfile",e)):this.trigger("whenaddingfilefailed",e)},this),this.queue.length!==d&&(this.trigger("afteraddingall",this.queue),this.progress=this._getTotalProgress()),this._render(),this.autoUpload&&this.uploadAll()},removeFromQueue:function(a){var b=this.getIndexOfItem(a),c=this.queue[b];c.isUploading&&c.cancel(),this.queue.splice(b,1),c._destroy(),this.progress=this._getTotalProgress()},clearQueue:function(){this.queue.forEach(function(a){a.isUploading&&a.cancel(),a._destroy()},this),this.queue.length=0,this.progress=0},getIndexOfItem:function(b){return a.isObject(b)?this.queue.indexOf(b):b},getNotUploadedItems:function(){return this.queue.filter(function(a){return!a.isUploaded})},getReadyItems:function(){return this.queue.filter(function(a){return a.isReady&&!a.isUploading}).sort(function(a,b){return a.index-b.index})},uploadItem:function(a){var b=this.getIndexOfItem(a),c=this.queue[b],d=this.isHTML5?"_xhrTransport":"_iframeTransport";c.index=c.index||this._nextIndex++,c.isReady=!0,this.isUploading||(this.isUploading=!0,this[d](c))},cancelItem:function(a){var b=this.getIndexOfItem(a),c=this.queue[b],d=this.isHTML5?"_xhr":"_form";c[d]&&c[d].abort()},uploadAll:function(){var a=this.getNotUploadedItems().filter(function(a){return!a.isUploading});a.forEach(function(a){a.index=a.index||this._nextIndex++,a.isReady=!0},this),a.length&&this.uploadItem(a[0])},cancelAll:function(){this.getNotUploadedItems().forEach(function(a){this.cancelItem(a)},this)},_render:function(){this.scope.$$phase||this.scope.$digest()},_getTotalProgress:function(a){if(this.removeAfterUpload)return a||0;var b=this.getNotUploadedItems().length,c=b?this.queue.length-b:this.queue.length,d=100/this.queue.length,e=(a||0)*d/100;return Math.round(c*d+e)},_progress:function(a,b,c){var d=this._getTotalProgress(c);this.trigger("progressall",d),this.progress=d,this._render()},_complete:function(){var b=this.getReadyItems()[0];return this.isUploading=!1,a.isDefined(b)?(this.uploadItem(b),void 0):(this.trigger("completeall",this.queue),this.progress=this._getTotalProgress(),this._render(),void 0)},_xhrTransport:function(b){var c=b._xhr=new XMLHttpRequest,d=new FormData,e=this;this.trigger("beforeupload",b),b.formData.forEach(function(b){a.forEach(b,function(a,b){d.append(b,a)})}),d.append(b.alias,b.file),c.upload.onprogress=function(a){var c=a.lengthComputable?100*a.loaded/a.total:0;e.trigger("in:progress",b,Math.round(c))},c.onload=function(){var a=e._transformResponse(c.response),d=e._isSuccessCode(c.status)?"success":"error";e.trigger("in:"+d,c,b,a),e.trigger("in:complete",c,b,a)},c.onerror=function(){e.trigger("in:error",c,b),e.trigger("in:complete",c,b)},c.onabort=function(){e.trigger("in:cancel",c,b),e.trigger("in:complete",c,b)},c.open(b.method,b.url,!0),a.forEach(b.headers,function(a,b){c.setRequestHeader(b,a)}),c.send(d)},_iframeTransport:function(b){var c=a.element('
'),d=a.element('