From 3ebdc668f0ce915e7ad767b16b449c2a64f786b9 Mon Sep 17 00:00:00 2001 From: Alexey Kostyuk <unitoff@gmail.com> Date: Sat, 12 Mar 2016 22:10:08 +0300 Subject: [PATCH] Added ipinfo.io provider --- README.md | 9 +++++ lib/geocoder/lookup.rb | 3 +- lib/geocoder/lookups/ipinfo_io.rb | 41 ++++++++++++++++++++++ lib/geocoder/results/ipinfo_io.rb | 56 ++++++++++++++++++++++++++++++ test/fixtures/ipinfo_io_8_8_8_8 | 8 +++++ test/fixtures/ipinfo_io_no_results | 0 test/test_helper.rb | 9 +++++ test/unit/lookup_test.rb | 2 +- 8 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 lib/geocoder/lookups/ipinfo_io.rb create mode 100644 lib/geocoder/results/ipinfo_io.rb create mode 100644 test/fixtures/ipinfo_io_8_8_8_8 create mode 100644 test/fixtures/ipinfo_io_no_results diff --git a/README.md b/README.md index a71dd671..92cfbc28 100644 --- a/README.md +++ b/README.md @@ -749,6 +749,15 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string * **Limitations**: ? * **Notes**: You must specify which MaxMind service you are using in your configuration, and also basic authentication. For example: `Geocoder.configure(:maxmind_geoip2 => {:service => :country, :basic_auth => {:user => '', :password => ''}})`. +#### IPInfo.io (`:ipinfo_io`) + +* **API key**: optional - see http://ipinfo.io/pricing +* **Quota**: 1,000/day - more with api key +* **Region**: world +* **SSL support**: no (not without access key - see http://ipinfo.io/pricing) +* **Languages**: English +* **Documentation**: http://ipinfo.io/developers +* **Terms of Service**: http://ipinfo.io/developers ### IP Address Local Database Services diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb index 92d5a50b..962f5a79 100644 --- a/lib/geocoder/lookup.rb +++ b/lib/geocoder/lookup.rb @@ -62,7 +62,8 @@ module Geocoder :maxmind_local, :telize, :pointpin, - :maxmind_geoip2 + :maxmind_geoip2, + :ipinfo_io ] end diff --git a/lib/geocoder/lookups/ipinfo_io.rb b/lib/geocoder/lookups/ipinfo_io.rb new file mode 100644 index 00000000..22efcbef --- /dev/null +++ b/lib/geocoder/lookups/ipinfo_io.rb @@ -0,0 +1,41 @@ +require 'geocoder/lookups/base' +require 'geocoder/results/ipinfo_io' + +module Geocoder::Lookup + class IpinfoIo < Base + + def name + "Ipinfo.io" + end + + def query_url(query) + "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo" + end + + # currently doesn't support HTTPS + def supported_protocols + [:http] + end + + private # --------------------------------------------------------------- + + def results(query) + # don't look up a loopback address, just return the stored result + return [reserved_result(query.text)] if query.loopback_ip_address? + if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc) + [] + else + [doc] + end + end + + def empty_result?(doc) + !doc.is_a?(Hash) or doc.keys == ["ip"] + end + + def reserved_result(ip) + {"message" => "Input string is not a valid IP address", "code" => 401} + end + + end +end diff --git a/lib/geocoder/results/ipinfo_io.rb b/lib/geocoder/results/ipinfo_io.rb new file mode 100644 index 00000000..4968a498 --- /dev/null +++ b/lib/geocoder/results/ipinfo_io.rb @@ -0,0 +1,56 @@ +require 'geocoder/results/base' + +module Geocoder::Result + class IpinfoIo < Base + + def address(format = :full) + "#{city} #{postal_code}, #{country}".sub(/^[ ,]*/, "") + end + + def latitude + @data['loc'].split(',')[0].to_f + end + + def longitude + @data['loc'].split(',')[1].to_f + end + + def coordinates + [@data['loc'].split(',')[0].to_f, @data['loc'].split(',')[1].to_f] + end + + def city + @data['city'] + end + + def state + @data['region'] + end + + def country + @data['country'] + end + + def postal_code + @data['postal'] + end + + def country_code + @data.fetch('country', '') + end + + def state_code + @data.fetch('region_code', '') + end + + def self.response_attributes + %w['ip', 'city', 'region', 'country', 'latitude', 'longitude', 'postal_code'] + end + + response_attributes.each do |a| + define_method a do + @data[a] + end + end + end +end diff --git a/test/fixtures/ipinfo_io_8_8_8_8 b/test/fixtures/ipinfo_io_8_8_8_8 new file mode 100644 index 00000000..7d213307 --- /dev/null +++ b/test/fixtures/ipinfo_io_8_8_8_8 @@ -0,0 +1,8 @@ +{ + "ip": "8.8.8.8", + "city": "Mountain View", + "region": "California", + "country": "US", + "loc": "37.3845,-122.0881", + "postal": "94040" +} diff --git a/test/fixtures/ipinfo_io_no_results b/test/fixtures/ipinfo_io_no_results new file mode 100644 index 00000000..e69de29b diff --git a/test/test_helper.rb b/test/test_helper.rb index 973bd083..73c9cac4 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -320,6 +320,15 @@ module Geocoder "latlon_6000_universal_blvd" end end + + require 'geocoder/lookups/ipinfo_io' + class IpinfoIo + private + def default_fixture_filename + "ipinfo_io_8_8_8_8" + end + end + end end diff --git a/test/unit/lookup_test.rb b/test/unit/lookup_test.rb index 1fba832a..002c6a84 100644 --- a/test/unit/lookup_test.rb +++ b/test/unit/lookup_test.rb @@ -24,7 +24,7 @@ class LookupTest < GeocoderTestCase def test_query_url_contains_values_in_params_hash Geocoder::Lookup.all_services_except_test.each do |l| - next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox].include? l # does not use query string + next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox, :ipinfo_io].include? l # does not use query string set_api_key!(l) url = Geocoder::Lookup.get(l).query_url(Geocoder::Query.new( "test", :params => {:one_in_the_hand => "two in the bush"} -- GitLab