geocoder 1.2.6 → 1.6.1

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 (276) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +189 -1
  3. data/LICENSE +1 -1
  4. data/README.md +387 -755
  5. data/examples/autoexpire_cache_redis.rb +5 -3
  6. data/examples/reverse_geocode_job.rb +40 -0
  7. data/lib/generators/geocoder/config/templates/initializer.rb +17 -16
  8. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
  9. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
  10. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
  11. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
  12. data/lib/generators/geocoder/migration_version.rb +15 -0
  13. data/lib/geocoder/cache.rb +6 -2
  14. data/lib/geocoder/calculations.rb +30 -38
  15. data/lib/geocoder/cli.rb +2 -2
  16. data/lib/geocoder/configuration.rb +18 -5
  17. data/lib/geocoder/esri_token.rb +38 -0
  18. data/lib/geocoder/exceptions.rb +19 -0
  19. data/lib/geocoder/ip_address.rb +16 -11
  20. data/lib/geocoder/kernel_logger.rb +25 -0
  21. data/lib/geocoder/logger.rb +47 -0
  22. data/lib/geocoder/lookup.rb +31 -12
  23. data/lib/geocoder/lookups/amap.rb +63 -0
  24. data/lib/geocoder/lookups/baidu.rb +17 -9
  25. data/lib/geocoder/lookups/baidu_ip.rb +7 -31
  26. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
  27. data/lib/geocoder/lookups/base.rb +73 -25
  28. data/lib/geocoder/lookups/bing.rb +38 -15
  29. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  30. data/lib/geocoder/lookups/dstk.rb +4 -2
  31. data/lib/geocoder/lookups/esri.rb +55 -8
  32. data/lib/geocoder/lookups/freegeoip.rb +18 -5
  33. data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
  34. data/lib/geocoder/lookups/geocodio.rb +8 -8
  35. data/lib/geocoder/lookups/geoip2.rb +10 -5
  36. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  37. data/lib/geocoder/lookups/google.rb +37 -9
  38. data/lib/geocoder/lookups/google_places_details.rb +9 -9
  39. data/lib/geocoder/lookups/google_places_search.rb +33 -0
  40. data/lib/geocoder/lookups/google_premier.rb +11 -1
  41. data/lib/geocoder/lookups/here.rb +29 -23
  42. data/lib/geocoder/lookups/ip2location.rb +67 -0
  43. data/lib/geocoder/lookups/ipapi_com.rb +82 -0
  44. data/lib/geocoder/lookups/ipdata_co.rb +62 -0
  45. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  46. data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
  47. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  48. data/lib/geocoder/lookups/ipstack.rb +63 -0
  49. data/lib/geocoder/lookups/latlon.rb +59 -0
  50. data/lib/geocoder/lookups/location_iq.rb +50 -0
  51. data/lib/geocoder/lookups/mapbox.rb +59 -0
  52. data/lib/geocoder/lookups/mapquest.rb +7 -9
  53. data/lib/geocoder/lookups/maxmind.rb +7 -7
  54. data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
  55. data/lib/geocoder/lookups/maxmind_local.rb +9 -2
  56. data/lib/geocoder/lookups/nominatim.rb +18 -6
  57. data/lib/geocoder/lookups/opencagedata.rb +16 -9
  58. data/lib/geocoder/lookups/osmnames.rb +57 -0
  59. data/lib/geocoder/lookups/pelias.rb +63 -0
  60. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  61. data/lib/geocoder/lookups/pointpin.rb +14 -13
  62. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +7 -8
  63. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  64. data/lib/geocoder/lookups/smarty_streets.rb +23 -5
  65. data/lib/geocoder/lookups/telize.rb +42 -7
  66. data/lib/geocoder/lookups/tencent.rb +59 -0
  67. data/lib/geocoder/lookups/yandex.rb +17 -9
  68. data/lib/geocoder/models/active_record.rb +4 -3
  69. data/lib/geocoder/models/mongo_base.rb +0 -2
  70. data/lib/geocoder/query.rb +15 -1
  71. data/lib/geocoder/railtie.rb +1 -1
  72. data/lib/geocoder/request.rb +103 -14
  73. data/lib/geocoder/results/amap.rb +87 -0
  74. data/lib/geocoder/results/baidu.rb +10 -14
  75. data/lib/geocoder/results/ban_data_gouv_fr.rb +257 -0
  76. data/lib/geocoder/results/base.rb +13 -1
  77. data/lib/geocoder/results/bing.rb +5 -1
  78. data/lib/geocoder/results/db_ip_com.rb +58 -0
  79. data/lib/geocoder/results/esri.rb +30 -6
  80. data/lib/geocoder/results/freegeoip.rb +2 -7
  81. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  82. data/lib/geocoder/results/geocodio.rb +15 -3
  83. data/lib/geocoder/results/geoip2.rb +37 -25
  84. data/lib/geocoder/results/geoportail_lu.rb +71 -0
  85. data/lib/geocoder/results/google.rb +26 -0
  86. data/lib/geocoder/results/google_places_details.rb +4 -0
  87. data/lib/geocoder/results/google_places_search.rb +52 -0
  88. data/lib/geocoder/results/here.rb +21 -1
  89. data/lib/geocoder/results/ip2location.rb +22 -0
  90. data/lib/geocoder/results/ipapi_com.rb +45 -0
  91. data/lib/geocoder/results/ipdata_co.rb +40 -0
  92. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  93. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  94. data/lib/geocoder/results/ipregistry.rb +308 -0
  95. data/lib/geocoder/results/ipstack.rb +60 -0
  96. data/lib/geocoder/results/latlon.rb +71 -0
  97. data/lib/geocoder/results/location_iq.rb +6 -0
  98. data/lib/geocoder/results/mapbox.rb +57 -0
  99. data/lib/geocoder/results/mapquest.rb +5 -8
  100. data/lib/geocoder/results/maxmind.rb +0 -5
  101. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  102. data/lib/geocoder/results/maxmind_local.rb +0 -5
  103. data/lib/geocoder/results/nominatim.rb +18 -3
  104. data/lib/geocoder/results/opencagedata.rb +20 -2
  105. data/lib/geocoder/results/osmnames.rb +56 -0
  106. data/lib/geocoder/results/pelias.rb +58 -0
  107. data/lib/geocoder/results/pickpoint.rb +6 -0
  108. data/lib/geocoder/results/pointpin.rb +0 -4
  109. data/lib/geocoder/results/postcodes_io.rb +40 -0
  110. data/lib/geocoder/results/smarty_streets.rb +55 -19
  111. data/lib/geocoder/results/telize.rb +0 -5
  112. data/lib/geocoder/results/tencent.rb +72 -0
  113. data/lib/geocoder/results/test.rb +1 -1
  114. data/lib/geocoder/results/yandex.rb +57 -7
  115. data/lib/geocoder/sql.rb +9 -6
  116. data/lib/geocoder/stores/active_record.rb +49 -10
  117. data/lib/geocoder/stores/base.rb +2 -14
  118. data/lib/geocoder/stores/mongo_base.rb +0 -31
  119. data/lib/geocoder/version.rb +1 -1
  120. data/lib/geocoder.rb +2 -1
  121. data/lib/hash_recursive_merge.rb +1 -2
  122. data/lib/maxmind_database.rb +4 -4
  123. data/lib/tasks/geocoder.rake +29 -4
  124. metadata +56 -159
  125. data/.gitignore +0 -6
  126. data/.travis.yml +0 -31
  127. data/Rakefile +0 -25
  128. data/gemfiles/Gemfile.mongoid-2.4.x +0 -16
  129. data/lib/geocoder/lookups/geocoder_us.rb +0 -39
  130. data/lib/geocoder/lookups/okf.rb +0 -43
  131. data/lib/geocoder/lookups/ovi.rb +0 -62
  132. data/lib/geocoder/lookups/yahoo.rb +0 -88
  133. data/lib/geocoder/results/geocoder_us.rb +0 -39
  134. data/lib/geocoder/results/okf.rb +0 -106
  135. data/lib/geocoder/results/ovi.rb +0 -62
  136. data/lib/geocoder/results/yahoo.rb +0 -55
  137. data/lib/oauth_util.rb +0 -112
  138. data/test/fixtures/baidu_invalid_key +0 -1
  139. data/test/fixtures/baidu_ip_202_198_16_3 +0 -19
  140. data/test/fixtures/baidu_ip_invalid_key +0 -1
  141. data/test/fixtures/baidu_ip_no_results +0 -1
  142. data/test/fixtures/baidu_no_results +0 -1
  143. data/test/fixtures/baidu_reverse +0 -1
  144. data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
  145. data/test/fixtures/bing_invalid_key +0 -1
  146. data/test/fixtures/bing_madison_square_garden +0 -40
  147. data/test/fixtures/bing_no_results +0 -16
  148. data/test/fixtures/bing_reverse +0 -42
  149. data/test/fixtures/cloudmade_invalid_key +0 -1
  150. data/test/fixtures/cloudmade_madison_square_garden +0 -1
  151. data/test/fixtures/cloudmade_no_results +0 -1
  152. data/test/fixtures/esri_madison_square_garden +0 -59
  153. data/test/fixtures/esri_no_results +0 -8
  154. data/test/fixtures/esri_reverse +0 -21
  155. data/test/fixtures/freegeoip_74_200_247_59 +0 -12
  156. data/test/fixtures/freegeoip_no_results +0 -1
  157. data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
  158. data/test/fixtures/geocoder_ca_no_results +0 -1
  159. data/test/fixtures/geocoder_ca_reverse +0 -34
  160. data/test/fixtures/geocoder_us_madison_square_garden +0 -1
  161. data/test/fixtures/geocoder_us_no_results +0 -1
  162. data/test/fixtures/geocodio_1101_pennsylvania_ave +0 -1
  163. data/test/fixtures/geocodio_bad_api_key +0 -3
  164. data/test/fixtures/geocodio_invalid +0 -4
  165. data/test/fixtures/geocodio_no_results +0 -1
  166. data/test/fixtures/geocodio_over_query_limit +0 -4
  167. data/test/fixtures/google_garbage +0 -456
  168. data/test/fixtures/google_madison_square_garden +0 -57
  169. data/test/fixtures/google_no_city_data +0 -44
  170. data/test/fixtures/google_no_locality +0 -51
  171. data/test/fixtures/google_no_results +0 -4
  172. data/test/fixtures/google_over_limit +0 -4
  173. data/test/fixtures/google_places_details_invalid_request +0 -4
  174. data/test/fixtures/google_places_details_madison_square_garden +0 -120
  175. data/test/fixtures/google_places_details_no_results +0 -4
  176. data/test/fixtures/google_places_details_no_reviews +0 -60
  177. data/test/fixtures/google_places_details_no_types +0 -66
  178. data/test/fixtures/here_madison_square_garden +0 -72
  179. data/test/fixtures/here_no_results +0 -8
  180. data/test/fixtures/mapquest_error +0 -16
  181. data/test/fixtures/mapquest_invalid_api_key +0 -16
  182. data/test/fixtures/mapquest_invalid_request +0 -16
  183. data/test/fixtures/mapquest_madison_square_garden +0 -52
  184. data/test/fixtures/mapquest_no_results +0 -16
  185. data/test/fixtures/maxmind_24_24_24_21 +0 -1
  186. data/test/fixtures/maxmind_24_24_24_22 +0 -1
  187. data/test/fixtures/maxmind_24_24_24_23 +0 -1
  188. data/test/fixtures/maxmind_24_24_24_24 +0 -1
  189. data/test/fixtures/maxmind_74_200_247_59 +0 -1
  190. data/test/fixtures/maxmind_invalid_key +0 -1
  191. data/test/fixtures/maxmind_no_results +0 -1
  192. data/test/fixtures/nominatim_madison_square_garden +0 -150
  193. data/test/fixtures/nominatim_no_results +0 -1
  194. data/test/fixtures/nominatim_over_limit +0 -1
  195. data/test/fixtures/okf_kirstinmaki +0 -67
  196. data/test/fixtures/okf_no_results +0 -4
  197. data/test/fixtures/opencagedata_invalid_api_key +0 -25
  198. data/test/fixtures/opencagedata_invalid_request +0 -26
  199. data/test/fixtures/opencagedata_madison_square_garden +0 -73
  200. data/test/fixtures/opencagedata_no_results +0 -29
  201. data/test/fixtures/opencagedata_over_limit +0 -31
  202. data/test/fixtures/ovi_madison_square_garden +0 -72
  203. data/test/fixtures/ovi_no_results +0 -8
  204. data/test/fixtures/pointpin_10_10_10_10 +0 -1
  205. data/test/fixtures/pointpin_555_555_555_555 +0 -1
  206. data/test/fixtures/pointpin_80_111_555_555 +0 -1
  207. data/test/fixtures/pointpin_no_results +0 -1
  208. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +0 -1
  209. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +0 -1
  210. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +0 -1
  211. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +0 -1
  212. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +0 -1
  213. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +0 -1
  214. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +0 -1
  215. data/test/fixtures/smarty_streets_11211 +0 -1
  216. data/test/fixtures/smarty_streets_madison_square_garden +0 -47
  217. data/test/fixtures/smarty_streets_no_results +0 -1
  218. data/test/fixtures/telize_10_10_10_10 +0 -1
  219. data/test/fixtures/telize_555_555_555_555 +0 -4
  220. data/test/fixtures/telize_74_200_247_59 +0 -1
  221. data/test/fixtures/telize_no_results +0 -1
  222. data/test/fixtures/yahoo_error +0 -1
  223. data/test/fixtures/yahoo_invalid_key +0 -2
  224. data/test/fixtures/yahoo_madison_square_garden +0 -52
  225. data/test/fixtures/yahoo_no_results +0 -10
  226. data/test/fixtures/yahoo_over_limit +0 -2
  227. data/test/fixtures/yandex_canada_rue_dupuis_14 +0 -446
  228. data/test/fixtures/yandex_invalid_key +0 -1
  229. data/test/fixtures/yandex_kremlin +0 -48
  230. data/test/fixtures/yandex_new_york +0 -1
  231. data/test/fixtures/yandex_no_city_and_town +0 -112
  232. data/test/fixtures/yandex_no_results +0 -16
  233. data/test/integration/http_client_test.rb +0 -31
  234. data/test/mongoid_test_helper.rb +0 -43
  235. data/test/test_helper.rb +0 -416
  236. data/test/unit/active_record_test.rb +0 -16
  237. data/test/unit/cache_test.rb +0 -37
  238. data/test/unit/calculations_test.rb +0 -220
  239. data/test/unit/configuration_test.rb +0 -55
  240. data/test/unit/error_handling_test.rb +0 -56
  241. data/test/unit/geocoder_test.rb +0 -78
  242. data/test/unit/https_test.rb +0 -17
  243. data/test/unit/ip_address_test.rb +0 -27
  244. data/test/unit/lookup_test.rb +0 -153
  245. data/test/unit/lookups/bing_test.rb +0 -68
  246. data/test/unit/lookups/dstk_test.rb +0 -26
  247. data/test/unit/lookups/esri_test.rb +0 -48
  248. data/test/unit/lookups/freegeoip_test.rb +0 -27
  249. data/test/unit/lookups/geocoder_ca_test.rb +0 -17
  250. data/test/unit/lookups/geocodio_test.rb +0 -55
  251. data/test/unit/lookups/geoip2_test.rb +0 -27
  252. data/test/unit/lookups/google_places_details_test.rb +0 -122
  253. data/test/unit/lookups/google_premier_test.rb +0 -22
  254. data/test/unit/lookups/google_test.rb +0 -84
  255. data/test/unit/lookups/mapquest_test.rb +0 -60
  256. data/test/unit/lookups/maxmind_local_test.rb +0 -28
  257. data/test/unit/lookups/maxmind_test.rb +0 -63
  258. data/test/unit/lookups/nominatim_test.rb +0 -31
  259. data/test/unit/lookups/okf_test.rb +0 -38
  260. data/test/unit/lookups/opencagedata_test.rb +0 -64
  261. data/test/unit/lookups/pointpin_test.rb +0 -30
  262. data/test/unit/lookups/postcode_anywhere_uk_test.rb +0 -70
  263. data/test/unit/lookups/smarty_streets_test.rb +0 -71
  264. data/test/unit/lookups/telize_test.rb +0 -36
  265. data/test/unit/lookups/yahoo_test.rb +0 -35
  266. data/test/unit/method_aliases_test.rb +0 -26
  267. data/test/unit/model_test.rb +0 -38
  268. data/test/unit/mongoid_test.rb +0 -47
  269. data/test/unit/near_test.rb +0 -87
  270. data/test/unit/oauth_util_test.rb +0 -31
  271. data/test/unit/proxy_test.rb +0 -37
  272. data/test/unit/query_test.rb +0 -52
  273. data/test/unit/rake_task_test.rb +0 -21
  274. data/test/unit/request_test.rb +0 -35
  275. data/test/unit/result_test.rb +0 -72
  276. data/test/unit/test_mode_test.rb +0 -70
@@ -0,0 +1,70 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/maxmind_geoip2'
3
+
4
+ module Geocoder::Lookup
5
+ class MaxmindGeoip2 < Base
6
+
7
+ def name
8
+ "MaxMind GeoIP2"
9
+ end
10
+
11
+ # Maxmind's GeoIP2 Precision Services only supports HTTPS,
12
+ # otherwise a `404 Not Found` HTTP response will be returned
13
+ def supported_protocols
14
+ [:https]
15
+ end
16
+
17
+ def query_url(query)
18
+ "#{protocol}://geoip.maxmind.com/geoip/v2.1/#{configured_service!}/#{query.sanitized_text.strip}"
19
+ end
20
+
21
+ private # ---------------------------------------------------------------
22
+
23
+ def cache_key(query)
24
+ query_url(query)
25
+ end
26
+
27
+ ##
28
+ # Return the name of the configured service, or raise an exception.
29
+ #
30
+ def configured_service!
31
+ if s = configuration[:service] and services.include?(s) and configuration[:basic_auth][:user] and configuration[:basic_auth][:password]
32
+ return s
33
+ else
34
+ raise(
35
+ Geocoder::ConfigurationError, "When using MaxMind GeoIP2 you must specify a service and credentials: Geocoder.configure(maxmind_geoip2: {service: ..., basic_auth: {user: ..., password: ...}}), where service is one of: #{services.inspect}"
36
+ )
37
+ end
38
+ end
39
+
40
+ def data_contains_error?(doc)
41
+ (["code", "error"] - doc.keys).empty?
42
+ end
43
+
44
+ ##
45
+ # Service names used in URL.
46
+ #
47
+ def services
48
+ [
49
+ :country,
50
+ :city,
51
+ :insights,
52
+ ]
53
+ end
54
+
55
+ def results(query)
56
+ # don't look up a loopback or private address, just return the stored result
57
+ return [] if query.internal_ip_address?
58
+
59
+ doc = fetch_data(query)
60
+ if doc
61
+ if !data_contains_error?(doc)
62
+ return [doc]
63
+ else
64
+ Geocoder.log(:warn, "MaxMind GeoIP2 Geocoding API error: #{doc['code']} (#{doc['error']}).")
65
+ end
66
+ end
67
+ return []
68
+ end
69
+ end
70
+ end
@@ -31,12 +31,12 @@ module Geocoder::Lookup
31
31
  if configuration[:file]
32
32
  geoip_class = RUBY_PLATFORM == "java" ? JGeoIP : GeoIP
33
33
  result = geoip_class.new(configuration[:file]).city(query.to_s)
34
- result.nil? ? [] : [result.to_hash]
34
+ result.nil? ? [] : [encode_hash(result.to_hash)]
35
35
  elsif configuration[:package] == :city
36
36
  addr = IPAddr.new(query.text).to_i
37
37
  q = "SELECT l.country, l.region, l.city, l.latitude, l.longitude
38
38
  FROM maxmind_geolite_city_location l WHERE l.loc_id = (SELECT b.loc_id FROM maxmind_geolite_city_blocks b
39
- WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num LIMIT 1)"
39
+ WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num)"
40
40
  format_result(q, [:country_name, :region_name, :city_name, :latitude, :longitude])
41
41
  elsif configuration[:package] == :country
42
42
  addr = IPAddr.new(query.text).to_i
@@ -46,6 +46,13 @@ module Geocoder::Lookup
46
46
  end
47
47
  end
48
48
 
49
+ def encode_hash(hash, encoding = "UTF-8")
50
+ hash.inject({}) do |h,i|
51
+ h[i[0]] = i[1].is_a?(String) ? i[1].encode(encoding) : i[1]
52
+ h
53
+ end
54
+ end
55
+
49
56
  def format_result(query, attr_names)
50
57
  if r = ActiveRecord::Base.connection.execute(query).first
51
58
  r = r.values if r.is_a?(Hash) # some db adapters return Hash, some Array
@@ -9,16 +9,28 @@ module Geocoder::Lookup
9
9
  end
10
10
 
11
11
  def map_link_url(coordinates)
12
- "http://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
12
+ "https://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
13
13
  end
14
14
 
15
- def query_url(query)
15
+ private # ---------------------------------------------------------------
16
+
17
+ def base_query_url(query)
16
18
  method = query.reverse_geocode? ? "reverse" : "search"
17
- host = configuration[:host] || "nominatim.openstreetmap.org"
18
- "#{protocol}://#{host}/#{method}?" + url_query_string(query)
19
+ "#{protocol}://#{configured_host}/#{method}?"
19
20
  end
20
21
 
21
- private # ---------------------------------------------------------------
22
+ def configured_host
23
+ configuration[:host] || "nominatim.openstreetmap.org"
24
+ end
25
+
26
+ def use_ssl?
27
+ # nominatim.openstreetmap.org redirects HTTP requests to HTTPS
28
+ if configured_host == "nominatim.openstreetmap.org"
29
+ true
30
+ else
31
+ super
32
+ end
33
+ end
22
34
 
23
35
  def results(query)
24
36
  return [] unless doc = fetch_data(query)
@@ -27,7 +39,7 @@ module Geocoder::Lookup
27
39
 
28
40
  def parse_raw_data(raw_data)
29
41
  if raw_data.include?("Bandwidth limit exceeded")
30
- raise_error(Geocoder::OverQueryLimitError) || warn("Over API query limit.")
42
+ raise_error(Geocoder::OverQueryLimitError) || Geocoder.log(:warn, "Over API query limit.")
31
43
  else
32
44
  super(raw_data)
33
45
  end
@@ -8,15 +8,15 @@ module Geocoder::Lookup
8
8
  "OpenCageData"
9
9
  end
10
10
 
11
- def query_url(query)
12
- "#{protocol}://api.opencagedata.com/geocode/v1/json?key=#{configuration.api_key}&#{url_query_string(query)}"
13
- end
14
-
15
11
  def required_api_key_parts
16
12
  ["key"]
17
13
  end
18
14
 
19
- private
15
+ private # ----------------------------------------------------------------
16
+
17
+ def base_query_url(query)
18
+ "#{protocol}://api.opencagedata.com/geocode/v1/json?"
19
+ end
20
20
 
21
21
  def results(query)
22
22
  return [] unless doc = fetch_data(query)
@@ -26,16 +26,16 @@ module Geocoder::Lookup
26
26
  case doc['status']['code']
27
27
  when 400 # Error with input
28
28
  raise_error(Geocoder::InvalidRequest, messages) ||
29
- warn("Opencagedata Geocoding API error: #{messages}")
29
+ Geocoder.log(:warn, "Opencagedata Geocoding API error: #{messages}")
30
30
  when 403 # Key related error
31
31
  raise_error(Geocoder::InvalidApiKey, messages) ||
32
- warn("Opencagedata Geocoding API error: #{messages}")
32
+ Geocoder.log(:warn, "Opencagedata Geocoding API error: #{messages}")
33
33
  when 402 # Quata Exceeded
34
34
  raise_error(Geocoder::OverQueryLimitError, messages) ||
35
- warn("Opencagedata Geocoding API error: #{messages}")
35
+ Geocoder.log(:warn, "Opencagedata Geocoding API error: #{messages}")
36
36
  when 500 # Unknown error
37
37
  raise_error(Geocoder::Error, messages) ||
38
- warn("Opencagedata Geocoding API error: #{messages}")
38
+ Geocoder.log(:warn, "Opencagedata Geocoding API error: #{messages}")
39
39
  end
40
40
 
41
41
  return doc["results"]
@@ -44,9 +44,16 @@ module Geocoder::Lookup
44
44
  def query_url_params(query)
45
45
  params = {
46
46
  :q => query.sanitized_text,
47
+ :key => configuration.api_key,
47
48
  :language => (query.language || configuration.language)
48
49
  }.merge(super)
49
50
 
51
+ [:abbrv, :countrycode, :min_confidence, :no_dedupe, :no_annotations, :no_record, :limit].each do |option|
52
+ unless (option_value = query.options[option]).nil?
53
+ params[option] = option_value
54
+ end
55
+ end
56
+
50
57
  unless (bounds = query.options[:bounds]).nil?
51
58
  params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join(',')
52
59
  end
@@ -0,0 +1,57 @@
1
+ require 'cgi'
2
+ require 'geocoder/lookups/base'
3
+ require 'geocoder/results/osmnames'
4
+
5
+ module Geocoder::Lookup
6
+ class Osmnames < Base
7
+
8
+ def name
9
+ 'OSM Names'
10
+ end
11
+
12
+ def required_api_key_parts
13
+ configuration[:host] ? [] : ['key']
14
+ end
15
+
16
+ def supported_protocols
17
+ [:https]
18
+ end
19
+
20
+ private
21
+
22
+ def base_query_url(query)
23
+ "#{base_url(query)}/#{params_url(query)}.js?"
24
+ end
25
+
26
+ def base_url(query)
27
+ host = configuration[:host] || 'geocoder.tilehosting.com'
28
+ "#{protocol}://#{host}"
29
+ end
30
+
31
+ def params_url(query)
32
+ method, args = 'q', CGI.escape(query.sanitized_text)
33
+ method, args = 'r', query.coordinates.join('/') if query.reverse_geocode?
34
+ "#{country_limited(query)}#{method}/#{args}"
35
+ end
36
+
37
+ def results(query)
38
+ return [] unless doc = fetch_data(query)
39
+ if (error = doc['message'])
40
+ raise_error(Geocoder::InvalidRequest, error) ||
41
+ Geocoder.log(:warn, "OSMNames Geocoding API error: #{error}")
42
+ else
43
+ return doc['results']
44
+ end
45
+ end
46
+
47
+ def query_url_params(query)
48
+ {
49
+ key: configuration.api_key
50
+ }.merge(super)
51
+ end
52
+
53
+ def country_limited(query)
54
+ "#{query.options[:country_code].downcase}/" if query.options[:country_code] && !query.reverse_geocode?
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,63 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/pelias'
3
+
4
+ module Geocoder::Lookup
5
+ class Pelias < Base
6
+ def name
7
+ 'Pelias'
8
+ end
9
+
10
+ def endpoint
11
+ configuration[:endpoint] || 'localhost'
12
+ end
13
+
14
+ def required_api_key_parts
15
+ ['search-XXXX']
16
+ end
17
+
18
+ private # ----------------------------------------------------------------
19
+
20
+ def base_query_url(query)
21
+ query_type = query.reverse_geocode? ? 'reverse' : 'search'
22
+ "#{protocol}://#{endpoint}/v1/#{query_type}?"
23
+ end
24
+
25
+ def query_url_params(query)
26
+ params = {
27
+ api_key: configuration.api_key
28
+ }.merge(super)
29
+
30
+ if query.reverse_geocode?
31
+ lat, lon = query.coordinates
32
+ params[:'point.lat'] = lat
33
+ params[:'point.lon'] = lon
34
+ else
35
+ params[:text] = query.text
36
+ end
37
+ params
38
+ end
39
+
40
+ def results(query)
41
+ return [] unless doc = fetch_data(query)
42
+
43
+ # not all responses include a meta
44
+ if doc['meta']
45
+ error = doc.fetch('results', {}).fetch('error', {})
46
+ message = error.fetch('type', 'Unknown Error') + ': ' + error.fetch('message', 'No message')
47
+ log_message = 'Pelias Geocoding API error - ' + message
48
+ case doc['meta']['status_code']
49
+ when '200'
50
+ # nothing to see here
51
+ when '403'
52
+ raise_error(Geocoder::RequestDenied, message) || Geocoder.log(:warn, log_message)
53
+ when '429'
54
+ raise_error(Geocoder::OverQueryLimitError, message) || Geocoder.log(:warn, log_message)
55
+ else
56
+ raise_error(Geocoder::Error, message) || Geocoder.log(:warn, log_message)
57
+ end
58
+ end
59
+
60
+ doc['features'] || []
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ require "geocoder/lookups/nominatim"
2
+ require "geocoder/results/pickpoint"
3
+
4
+ module Geocoder::Lookup
5
+ class Pickpoint < Nominatim
6
+ def name
7
+ "Pickpoint"
8
+ end
9
+
10
+ def supported_protocols
11
+ [:https]
12
+ end
13
+
14
+ def required_api_key_parts
15
+ ["api_key"]
16
+ end
17
+
18
+ private # ----------------------------------------------------------------
19
+
20
+ def base_query_url(query)
21
+ method = query.reverse_geocode? ? "reverse" : "forward"
22
+ "#{protocol}://api.pickpoint.io/v1/#{method}?"
23
+ end
24
+
25
+ def query_url_params(query)
26
+ {
27
+ key: configuration.api_key
28
+ }.merge(super)
29
+ end
30
+
31
+ def results(query)
32
+ return [] unless doc = fetch_data(query)
33
+
34
+ if !doc.is_a?(Array) && doc['message'] == 'Unauthorized'
35
+ raise_error(Geocoder::InvalidApiKey, 'Unauthorized')
36
+ end
37
+
38
+ doc.is_a?(Array) ? doc : [doc]
39
+ end
40
+ end
41
+ end
@@ -13,14 +13,18 @@ module Geocoder::Lookup
13
13
  end
14
14
 
15
15
  def query_url(query)
16
- "#{ protocol }://geo.pointp.in/#{ api_key }/json/#{ query.sanitized_text }"
16
+ "#{protocol}://geo.pointp.in/#{configuration.api_key}/json/#{query.sanitized_text}"
17
17
  end
18
18
 
19
- private
19
+ private # ----------------------------------------------------------------
20
+
21
+ def cache_key(query)
22
+ "#{protocol}://geo.pointp.in/json/#{query.sanitized_text}"
23
+ end
20
24
 
21
25
  def results(query)
22
- # don't look up a loopback address, just return the stored result
23
- return [] if query.loopback_ip_address?
26
+ # don't look up a loopback or private address, just return the stored result
27
+ return [] if query.internal_ip_address?
24
28
  doc = fetch_data(query)
25
29
  if doc and doc.is_a?(Hash)
26
30
  if !data_contains_error?(doc)
@@ -28,17 +32,17 @@ module Geocoder::Lookup
28
32
  elsif doc['error']
29
33
  case doc['error']
30
34
  when "Invalid IP address"
31
- raise_error(Geocoder::InvalidRequest) || warn("Invalid Pointpin request.")
35
+ raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, "Invalid Pointpin request.")
32
36
  when "Invalid API key"
33
- raise_error(Geocoder::InvalidApiKey) || warn("Invalid Pointpin API key.")
37
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid Pointpin API key.")
34
38
  when "Address not found"
35
- warn("Address not found.")
39
+ Geocoder.log(:warn, "Address not found.")
36
40
  end
37
41
  else
38
- raise_error(Geocoder::Error) || warn("Pointpin server error")
42
+ raise_error(Geocoder::Error) || Geocoder.log(:warn, "Pointpin server error")
39
43
  end
40
44
  end
41
-
45
+
42
46
  return []
43
47
  end
44
48
 
@@ -46,6 +50,7 @@ module Geocoder::Lookup
46
50
  parsed_data.keys.include?('error')
47
51
  end
48
52
 
53
+ # TODO: replace this hash with what's actually returned by Pointpin
49
54
  def reserved_result(ip)
50
55
  {
51
56
  "ip" => ip,
@@ -60,9 +65,5 @@ module Geocoder::Lookup
60
65
  "country_code" => "RD"
61
66
  }
62
67
  end
63
-
64
- def api_key
65
- configuration.api_key
66
- end
67
68
  end
68
69
  end
@@ -4,7 +4,6 @@ require 'geocoder/results/postcode_anywhere_uk'
4
4
  module Geocoder::Lookup
5
5
  class PostcodeAnywhereUk < Base
6
6
  # API documentation: http://www.postcodeanywhere.co.uk/Support/WebService/Geocoding/UK/Geocode/2/
7
- BASE_URL_GEOCODE_V2_00 = 'services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws'
8
7
  DAILY_LIMIT_EXEEDED_ERROR_CODES = ['8', '17'] # api docs say these two codes are the same error
9
8
  INVALID_API_KEY_ERROR_CODE = '2'
10
9
 
@@ -16,11 +15,11 @@ module Geocoder::Lookup
16
15
  %w(key)
17
16
  end
18
17
 
19
- def query_url(query)
20
- format('%s://%s?%s', protocol, BASE_URL_GEOCODE_V2_00, url_query_string(query))
21
- end
18
+ private # ----------------------------------------------------------------
22
19
 
23
- private
20
+ def base_query_url(query)
21
+ "#{protocol}://services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws?"
22
+ end
24
23
 
25
24
  def results(query)
26
25
  response = fetch_data(query)
@@ -33,11 +32,11 @@ module Geocoder::Lookup
33
32
  def raise_exception_for_response(response)
34
33
  case response['Error']
35
34
  when *DAILY_LIMIT_EXEEDED_ERROR_CODES
36
- raise_error(Geocoder::OverQueryLimitError, response['Cause']) || warn(response['Cause'])
35
+ raise_error(Geocoder::OverQueryLimitError, response['Cause']) || Geocoder.log(:warn, response['Cause'])
37
36
  when INVALID_API_KEY_ERROR_CODE
38
- raise_error(Geocoder::InvalidApiKey, response['Cause']) || warn(response['Cause'])
37
+ raise_error(Geocoder::InvalidApiKey, response['Cause']) || Geocoder.log(:warn, response['Cause'])
39
38
  else # anything else just raise general error with the api cause
40
- raise_error(Geocoder::Error, response['Cause']) || warn(response['Cause'])
39
+ raise_error(Geocoder::Error, response['Cause']) || Geocoder.log(:warn, response['Cause'])
41
40
  end
42
41
  end
43
42
 
@@ -0,0 +1,31 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/postcodes_io'
3
+
4
+ module Geocoder::Lookup
5
+ class PostcodesIo < Base
6
+ def name
7
+ 'Postcodes.io'
8
+ end
9
+
10
+ def query_url(query)
11
+ "#{protocol}://api.postcodes.io/postcodes/#{query.sanitized_text.gsub(/\s/, '')}"
12
+ end
13
+
14
+ def supported_protocols
15
+ [:https]
16
+ end
17
+
18
+ private # ----------------------------------------------------------------
19
+
20
+ def cache_key(query)
21
+ query_url(query)
22
+ end
23
+
24
+ def results(query)
25
+ response = fetch_data(query)
26
+ return [] if response.nil? || response['status'] != 200 || response.empty?
27
+
28
+ [response['result']]
29
+ end
30
+ end
31
+ end
@@ -8,23 +8,41 @@ module Geocoder::Lookup
8
8
  end
9
9
 
10
10
  def required_api_key_parts
11
- %w(auti-id auth-token)
11
+ %w(auth-id auth-token)
12
12
  end
13
13
 
14
- def query_url(query)
15
- path = zipcode_only?(query) ? "zipcode" : "street-address"
16
- "#{protocol}://api.smartystreets.com/#{path}?#{url_query_string(query)}"
14
+ # required by API as of 26 March 2015
15
+ def supported_protocols
16
+ [:https]
17
17
  end
18
18
 
19
19
  private # ---------------------------------------------------------------
20
20
 
21
+ def base_query_url(query)
22
+ if international?(query)
23
+ "#{protocol}://international-street.api.smartystreets.com/verify?"
24
+ elsif zipcode_only?(query)
25
+ "#{protocol}://us-zipcode.api.smartystreets.com/lookup?"
26
+ else
27
+ "#{protocol}://us-street.api.smartystreets.com/street-address?"
28
+ end
29
+ end
30
+
21
31
  def zipcode_only?(query)
22
32
  !query.text.is_a?(Array) and query.to_s.strip =~ /\A\d{5}(-\d{4})?\Z/
23
33
  end
24
34
 
35
+ def international?(query)
36
+ !query.options[:country].nil?
37
+ end
38
+
25
39
  def query_url_params(query)
26
40
  params = {}
27
- if zipcode_only?(query)
41
+ if international?(query)
42
+ params[:freeform] = query.sanitized_text
43
+ params[:country] = query.options[:country]
44
+ params[:geocode] = true
45
+ elsif zipcode_only?(query)
28
46
  params[:zipcode] = query.sanitized_text
29
47
  else
30
48
  params[:street] = query.sanitized_text
@@ -8,20 +8,34 @@ module Geocoder::Lookup
8
8
  "Telize"
9
9
  end
10
10
 
11
+ def required_api_key_parts
12
+ configuration[:host] ? [] : ["key"]
13
+ end
14
+
11
15
  def query_url(query)
12
- #currently doesn't support HTTPS
13
- "http://www.telize.com/geoip/#{query.sanitized_text}"
16
+ if configuration[:host]
17
+ "#{protocol}://#{configuration[:host]}/location/#{query.sanitized_text}"
18
+ else
19
+ "#{protocol}://telize-v1.p.mashape.com/location/#{query.sanitized_text}?mashape-key=#{api_key}"
20
+ end
21
+ end
22
+
23
+ def supported_protocols
24
+ [].tap do |array|
25
+ array << :https
26
+ array << :http if configuration[:host]
27
+ end
14
28
  end
15
29
 
16
30
  private # ---------------------------------------------------------------
17
31
 
18
- def use_ssl?
19
- false
32
+ def cache_key(query)
33
+ query_url(query)[/(.*)\?.*/, 1]
20
34
  end
21
35
 
22
36
  def results(query)
23
- # don't look up a loopback address, just return the stored result
24
- 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?
25
39
  if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc)
26
40
  []
27
41
  else
@@ -34,7 +48,28 @@ module Geocoder::Lookup
34
48
  end
35
49
 
36
50
  def reserved_result(ip)
37
- {"message" => "Input string is not a valid IP address", "code" => 401}
51
+ {
52
+ "ip" => ip,
53
+ "latitude" => 0,
54
+ "longitude" => 0,
55
+ "city" => "",
56
+ "timezone" => "",
57
+ "asn" => 0,
58
+ "region" => "",
59
+ "offset" => 0,
60
+ "organization" => "",
61
+ "country_code" => "",
62
+ "country_code3" => "",
63
+ "postal_code" => "",
64
+ "continent_code" => "",
65
+ "country" => "",
66
+ "region_code" => ""
67
+ }
38
68
  end
69
+
70
+ def api_key
71
+ configuration.api_key
72
+ end
73
+
39
74
  end
40
75
  end
@@ -0,0 +1,59 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/tencent"
3
+
4
+ module Geocoder::Lookup
5
+ class Tencent < Base
6
+
7
+ def name
8
+ "Tencent"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def supported_protocols
16
+ [:https]
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://apis.map.qq.com/ws/geocoder/v1/?"
23
+ end
24
+
25
+ def content_key
26
+ 'result'
27
+ end
28
+
29
+ def results(query, reverse = false)
30
+ return [] unless doc = fetch_data(query)
31
+ case doc['status']
32
+ when 0
33
+ return [doc[content_key]]
34
+ when 311
35
+ raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
36
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid api key.")
37
+ when 310
38
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
39
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, invalid parameters.")
40
+ when 306
41
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
42
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, check response for more info.")
43
+ when 110
44
+ raise_error(Geocoder::RequestDenied, "request denied.") ||
45
+ Geocoder.log(:warn, "#{name} Geocoding API error: request source is not authorized.")
46
+ end
47
+ return []
48
+ end
49
+
50
+ def query_url_params(query)
51
+ {
52
+ (query.reverse_geocode? ? :location : :address) => query.sanitized_text,
53
+ :key => configuration.api_key,
54
+ :output => "json"
55
+ }.merge(super)
56
+ end
57
+
58
+ end
59
+ end