From 85e4715412352058b5072fa6ab070ed7f81a7f3e Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Tue, 19 Sep 2023 18:07:00 +0200 Subject: [PATCH] feat(federation): expose public activities as announcements in relay outbx & rfrsh profile aftr fllw Also change ActorView to send proper HTTP error codes Signed-off-by: Thomas Citharel --- lib/federation/activity_pub/relay.ex | 9 +++- .../controllers/activity_pub_controller.ex | 44 ++++++++++++------- lib/web/views/activity_pub/actor_view.ex | 19 +++++++- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/lib/federation/activity_pub/relay.ex b/lib/federation/activity_pub/relay.ex index a45635cec..b722eca62 100644 --- a/lib/federation/activity_pub/relay.ex +++ b/lib/federation/activity_pub/relay.ex @@ -49,10 +49,17 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do %Actor{} = local_actor = get_actor() with {:ok, target_instance} <- fetch_actor(address), - {:ok, %Actor{} = target_actor} <- + {:ok, %Actor{id: target_actor_id} = target_actor} <- ActivityPubActor.get_or_fetch_actor_by_url(target_instance), {:ok, activity, follow} <- Follows.follow(local_actor, target_actor) do Logger.info("Relay: followed instance #{target_instance}; id=#{activity.data["id"]}") + + Background.enqueue("refresh_profile", %{ + "actor_id" => target_actor_id + }) + + Logger.info("Relay: schedule refreshing instance #{target_instance} after follow") + {:ok, activity, follow} else {:error, :person_no_follow} -> diff --git a/lib/web/controllers/activity_pub_controller.ex b/lib/web/controllers/activity_pub_controller.ex index 2d97e4a55..9ea5a81bd 100644 --- a/lib/web/controllers/activity_pub_controller.ex +++ b/lib/web/controllers/activity_pub_controller.ex @@ -175,25 +175,25 @@ defmodule Mobilizon.Web.ActivityPubController do end def errors(conn, {:error, :not_found}) do - conn - |> put_status(404) - |> json("Not found") + send_resp(conn, 404, "Not found") + end + + def errors(conn, {:error, :bad_request}) do + send_resp(conn, 400, "Bad request") end def errors(conn, e) do Logger.debug(inspect(e)) - conn - |> put_status(500) - |> json("Unknown Error") + send_resp(conn, 500, "Unknown Error") end @spec actor_collection(Conn.t(), String.t(), map()) :: Conn.t() defp actor_collection(conn, collection, %{"name" => name, "page" => page}) do - with {page, ""} <- Integer.parse(page), + with {:page, {page, ""}} <- {:page, Integer.parse(page)}, page <- max(page, 1), - %Actor{} = actor <- Actors.get_local_actor_by_name_with_preload(name) do + {:actor, %Actor{} = actor} <- {:actor, Actors.get_local_actor_by_name_with_preload(name)} do conn |> put_resp_content_type("application/activity+json") |> json( @@ -203,19 +203,29 @@ defmodule Mobilizon.Web.ActivityPubController do actor_applicant: Map.get(conn.assigns, :actor) }) ) + else + {:page, _} -> + {:error, :bad_request} + + {:actor, _} -> + {:error, :not_found} end end defp actor_collection(conn, collection, %{"name" => name}) do - with %Actor{} = actor <- Actors.get_local_actor_by_name_with_preload(name) do - conn - |> put_resp_content_type("application/activity+json") - |> json( - ActorView.render("#{collection}.json", %{ - actor: actor, - actor_applicant: Map.get(conn.assigns, :actor) - }) - ) + case Actors.get_local_actor_by_name_with_preload(name) do + %Actor{} = actor -> + conn + |> put_resp_content_type("application/activity+json") + |> json( + ActorView.render("#{collection}.json", %{ + actor: actor, + actor_applicant: Map.get(conn.assigns, :actor) + }) + ) + + _ -> + {:error, :not_found} end end diff --git a/lib/web/views/activity_pub/actor_view.ex b/lib/web/views/activity_pub/actor_view.ex index e67e5790d..c7707ef5a 100644 --- a/lib/web/views/activity_pub/actor_view.ex +++ b/lib/web/views/activity_pub/actor_view.ex @@ -6,7 +6,7 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do alias Mobilizon.Discussions.Discussion alias Mobilizon.Events.Event alias Mobilizon.Federation.ActivityPub - alias Mobilizon.Federation.ActivityPub.{Activity, Utils} + alias Mobilizon.Federation.ActivityPub.{Activity, Relay, Utils} alias Mobilizon.Federation.ActivityStream.Convertible alias Mobilizon.Posts.Post alias Mobilizon.Resources.Resource @@ -124,7 +124,21 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do end defp fetch_collection(:outbox, actor, page) do - ActivityPub.fetch_public_activities_for_actor(actor, page) + # In the specific case of the relay outbox collection we need to expose public activities as "Announce" + if Relay.get_actor().id == actor.id do + %{total: total, elements: elements} = + ActivityPub.fetch_public_activities_for_actor(actor, page) + + %{ + total: total, + elements: + Enum.map(elements, fn object -> + Utils.make_announce_data(actor, item(object), nil, true) + end) + } + else + ActivityPub.fetch_public_activities_for_actor(actor, page) + end end defp fetch_collection(_, _, _), do: @private_visibility_empty_collection @@ -202,6 +216,7 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do def item(%Post{} = post), do: Convertible.model_to_as(post) def item(%Event{} = event), do: Convertible.model_to_as(event) def item(%TodoList{} = todo_list), do: Convertible.model_to_as(todo_list) + def item(item), do: item @spec actor_applicant_group_member?(Actor.t(), Actor.t()) :: boolean() defp actor_applicant_group_member?(%Actor{id: group_id}, %Actor{id: actor_applicant_id}),