Allow events to be searched by location and period
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -239,8 +239,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||
def handle_incoming(
|
||||
%{
|
||||
"type" => activity_type,
|
||||
"object" => %{"type" => object_type, "id" => object_url} = object,
|
||||
"to" => to
|
||||
"object" => %{"type" => object_type, "id" => object_url} = object
|
||||
} = data
|
||||
)
|
||||
when activity_type in ["Create", "Add"] and
|
||||
|
||||
@@ -51,25 +51,20 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||
"""
|
||||
@spec search_events(String.t(), integer | nil, integer | nil) ::
|
||||
{:ok, Page.t()} | {:error, String.t()}
|
||||
def search_events(search, page \\ 1, limit \\ 10) do
|
||||
search = String.trim(search)
|
||||
def search_events(%{term: term} = args, page \\ 1, limit \\ 10) do
|
||||
term = String.trim(term)
|
||||
|
||||
cond do
|
||||
search == "" ->
|
||||
{:error, "Search can't be empty"}
|
||||
if is_url(term) do
|
||||
# skip, if it's w not an actor
|
||||
case process_from_url(term) do
|
||||
%Page{total: _total, elements: _elements} = page ->
|
||||
{:ok, page}
|
||||
|
||||
is_url(search) ->
|
||||
# skip, if it's w not an actor
|
||||
case process_from_url(search) do
|
||||
%Page{total: _total, elements: _elements} = page ->
|
||||
{:ok, page}
|
||||
|
||||
_ ->
|
||||
{:ok, %{total: 0, elements: []}}
|
||||
end
|
||||
|
||||
true ->
|
||||
{:ok, Events.build_events_for_search(search, page, limit)}
|
||||
_ ->
|
||||
{:ok, %{total: 0, elements: []}}
|
||||
end
|
||||
else
|
||||
{:ok, Events.build_events_for_search(Map.put(args, :term, term), page, limit)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Search do
|
||||
@doc """
|
||||
Search events
|
||||
"""
|
||||
def search_events(_parent, %{search: search, page: page, limit: limit}, _resolution) do
|
||||
Search.search_events(search, page, limit)
|
||||
def search_events(_parent, %{page: page, limit: limit} = args, _resolution) do
|
||||
Search.search_events(args, page, limit)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,7 +45,10 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
||||
|
||||
@desc "Search events"
|
||||
field :search_events, :events do
|
||||
arg(:search, non_null(:string))
|
||||
arg(:term, :string, default_value: "")
|
||||
arg(:tag, :string)
|
||||
arg(:location, :string, description: "A geohash for coordinates")
|
||||
arg(:radius, :float, default_value: 50)
|
||||
arg(:page, :integer, default_value: 1)
|
||||
arg(:limit, :integer, default_value: 10)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ defmodule Mobilizon.Events do
|
||||
import Ecto.Query
|
||||
import EctoEnum
|
||||
|
||||
import Mobilizon.Service.Guards
|
||||
import Mobilizon.Storage.Ecto
|
||||
|
||||
alias Ecto.{Changeset, Multi}
|
||||
@@ -457,14 +458,13 @@ defmodule Mobilizon.Events do
|
||||
@doc """
|
||||
Builds a page struct for events by their name.
|
||||
"""
|
||||
@spec build_events_for_search(String.t(), integer | nil, integer | nil) :: Page.t()
|
||||
def build_events_for_search(name, page \\ nil, limit \\ nil)
|
||||
def build_events_for_search("", _page, _limit), do: %Page{total: 0, elements: []}
|
||||
|
||||
def build_events_for_search(name, page, limit) do
|
||||
name
|
||||
@spec build_events_for_search(map(), integer | nil, integer | nil) :: Page.t()
|
||||
def build_events_for_search(%{term: term} = args, page \\ nil, limit \\ nil) do
|
||||
term
|
||||
|> normalize_search_string()
|
||||
|> events_for_search_query()
|
||||
|> events_for_tag(args)
|
||||
|> events_for_location(args)
|
||||
|> filter_local_or_from_followed_instances_events()
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
@@ -1283,6 +1283,8 @@ defmodule Mobilizon.Events do
|
||||
end
|
||||
|
||||
@spec do_event_for_search_query(Ecto.Query.t(), String.t()) :: Ecto.Query.t()
|
||||
# defp do_event_for_search_query(query, ""), do: query
|
||||
|
||||
defp do_event_for_search_query(query, search_string) do
|
||||
from(event in query,
|
||||
join: id_and_rank in matching_event_ids_and_ranks(search_string),
|
||||
@@ -1291,6 +1293,34 @@ defmodule Mobilizon.Events do
|
||||
)
|
||||
end
|
||||
|
||||
@spec events_for_tag(Ecto.Query.t(), map()) :: Ecto.Query.t()
|
||||
defp events_for_tag(query, %{tag: tag}) when not is_nil(tag) and tag != "" do
|
||||
query
|
||||
|> join(:inner, [q, _r], te in "events_tags", on: q.id == te.event_id)
|
||||
|> join(:inner, [q, _r, te], t in Tag, on: te.tag_id == t.id)
|
||||
|> where([q, _r, te, t], t.title == ^tag)
|
||||
end
|
||||
|
||||
defp events_for_tag(query, _args), do: query
|
||||
|
||||
@spec events_for_location(Ecto.Query.t(), map()) :: Ecto.Query.t()
|
||||
defp events_for_location(query, %{location: location, radius: radius})
|
||||
when not is_nil_or_empty_string(location) and not is_nil(radius) do
|
||||
with {lon, lat} <- Geohax.decode(location),
|
||||
point <- Geo.WKT.decode!("SRID=4326;POINT(#{lon} #{lat})") do
|
||||
query
|
||||
|> join(:inner, [q], a in Address, on: a.id == q.physical_address_id, as: :address)
|
||||
|> where(
|
||||
[q],
|
||||
st_dwithin_in_meters(^point, as(:address).geom, ^(radius * 1000))
|
||||
)
|
||||
else
|
||||
_ -> query
|
||||
end
|
||||
end
|
||||
|
||||
defp events_for_location(query, _args), do: query
|
||||
|
||||
@spec normalize_search_string(String.t()) :: String.t()
|
||||
defp normalize_search_string(search_string) do
|
||||
search_string
|
||||
|
||||
7
lib/service/guards.ex
Normal file
7
lib/service/guards.ex
Normal file
@@ -0,0 +1,7 @@
|
||||
defmodule Mobilizon.Service.Guards do
|
||||
@moduledoc """
|
||||
Various guards
|
||||
"""
|
||||
|
||||
defguard is_nil_or_empty_string(value) when is_nil(value) or value == ""
|
||||
end
|
||||
Reference in New Issue
Block a user