Merge branch 'fix-geospatials' into 'master'

fix-geospatials

See merge request framasoft/mobilizon!559
This commit is contained in:
Thomas Citharel 2020-09-21 15:08:09 +02:00
commit 07c1c0ed7e
15 changed files with 124 additions and 111 deletions

View file

@ -47,7 +47,8 @@ config :exvcr,
config :tesla, Mobilizon.Service.HTTP.ActivityPub, config :tesla, Mobilizon.Service.HTTP.ActivityPub,
adapter: Mobilizon.Service.HTTP.ActivityPub.Mock adapter: Mobilizon.Service.HTTP.ActivityPub.Mock
config :tesla, Mobilizon.Service.HTTP.BaseClient, adapter: Mobilizon.Service.HTTP.BaseClient.Mock config :tesla, Mobilizon.Service.HTTP.GeospatialClient,
adapter: Mobilizon.Service.HTTP.GeospatialClient.Mock
config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Mock config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Mock

View file

@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Geospatial.Addok do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Provider alias Mobilizon.Service.Geospatial.Provider
alias Mobilizon.Service.HTTP.BaseClient alias Mobilizon.Service.HTTP.GeospatialClient
require Logger require Logger
@ -21,16 +21,9 @@ defmodule Mobilizon.Service.Geospatial.Addok do
""" """
@spec geocode(String.t(), keyword()) :: list(Address.t()) @spec geocode(String.t(), keyword()) :: list(Address.t())
def geocode(lon, lat, options \\ []) do def geocode(lon, lat, options \\ []) do
url = build_url(:geocode, %{lon: lon, lat: lat}, options) :geocode
|> build_url(%{lon: lon, lat: lat}, options)
Logger.debug("Asking addok for addresses with #{url}") |> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ -> []
end
end end
@impl Provider @impl Provider
@ -39,15 +32,9 @@ defmodule Mobilizon.Service.Geospatial.Addok do
""" """
@spec search(String.t(), keyword()) :: list(Address.t()) @spec search(String.t(), keyword()) :: list(Address.t())
def search(q, options \\ []) do def search(q, options \\ []) do
url = build_url(:search, %{q: q}, options) :search
Logger.debug("Asking addok for addresses with #{url}") |> build_url(%{q: q}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ -> []
end
end end
@spec build_url(atom(), map(), list()) :: String.t() @spec build_url(atom(), map(), list()) :: String.t()
@ -66,6 +53,20 @@ defmodule Mobilizon.Service.Geospatial.Addok do
end end
end end
@spec fetch_features(String.t()) :: list(Address.t())
defp fetch_features(url) do
Logger.debug("Asking addok with #{url}")
with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ ->
Logger.error("Asking addok with #{url}")
[]
end
end
defp process_data(features) do defp process_data(features) do
features features
|> Enum.map(fn %{"geometry" => geometry, "properties" => properties} -> |> Enum.map(fn %{"geometry" => geometry, "properties" => properties} ->

View file

@ -7,7 +7,7 @@ defmodule Mobilizon.Service.Geospatial.GoogleMaps do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Provider alias Mobilizon.Service.Geospatial.Provider
alias Mobilizon.Service.HTTP.BaseClient alias Mobilizon.Service.HTTP.GeospatialClient
require Logger require Logger
@ -39,7 +39,7 @@ defmodule Mobilizon.Service.Geospatial.GoogleMaps do
Logger.debug("Asking Google Maps for reverse geocode with #{url}") Logger.debug("Asking Google Maps for reverse geocode with #{url}")
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url), with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"results" => results, "status" => "OK"} <- body do %{"results" => results, "status" => "OK"} <- body do
Enum.map(results, fn entry -> process_data(entry, options) end) Enum.map(results, fn entry -> process_data(entry, options) end)
else else
@ -58,7 +58,7 @@ defmodule Mobilizon.Service.Geospatial.GoogleMaps do
Logger.debug("Asking Google Maps for addresses with #{url}") Logger.debug("Asking Google Maps for addresses with #{url}")
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url), with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"results" => results, "status" => "OK"} <- body do %{"results" => results, "status" => "OK"} <- body do
results |> Enum.map(fn entry -> process_data(entry, options) end) results |> Enum.map(fn entry -> process_data(entry, options) end)
else else
@ -159,7 +159,7 @@ defmodule Mobilizon.Service.Geospatial.GoogleMaps do
Logger.debug("Asking Google Maps for details with #{url}") Logger.debug("Asking Google Maps for details with #{url}")
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url), with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"result" => %{"name" => name}, "status" => "OK"} <- body do %{"result" => %{"name" => name}, "status" => "OK"} <- body do
name name
else else

View file

@ -11,7 +11,7 @@ defmodule Mobilizon.Service.Geospatial.MapQuest do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Provider alias Mobilizon.Service.Geospatial.Provider
alias Mobilizon.Service.HTTP.BaseClient alias Mobilizon.Service.HTTP.GeospatialClient
require Logger require Logger
@ -36,7 +36,7 @@ defmodule Mobilizon.Service.Geospatial.MapQuest do
if is_nil(api_key), do: raise(ArgumentError, message: @api_key_missing_message) if is_nil(api_key), do: raise(ArgumentError, message: @api_key_missing_message)
with {:ok, %{status: 200, body: body}} <- with {:ok, %{status: 200, body: body}} <-
BaseClient.get( GeospatialClient.get(
"https://#{prefix}.mapquestapi.com/geocoding/v1/reverse?key=#{api_key}&location=#{ "https://#{prefix}.mapquestapi.com/geocoding/v1/reverse?key=#{api_key}&location=#{
lat lat
},#{lon}&maxResults=#{limit}" },#{lon}&maxResults=#{limit}"
@ -71,7 +71,7 @@ defmodule Mobilizon.Service.Geospatial.MapQuest do
Logger.debug("Asking MapQuest for addresses with #{url}") Logger.debug("Asking MapQuest for addresses with #{url}")
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url), with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"results" => results, "info" => %{"statuscode" => 0}} <- body do %{"results" => results, "info" => %{"statuscode" => 0}} <- body do
results |> Enum.map(&process_data/1) results |> Enum.map(&process_data/1)
else else

View file

@ -9,7 +9,7 @@ defmodule Mobilizon.Service.Geospatial.Mimirsbrunn do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Provider alias Mobilizon.Service.Geospatial.Provider
alias Mobilizon.Service.HTTP.BaseClient alias Mobilizon.Service.HTTP.GeospatialClient
require Logger require Logger
@ -23,15 +23,9 @@ defmodule Mobilizon.Service.Geospatial.Mimirsbrunn do
""" """
@spec geocode(number(), number(), keyword()) :: list(Address.t()) @spec geocode(number(), number(), keyword()) :: list(Address.t())
def geocode(lon, lat, options \\ []) do def geocode(lon, lat, options \\ []) do
url = build_url(:geocode, %{lon: lon, lat: lat}, options) :geocode
Logger.debug("Asking Mimirsbrunn for reverse geocoding with #{url}") |> build_url(%{lon: lon, lat: lat}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
{:ok, %{"features" => features}} <- Jason.decode(body) do
process_data(features)
else
_ -> []
end
end end
@impl Provider @impl Provider
@ -40,15 +34,9 @@ defmodule Mobilizon.Service.Geospatial.Mimirsbrunn do
""" """
@spec search(String.t(), keyword()) :: list(Address.t()) @spec search(String.t(), keyword()) :: list(Address.t())
def search(q, options \\ []) do def search(q, options \\ []) do
url = build_url(:search, %{q: q}, options) :search
Logger.debug("Asking Mimirsbrunn for addresses with #{url}") |> build_url(%{q: q}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
{:ok, %{"features" => features}} <- Jason.decode(body) do
process_data(features)
else
_ -> []
end
end end
@spec build_url(atom(), map(), list()) :: String.t() @spec build_url(atom(), map(), list()) :: String.t()
@ -68,6 +56,20 @@ defmodule Mobilizon.Service.Geospatial.Mimirsbrunn do
end end
end end
@spec fetch_features(String.t()) :: list(Address.t())
defp fetch_features(url) do
Logger.debug("Asking addok with #{url}")
with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ ->
Logger.error("Asking addok with #{url}")
[]
end
end
defp process_data(features) do defp process_data(features) do
features features
|> Enum.map(fn %{ |> Enum.map(fn %{

View file

@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Geospatial.Nominatim do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Provider alias Mobilizon.Service.Geospatial.Provider
alias Mobilizon.Service.HTTP.BaseClient alias Mobilizon.Service.HTTP.GeospatialClient
require Logger require Logger
@ -20,15 +20,9 @@ defmodule Mobilizon.Service.Geospatial.Nominatim do
""" """
@spec geocode(String.t(), keyword()) :: list(Address.t()) @spec geocode(String.t(), keyword()) :: list(Address.t())
def geocode(lon, lat, options \\ []) do def geocode(lon, lat, options \\ []) do
url = build_url(:geocode, %{lon: lon, lat: lat}, options) :geocode
Logger.debug("Asking Nominatim for geocode with #{url}") |> build_url(%{lon: lon, lat: lat}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
%{"features" => features} <- body do
features |> process_data() |> Enum.filter(& &1)
else
_ -> []
end
end end
@impl Provider @impl Provider
@ -37,15 +31,9 @@ defmodule Mobilizon.Service.Geospatial.Nominatim do
""" """
@spec search(String.t(), keyword()) :: list(Address.t()) @spec search(String.t(), keyword()) :: list(Address.t())
def search(q, options \\ []) do def search(q, options \\ []) do
url = build_url(:search, %{q: q}, options) :search
Logger.debug("Asking Nominatim for addresses with #{url}") |> build_url(%{q: q}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
%{"features" => features} <- body do
features |> process_data() |> Enum.filter(& &1)
else
_ -> []
end
end end
@spec build_url(atom(), map(), list()) :: String.t() @spec build_url(atom(), map(), list()) :: String.t()
@ -77,6 +65,20 @@ defmodule Mobilizon.Service.Geospatial.Nominatim do
if is_nil(api_key), do: url, else: url <> "&key=#{api_key}" if is_nil(api_key), do: url, else: url <> "&key=#{api_key}"
end end
@spec fetch_features(String.t()) :: list(Address.t())
defp fetch_features(url) do
Logger.debug("Asking Nominatim with #{url}")
with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"features" => features} <- body do
features |> process_data |> Enum.filter(& &1)
else
_ ->
Logger.error("Asking Nominatim with #{url}")
[]
end
end
defp process_data(features) do defp process_data(features) do
features features
|> Enum.map(fn %{ |> Enum.map(fn %{

View file

@ -7,7 +7,7 @@ defmodule Mobilizon.Service.Geospatial.Pelias do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Provider alias Mobilizon.Service.Geospatial.Provider
alias Mobilizon.Service.HTTP.BaseClient alias Mobilizon.Service.HTTP.GeospatialClient
require Logger require Logger
@ -21,15 +21,9 @@ defmodule Mobilizon.Service.Geospatial.Pelias do
""" """
@spec geocode(number(), number(), keyword()) :: list(Address.t()) @spec geocode(number(), number(), keyword()) :: list(Address.t())
def geocode(lon, lat, options \\ []) do def geocode(lon, lat, options \\ []) do
url = build_url(:geocode, %{lon: lon, lat: lat}, options) :geocode
Logger.debug("Asking Pelias for reverse geocoding with #{url}") |> build_url(%{lon: lon, lat: lat}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
{:ok, %{"features" => features}} <- Jason.decode(body) do
process_data(features)
else
_ -> []
end
end end
@impl Provider @impl Provider
@ -38,15 +32,9 @@ defmodule Mobilizon.Service.Geospatial.Pelias do
""" """
@spec search(String.t(), keyword()) :: list(Address.t()) @spec search(String.t(), keyword()) :: list(Address.t())
def search(q, options \\ []) do def search(q, options \\ []) do
url = build_url(:search, %{q: q}, options) :search
Logger.debug("Asking Pelias for addresses with #{url}") |> build_url(%{q: q}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
{:ok, %{"features" => features}} <- Jason.decode(body) do
process_data(features)
else
_ -> []
end
end end
@spec build_url(atom(), map(), list()) :: String.t() @spec build_url(atom(), map(), list()) :: String.t()
@ -74,6 +62,20 @@ defmodule Mobilizon.Service.Geospatial.Pelias do
if is_nil(country_code), do: url, else: "#{url}&boundary.country=#{country_code}" if is_nil(country_code), do: url, else: "#{url}&boundary.country=#{country_code}"
end end
@spec fetch_features(String.t()) :: list(Address.t())
defp fetch_features(url) do
Logger.debug("Asking pelias with #{url}")
with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ ->
Logger.error("Asking pelias with #{url}")
[]
end
end
defp process_data(features) do defp process_data(features) do
features features
|> Enum.map(fn %{ |> Enum.map(fn %{

View file

@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Geospatial.Photon do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Provider alias Mobilizon.Service.Geospatial.Provider
alias Mobilizon.Service.HTTP.BaseClient alias Mobilizon.Service.HTTP.GeospatialClient
require Logger require Logger
@ -21,15 +21,9 @@ defmodule Mobilizon.Service.Geospatial.Photon do
""" """
@spec geocode(number(), number(), keyword()) :: list(Address.t()) @spec geocode(number(), number(), keyword()) :: list(Address.t())
def geocode(lon, lat, options \\ []) do def geocode(lon, lat, options \\ []) do
url = build_url(:geocode, %{lon: lon, lat: lat}, options) :geocode
Logger.debug("Asking photon for reverse geocoding with #{url}") |> build_url(%{lon: lon, lat: lat}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ -> []
end
end end
@impl Provider @impl Provider
@ -38,15 +32,9 @@ defmodule Mobilizon.Service.Geospatial.Photon do
""" """
@spec search(String.t(), keyword()) :: list(Address.t()) @spec search(String.t(), keyword()) :: list(Address.t())
def search(q, options \\ []) do def search(q, options \\ []) do
url = build_url(:search, %{q: q}, options) :search
Logger.debug("Asking photon for addresses with #{url}") |> build_url(%{q: q}, options)
|> fetch_features
with {:ok, %{status: 200, body: body}} <- BaseClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ -> []
end
end end
@spec build_url(atom(), map(), list()) :: String.t() @spec build_url(atom(), map(), list()) :: String.t()
@ -66,6 +54,20 @@ defmodule Mobilizon.Service.Geospatial.Photon do
end end
end end
@spec fetch_features(String.t()) :: list(Address.t())
defp fetch_features(url) do
Logger.debug("Asking photon with #{url}")
with {:ok, %{status: 200, body: body}} <- GeospatialClient.get(url),
%{"features" => features} <- body do
process_data(features)
else
_ ->
Logger.error("Asking photon with #{url}")
[]
end
end
defp process_data(features) do defp process_data(features) do
features features
|> Enum.map(fn %{"geometry" => geometry, "properties" => properties} -> |> Enum.map(fn %{"geometry" => geometry, "properties" => properties} ->

View file

@ -1,6 +1,7 @@
defmodule Mobilizon.Service.HTTP.BaseClient do defmodule Mobilizon.Service.HTTP.GeospatialClient do
@moduledoc """ @moduledoc """
Tesla HTTP Basic Client Tesla HTTP Basic Client
with JSON middleware
""" """
use Tesla use Tesla
@ -19,4 +20,6 @@ defmodule Mobilizon.Service.HTTP.BaseClient do
plug(Tesla.Middleware.Timeout, timeout: 10_000) plug(Tesla.Middleware.Timeout, timeout: 10_000)
plug(Tesla.Middleware.Headers, [{"User-Agent", @user_agent}]) plug(Tesla.Middleware.Headers, [{"User-Agent", @user_agent}])
plug(Tesla.Middleware.JSON)
end end

View file

@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Geospatial.AddokTest do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Addok alias Mobilizon.Service.Geospatial.Addok
alias Mobilizon.Service.HTTP.BaseClient.Mock alias Mobilizon.Service.HTTP.GeospatialClient.Mock
describe "search address" do describe "search address" do
test "returns a valid address from search" do test "returns a valid address from search" do

View file

@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Geospatial.GoogleMapsTest do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.GoogleMaps alias Mobilizon.Service.Geospatial.GoogleMaps
alias Mobilizon.Service.HTTP.BaseClient.Mock alias Mobilizon.Service.HTTP.GeospatialClient.Mock
describe "search address" do describe "search address" do
test "without API Key triggers an error" do test "without API Key triggers an error" do

View file

@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Geospatial.MapQuestTest do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.MapQuest alias Mobilizon.Service.Geospatial.MapQuest
alias Mobilizon.Service.HTTP.BaseClient.Mock alias Mobilizon.Service.HTTP.GeospatialClient.Mock
describe "search address" do describe "search address" do
test "without API Key triggers an error" do test "without API Key triggers an error" do

View file

@ -4,7 +4,7 @@ defmodule Mobilizon.Service.Geospatial.NominatimTest do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Nominatim alias Mobilizon.Service.Geospatial.Nominatim
alias Mobilizon.Service.HTTP.BaseClient.Mock alias Mobilizon.Service.HTTP.GeospatialClient.Mock
describe "search address" do describe "search address" do
test "returns a valid address from search" do test "returns a valid address from search" do

View file

@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Geospatial.PhotonTest do
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial.Photon alias Mobilizon.Service.Geospatial.Photon
alias Mobilizon.Service.HTTP.BaseClient.Mock alias Mobilizon.Service.HTTP.GeospatialClient.Mock
describe "search address" do describe "search address" do
test "returns a valid address from search" do test "returns a valid address from search" do

View file

@ -75,5 +75,5 @@ defmodule Mobilizon.DataCase do
end end
Mox.defmock(Mobilizon.Service.HTTP.ActivityPub.Mock, for: Tesla.Adapter) Mox.defmock(Mobilizon.Service.HTTP.ActivityPub.Mock, for: Tesla.Adapter)
Mox.defmock(Mobilizon.Service.HTTP.BaseClient.Mock, for: Tesla.Adapter) Mox.defmock(Mobilizon.Service.HTTP.GeospatialClient.Mock, for: Tesla.Adapter)
end end