geocoder 1.4.3 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -0
- data/README.md +364 -880
- data/examples/autoexpire_cache_redis.rb +3 -3
- data/lib/generators/geocoder/config/templates/initializer.rb +3 -2
- data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
- data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
- data/lib/generators/geocoder/migration_version.rb +15 -0
- data/lib/geocoder/cache.rb +6 -2
- data/lib/geocoder/cli.rb +2 -2
- data/lib/geocoder/configuration.rb +2 -2
- data/lib/geocoder/exceptions.rb +1 -1
- data/lib/geocoder/ip_address.rb +1 -1
- data/lib/geocoder/lookup.rb +9 -4
- data/lib/geocoder/lookups/amap.rb +63 -0
- data/lib/geocoder/lookups/baidu.rb +14 -10
- data/lib/geocoder/lookups/baidu_ip.rb +6 -35
- data/lib/geocoder/lookups/ban_data_gouv_fr.rb +4 -4
- data/lib/geocoder/lookups/base.rb +22 -4
- data/lib/geocoder/lookups/bing.rb +13 -12
- data/lib/geocoder/lookups/db_ip_com.rb +52 -0
- data/lib/geocoder/lookups/dstk.rb +4 -2
- data/lib/geocoder/lookups/esri.rb +1 -16
- data/lib/geocoder/lookups/freegeoip.rb +11 -2
- data/lib/geocoder/lookups/geocoder_ca.rb +4 -4
- data/lib/geocoder/lookups/geocoder_us.rb +17 -9
- data/lib/geocoder/lookups/geocodio.rb +5 -5
- data/lib/geocoder/lookups/geoportail_lu.rb +7 -7
- data/lib/geocoder/lookups/google.rb +13 -9
- data/lib/geocoder/lookups/google_places_details.rb +4 -4
- data/lib/geocoder/lookups/google_places_search.rb +4 -4
- data/lib/geocoder/lookups/google_premier.rb +11 -1
- data/lib/geocoder/lookups/here.rb +4 -4
- data/lib/geocoder/lookups/ip2location.rb +74 -0
- data/lib/geocoder/lookups/ipapi_com.rb +7 -12
- data/lib/geocoder/lookups/ipdata_co.rb +61 -0
- data/lib/geocoder/lookups/ipinfo_io.rb +10 -19
- data/lib/geocoder/lookups/ipstack.rb +63 -0
- data/lib/geocoder/lookups/latlon.rb +4 -4
- data/lib/geocoder/lookups/location_iq.rb +26 -8
- data/lib/geocoder/lookups/mapbox.rb +12 -6
- data/lib/geocoder/lookups/mapquest.rb +4 -5
- data/lib/geocoder/lookups/maxmind.rb +4 -4
- data/lib/geocoder/lookups/maxmind_geoip2.rb +4 -0
- data/lib/geocoder/lookups/nominatim.rb +17 -5
- data/lib/geocoder/lookups/opencagedata.rb +7 -6
- data/lib/geocoder/lookups/pelias.rb +6 -6
- data/lib/geocoder/lookups/pickpoint.rb +41 -0
- data/lib/geocoder/lookups/pointpin.rb +7 -6
- data/lib/geocoder/lookups/postcode_anywhere_uk.rb +4 -5
- data/lib/geocoder/lookups/postcodes_io.rb +31 -0
- data/lib/geocoder/lookups/smarty_streets.rb +8 -8
- data/lib/geocoder/lookups/telize.rb +24 -4
- data/lib/geocoder/lookups/yandex.rb +10 -6
- data/lib/geocoder/models/active_record.rb +4 -3
- data/lib/geocoder/request.rb +32 -0
- data/lib/geocoder/results/amap.rb +87 -0
- data/lib/geocoder/results/baidu.rb +10 -10
- data/lib/geocoder/results/base.rb +13 -1
- data/lib/geocoder/results/bing.rb +1 -1
- data/lib/geocoder/results/db_ip_com.rb +58 -0
- data/lib/geocoder/results/freegeoip.rb +0 -5
- data/lib/geocoder/results/geocoder_ca.rb +3 -3
- data/lib/geocoder/results/geoip2.rb +24 -10
- data/lib/geocoder/results/geoportail_lu.rb +5 -3
- data/lib/geocoder/results/google.rb +16 -5
- data/lib/geocoder/results/here.rb +8 -0
- data/lib/geocoder/results/ip2location.rb +22 -0
- data/lib/geocoder/results/ipdata_co.rb +40 -0
- data/lib/geocoder/results/ipstack.rb +60 -0
- data/lib/geocoder/results/maxmind.rb +0 -5
- data/lib/geocoder/results/maxmind_local.rb +0 -5
- data/lib/geocoder/results/nominatim.rb +12 -0
- data/lib/geocoder/results/opencagedata.rb +12 -2
- data/lib/geocoder/results/pickpoint.rb +6 -0
- data/lib/geocoder/results/postcodes_io.rb +40 -0
- data/lib/geocoder/results/smarty_streets.rb +7 -1
- data/lib/geocoder/results/telize.rb +0 -5
- data/lib/geocoder/results/test.rb +1 -1
- data/lib/geocoder/sql.rb +2 -2
- data/lib/geocoder/stores/active_record.rb +15 -4
- data/lib/geocoder/stores/base.rb +1 -2
- data/lib/geocoder/version.rb +1 -1
- data/lib/tasks/geocoder.rake +11 -3
- metadata +27 -10
- data/lib/geocoder/lookups/okf.rb +0 -44
- data/lib/geocoder/lookups/ovi.rb +0 -62
- data/lib/geocoder/results/okf.rb +0 -106
- data/lib/geocoder/results/ovi.rb +0 -71
|
@@ -8,20 +8,28 @@ module Geocoder::Lookup
|
|
|
8
8
|
"Geocoder.us"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
def supported_protocols
|
|
12
|
+
[:http]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private # ----------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
def base_query_url(query)
|
|
18
|
+
base_query_url_with_optional_key(configuration.api_key)
|
|
19
|
+
end
|
|
14
20
|
|
|
15
|
-
def
|
|
21
|
+
def cache_key(query)
|
|
22
|
+
base_query_url_with_optional_key(nil) + url_query_string(query)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def base_query_url_with_optional_key(key = nil)
|
|
26
|
+
base = "#{protocol}://"
|
|
16
27
|
if configuration.api_key
|
|
17
|
-
"#{
|
|
18
|
-
else
|
|
19
|
-
"#{protocol}://geocoder.us/service/csv/geocode?" + url_query_string(query)
|
|
28
|
+
base << "#{configuration.api_key}@"
|
|
20
29
|
end
|
|
30
|
+
base + "geocoder.us/member/service/csv/geocode?"
|
|
21
31
|
end
|
|
22
32
|
|
|
23
|
-
private
|
|
24
|
-
|
|
25
33
|
def results(query)
|
|
26
34
|
return [] unless doc = fetch_data(query)
|
|
27
35
|
if doc[0].to_s =~ /^(\d+)\:/
|
|
@@ -8,11 +8,6 @@ module Geocoder::Lookup
|
|
|
8
8
|
"Geocodio"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def query_url(query)
|
|
12
|
-
path = query.reverse_geocode? ? "reverse" : "geocode"
|
|
13
|
-
"#{protocol}://api.geocod.io/v1/#{path}?#{url_query_string(query)}"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
11
|
def results(query)
|
|
17
12
|
return [] unless doc = fetch_data(query)
|
|
18
13
|
return doc["results"] if doc['error'].nil?
|
|
@@ -32,6 +27,11 @@ module Geocoder::Lookup
|
|
|
32
27
|
|
|
33
28
|
private # ---------------------------------------------------------------
|
|
34
29
|
|
|
30
|
+
def base_query_url(query)
|
|
31
|
+
path = query.reverse_geocode? ? "reverse" : "geocode"
|
|
32
|
+
"#{protocol}://api.geocod.io/v1.3/#{path}?"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
35
|
def query_url_params(query)
|
|
36
36
|
{
|
|
37
37
|
:api_key => configuration.api_key,
|
|
@@ -9,14 +9,14 @@ module Geocoder
|
|
|
9
9
|
"Geoportail.lu"
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
url_base_path(query) + url_query_string(query)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private
|
|
12
|
+
private # ---------------------------------------------------------------
|
|
17
13
|
|
|
18
|
-
def
|
|
19
|
-
query.reverse_geocode?
|
|
14
|
+
def base_query_url(query)
|
|
15
|
+
if query.reverse_geocode?
|
|
16
|
+
reverse_geocode_url_base_path
|
|
17
|
+
else
|
|
18
|
+
search_url_base_path
|
|
19
|
+
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def search_url_base_path
|
|
@@ -21,12 +21,12 @@ module Geocoder::Lookup
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def query_url(query)
|
|
25
|
-
"#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
24
|
private # ---------------------------------------------------------------
|
|
29
25
|
|
|
26
|
+
def base_query_url(query)
|
|
27
|
+
"#{protocol}://maps.googleapis.com/maps/api/geocode/json?"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
30
|
def configure_ssl!(client)
|
|
31
31
|
client.instance_eval {
|
|
32
32
|
@ssl_context = OpenSSL::SSL::SSLContext.new
|
|
@@ -52,21 +52,25 @@ module Geocoder::Lookup
|
|
|
52
52
|
raise_error(Geocoder::OverQueryLimitError) ||
|
|
53
53
|
Geocoder.log(:warn, "#{name} API error: over query limit.")
|
|
54
54
|
when "REQUEST_DENIED"
|
|
55
|
-
raise_error(Geocoder::RequestDenied) ||
|
|
56
|
-
Geocoder.log(:warn, "#{name} API error: request denied.")
|
|
55
|
+
raise_error(Geocoder::RequestDenied, doc['error_message']) ||
|
|
56
|
+
Geocoder.log(:warn, "#{name} API error: request denied (#{doc['error_message']}).")
|
|
57
57
|
when "INVALID_REQUEST"
|
|
58
|
-
raise_error(Geocoder::InvalidRequest) ||
|
|
59
|
-
Geocoder.log(:warn, "#{name} API error: invalid request.")
|
|
58
|
+
raise_error(Geocoder::InvalidRequest, doc['error_message']) ||
|
|
59
|
+
Geocoder.log(:warn, "#{name} API error: invalid request (#{doc['error_message']}).")
|
|
60
60
|
end
|
|
61
61
|
return []
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def query_url_google_params(query)
|
|
65
65
|
params = {
|
|
66
|
-
(query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
|
|
67
66
|
:sensor => "false",
|
|
68
67
|
:language => (query.language || configuration.language)
|
|
69
68
|
}
|
|
69
|
+
if query.options[:google_place_id]
|
|
70
|
+
params[:place_id] = query.sanitized_text
|
|
71
|
+
else
|
|
72
|
+
params[(query.reverse_geocode? ? :latlng : :address)] = query.sanitized_text
|
|
73
|
+
end
|
|
70
74
|
unless (bounds = query.options[:bounds]).nil?
|
|
71
75
|
params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
|
|
72
76
|
end
|
|
@@ -16,12 +16,12 @@ module Geocoder
|
|
|
16
16
|
[:https]
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def query_url(query)
|
|
20
|
-
"#{protocol}://maps.googleapis.com/maps/api/place/details/json?#{url_query_string(query)}"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
19
|
private
|
|
24
20
|
|
|
21
|
+
def base_query_url(query)
|
|
22
|
+
"#{protocol}://maps.googleapis.com/maps/api/place/details/json?"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
25
|
def results(query)
|
|
26
26
|
return [] unless doc = fetch_data(query)
|
|
27
27
|
|
|
@@ -16,12 +16,12 @@ module Geocoder
|
|
|
16
16
|
[:https]
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def query_url(query)
|
|
20
|
-
"#{protocol}://maps.googleapis.com/maps/api/place/textsearch/json?#{url_query_string(query)}"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
19
|
private
|
|
24
20
|
|
|
21
|
+
def base_query_url(query)
|
|
22
|
+
"#{protocol}://maps.googleapis.com/maps/api/place/textsearch/json?"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
25
|
def query_url_google_params(query)
|
|
26
26
|
{
|
|
27
27
|
query: query.text,
|
|
@@ -11,7 +11,7 @@ module Geocoder::Lookup
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def required_api_key_parts
|
|
14
|
-
["private key"
|
|
14
|
+
["private key"]
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def query_url(query)
|
|
@@ -21,6 +21,16 @@ module Geocoder::Lookup
|
|
|
21
21
|
|
|
22
22
|
private # ---------------------------------------------------------------
|
|
23
23
|
|
|
24
|
+
def cache_key(query)
|
|
25
|
+
"#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(cache_key_params(query))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def cache_key_params(query)
|
|
29
|
+
query_url_google_params(query).merge(super).reject do |k,v|
|
|
30
|
+
[:key, :client, :channel].include?(k)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
24
34
|
def query_url_params(query)
|
|
25
35
|
query_url_google_params(query).merge(super).merge(
|
|
26
36
|
:key => nil, # don't use param inherited from Google lookup
|
|
@@ -12,12 +12,12 @@ module Geocoder::Lookup
|
|
|
12
12
|
["app_id", "app_code"]
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def query_url(query)
|
|
16
|
-
"#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?" + url_query_string(query)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
15
|
private # ---------------------------------------------------------------
|
|
20
16
|
|
|
17
|
+
def base_query_url(query)
|
|
18
|
+
"#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
21
|
def results(query)
|
|
22
22
|
return [] unless doc = fetch_data(query)
|
|
23
23
|
return [] unless doc['Response'] && doc['Response']['View']
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'geocoder/lookups/base'
|
|
2
|
+
require 'geocoder/results/ip2location'
|
|
3
|
+
|
|
4
|
+
module Geocoder::Lookup
|
|
5
|
+
class Ip2location < Base
|
|
6
|
+
|
|
7
|
+
def name
|
|
8
|
+
"IP2LocationApi"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def supported_protocols
|
|
12
|
+
[:http, :https]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private # ----------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
def base_query_url(query)
|
|
18
|
+
"#{protocol}://api.ip2location.com/?"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def query_url_params(query)
|
|
22
|
+
{
|
|
23
|
+
key: configuration.api_key ? configuration.api_key : "demo",
|
|
24
|
+
format: "json",
|
|
25
|
+
ip: query.sanitized_text
|
|
26
|
+
}.merge(super)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def results(query)
|
|
30
|
+
return [reserved_result(query.text)] if query.loopback_ip_address?
|
|
31
|
+
return [] unless doc = fetch_data(query)
|
|
32
|
+
if doc["response"] == "INVALID ACCOUNT"
|
|
33
|
+
raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "INVALID ACCOUNT")
|
|
34
|
+
return []
|
|
35
|
+
else
|
|
36
|
+
return [doc]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reserved_result(query)
|
|
41
|
+
{
|
|
42
|
+
"country_code" => "INVALID IP ADDRESS",
|
|
43
|
+
"country_name" => "INVALID IP ADDRESS",
|
|
44
|
+
"region_name" => "INVALID IP ADDRESS",
|
|
45
|
+
"city_name" => "INVALID IP ADDRESS",
|
|
46
|
+
"latitude" => "INVALID IP ADDRESS",
|
|
47
|
+
"longitude" => "INVALID IP ADDRESS",
|
|
48
|
+
"zip_code" => "INVALID IP ADDRESS",
|
|
49
|
+
"time_zone" => "INVALID IP ADDRESS",
|
|
50
|
+
"isp" => "INVALID IP ADDRESS",
|
|
51
|
+
"domain" => "INVALID IP ADDRESS",
|
|
52
|
+
"net_speed" => "INVALID IP ADDRESS",
|
|
53
|
+
"idd_code" => "INVALID IP ADDRESS",
|
|
54
|
+
"area_code" => "INVALID IP ADDRESS",
|
|
55
|
+
"weather_station_code" => "INVALID IP ADDRESS",
|
|
56
|
+
"weather_station_name" => "INVALID IP ADDRESS",
|
|
57
|
+
"mcc" => "INVALID IP ADDRESS",
|
|
58
|
+
"mnc" => "INVALID IP ADDRESS",
|
|
59
|
+
"mobile_brand" => "INVALID IP ADDRESS",
|
|
60
|
+
"elevation" => "INVALID IP ADDRESS",
|
|
61
|
+
"usage_type" => "INVALID IP ADDRESS"
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def query_url_params(query)
|
|
66
|
+
params = super
|
|
67
|
+
if configuration.has_key?(:package)
|
|
68
|
+
params.merge!(package: configuration[:package])
|
|
69
|
+
end
|
|
70
|
+
params
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -8,17 +8,6 @@ module Geocoder::Lookup
|
|
|
8
8
|
"ip-api.com"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def query_url(query)
|
|
12
|
-
domain = configuration.api_key ? "pro.ip-api.com" : "ip-api.com"
|
|
13
|
-
url_ = "#{protocol}://#{domain}/json/#{query.sanitized_text}"
|
|
14
|
-
|
|
15
|
-
if (params = url_query_string(query)) && !params.empty?
|
|
16
|
-
url_ + "?" + params
|
|
17
|
-
else
|
|
18
|
-
url_
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
11
|
def supported_protocols
|
|
23
12
|
if configuration.api_key
|
|
24
13
|
[:http, :https]
|
|
@@ -27,8 +16,14 @@ module Geocoder::Lookup
|
|
|
27
16
|
end
|
|
28
17
|
end
|
|
29
18
|
|
|
19
|
+
private # ----------------------------------------------------------------
|
|
30
20
|
|
|
31
|
-
|
|
21
|
+
def base_query_url(query)
|
|
22
|
+
domain = configuration.api_key ? "pro.ip-api.com" : "ip-api.com"
|
|
23
|
+
url = "#{protocol}://#{domain}/json/#{query.sanitized_text}"
|
|
24
|
+
url << "?" if not url_query_string(query).empty?
|
|
25
|
+
url
|
|
26
|
+
end
|
|
32
27
|
|
|
33
28
|
def parse_raw_data(raw_data)
|
|
34
29
|
if raw_data.chomp == "invalid key"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'geocoder/lookups/base'
|
|
2
|
+
require 'geocoder/results/ipdata_co'
|
|
3
|
+
|
|
4
|
+
module Geocoder::Lookup
|
|
5
|
+
class IpdataCo < Base
|
|
6
|
+
|
|
7
|
+
def name
|
|
8
|
+
"ipdata.co"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def supported_protocols
|
|
12
|
+
[:https]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def query_url(query)
|
|
16
|
+
"#{protocol}://#{host}/#{query.sanitized_text}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private # ---------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
def cache_key(query)
|
|
22
|
+
query_url(query)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def results(query)
|
|
26
|
+
Geocoder.configure(:ipdata_co => {:http_headers => { "api-key" => configuration.api_key }}) if configuration.api_key
|
|
27
|
+
# don't look up a loopback address, just return the stored result
|
|
28
|
+
return [reserved_result(query.text)] if query.loopback_ip_address?
|
|
29
|
+
# note: Ipdata.co returns plain text on bad request
|
|
30
|
+
(doc = fetch_data(query)) ? [doc] : []
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def reserved_result(ip)
|
|
34
|
+
{
|
|
35
|
+
"ip" => ip,
|
|
36
|
+
"city" => "",
|
|
37
|
+
"region_code" => "",
|
|
38
|
+
"region_name" => "",
|
|
39
|
+
"metrocode" => "",
|
|
40
|
+
"zipcode" => "",
|
|
41
|
+
"latitude" => "0",
|
|
42
|
+
"longitude" => "0",
|
|
43
|
+
"country_name" => "Reserved",
|
|
44
|
+
"country_code" => "RD"
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def host
|
|
49
|
+
"api.ipdata.co"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def check_response_for_errors!(response)
|
|
53
|
+
if response.code.to_i == 403
|
|
54
|
+
raise_error(Geocoder::RequestDenied) ||
|
|
55
|
+
Geocoder.log(:warn, "Geocoding API error: 403 API key does not exist")
|
|
56
|
+
else
|
|
57
|
+
super(response)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -8,14 +8,6 @@ module Geocoder::Lookup
|
|
|
8
8
|
"Ipinfo.io"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def query_url(query)
|
|
12
|
-
if configuration.api_key
|
|
13
|
-
"#{protocol}://ipinfo.io/#{query.sanitized_text}/geo?" + url_query_string(query)
|
|
14
|
-
else
|
|
15
|
-
"#{protocol}://ipinfo.io/#{query.sanitized_text}/geo"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
11
|
# HTTPS available only for paid plans
|
|
20
12
|
def supported_protocols
|
|
21
13
|
if configuration.api_key
|
|
@@ -27,28 +19,27 @@ module Geocoder::Lookup
|
|
|
27
19
|
|
|
28
20
|
private # ---------------------------------------------------------------
|
|
29
21
|
|
|
22
|
+
def base_query_url(query)
|
|
23
|
+
url = "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo"
|
|
24
|
+
url << "?" if configuration.api_key
|
|
25
|
+
url
|
|
26
|
+
end
|
|
27
|
+
|
|
30
28
|
def results(query)
|
|
31
29
|
# don't look up a loopback address, just return the stored result
|
|
32
30
|
return [reserved_result(query.text)] if query.loopback_ip_address?
|
|
33
|
-
|
|
31
|
+
|
|
32
|
+
if !(doc = fetch_data(query)).is_a?(Hash) or doc['error']
|
|
34
33
|
[]
|
|
35
34
|
else
|
|
36
35
|
[doc]
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
38
|
|
|
40
|
-
def empty_result?(doc)
|
|
41
|
-
!doc.is_a?(Hash) or doc.keys == ["ip"]
|
|
42
|
-
end
|
|
43
|
-
|
|
44
39
|
def reserved_result(ip)
|
|
45
40
|
{
|
|
46
|
-
"ip"
|
|
47
|
-
"
|
|
48
|
-
"region" => "",
|
|
49
|
-
"country" => "",
|
|
50
|
-
"loc" => "0,0",
|
|
51
|
-
"postal" => ""
|
|
41
|
+
"ip" => ip,
|
|
42
|
+
"bogon" => true
|
|
52
43
|
}
|
|
53
44
|
end
|
|
54
45
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'geocoder/lookups/base'
|
|
2
|
+
require 'geocoder/results/ipstack'
|
|
3
|
+
|
|
4
|
+
module Geocoder::Lookup
|
|
5
|
+
class Ipstack < Base
|
|
6
|
+
|
|
7
|
+
ERROR_CODES = {
|
|
8
|
+
404 => Geocoder::InvalidRequest,
|
|
9
|
+
101 => Geocoder::InvalidApiKey,
|
|
10
|
+
102 => Geocoder::Error,
|
|
11
|
+
103 => Geocoder::InvalidRequest,
|
|
12
|
+
104 => Geocoder::OverQueryLimitError,
|
|
13
|
+
105 => Geocoder::RequestDenied,
|
|
14
|
+
301 => Geocoder::InvalidRequest,
|
|
15
|
+
302 => Geocoder::InvalidRequest,
|
|
16
|
+
303 => Geocoder::RequestDenied,
|
|
17
|
+
}
|
|
18
|
+
ERROR_CODES.default = Geocoder::Error
|
|
19
|
+
|
|
20
|
+
def name
|
|
21
|
+
"Ipstack"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private # ----------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
def base_query_url(query)
|
|
27
|
+
"#{protocol}://#{host}/#{query.sanitized_text}?"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def query_url_params(query)
|
|
31
|
+
{
|
|
32
|
+
access_key: configuration.api_key
|
|
33
|
+
}.merge(super)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def results(query)
|
|
37
|
+
# don't look up a loopback address, just return the stored result
|
|
38
|
+
return [reserved_result(query.text)] if query.loopback_ip_address?
|
|
39
|
+
|
|
40
|
+
return [] unless doc = fetch_data(query)
|
|
41
|
+
|
|
42
|
+
if error = doc['error']
|
|
43
|
+
code = error['code']
|
|
44
|
+
msg = error['info']
|
|
45
|
+
raise_error(ERROR_CODES[code], msg ) || Geocoder.log(:warn, "Ipstack Geocoding API error: #{msg}")
|
|
46
|
+
return []
|
|
47
|
+
end
|
|
48
|
+
[doc]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def reserved_result(ip)
|
|
52
|
+
{
|
|
53
|
+
"ip" => ip,
|
|
54
|
+
"country_name" => "Reserved",
|
|
55
|
+
"country_code" => "RD"
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def host
|
|
60
|
+
configuration[:host] || "api.ipstack.com"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -12,12 +12,12 @@ module Geocoder::Lookup
|
|
|
12
12
|
["api_key"]
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def query_url(query)
|
|
16
|
-
"#{protocol}://latlon.io/api/v1/#{'reverse_' if query.reverse_geocode?}geocode?#{url_query_string(query)}"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
15
|
private # ---------------------------------------------------------------
|
|
20
16
|
|
|
17
|
+
def base_query_url(query)
|
|
18
|
+
"#{protocol}://latlon.io/api/v1/#{'reverse_' if query.reverse_geocode?}geocode?"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
21
|
def results(query)
|
|
22
22
|
return [] unless doc = fetch_data(query)
|
|
23
23
|
if doc['error'].nil?
|
|
@@ -10,20 +10,38 @@ module Geocoder::Lookup
|
|
|
10
10
|
def required_api_key_parts
|
|
11
11
|
["api_key"]
|
|
12
12
|
end
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
|
|
14
|
+
private # ----------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
def base_query_url(query)
|
|
17
|
+
method = query.reverse_geocode? ? "reverse" : "search"
|
|
18
|
+
"#{protocol}://#{configured_host}/v1/#{method}.php?"
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
def query_url_params(query)
|
|
22
|
+
{
|
|
23
|
+
key: configuration.api_key
|
|
24
|
+
}.merge(super)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def configured_host
|
|
28
|
+
configuration[:host] || "locationiq.org"
|
|
29
|
+
end
|
|
21
30
|
|
|
22
31
|
def results(query)
|
|
23
32
|
return [] unless doc = fetch_data(query)
|
|
24
33
|
|
|
25
|
-
if !doc.is_a?(Array)
|
|
26
|
-
|
|
34
|
+
if !doc.is_a?(Array)
|
|
35
|
+
case doc['error']
|
|
36
|
+
when "Invalid key"
|
|
37
|
+
raise_error(Geocoder::InvalidApiKey, doc['error'])
|
|
38
|
+
when "Key not active - Please write to contact@unwiredlabs.com"
|
|
39
|
+
raise_error(Geocoder::RequestDenied, doc['error'])
|
|
40
|
+
when "Rate Limited"
|
|
41
|
+
raise_error(Geocoder::OverQueryLimitError, doc['error'])
|
|
42
|
+
when "Unknown error - Please try again after some time"
|
|
43
|
+
raise_error(Geocoder::InvalidRequest, doc['error'])
|
|
44
|
+
end
|
|
27
45
|
end
|
|
28
46
|
|
|
29
47
|
doc.is_a?(Array) ? doc : [doc]
|
|
@@ -8,12 +8,12 @@ module Geocoder::Lookup
|
|
|
8
8
|
"Mapbox"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def query_url(query)
|
|
12
|
-
"#{protocol}://api.mapbox.com/geocoding/v5/#{dataset}/#{url_query_string(query)}.json?access_token=#{configuration.api_key}"
|
|
13
|
-
end
|
|
14
|
-
|
|
15
11
|
private # ---------------------------------------------------------------
|
|
16
12
|
|
|
13
|
+
def base_query_url(query)
|
|
14
|
+
"#{protocol}://api.mapbox.com/geocoding/v5/#{dataset}/#{mapbox_search_term(query)}.json?"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
17
|
def results(query)
|
|
18
18
|
return [] unless data = fetch_data(query)
|
|
19
19
|
if data['features']
|
|
@@ -25,13 +25,19 @@ module Geocoder::Lookup
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def
|
|
28
|
+
def query_url_params(query)
|
|
29
|
+
{access_token: configuration.api_key}.merge(super(query))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def mapbox_search_term(query)
|
|
29
33
|
require 'cgi' unless defined?(CGI) && defined?(CGI.escape)
|
|
30
34
|
if query.reverse_geocode?
|
|
31
35
|
lat,lon = query.coordinates
|
|
32
36
|
"#{CGI.escape lon},#{CGI.escape lat}"
|
|
33
37
|
else
|
|
34
|
-
|
|
38
|
+
# truncate at first semicolon so Mapbox doesn't go into batch mode
|
|
39
|
+
# (see Github issue #1299)
|
|
40
|
+
CGI.escape query.text.to_s.split(';').first.to_s
|
|
35
41
|
end
|
|
36
42
|
end
|
|
37
43
|
|
|
@@ -13,14 +13,13 @@ module Geocoder::Lookup
|
|
|
13
13
|
["key"]
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
private # ---------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
def base_query_url(query)
|
|
17
19
|
domain = configuration[:open] ? "open" : "www"
|
|
18
|
-
|
|
19
|
-
url + url_query_string(query)
|
|
20
|
+
"#{protocol}://#{domain}.mapquestapi.com/geocoding/v1/#{search_type(query)}?"
|
|
20
21
|
end
|
|
21
22
|
|
|
22
|
-
private # ---------------------------------------------------------------
|
|
23
|
-
|
|
24
23
|
def search_type(query)
|
|
25
24
|
query.reverse_geocode? ? "reverse" : "address"
|
|
26
25
|
end
|
|
@@ -9,12 +9,12 @@ module Geocoder::Lookup
|
|
|
9
9
|
"MaxMind"
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def query_url(query)
|
|
13
|
-
"#{protocol}://geoip.maxmind.com/#{service_code}?" + url_query_string(query)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
12
|
private # ---------------------------------------------------------------
|
|
17
13
|
|
|
14
|
+
def base_query_url(query)
|
|
15
|
+
"#{protocol}://geoip.maxmind.com/#{service_code}?"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
18
|
##
|
|
19
19
|
# Return the name of the configured service, or raise an exception.
|
|
20
20
|
#
|