feat: allow to filter events by local-only
In addition to internal (self + federated) and global (global external search engine), introduce the self possibility Closes #1322 Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
d1b1979ee5
commit
9d99684402
|
@ -1,2 +1,2 @@
|
||||||
elixir 1.15.5-otp-26
|
erlang 26.2.2
|
||||||
erlang 26.0.2
|
elixir 1.16.1-otp-26
|
||||||
|
|
|
@ -56,7 +56,8 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||||
minimum_visibility: Map.get(args, :minimum_visibility, :public),
|
minimum_visibility: Map.get(args, :minimum_visibility, :public),
|
||||||
current_actor_id: Map.get(args, :current_actor_id),
|
current_actor_id: Map.get(args, :current_actor_id),
|
||||||
exclude_my_groups: Map.get(args, :exclude_my_groups, false),
|
exclude_my_groups: Map.get(args, :exclude_my_groups, false),
|
||||||
exclude_stale_actors: true
|
exclude_stale_actors: true,
|
||||||
|
local_only: Map.get(args, :search_target, :internal) == :self
|
||||||
],
|
],
|
||||||
page,
|
page,
|
||||||
limit
|
limit
|
||||||
|
@ -94,7 +95,13 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||||
|
|
||||||
{:ok, service.search_events(Keyword.new(args, fn {k, v} -> {k, v} end))}
|
{:ok, service.search_events(Keyword.new(args, fn {k, v} -> {k, v} end))}
|
||||||
else
|
else
|
||||||
{:ok, Events.build_events_for_search(Map.put(args, :term, term), page, limit)}
|
results =
|
||||||
|
args
|
||||||
|
|> Map.put(:term, term)
|
||||||
|
|> Map.put(:local_only, Map.get(args, :search_target, :internal) == :self)
|
||||||
|
|> Events.build_events_for_search(page, limit)
|
||||||
|
|
||||||
|
{:ok, results}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -160,6 +160,8 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
||||||
end
|
end
|
||||||
|
|
||||||
enum :search_target do
|
enum :search_target do
|
||||||
|
value(:self, description: "Search only on content from this instance")
|
||||||
|
|
||||||
value(:internal,
|
value(:internal,
|
||||||
description: "Search on content from this instance and from the followed instances"
|
description: "Search on content from this instance and from the followed instances"
|
||||||
)
|
)
|
||||||
|
|
|
@ -525,6 +525,7 @@ defmodule Mobilizon.Actors do
|
||||||
Keyword.get(options, :radius),
|
Keyword.get(options, :radius),
|
||||||
Keyword.get(options, :bbox)
|
Keyword.get(options, :bbox)
|
||||||
)
|
)
|
||||||
|
|> filter_by_local_only(Keyword.get(options, :local_only, false))
|
||||||
|> actors_for_location(Keyword.get(options, :location), Keyword.get(options, :radius))
|
|> actors_for_location(Keyword.get(options, :location), Keyword.get(options, :radius))
|
||||||
|> events_for_bounding_box(Keyword.get(options, :bbox))
|
|> events_for_bounding_box(Keyword.get(options, :bbox))
|
||||||
|> filter_by_type(Keyword.get(options, :actor_type, :Group))
|
|> filter_by_type(Keyword.get(options, :actor_type, :Group))
|
||||||
|
@ -1418,6 +1419,13 @@ defmodule Mobilizon.Actors do
|
||||||
|
|
||||||
defp maybe_join_address(query, _location, _radius, _bbox), do: query
|
defp maybe_join_address(query, _location, _radius, _bbox), do: query
|
||||||
|
|
||||||
|
@spec filter_by_local_only(Ecto.Queryable.t(), boolean()) :: Ecto.Query.t()
|
||||||
|
defp filter_by_local_only(query, true) do
|
||||||
|
where(query, [q], is_nil(q.domain))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp filter_by_local_only(query, false), do: query
|
||||||
|
|
||||||
@spec actors_for_location(Ecto.Queryable.t(), String.t(), integer()) :: Ecto.Query.t()
|
@spec actors_for_location(Ecto.Queryable.t(), String.t(), integer()) :: Ecto.Query.t()
|
||||||
defp actors_for_location(query, location, radius)
|
defp actors_for_location(query, location, radius)
|
||||||
when is_valid_string(location) and not is_nil(radius) do
|
when is_valid_string(location) and not is_nil(radius) do
|
||||||
|
|
|
@ -581,6 +581,7 @@ defmodule Mobilizon.Events do
|
||||||
|> events_for_bounding_box(args)
|
|> events_for_bounding_box(args)
|
||||||
|> filter_online(args)
|
|> filter_online(args)
|
||||||
|> filter_draft()
|
|> filter_draft()
|
||||||
|
|> filter_local(if Map.get(args, :local_only, nil) == true, do: true, else: nil)
|
||||||
|> filter_local_or_from_followed_instances_events()
|
|> filter_local_or_from_followed_instances_events()
|
||||||
|> filter_public_visibility()
|
|> filter_public_visibility()
|
||||||
|> event_order(Map.get(args, :sort_by, :match_desc), search_string)
|
|> event_order(Map.get(args, :sort_by, :match_desc), search_string)
|
||||||
|
|
|
@ -293,6 +293,7 @@ export enum InstanceFollowStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SearchTargets {
|
export enum SearchTargets {
|
||||||
|
SELF = "SELF",
|
||||||
INTERNAL = "INTERNAL",
|
INTERNAL = "INTERNAL",
|
||||||
GLOBAL = "GLOBAL",
|
GLOBAL = "GLOBAL",
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,22 @@
|
||||||
<fieldset class="flex flex-col">
|
<fieldset class="flex flex-col">
|
||||||
<legend class="sr-only">{{ t("Search target") }}</legend>
|
<legend class="sr-only">{{ t("Search target") }}</legend>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
id="selfTarget"
|
||||||
|
v-model="searchTarget"
|
||||||
|
type="radio"
|
||||||
|
name="selfTarget"
|
||||||
|
:value="SearchTargets.SELF"
|
||||||
|
class="w-4 h-4 border-gray-300 focus:ring-2 focus:ring-blue-300 dark:focus:ring-blue-600 dark:focus:bg-blue-600 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="selfTarget"
|
||||||
|
class="ml-3 font-medium text-gray-900 dark:text-gray-300"
|
||||||
|
>{{ t("From this instance only") }}</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
id="internalTarget"
|
id="internalTarget"
|
||||||
|
|
|
@ -55,7 +55,8 @@ defmodule Mobilizon.GraphQL.API.SearchTest do
|
||||||
minimum_visibility: :public,
|
minimum_visibility: :public,
|
||||||
current_actor_id: nil,
|
current_actor_id: nil,
|
||||||
exclude_my_groups: false,
|
exclude_my_groups: false,
|
||||||
exclude_stale_actors: true
|
exclude_stale_actors: true,
|
||||||
|
local_only: false
|
||||||
],
|
],
|
||||||
1,
|
1,
|
||||||
10
|
10
|
||||||
|
@ -72,7 +73,7 @@ defmodule Mobilizon.GraphQL.API.SearchTest do
|
||||||
assert {:ok, %{total: 1, elements: [%Event{title: "super toto event"}]}} =
|
assert {:ok, %{total: 1, elements: [%Event{title: "super toto event"}]}} =
|
||||||
Search.search_events(%{term: "toto"}, 1, 10)
|
Search.search_events(%{term: "toto"}, 1, 10)
|
||||||
|
|
||||||
assert_called(Events.build_events_for_search(%{term: "toto"}, 1, 10))
|
assert_called(Events.build_events_for_search(%{term: "toto", local_only: false}, 1, 10))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,9 @@ defmodule Mobilizon.GraphQL.Resolvers.SearchTest do
|
||||||
|
|
||||||
import Mobilizon.Factory
|
import Mobilizon.Factory
|
||||||
|
|
||||||
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Events.Event
|
||||||
|
alias Mobilizon.Federation.ActivityPub.Relay
|
||||||
alias Mobilizon.Service.Workers
|
alias Mobilizon.Service.Workers
|
||||||
|
|
||||||
alias Mobilizon.GraphQL.AbsintheHelpers
|
alias Mobilizon.GraphQL.AbsintheHelpers
|
||||||
|
@ -15,8 +18,8 @@ defmodule Mobilizon.GraphQL.Resolvers.SearchTest do
|
||||||
|
|
||||||
describe "search events/3" do
|
describe "search events/3" do
|
||||||
@search_events_query """
|
@search_events_query """
|
||||||
query SearchEvents($location: String, $radius: Float, $tags: String, $term: String, $beginsOn: DateTime, $endsOn: DateTime) {
|
query SearchEvents($location: String, $radius: Float, $tags: String, $term: String, $beginsOn: DateTime, $endsOn: DateTime, $searchTarget: SearchTarget) {
|
||||||
searchEvents(location: $location, radius: $radius, tags: $tags, term: $term, beginsOn: $beginsOn, endsOn: $endsOn) {
|
searchEvents(location: $location, radius: $radius, tags: $tags, term: $term, beginsOn: $beginsOn, endsOn: $endsOn, searchTarget: $searchTarget) {
|
||||||
total,
|
total,
|
||||||
elements {
|
elements {
|
||||||
id
|
id
|
||||||
|
@ -218,6 +221,46 @@ defmodule Mobilizon.GraphQL.Resolvers.SearchTest do
|
||||||
assert res["errors"] == nil
|
assert res["errors"] == nil
|
||||||
assert res["data"]["searchEvents"]["total"] == 0
|
assert res["data"]["searchEvents"]["total"] == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "finds events for the correct target", %{conn: conn} do
|
||||||
|
event1 = insert(:event, title: "A local event")
|
||||||
|
|
||||||
|
%Actor{id: remote_instance_actor_id} = remote_instance_actor = insert(:instance_actor)
|
||||||
|
%Actor{id: remote_actor_id} = insert(:actor, domain: "somedomain.tld", user: nil)
|
||||||
|
|
||||||
|
%Event{url: remote_event_url} =
|
||||||
|
event2 = insert(:event, local: false, title: "My Remote event")
|
||||||
|
|
||||||
|
Mobilizon.Share.create(remote_event_url, remote_instance_actor_id, remote_actor_id)
|
||||||
|
|
||||||
|
%Actor{} = own_instance_actor = Relay.get_actor()
|
||||||
|
|
||||||
|
insert(:follower, target_actor: remote_instance_actor, actor: own_instance_actor)
|
||||||
|
Workers.BuildSearch.insert_search_event(event1)
|
||||||
|
Workers.BuildSearch.insert_search_event(event2)
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{term: "event"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 2
|
||||||
|
elements = res["data"]["searchEvents"]["elements"]
|
||||||
|
|
||||||
|
assert MapSet.new(Enum.map(elements, & &1["id"])) ==
|
||||||
|
MapSet.new([to_string(event1.id), to_string(event2.id)])
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{term: "event", searchTarget: "SELF"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "search_persons/3" do
|
describe "search_persons/3" do
|
||||||
|
|
Loading…
Reference in a new issue