geocoder 1.1.9 → 1.8.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.
Files changed (238) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +309 -0
  3. data/LICENSE +1 -1
  4. data/README.md +544 -540
  5. data/bin/console +13 -0
  6. data/examples/app_defined_lookup_services.rb +22 -0
  7. data/examples/reverse_geocode_job.rb +40 -0
  8. data/lib/easting_northing.rb +171 -0
  9. data/lib/generators/geocoder/config/templates/initializer.rb +22 -16
  10. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +30 -0
  11. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +30 -0
  12. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +30 -0
  13. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
  14. data/lib/generators/geocoder/migration_version.rb +15 -0
  15. data/lib/geocoder/cache.rb +20 -32
  16. data/lib/geocoder/cache_stores/base.rb +40 -0
  17. data/lib/geocoder/cache_stores/generic.rb +35 -0
  18. data/lib/geocoder/cache_stores/redis.rb +34 -0
  19. data/lib/geocoder/calculations.rb +67 -36
  20. data/lib/geocoder/cli.rb +2 -2
  21. data/lib/geocoder/configuration.rb +33 -16
  22. data/lib/geocoder/configuration_hash.rb +4 -4
  23. data/lib/geocoder/esri_token.rb +38 -0
  24. data/lib/geocoder/exceptions.rb +19 -0
  25. data/lib/geocoder/ip_address.rb +33 -0
  26. data/lib/geocoder/kernel_logger.rb +25 -0
  27. data/lib/geocoder/logger.rb +47 -0
  28. data/lib/geocoder/lookup.rb +74 -11
  29. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  30. data/lib/geocoder/lookups/amap.rb +63 -0
  31. data/lib/geocoder/lookups/amazon_location_service.rb +54 -0
  32. data/lib/geocoder/lookups/baidu.rb +24 -15
  33. data/lib/geocoder/lookups/baidu_ip.rb +30 -0
  34. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
  35. data/lib/geocoder/lookups/base.rb +109 -23
  36. data/lib/geocoder/lookups/bing.rb +45 -10
  37. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  38. data/lib/geocoder/lookups/dstk.rb +4 -2
  39. data/lib/geocoder/lookups/esri.rb +61 -8
  40. data/lib/geocoder/lookups/freegeoip.rb +25 -6
  41. data/lib/geocoder/lookups/geoapify.rb +72 -0
  42. data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
  43. data/lib/geocoder/lookups/geocodio.rb +42 -0
  44. data/lib/geocoder/lookups/geoip2.rb +49 -0
  45. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  46. data/lib/geocoder/lookups/google.rb +45 -12
  47. data/lib/geocoder/lookups/google_places_details.rb +64 -0
  48. data/lib/geocoder/lookups/google_places_search.rb +76 -0
  49. data/lib/geocoder/lookups/google_premier.rb +16 -2
  50. data/lib/geocoder/lookups/here.rb +73 -0
  51. data/lib/geocoder/lookups/ip2location.rb +71 -0
  52. data/lib/geocoder/lookups/ipapi_com.rb +82 -0
  53. data/lib/geocoder/lookups/ipdata_co.rb +62 -0
  54. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  55. data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
  56. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  57. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  58. data/lib/geocoder/lookups/ipstack.rb +63 -0
  59. data/lib/geocoder/lookups/latlon.rb +58 -0
  60. data/lib/geocoder/lookups/location_iq.rb +54 -0
  61. data/lib/geocoder/lookups/mapbox.rb +59 -0
  62. data/lib/geocoder/lookups/mapquest.rb +9 -10
  63. data/lib/geocoder/lookups/maxmind.rb +10 -8
  64. data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
  65. data/lib/geocoder/lookups/maxmind_local.rb +71 -0
  66. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  67. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  68. data/lib/geocoder/lookups/nominatim.rb +26 -6
  69. data/lib/geocoder/lookups/opencagedata.rb +65 -0
  70. data/lib/geocoder/lookups/osmnames.rb +57 -0
  71. data/lib/geocoder/lookups/pelias.rb +63 -0
  72. data/lib/geocoder/lookups/photon.rb +89 -0
  73. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  74. data/lib/geocoder/lookups/pointpin.rb +69 -0
  75. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +50 -0
  76. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  77. data/lib/geocoder/lookups/smarty_streets.rb +68 -0
  78. data/lib/geocoder/lookups/telize.rb +75 -0
  79. data/lib/geocoder/lookups/tencent.rb +59 -0
  80. data/lib/geocoder/lookups/test.rb +4 -0
  81. data/lib/geocoder/lookups/twogis.rb +58 -0
  82. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  83. data/lib/geocoder/lookups/yandex.rb +18 -11
  84. data/lib/geocoder/models/active_record.rb +9 -4
  85. data/lib/geocoder/models/base.rb +1 -4
  86. data/lib/geocoder/models/mongo_base.rb +6 -4
  87. data/lib/geocoder/query.rb +23 -5
  88. data/lib/geocoder/railtie.rb +2 -2
  89. data/lib/geocoder/request.rb +102 -11
  90. data/lib/geocoder/results/abstract_api.rb +146 -0
  91. data/lib/geocoder/results/amap.rb +87 -0
  92. data/lib/geocoder/results/amazon_location_service.rb +57 -0
  93. data/lib/geocoder/results/baidu.rb +10 -14
  94. data/lib/geocoder/results/baidu_ip.rb +62 -0
  95. data/lib/geocoder/results/ban_data_gouv_fr.rb +282 -0
  96. data/lib/geocoder/results/base.rb +13 -1
  97. data/lib/geocoder/results/bing.rb +5 -1
  98. data/lib/geocoder/results/db_ip_com.rb +58 -0
  99. data/lib/geocoder/results/esri.rb +35 -8
  100. data/lib/geocoder/results/freegeoip.rb +2 -7
  101. data/lib/geocoder/results/geoapify.rb +179 -0
  102. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  103. data/lib/geocoder/results/geocodio.rb +78 -0
  104. data/lib/geocoder/results/geoip2.rb +76 -0
  105. data/lib/geocoder/results/geoportail_lu.rb +71 -0
  106. data/lib/geocoder/results/google.rb +26 -0
  107. data/lib/geocoder/results/google_places_details.rb +39 -0
  108. data/lib/geocoder/results/google_places_search.rb +52 -0
  109. data/lib/geocoder/results/here.rb +77 -0
  110. data/lib/geocoder/results/ip2location.rb +22 -0
  111. data/lib/geocoder/results/ipapi_com.rb +45 -0
  112. data/lib/geocoder/results/ipdata_co.rb +40 -0
  113. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  114. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  115. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  116. data/lib/geocoder/results/ipregistry.rb +304 -0
  117. data/lib/geocoder/results/ipstack.rb +60 -0
  118. data/lib/geocoder/results/latlon.rb +71 -0
  119. data/lib/geocoder/results/location_iq.rb +6 -0
  120. data/lib/geocoder/results/mapbox.rb +63 -0
  121. data/lib/geocoder/results/mapquest.rb +5 -8
  122. data/lib/geocoder/results/maxmind.rb +0 -5
  123. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  124. data/lib/geocoder/results/maxmind_local.rb +44 -0
  125. data/lib/geocoder/results/melissa_street.rb +46 -0
  126. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  127. data/lib/geocoder/results/nominatim.rb +41 -14
  128. data/lib/geocoder/results/opencagedata.rb +100 -0
  129. data/lib/geocoder/results/osmnames.rb +56 -0
  130. data/lib/geocoder/results/pelias.rb +58 -0
  131. data/lib/geocoder/results/photon.rb +119 -0
  132. data/lib/geocoder/results/pickpoint.rb +6 -0
  133. data/lib/geocoder/results/pointpin.rb +40 -0
  134. data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
  135. data/lib/geocoder/results/postcodes_io.rb +40 -0
  136. data/lib/geocoder/results/smarty_streets.rb +142 -0
  137. data/lib/geocoder/results/telize.rb +40 -0
  138. data/lib/geocoder/results/tencent.rb +72 -0
  139. data/lib/geocoder/results/test.rb +20 -3
  140. data/lib/geocoder/results/twogis.rb +76 -0
  141. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  142. data/lib/geocoder/results/yandex.rb +244 -32
  143. data/lib/geocoder/sql.rb +25 -21
  144. data/lib/geocoder/stores/active_record.rb +82 -26
  145. data/lib/geocoder/stores/base.rb +9 -14
  146. data/lib/geocoder/stores/mongo_base.rb +0 -31
  147. data/lib/geocoder/util.rb +29 -0
  148. data/lib/geocoder/version.rb +1 -1
  149. data/lib/geocoder.rb +6 -13
  150. data/lib/maxmind_database.rb +109 -0
  151. data/lib/tasks/geocoder.rake +30 -3
  152. data/lib/tasks/maxmind.rake +73 -0
  153. metadata +115 -98
  154. data/.gitignore +0 -5
  155. data/.travis.yml +0 -27
  156. data/Rakefile +0 -25
  157. data/examples/autoexpire_cache_dalli.rb +0 -62
  158. data/examples/autoexpire_cache_redis.rb +0 -28
  159. data/gemfiles/Gemfile.mongoid-2.4.x +0 -15
  160. data/lib/geocoder/lookups/geocoder_us.rb +0 -39
  161. data/lib/geocoder/lookups/ovi.rb +0 -62
  162. data/lib/geocoder/lookups/yahoo.rb +0 -86
  163. data/lib/geocoder/results/geocoder_us.rb +0 -39
  164. data/lib/geocoder/results/ovi.rb +0 -62
  165. data/lib/geocoder/results/yahoo.rb +0 -55
  166. data/lib/hash_recursive_merge.rb +0 -74
  167. data/lib/oauth_util.rb +0 -112
  168. data/test/active_record_test.rb +0 -15
  169. data/test/cache_test.rb +0 -35
  170. data/test/calculations_test.rb +0 -211
  171. data/test/configuration_test.rb +0 -78
  172. data/test/custom_block_test.rb +0 -32
  173. data/test/error_handling_test.rb +0 -43
  174. data/test/fixtures/baidu_invalid_key +0 -1
  175. data/test/fixtures/baidu_no_results +0 -1
  176. data/test/fixtures/baidu_reverse +0 -1
  177. data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
  178. data/test/fixtures/bing_invalid_key +0 -1
  179. data/test/fixtures/bing_madison_square_garden +0 -40
  180. data/test/fixtures/bing_no_results +0 -16
  181. data/test/fixtures/bing_reverse +0 -42
  182. data/test/fixtures/esri_madison_square_garden +0 -59
  183. data/test/fixtures/esri_no_results +0 -8
  184. data/test/fixtures/esri_reverse +0 -21
  185. data/test/fixtures/freegeoip_74_200_247_59 +0 -12
  186. data/test/fixtures/freegeoip_no_results +0 -1
  187. data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
  188. data/test/fixtures/geocoder_ca_no_results +0 -1
  189. data/test/fixtures/geocoder_ca_reverse +0 -34
  190. data/test/fixtures/geocoder_us_madison_square_garden +0 -1
  191. data/test/fixtures/geocoder_us_no_results +0 -1
  192. data/test/fixtures/google_garbage +0 -456
  193. data/test/fixtures/google_madison_square_garden +0 -57
  194. data/test/fixtures/google_no_city_data +0 -44
  195. data/test/fixtures/google_no_locality +0 -51
  196. data/test/fixtures/google_no_results +0 -4
  197. data/test/fixtures/google_over_limit +0 -4
  198. data/test/fixtures/mapquest_error +0 -16
  199. data/test/fixtures/mapquest_invalid_api_key +0 -16
  200. data/test/fixtures/mapquest_invalid_request +0 -16
  201. data/test/fixtures/mapquest_madison_square_garden +0 -52
  202. data/test/fixtures/mapquest_no_results +0 -16
  203. data/test/fixtures/maxmind_24_24_24_21 +0 -1
  204. data/test/fixtures/maxmind_24_24_24_22 +0 -1
  205. data/test/fixtures/maxmind_24_24_24_23 +0 -1
  206. data/test/fixtures/maxmind_24_24_24_24 +0 -1
  207. data/test/fixtures/maxmind_74_200_247_59 +0 -1
  208. data/test/fixtures/maxmind_invalid_key +0 -1
  209. data/test/fixtures/maxmind_no_results +0 -1
  210. data/test/fixtures/nominatim_madison_square_garden +0 -150
  211. data/test/fixtures/nominatim_no_results +0 -1
  212. data/test/fixtures/ovi_madison_square_garden +0 -72
  213. data/test/fixtures/ovi_no_results +0 -8
  214. data/test/fixtures/yahoo_error +0 -1
  215. data/test/fixtures/yahoo_invalid_key +0 -2
  216. data/test/fixtures/yahoo_madison_square_garden +0 -52
  217. data/test/fixtures/yahoo_no_results +0 -10
  218. data/test/fixtures/yahoo_over_limit +0 -2
  219. data/test/fixtures/yandex_invalid_key +0 -1
  220. data/test/fixtures/yandex_kremlin +0 -48
  221. data/test/fixtures/yandex_no_city_and_town +0 -112
  222. data/test/fixtures/yandex_no_results +0 -16
  223. data/test/geocoder_test.rb +0 -59
  224. data/test/https_test.rb +0 -16
  225. data/test/integration/smoke_test.rb +0 -26
  226. data/test/lookup_test.rb +0 -117
  227. data/test/method_aliases_test.rb +0 -25
  228. data/test/mongoid_test.rb +0 -46
  229. data/test/mongoid_test_helper.rb +0 -43
  230. data/test/near_test.rb +0 -61
  231. data/test/oauth_util_test.rb +0 -30
  232. data/test/proxy_test.rb +0 -36
  233. data/test/query_test.rb +0 -52
  234. data/test/request_test.rb +0 -29
  235. data/test/result_test.rb +0 -42
  236. data/test/services_test.rb +0 -393
  237. data/test/test_helper.rb +0 -289
  238. data/test/test_mode_test.rb +0 -59
@@ -16,32 +16,67 @@ module Geocoder::Lookup
16
16
  ["key"]
17
17
  end
18
18
 
19
- def query_url(query)
20
- "#{protocol}://dev.virtualearth.net/REST/v1/Locations" +
21
- (query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?") +
22
- url_query_string(query)
23
- end
24
-
25
19
  private # ---------------------------------------------------------------
26
20
 
21
+ def base_query_url(query)
22
+ text = CGI.escape(query.sanitized_text.strip)
23
+ url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations/"
24
+ if query.reverse_geocode?
25
+ url + "#{text}?"
26
+ else
27
+ if r = query.options[:region]
28
+ url << "#{r}/"
29
+ end
30
+ # use the more forgiving 'unstructured' query format to allow special
31
+ # chars, newlines, brackets, typos.
32
+ url + "?q=#{text}&"
33
+ end
34
+ end
35
+
27
36
  def results(query)
28
37
  return [] unless doc = fetch_data(query)
29
38
 
30
39
  if doc['statusCode'] == 200
31
40
  return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : []
32
41
  elsif doc['statusCode'] == 401 and doc["authenticationResultCode"] == "InvalidCredentials"
33
- raise_error(Geocoder::InvalidApiKey) || warn("Invalid Bing API key.")
42
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid Bing API key.")
43
+ elsif doc['statusCode'] == 403
44
+ raise_error(Geocoder::RequestDenied) || Geocoder.log(:warn, "Bing Geocoding API error: Forbidden Request")
45
+ elsif [500, 503].include?(doc['statusCode'])
46
+ raise_error(Geocoder::ServiceUnavailable) ||
47
+ Geocoder.log(:warn, "Bing Geocoding API error: Service Unavailable")
34
48
  else
35
- warn "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']})."
49
+ Geocoder.log(:warn, "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']}).")
36
50
  end
37
51
  return []
38
52
  end
39
53
 
40
54
  def query_url_params(query)
41
55
  {
42
- :key => configuration.api_key,
43
- :query => query.reverse_geocode? ? nil : query.sanitized_text
56
+ key: configuration.api_key,
57
+ culture: (query.language || configuration.language)
44
58
  }.merge(super)
45
59
  end
60
+
61
+ def check_response_for_errors!(response)
62
+ super
63
+ if server_overloaded?(response)
64
+ raise_error(Geocoder::ServiceUnavailable) ||
65
+ Geocoder.log(:warn, "Bing Geocoding API error: Service Unavailable")
66
+ end
67
+ end
68
+
69
+ def valid_response?(response)
70
+ super(response) and not server_overloaded?(response)
71
+ end
72
+
73
+ def server_overloaded?(response)
74
+ # Occasionally, the servers processing service requests can be overloaded,
75
+ # and you may receive some responses that contain no results for queries that
76
+ # you would normally receive a result. To identify this situation,
77
+ # check the HTTP headers of the response. If the HTTP header X-MS-BM-WS-INFO is set to 1,
78
+ # it is best to wait a few seconds and try again.
79
+ response['x-ms-bm-ws-info'].to_i == 1
80
+ end
46
81
  end
47
82
  end
@@ -0,0 +1,52 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/db_ip_com'
3
+
4
+ module Geocoder::Lookup
5
+ class DbIpCom < Base
6
+
7
+ def name
8
+ 'DB-IP.com'
9
+ end
10
+
11
+ def supported_protocols
12
+ [:https, :http]
13
+ end
14
+
15
+ def required_api_key_parts
16
+ ['api_key']
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://api.db-ip.com/v2/#{configuration.api_key}/#{query.sanitized_text}?"
23
+ end
24
+
25
+ ##
26
+ # Same as query_url but without the api key.
27
+ #
28
+ def cache_key(query)
29
+ "#{protocol}://api.db-ip.com/v2/#{query.sanitized_text}?" + hash_to_query(cache_key_params(query))
30
+ end
31
+
32
+ def results(query)
33
+ return [] unless (doc = fetch_data(query))
34
+
35
+ case doc['error']
36
+ when 'maximum number of queries per day exceeded'
37
+ raise_error Geocoder::OverQueryLimitError ||
38
+ Geocoder.log(:warn, 'DB-API query limit exceeded.')
39
+
40
+ when 'invalid API key'
41
+ raise_error Geocoder::InvalidApiKey ||
42
+ Geocoder.log(:warn, 'Invalid DB-IP API key.')
43
+ when nil
44
+ [doc]
45
+
46
+ else
47
+ raise_error Geocoder::Error ||
48
+ Geocoder.log(:warn, "Request failed: #{doc['error']}")
49
+ end
50
+ end
51
+ end
52
+ end
@@ -12,9 +12,11 @@ module Geocoder::Lookup
12
12
  "Data Science Toolkit"
13
13
  end
14
14
 
15
- def query_url(query)
15
+ private # ----------------------------------------------------------------
16
+
17
+ def base_query_url(query)
16
18
  host = configuration[:host] || "www.datasciencetoolkit.org"
17
- "#{protocol}://#{host}/maps/api/geocode/json?" + url_query_string(query)
19
+ "#{protocol}://#{host}/maps/api/geocode/json?"
18
20
  end
19
21
  end
20
22
  end
@@ -1,27 +1,30 @@
1
1
  require 'geocoder/lookups/base'
2
2
  require "geocoder/results/esri"
3
+ require 'geocoder/esri_token'
3
4
 
4
5
  module Geocoder::Lookup
5
6
  class Esri < Base
6
-
7
+
7
8
  def name
8
9
  "Esri"
9
10
  end
10
11
 
11
- def query_url(query)
12
- search_keyword = query.reverse_geocode? ? "reverseGeocode" : "find"
13
-
14
- "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{search_keyword}?" +
15
- url_query_string(query)
16
- end
12
+ def supported_protocols
13
+ [:https]
14
+ end
17
15
 
18
16
  private # ---------------------------------------------------------------
19
17
 
18
+ def base_query_url(query)
19
+ action = query.reverse_geocode? ? "reverseGeocode" : "find"
20
+ "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{action}?"
21
+ end
22
+
20
23
  def results(query)
21
24
  return [] unless doc = fetch_data(query)
22
25
 
23
26
  if (!query.reverse_geocode?)
24
- return [] if doc['locations'].empty?
27
+ return [] if !doc['locations'] || doc['locations'].empty?
25
28
  end
26
29
 
27
30
  if (doc['error'].nil?)
@@ -41,8 +44,58 @@ module Geocoder::Lookup
41
44
  else
42
45
  params[:text] = query.sanitized_text
43
46
  end
47
+
48
+ params[:token] = token(query)
49
+
50
+ if for_storage_value = for_storage(query)
51
+ params[:forStorage] = for_storage_value
52
+ end
53
+ params[:sourceCountry] = configuration[:source_country] if configuration[:source_country]
54
+ params[:preferredLabelValues] = configuration[:preferred_label_values] if configuration[:preferred_label_values]
55
+
44
56
  params.merge(super)
45
57
  end
46
58
 
59
+ def for_storage(query)
60
+ if query.options.has_key?(:for_storage)
61
+ query.options[:for_storage]
62
+ else
63
+ configuration[:for_storage]
64
+ end
65
+ end
66
+
67
+ def token(query)
68
+ token_instance = if query.options[:token]
69
+ query.options[:token]
70
+ else
71
+ configuration[:token]
72
+ end
73
+
74
+ if !valid_token_configured?(token_instance) && configuration.api_key
75
+ token_instance = create_and_save_token!(query)
76
+ end
77
+
78
+ token_instance.to_s unless token_instance.nil?
79
+ end
80
+
81
+ def valid_token_configured?(token_instance)
82
+ !token_instance.nil? && token_instance.active?
83
+ end
84
+
85
+ def create_and_save_token!(query)
86
+ token_instance = create_token
87
+
88
+ if query.options[:token]
89
+ query.options[:token] = token_instance
90
+ else
91
+ Geocoder.merge_into_lookup_config(:esri, token: token_instance)
92
+ end
93
+
94
+ token_instance
95
+ end
96
+
97
+ def create_token
98
+ Geocoder::EsriToken.generate_token(*configuration.api_key)
99
+ end
47
100
  end
48
101
  end
@@ -8,19 +8,34 @@ module Geocoder::Lookup
8
8
  "FreeGeoIP"
9
9
  end
10
10
 
11
- def query_url(query)
12
- "#{protocol}://freegeoip.net/json/#{query.sanitized_text}"
11
+ def supported_protocols
12
+ if configuration[:host]
13
+ [:https]
14
+ else
15
+ # use https for default host
16
+ [:https]
17
+ end
13
18
  end
14
19
 
15
20
  private # ---------------------------------------------------------------
16
21
 
22
+ def base_query_url(query)
23
+ "#{protocol}://#{host}/json/#{query.sanitized_text}?"
24
+ end
25
+
26
+ def query_url_params(query)
27
+ {
28
+ :apikey => configuration.api_key
29
+ }.merge(super)
30
+ end
31
+
17
32
  def parse_raw_data(raw_data)
18
33
  raw_data.match(/^<html><title>404/) ? nil : super(raw_data)
19
34
  end
20
35
 
21
36
  def results(query)
22
- # don't look up a loopback address, just return the stored result
23
- return [reserved_result(query.text)] if query.loopback_ip_address?
37
+ # don't look up a loopback or private address, just return the stored result
38
+ return [reserved_result(query.text)] if query.internal_ip_address?
24
39
  # note: Freegeoip.net returns plain text "Not Found" on bad request
25
40
  (doc = fetch_data(query)) ? [doc] : []
26
41
  end
@@ -31,13 +46,17 @@ module Geocoder::Lookup
31
46
  "city" => "",
32
47
  "region_code" => "",
33
48
  "region_name" => "",
34
- "metrocode" => "",
35
- "zipcode" => "",
49
+ "metro_code" => "",
50
+ "zip_code" => "",
36
51
  "latitude" => "0",
37
52
  "longitude" => "0",
38
53
  "country_name" => "Reserved",
39
54
  "country_code" => "RD"
40
55
  }
41
56
  end
57
+
58
+ def host
59
+ configuration[:host] || "freegeoip.app"
60
+ end
42
61
  end
43
62
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'geocoder/lookups/base'
4
+ require 'geocoder/results/geoapify'
5
+
6
+ module Geocoder
7
+ module Lookup
8
+ # https://apidocs.geoapify.com/docs/geocoding/api
9
+ class Geoapify < Base
10
+ def name
11
+ 'Geoapify'
12
+ end
13
+
14
+ def required_api_key_parts
15
+ ['api_key']
16
+ end
17
+
18
+ def supported_protocols
19
+ [:https]
20
+ end
21
+
22
+ private
23
+
24
+ def base_query_url(query)
25
+ method = query.reverse_geocode? ? 'reverse' : 'search'
26
+ "https://api.geoapify.com/v1/geocode/#{method}?"
27
+ end
28
+
29
+ def results(query)
30
+ return [] unless (doc = fetch_data(query))
31
+
32
+ # The rest of the status codes should be already handled by the default
33
+ # functionality as the API returns correct HTTP response codes in most
34
+ # cases. There may be some unhandled cases still (such as over query
35
+ # limit reached) but there is not enough documentation to cover them.
36
+ case doc['statusCode']
37
+ when 500
38
+ raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, doc['message'])
39
+ end
40
+
41
+ return [] unless doc['type'] == 'FeatureCollection'
42
+ return [] unless doc['features'] || doc['features'].present?
43
+
44
+ doc['features']
45
+ end
46
+
47
+ def query_url_params(query)
48
+ lang = query.language || configuration.language
49
+ params = { apiKey: configuration.api_key, lang: lang, limit: query.options[:limit] }
50
+
51
+ if query.reverse_geocode?
52
+ params.merge!(query_url_params_reverse(query))
53
+ else
54
+ params.merge!(query_url_params_coordinates(query))
55
+ end
56
+
57
+ params.merge!(super)
58
+ end
59
+
60
+ def query_url_params_coordinates(query)
61
+ { text: query.sanitized_text }
62
+ end
63
+
64
+ def query_url_params_reverse(query)
65
+ {
66
+ lat: query.coordinates[0],
67
+ lon: query.coordinates[1]
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -8,12 +8,12 @@ module Geocoder::Lookup
8
8
  "Geocoder.ca"
9
9
  end
10
10
 
11
- def query_url(query)
12
- "#{protocol}://geocoder.ca/?" + url_query_string(query)
13
- end
14
-
15
11
  private # ---------------------------------------------------------------
16
12
 
13
+ def base_query_url(query)
14
+ "#{protocol}://geocoder.ca/?"
15
+ end
16
+
17
17
  def results(query)
18
18
  return [] unless doc = fetch_data(query)
19
19
  if doc['error'].nil?
@@ -21,7 +21,7 @@ module Geocoder::Lookup
21
21
  elsif doc['error']['code'] == "005"
22
22
  # "Postal Code is not in the proper Format" => no results, just shut up
23
23
  else
24
- warn "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']})."
24
+ Geocoder.log(:warn, "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']}).")
25
25
  end
26
26
  return []
27
27
  end
@@ -51,4 +51,3 @@ module Geocoder::Lookup
51
51
  end
52
52
  end
53
53
  end
54
-
@@ -0,0 +1,42 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/geocodio"
3
+
4
+ module Geocoder::Lookup
5
+ class Geocodio < Base
6
+
7
+ def name
8
+ "Geocodio"
9
+ end
10
+
11
+ def results(query)
12
+ return [] unless doc = fetch_data(query)
13
+ return doc["results"] if doc['error'].nil?
14
+
15
+ if doc['error'] == 'Invalid API key'
16
+ raise_error(Geocoder::InvalidApiKey) ||
17
+ Geocoder.log(:warn, "Geocodio service error: invalid API key.")
18
+ elsif doc['error'].match(/You have reached your daily maximum/)
19
+ raise_error(Geocoder::OverQueryLimitError, doc['error']) ||
20
+ Geocoder.log(:warn, "Geocodio service error: #{doc['error']}.")
21
+ else
22
+ raise_error(Geocoder::InvalidRequest, doc['error']) ||
23
+ Geocoder.log(:warn, "Geocodio service error: #{doc['error']}.")
24
+ end
25
+ []
26
+ end
27
+
28
+ private # ---------------------------------------------------------------
29
+
30
+ def base_query_url(query)
31
+ path = query.reverse_geocode? ? "reverse" : "geocode"
32
+ "#{protocol}://api.geocod.io/v1.6/#{path}?"
33
+ end
34
+
35
+ def query_url_params(query)
36
+ {
37
+ :api_key => configuration.api_key,
38
+ :q => query.sanitized_text
39
+ }.merge(super)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,49 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/geoip2'
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class Geoip2 < Base
7
+ attr_reader :gem_name
8
+
9
+ def initialize
10
+ unless configuration[:file].nil?
11
+ begin
12
+ @gem_name = configuration[:lib] || 'maxminddb'
13
+ require @gem_name
14
+ rescue LoadError
15
+ raise "Could not load Maxmind DB dependency. To use the GeoIP2 lookup you must add the #{@gem_name} gem to your Gemfile or have it installed in your system."
16
+ end
17
+
18
+ @mmdb = db_class.new(configuration[:file].to_s)
19
+ end
20
+ super
21
+ end
22
+
23
+ def name
24
+ 'GeoIP2'
25
+ end
26
+
27
+ def required_api_key_parts
28
+ []
29
+ end
30
+
31
+ private
32
+
33
+ def db_class
34
+ gem_name == 'hive_geoip2' ? Hive::GeoIP2 : MaxMindDB
35
+ end
36
+
37
+ def results(query)
38
+ return [] unless configuration[:file]
39
+
40
+ if @mmdb.respond_to?(:local_ip_alias) && !configuration[:local_ip_alias].nil?
41
+ @mmdb.local_ip_alias = configuration[:local_ip_alias]
42
+ end
43
+
44
+ result = @mmdb.lookup(query.to_s)
45
+ result.nil? ? [] : [result]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,65 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/geoportail_lu"
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class GeoportailLu < Base
7
+
8
+ def name
9
+ "Geoportail.lu"
10
+ end
11
+
12
+ private # ---------------------------------------------------------------
13
+
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
+ end
21
+
22
+ def search_url_base_path
23
+ "#{protocol}://api.geoportail.lu/geocoder/search?"
24
+ end
25
+
26
+ def reverse_geocode_url_base_path
27
+ "#{protocol}://api.geoportail.lu/geocoder/reverseGeocode?"
28
+ end
29
+
30
+ def query_url_geoportail_lu_params(query)
31
+ query.reverse_geocode? ? reverse_geocode_params(query) : search_params(query)
32
+ end
33
+
34
+ def search_params(query)
35
+ {
36
+ queryString: query.sanitized_text
37
+ }
38
+ end
39
+
40
+ def reverse_geocode_params(query)
41
+ lat_lon = query.coordinates
42
+ {
43
+ lat: lat_lon.first,
44
+ lon: lat_lon.last
45
+ }
46
+ end
47
+
48
+ def query_url_params(query)
49
+ query_url_geoportail_lu_params(query).merge(super)
50
+ end
51
+
52
+ def results(query)
53
+ return [] unless doc = fetch_data(query)
54
+ if doc['success'] == true
55
+ result = doc['results']
56
+ else
57
+ result = []
58
+ raise_error(Geocoder::Error) ||
59
+ warn("Geportail.lu Geocoding API error")
60
+ end
61
+ result
62
+ end
63
+ end
64
+ end
65
+ end
@@ -12,40 +12,70 @@ module Geocoder::Lookup
12
12
  "http://maps.google.com/maps?q=#{coordinates.join(',')}"
13
13
  end
14
14
 
15
- def query_url(query)
16
- "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
15
+ def supported_protocols
16
+ # Google requires HTTPS if an API key is used.
17
+ if configuration.api_key
18
+ [:https]
19
+ else
20
+ [:http, :https]
21
+ end
17
22
  end
18
23
 
19
24
  private # ---------------------------------------------------------------
20
25
 
26
+ def base_query_url(query)
27
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?"
28
+ end
29
+
30
+ def configure_ssl!(client)
31
+ client.instance_eval {
32
+ @ssl_context = OpenSSL::SSL::SSLContext.new
33
+ options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
34
+ if OpenSSL::SSL.const_defined?('OP_NO_COMPRESSION')
35
+ options |= OpenSSL::SSL::OP_NO_COMPRESSION
36
+ end
37
+ @ssl_context.set_params({options: options})
38
+ }
39
+ end
40
+
21
41
  def valid_response?(response)
22
- status = parse_json(response.body)["status"]
42
+ json = parse_json(response.body)
43
+ status = json["status"] if json
23
44
  super(response) and ['OK', 'ZERO_RESULTS'].include?(status)
24
45
  end
25
46
 
47
+ def result_root_attr
48
+ 'results'
49
+ end
50
+
26
51
  def results(query)
27
52
  return [] unless doc = fetch_data(query)
28
- case doc['status']; when "OK" # OK status implies >0 results
29
- return doc['results']
53
+ case doc['status']
54
+ when "OK" # OK status implies >0 results
55
+ return doc[result_root_attr]
30
56
  when "OVER_QUERY_LIMIT"
31
57
  raise_error(Geocoder::OverQueryLimitError) ||
32
- warn("Google Geocoding API error: over query limit.")
58
+ Geocoder.log(:warn, "#{name} API error: over query limit.")
33
59
  when "REQUEST_DENIED"
34
- raise_error(Geocoder::RequestDenied) ||
35
- warn("Google Geocoding API error: request denied.")
60
+ raise_error(Geocoder::RequestDenied, doc['error_message']) ||
61
+ Geocoder.log(:warn, "#{name} API error: request denied (#{doc['error_message']}).")
36
62
  when "INVALID_REQUEST"
37
- raise_error(Geocoder::InvalidRequest) ||
38
- warn("Google Geocoding API error: invalid request.")
63
+ raise_error(Geocoder::InvalidRequest, doc['error_message']) ||
64
+ Geocoder.log(:warn, "#{name} API error: invalid request (#{doc['error_message']}).")
39
65
  end
40
66
  return []
41
67
  end
42
68
 
43
69
  def query_url_google_params(query)
44
70
  params = {
45
- (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
46
71
  :sensor => "false",
47
- :language => configuration.language
72
+ :language => (query.language || configuration.language)
48
73
  }
74
+ if query.options[:google_place_id]
75
+ params[:place_id] = query.sanitized_text
76
+ else
77
+ params[(query.reverse_geocode? ? :latlng : :address)] = query.sanitized_text
78
+ end
49
79
  unless (bounds = query.options[:bounds]).nil?
50
80
  params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
51
81
  end
@@ -55,6 +85,9 @@ module Geocoder::Lookup
55
85
  unless (components = query.options[:components]).nil?
56
86
  params[:components] = components.is_a?(Array) ? components.join("|") : components
57
87
  end
88
+ unless (result_type = query.options[:result_type]).nil?
89
+ params[:result_type] = result_type.is_a?(Array) ? result_type.join("|") : result_type
90
+ end
58
91
  params
59
92
  end
60
93