From d29f47c538484afd2c1897986a4dbf8de9c869f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:28:54 -0300 Subject: [PATCH 01/54] Actualizar README --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index ea8a88e..88e0979 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,22 @@ storage services including: For more details on the architecture of the module, please see the introduction section of the [blog post](https://strongloop.com/strongblog/managing-nodejs-loopback-storage-service-provider/) written up its launch. +## Use +Now you can use Container's name with slash! If you want to create a directory, like `this/isMy/newContainer`, you have to use the char `%2F` instead of `/`, so your Container's name going to be `this%2FisMy%2FnewContainer`. + +## URL Example +Syntax +``` +[POST] <>:<>/api/Containers/<>/ +[POST] <>:<>/api/Containers/<>/upload (For upload file) +``` + +Example +``` +[POST] http://example.com:3000/api/Containers/images%2Fprofile%2Fpersonal/ +[POST] http://example.com:3000/api/Containers/images%2Fprofile%2Fpersonal/upload (For upload file) +``` + ## Examples See https://github.com/strongloop/loopback-example-storage. From 71e0d5255fd12c5e9972305c67e3e71e4bd459bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:45:47 -0300 Subject: [PATCH 02/54] Actualizar dependencias --- package.json | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 package.json diff --git a/package.json b/package.json old mode 100644 new mode 100755 index 90739b5..b8bfec5 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dependencies": { "async": "^2.1.5", "formidable": "^1.0.16", + "mkdirp": "^0.5.1", "pkgcloud": "^1.1.0", "strong-globalize": "^2.6.2", "uuid": "^3.0.1" From 46e681dd47885cfb83e41dbc3165788e8a1c1635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:46:20 -0300 Subject: [PATCH 03/54] Verificar que nombre de Contenedor es un string --- lib/providers/filesystem/index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index a941587..6dcc5fd 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -124,6 +124,8 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; + var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); + name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); validateName(name, cb) && fs.mkdir(dir, options, function(err) { if (err) { @@ -180,12 +182,8 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - if (!validateName(container)) { - return writeStreamError( - new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', container)), - cb - ); - } + var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); + container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { return writeStreamError( From 22ddb136b1b80620e670d506a2c87a58715729dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:46:40 -0300 Subject: [PATCH 04/54] Verificar si existe dataSources.json --- lib/storage-handler.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index cc7a444..e9d60fa 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -11,11 +11,31 @@ var IncomingForm = require('formidable'); var StringDecoder = require('string_decoder').StringDecoder; var path = require('path'); var uuid = require('uuid'); - -var defaultOptions = { - maxFileSize: 10 * 1024 * 1024, // 10 MB +var fs = require('fs'); +var defaultOptions = function() { + var dataSources = path.join(__dirname, '../../../server/datasources.json'); + fs.stat(dataSources, function(err, stats) { + if(!error) { + return require(dataSources).container; + } else { + return false; + } + }); }; +var isImage = function(ext) { + switch(ext) { + case '.jpg': + case '.jpeg': + case '.png': + return true; + break; + default: + return false; + break; + } +} + /** * Handle multipart/form-data upload to the storage service * @param {Object} provider The storage service provider From d152ca900acc2308ca6058763f81f9633cfc31db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:50:11 -0300 Subject: [PATCH 05/54] Explicar nueva funcionalidad en README --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 88e0979..d139e3f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,22 @@ Example [POST] http://example.com:3000/api/Containers/images%2Fprofile%2Fpersonal/upload (For upload file) ``` +## Add option to your dataSources.json +If you want a default name only for the upload images (not files), you have to add `defaultImageName` to your Container options. +**datasources.json** +``` +[...] + "container": { + "name": "container", + "connector": "loopback-component-storage", + "provider": "filesystem", + "maxFileSize": "10485760", + "root": "./storage", + "defaultImageName": "photo" + } +[...] + ``` + ## Examples See https://github.com/strongloop/loopback-example-storage. From 9cefe77adef3dc205d002f852a7ecd47e83198c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 04:34:00 -0300 Subject: [PATCH 06/54] Arreglar error de test --- lib/providers/filesystem/index.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 6dcc5fd..8d0f038 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -124,22 +124,24 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; - var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); + var hasSlash = name.search('%2F'); name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); - validateName(name, cb) && fs.mkdir(dir, options, function(err) { - if (err) { - return cb && cb(err); + + mkdirp(dir, function(err) { + if(err) { + cb(err); + } else { + fs.stat(dir, function(err, stat) { + var container = null; + if(!err) { + var props = { name: name }; + populateMetadata(stat, props); + container = new Container(self, props); + } + cb(err, container); + }); } - fs.stat(dir, function(err, stat) { - var container = null; - if (!err) { - var props = {name: name}; - populateMetadata(stat, props); - container = new Container(self, props); - } - cb && cb(err, container); - }); }); }; @@ -182,7 +184,7 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); + var hasSlash = container.search('%2F'); container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { From 955b1153f7ed97cfd275bc94661815e05eefb5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 04:42:06 -0300 Subject: [PATCH 07/54] Arreglar errores de eslint --- lib/providers/filesystem/index.js | 6 +++--- lib/storage-handler.js | 13 +++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 8d0f038..842dca9 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -129,13 +129,13 @@ FileSystemProvider.prototype.createContainer = function(options, cb) { var dir = path.join(this.root, name); mkdirp(dir, function(err) { - if(err) { + if (err) { cb(err); } else { fs.stat(dir, function(err, stat) { var container = null; - if(!err) { - var props = { name: name }; + if (!err) { + var props = {name: name}; populateMetadata(stat, props); container = new Container(self, props); } diff --git a/lib/storage-handler.js b/lib/storage-handler.js index e9d60fa..8bfad14 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -15,7 +15,7 @@ var fs = require('fs'); var defaultOptions = function() { var dataSources = path.join(__dirname, '../../../server/datasources.json'); fs.stat(dataSources, function(err, stats) { - if(!error) { + if (!err) { return require(dataSources).container; } else { return false; @@ -24,7 +24,7 @@ var defaultOptions = function() { }; var isImage = function(ext) { - switch(ext) { + switch (ext) { case '.jpg': case '.jpeg': case '.png': @@ -34,7 +34,7 @@ var isImage = function(ext) { return false; break; } -} +}; /** * Handle multipart/form-data upload to the storage service @@ -93,9 +93,14 @@ exports.upload = function(provider, req, res, options, cb) { this._flushing++; + var fileName = part.filename; + var useDefaultname = (typeof defaultOptions.defaultImageName != 'undefined' ? + true : false); + var file = { container: container, - name: part.filename, + name: (isImage(path.extname(fileName)) && useDefaultname ? + defaultOptions.defaultImageName + path.extname(fileName) : fileName), type: part.mime, field: part.name, }; From d981e28ca1ee3b2671c100617222d9f3358e73ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:20:36 -0300 Subject: [PATCH 08/54] Crear contenedores y subir archivos con '/' --- lib/providers/filesystem/index.js | 7 ++++--- lib/storage-handler.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 842dca9..5a8870c 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -16,7 +16,8 @@ var fs = require('fs'), stream = require('stream'), async = require('async'), File = require('./file').File, - Container = require('./container').Container; + Container = require('./container').Container, + mkdirp = require('mkdirp'); module.exports.storage = module.exports; // To make it consistent with pkgcloud @@ -194,8 +195,8 @@ FileSystemProvider.prototype.upload = function(options, cb) { ); } var filePath = path.join(this.root, container, file); - - var fileOpts = {flags: options.flags || 'w+', + var fileOpts = { + flags: options.flags || 'w+', encoding: options.encoding || null, mode: options.mode || parseInt('0666', 8), }; diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 8bfad14..bd66ad9 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -52,7 +52,7 @@ exports.upload = function(provider, req, res, options, cb) { } if (!options.maxFileSize) { - options.maxFileSize = defaultOptions.maxFileSize; + options.maxFileSize = defaultOptions.maxFileSize || 10 * 1024 * 1024; } var form = new IncomingForm(options); From 8f7fdfa20c17372140128f5f3507f12b0ef600cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:46:20 -0300 Subject: [PATCH 10/54] Verificar que nombre de Contenedor es un string --- lib/providers/filesystem/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 5a8870c..3d21f83 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -125,7 +125,7 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; - var hasSlash = name.search('%2F'); + var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); @@ -185,7 +185,7 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - var hasSlash = container.search('%2F'); + var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { From 7bd662151af2cdf1ca8620d82c287a92e2942fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:46:40 -0300 Subject: [PATCH 11/54] Verificar si existe dataSources.json --- lib/storage-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index bd66ad9..911b560 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -15,7 +15,7 @@ var fs = require('fs'); var defaultOptions = function() { var dataSources = path.join(__dirname, '../../../server/datasources.json'); fs.stat(dataSources, function(err, stats) { - if (!err) { + if(!error) { return require(dataSources).container; } else { return false; From 44ed5365782c450bba43328615227df567492603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 04:34:00 -0300 Subject: [PATCH 12/54] Arreglar error de test --- lib/providers/filesystem/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 3d21f83..5a8870c 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -125,7 +125,7 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; - var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); + var hasSlash = name.search('%2F'); name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); @@ -185,7 +185,7 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); + var hasSlash = container.search('%2F'); container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { From 38b1b2fae6ca9d99dd2e5ba1335a4b30d040f636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 04:42:06 -0300 Subject: [PATCH 13/54] Arreglar errores de eslint --- lib/storage-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 911b560..bd66ad9 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -15,7 +15,7 @@ var fs = require('fs'); var defaultOptions = function() { var dataSources = path.join(__dirname, '../../../server/datasources.json'); fs.stat(dataSources, function(err, stats) { - if(!error) { + if (!err) { return require(dataSources).container; } else { return false; From 4005a8fc2e35c9dd4a2e61d44c8f543fcb296480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:46:20 -0300 Subject: [PATCH 15/54] Verificar que nombre de Contenedor es un string --- lib/providers/filesystem/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 5a8870c..3d21f83 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -125,7 +125,7 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; - var hasSlash = name.search('%2F'); + var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); @@ -185,7 +185,7 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - var hasSlash = container.search('%2F'); + var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { From c0b546aa954676715124a30bd073ba9437e026e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 04:34:00 -0300 Subject: [PATCH 17/54] Arreglar error de test --- lib/providers/filesystem/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 3d21f83..5a8870c 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -125,7 +125,7 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; - var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); + var hasSlash = name.search('%2F'); name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); @@ -185,7 +185,7 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); + var hasSlash = container.search('%2F'); container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { From 6b1f9ffc8d17fa0790b640e940a14c8a7bfcf95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 05:33:24 -0300 Subject: [PATCH 18/54] =?UTF-8?q?Arreglar=20petici=C3=B3n=20de=20archivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/providers/filesystem/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 5a8870c..1620db0 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -283,7 +283,6 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) { FileSystemProvider.prototype.getFile = function(container, file, cb) { var self = this; - if (!validateName(container, cb)) return; if (!validateName(file, cb)) return; var filePath = path.join(this.root, container, file); fs.stat(filePath, function(err, stat) { From edd5651e0e457bbc19b9a8ef51f3b3f165d1ae8c Mon Sep 17 00:00:00 2001 From: Cristobal Vergara Date: Thu, 28 Jan 2016 11:18:37 -0800 Subject: [PATCH 19/54] Added support for external providers as npm modules. --- lib/factory.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/factory.js b/lib/factory.js index ec61410..822bf60 100644 --- a/lib/factory.js +++ b/lib/factory.js @@ -84,8 +84,17 @@ function createClient(options) { // Try to load the provider from providers folder handler = require('./providers/' + provider); } catch (err) { - // Fall back to pkgcloud - handler = require('pkgcloud').storage; + try { + // Fall back to using an external provider + handler = require(provider); + if (!handler || !handler.createClient) { + // Fall back to pkgcloud + handler = require('pkgcloud').storage; + } + } catch(err) { + // Fall back to pkgcloud + handler = require('pkgcloud').storage; + } } patchContainerAndFileClass(provider); return handler.createClient(options); @@ -101,8 +110,13 @@ function getProvider(provider) { // Try to load the provider from providers folder return require('./providers/' + provider); } catch (err) { - // Fall back to pkgcloud - return require('pkgcloud').providers[provider]; + try { + // Fall back to using an external provider + return require(provider); + } catch(err) { + // Fall back to pkgcloud + return require('pkgcloud').providers[provider]; + } } } From ecf44e0c681230f9586844c9a3d86cb6db8ef1c7 Mon Sep 17 00:00:00 2001 From: ole3021 Date: Wed, 7 Dec 2016 16:19:11 +0800 Subject: [PATCH 20/54] fix scope error --- lib/storage-handler.js | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 3b27845..b5a6240 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -267,25 +267,26 @@ exports.download = function(provider, req, res, container, file, cb) { cb = function() {}; // avoid double-callback }); } + + function setupPartialDownload(params, stats, res) { + var total = stats.size; + + var parts = range.replace(/bytes=/, '').split('-'); + var partialstart = parts[0]; + var partialend = parts[1]; + + params.start = parseInt(partialstart, 10); + params.end = partialend ? parseInt(partialend, 10) : total - 1; + + var chunksize = (params.end - params.start) + 1; + + res.status(206); + res.set('Content-Range', 'bytes ' + params.start + '-' + params.end + '/' + total); + res.set('Accept-Ranges', 'bytes'); + res.set('Content-Length', chunksize); + }; }; -function setupPartialDownload(params, stats, res) { - var total = stats.size; - - var parts = range.replace(/bytes=/, '').split('-'); - var partialstart = parts[0]; - var partialend = parts[1]; - - params.start = parseInt(partialstart, 10); - params.end = partialend ? parseInt(partialend, 10) : total - 1; - - var chunksize = (params.end - params.start) + 1; - - res.status(206); - res.set('Content-Range', 'bytes ' + params.start + '-' + params.end + '/' + total); - res.set('Accept-Ranges', 'bytes'); - res.set('Content-Length', chunksize); -}; function processError(err, fileName) { if (err.code === 'ENOENT') { From 7df8f45489d288fbf9816d567e681b5855aeef8a Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 1 Mar 2017 15:18:26 -0800 Subject: [PATCH 21/54] Fix eslint --- .eslintignore | 1 + lib/factory.js | 4 ++-- lib/storage-handler.js | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.eslintignore b/.eslintignore index e69de29..3c3629e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -0,0 +1 @@ +node_modules diff --git a/lib/factory.js b/lib/factory.js index 822bf60..52d1510 100644 --- a/lib/factory.js +++ b/lib/factory.js @@ -91,7 +91,7 @@ function createClient(options) { // Fall back to pkgcloud handler = require('pkgcloud').storage; } - } catch(err) { + } catch (err) { // Fall back to pkgcloud handler = require('pkgcloud').storage; } @@ -113,7 +113,7 @@ function getProvider(provider) { try { // Fall back to using an external provider return require(provider); - } catch(err) { + } catch (err) { // Fall back to pkgcloud return require('pkgcloud').providers[provider]; } diff --git a/lib/storage-handler.js b/lib/storage-handler.js index b5a6240..f14a8f7 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -287,7 +287,6 @@ exports.download = function(provider, req, res, container, file, cb) { }; }; - function processError(err, fileName) { if (err.code === 'ENOENT') { err.statusCode = err.status = 404; From e55595b99ea367edb4a8f8c91810789f16373c1c Mon Sep 17 00:00:00 2001 From: Oscar Bernal Date: Wed, 23 Dec 2015 09:15:44 -0500 Subject: [PATCH 22/54] added maxFieldsSize override to formidable limit --- lib/storage-service.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/storage-service.js b/lib/storage-service.js index 834639d..021e16a 100644 --- a/lib/storage-service.js +++ b/lib/storage-service.js @@ -49,6 +49,9 @@ function StorageService(options) { if (options.nameConflict) { this.nameConflict = options.nameConflict; } + if (options.maxFieldsSize) { + this.maxFieldsSize = options.maxFieldsSize; + } } function map(obj) { @@ -247,6 +250,9 @@ StorageService.prototype.upload = function(req, res, options, cb) { if (this.nameConflict && !options.nameConflict) { options.nameConflict = this.nameConflict; } + if (this.maxFieldsSize && !options.maxFieldsSize) { + options.maxFieldsSize = this.maxFieldsSize; + } return handler.upload(this.client, req, res, options, cb); }; From 64c723e1239eeecd1304064a6a86a4983155db23 Mon Sep 17 00:00:00 2001 From: Jeff Burn Date: Mon, 19 Dec 2016 11:49:43 +1100 Subject: [PATCH 23/54] Fix #185: Validation failures crash server Fixes issue where upload and download methods in FileSystemProvider cause crashes in downstream methods by not returning streams in error scenarios - Add streamError, readStreamError, writeStreamError helper function - Wrap all returns from upload / download methods in streams - Fix incorrect format string - Add new unit tests --- lib/providers/filesystem/index.js | 46 ++++++++++++++++++++++++++----- test/files/.gitignore | 1 + test/fs.test.js | 31 ++++++++++++++++++++- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 251ff61..a0fd84d 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -13,6 +13,7 @@ var g = require('strong-globalize')(); var fs = require('fs'), path = require('path'), + stream = require('stream'), async = require('async'), File = require('./file').File, Container = require('./container').Container; @@ -58,12 +59,23 @@ function validateName(name, cb) { cb && process.nextTick(cb.bind(null, new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', name)))); if (!cb) { - console.error(g.f('{{FileSystemProvider}}: Invalid name: ', name)); + console.error(g.f('{{FileSystemProvider}}: Invalid name: %s', name)); } return false; } } +function streamError(errStream, err, cb) { + process.nextTick(function() { + errStream.emit('error', err); + cb && cb(null, err); + }); + return errStream; +} + +var writeStreamError = streamError.bind(null, new stream.Writable()); +var readStreamError = streamError.bind(null, new stream.Readable()); + /*! * Populate the metadata from file stat into props * @param {fs.Stats} stat The file stat instance @@ -168,9 +180,19 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - if (!validateName(container, cb)) return; + if (!validateName(container)) { + return writeStreamError( + new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', container)), + cb + ); + } var file = options.remote; - if (!validateName(file, cb)) return; + if (!validateName(file)) { + return writeStreamError( + new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', file)), + cb + ); + } var filePath = path.join(this.root, container, file); var fileOpts = {flags: options.flags || 'w+', @@ -188,15 +210,25 @@ FileSystemProvider.prototype.upload = function(options, cb) { }); return stream; } catch (e) { - cb && cb(e); + return writeStreamError(e, cb); } }; FileSystemProvider.prototype.download = function(options, cb) { var container = options.container; - if (!validateName(container, cb)) return; + if (!validateName(container, cb)) { + return readStreamError( + new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', container)), + cb + ); + } var file = options.remote; - if (!validateName(file, cb)) return; + if (!validateName(file, cb)) { + return readStreamError( + new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', file)), + cb + ); + } var filePath = path.join(this.root, container, file); @@ -211,7 +243,7 @@ FileSystemProvider.prototype.download = function(options, cb) { try { return fs.createReadStream(filePath, fileOpts); } catch (e) { - cb && cb(e); + return readStreamError(e, cb); } }; diff --git a/test/files/.gitignore b/test/files/.gitignore index 7173ab8..b053536 100644 --- a/test/files/.gitignore +++ b/test/files/.gitignore @@ -1 +1,2 @@ +a-f1_downloaded.txt f1_downloaded.txt diff --git a/test/fs.test.js b/test/fs.test.js index a9f8c4b..5a2329e 100644 --- a/test/fs.test.js +++ b/test/fs.test.js @@ -110,6 +110,21 @@ describe('FileSystem based storage provider', function() { writer.on('error', done); }); + it('should fail to upload a file with invalid characters', function(done) { + var writer = client.upload({container: 'c1', remote: 'a/f1.txt'}); + fs.createReadStream(path.join(__dirname, 'files/f1.txt')).pipe(writer); + var cb = done; + var clearCb = function() {}; + writer.on('error', function() { + cb(); + cb = clearCb; + }); + writer.on('finish', function() { + cb(new Error('Should have finished with error callback')); + cb = clearCb; + }); + }); + it('should download a file', function(done) { var reader = client.download({ container: 'c1', @@ -120,6 +135,21 @@ describe('FileSystem based storage provider', function() { reader.on('error', done); }); + it('should fail to download a file with invalid characters', function(done) { + var reader = client.download({container: 'c1', remote: 'a/f1.txt'}); + reader.pipe(fs.createWriteStream(path.join(__dirname, 'files/a-f1_downloaded.txt'))); + var cb = done; + var clearCb = function() {}; + reader.on('error', function() { + cb(); + cb = clearCb; + }); + reader.on('end', function() { + cb(new Error('Expected error: Invalid name')); + cb = clearCb; + }); + }); + it('should get files for a container', function(done) { client.getFiles('c1', function(err, files) { assert(!err); @@ -161,4 +191,3 @@ describe('FileSystem based storage provider', function() { }); }); }); - From ff200bf3288c9dee4e91d0aa8b0cbf45cbcfec3e Mon Sep 17 00:00:00 2001 From: Jose De Gouveia Date: Wed, 7 Sep 2016 17:29:12 +0200 Subject: [PATCH 24/54] added file field name into getFilename function --- lib/storage-handler.js | 1 + test/images/album1/.gitignore | 1 + test/upload-download.test.js | 71 ++++++++++++++++++++++------------- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index f14a8f7..535a80b 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -77,6 +77,7 @@ exports.upload = function(provider, req, res, options, cb) { container: container, name: part.filename, type: part.mime, + field: part.name }; // Options for this file diff --git a/test/images/album1/.gitignore b/test/images/album1/.gitignore index 9df892a..9084277 100644 --- a/test/images/album1/.gitignore +++ b/test/images/album1/.gitignore @@ -1,2 +1,3 @@ test.jpg image-*.jpg +customimagefield_test.jpg \ No newline at end of file diff --git a/test/upload-download.test.js b/test/upload-download.test.js index b11c35d..9e8901a 100644 --- a/test/upload-download.test.js +++ b/test/upload-download.test.js @@ -15,6 +15,26 @@ var path = require('path'); // configure errorHandler to show full error message app.set('remoting', {errorHandler: {debug: true, log: false}}); +//custom route with renamer +app.post('/custom/upload', function(req, res, next) { + var options = { + container : 'album1', + getFilename : function(file, req, res) { + return file.field + "_" +file.name; + } + }; + ds.connector.upload(req, res, options, function(err,result){ + if (!err){ + res.setHeader('Content-Type', 'application/json'); + res.status(200).send({ result : result }); + }else{ + res.status(500).send(err); + } + }); + +}); +>>>>>>> efe4e08... added file field name into getFilename function + // expose a rest api app.use(loopback.rest()); @@ -164,29 +184,10 @@ describe('storage service', function() { .attach('image', path.join(__dirname, './fixtures/test.jpg')) .set('Accept', 'application/json') .expect('Content-Type', /json/) - .expect(200, function(err, res) { - assert.deepEqual(res.body, {'result': {'files': {'image': [ - {'container': 'album1', 'name': 'test.jpg', 'type': 'image/jpeg', - 'size': 60475}, - ]}, 'fields': {}}}); - done(); - }); - }); - - it('fails to upload using dotdot file path', function(done) { - request('http://localhost:' + app.get('port')) - .post('/containers/%2e%2e/upload') - .expect(200, function(err, res) { - assert(err); - done(); - }); - }); - - it('fails to upload using dotdot file path', function(done) { - request('http://localhost:' + app.get('port')) - .post('%2e%2e/containers/upload') - .expect(200, function(err, res) { - assert(err); + .expect(200, function (err, res) { + assert.deepEqual(res.body, {"result": {"files": {"image": [ + {"container": "album1", "name": "test.jpg", "type": "image/jpeg","field":"image","size": 60475} + ]}, "fields": {}}}); done(); }); }); @@ -215,10 +216,10 @@ describe('storage service', function() { .attach('image', path.join(__dirname, './fixtures/test.jpg')) .set('Accept', 'application/json') .expect('Content-Type', /json/) - .expect(200, function(err, res) { - assert.deepEqual(res.body, {'result': {'files': {'image': [ - {'container': 'album1', 'name': 'image-test.jpg', 'originalFilename': 'test.jpg', 'type': 'image/jpeg', 'acl': 'public-read', 'size': 60475}, - ]}, 'fields': {}}}); + .expect(200, function (err, res) { + assert.deepEqual(res.body, {"result": {"files": {"image": [ + {"container": "album1", "name": "image-test.jpg", "originalFilename":"test.jpg", "type": "image/jpeg", "field":"image", "acl":"public-read", "size": 60475} + ]}, "fields": {}}}); done(); }); }); @@ -387,4 +388,20 @@ describe('storage service', function() { done(); }); }); + + it('should upload a file with custom route accessing directly to the storage connector with renamer',function (done){ + + request('http://localhost:' + app.get('port')) + .post('/custom/upload') + .attach('customimagefield', path.join(__dirname, './fixtures/test.jpg')) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200, function (err, res) { + assert.deepEqual(res.body, {"result": {"files": {"customimagefield": [ + {"container": "album1", "name": "customimagefield_test.jpg", "originalFilename":"test.jpg", "type": "image/jpeg", "field":"customimagefield", "size": 60475} + ]}, "fields": {}}}); + done(); + }); + }); + }); From ba5533b767dae8842e61a02a9931bde4d3cc40e4 Mon Sep 17 00:00:00 2001 From: Jose De Gouveia Date: Wed, 7 Sep 2016 17:29:12 +0200 Subject: [PATCH 25/54] added file field name into getFilename function in storage-handler --- test/upload-download.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/upload-download.test.js b/test/upload-download.test.js index 9e8901a..f538dd7 100644 --- a/test/upload-download.test.js +++ b/test/upload-download.test.js @@ -33,7 +33,6 @@ app.post('/custom/upload', function(req, res, next) { }); }); ->>>>>>> efe4e08... added file field name into getFilename function // expose a rest api app.use(loopback.rest()); From b0139a1eecc6b34003a4fe6181e87d90f314be10 Mon Sep 17 00:00:00 2001 From: Siddhi Pai Date: Mon, 13 Feb 2017 10:26:24 -0800 Subject: [PATCH 26/54] Replicate issue_template from loopback repo --- .github/ISSUE_TEMPLATE.md | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index ccc915a..c8b30b2 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,36 +1,21 @@ - - -### Bug or feature request - - - -- [ ] Bug -- [ ] Feature request - -### Description of feature (or steps to reproduce if bug) - - - -### Link to sample repo to reproduce issue (if bug) +Immediate support is available through our subscription plans, +see https://strongloop.com/api-connect-faqs/ --> +### Bug/Feature request + ### Expected result + +### Additional information -### Actual result (if bug) - - - -### Additional information (Node.js version, LoopBack version, etc) - + From 3f1625a3fb18069bcf89b6d0caa51825756d5c3a Mon Sep 17 00:00:00 2001 From: Siddhi Pai Date: Wed, 15 Feb 2017 15:28:27 -0800 Subject: [PATCH 27/54] Replicate new issue_template from loopback --- .github/ISSUE_TEMPLATE.md | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index c8b30b2..269b11d 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,21 +1,29 @@ - -Immediate support is available through our subscription plans, -see https://strongloop.com/api-connect-faqs/ --> +# Description/Steps to reproduce -### Bug/Feature request + - +# Expected result -### Expected result + - +# Additional information -### Additional information - - + From 7b60e6553a312e05d6548b58cf571a18e888e24c Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 1 Mar 2017 15:33:45 -0800 Subject: [PATCH 28/54] 3.1.0 * Fix eslint (Raymond Feng) * Replicate new issue_template from loopback (Siddhi Pai) * Fix insert of finalNewLine (Loay) * Replicate issue_template from loopback repo (Siddhi Pai) * fix lint (Raymond Camden) * Support nameConflict and makeUnique options (Raymond Camden) * Fix #185: Validation failures crash server (Jeff Burn) * fix scope error (ole3021) * added file field name into getFilename function (Jose De Gouveia) * added file field name into getFilename function in storage-handler (Jose De Gouveia) * Added support for external providers as npm modules. (Cristobal Vergara) * added maxFieldsSize override to formidable limit (Oscar Bernal) --- CHANGES.md | 28 ++++++++++++++++++++++++++++ package.json | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 97e11e6..0e5bcec 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,31 @@ +2017-03-01, Version 3.1.0 +========================= + + * Fix eslint (Raymond Feng) + + * Replicate new issue_template from loopback (Siddhi Pai) + + * Fix insert of finalNewLine (Loay) + + * Replicate issue_template from loopback repo (Siddhi Pai) + + * fix lint (Raymond Camden) + + * Support nameConflict and makeUnique options (Raymond Camden) + + * Fix #185: Validation failures crash server (Jeff Burn) + + * fix scope error (ole3021) + + * added file field name into getFilename function (Jose De Gouveia) + + * added file field name into getFilename function in storage-handler (Jose De Gouveia) + + * Added support for external providers as npm modules. (Cristobal Vergara) + + * added maxFieldsSize override to formidable limit (Oscar Bernal) + + 2017-02-10, Version 3.0.1 ========================= diff --git a/package.json b/package.json index eea04d2..c2816b3 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "engines": { "node": ">=4" }, - "version": "3.0.1", + "version": "3.1.0", "main": "index.js", "scripts": { "lint": "eslint .", @@ -16,7 +16,7 @@ "formidable": "^1.0.16", "pkgcloud": "^1.1.0", "strong-globalize": "^2.6.2", - "uuid":"^3.0.1" + "uuid": "^3.0.1" }, "devDependencies": { "eslint": "^2.13.1", From 990649b6076c7c86a10884ab32ccfd90984402a0 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Thu, 9 Mar 2017 08:22:03 -0800 Subject: [PATCH 29/54] Update deps --- lib/providers/filesystem/index.js | 4 ++-- package.json | 10 +++++----- test/upload-download.test.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index a0fd84d..a941587 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -201,8 +201,8 @@ FileSystemProvider.prototype.upload = function(options, cb) { }; try { - //simulate the success event in filesystem provider - //fixes: https://github.com/strongloop/loopback-component-storage/issues/58 + // simulate the success event in filesystem provider + // fixes: https://github.com/strongloop/loopback-component-storage/issues/58 // & #23 & #67 var stream = fs.createWriteStream(filePath, fileOpts); stream.on('finish', function() { diff --git a/package.json b/package.json index c2816b3..2c7f0aa 100644 --- a/package.json +++ b/package.json @@ -12,20 +12,20 @@ "posttest": "npm run lint" }, "dependencies": { - "async": "^0.9.0", + "async": "^2.1.5", "formidable": "^1.0.16", "pkgcloud": "^1.1.0", "strong-globalize": "^2.6.2", "uuid": "^3.0.1" }, "devDependencies": { - "eslint": "^2.13.1", - "eslint-config-loopback": "^4.0.0", + "eslint": "^3.17.1", + "eslint-config-loopback": "^8.0.0", "express": "^4.11.0", "loopback": "^3.0.0", "mkdirp": "^0.5.0", - "mocha": "^2.1.0", - "supertest": "^0.15.0", + "mocha": "^3.2.0", + "supertest": "^3.0.0", "semver": "^5.3.0" }, "repository": { diff --git a/test/upload-download.test.js b/test/upload-download.test.js index f538dd7..257294d 100644 --- a/test/upload-download.test.js +++ b/test/upload-download.test.js @@ -15,7 +15,7 @@ var path = require('path'); // configure errorHandler to show full error message app.set('remoting', {errorHandler: {debug: true, log: false}}); -//custom route with renamer +// custom route with renamer app.post('/custom/upload', function(req, res, next) { var options = { container : 'album1', From 807fdc63081bcf7f9d3ed8de5e652b1f8c9ce310 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Thu, 9 Mar 2017 08:22:23 -0800 Subject: [PATCH 30/54] 3.2.0 * Update deps (Raymond Feng) --- CHANGES.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 0e5bcec..d7ba551 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,9 @@ +2017-03-09, Version 3.2.0 +========================= + + * Update deps (Raymond Feng) + + 2017-03-01, Version 3.1.0 ========================= diff --git a/package.json b/package.json index 2c7f0aa..90739b5 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "engines": { "node": ">=4" }, - "version": "3.1.0", + "version": "3.2.0", "main": "index.js", "scripts": { "lint": "eslint .", From ba9fc3aeb10ffd30bbbafa0f66cac6b63fb3ddab Mon Sep 17 00:00:00 2001 From: Diana Lau Date: Mon, 31 Jul 2017 21:52:33 -0400 Subject: [PATCH 31/54] add .travis.yml --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..dd338dd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "4" + - "6" + - "8" From a48d36ba4949293294e1f11d6aefb5fd26f7c57b Mon Sep 17 00:00:00 2001 From: Diana Lau Date: Tue, 1 Aug 2017 21:51:04 -0400 Subject: [PATCH 32/54] update messages.json --- intl/en/messages.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/intl/en/messages.json b/intl/en/messages.json index 41f4dca..06a89c1 100644 --- a/intl/en/messages.json +++ b/intl/en/messages.json @@ -1,10 +1,9 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: Path does not exist: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Invalid name: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: Invalid name: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Invalid name: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Invalid directory: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} exceeded, received {0} bytes of field data (max is {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Invalid name: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" is not allowed (Must be in [{1}])", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} exceeded, received {0} bytes of field data" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} exceeded, received {0} bytes of field data", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Invalid name: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Invalid directory: {0}" } From 7beac34300f8ff8d97fc34a63a2c5458372f2230 Mon Sep 17 00:00:00 2001 From: Diana Lau Date: Mon, 24 Jul 2017 19:47:21 -0400 Subject: [PATCH 33/54] Add CODEOWNER file --- CODEOWNERS | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..e8cad33 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,6 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners, +# the last matching pattern has the most precendence. + +# Core team members from IBM +* @kjdelisle @jannyHou @loay @b-admike @ssh24 @virkt25 @dhmlau From 2fb5d85a06d9855114dac47cf90499e30e55ea4c Mon Sep 17 00:00:00 2001 From: Allen Boone Date: Thu, 10 Aug 2017 15:27:31 -0400 Subject: [PATCH 34/54] Update translated strings Q3 2017 --- intl/de/messages.json | 9 ++++----- intl/es/messages.json | 9 ++++----- intl/fr/messages.json | 9 ++++----- intl/it/messages.json | 9 ++++----- intl/ja/messages.json | 9 ++++----- intl/ko/messages.json | 9 ++++----- intl/nl/messages.json | 9 ++++----- intl/pt/messages.json | 9 ++++----- intl/tr/messages.json | 9 ++++----- intl/zh-Hans/messages.json | 9 ++++----- intl/zh-Hant/messages.json | 9 ++++----- 11 files changed, 44 insertions(+), 55 deletions(-) diff --git a/intl/de/messages.json b/intl/de/messages.json index d0bb679..8125dae 100644 --- a/intl/de/messages.json +++ b/intl/de/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: Pfad ist nicht vorhanden: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Ungültiger Name: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: Ungültiger Name: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Ungültiger Name: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Ungültiges Verzeichnis: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} überschritten, {0} Byte Felddaten erhalten (Maximum ist {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Ungültiger Name: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" ist nicht zulässig (muss in [{1}] sein)", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} überschritten, {0} Byte Felddaten erhalten" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} überschritten, {0} Byte Felddaten erhalten", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Ungültiger Name: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Ungültiges Verzeichnis: {0}" } diff --git a/intl/es/messages.json b/intl/es/messages.json index fcde445..4486e1b 100644 --- a/intl/es/messages.json +++ b/intl/es/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: La vía de acceso no existe: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Nombre no válido: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: Nombre no válido: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Nombre no válido: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Directorio no válido: {0}", "45c1c136e750c62179d75a1c99151281": "Se ha superado {{maxFileSize}}, se han recibido {0} bytes de datos de campo (el máximo es {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Nombre no válido: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" no está permitido (Debe estar en [{1}])", - "b8a9e184534171cf66caf58d29ad76f5": "Se ha superado {{maxFieldsSize}}, se han recibido {0} bytes de datos de campo" + "b8a9e184534171cf66caf58d29ad76f5": "Se ha superado {{maxFieldsSize}}, se han recibido {0} bytes de datos de campo", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Nombre no válido: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Directorio no válido: {0}" } diff --git a/intl/fr/messages.json b/intl/fr/messages.json index 89033f7..b91cc63 100644 --- a/intl/fr/messages.json +++ b/intl/fr/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}} : Le chemin n'existe pas : {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}} : Nom invalide : {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}} : Nom invalide : ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Nom invalide : {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}} : Répertoire non valide : {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} dépassé, réception de {0} octets de données de zone (max est {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}} : Nom invalide : {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" n'est pas autorisé (Doit être dans [{1}])", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} dépassé, réception de {0} octets de données de zone" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} dépassé, réception de {0} octets de données de zone", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Nom invalide : {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}} : Répertoire non valide : {0}" } diff --git a/intl/it/messages.json b/intl/it/messages.json index 1b13054..fe8d6d4 100644 --- a/intl/it/messages.json +++ b/intl/it/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: Il percorso non esiste: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Nome non valido: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: Nome non valido: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Nome non valido: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Directory non valida: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} superata, sono stati ricevuti {0} byte di dati del campo (il valore massimo è {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Nome non valido: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" non è consentito (deve essere in [{1}])", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} superata, sono stati ricevuti {0} byte di dati del campo" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} superata, sono stati ricevuti {0} byte di dati del campo", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Nome non valido: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Directory non valida: {0}" } diff --git a/intl/ja/messages.json b/intl/ja/messages.json index 102e052..5258483 100644 --- a/intl/ja/messages.json +++ b/intl/ja/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: パスが存在しません: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: 名前が無効です: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: 名前が無効です: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "名前が無効です: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: ディレクトリーが無効です: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} を超過しました。{0} バイトのフィールド・データを受信しました (最大 {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: 名前が無効です: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" は許可されていません ([{1}] でなければなりません)", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} を超過しました。{0} バイトのフィールド・データを受信しました" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} を超過しました。{0} バイトのフィールド・データを受信しました", + "c9fb0aba850059a14f4ed5e045e4ec3e": "名前が無効です: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: ディレクトリーが無効です: {0}" } diff --git a/intl/ko/messages.json b/intl/ko/messages.json index fb38f53..580e840 100644 --- a/intl/ko/messages.json +++ b/intl/ko/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: 경로가 존재하지 않음: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: 올바르지 않은 이름: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: 올바르지 않은 이름: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "올바르지 않은 이름: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: 올바르지 않은 디렉토리: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}}이(가) 초과되었습니다. {0}바이트의 필드 데이터를 받았습니다(최대값 {1}).", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: 올바르지 않은 이름: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\"이(가) 허용되지 않습니다([{1}]에 있어야 함).", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}}이(가) 초과되었습니다. {0}바이트의 필드 데이터를 받았습니다." + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}}이(가) 초과되었습니다. {0}바이트의 필드 데이터를 받았습니다.", + "c9fb0aba850059a14f4ed5e045e4ec3e": "올바르지 않은 이름: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: 올바르지 않은 디렉토리: {0}" } diff --git a/intl/nl/messages.json b/intl/nl/messages.json index 427eb47..943e96f 100644 --- a/intl/nl/messages.json +++ b/intl/nl/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: Pad bestaat niet: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Ongeldige naam: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}Ongeldige naam: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Ongeldige naam: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Ongeldige directory: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} overschreden, {0} bytes aan veldgegevens ontvangen (max is {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Ongeldige naam: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" is niet toegestaan (moet vallen in [{1}])", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} overschreden, {0} bytes aan veldgegevens ontvangen" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} overschreden, {0} bytes aan veldgegevens ontvangen", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Ongeldige naam: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Ongeldige directory: {0}" } diff --git a/intl/pt/messages.json b/intl/pt/messages.json index 75f85c0..a7b579b 100644 --- a/intl/pt/messages.json +++ b/intl/pt/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: Caminho não existe: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Nome inválido: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: Nome inválido: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Nome inválido: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Diretório inválido: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} excedido, recebidos {0} bytes de dados do campo (máximo é {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Nome inválido: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" não é permitido (deve estar em [{1}])", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} excedido, recebidos {0} bytes de dados do campo" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} excedido, recebidos {0} bytes de dados do campo", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Nome inválido: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Diretório inválido: {0}" } diff --git a/intl/tr/messages.json b/intl/tr/messages.json index 047a5f2..34b40d6 100644 --- a/intl/tr/messages.json +++ b/intl/tr/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}: Yol yok: {0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Geçersiz ad: {0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}: Geçersiz ad: ", - "c9fb0aba850059a14f4ed5e045e4ec3e": "Geçersiz ad: {0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Geçersiz dizin: {0}", "45c1c136e750c62179d75a1c99151281": "{{maxFileSize}} aşıldı, {0} baytlık alan verisi alındı (üst sınır {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}: Geçersiz ad: {0}", "78f6f36e8300e15cff778496fb1dd178": "{{contentType}} \"{0}\" kullanılamaz ([{1}] içinde olmalıdır)", - "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} aşıldı, {0} baytlık alan verisi alındı" + "b8a9e184534171cf66caf58d29ad76f5": "{{maxFieldsSize}} aşıldı, {0} baytlık alan verisi alındı", + "c9fb0aba850059a14f4ed5e045e4ec3e": "Geçersiz ad: {0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}: Geçersiz dizin: {0}" } diff --git a/intl/zh-Hans/messages.json b/intl/zh-Hans/messages.json index 33b6a0b..e514e60 100644 --- a/intl/zh-Hans/messages.json +++ b/intl/zh-Hans/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}:路径不存在:{0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}:无效名称:{0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}:无效名称", - "c9fb0aba850059a14f4ed5e045e4ec3e": "无效名称:{0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}:无效目录:{0}", "45c1c136e750c62179d75a1c99151281": "已超过 {{maxFileSize}},收到 {0} 字节字段数据(最大为 {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}:无效名称:{0}", "78f6f36e8300e15cff778496fb1dd178": "不允许 {{contentType}}“{0}”(必须在 [{1}] 中)", - "b8a9e184534171cf66caf58d29ad76f5": "已超过 {{maxFieldsSize}},收到 {0} 字节字段数据" + "b8a9e184534171cf66caf58d29ad76f5": "已超过 {{maxFieldsSize}},收到 {0} 字节字段数据", + "c9fb0aba850059a14f4ed5e045e4ec3e": "无效名称:{0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}:无效目录:{0}" } diff --git a/intl/zh-Hant/messages.json b/intl/zh-Hant/messages.json index 072f4a1..b69d1ea 100644 --- a/intl/zh-Hant/messages.json +++ b/intl/zh-Hant/messages.json @@ -1,11 +1,10 @@ { "2eb418c4dc7f7a3e989bb71a8f5388d7": "{{FileSystemProvider}}:路徑不存在:{0}", - "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}:無效名稱:{0}", - "95065f7f9499f75f49e3714aa4e2031d": "{{FileSystemProvider}}:無效名稱:", - "c9fb0aba850059a14f4ed5e045e4ec3e": "無效名稱:{0}", - "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}:無效目錄:{0}", "45c1c136e750c62179d75a1c99151281": "已超出 {{maxFileSize}},收到 {0} 位元組的欄位資料(最大值為 {1})", + "6af59b6408b92f4c6b13a2c9b06379f2": "{{FileSystemProvider}}:無效名稱:{0}", "78f6f36e8300e15cff778496fb1dd178": "不接受 {{contentType}} \"{0}\"(必須在 [{1}] 中)", - "b8a9e184534171cf66caf58d29ad76f5": "已超出 {{maxFieldsSize}},收到 {0} 位元組的欄位資料" + "b8a9e184534171cf66caf58d29ad76f5": "已超出 {{maxFieldsSize}},收到 {0} 位元組的欄位資料", + "c9fb0aba850059a14f4ed5e045e4ec3e": "無效名稱:{0}", + "f589fe721f4e6fa112d1f66081ed29ac": "{{FileSystemProvider}}:無效目錄:{0}" } From 7b6df190a9b7a0e6a44c985f4c78cdd0ebfbf444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:28:54 -0300 Subject: [PATCH 35/54] Update README --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index ea8a88e..88e0979 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,22 @@ storage services including: For more details on the architecture of the module, please see the introduction section of the [blog post](https://strongloop.com/strongblog/managing-nodejs-loopback-storage-service-provider/) written up its launch. +## Use +Now you can use Container's name with slash! If you want to create a directory, like `this/isMy/newContainer`, you have to use the char `%2F` instead of `/`, so your Container's name going to be `this%2FisMy%2FnewContainer`. + +## URL Example +Syntax +``` +[POST] <>:<>/api/Containers/<>/ +[POST] <>:<>/api/Containers/<>/upload (For upload file) +``` + +Example +``` +[POST] http://example.com:3000/api/Containers/images%2Fprofile%2Fpersonal/ +[POST] http://example.com:3000/api/Containers/images%2Fprofile%2Fpersonal/upload (For upload file) +``` + ## Examples See https://github.com/strongloop/loopback-example-storage. From 628be5142933a2fb432d48afbe19ddcaa1845661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:45:47 -0300 Subject: [PATCH 36/54] Update dependencies --- package.json | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 package.json diff --git a/package.json b/package.json old mode 100644 new mode 100755 index 90739b5..b8bfec5 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dependencies": { "async": "^2.1.5", "formidable": "^1.0.16", + "mkdirp": "^0.5.1", "pkgcloud": "^1.1.0", "strong-globalize": "^2.6.2", "uuid": "^3.0.1" From 95971444223152c72cc72927d96ae11d31f2c64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:46:20 -0300 Subject: [PATCH 37/54] Verify Container's name is a string --- lib/providers/filesystem/index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index a941587..6dcc5fd 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -124,6 +124,8 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; + var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); + name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); validateName(name, cb) && fs.mkdir(dir, options, function(err) { if (err) { @@ -180,12 +182,8 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - if (!validateName(container)) { - return writeStreamError( - new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', container)), - cb - ); - } + var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); + container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { return writeStreamError( From 9ebfdcbdc2786e56fa89b12666142641caec03c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:46:40 -0300 Subject: [PATCH 38/54] Verify if dataSources.json exist --- lib/storage-handler.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 535a80b..7fd6fde 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -11,11 +11,31 @@ var IncomingForm = require('formidable'); var StringDecoder = require('string_decoder').StringDecoder; var path = require('path'); var uuid = require('uuid'); - -var defaultOptions = { - maxFileSize: 10 * 1024 * 1024, // 10 MB +var fs = require('fs'); +var defaultOptions = function() { + var dataSources = path.join(__dirname, '../../../server/datasources.json'); + fs.stat(dataSources, function(err, stats) { + if(!error) { + return require(dataSources).container; + } else { + return false; + } + }); }; +var isImage = function(ext) { + switch(ext) { + case '.jpg': + case '.jpeg': + case '.png': + return true; + break; + default: + return false; + break; + } +} + /** * Handle multipart/form-data upload to the storage service * @param {Object} provider The storage service provider From 908d137a040410311139858953d2e5c6c05be354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:50:11 -0300 Subject: [PATCH 39/54] Explain new functionality in README --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 88e0979..d139e3f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,22 @@ Example [POST] http://example.com:3000/api/Containers/images%2Fprofile%2Fpersonal/upload (For upload file) ``` +## Add option to your dataSources.json +If you want a default name only for the upload images (not files), you have to add `defaultImageName` to your Container options. +**datasources.json** +``` +[...] + "container": { + "name": "container", + "connector": "loopback-component-storage", + "provider": "filesystem", + "maxFileSize": "10485760", + "root": "./storage", + "defaultImageName": "photo" + } +[...] + ``` + ## Examples See https://github.com/strongloop/loopback-example-storage. From 0c48e20d888a283e4a0c937ac39734715bb75d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 04:34:00 -0300 Subject: [PATCH 40/54] Fix test error --- lib/providers/filesystem/index.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 6dcc5fd..8d0f038 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -124,22 +124,24 @@ FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.createContainer = function(options, cb) { var self = this; var name = options.name; - var hasSlash = (typeof name == 'string' ? name.search('%2F') : false); + var hasSlash = name.search('%2F'); name = (hasSlash != -1 ? name.replace(/%2F/gi, '/') : name); var dir = path.join(this.root, name); - validateName(name, cb) && fs.mkdir(dir, options, function(err) { - if (err) { - return cb && cb(err); + + mkdirp(dir, function(err) { + if(err) { + cb(err); + } else { + fs.stat(dir, function(err, stat) { + var container = null; + if(!err) { + var props = { name: name }; + populateMetadata(stat, props); + container = new Container(self, props); + } + cb(err, container); + }); } - fs.stat(dir, function(err, stat) { - var container = null; - if (!err) { - var props = {name: name}; - populateMetadata(stat, props); - container = new Container(self, props); - } - cb && cb(err, container); - }); }); }; @@ -182,7 +184,7 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { // File related functions FileSystemProvider.prototype.upload = function(options, cb) { var container = options.container; - var hasSlash = (typeof container == 'string' ? container.search('%2F') : false); + var hasSlash = container.search('%2F'); container = (hasSlash != -1 ? container.replace(/%2F/gi, '/') : container); var file = options.remote; if (!validateName(file)) { From e9a7c7e42f8d801b31925e82f15b51ae78a73ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 04:42:06 -0300 Subject: [PATCH 41/54] Fix eslint error --- lib/providers/filesystem/index.js | 6 +++--- lib/storage-handler.js | 13 +++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 8d0f038..842dca9 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -129,13 +129,13 @@ FileSystemProvider.prototype.createContainer = function(options, cb) { var dir = path.join(this.root, name); mkdirp(dir, function(err) { - if(err) { + if (err) { cb(err); } else { fs.stat(dir, function(err, stat) { var container = null; - if(!err) { - var props = { name: name }; + if (!err) { + var props = {name: name}; populateMetadata(stat, props); container = new Container(self, props); } diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 7fd6fde..4f9d1f3 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -15,7 +15,7 @@ var fs = require('fs'); var defaultOptions = function() { var dataSources = path.join(__dirname, '../../../server/datasources.json'); fs.stat(dataSources, function(err, stats) { - if(!error) { + if (!err) { return require(dataSources).container; } else { return false; @@ -24,7 +24,7 @@ var defaultOptions = function() { }; var isImage = function(ext) { - switch(ext) { + switch (ext) { case '.jpg': case '.jpeg': case '.png': @@ -34,7 +34,7 @@ var isImage = function(ext) { return false; break; } -} +}; /** * Handle multipart/form-data upload to the storage service @@ -93,9 +93,14 @@ exports.upload = function(provider, req, res, options, cb) { this._flushing++; + var fileName = part.filename; + var useDefaultname = (typeof defaultOptions.defaultImageName != 'undefined' ? + true : false); + var file = { container: container, - name: part.filename, + name: (isImage(path.extname(fileName)) && useDefaultname ? + defaultOptions.defaultImageName + path.extname(fileName) : fileName), type: part.mime, field: part.name }; From 88a261e86da34572778dcc39fa2e7141bc651f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Tue, 15 Aug 2017 03:20:36 -0300 Subject: [PATCH 42/54] Create containers with slash --- lib/providers/filesystem/index.js | 7 ++++--- lib/storage-handler.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 842dca9..5a8870c 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -16,7 +16,8 @@ var fs = require('fs'), stream = require('stream'), async = require('async'), File = require('./file').File, - Container = require('./container').Container; + Container = require('./container').Container, + mkdirp = require('mkdirp'); module.exports.storage = module.exports; // To make it consistent with pkgcloud @@ -194,8 +195,8 @@ FileSystemProvider.prototype.upload = function(options, cb) { ); } var filePath = path.join(this.root, container, file); - - var fileOpts = {flags: options.flags || 'w+', + var fileOpts = { + flags: options.flags || 'w+', encoding: options.encoding || null, mode: options.mode || parseInt('0666', 8), }; diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 4f9d1f3..2c42bac 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -52,7 +52,7 @@ exports.upload = function(provider, req, res, options, cb) { } if (!options.maxFileSize) { - options.maxFileSize = defaultOptions.maxFileSize; + options.maxFileSize = defaultOptions.maxFileSize || 10 * 1024 * 1024; } var form = new IncomingForm(options); From 3e7d5c819d0b74ec76d9ded4f73075e4fe6d9c55 Mon Sep 17 00:00:00 2001 From: Sakib Hasan Date: Wed, 16 Aug 2017 14:27:54 -0400 Subject: [PATCH 43/54] Create Issue and PR Templates (#218) * create issue template * create pr template --- .github/ISSUE_TEMPLATE.md | 10 +++++++++- .github/PULL_REQUEST_TEMPLATE.md | 9 +++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 269b11d..795176c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -11,7 +11,15 @@ Immediate support: + +# Link to reproduction sandbox + + # Expected result diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d2b240f..368cb4c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,17 +6,18 @@ -- None +- connect to ### Checklist - [ ] New tests added or existing tests modified to cover all changes From 6a3d9f47d58d61d463b3163017205816b405cdc7 Mon Sep 17 00:00:00 2001 From: Kevin Delisle Date: Wed, 23 Aug 2017 08:27:24 -0400 Subject: [PATCH 44/54] Add stalebot configuration --- .github/stale.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..bebe60a --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,23 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 14 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security + - critical + - p1 + - major +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: > + This issue has been closed due to continued inactivity. Thank you for your understanding. + If you believe this to be in error, please contact one of the code owners, + listed in the `CODEOWNERS` file at the top-level of this repository. From 4ea51fcd8c666cc1d3b342954a1b72e68fd75d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 30 Aug 2017 15:09:02 +0200 Subject: [PATCH 45/54] Mark HTTP path parameters as required Per Swagger spec 2.0, parameters coming from the path must be marked as required. Before this change, the Swagger spec produced by loopback-swagger was not valid because path parameters were optional. Note that this commit does not fix the problem of the "uploaded" method which does not have any swagger-supported parameters now, and therefore the swagger spec will remain invalid (but with less errors). --- lib/storage-service.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/storage-service.js b/lib/storage-service.js index 021e16a..322b518 100644 --- a/lib/storage-service.js +++ b/lib/storage-service.js @@ -282,7 +282,7 @@ StorageService.prototype.getContainers.http = StorageService.prototype.getContainer.shared = true; StorageService.prototype.getContainer.accepts = [ - {arg: 'container', type: 'string'}, + {arg: 'container', type: 'string', required: true}, ]; StorageService.prototype.getContainer.returns = { arg: 'container', @@ -312,7 +312,7 @@ StorageService.prototype.destroyContainer.http = StorageService.prototype.getFiles.shared = true; StorageService.prototype.getFiles.accepts = [ - {arg: 'container', type: 'string'}, + {arg: 'container', type: 'string', required: true}, ]; StorageService.prototype.getFiles.returns = {arg: 'files', type: 'array', root: true}; StorageService.prototype.getFiles.http = @@ -320,8 +320,8 @@ StorageService.prototype.getFiles.http = StorageService.prototype.getFile.shared = true; StorageService.prototype.getFile.accepts = [ - {arg: 'container', type: 'string'}, - {arg: 'file', type: 'string'}, + {arg: 'container', type: 'string', required: true}, + {arg: 'file', type: 'string', required: true}, ]; StorageService.prototype.getFile.returns = {arg: 'file', type: 'object', root: true}; StorageService.prototype.getFile.http = @@ -329,8 +329,8 @@ StorageService.prototype.getFile.http = StorageService.prototype.removeFile.shared = true; StorageService.prototype.removeFile.accepts = [ - {arg: 'container', type: 'string'}, - {arg: 'file', type: 'string'}, + {arg: 'container', type: 'string', required: true}, + {arg: 'file', type: 'string', required: true}, ]; StorageService.prototype.removeFile.returns = {}; StorageService.prototype.removeFile.http = @@ -347,8 +347,8 @@ StorageService.prototype.upload.http = StorageService.prototype.download.shared = true; StorageService.prototype.download.accepts = [ - {arg: 'container', type: 'string', 'http': {source: 'path'}}, - {arg: 'file', type: 'string', 'http': {source: 'path'}}, + {arg: 'container', type: 'string', required: true, 'http': {source: 'path'}}, + {arg: 'file', type: 'string', required: true, 'http': {source: 'path'}}, {arg: 'req', type: 'object', 'http': {source: 'req'}}, {arg: 'res', type: 'object', 'http': {source: 'res'}}, ]; From 82f1e92a5bd86a33ee10a88e06a80fee2616f9c3 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 30 Aug 2017 08:30:15 -0700 Subject: [PATCH 46/54] 3.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Mark HTTP path parameters as required (Miroslav Bajtoš) * Add stalebot configuration (Kevin Delisle) * Create Issue and PR Templates (#218) (Sakib Hasan) * Update translated strings Q3 2017 (Allen Boone) * Add CODEOWNER file (Diana Lau) * update messages.json (Diana Lau) * add .travis.yml (Diana Lau) --- CHANGES.md | 18 ++++++++++++++++++ package.json | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index d7ba551..eb13fa5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,21 @@ +2017-08-30, Version 3.3.0 +========================= + + * Mark HTTP path parameters as required (Miroslav Bajtoš) + + * Add stalebot configuration (Kevin Delisle) + + * Create Issue and PR Templates (#218) (Sakib Hasan) + + * Update translated strings Q3 2017 (Allen Boone) + + * Add CODEOWNER file (Diana Lau) + + * update messages.json (Diana Lau) + + * add .travis.yml (Diana Lau) + + 2017-03-09, Version 3.2.0 ========================= diff --git a/package.json b/package.json index b8bfec5..cc6408c 100755 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "engines": { "node": ">=4" }, - "version": "3.2.0", + "version": "3.3.0", "main": "index.js", "scripts": { "lint": "eslint .", From 8b663ddf9c6fd81dacd79a064dedd264f4c9a249 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 30 Aug 2017 13:13:25 -0700 Subject: [PATCH 47/54] Declare container parameter for swagger spec Without this change, generated Swagger spec for the upload operation does not have `container` parameter even it's a variable on the path. As a result, the sepc fails validations. An optional `container` is added to the remote method. Conditional check is added to ensure backward compatibility. --- lib/storage-service.js | 29 +++++++++++++++++++++-------- test/images/album1/.gitignore | 3 ++- test/upload-download.test.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/lib/storage-service.js b/lib/storage-service.js index 322b518..dbb1d50 100644 --- a/lib/storage-service.js +++ b/lib/storage-service.js @@ -225,12 +225,21 @@ StorageService.prototype.removeFile = function(container, file, cb) { /** * Upload middleware for the HTTP request/response + * @param {String} [container] Container name * @param {Request} req Request object * @param {Response} res Response object * @param {Object} [options] Options for upload * @param {Function} cb Callback function */ -StorageService.prototype.upload = function(req, res, options, cb) { +StorageService.prototype.upload = function(container, req, res, options, cb) { + // Test if container is req for backward compatibility + if (typeof container === 'object' && container.url && container.method) { + // First argument is req, shift all args + cb = options; + options = res; + res = req; + req = container; + } if (!cb && 'function' === typeof options) { cb = options; options = {}; @@ -253,6 +262,9 @@ StorageService.prototype.upload = function(req, res, options, cb) { if (this.maxFieldsSize && !options.maxFieldsSize) { options.maxFieldsSize = this.maxFieldsSize; } + if (typeof container === 'string') { + options.container = container; + } return handler.upload(this.client, req, res, options, cb); }; @@ -282,7 +294,7 @@ StorageService.prototype.getContainers.http = StorageService.prototype.getContainer.shared = true; StorageService.prototype.getContainer.accepts = [ - {arg: 'container', type: 'string', required: true}, + {arg: 'container', type: 'string', required: true, 'http': {source: 'path'}}, ]; StorageService.prototype.getContainer.returns = { arg: 'container', @@ -304,7 +316,7 @@ StorageService.prototype.createContainer.http = StorageService.prototype.destroyContainer.shared = true; StorageService.prototype.destroyContainer.accepts = [ - {arg: 'container', type: 'string'}, + {arg: 'container', type: 'string', required: true, 'http': {source: 'path'}}, ]; StorageService.prototype.destroyContainer.returns = {}; StorageService.prototype.destroyContainer.http = @@ -312,7 +324,7 @@ StorageService.prototype.destroyContainer.http = StorageService.prototype.getFiles.shared = true; StorageService.prototype.getFiles.accepts = [ - {arg: 'container', type: 'string', required: true}, + {arg: 'container', type: 'string', required: true, 'http': {source: 'path'}}, ]; StorageService.prototype.getFiles.returns = {arg: 'files', type: 'array', root: true}; StorageService.prototype.getFiles.http = @@ -320,8 +332,8 @@ StorageService.prototype.getFiles.http = StorageService.prototype.getFile.shared = true; StorageService.prototype.getFile.accepts = [ - {arg: 'container', type: 'string', required: true}, - {arg: 'file', type: 'string', required: true}, + {arg: 'container', type: 'string', required: true, 'http': {source: 'path'}}, + {arg: 'file', type: 'string', required: true, 'http': {source: 'path'}}, ]; StorageService.prototype.getFile.returns = {arg: 'file', type: 'object', root: true}; StorageService.prototype.getFile.http = @@ -329,8 +341,8 @@ StorageService.prototype.getFile.http = StorageService.prototype.removeFile.shared = true; StorageService.prototype.removeFile.accepts = [ - {arg: 'container', type: 'string', required: true}, - {arg: 'file', type: 'string', required: true}, + {arg: 'container', type: 'string', required: true, 'http': {source: 'path'}}, + {arg: 'file', type: 'string', required: true, 'http': {source: 'path'}}, ]; StorageService.prototype.removeFile.returns = {}; StorageService.prototype.removeFile.http = @@ -338,6 +350,7 @@ StorageService.prototype.removeFile.http = StorageService.prototype.upload.shared = true; StorageService.prototype.upload.accepts = [ + {arg: 'container', type: 'string', required: true, 'http': {source: 'path'}}, {arg: 'req', type: 'object', 'http': {source: 'req'}}, {arg: 'res', type: 'object', 'http': {source: 'res'}}, ]; diff --git a/test/images/album1/.gitignore b/test/images/album1/.gitignore index 9084277..ea550c4 100644 --- a/test/images/album1/.gitignore +++ b/test/images/album1/.gitignore @@ -1,3 +1,4 @@ test.jpg image-*.jpg -customimagefield_test.jpg \ No newline at end of file +customimagefield_test.jpg +customimagefield1_test.jpg diff --git a/test/upload-download.test.js b/test/upload-download.test.js index 257294d..8b6f663 100644 --- a/test/upload-download.test.js +++ b/test/upload-download.test.js @@ -34,6 +34,23 @@ app.post('/custom/upload', function(req, res, next) { }); +// custom route with renamer +app.post('/custom/uploadWithContainer', function(req, res, next) { + var options = { + getFilename: function(file, req, res) { + return file.field + '_' + file.name; + }, + }; + ds.connector.upload('album1', req, res, options, function(err, result) { + if (!err) { + res.setHeader('Content-Type', 'application/json'); + res.status(200).send({result: result}); + } else { + res.status(500).send(err); + } + }); +}); + // expose a rest api app.use(loopback.rest()); @@ -403,4 +420,19 @@ describe('storage service', function() { }); }); + it('should upload a file with container param', function(done) { + request('http://localhost:' + app.get('port')) + .post('/custom/uploadWithContainer') + .attach('customimagefield1', path.join(__dirname, './fixtures/test.jpg')) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200, function(err, res) { + assert.deepEqual(res.body, {'result': {'files': {'customimagefield1': [ + {'container': 'album1', 'name': 'customimagefield1_test.jpg', + 'originalFilename': 'test.jpg', 'type': 'image/jpeg', + 'field': 'customimagefield1', 'size': 60475}, + ]}, 'fields': {}}}); + done(); + }); + }); }); From 5203d9bd227b306742875fb21e1679489f2d00cc Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 30 Aug 2017 13:54:54 -0700 Subject: [PATCH 48/54] 3.3.1 * Declare container parameter for swagger spec (Raymond Feng) --- CHANGES.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index eb13fa5..61912bb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,9 @@ +2017-08-30, Version 3.3.1 +========================= + + * Declare container parameter for swagger spec (Raymond Feng) + + 2017-08-30, Version 3.3.0 ========================= diff --git a/package.json b/package.json index cc6408c..bed17b8 100755 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "engines": { "node": ">=4" }, - "version": "3.3.0", + "version": "3.3.1", "main": "index.js", "scripts": { "lint": "eslint .", From 033f6d8cd4521ecf501b320ea752d09b7aaa4356 Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Tue, 12 Sep 2017 10:11:20 -0700 Subject: [PATCH 49/54] Update README.md Add Google Cloud support to README --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d139e3f..03555be 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,20 @@ **NOTE: The loopback-component-storage module supersedes [loopback-storage-service](https://www.npmjs.org/package/loopback-storage-service). Please update your package.json accordingly.** -LoopBack storage component provides Node.js and REST APIs to manage binary contents +LoopBack storage component provides Node.js and REST APIs to manage binary file contents using pluggable storage providers, such as local file systems, Amazon S3, or -Rackspace cloud files. We use [pkgcloud](https://github.com/pkgcloud/pkgcloud) to support the cloud based +Rackspace cloud files. It uses [pkgcloud](https://github.com/pkgcloud/pkgcloud) to support cloud-based storage services including: - Amazon -- Rackspace -- Openstack - Azure +- Google Cloud +- Openstack +- Rackspace -> Please see the [Storage Service Documentaion](http://loopback.io/doc/en/lb2/Storage-component.html). +> Please see the [Storage Service Documentaion](http://loopback.io/doc/en/lb3/Storage-component.html). -For more details on the architecture of the module, please see the introduction section of the [blog post](https://strongloop.com/strongblog/managing-nodejs-loopback-storage-service-provider/) written up its launch. +For more details on the architecture of the module, please see the introduction section of the [blog post](https://strongloop.com/strongblog/managing-nodejs-loopback-storage-service-provider/). ## Use Now you can use Container's name with slash! If you want to create a directory, like `this/isMy/newContainer`, you have to use the char `%2F` instead of `/`, so your Container's name going to be `this%2FisMy%2FnewContainer`. From f467d964a7f19a132b77a20b9a3c648f6278ab7f Mon Sep 17 00:00:00 2001 From: Timo Wolf Date: Sun, 8 Oct 2017 18:00:46 +0200 Subject: [PATCH 50/54] add AWS S3 options for server side encryption Now, the AWS S3 options for server side encryptions are passed to the upload handler. Thus, the client can specify the AWS options and use AWS Server Side Encryption. --- lib/storage-handler.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 2c42bac..0abc0b6 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -166,6 +166,30 @@ exports.upload = function(provider, req, res, options, cb) { uploadParams.acl = file.acl; } + // add AWS specific options + // See http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property + if (options.StorageClass) { + uploadParams.StorageClass = options.StorageClass; + } + if (options.CacheControl) { + uploadParams.CacheControl = options.CacheControl; + } + if (options.ServerSideEncryption) { + uploadParams.ServerSideEncryption = options.ServerSideEncryption; + } + if (options.SSEKMSKeyId) { + uploadParams.SSEKMSKeyId = options.SSEKMSKeyId; + } + if (options.SSECustomerAlgorithm) { + uploadParams.SSECustomerAlgorithm = options.SSECustomerAlgorithm; + } + if (options.SSECustomerKey) { + uploadParams.SSECustomerKey = options.SSECustomerKey; + } + if (options.SSECustomerKeyMD5) { + uploadParams.SSECustomerKeyMD5 = options.SSECustomerKeyMD5; + } + var writer = provider.upload(uploadParams); writer.on('error', function(err) { From 92c3b4df8c8462ed3fe962285c711e59c7d416e1 Mon Sep 17 00:00:00 2001 From: Diana Lau Date: Fri, 10 Nov 2017 17:54:11 -0500 Subject: [PATCH 51/54] chore: update license --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index a7161d5..3474cfc 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) IBM Corp. 2013,2016. All Rights Reserved. +Copyright (c) IBM Corp. 2013,2017. All Rights Reserved. Node module: loopback-component-storage This project is licensed under the Artistic License 2.0, full text below. From 3ecf08961fd7f398f7d4883e4090108bd854cac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Sun, 7 Jan 2018 23:58:31 -0300 Subject: [PATCH 52/54] Add test create to container with slash --- test/fs.test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/fs.test.js b/test/fs.test.js index 5a2329e..ecae65f 100644 --- a/test/fs.test.js +++ b/test/fs.test.js @@ -54,6 +54,14 @@ describe('FileSystem based storage provider', function() { }); }); + it('should create a new container with slash', function(done) { + client.createContainer({name: 'c1%2Fc2'}, function(err, container) { + assert(!err); + verifyMetadata(container, 'c1/c2'); + done(err, container); + }); + }); + it('should get a container c1', function(done) { client.getContainer('c1', function(err, container) { assert(!err); From 9fba79d15461db323f142aff32983fd884cae0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Mon, 8 Jan 2018 09:07:30 -0300 Subject: [PATCH 53/54] Fix eslint errors --- lib/storage-handler.js | 5 ++--- test/upload-download.test.js | 17 ++++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/storage-handler.js b/lib/storage-handler.js index 0abc0b6..c752cf1 100644 --- a/lib/storage-handler.js +++ b/lib/storage-handler.js @@ -94,15 +94,14 @@ exports.upload = function(provider, req, res, options, cb) { this._flushing++; var fileName = part.filename; - var useDefaultname = (typeof defaultOptions.defaultImageName != 'undefined' ? - true : false); + var useDefaultname = (typeof defaultOptions.defaultImageName != 'undefined'); var file = { container: container, name: (isImage(path.extname(fileName)) && useDefaultname ? defaultOptions.defaultImageName + path.extname(fileName) : fileName), type: part.mime, - field: part.name + field: part.name, }; // Options for this file diff --git a/test/upload-download.test.js b/test/upload-download.test.js index 989daa5..c1519cc 100644 --- a/test/upload-download.test.js +++ b/test/upload-download.test.js @@ -52,20 +52,19 @@ app.post('/custom/uploadWithContainer', function(req, res, next) { // custom route with renamer app.post('/custom/upload', function(req, res, next) { var options = { - container : 'album1', - getFilename : function(file, req, res) { - return file.field + "_" +file.name; - } + container: 'album1', + getFilename: function(file, req, res) { + return file.field + '_' + file.name; + }, }; - ds.connector.upload(req, res, options, function(err,result){ - if (!err){ + ds.connector.upload(req, res, options, function(err, result) { + if (!err) { res.setHeader('Content-Type', 'application/json'); - res.status(200).send({ result : result }); - }else{ + res.status(200).send({result: result}); + } else { res.status(500).send(err); } }); - }); // custom route with renamer From 629ee1a5c81008d09b3a42fd1b516707ade41cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20Aravena?= Date: Mon, 8 Jan 2018 11:26:01 -0300 Subject: [PATCH 54/54] Fix npm test --- lib/providers/filesystem/index.js | 23 ++++++++++++++++++----- test/fs.test.js | 23 +++++++++++++++-------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index 1620db0..bcb5b6d 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -44,6 +44,7 @@ function FileSystemProvider(options) { var namePattern = new RegExp('[^' + path.sep + '/]+'); // To detect any file/directory containing dotdot paths var containsDotDotPaths = /(^|[\\\/])\.\.([\\\/]|$)/; +var containsDotDotPathsContainer = /(^)\.\.($)/; function validateName(name, cb) { if (!name || containsDotDotPaths.test(name)) { @@ -66,6 +67,18 @@ function validateName(name, cb) { } } +function validateContainerName(name, cb) { + if (!name || containsDotDotPathsContainer.test(name)) { + cb && process.nextTick(cb.bind(null, new Error(g.f('Invalid name: %s', name)))); + if (!cb) { + console.error(g.f('{{FileSystemProvider}}: Invalid name: %s', name)); + } + return false; + } + + return true; +} + function streamError(errStream, err, cb) { process.nextTick(function() { errStream.emit('error', err); @@ -147,7 +160,7 @@ FileSystemProvider.prototype.createContainer = function(options, cb) { }; FileSystemProvider.prototype.destroyContainer = function(containerName, cb) { - if (!validateName(containerName, cb)) return; + if (!validateContainerName(containerName, cb)) return; var dir = path.join(this.root, containerName); fs.readdir(dir, function(err, files) { @@ -169,7 +182,7 @@ FileSystemProvider.prototype.destroyContainer = function(containerName, cb) { FileSystemProvider.prototype.getContainer = function(containerName, cb) { var self = this; - if (!validateName(containerName, cb)) return; + if (!validateContainerName(containerName, cb)) return; var dir = path.join(this.root, containerName); fs.stat(dir, function(err, stat) { var container = null; @@ -217,7 +230,7 @@ FileSystemProvider.prototype.upload = function(options, cb) { FileSystemProvider.prototype.download = function(options, cb) { var container = options.container; - if (!validateName(container, cb)) { + if (!validateContainerName(container, cb)) { return readStreamError( new Error(g.f('{{FileSystemProvider}}: Invalid name: %s', container)), cb @@ -254,7 +267,7 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) { options = false; } var self = this; - if (!validateName(container, cb)) return; + if (!validateContainerName(container, cb)) return; var dir = path.join(this.root, container); fs.readdir(dir, function(err, entries) { entries = entries || []; @@ -303,7 +316,7 @@ FileSystemProvider.prototype.getUrl = function(options) { }; FileSystemProvider.prototype.removeFile = function(container, file, cb) { - if (!validateName(container, cb)) return; + if (!validateContainerName(container, cb)) return; if (!validateName(file, cb)) return; var filePath = path.join(this.root, container, file); diff --git a/test/fs.test.js b/test/fs.test.js index ecae65f..d91c12d 100644 --- a/test/fs.test.js +++ b/test/fs.test.js @@ -46,14 +46,6 @@ describe('FileSystem based storage provider', function() { }); }); - it('should create a new container', function(done) { - client.createContainer({name: 'c1'}, function(err, container) { - assert(!err); - verifyMetadata(container, 'c1'); - done(err, container); - }); - }); - it('should create a new container with slash', function(done) { client.createContainer({name: 'c1%2Fc2'}, function(err, container) { assert(!err); @@ -62,6 +54,21 @@ describe('FileSystem based storage provider', function() { }); }); + it('should destroy a container c1/c2', function(done) { + client.destroyContainer('c1/c2', function(err, container) { + assert(!err); + done(err, container); + }); + }); + + it('should create a new container', function(done) { + client.createContainer({name: 'c1'}, function(err, container) { + assert(!err); + verifyMetadata(container, 'c1'); + done(err, container); + }); + }); + it('should get a container c1', function(done) { client.getContainer('c1', function(err, container) { assert(!err);