2020-01-26 21:11:16 +01:00
|
|
|
defmodule Mobilizon.GraphQL.API.Search do
|
2019-02-22 14:18:52 +01:00
|
|
|
@moduledoc """
|
2019-09-09 00:52:49 +02:00
|
|
|
API for search.
|
2019-02-22 14:18:52 +01:00
|
|
|
"""
|
2019-09-09 00:52:49 +02:00
|
|
|
|
2019-02-21 18:11:49 +01:00
|
|
|
alias Mobilizon.Actors
|
2020-10-02 16:18:11 +02:00
|
|
|
alias Mobilizon.Actors.{Actor, ActorType}
|
2019-02-21 18:11:49 +01:00
|
|
|
alias Mobilizon.Events
|
2020-10-02 16:18:11 +02:00
|
|
|
alias Mobilizon.Events.Event
|
2019-09-09 00:52:49 +02:00
|
|
|
alias Mobilizon.Storage.Page
|
2019-02-21 18:11:49 +01:00
|
|
|
|
2020-01-22 02:14:42 +01:00
|
|
|
alias Mobilizon.Federation.ActivityPub
|
|
|
|
|
2019-02-21 18:11:49 +01:00
|
|
|
require Logger
|
|
|
|
|
|
|
|
@doc """
|
2019-09-09 00:52:49 +02:00
|
|
|
Searches actors.
|
2019-02-21 18:11:49 +01:00
|
|
|
"""
|
2020-08-05 16:44:08 +02:00
|
|
|
@spec search_actors(map(), integer | nil, integer | nil, ActorType.t()) ::
|
2019-09-09 00:52:49 +02:00
|
|
|
{:ok, Page.t()} | {:error, String.t()}
|
2020-08-05 16:44:08 +02:00
|
|
|
def search_actors(%{term: term} = args, page \\ 1, limit \\ 10, result_type) do
|
|
|
|
term = String.trim(term)
|
2019-02-21 18:11:49 +01:00
|
|
|
|
2019-04-12 15:04:32 +02:00
|
|
|
cond do
|
2019-09-09 00:52:49 +02:00
|
|
|
# Some URLs could be domain.tld/@username, so keep this condition above
|
|
|
|
# the `is_handle` function
|
2020-08-05 16:44:08 +02:00
|
|
|
is_url(term) ->
|
2019-09-09 00:52:49 +02:00
|
|
|
# skip, if it's not an actor
|
2020-08-05 16:44:08 +02:00
|
|
|
case process_from_url(term) do
|
2020-10-02 16:18:11 +02:00
|
|
|
%Page{total: _total, elements: [%Actor{} = _actor]} = page ->
|
2019-09-09 00:52:49 +02:00
|
|
|
{:ok, page}
|
2019-07-23 18:06:22 +02:00
|
|
|
|
2019-04-12 15:04:32 +02:00
|
|
|
_ ->
|
|
|
|
{:ok, %{total: 0, elements: []}}
|
|
|
|
end
|
|
|
|
|
2020-08-05 16:44:08 +02:00
|
|
|
is_handle(term) ->
|
|
|
|
{:ok, process_from_username(term)}
|
2019-04-12 15:04:32 +02:00
|
|
|
|
|
|
|
true ->
|
2020-08-05 16:44:08 +02:00
|
|
|
page =
|
|
|
|
Actors.build_actors_by_username_or_name_page(
|
|
|
|
Map.put(args, :term, term),
|
|
|
|
[result_type],
|
|
|
|
page,
|
|
|
|
limit
|
|
|
|
)
|
2019-09-09 00:52:49 +02:00
|
|
|
|
|
|
|
{:ok, page}
|
2019-04-12 15:04:32 +02:00
|
|
|
end
|
2019-02-21 18:11:49 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
2019-04-12 15:04:32 +02:00
|
|
|
Search events
|
2019-02-21 18:11:49 +01:00
|
|
|
"""
|
2019-09-09 00:52:49 +02:00
|
|
|
@spec search_events(String.t(), integer | nil, integer | nil) ::
|
|
|
|
{:ok, Page.t()} | {:error, String.t()}
|
2020-07-31 17:52:26 +02:00
|
|
|
def search_events(%{term: term} = args, page \\ 1, limit \\ 10) do
|
|
|
|
term = String.trim(term)
|
|
|
|
|
|
|
|
if is_url(term) do
|
|
|
|
# skip, if it's w not an actor
|
|
|
|
case process_from_url(term) do
|
2020-10-02 16:18:11 +02:00
|
|
|
%Page{total: _total, elements: [%Event{} = _event]} = page ->
|
2020-07-31 17:52:26 +02:00
|
|
|
{:ok, page}
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
{:ok, %{total: 0, elements: []}}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
{:ok, Events.build_events_for_search(Map.put(args, :term, term), page, limit)}
|
2019-02-21 18:11:49 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-06 11:34:32 +01:00
|
|
|
def interact(uri) do
|
|
|
|
case ActivityPub.fetch_object_from_url(uri) do
|
|
|
|
{:ok, object} ->
|
|
|
|
{:ok, object}
|
|
|
|
|
|
|
|
{:error, _err} ->
|
|
|
|
Logger.debug(fn -> "Unable to find or make object from URI '#{uri}'" end)
|
|
|
|
|
|
|
|
{:error, :not_found}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-02-21 18:11:49 +01:00
|
|
|
# If the search string is an username
|
2019-09-09 00:52:49 +02:00
|
|
|
@spec process_from_username(String.t()) :: Page.t()
|
2019-02-21 18:11:49 +01:00
|
|
|
defp process_from_username(search) do
|
2019-07-23 18:06:22 +02:00
|
|
|
case ActivityPub.find_or_make_actor_from_nickname(search) do
|
|
|
|
{:ok, actor} ->
|
2019-09-09 00:52:49 +02:00
|
|
|
%Page{total: 1, elements: [actor]}
|
2019-07-23 18:06:22 +02:00
|
|
|
|
2019-02-21 18:11:49 +01:00
|
|
|
{:error, _err} ->
|
2019-02-22 14:18:52 +01:00
|
|
|
Logger.debug(fn -> "Unable to find or make actor '#{search}'" end)
|
2019-09-09 00:52:49 +02:00
|
|
|
|
|
|
|
%Page{total: 0, elements: []}
|
2019-02-21 18:11:49 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# If the search string is an URL
|
2019-09-09 00:52:49 +02:00
|
|
|
@spec process_from_url(String.t()) :: Page.t()
|
2019-02-21 18:11:49 +01:00
|
|
|
defp process_from_url(search) do
|
2019-07-23 18:06:22 +02:00
|
|
|
case ActivityPub.fetch_object_from_url(search) do
|
|
|
|
{:ok, object} ->
|
2019-09-09 00:52:49 +02:00
|
|
|
%Page{total: 1, elements: [object]}
|
2019-07-23 18:06:22 +02:00
|
|
|
|
2019-02-21 18:11:49 +01:00
|
|
|
{:error, _err} ->
|
2019-02-22 14:18:52 +01:00
|
|
|
Logger.debug(fn -> "Unable to find or make object from URL '#{search}'" end)
|
2019-09-09 00:52:49 +02:00
|
|
|
|
|
|
|
%Page{total: 0, elements: []}
|
2019-02-21 18:11:49 +01:00
|
|
|
end
|
|
|
|
end
|
2019-04-12 15:04:32 +02:00
|
|
|
|
2019-09-09 00:52:49 +02:00
|
|
|
@spec is_url(String.t()) :: boolean
|
|
|
|
defp is_url(search), do: String.starts_with?(search, ["http://", "https://"])
|
2019-04-12 15:04:32 +02:00
|
|
|
|
2019-09-09 00:52:49 +02:00
|
|
|
@spec is_handle(String.t()) :: boolean
|
|
|
|
defp is_handle(search), do: String.match?(search, ~r/@/)
|
2019-02-21 18:11:49 +01:00
|
|
|
end
|