diff --git a/lib/graphql/resolvers/event.ex b/lib/graphql/resolvers/event.ex index 93e8af394..addfc1ffa 100644 --- a/lib/graphql/resolvers/event.ex +++ b/lib/graphql/resolvers/event.ex @@ -5,6 +5,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do alias Mobilizon.{Actors, Admin, Events} alias Mobilizon.Actors.Actor + alias Mobilizon.Config alias Mobilizon.Events.{Event, EventParticipantStats} alias Mobilizon.Users.User @@ -44,16 +45,31 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do {:error, "Event with UUID #{uuid} not found"} end - def find_event(parent, %{uuid: uuid} = args, resolution) do - case {:has_event, Events.get_public_event_by_uuid_with_preload(uuid)} do - {:has_event, %Event{} = event} -> - {:ok, Map.put(event, :organizer_actor, Person.proxify_pictures(event.organizer_actor))} + def find_event(parent, %{uuid: uuid} = args, %{context: context} = resolution) do + require Logger + Logger.error(inspect(context)) + with {:has_event, %Event{} = event} <- + {:has_event, Events.get_public_event_by_uuid_with_preload(uuid)}, + {:access_valid, true} <- + {:access_valid, Map.has_key?(context, :current_user) || check_event_access(event)} do + {:ok, Map.put(event, :organizer_actor, Person.proxify_pictures(event.organizer_actor))} + else {:has_event, _} -> find_private_event(parent, args, resolution) + + {:access_valid, _} -> + {:error, "Event with UUID #{uuid} not found"} end end + def check_event_access(%Event{local: true}), do: true + + def check_event_access(%Event{url: url}) do + relay_actor_id = Config.relay_actor_id() + Events.check_if_event_has_instance_follow(url, relay_actor_id) + end + @doc """ List participants for event (through an event request) """ diff --git a/lib/mobilizon/config.ex b/lib/mobilizon/config.ex index dd7caf911..5b3e69bb3 100644 --- a/lib/mobilizon/config.ex +++ b/lib/mobilizon/config.ex @@ -140,6 +140,7 @@ defmodule Mobilizon.Config do ] def anonymous_actor_id, do: get_cached_value(:anonymous_actor_id) + def relay_actor_id, do: get_cached_value(:relay_actor_id) @spec get(module | atom) :: any def get(key), do: get(key, nil) @@ -202,6 +203,13 @@ defmodule Mobilizon.Config do end end + @spec create_cache(atom()) :: integer() + defp create_cache(:relay_actor_id) do + with {:ok, %Actor{id: actor_id}} <- Actors.get_or_create_internal_actor("relay") do + actor_id + end + end + def clear_config_cache do Cachex.clear(:config) end diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex index 74b29557b..c22d3ea38 100644 --- a/lib/mobilizon/events/events.ex +++ b/lib/mobilizon/events/events.ex @@ -12,7 +12,7 @@ defmodule Mobilizon.Events do alias Ecto.{Changeset, Multi} - alias Mobilizon.Actors.Actor + alias Mobilizon.Actors.{Actor, Follower} alias Mobilizon.Addresses.Address alias Mobilizon.Events.{ @@ -28,6 +28,7 @@ defmodule Mobilizon.Events do } alias Mobilizon.Service.Workers + alias Mobilizon.Share alias Mobilizon.Storage.{Page, Repo} alias Mobilizon.Users.User @@ -228,6 +229,14 @@ defmodule Mobilizon.Events do |> Repo.one() end + @spec check_if_event_has_instance_follow(String.t(), integer()) :: boolean() + def check_if_event_has_instance_follow(event_uri, follower_actor_id) do + Share + |> join(:inner, [s], f in Follower, on: f.target_actor_id == s.actor_id) + |> where([s, f], f.actor_id == ^follower_actor_id and s.uri == ^event_uri) + |> Repo.exists?() + end + @doc """ Gets an event by its UUID, with all associations loaded. """ @@ -379,6 +388,7 @@ defmodule Mobilizon.Events do |> filter_future_events(is_future) |> filter_unlisted(is_unlisted) |> filter_draft() + |> filter_local_or_from_followed_instances_events() |> Repo.all() end @@ -461,6 +471,7 @@ defmodule Mobilizon.Events do name |> normalize_search_string() |> events_for_search_query() + |> filter_local_or_from_followed_instances_events() |> Page.build_page(page, limit) end @@ -1757,6 +1768,14 @@ defmodule Mobilizon.Events do defp filter_future_events(query, false), do: query + defp filter_local_or_from_followed_instances_events(query) do + from(q in query, + left_join: s in Share, + on: s.uri == q.url, + where: q.local == true or not is_nil(s.uri) + ) + end + @spec filter_unlisted(Ecto.Query.t(), boolean) :: Ecto.Query.t() defp filter_unlisted(query, true) do from(q in query, where: q.visibility in ^@public_visibility)