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