diff --git a/sanitiser/_geo_common.js b/sanitiser/_geo_common.js index b88e9453..bc5a4bcc 100644 --- a/sanitiser/_geo_common.js +++ b/sanitiser/_geo_common.js @@ -2,7 +2,8 @@ * helper sanitiser methods for geo parameters */ var util = require('util'), - check = require('check-types'); + check = require('check-types'), + _ = require('lodash'); /** * Parse and validate rect parameter @@ -86,7 +87,7 @@ function sanitize_circle( key_prefix, clean, raw, circle_is_required ) { // radius was specified without lat or lon else if( raw.hasOwnProperty( key_prefix + '.radius' ) ){ var format2 = 'missing circle param \'%s\' requires all of: \'%s\' to be present'; - throw new Error( util.format( format2, key_prefix, mandatoryProps.join('\',\'') ) ); + throw new Error( util.format( format2, key_prefix, mandatoryProps.join('\',\'') ) ); } // fields required, eg. ( totalFieldsSpecified === 0 && bbox_is_required === true ) else if( circle_is_required ){ @@ -140,13 +141,13 @@ function sanitize_point( key_prefix, clean, raw, point_is_required ) { * * @param {string} key * @param {object} clean - * @param {string} param + * @param {string} rawValue * @param {bool} latlon_is_required */ -function sanitize_coord( key, clean, param, latlon_is_required ) { - var value = parseFloat( param ); - if ( !isNaN( value ) ) { - clean[key] = value; +function sanitize_coord( key, clean, rawValue, latlon_is_required ) { + var parsedValue = parseFloat( rawValue ); + if ( _.isFinite( parsedValue ) ) { + clean[key] = parsedValue; } else if (latlon_is_required) { throw new Error( util.format( 'missing param \'%s\'', key ) ); diff --git a/sanitiser/_geo_reverse.js b/sanitiser/_geo_reverse.js index 4b5ee959..c15af48b 100644 --- a/sanitiser/_geo_reverse.js +++ b/sanitiser/_geo_reverse.js @@ -1,8 +1,9 @@ var geo_common = require ('./_geo_common'); +var _ = require('lodash'); +var defaults = require('../query/defaults'); var LAT_LON_IS_REQUIRED = true, - CIRCLE_IS_REQUIRED = false, - CIRCLE_MUST_BE_COMPLETE = false; + CIRCLE_IS_REQUIRED = false; // validate inputs, convert types and apply defaults module.exports = function sanitize( raw, clean ){ @@ -10,19 +11,31 @@ module.exports = function sanitize( raw, clean ){ // error & warning messages var messages = { errors: [], warnings: [] }; + // helper function to determine if raw has a boundary.circle property + var hasBoundaryCircleField = function(field) { + return raw.hasOwnProperty('boundary.circle.' + field); + }; + + if (['lat', 'lon', 'radius'].some(hasBoundaryCircleField)) { + messages.warnings.push('boundary.circle is currently unsupported'); + } + try { + // first verify that point.lat/point.lon are valid geo_common.sanitize_point( 'point', clean, raw, LAT_LON_IS_REQUIRED ); - // this hack is to allow point.lat/point.lon to be used interchanagbly - // with boundary.circle.lat/boundary.circle/lon - if( !clean.hasOwnProperty('boundary.circle.lat') && clean.hasOwnProperty('point.lat') ){ - raw['boundary.circle.lat'] = clean['point.lat']; - } - if( !clean.hasOwnProperty('boundary.circle.lon') && clean.hasOwnProperty('point.lon') ){ - raw['boundary.circle.lon'] = clean['point.lon']; + // overwrite boundary.circle.lat/lon with point.lat/lon + raw['boundary.circle.lat'] = clean['point.lat']; + raw['boundary.circle.lon'] = clean['point.lon']; + + // if no radius was passed, set the default + if ( _.isUndefined( raw['boundary.circle.radius'] ) ) { + raw['boundary.circle.radius'] = defaults['boundary:circle:radius']; } + // santize the boundary.circle geo_common.sanitize_circle( 'boundary.circle', clean, raw, CIRCLE_IS_REQUIRED ); + } catch (err) { messages.errors.push( err.message ); diff --git a/test/unit/run.js b/test/unit/run.js index a95764e5..977c1c58 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -31,6 +31,7 @@ var tests = [ require('./middleware/confidenceScoreReverse'), require('./sanitiser/_size'), require('./sanitiser/_single_scalar_parameters'), + require('./sanitiser/_geo_reverse'), ]; tests.map(function(t) { diff --git a/test/unit/sanitiser/_geo_reverse.js b/test/unit/sanitiser/_geo_reverse.js new file mode 100644 index 00000000..e03e7ddd --- /dev/null +++ b/test/unit/sanitiser/_geo_reverse.js @@ -0,0 +1,114 @@ +var sanitize = require('../../../sanitiser/_geo_reverse'); +var defaults = require('../../../query/defaults'); + +module.exports.tests = {}; + +module.exports.tests.sanitize_boundary_country = function(test, common) { + test('raw with boundary.circle.lat should add warning about ignored boundary.circle', function(t) { + var raw = { + 'point.lat': '12.121212', + 'point.lon': '21.212121', + 'boundary.circle.lat': '13.131313' + }; + var clean = {}; + var errorsAndWarnings = sanitize(raw, clean); + + t.equals(clean['boundary.circle.lat'], 12.121212, 'should be set to point.lat'); + t.deepEquals(errorsAndWarnings, { + errors: [], + warnings: ['boundary.circle is currently unsupported'] + }, 'no warnings/errors'); + t.end(); + }); + + test('raw with boundary.circle.lon should add warning about ignored boundary.circle', function(t) { + var raw = { + 'point.lat': '12.121212', + 'point.lon': '21.212121', + 'boundary.circle.lon': '31.313131' + }; + var clean = {}; + var errorsAndWarnings = sanitize(raw, clean); + + t.equals(clean['boundary.circle.lon'], 21.212121, 'should be set to point.lon'); + t.deepEquals(errorsAndWarnings, { + errors: [], + warnings: ['boundary.circle is currently unsupported'] + }, 'no warnings/errors'); + t.end(); + }); + + test('raw with boundary.circle.radius should add warning about ignored boundary.circle', function(t) { + var raw = { + 'point.lat': '12.121212', + 'point.lon': '21.212121', + 'boundary.circle.radius': '17' + }; + var clean = {}; + var errorsAndWarnings = sanitize(raw, clean); + + // t.equals(clean['boundary.circle.radius'], 12.121212, 'should be set to point.lat') + t.deepEquals(errorsAndWarnings, { + errors: [], + warnings: ['boundary.circle is currently unsupported'] + }, 'no warnings/errors'); + t.end(); + }); + + test('boundary.circle.lat/lon should be overridden with point.lat/lon', function(t) { + var raw = { + 'point.lat': '12.121212', + 'point.lon': '21.212121', + 'boundary.circle.lat': '13.131313', + 'boundary.circle.lon': '31.313131' + }; + var clean = {}; + var errorsAndWarnings = sanitize(raw, clean); + + t.equals(raw['boundary.circle.lat'], 12.121212, 'should be set to point.lat'); + t.equals(raw['boundary.circle.lon'], 21.212121, 'should be set to point.lon'); + t.equals(clean['boundary.circle.lat'], 12.121212, 'should be set to point.lat'); + t.equals(clean['boundary.circle.lon'], 21.212121, 'should be set to point.lon'); + t.end(); + }); + + test('no boundary.circle.radius supplied should be set to default', function(t) { + var raw = { + 'point.lat': '12.121212', + 'point.lon': '21.212121' + }; + var clean = {}; + var errorsAndWarnings = sanitize(raw, clean); + + t.equals(raw['boundary.circle.radius'], defaults['boundary:circle:radius'], 'should be from defaults'); + t.equals(clean['boundary.circle.radius'], parseFloat(defaults['boundary:circle:radius']), 'should be same as raw'); + t.end(); + + }); + + test('explicit boundary.circle.radius should be used instead of default', function(t) { + var raw = { + 'point.lat': '12.121212', + 'point.lon': '21.212121', + 'boundary.circle.radius': '3248732857km' // this will never be the default + }; + var clean = {}; + var errorsAndWarnings = sanitize(raw, clean); + + t.equals(raw['boundary.circle.radius'], '3248732857km', 'should be parsed float'); + t.equals(clean['boundary.circle.radius'], 3248732857.0, 'should be copied from raw'); + t.end(); + + }); + +}; + +module.exports.all = function (tape, common) { + function test(name, testFunction) { + return tape('SANTIZE _geo_reverse ' + name, testFunction); + } + + for( var testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +}; diff --git a/test/unit/sanitiser/reverse.js b/test/unit/sanitiser/reverse.js index 818829f9..b92896e7 100644 --- a/test/unit/sanitiser/reverse.js +++ b/test/unit/sanitiser/reverse.js @@ -4,11 +4,13 @@ var reverse = require('../../../sanitiser/reverse'), sanitize = reverse.sanitize, middleware = reverse.middleware, + defaults = require('../../../query/defaults'), defaultError = 'missing param \'lat\'', defaultClean = { 'point.lat': 0, 'point.lon': 0, 'boundary.circle.lat': 0, 'boundary.circle.lon': 0, + 'boundary.circle.radius': parseFloat(defaults['boundary:circle:radius']), types: { }, size: 10,