d66bbc5414
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
109 lines
3.2 KiB
Elixir
109 lines
3.2 KiB
Elixir
defmodule MobilizonWeb.API.Search do
|
|
@moduledoc """
|
|
API for Search
|
|
"""
|
|
alias Mobilizon.Service.ActivityPub
|
|
alias Mobilizon.Actors
|
|
alias Mobilizon.Actors.Actor
|
|
alias Mobilizon.Events
|
|
alias Mobilizon.Events.{Event, Comment}
|
|
|
|
require Logger
|
|
|
|
@doc """
|
|
Search actors
|
|
"""
|
|
@spec search_actors(String.t(), integer(), integer(), String.t()) ::
|
|
{:ok, %{total: integer(), elements: list(Actor.t())}} | {:error, any()}
|
|
def search_actors(search, page \\ 1, limit \\ 10, result_type) do
|
|
search = String.trim(search)
|
|
|
|
cond do
|
|
search == "" ->
|
|
{:error, "Search can't be empty"}
|
|
|
|
# Some URLs could be domain.tld/@username, so keep this condition above handle_search? function
|
|
url_search?(search) ->
|
|
# If this is not an actor, skip
|
|
with %{:total => total, :elements => [%Actor{}] = elements} <- process_from_url(search) do
|
|
{:ok, %{total: total, elements: elements}}
|
|
else
|
|
_ ->
|
|
{:ok, %{total: 0, elements: []}}
|
|
end
|
|
|
|
handle_search?(search) ->
|
|
{:ok, process_from_username(search)}
|
|
|
|
true ->
|
|
{:ok,
|
|
Actors.find_and_count_actors_by_username_or_name(search, [result_type], page, limit)}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Search events
|
|
"""
|
|
@spec search_events(String.t(), integer(), integer()) ::
|
|
{:ok, %{total: integer(), elements: list(Event.t())}} | {:error, any()}
|
|
def search_events(search, page \\ 1, limit \\ 10) do
|
|
search = String.trim(search)
|
|
|
|
cond do
|
|
search == "" ->
|
|
{:error, "Search can't be empty"}
|
|
|
|
url_search?(search) ->
|
|
# If this is not an event, skip
|
|
with {total = total, [%Event{} = elements]} <- process_from_url(search) do
|
|
{:ok, %{total: total, elements: elements}}
|
|
else
|
|
_ ->
|
|
{:ok, %{total: 0, elements: []}}
|
|
end
|
|
|
|
true ->
|
|
{:ok, Events.find_and_count_events_by_name(search, page, limit)}
|
|
end
|
|
end
|
|
|
|
# If the search string is an username
|
|
@spec process_from_username(String.t()) :: %{total: integer(), elements: [Actor.t()]}
|
|
defp process_from_username(search) do
|
|
with {:ok, actor} <- ActivityPub.find_or_make_actor_from_nickname(search) do
|
|
%{total: 1, elements: [actor]}
|
|
else
|
|
{:error, _err} ->
|
|
Logger.debug(fn -> "Unable to find or make actor '#{search}'" end)
|
|
%{total: 0, elements: []}
|
|
end
|
|
end
|
|
|
|
# If the search string is an URL
|
|
@spec process_from_url(String.t()) :: %{
|
|
total: integer(),
|
|
elements: [Actor.t() | Event.t() | Comment.t()]
|
|
}
|
|
defp process_from_url(search) do
|
|
with {:ok, object} <- ActivityPub.fetch_object_from_url(search) do
|
|
%{total: 1, elements: [object]}
|
|
else
|
|
{:error, _err} ->
|
|
Logger.debug(fn -> "Unable to find or make object from URL '#{search}'" end)
|
|
%{total: 0, elements: []}
|
|
end
|
|
end
|
|
|
|
# Is the search an URL search?
|
|
@spec url_search?(String.t()) :: boolean
|
|
defp url_search?(search) do
|
|
String.starts_with?(search, "https://") or String.starts_with?(search, "http://")
|
|
end
|
|
|
|
# Is the search an handle search?
|
|
@spec handle_search?(String.t()) :: boolean
|
|
defp handle_search?(search) do
|
|
String.match?(search, ~r/@/)
|
|
end
|
|
end
|