From f67664c3e04a1168a37376060494e45bce21502d Mon Sep 17 00:00:00 2001 From: Lily He Date: Wed, 5 Jul 2017 17:18:46 -0400 Subject: [PATCH 1/5] location bias feature - sets default focus.point --- sanitizer/_location_bias.js | 18 ++++++ schema.js | 6 +- test/unit/run.js | 1 + test/unit/sanitizer/_location_bias.js | 90 +++++++++++++++++++++++++++ test/unit/schema.js | 78 +++++++++++++++++++++++ 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 sanitizer/_location_bias.js create mode 100644 test/unit/sanitizer/_location_bias.js diff --git a/sanitizer/_location_bias.js b/sanitizer/_location_bias.js new file mode 100644 index 00000000..ee6646f6 --- /dev/null +++ b/sanitizer/_location_bias.js @@ -0,0 +1,18 @@ +/* +Set a focus.lat and focus.lon if specified in pelias config +*/ +var _ = require('lodash'); + +function setup(defaultParameters){ + return function setLocationBias(req, res, next){ + if (_.isUndefined(req.clean) || _.isUndefined(defaultParameters['focus.point.lat']) || _.isUndefined(defaultParameters['focus.point.lon'])) { + return next(); + } + req.clean['focus.point.lat'] = defaultParameters['focus.point.lat']; + req.clean['focus.point.lon'] = defaultParameters['focus.point.lon']; + next(); + }; +} + + +module.exports = setup; diff --git a/schema.js b/schema.js index df544677..e261cfe6 100644 --- a/schema.js +++ b/schema.js @@ -39,7 +39,11 @@ module.exports = Joi.object().keys({ timeout: Joi.number().integer().optional().default(250).min(0), retries: Joi.number().integer().optional().default(3).min(0), }).unknown(false).requiredKeys('url') - }).unknown(false).default({}) // default api.services to an empty object + }).unknown(false).default({}), // default api.services to an empty object + defaultParameters: Joi.object().keys({ + 'focus.point.lat': Joi.number().optional().min(-90).max(90), + 'focus.point.lon': Joi.number().optional().min(-180).max(180), + }).unknown(true).default({}) }).requiredKeys('version', 'indexName', 'host').unknown(true), esclient: Joi.object().keys({ diff --git a/test/unit/run.js b/test/unit/run.js index 92d258fa..b60f06c5 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -64,6 +64,7 @@ var tests = [ require('./sanitizer/_ids'), require('./sanitizer/_iso2_to_iso3'), require('./sanitizer/_layers'), + require('./sanitizer/_location_bias'), require('./sanitizer/_city_name_standardizer'), require('./sanitizer/_single_scalar_parameters'), require('./sanitizer/_size'), diff --git a/test/unit/sanitizer/_location_bias.js b/test/unit/sanitizer/_location_bias.js new file mode 100644 index 00000000..c0f48cf9 --- /dev/null +++ b/test/unit/sanitizer/_location_bias.js @@ -0,0 +1,90 @@ +var setup = require('../../../sanitizer/_location_bias'); + +module.exports.tests = {}; + +module.exports.tests.setLocationBias = function(test, common) { + test('set focus point', t => { + var defaultParameters = { // specify focus point latitude and longitude + 'focus.point.lat': 12.12121212, + 'focus.point.lon': 21.21212121 + }; + var locationBias = setup(defaultParameters); + var req = { + clean: {} + }; + var expected = { + clean: { + 'focus.point.lat': 12.12121212, + 'focus.point.lon': 21.21212121 + } + }; + + locationBias(req, undefined, () => { + t.deepEqual(req, expected, 'focus point should be set'); + t.end(); + }); + }); + + test('undefined req.clean', t => { + var defaultParameters = { + 'focus.point.lat': 12.12121212, + 'focus.point.lon': 21.21212121 + }; + var locationBias = setup(defaultParameters); + var req = {}; + var expected = {}; + + locationBias(req, undefined, () => { + t.deepEqual(req, expected, 'should be unmodified' ); + t.end(); + }); + }); + + test('focusPointLat is undefined', t => { + var defaultParameters = { + 'focus.point.lon': 12.2121212 + }; + var locationBias = setup(defaultParameters); + var req = { + clean: {} + }; + var expected = { + clean: {} + }; + + locationBias(req, undefined, () => { + t.deepEqual(req, expected, 'should be unmodified' ); + t.end(); + }); + }); + + test('focusPointLon is undefined', t => { + var defaultParameters = { + 'focus.point.lat': 12.2121212 + }; + var locationBias = setup(defaultParameters); + var req = { + clean: {} + }; + var expected = { + clean: {} + }; + + locationBias(req, undefined, () => { + t.deepEqual(req, expected, 'should be unmodified' ); + t.end(); + }); + }); + +}; + +module.exports.all = function (tape, common) { + + function test(name, testFunction) { + return tape('[middleware] locationBias: ' + name, testFunction); + } + + for( var testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +}; diff --git a/test/unit/schema.js b/test/unit/schema.js index d48c7392..332347dd 100644 --- a/test/unit/schema.js +++ b/test/unit/schema.js @@ -26,6 +26,10 @@ module.exports.tests.completely_valid = (test, common) => { placeholder: { url: 'http://locahost' } + }, + defaultParameters: { + 'focus.point.lat': 19, + 'focus.point.lon': 91 } }, esclient: { @@ -457,6 +461,80 @@ module.exports.tests.api_validation = (test, common) => { }); + test('non-number defaultParameters.focus.point.lat should throw error', (t) => { + [null, 'string', {}, [], false].forEach((value) => { + const config = { + api: { + version: 'version value', + indexName: 'index name value', + host: 'host value', + defaultParameters: { + 'focus.point.lat': value + } + }, + esclient: {} + }; + + const result = Joi.validate(config, schema); + + t.equals(result.error.details.length, 1); + t.equals(result.error.details[0].message, '"focus.point.lat" must be a number'); + + }); + + t.end(); + + }); + + test('non-number defaultParameters.focus.point.lon should throw error', (t) => { + [null, 'string', {}, [], false].forEach((value) => { + const config = { + api: { + version: 'version value', + indexName: 'index name value', + host: 'host value', + defaultParameters: { + 'focus.point.lon': value + } + }, + esclient: {} + }; + + const result = Joi.validate(config, schema); + + t.equals(result.error.details.length, 1); + t.equals(result.error.details[0].message, '"focus.point.lon" must be a number'); + + }); + + t.end(); + + }); + + test('non-object api.defaultParameters should throw error', (t) => { + [null, 17, false, [], 'string'].forEach((value) => { + var config = { + api: { + version: 'version value', + indexName: 'index name value', + host: 'host value', + defaultParameters: value + }, + esclient: {} + }; + + const result = Joi.validate(config, schema); + + t.equals(result.error.details.length, 1); + t.equals(result.error.details[0].message, '"defaultParameters" must be an object'); + + }); + + t.end(); + + }); + + }; module.exports.tests.api_services_validation = (test, common) => { From 2e2ae9b0052cfe62b9ed9f6e807b0e51a740798d Mon Sep 17 00:00:00 2001 From: Lily He Date: Wed, 5 Jul 2017 17:23:13 -0400 Subject: [PATCH 2/5] added location_bias sanitizer to autocomplete, search, and structured_geocoding --- sanitizer/_location_bias.js | 4 +++- sanitizer/autocomplete.js | 1 + sanitizer/search.js | 1 + sanitizer/structured_geocoding.js | 1 + test/unit/sanitizer/autocomplete.js | 2 +- test/unit/sanitizer/search.js | 6 ++++++ test/unit/sanitizer/structured_geocoding.js | 5 +++++ 7 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sanitizer/_location_bias.js b/sanitizer/_location_bias.js index ee6646f6..2ecc76b6 100644 --- a/sanitizer/_location_bias.js +++ b/sanitizer/_location_bias.js @@ -5,7 +5,9 @@ var _ = require('lodash'); function setup(defaultParameters){ return function setLocationBias(req, res, next){ - if (_.isUndefined(req.clean) || _.isUndefined(defaultParameters['focus.point.lat']) || _.isUndefined(defaultParameters['focus.point.lon'])) { + if (_.isUndefined(req.clean) || + _.isUndefined(defaultParameters['focus.point.lat']) || + _.isUndefined(defaultParameters['focus.point.lon'])) { return next(); } req.clean['focus.point.lat'] = defaultParameters['focus.point.lat']; diff --git a/sanitizer/autocomplete.js b/sanitizer/autocomplete.js index 86f85447..bf959c78 100644 --- a/sanitizer/autocomplete.js +++ b/sanitizer/autocomplete.js @@ -11,6 +11,7 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'), // depends on the layers and sources sanitizers, must be run after them sources_and_layers: require('../sanitizer/_sources_and_layers'), private: require('../sanitizer/_flag_bool')('private', false), + location_bias: require('../sanitizer/_location_bias'), geo_autocomplete: require('../sanitizer/_geo_autocomplete'), boundary_country: require('../sanitizer/_boundary_country'), categories: require('../sanitizer/_categories') diff --git a/sanitizer/search.js b/sanitizer/search.js index 1d2507c2..d036eb2f 100644 --- a/sanitizer/search.js +++ b/sanitizer/search.js @@ -13,6 +13,7 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'), // depends on the layers and sources sanitizers, must be run after them sources_and_layers: require('../sanitizer/_sources_and_layers'), private: require('../sanitizer/_flag_bool')('private', false), + location_bias: require('../sanitizer/_location_bias'), geo_search: require('../sanitizer/_geo_search'), boundary_country: require('../sanitizer/_boundary_country'), categories: require('../sanitizer/_categories'), diff --git a/sanitizer/structured_geocoding.js b/sanitizer/structured_geocoding.js index 29edce41..7f2248da 100644 --- a/sanitizer/structured_geocoding.js +++ b/sanitizer/structured_geocoding.js @@ -13,6 +13,7 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'), // depends on the layers and sources sanitizers, must be run after them sources_and_layers: require('../sanitizer/_sources_and_layers'), private: require('../sanitizer/_flag_bool')('private', false), + location_bias: require('../sanitizer/_location_bias'), geo_search: require('../sanitizer/_geo_search'), boundary_country: require('../sanitizer/_boundary_country'), categories: require('../sanitizer/_categories') diff --git a/test/unit/sanitizer/autocomplete.js b/test/unit/sanitizer/autocomplete.js index 29db50ee..efdb54b9 100644 --- a/test/unit/sanitizer/autocomplete.js +++ b/test/unit/sanitizer/autocomplete.js @@ -6,7 +6,7 @@ module.exports.tests.sanitizers = function(test, common) { test('check sanitizer list', function (t) { var expected = [ 'singleScalarParameters', 'text', 'tokenizer', 'size', 'layers', 'sources', - 'sources_and_layers', 'private', 'geo_autocomplete', 'boundary_country', 'categories' + 'sources_and_layers', 'private', 'location_bias', 'geo_autocomplete', 'boundary_country', 'categories' ]; t.deepEqual(Object.keys(autocomplete.sanitizer_list), expected); t.end(); diff --git a/test/unit/sanitizer/search.js b/test/unit/sanitizer/search.js index e7a8e3fe..fca395c2 100644 --- a/test/unit/sanitizer/search.js +++ b/test/unit/sanitizer/search.js @@ -87,7 +87,12 @@ module.exports.tests.sanitize = (test, common) => { '../sanitizer/_geonames_warnings': () => { called_sanitizers.push('_geonames_warnings'); return { errors: [], warnings: [] }; + }, + '../sanitizer/_location_bias': () => { + called_sanitizers.push('_location_bias'); + return { errors: [], warnings: [] }; } + }); const expected_sanitizers = [ @@ -101,6 +106,7 @@ module.exports.tests.sanitize = (test, common) => { '_targets/sources', '_sources_and_layers', '_flag_bool', + '_location_bias', '_geo_search', '_boundary_country', '_categories', diff --git a/test/unit/sanitizer/structured_geocoding.js b/test/unit/sanitizer/structured_geocoding.js index 133be462..b93e1e71 100644 --- a/test/unit/sanitizer/structured_geocoding.js +++ b/test/unit/sanitizer/structured_geocoding.js @@ -83,6 +83,10 @@ module.exports.tests.sanitize = function(test, common) { called_sanitizers.push('_categories'); return { errors: [], warnings: [] }; }, + '../sanitizer/_location_bias': () => { + called_sanitizers.push('_location_bias'); + return { errors: [], warnings: [] }; + } }); var expected_sanitizers = [ @@ -96,6 +100,7 @@ module.exports.tests.sanitize = function(test, common) { '_targets/sources', '_sources_and_layers', '_flag_bool', + '_location_bias', '_geo_search', '_boundary_country', '_categories' From 40ca17b88678d5285d4d31318b535f95d40f738b Mon Sep 17 00:00:00 2001 From: Lily He Date: Fri, 7 Jul 2017 14:18:38 -0400 Subject: [PATCH 3/5] passed down peliasConfig.api schema to sanitizers --- routes/v1.js | 6 +- sanitizer/_location_bias.js | 23 ++-- sanitizer/autocomplete.js | 30 +++-- sanitizer/search.js | 54 ++++----- sanitizer/structured_geocoding.js | 51 +++++---- test/unit/sanitizer/_location_bias.js | 77 +++++-------- test/unit/sanitizer/autocomplete.js | 121 ++++++++++++++++++-- test/unit/sanitizer/search.js | 23 +++- test/unit/sanitizer/structured_geocoding.js | 23 +++- 9 files changed, 263 insertions(+), 145 deletions(-) diff --git a/routes/v1.js b/routes/v1.js index 1449887f..83d2fb78 100644 --- a/routes/v1.js +++ b/routes/v1.js @@ -129,7 +129,7 @@ function addRoutes(app, peliasConfig) { controllers.mdToHTML(peliasConfig.api, './public/attribution.md') ]), search: createRouter([ - sanitizers.search.middleware, + sanitizers.search.middleware(peliasConfig.api), middleware.requestLanguage, middleware.calcSize(), controllers.placeholder(placeholderService, placeholderShouldExecute), @@ -156,7 +156,7 @@ function addRoutes(app, peliasConfig) { postProc.sendJSON ]), structured: createRouter([ - sanitizers.structured_geocoding.middleware, + sanitizers.structured_geocoding.middleware(peliasConfig.api), middleware.requestLanguage, middleware.calcSize(), controllers.search(peliasConfig.api, esclient, queries.structured_geocoding, not(hasResponseDataOrRequestErrors)), @@ -177,7 +177,7 @@ function addRoutes(app, peliasConfig) { postProc.sendJSON ]), autocomplete: createRouter([ - sanitizers.autocomplete.middleware, + sanitizers.autocomplete.middleware(peliasConfig.api), middleware.requestLanguage, controllers.search(peliasConfig.api, esclient, queries.autocomplete, not(hasResponseDataOrRequestErrors)), postProc.distances('focus.point.'), diff --git a/sanitizer/_location_bias.js b/sanitizer/_location_bias.js index 2ecc76b6..329b34ed 100644 --- a/sanitizer/_location_bias.js +++ b/sanitizer/_location_bias.js @@ -1,18 +1,21 @@ -/* +const _ = require('lodash'); +/** Set a focus.lat and focus.lon if specified in pelias config +* @param {object} defaultParameters property of pelias config */ -var _ = require('lodash'); function setup(defaultParameters){ - return function setLocationBias(req, res, next){ - if (_.isUndefined(req.clean) || - _.isUndefined(defaultParameters['focus.point.lat']) || - _.isUndefined(defaultParameters['focus.point.lon'])) { - return next(); + + return function setLocationBias(raw, clean){ + if (!_.isUndefined(raw) && + !_.isUndefined(defaultParameters['focus.point.lat']) && + !_.isUndefined(defaultParameters['focus.point.lon'])) { + + raw['focus.point.lat'] = defaultParameters['focus.point.lat']; + raw['focus.point.lon'] = defaultParameters['focus.point.lon']; } - req.clean['focus.point.lat'] = defaultParameters['focus.point.lat']; - req.clean['focus.point.lon'] = defaultParameters['focus.point.lon']; - next(); + + return { errors: [], warnings: [] }; }; } diff --git a/sanitizer/autocomplete.js b/sanitizer/autocomplete.js index bf959c78..ed875bf5 100644 --- a/sanitizer/autocomplete.js +++ b/sanitizer/autocomplete.js @@ -1,7 +1,9 @@ var type_mapping = require('../helper/type_mapping'); +var sanitizeAll = require('../sanitizer/sanitizeAll'); -var sanitizeAll = require('../sanitizer/sanitizeAll'), - sanitizers = { +// middleware +module.exports.middleware = (_api_pelias_config) => { + var sanitizers = { singleScalarParameters: require('../sanitizer/_single_scalar_parameters'), text: require('../sanitizer/_text_addressit'), tokenizer: require('../sanitizer/_tokenizer'), @@ -11,25 +13,21 @@ var sanitizeAll = require('../sanitizer/sanitizeAll'), // depends on the layers and sources sanitizers, must be run after them sources_and_layers: require('../sanitizer/_sources_and_layers'), private: require('../sanitizer/_flag_bool')('private', false), - location_bias: require('../sanitizer/_location_bias'), + location_bias: require('../sanitizer/_location_bias')(_api_pelias_config.defaultParameters), geo_autocomplete: require('../sanitizer/_geo_autocomplete'), boundary_country: require('../sanitizer/_boundary_country'), categories: require('../sanitizer/_categories') }; -var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; - -// export sanitize for testing -module.exports.sanitize = sanitize; -module.exports.sanitizer_list = sanitizers; + var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; -// middleware -module.exports.middleware = function( req, res, next ){ - sanitize( req, function( err, clean ){ - if( err ){ - res.status(400); // 400 Bad Request - return next(err); - } + return function( req, res, next ){ + sanitize( req, function( err, clean ){ + if( err ){ + res.status(400); // 400 Bad Request + return next(err); + } next(); - }); + }); + }; }; diff --git a/sanitizer/search.js b/sanitizer/search.js index d036eb2f..99baa5a7 100644 --- a/sanitizer/search.js +++ b/sanitizer/search.js @@ -1,31 +1,33 @@ var type_mapping = require('../helper/type_mapping'); +var sanitizeAll = require('../sanitizer/sanitizeAll'); +// middleware +module.exports.middleware = (_api_pelias_config) => { + var sanitizers = { + singleScalarParameters: require('../sanitizer/_single_scalar_parameters'), + quattroshapes_deprecation: require('../sanitizer/_deprecate_quattroshapes'), + text: require('../sanitizer/_text'), + iso2_to_iso3: require('../sanitizer/_iso2_to_iso3'), + city_name_standardizer: require('../sanitizer/_city_name_standardizer'), + size: require('../sanitizer/_size')(/* use defaults*/), + layers: require('../sanitizer/_targets')('layers', type_mapping.layer_mapping), + sources: require('../sanitizer/_targets')('sources', type_mapping.source_mapping), + // depends on the layers and sources sanitizers, must be run after them + sources_and_layers: require('../sanitizer/_sources_and_layers'), + private: require('../sanitizer/_flag_bool')('private', false), + location_bias: require('../sanitizer/_location_bias')(_api_pelias_config.defaultParameters), + geo_search: require('../sanitizer/_geo_search'), + boundary_country: require('../sanitizer/_boundary_country'), + categories: require('../sanitizer/_categories'), + // this can go away once geonames has been abrogated + geonames_warnings: require('../sanitizer/_geonames_warnings') + }; -var sanitizeAll = require('../sanitizer/sanitizeAll'), - sanitizers = { - singleScalarParameters: require('../sanitizer/_single_scalar_parameters'), - quattroshapes_deprecation: require('../sanitizer/_deprecate_quattroshapes'), - text: require('../sanitizer/_text'), - iso2_to_iso3: require('../sanitizer/_iso2_to_iso3'), - city_name_standardizer: require('../sanitizer/_city_name_standardizer'), - size: require('../sanitizer/_size')(/* use defaults*/), - layers: require('../sanitizer/_targets')('layers', type_mapping.layer_mapping), - sources: require('../sanitizer/_targets')('sources', type_mapping.source_mapping), - // depends on the layers and sources sanitizers, must be run after them - sources_and_layers: require('../sanitizer/_sources_and_layers'), - private: require('../sanitizer/_flag_bool')('private', false), - location_bias: require('../sanitizer/_location_bias'), - geo_search: require('../sanitizer/_geo_search'), - boundary_country: require('../sanitizer/_boundary_country'), - categories: require('../sanitizer/_categories'), - // this can go away once geonames has been abrogated - geonames_warnings: require('../sanitizer/_geonames_warnings') - }; + var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; -var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; + return function( req, res, next ){ + sanitize( req, function( err, clean ){ + next(); + }); + }; -// middleware -module.exports.middleware = function( req, res, next ){ - sanitize( req, function( err, clean ){ - next(); - }); }; diff --git a/sanitizer/structured_geocoding.js b/sanitizer/structured_geocoding.js index 7f2248da..e19a2837 100644 --- a/sanitizer/structured_geocoding.js +++ b/sanitizer/structured_geocoding.js @@ -1,29 +1,30 @@ var type_mapping = require('../helper/type_mapping'); - -var sanitizeAll = require('../sanitizer/sanitizeAll'), - sanitizers = { - singleScalarParameters: require('../sanitizer/_single_scalar_parameters'), - quattroshapes_deprecation: require('../sanitizer/_deprecate_quattroshapes'), - synthesize_analysis: require('../sanitizer/_synthesize_analysis'), - iso2_to_iso3: require('../sanitizer/_iso2_to_iso3'), - city_name_standardizer: require('../sanitizer/_city_name_standardizer'), - size: require('../sanitizer/_size')(/* use defaults*/), - layers: require('../sanitizer/_targets')('layers', type_mapping.layer_mapping), - sources: require('../sanitizer/_targets')('sources', type_mapping.source_mapping), - // depends on the layers and sources sanitizers, must be run after them - sources_and_layers: require('../sanitizer/_sources_and_layers'), - private: require('../sanitizer/_flag_bool')('private', false), - location_bias: require('../sanitizer/_location_bias'), - geo_search: require('../sanitizer/_geo_search'), - boundary_country: require('../sanitizer/_boundary_country'), - categories: require('../sanitizer/_categories') - }; - -var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; +var sanitizeAll = require('../sanitizer/sanitizeAll'); // middleware -module.exports.middleware = function( req, res, next ){ - sanitize( req, function( err, clean ){ - next(); - }); +module.exports.middleware = (_api_pelias_config) => { + var sanitizers = { + singleScalarParameters: require('../sanitizer/_single_scalar_parameters'), + quattroshapes_deprecation: require('../sanitizer/_deprecate_quattroshapes'), + synthesize_analysis: require('../sanitizer/_synthesize_analysis'), + iso2_to_iso3: require('../sanitizer/_iso2_to_iso3'), + city_name_standardizer: require('../sanitizer/_city_name_standardizer'), + size: require('../sanitizer/_size')(/* use defaults*/), + layers: require('../sanitizer/_targets')('layers', type_mapping.layer_mapping), + sources: require('../sanitizer/_targets')('sources', type_mapping.source_mapping), + // depends on the layers and sources sanitizers, must be run after them + sources_and_layers: require('../sanitizer/_sources_and_layers'), + private: require('../sanitizer/_flag_bool')('private', false), + location_bias: require('../sanitizer/_location_bias')(_api_pelias_config.defaultParameters), + geo_search: require('../sanitizer/_geo_search'), + boundary_country: require('../sanitizer/_boundary_country'), + categories: require('../sanitizer/_categories') + }; + var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; + + return function( req, res, next ){ + sanitize( req, function( err, clean ){ + next(); + }); + }; }; diff --git a/test/unit/sanitizer/_location_bias.js b/test/unit/sanitizer/_location_bias.js index c0f48cf9..b78cdac4 100644 --- a/test/unit/sanitizer/_location_bias.js +++ b/test/unit/sanitizer/_location_bias.js @@ -1,87 +1,70 @@ -var setup = require('../../../sanitizer/_location_bias'); +const setup = require('../../../sanitizer/_location_bias'); module.exports.tests = {}; module.exports.tests.setLocationBias = function(test, common) { test('set focus point', t => { - var defaultParameters = { // specify focus point latitude and longitude + const defaultParameters = { // specify focus point latitude and longitude 'focus.point.lat': 12.12121212, 'focus.point.lon': 21.21212121 }; - var locationBias = setup(defaultParameters); - var req = { - clean: {} - }; - var expected = { - clean: { + const locationBias = setup(defaultParameters); + const raw = {}; + const expected = { 'focus.point.lat': 12.12121212, 'focus.point.lon': 21.21212121 - } }; - locationBias(req, undefined, () => { - t.deepEqual(req, expected, 'focus point should be set'); - t.end(); - }); + locationBias(raw, undefined); + t.deepEqual(raw, expected, 'focus point should be set'); + t.end(); + }); - test('undefined req.clean', t => { - var defaultParameters = { + test('undefined raw', t => { + const defaultParameters = { 'focus.point.lat': 12.12121212, 'focus.point.lon': 21.21212121 }; - var locationBias = setup(defaultParameters); - var req = {}; - var expected = {}; + const locationBias = setup(defaultParameters); - locationBias(req, undefined, () => { - t.deepEqual(req, expected, 'should be unmodified' ); - t.end(); - }); + locationBias(undefined, undefined); + t.deepEqual(undefined, undefined, 'should be unmodified' ); + t.end(); }); test('focusPointLat is undefined', t => { - var defaultParameters = { + const defaultParameters = { 'focus.point.lon': 12.2121212 }; - var locationBias = setup(defaultParameters); - var req = { - clean: {} - }; - var expected = { - clean: {} - }; + const locationBias = setup(defaultParameters); + const raw = {}; + const expected = {}; - locationBias(req, undefined, () => { - t.deepEqual(req, expected, 'should be unmodified' ); - t.end(); - }); + locationBias(raw, undefined); + t.deepEqual(raw, expected, 'should be unmodified' ); + t.end(); }); test('focusPointLon is undefined', t => { - var defaultParameters = { + const defaultParameters = { 'focus.point.lat': 12.2121212 }; - var locationBias = setup(defaultParameters); - var req = { - clean: {} - }; - var expected = { - clean: {} - }; + const locationBias = setup(defaultParameters); + const raw = {}; + const expected = {}; - locationBias(req, undefined, () => { - t.deepEqual(req, expected, 'should be unmodified' ); + locationBias(raw, undefined); + t.deepEqual(raw, expected, 'should be unmodified' ); t.end(); - }); }); }; -module.exports.all = function (tape, common) { +module.exports.all = (tape, common) => { function test(name, testFunction) { - return tape('[middleware] locationBias: ' + name, testFunction); + return tape(`SANITIZE _location_bias: ${name}`, testFunction); } for( var testCase in module.exports.tests ){ diff --git a/test/unit/sanitizer/autocomplete.js b/test/unit/sanitizer/autocomplete.js index efdb54b9..9f0b4a3a 100644 --- a/test/unit/sanitizer/autocomplete.js +++ b/test/unit/sanitizer/autocomplete.js @@ -1,21 +1,126 @@ -var autocomplete = require('../../../sanitizer/autocomplete'); +const proxyquire = require('proxyquire').noCallThru(); +const _ = require('lodash'); module.exports.tests = {}; module.exports.tests.sanitizers = function(test, common) { - test('check sanitizer list', function (t) { - var expected = [ - 'singleScalarParameters', 'text', 'tokenizer', 'size', 'layers', 'sources', - 'sources_and_layers', 'private', 'location_bias', 'geo_autocomplete', 'boundary_country', 'categories' + test('verify that all sanitizers were called as expected', function(t) { + var called_sanitizers = []; + + var autocomplete = proxyquire('../../../sanitizer/autocomplete', { + '../sanitizer/_single_scalar_parameters': () => { + called_sanitizers.push('_single_scalar_parameters'); + return { errors: [], warnings: [] }; + }, + '../sanitizer/_text_addressit': () => { + called_sanitizers.push('_text_addressit'); + return { errors: [], warnings: [] }; + }, + '../sanitizer/_tokenizer': () => { + called_sanitizers.push('_tokenizer'); + return { errors: [], warnings: [] }; + }, + '../sanitizer/_size': function() { + if (_.isEqual(_.values(arguments), [10, 10, 10])) { + return () => { + called_sanitizers.push('_size'); + return { errors: [], warnings: [] }; + }; + + } else { + throw new Error('incorrect parameters passed to _size'); + } + + }, + '../sanitizer/_targets': (type) => { + if (['layers', 'sources'].indexOf(type) !== -1) { + return () => { + called_sanitizers.push(`_targets/${type}`); + return { errors: [], warnings: [] }; + }; + + } + else { + throw new Error('incorrect parameters passed to _targets'); + } + + }, + '../sanitizer/_sources_and_layers': () => { + called_sanitizers.push('_sources_and_layers'); + return { errors: [], warnings: [] }; + }, + '../sanitizer/_flag_bool': function() { + if (arguments[0] === 'private' && arguments[1] === false) { + return () => { + called_sanitizers.push('_flag_bool'); + return { errors: [], warnings: [] }; + }; + + } + else { + throw new Error('incorrect parameters passed to _flag_bool'); + } + + }, + '../sanitizer/_location_bias': (defaultParameters) => { + if (defaultParameters.key === 'value'){ + return () => { + called_sanitizers.push('_location_bias'); + return { errors: [], warnings: [] }; + }; + } else { + throw new Error('incorrect parameter passed to _location_bias'); + } + }, + '../sanitizer/_geo_autocomplete': () => { + called_sanitizers.push('_geo_autocomplete'); + return { errors: [], warnings: [] }; + }, + '../sanitizer/_boundary_country': () => { + called_sanitizers.push('_boundary_country'); + return { errors: [], warnings: [] }; + }, + '../sanitizer/_categories': () => { + called_sanitizers.push('_categories'); + return { errors: [], warnings: [] }; + }, + }); + + const expected_sanitizers = [ + '_single_scalar_parameters', + '_text_addressit', + '_tokenizer', + '_size', + '_targets/layers', + '_targets/sources', + '_sources_and_layers', + '_flag_bool', + '_location_bias', + '_geo_autocomplete', + '_boundary_country', + '_categories' ]; - t.deepEqual(Object.keys(autocomplete.sanitizer_list), expected); - t.end(); + + const req = {}; + const res = {}; + + const middleware = autocomplete.middleware({ + defaultParameters: { + key: 'value' + } + }); + + middleware(req, res, () => { + t.deepEquals(called_sanitizers, expected_sanitizers); + t.end(); + }); + }); }; module.exports.all = function (tape, common) { function test(name, testFunction) { - return tape('SANTIZE /autocomplete ' + name, testFunction); + return tape('SANITIZE /autocomplete ' + name, testFunction); } for( var testCase in module.exports.tests ){ diff --git a/test/unit/sanitizer/search.js b/test/unit/sanitizer/search.js index fca395c2..214c9cbc 100644 --- a/test/unit/sanitizer/search.js +++ b/test/unit/sanitizer/search.js @@ -88,9 +88,15 @@ module.exports.tests.sanitize = (test, common) => { called_sanitizers.push('_geonames_warnings'); return { errors: [], warnings: [] }; }, - '../sanitizer/_location_bias': () => { - called_sanitizers.push('_location_bias'); - return { errors: [], warnings: [] }; + '../sanitizer/_location_bias': (defaultParameters) => { + if (defaultParameters.key === 'value'){ + return () => { + called_sanitizers.push('_location_bias'); + return { errors: [], warnings: [] }; + }; + } else { + throw new Error('incorrect parameter passed to _location_bias'); + } } }); @@ -116,17 +122,24 @@ module.exports.tests.sanitize = (test, common) => { const req = {}; const res = {}; - search.middleware(req, res, () => { + const middleware = search.middleware({ + defaultParameters: { + key: 'value' + } + }); + + middleware(req, res, () => { t.deepEquals(called_sanitizers, expected_sanitizers); t.end(); }); + }); }; module.exports.all = (tape, common) => { function test(name, testFunction) { - return tape(`SANTIZE /search ${name}`, testFunction); + return tape(`SANITIZE /search ${name}`, testFunction); } for( const testCase in module.exports.tests ){ diff --git a/test/unit/sanitizer/structured_geocoding.js b/test/unit/sanitizer/structured_geocoding.js index b93e1e71..3cc10432 100644 --- a/test/unit/sanitizer/structured_geocoding.js +++ b/test/unit/sanitizer/structured_geocoding.js @@ -83,9 +83,15 @@ module.exports.tests.sanitize = function(test, common) { called_sanitizers.push('_categories'); return { errors: [], warnings: [] }; }, - '../sanitizer/_location_bias': () => { - called_sanitizers.push('_location_bias'); - return { errors: [], warnings: [] }; + '../sanitizer/_location_bias': function (defaultParameters) { + if (defaultParameters.key === 'value'){ + return () => { + called_sanitizers.push('_location_bias'); + return { errors: [], warnings: [] }; + }; + } else { + throw new Error('incorrect parameter passed to _location_bias'); + } } }); @@ -109,17 +115,24 @@ module.exports.tests.sanitize = function(test, common) { var req = {}; var res = {}; - search.middleware(req, res, function(){ + const middleware = search.middleware({ + defaultParameters: { + key: 'value' + } + }); + + middleware(req, res, function(){ t.deepEquals(called_sanitizers, expected_sanitizers); t.end(); }); + }); }; module.exports.all = function (tape, common) { function test(name, testFunction) { - return tape('SANTIZE /structured ' + name, testFunction); + return tape('SANITIZE /structured ' + name, testFunction); } for( var testCase in module.exports.tests ){ From 5504240016479f404a70927ff9555f28ec10d924 Mon Sep 17 00:00:00 2001 From: Lily He Date: Mon, 10 Jul 2017 12:50:03 -0400 Subject: [PATCH 4/5] prevent overriding raw.focus.point.lat/lon --- sanitizer/_location_bias.js | 12 +++++++-- schema.js | 4 +-- test/unit/sanitizer/_location_bias.js | 36 +++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/sanitizer/_location_bias.js b/sanitizer/_location_bias.js index 329b34ed..4c9c7f8b 100644 --- a/sanitizer/_location_bias.js +++ b/sanitizer/_location_bias.js @@ -7,9 +7,17 @@ Set a focus.lat and focus.lon if specified in pelias config function setup(defaultParameters){ return function setLocationBias(raw, clean){ +/* +check that: +1. {object} raw exists +2. pelias-config included the properties focus.point.lat and focus.point.lon +3. raw.focus.point.lon and raw.focus.point.lat have not been set +*/ if (!_.isUndefined(raw) && !_.isUndefined(defaultParameters['focus.point.lat']) && - !_.isUndefined(defaultParameters['focus.point.lon'])) { + !_.isUndefined(defaultParameters['focus.point.lon']) && + !_.has(raw, 'focus.point.lon') && + !_.has(raw, 'focus.point.lat') ) { raw['focus.point.lat'] = defaultParameters['focus.point.lat']; raw['focus.point.lon'] = defaultParameters['focus.point.lon']; @@ -19,5 +27,5 @@ function setup(defaultParameters){ }; } - +// if focus.point.lat and focus.point.lon already exists, don't change module.exports = setup; diff --git a/schema.js b/schema.js index e261cfe6..e37cf055 100644 --- a/schema.js +++ b/schema.js @@ -41,8 +41,8 @@ module.exports = Joi.object().keys({ }).unknown(false).requiredKeys('url') }).unknown(false).default({}), // default api.services to an empty object defaultParameters: Joi.object().keys({ - 'focus.point.lat': Joi.number().optional().min(-90).max(90), - 'focus.point.lon': Joi.number().optional().min(-180).max(180), + 'focus.point.lat': Joi.number(), + 'focus.point.lon': Joi.number(), }).unknown(true).default({}) }).requiredKeys('version', 'indexName', 'host').unknown(true), diff --git a/test/unit/sanitizer/_location_bias.js b/test/unit/sanitizer/_location_bias.js index b78cdac4..6778f045 100644 --- a/test/unit/sanitizer/_location_bias.js +++ b/test/unit/sanitizer/_location_bias.js @@ -59,6 +59,42 @@ module.exports.tests.setLocationBias = function(test, common) { t.end(); }); + test('raw has focus.point.lon already', t => { + const defaultParameters = { + 'focus.point.lon': 12.2121212, + 'focus.point.lat': 12.2121212 + }; + const locationBias = setup(defaultParameters); + const raw = { + 'focus.point.lon': 43.4343434 + }; + const expected = { + 'focus.point.lon': 43.4343434 + }; + + locationBias(raw, undefined); + t.deepEqual(raw, expected, 'should be unmodified' ); + t.end(); + }); + + test('raw has focus.point.lat already', t => { + const defaultParameters = { + 'focus.point.lon': 12.2121212, + 'focus.point.lat': 12.2121212 + }; + const locationBias = setup(defaultParameters); + const raw = { + 'focus.point.lat': 34.3434343 + }; + const expected = { + 'focus.point.lat': 34.3434343 + }; + + locationBias(raw, undefined); + t.deepEqual(raw, expected, 'should be unmodified' ); + t.end(); + }); + }; module.exports.all = (tape, common) => { From a66df9bbdc16581ef6b68dfa8df9b534612eabde Mon Sep 17 00:00:00 2001 From: Lily He Date: Mon, 10 Jul 2017 15:03:57 -0400 Subject: [PATCH 5/5] location bias description in README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index e066a575..5c7680ab 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ The API recognizes the following properties under the top-level `api` key in you |`relativeScores`|*no*|true|if set to true, confidence scores will be normalized, realistically at this point setting this to false is not tested or desirable |`accessLog`|*no*||name of the format to use for access logs; may be any one of the [predefined values](https://github.com/expressjs/morgan#predefined-formats) in the `morgan` package. Defaults to `"common"`; if set to `false`, or an otherwise falsy value, disables access-logging entirely.| |`services`|*no*||service definitions for [point-in-polygon](https://github.com/pelias/pip-service) and [placholder](https://github.com/pelias/placeholder) services. If missing (which is not recommended), the point-in-polygon and placeholder services will not be called.| +|`defaultParameters.focus.point.lon`
`defaultParameters.focus.point.lat`|no | |default coordinates for focus point Example configuration file would look something like this: @@ -76,6 +77,10 @@ Example configuration file would look something like this: "url": "http://myplaceholderservice.com:5000" } } + "defaultParameters": { + "focus.point.lat": 12.121212, + "focus.point.lon": 21.212121 + } }, "interpolation": { "client": {