Add the map in search view

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2022-09-01 10:00:17 +02:00
parent b36ce27bbe
commit eecb04516e
26 changed files with 1507 additions and 329 deletions

View File

@@ -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),

View File

@@ -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")

View File

@@ -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)

View File

@@ -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

View File

@@ -13,6 +13,7 @@ defmodule Mobilizon.Service.GlobalSearch.EventResult do
:category,
:tags,
:organizer_actor,
:participants
:participants,
:physical_address
]
end

View File

@@ -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