Merge branch 'master' into master

dev
Richard Girges 5 years ago committed by GitHub
commit da97f779c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      README.md
  2. 7
      lib/index.js
  3. 9
      lib/processMultipart.js
  4. 28
      lib/processNested.js
  5. 31
      test/options.spec.js
  6. 48
      test/processNested.spec.js
  7. 43
      test/server.js

@ -74,6 +74,7 @@ preserveExtension | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>
abortOnLimit | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>true</code></ul> | Returns a HTTP 413 when the file is bigger than the size limit if true. Otherwise, it will add a <code>truncate = true</code> to the resulting file structure.
useTempFiles | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>true</code></ul> | Will use temporary files at the specified tempDir for managing uploads rather than using buffers in memory. This avoids memory issues when uploading large files.
tempFileDir | <ul><li><code>String</code>&nbsp;**(path)**</li></ul> | Used with the <code>useTempFiles</code> option. Path to the directory where temp files will be stored during the upload process. Add trailing slash.
parseNested | <ul><li><code>false</code>&nbsp;**(default)**</li><li><code>true</code></li></ul> | By default, req.body and req.files are flattened like this: <code>{'name': 'John', 'hobbies[0]': 'Cinema', 'hobbies[1]': 'Bike'}</code><br /><br/>When this option is enabled they are parsed in order to be nested like this: <code>{'name': 'John', 'hobbies': ['Cinema', 'Bike']}</code>
# Help Wanted
Looking for additional maintainers. Please contact `richardgirges [ at ] gmail.com` if you're interested. Pull Requests are welcomed!

@ -3,12 +3,14 @@
const fileFactory = require('./fileFactory');
const processMultipart = require('./processMultipart');
const isEligibleRequest = require('./isEligibleRequest');
const processNested = require('./processNested');
const fileUploadOptionsDefaults = {
safeFileNames: false,
preserveExtension: false,
abortOnLimit: false,
createParentPath: false
createParentPath: false,
parseNested: false
};
/**
@ -27,6 +29,7 @@ module.exports = function(fileUploadOptions) {
};
/**
* Quietly expose fileFactory; useful for testing
* Quietly expose fileFactory and processNested; useful for testing
*/
module.exports.fileFactory = fileFactory;
module.exports.processNested = processNested;

@ -6,6 +6,7 @@ const {
cleanupStream,
tempFileHandler
} = require('./tempFileHandler');
const processNested = require('./processNested');
/**
* Processes multipart request
@ -161,7 +162,13 @@ module.exports = function processMultipart(options, req, res, next) {
file.on('error', cleanupStream, next);
});
busboy.on('finish', next);
busboy.on('finish', () => {
if (options.parseNested) {
req.body = processNested(req.body);
req.files = processNested(req.files);
}
next();
});
busboy.on('error', next);

@ -0,0 +1,28 @@
module.exports = function(data){
if (!data || data.length < 1) return {};
let d = {},
keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
let key = keys[i],
value = data[key],
current = d,
keyParts = key
.replace(new RegExp(/\[/g), '.')
.replace(new RegExp(/\]/g), '')
.split('.');
for (let index = 0; index < keyParts.length; index++){
let k = keyParts[index];
if (index >= keyParts.length - 1){
current[k] = value;
} else {
if (!current[k]) current[k] = !isNaN(keyParts[index + 1]) ? [] : {};
current = current[k];
}
}
}
return d;
};

@ -185,4 +185,35 @@ describe('File Upload Options Tests', function() {
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
});
});
describe('Testing [parseNested] option to ensure:', function() {
it('When [parseNested] is enabled result are nested', function(done){
const app = server.setup({parseNested: true});
request(app)
.post('/fields/nested')
.field('name', 'John')
.field('hobbies[0]', 'Cinema')
.field('hobbies[1]', 'Bike')
.expect('Content-Type', /json/)
.expect(200, {
name: 'John',
hobbies: ['Cinema', 'Bike']
}, done);
});
it('When [parseNested] is disabled are flattened', function(done){
const app = server.setup({parseNested: false});
request(app)
.post('/fields/flattened')
.field('name', 'John')
.field('hobbies[0]', 'Cinema')
.field('hobbies[1]', 'Bike')
.expect('Content-Type', /json/)
.expect(200, {
name: 'John',
'hobbies[0]': 'Cinema',
'hobbies[1]': 'Bike'
}, done);
});
});
});

@ -0,0 +1,48 @@
'use strict';
const assert = require('assert');
const processNested = require('../lib').processNested;
describe('Test Convert Flatten object to Nested object', function() {
it('With no nested data', function(){
const data = {
'firstname': 'John',
'lastname': 'Doe',
'age': 22
},
excerpt= { firstname: 'John', lastname: 'Doe', age: 22 },
processed = processNested(data);
assert.deepEqual(processed, excerpt);
});
it('With nested data', function(){
const data = {
'firstname': 'John',
'lastname': 'Doe',
'age': 22,
'hobbies[0]': 'Cinema',
'hobbies[1]': 'Bike',
'address[line]': '78 Lynch Street',
'address[city]': 'Milwaukee',
'friends[0][name]': 'Jane',
'friends[0][lastname]': 'Doe',
'friends[1][name]': 'Joe',
'friends[1][lastname]': 'Doe'
},
excerpt = {
firstname: 'John',
lastname: 'Doe',
age: 22,
hobbies: [ 'Cinema', 'Bike' ],
address: { line: '78 Lynch Street', city: 'Milwaukee' },
friends: [
{ name: 'Jane', lastname: 'Doe' },
{ name: 'Joe', lastname: 'Doe' }
]
},
processed = processNested(data);
assert.deepEqual(processed, excerpt);
});
});

@ -214,6 +214,49 @@ const setup = function(fileUploadOptions) {
});
});
app.all('/fields/nested', function(req, res) {
if (!req.body) {
return res.status(400).send('No request body found');
}
if (!req.body.name || !req.body.name.trim()) {
return res.status(400).send('Invalid name');
}
if (!req.body.hobbies || !req.body.hobbies.length == 2) {
return res.status(400).send('Invalid hobbies');
}
res.json({
name: req.body.name,
hobbies: req.body.hobbies
});
});
app.all('/fields/flattened', function(req, res) {
if (!req.body) {
return res.status(400).send('No request body found');
}
if (!req.body.name || !req.body.name.trim()) {
return res.status(400).send('Invalid name');
}
if (!req.body['hobbies[0]'] || !req.body['hobbies[0]'].trim()) {
return res.status(400).send('Invalid hobbies[0]');
}
if (!req.body['hobbies[1]'] || !req.body['hobbies[1]'].trim()) {
return res.status(400).send('Invalid hobbies[1]');
}
res.json({
name: req.body.name,
'hobbies[0]': req.body['hobbies[0]'],
'hobbies[1]': req.body['hobbies[1]']
});
});
app.all('/fields/array', function(req, res) {
if (!req.body) {
return res.status(400).send('No request body found');

Loading…
Cancel
Save