diff --git a/controller/status.js b/controller/status.js new file mode 100644 index 00000000..7c87af6d --- /dev/null +++ b/controller/status.js @@ -0,0 +1,3 @@ +module.exports = function controller( req, res, next) { + res.send('status: ok'); +}; diff --git a/package.json b/package.json index e47affc6..8018919c 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "dependencies": { "addressit": "1.3.0", "async": "^0.9.0", + "check-types": "^3.3.1", "cluster2": "git://github.com/missinglink/cluster2.git#node_zero_twelve", "express": "^4.8.8", "express-http-proxy": "^0.6.0", @@ -43,7 +44,6 @@ "geojson-extent": "^0.3.1", "geolib": "^2.0.18", "geopipes-elasticsearch-backend": "^0.2.0", - "is-object": "^1.0.1", "lodash": "^3.10.1", "markdown": "0.5.0", "microtime": "1.4.0", diff --git a/routes/v1.js b/routes/v1.js index d041ae32..49fb3021 100644 --- a/routes/v1.js +++ b/routes/v1.js @@ -19,7 +19,8 @@ var middleware = { var controllers = { mdToHTML: require('../controller/markdownToHtml'), place: require('../controller/place'), - search: require('../controller/search') + search: require('../controller/search'), + status: require('../controller/status') }; /** ----------------------- controllers ----------------------- **/ @@ -83,6 +84,9 @@ function addRoutes(app, peliasConfig) { postProc.renamePlacenames(), postProc.geocodeJSON(peliasConfig), postProc.sendJSON + ]), + status: createRouter([ + controllers.status ]) }; @@ -97,6 +101,8 @@ function addRoutes(app, peliasConfig) { app.get ( base + 'search', routers.search ); app.post( base + 'search', routers.search ); app.get ( base + 'reverse', routers.reverse ); + + app.get ( '/status', routers.status ); } /** diff --git a/sanitiser/_categories.js b/sanitiser/_categories.js index f29c9fd0..e76e8767 100644 --- a/sanitiser/_categories.js +++ b/sanitiser/_categories.js @@ -1,36 +1,33 @@ -var isObject = require('is-object'); +var check = require('check-types'); // validate inputs, convert types and apply defaults -function sanitize( req ){ +function sanitize( raw, clean ){ - var clean = req.clean || {}; - var params= req.query; - - // ensure the input params are a valid object - if( !isObject( params ) ){ - params = {}; - } + // error & warning messages + var messages = { errors: [], warnings: [] }; // default case (no categories specified in GET params) - if('string' !== typeof params.categories || !params.categories.length){ - clean.categories = []; - } - else { - // parse GET params - clean.categories = params.categories.split(',') + clean.categories = []; + + // if categories string has been set + if( check.unemptyString( raw.categories ) ){ + + // map input categories to valid format + clean.categories = raw.categories.split(',') .map(function (cat) { return cat.toLowerCase().trim(); // lowercase inputs }) .filter( function( cat ) { return ( cat.length > 0 ); }); - } - // pass validated params to next middleware - req.clean = clean; + if( !clean.categories.length ){ + messages.warnings.push( 'invalid \'categories\': no valid category strings found'); + } + } - return { 'error': false }; + return messages; } diff --git a/sanitiser/_details.js b/sanitiser/_details.js index 6dc2b119..e17c656c 100644 --- a/sanitiser/_details.js +++ b/sanitiser/_details.js @@ -1,36 +1,25 @@ -var isObject = require('is-object'); + +var check = require('check-types'); +var DEFAULT_DETAILS_BOOL = true; // validate inputs, convert types and apply defaults -function sanitize( req, default_value ){ - - var clean = req.clean || {}; - var params= req.query; +function sanitize( raw, clean ){ - if (default_value === undefined) { - default_value = true; - } - - default_value = !!default_value; + // error & warning messages + var messages = { errors: [], warnings: [] }; - // ensure the input params are a valid object - if( !isObject( params ) ){ - params = {}; - } - - if (params.details !== undefined) { - clean.details = isTruthy(params.details); + if( !check.undefined( raw.details ) ){ + clean.details = isTruthy( raw.details ); } else { - clean.details = default_value; + clean.details = DEFAULT_DETAILS_BOOL; } - req.clean = clean; - - return {'error':false}; - + return messages; } +// be lenient with 'truthy' values function isTruthy(val) { - if (typeof val === 'string') { + if( check.string( val ) ){ return ['true', '1', 'yes', 'y'].indexOf(val) !== -1; } diff --git a/sanitiser/_geo_common.js b/sanitiser/_geo_common.js index 2bf8c6a5..71b728cb 100644 --- a/sanitiser/_geo_common.js +++ b/sanitiser/_geo_common.js @@ -1,7 +1,8 @@ /** * helper sanitiser methods for geo parameters */ -var util = require( 'util' ); +var util = require('util'), + check = require('check-types'); /** * Parse and validate bbox parameter @@ -9,15 +10,15 @@ var util = require( 'util' ); * bbox = left, bottom, right, top * bbox = min Longitude, min Latitude, max Longitude, max Latitude * + * @param {object} raw * @param {object} clean - * @param {string} param */ -function sanitize_bbox( clean, param ) { - if( !param ) { +function sanitize_bbox( raw, clean ) { + if( !check.unemptyString( raw.bbox ) ) { return; } - var bboxArr = param.split( ',' ); + var bboxArr = raw.bbox.split( ',' ); if( Array.isArray( bboxArr ) && bboxArr.length === 4 ) { var bbox = bboxArr.map(parseFloat); diff --git a/sanitiser/_geo_reverse.js b/sanitiser/_geo_reverse.js index f613e54f..4b259199 100644 --- a/sanitiser/_geo_reverse.js +++ b/sanitiser/_geo_reverse.js @@ -1,39 +1,26 @@ -var isObject = require('is-object'); + var geo_common = require ('./_geo_common'); +var LAT_LON_IS_REQUIRED = true, + CIRCLE_IS_REQUIRED = false, + CIRCLE_MUST_BE_COMPLETE = false; // validate inputs, convert types and apply defaults -module.exports = function sanitize( req ){ - var clean = req.clean || {}; - var params = req.query; - var latlon_is_required = true; - var circle_is_required = false; - var circle_must_be_complete = false; +module.exports = function sanitize( raw, clean ){ - // ensure the input params are a valid object - if( !isObject( params ) ){ - params = {}; - } - - if( !isObject( params.point ) ){ - params.point = {}; - } + // error & warning messages + var messages = { errors: [], warnings: [] }; try { - geo_common.sanitize_coord( 'lat', clean, params['point.lat'], latlon_is_required ); - geo_common.sanitize_coord( 'lon', clean, params['point.lon'], latlon_is_required ); + geo_common.sanitize_coord( 'lat', clean, raw['point.lat'], LAT_LON_IS_REQUIRED ); + geo_common.sanitize_coord( 'lon', clean, raw['point.lon'], LAT_LON_IS_REQUIRED ); // boundary.circle.* is not mandatory, and only specifying radius is fine, // as point.lat/lon will be used to fill those values by default - geo_common.sanitize_boundary_circle( clean, params, circle_is_required, circle_must_be_complete); + geo_common.sanitize_boundary_circle( clean, raw, CIRCLE_IS_REQUIRED, CIRCLE_MUST_BE_COMPLETE); } catch (err) { - return { - 'error': true, - 'message': err.message - }; + messages.errors.push( err.message ); } - req.clean = clean; - - return { 'error': false }; + return messages; }; diff --git a/sanitiser/_geo_search.js b/sanitiser/_geo_search.js index 1f1fbeb2..cc2fafcb 100644 --- a/sanitiser/_geo_search.js +++ b/sanitiser/_geo_search.js @@ -1,38 +1,21 @@ -var isObject = require('is-object'); + var geo_common = require ('./_geo_common'); +var LAT_LON_IS_REQUIRED = false; // validate inputs, convert types and apply defaults -module.exports = function sanitize( req ){ - var clean = req.clean || {}; - var params = req.query; - var latlon_is_required = false; - - // ensure the input params are a valid object - if( !isObject( params ) ){ - params = {}; - } +module.exports = function sanitize( raw, clean ){ - if( !isObject( params.focus ) ){ - params.focus = {}; - } - - if( !isObject( params.focus.point ) ){ - params.focus.point = {}; - } + // error & warning messages + var messages = { errors: [], warnings: [] }; try { - geo_common.sanitize_coord( 'lat', clean, params['focus.point.lat'], latlon_is_required ); - geo_common.sanitize_coord( 'lon', clean, params['focus.point.lon'], latlon_is_required ); - geo_common.sanitize_bbox(clean, params.bbox); + geo_common.sanitize_coord( 'lat', clean, raw['focus.point.lat'], LAT_LON_IS_REQUIRED ); + geo_common.sanitize_coord( 'lon', clean, raw['focus.point.lon'], LAT_LON_IS_REQUIRED ); + geo_common.sanitize_bbox(raw, clean); } catch (err) { - return { - 'error': true, - 'message': err.message - }; + messages.errors.push( err.message ); } - req.clean = clean; - - return { 'error': false }; + return messages; }; diff --git a/sanitiser/_id.js b/sanitiser/_id.js index 78ff6b1f..77d21fa8 100644 --- a/sanitiser/_id.js +++ b/sanitiser/_id.js @@ -1,72 +1,79 @@ -var isObject = require('is-object'); + +var check = require('check-types'), + types = require('../query/types'); + +var ID_DELIM = ':'; // validate inputs, convert types and apply defaults // id generally looks like 'geoname:4163334' (type:id) // so, both type and id are required fields. -function sanitize( req ){ - req.clean = req.clean || {}; - var params = req.query; - var types = require('../query/types'); - var delim = ':'; - - // ensure params is a valid object - if( !isObject( params ) ){ - params = {}; - } - - var errormessage = function(fieldname, message) { - return { - 'error': true, - 'message': message || ('invalid param \''+ fieldname + '\': text length, must be >0') - }; - }; - - if(('string' === typeof params.id && !params.id.length) || params.id === undefined){ - return errormessage('id'); - } - - if( params && params.id && params.id.length ){ - req.clean.ids = []; - params.ids = Array.isArray(params.id) ? params.id : [params.id]; - - // de-dupe - params.ids = params.ids.filter(function(item, pos) { - return params.ids.indexOf(item) === pos; - }); +function errorMessage(fieldname, message) { + return message || 'invalid param \''+ fieldname + '\': text length, must be >0'; +} + +function sanitize( raw, clean ){ - for (var i=0; i MAX_SIZE ){ + // set the max size + messages.warnings.push('out-of-range integer \'size\', using MAX_SIZE'); + clean.size = MAX_SIZE; + } + else if( _size < MIN_SIZE ){ + // set the min size + messages.warnings.push('out-of-range integer \'size\', using MIN_SIZE'); + clean.size = MIN_SIZE; + } + else { + // set the input size + clean.size = _size; + } + + } + return messages; } // export function diff --git a/sanitiser/_targets.js b/sanitiser/_targets.js index 43092fd7..81e345b6 100644 --- a/sanitiser/_targets.js +++ b/sanitiser/_targets.js @@ -1,57 +1,81 @@ -var _ = require('lodash'); -function setup(paramName, targetMap) { - return function (req ) { - return sanitize(paramName, targetMap, req); +var _ = require('lodash'), + check = require('check-types'); + +function setup( paramName, targetMap ) { + return function( raw, clean ){ + return sanitize( raw, clean, { + paramName: paramName, + targetMap: targetMap, + targetMapKeysString: Object.keys(targetMap).join(',') + }); }; } -function sanitize( paramName, targetMap, req ) { - var params = req.query || {}; +function sanitize( raw, clean, opts ) { - req.clean = req.clean || {}; - req.clean.types = req.clean.types || {}; + // error & warning messages + var messages = { errors: [], warnings: [] }; - // default case (no sources specified in GET params) - // there is a case where the property is present, but set to null or undefined - if (params.hasOwnProperty(paramName) === false || typeof params[paramName] === 'undefined') { - return { error: false }; - } + // init clean.types + clean.types = clean.types || {}; - params[paramName] = params[paramName].trim(); + // the string of targets (comma delimeted) + var targetsString = raw[opts.paramName]; - if (params[paramName].length === 0) { - return { - error: true, - message: paramName + ' parameter cannot be an empty string. Valid options: ' + Object.keys(targetMap).join(', ') - }; - } + // trim whitespace + if( check.unemptyString( targetsString ) ){ + targetsString = targetsString.trim(); - var targets = params[paramName].split(',').map( function( target ){ - return target.toLowerCase(); // lowercase inputs - }); + // param must be a valid non-empty string + if( !check.unemptyString( targetsString ) ){ + messages.errors.push( + opts.paramName + ' parameter cannot be an empty string. Valid options: ' + opts.targetMapKeysString + ); + } + else { - var invalidTargets = targets.filter(function(target) { - return targetMap.hasOwnProperty(target) === false; - }); + // split string in to array and lowercase each target string + var targets = targetsString.split(',').map( function( target ){ + return target.toLowerCase(); // lowercase inputs + }); - if (invalidTargets.length > 0) { - return { - error: true, - message: invalidTargets[0] + ' is an invalid ' + paramName + ' parameter. Valid options: ' + Object.keys(targetMap).join(', ') - }; - } + // emit an error for each target *not* present in the targetMap + targets.filter( function( target ){ + return !opts.targetMap.hasOwnProperty(target); + }).forEach( function( target ){ + messages.errors.push( + '\'' + target + '\' is an invalid ' + opts.paramName + ' parameter. Valid options: ' + opts.targetMapKeysString + ); + }); + + // only set types value when no error occured + if( !messages.errors.length ){ - var cleanPropName = 'from_' + paramName; + // store the values under a new key as 'clean.types.from_*' + var typesKey = 'from_' + opts.paramName; - req.clean.types[cleanPropName] = targets.reduce(function(acc, target) { - return acc.concat(targetMap[target]); - }, []); + // ? + clean.types[typesKey] = targets.reduce(function(acc, target) { + return acc.concat(opts.targetMap[target]); + }, []); + + // dedupe in case aliases expanded to common things or user typed in duplicates + clean.types[typesKey] = _.unique(clean.types[typesKey]); + } + + } + } + + // string is empty + else if( check.string( targetsString ) ){ + messages.errors.push( + opts.paramName + ' parameter cannot be an empty string. Valid options: ' + opts.targetMapKeysString + ); + } - // dedupe in case aliases expanded to common things or user typed in duplicates - req.clean.types[cleanPropName] = _.unique(req.clean.types[cleanPropName]); - return { error: false }; + return messages; } module.exports = setup; diff --git a/sanitiser/_text.js b/sanitiser/_text.js index 41f38d6c..2f1f96af 100644 --- a/sanitiser/_text.js +++ b/sanitiser/_text.js @@ -1,32 +1,33 @@ -var isObject = require('is-object'); -var query_parser = require('../helper/query_parser'); + +var check = require('check-types'), + query_parser = require('../helper/query_parser'); // validate texts, convert types and apply defaults -function sanitize( req ){ - req.clean = req.clean || {}; - var params= req.query; +function sanitize( raw, clean ){ - // ensure the text params are a valid object - if( !isObject( params ) ){ - params = {}; - } + // error & warning messages + var messages = { errors: [], warnings: [] }; - // text text - if('string' !== typeof params.text || !params.text.length){ - return { - 'error': true, - 'message': 'invalid param \'text\': text length, must be >0' - }; + // invalid input 'text' + if( !check.unemptyString( raw.text ) ){ + messages.errors.push('invalid param \'text\': text length, must be >0'); } - req.clean.text = params.text; + // valid input 'text' + else { - req.clean.parsed_text = query_parser.get_parsed_address(params.text); + // valid text + clean.text = raw.text; - req.clean.types = req.clean.layers || {}; - req.clean.types.from_address_parsing = query_parser.get_layers(params.text); + // parse text with query parser + clean.parsed_text = query_parser.get_parsed_address(clean.text); + + // try to set layers from query parser results + clean.types = clean.layers || {}; + clean.types.from_address_parsing = query_parser.get_layers(clean.text); + } - return { 'error': false }; + return messages; } // export function diff --git a/sanitiser/place.js b/sanitiser/place.js index 352777a6..e48f362b 100644 --- a/sanitiser/place.js +++ b/sanitiser/place.js @@ -1,13 +1,15 @@ -var _sanitize = require('../sanitiser/_sanitize'), + +var sanitizeAll = require('../sanitiser/sanitizeAll'), sanitizers = { id: require('../sanitiser/_id'), details: require('../sanitiser/_details') }; -var sanitize = function(req, cb) { _sanitize(req, sanitizers, cb); }; +var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; // export sanitize for testing module.exports.sanitize = sanitize; +module.exports.sanitiser_list = sanitizers; // middleware module.exports.middleware = function( req, res, next ){ @@ -16,7 +18,6 @@ module.exports.middleware = function( req, res, next ){ res.status(400); // 400 Bad Request return next(err); } - req.clean = clean; next(); }); }; diff --git a/sanitiser/reverse.js b/sanitiser/reverse.js index 1aab041d..ec86e289 100644 --- a/sanitiser/reverse.js +++ b/sanitiser/reverse.js @@ -1,21 +1,19 @@ -var _sanitize = require('../sanitiser/_sanitize'); -var sanitiser = { - latlonzoom: require('../sanitiser/_geo_reverse'), - layers: require('../sanitiser/_targets')('layers', require('../query/layers')), - sources: require('../sanitiser/_targets')('sources', require('../query/sources')), - details: require('../sanitiser/_details'), - size: require('../sanitiser/_size'), - categories: function (req) { - var categories = require('../sanitiser/_categories'); - return categories(req); - } -}; +var sanitizeAll = require('../sanitiser/sanitizeAll'), + sanitizers = { + layers: require('../sanitiser/_targets')('layers', require('../query/layers')), + sources: require('../sanitiser/_targets')('sources', require('../query/sources')), + size: require('../sanitiser/_size'), + details: require('../sanitiser/_details'), + geo_reverse: require('../sanitiser/_geo_reverse'), + categories: require('../sanitiser/_categories') + }; -var sanitize = function(req, cb) { _sanitize(req, sanitiser, cb); }; +var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; // export sanitize for testing module.exports.sanitize = sanitize; +module.exports.sanitiser_list = sanitizers; // middleware module.exports.middleware = function( req, res, next ){ @@ -24,9 +22,7 @@ module.exports.middleware = function( req, res, next ){ res.status(400); // 400 Bad Request return next(err); } - req.clean = clean; next(); }); }; -module.exports.sanitiser_list = sanitiser; diff --git a/sanitiser/sanitizeAll.js b/sanitiser/sanitizeAll.js new file mode 100644 index 00000000..886a64c3 --- /dev/null +++ b/sanitiser/sanitizeAll.js @@ -0,0 +1,26 @@ + +function sanitize( req, sanitizers, cb ){ + + // init an object to store clean + // (sanitized) input parameters + req.clean = {}; + + // source of input parameters + // (in this case from the GET querystring params) + var params = req.query || {}; + + for (var s in sanitizers) { + var sanity = sanitizers[s]( params, req.clean ); + + // errors + if( sanity.errors.length ){ + return cb( sanity.errors[0] ); + } + } + + return cb( undefined, req.clean ); + +} + +// export function +module.exports = sanitize; \ No newline at end of file diff --git a/sanitiser/search.js b/sanitiser/search.js index 0427a2ac..dd042761 100644 --- a/sanitiser/search.js +++ b/sanitiser/search.js @@ -1,22 +1,20 @@ -var _sanitize = require('../sanitiser/_sanitize'), +var sanitizeAll = require('../sanitiser/sanitizeAll'), sanitizers = { text: require('../sanitiser/_text'), size: require('../sanitiser/_size'), layers: require('../sanitiser/_targets')('layers', require( '../query/layers' )), sources: require('../sanitiser/_targets')('sources', require( '../query/sources' )), details: require('../sanitiser/_details'), - latlonzoom: require('../sanitiser/_geo_search'), - categories: function (req) { - var categories = require('../sanitiser/_categories'); - return categories(req); - } + geo_search: require('../sanitiser/_geo_search'), + categories: require('../sanitiser/_categories') }; -var sanitize = function(req, cb) { _sanitize(req, sanitizers, cb); }; +var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; // export sanitize for testing module.exports.sanitize = sanitize; +module.exports.sanitiser_list = sanitizers; // middleware module.exports.middleware = function( req, res, next ){ @@ -25,9 +23,7 @@ module.exports.middleware = function( req, res, next ){ res.status(400); // 400 Bad Request return next(err); } - req.clean = clean; next(); }); }; -module.exports.sanitiser_list = sanitizers; \ No newline at end of file diff --git a/test/unit/sanitiser/_layers.js b/test/unit/sanitiser/_layers.js index 3ea3f2c7..12d2cfd3 100644 --- a/test/unit/sanitiser/_layers.js +++ b/test/unit/sanitiser/_layers.js @@ -5,78 +5,105 @@ module.exports.tests = {}; module.exports.tests.sanitize_layers = function(test, common) { test('unspecified', function(t) { - var res = sanitize({ query: { layers: undefined } }); - t.equal(res.error, false); + var messages = sanitize({ layers: undefined }, {}); + t.equal(messages.errors.length, 0, 'no errors'); t.end(); }); test('invalid layer', function(t) { - var req = { query: { layers: 'test_layer' } }; - var res = sanitize(req); + var raw = { layers: 'test_layer' }; + var clean = {}; + + var messages = sanitize(raw, clean); + var msg = ' is an invalid layers parameter. Valid options: '; - t.true(res.error, 'error flag set'); - t.true(res.message.match(msg), 'invalid layer requested'); - t.true(res.message.length > msg.length, 'invalid error message'); + t.equal(messages.errors.length, 1, 'errors set'); + t.true(messages.errors[0].match(msg), 'invalid layer requested'); + t.true(messages.errors[0].length > msg.length, 'invalid error message'); t.end(); }); test('venue (alias) layer', function(t) { var venue_layers = ['geoname','osmnode','osmway']; - var req = { query: { layers: 'venue' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, venue_layers, 'venue layers set'); + var raw = { layers: 'venue' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, venue_layers, 'venue layers set'); t.end(); }); test('coarse (alias) layer', function(t) { var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin']; - var req = { query: { layers: 'coarse' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, admin_layers, 'coarse layers set'); + var raw = { layers: 'coarse' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, admin_layers, 'coarse layers set'); t.end(); }); test('address (alias) layer', function(t) { var address_layers = ['osmaddress','openaddresses']; - var req = { query: { layers: 'address' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, address_layers, 'address layers set'); + var raw = { layers: 'address' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, address_layers, 'address layers set'); t.end(); }); test('venue alias layer plus regular layers', function(t) { var venue_layers = ['geoname','osmnode','osmway']; var reg_layers = ['admin0', 'admin1']; - var req = { query: { layers: 'venue,country,region' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, venue_layers.concat(reg_layers), 'venue + regular layers'); + var raw = { layers: 'venue,country,region' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, venue_layers.concat(reg_layers), 'venue + regular layers'); t.end(); }); test('coarse alias layer plus regular layers', function(t) { var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin']; var reg_layers = ['geoname', 'osmnode', 'osmway']; - var req = { query: { layers: 'coarse,venue,country' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, admin_layers.concat(reg_layers), 'coarse + regular layers set'); + var raw = { layers: 'coarse,venue,country' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, admin_layers.concat(reg_layers), 'coarse + regular layers set'); t.end(); }); test('address alias layer plus regular layers', function(t) { var address_layers = ['osmaddress','openaddresses']; var reg_layers = ['admin0', 'locality']; - var req = { query: { layers: 'address,country,locality' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, address_layers.concat(reg_layers), 'address + regular layers set'); + var raw = { layers: 'address,country,locality' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, address_layers.concat(reg_layers), 'address + regular layers set'); t.end(); }); test('alias layer plus regular layers (no duplicates)', function(t) { var venue_layers = ['geoname','osmnode','osmway','admin0']; - var req = { query: { layers: 'venue,country' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, venue_layers, 'venue layers found (no duplicates)'); + var raw = { layers: 'venue,country' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, venue_layers, 'venue layers found (no duplicates)'); t.end(); }); test('multiple alias layers (no duplicates)', function(t) { var alias_layers = ['geoname','osmnode','osmway','admin0','admin1','admin2','neighborhood','locality','local_admin']; - var req = { query: { layers: 'venue,coarse' } }; - sanitize(req); - t.deepEqual(req.clean.types.from_layers, alias_layers, 'all layers found (no duplicates)'); + var raw = { layers: 'venue,coarse' }; + var clean = {}; + + sanitize(raw, clean); + + t.deepEqual(clean.types.from_layers, alias_layers, 'all layers found (no duplicates)'); t.end(); }); }; diff --git a/test/unit/sanitiser/_sources.js b/test/unit/sanitiser/_sources.js index 81bb4a37..05507a36 100644 --- a/test/unit/sanitiser/_sources.js +++ b/test/unit/sanitiser/_sources.js @@ -1,19 +1,21 @@ var sanitize = require( '../../../sanitiser/_targets' )('sources', require('../../../query/sources')); -var success_response = { error: false }; +var success_messages = { error: false }; module.exports.tests = {}; module.exports.tests.no_sources = function(test, common) { test('sources is not set', function(t) { var req = { - query: { } + query: { }, + clean: { } }; - var response = sanitize(req); + var messages = sanitize(req.query, req.clean); t.deepEqual(req.clean.types, {}, 'clean.types should be empty object'); - t.deepEqual(response, success_response, 'no error returned'); + t.deepEqual(messages.errors, [], 'no error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); t.end(); }); @@ -21,19 +23,19 @@ module.exports.tests.no_sources = function(test, common) { var req = { query: { sources: '' - } + }, + clean: { } }; - var expected_response = { - error: true, - message: 'sources parameter cannot be an empty string. ' + - 'Valid options: gn, geonames, oa, openaddresses, qs, quattroshapes, osm, openstreetmap' - }; + var expected_error = 'sources parameter cannot be an empty string. ' + + 'Valid options: gn,geonames,oa,openaddresses,qs,quattroshapes,osm,openstreetmap'; - var response = sanitize(req); + var messages = sanitize(req.query, req.clean); t.deepEqual(req.clean.types, {}, 'clean.types should be empty object'); - t.deepEqual(response, expected_response, 'no error returned'); + t.deepEqual(messages.errors.length, 1, 'error returned'); + t.deepEqual(messages.errors[0], expected_error, 'error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); t.end(); }); }; @@ -43,13 +45,16 @@ module.exports.tests.valid_sources = function(test, common) { var req = { query: { sources: 'geonames' - } + }, + clean: { } }; - var response = sanitize(req); + var messages = sanitize(req.query, req.clean); t.deepEqual(req.clean.types, { from_sources: ['geoname'] }, 'clean.types should contain from_source entry with geonames'); - t.deepEqual(response, success_response, 'no error returned'); + t.deepEqual(messages.errors, [], 'no error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); + t.end(); }); @@ -57,16 +62,18 @@ module.exports.tests.valid_sources = function(test, common) { var req = { query: { sources: 'openstreetmap' - } + }, + clean: { } }; var expected_types = { from_sources: ['osmaddress', 'osmnode', 'osmway'] }; - var response = sanitize(req); + var messages = sanitize(req.query, req.clean); t.deepEqual(req.clean.types, expected_types, 'clean.types should contain from_source entry with multiple entries for openstreetmap'); - t.deepEqual(response, success_response, 'no error returned'); + t.deepEqual(messages.errors, [], 'no error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); t.end(); }); @@ -74,17 +81,19 @@ module.exports.tests.valid_sources = function(test, common) { var req = { query: { sources: 'openstreetmap,openaddresses' - } + }, + clean: { } }; var expected_types = { from_sources: ['osmaddress', 'osmnode', 'osmway', 'openaddresses'] }; - var response = sanitize(req); + var messages = sanitize(req.query, req.clean); t.deepEqual(req.clean.types, expected_types, 'clean.types should contain from_source entry with multiple entries for openstreetmap and openadresses'); - t.deepEqual(response, success_response, 'no error returned'); + t.deepEqual(messages.errors, [], 'no error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); t.end(); }); }; @@ -94,17 +103,19 @@ module.exports.tests.invalid_sources = function(test, common) { var req = { query: { sources: 'notasource' - } + }, + clean: { } }; - var expected_response = { - error: true, - message: 'notasource is an invalid sources parameter. ' + - 'Valid options: gn, geonames, oa, openaddresses, qs, quattroshapes, osm, openstreetmap' + var expected_messages = { + errors: [ + '\'notasource\' is an invalid sources parameter. Valid options: gn,geonames,oa,openaddresses,qs,quattroshapes,osm,openstreetmap' + ], + warnings: [] }; - var response = sanitize(req); + var messages = sanitize(req.query, req.clean); - t.deepEqual(response, expected_response, 'error with message returned'); + t.deepEqual(messages, expected_messages, 'error with message returned'); t.deepEqual(req.clean.types, { }, 'clean.types should remain empty'); t.end(); }); @@ -112,7 +123,7 @@ module.exports.tests.invalid_sources = function(test, common) { module.exports.all = function (tape, common) { function test(name, testFunction) { - return tape('SANTIZE _source ' + name, testFunction); + return tape('SANTIZE _sources ' + name, testFunction); } for( var testCase in module.exports.tests ){ diff --git a/test/unit/sanitiser/reverse.js b/test/unit/sanitiser/reverse.js index d249bd3a..5c2a3a9f 100644 --- a/test/unit/sanitiser/reverse.js +++ b/test/unit/sanitiser/reverse.js @@ -1,7 +1,7 @@ -var suggest = require('../../../sanitiser/reverse'), - _sanitize = suggest.sanitize, - middleware = suggest.middleware, +var reverse = require('../../../sanitiser/reverse'), + _sanitize = reverse.sanitize, + middleware = reverse.middleware, defaultError = 'missing param \'lat\'', defaultClean = { lat:0, types: { @@ -30,8 +30,8 @@ module.exports.tests.interface = function(test, common) { module.exports.tests.sanitisers = function(test, common) { test('check sanitiser list', function (t) { - var expected = ['latlonzoom', 'layers', 'sources', 'details', 'size', 'categories']; - t.deepEqual(Object.keys(suggest.sanitiser_list), expected); + var expected = ['layers', 'sources', 'size', 'details', 'geo_reverse', 'categories']; + t.deepEqual(Object.keys(reverse.sanitiser_list), expected); t.end(); }); }; diff --git a/test/unit/sanitiser/search.js b/test/unit/sanitiser/search.js index bdc791c5..e6c39284 100644 --- a/test/unit/sanitiser/search.js +++ b/test/unit/sanitiser/search.js @@ -32,7 +32,7 @@ module.exports.tests.interface = function(test, common) { module.exports.tests.sanitisers = function(test, common) { test('check sanitiser list', function (t) { - var expected = ['text', 'size', 'layers', 'sources', 'details', 'latlonzoom', 'categories' ]; + var expected = ['text', 'size', 'layers', 'sources', 'details', 'geo_search', 'categories' ]; t.deepEqual(Object.keys(search.sanitiser_list), expected); t.end(); });