Add the map in search view
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -52,6 +52,7 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||
actor_type: result_type,
|
||||
radius: Map.get(args, :radius),
|
||||
location: Map.get(args, :location),
|
||||
bbox: Map.get(args, :bbox),
|
||||
minimum_visibility: Map.get(args, :minimum_visibility, :public),
|
||||
current_actor_id: Map.get(args, :current_actor_id),
|
||||
exclude_my_groups: Map.get(args, :exclude_my_groups, false),
|
||||
|
||||
@@ -189,6 +189,9 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
||||
description: "The target of the search (internal or global)"
|
||||
)
|
||||
|
||||
arg(:bbox, :string, description: "The bbox to search groups into")
|
||||
arg(:zoom, :integer, description: "The zoom level for searching groups")
|
||||
|
||||
arg(:page, :integer, default_value: 1, description: "Result page")
|
||||
arg(:limit, :integer, default_value: 10, description: "Results limit per page")
|
||||
|
||||
@@ -225,6 +228,9 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
||||
description: "Radius around the location to search in"
|
||||
)
|
||||
|
||||
arg(:bbox, :string, description: "The bbox to search events into")
|
||||
arg(:zoom, :integer, description: "The zoom level for searching events")
|
||||
|
||||
arg(:page, :integer, default_value: 1, description: "Result page")
|
||||
arg(:limit, :integer, default_value: 10, description: "Results limit per page")
|
||||
arg(:begins_on, :datetime, description: "Filter events by their start date")
|
||||
|
||||
@@ -512,7 +512,13 @@ defmodule Mobilizon.Actors do
|
||||
query
|
||||
|> distinct([q], q.id)
|
||||
|> actor_by_username_or_name_query(term)
|
||||
|> maybe_join_address(
|
||||
Keyword.get(options, :location),
|
||||
Keyword.get(options, :radius),
|
||||
Keyword.get(options, :bbox)
|
||||
)
|
||||
|> actors_for_location(Keyword.get(options, :location), Keyword.get(options, :radius))
|
||||
|> events_for_bounding_box(Keyword.get(options, :bbox))
|
||||
|> filter_by_type(Keyword.get(options, :actor_type, :Group))
|
||||
|> filter_by_minimum_visibility(Keyword.get(options, :minimum_visibility, :public))
|
||||
|> filter_suspended(false)
|
||||
@@ -1385,15 +1391,27 @@ defmodule Mobilizon.Actors do
|
||||
)
|
||||
end
|
||||
|
||||
@spec maybe_join_address(
|
||||
Ecto.Queryable.t(),
|
||||
String.t() | nil,
|
||||
integer() | nil,
|
||||
String.t() | nil
|
||||
) :: Ecto.Query.t()
|
||||
defp maybe_join_address(query, location, radius, bbox)
|
||||
when (is_valid_string(location) and not is_nil(radius)) or is_valid_string(bbox) do
|
||||
join(query, :inner, [q], a in Address, on: a.id == q.physical_address_id, as: :address)
|
||||
end
|
||||
|
||||
defp maybe_join_address(query, _location, _radius, _bbox), do: query
|
||||
|
||||
@spec actors_for_location(Ecto.Queryable.t(), String.t(), integer()) :: Ecto.Query.t()
|
||||
defp actors_for_location(query, location, radius)
|
||||
when is_valid_string(location) and not is_nil(radius) do
|
||||
{lon, lat} = Geohax.decode(location)
|
||||
point = Geo.WKT.decode!("SRID=4326;POINT(#{lon} #{lat})")
|
||||
|
||||
query
|
||||
|> join(:inner, [q], a in Address, on: a.id == q.physical_address_id, as: :address)
|
||||
|> where(
|
||||
where(
|
||||
query,
|
||||
[q],
|
||||
st_dwithin_in_meters(^point, as(:address).geom, ^(radius * 1000))
|
||||
)
|
||||
@@ -1401,6 +1419,36 @@ defmodule Mobilizon.Actors do
|
||||
|
||||
defp actors_for_location(query, _location, _radius), do: query
|
||||
|
||||
defp events_for_bounding_box(query, bbox) when is_valid_string(bbox) do
|
||||
[top_left, bottom_right] = String.split(bbox, ":")
|
||||
[ymax, xmin] = String.split(top_left, ",")
|
||||
[ymin, xmax] = String.split(bottom_right, ",")
|
||||
|
||||
where(
|
||||
query,
|
||||
[q, ..., a],
|
||||
fragment(
|
||||
"? @ ST_MakeEnvelope(?,?,?,?,?)",
|
||||
a.geom,
|
||||
^sanitize_bounding_box_params(xmin),
|
||||
^sanitize_bounding_box_params(ymin),
|
||||
^sanitize_bounding_box_params(xmax),
|
||||
^sanitize_bounding_box_params(ymax),
|
||||
"4326"
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
defp events_for_bounding_box(query, _args), do: query
|
||||
|
||||
@spec sanitize_bounding_box_params(String.t()) :: float()
|
||||
defp sanitize_bounding_box_params(param) do
|
||||
param
|
||||
|> String.trim()
|
||||
|> String.to_float()
|
||||
|> Float.floor(10)
|
||||
end
|
||||
|
||||
@spec person_query :: Ecto.Query.t()
|
||||
defp person_query do
|
||||
from(a in Actor, where: a.type == ^:Person)
|
||||
|
||||
@@ -534,7 +534,9 @@ defmodule Mobilizon.Events do
|
||||
|> events_for_languages(args)
|
||||
|> events_for_statuses(args)
|
||||
|> events_for_tags(args)
|
||||
|> maybe_join_address(args)
|
||||
|> events_for_location(args)
|
||||
|> events_for_bounding_box(args)
|
||||
|> filter_online(args)
|
||||
|> filter_draft()
|
||||
|> filter_local_or_from_followed_instances_events()
|
||||
@@ -1355,6 +1357,20 @@ defmodule Mobilizon.Events do
|
||||
|
||||
defp events_for_tags(query, _args), do: query
|
||||
|
||||
# We add the inner join on address only if we're going to use it in
|
||||
# events_for_location or events_for_bounding_box
|
||||
# So we're sure it's only being added once
|
||||
defp maybe_join_address(query, %{location: location, radius: radius})
|
||||
when is_valid_string(location) and not is_nil(radius) do
|
||||
join(query, :inner, [q], a in Address, on: a.id == q.physical_address_id, as: :address)
|
||||
end
|
||||
|
||||
defp maybe_join_address(query, %{bbox: bbox}) when is_valid_string(bbox) do
|
||||
join(query, :inner, [q], a in Address, on: a.id == q.physical_address_id, as: :address)
|
||||
end
|
||||
|
||||
defp maybe_join_address(query, _), do: query
|
||||
|
||||
@spec events_for_location(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
||||
defp events_for_location(query, %{radius: radius}) when is_nil(radius),
|
||||
do: query
|
||||
@@ -1364,9 +1380,8 @@ defmodule Mobilizon.Events do
|
||||
with {lon, lat} <- Geohax.decode(location),
|
||||
point <- Geo.WKT.decode!("SRID=4326;POINT(#{lon} #{lat})"),
|
||||
{{x_min, y_min}, {x_max, y_max}} <- search_box({lon, lat}, radius) do
|
||||
query
|
||||
|> join(:inner, [q], a in Address, on: a.id == q.physical_address_id, as: :address)
|
||||
|> where(
|
||||
where(
|
||||
query,
|
||||
[q, ..., a],
|
||||
st_x(a.geom) > ^x_min and st_x(a.geom) < ^x_max and
|
||||
st_y(a.geom) > ^y_min and st_y(a.geom) < ^y_max and
|
||||
@@ -1379,6 +1394,36 @@ defmodule Mobilizon.Events do
|
||||
|
||||
defp events_for_location(query, _args), do: query
|
||||
|
||||
defp events_for_bounding_box(query, %{bbox: bbox}) when is_valid_string(bbox) do
|
||||
[top_left, bottom_right] = String.split(bbox, ":")
|
||||
[ymax, xmin] = String.split(top_left, ",")
|
||||
[ymin, xmax] = String.split(bottom_right, ",")
|
||||
|
||||
where(
|
||||
query,
|
||||
[q, ..., a],
|
||||
fragment(
|
||||
"? @ ST_MakeEnvelope(?,?,?,?,?)",
|
||||
a.geom,
|
||||
^sanitize_bounding_box_params(xmin),
|
||||
^sanitize_bounding_box_params(ymin),
|
||||
^sanitize_bounding_box_params(xmax),
|
||||
^sanitize_bounding_box_params(ymax),
|
||||
"4326"
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
defp events_for_bounding_box(query, _args), do: query
|
||||
|
||||
@spec sanitize_bounding_box_params(String.t()) :: float()
|
||||
defp sanitize_bounding_box_params(param) do
|
||||
param
|
||||
|> String.trim()
|
||||
|> String.to_float()
|
||||
|> Float.floor(10)
|
||||
end
|
||||
|
||||
@spec search_box({float(), float()}, float()) :: {{float, float}, {float, float}}
|
||||
defp search_box({lon0, lat0}, radius) do
|
||||
km_per_lat_deg = 111.195
|
||||
|
||||
@@ -13,6 +13,7 @@ defmodule Mobilizon.Service.GlobalSearch.EventResult do
|
||||
:category,
|
||||
:tags,
|
||||
:organizer_actor,
|
||||
:participants
|
||||
:participants,
|
||||
:physical_address
|
||||
]
|
||||
end
|
||||
|
||||
@@ -40,7 +40,8 @@ defmodule Mobilizon.Service.GlobalSearch.SearchMobilizon do
|
||||
distance: if(options[:radius], do: "#{options[:radius]}_km", else: nil),
|
||||
count: options[:limit],
|
||||
start: (options[:page] - 1) * options[:limit],
|
||||
latlon: to_lat_lon(options[:location])
|
||||
latlon: to_lat_lon(options[:location]),
|
||||
bbox: options[:bbox]
|
||||
)
|
||||
|> Keyword.take([
|
||||
:search,
|
||||
@@ -53,6 +54,7 @@ defmodule Mobilizon.Service.GlobalSearch.SearchMobilizon do
|
||||
:distance,
|
||||
:sort,
|
||||
:statusOneOf,
|
||||
:bbox,
|
||||
:start,
|
||||
:count
|
||||
])
|
||||
@@ -86,7 +88,8 @@ defmodule Mobilizon.Service.GlobalSearch.SearchMobilizon do
|
||||
distance: if(options[:radius], do: "#{options[:radius]}_km", else: nil),
|
||||
count: options[:limit],
|
||||
start: (options[:page] - 1) * options[:limit],
|
||||
latlon: to_lat_lon(options[:location])
|
||||
latlon: to_lat_lon(options[:location]),
|
||||
bbox: options[:bbox]
|
||||
)
|
||||
|> Keyword.take([
|
||||
:search,
|
||||
@@ -95,7 +98,8 @@ defmodule Mobilizon.Service.GlobalSearch.SearchMobilizon do
|
||||
:distance,
|
||||
:sort,
|
||||
:start,
|
||||
:count
|
||||
:count,
|
||||
:bbox
|
||||
])
|
||||
|> Keyword.reject(fn {_key, val} -> is_nil(val) end)
|
||||
|
||||
@@ -138,6 +142,27 @@ defmodule Mobilizon.Service.GlobalSearch.SearchMobilizon do
|
||||
nil
|
||||
end
|
||||
|
||||
address =
|
||||
if data["location"] do
|
||||
%Address{
|
||||
id: data["location"]["id"],
|
||||
country: data["location"]["address"]["addressCountry"],
|
||||
locality: data["location"]["address"]["addressLocality"],
|
||||
region: data["location"]["address"]["addressRegion"],
|
||||
postal_code: data["location"]["address"]["postalCode"],
|
||||
street: data["location"]["address"]["streetAddress"],
|
||||
url: data["location"]["id"],
|
||||
description: data["location"]["name"],
|
||||
geom: %Geo.Point{
|
||||
coordinates:
|
||||
{data["location"]["location"]["lon"], data["location"]["location"]["lat"]},
|
||||
srid: 4326
|
||||
}
|
||||
}
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
%EventResult{
|
||||
id: data["id"],
|
||||
uuid: data["uuid"],
|
||||
@@ -153,6 +178,7 @@ defmodule Mobilizon.Service.GlobalSearch.SearchMobilizon do
|
||||
preferred_username: data["creator"]["name"],
|
||||
avatar: organizer_actor_avatar
|
||||
},
|
||||
physical_address: address,
|
||||
tags:
|
||||
Enum.map(data["tags"], fn tag ->
|
||||
tag = String.trim_leading(tag, "#")
|
||||
@@ -224,12 +250,7 @@ defmodule Mobilizon.Service.GlobalSearch.SearchMobilizon do
|
||||
defp to_lat_lon(nil), do: nil
|
||||
|
||||
defp to_lat_lon(location) do
|
||||
case Geohax.decode(location) do
|
||||
{lon, lat} ->
|
||||
"#{lat}:#{lon}"
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
{lon, lat} = Geohax.decode(location)
|
||||
"#{lat}:#{lon}"
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user