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 <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2023-09-19 18:07:00 +02:00
parent daa68533d5
commit 85e4715412
No known key found for this signature in database
GPG key ID: A061B9DDE0CA0773
3 changed files with 52 additions and 20 deletions

View file

@ -49,10 +49,17 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do
%Actor{} = local_actor = get_actor() %Actor{} = local_actor = get_actor()
with {:ok, target_instance} <- fetch_actor(address), 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), ActivityPubActor.get_or_fetch_actor_by_url(target_instance),
{:ok, activity, follow} <- Follows.follow(local_actor, target_actor) do {:ok, activity, follow} <- Follows.follow(local_actor, target_actor) do
Logger.info("Relay: followed instance #{target_instance}; id=#{activity.data["id"]}") 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} {:ok, activity, follow}
else else
{:error, :person_no_follow} -> {:error, :person_no_follow} ->

View file

@ -175,25 +175,25 @@ defmodule Mobilizon.Web.ActivityPubController do
end end
def errors(conn, {:error, :not_found}) do def errors(conn, {:error, :not_found}) do
conn send_resp(conn, 404, "Not found")
|> put_status(404) end
|> json("Not found")
def errors(conn, {:error, :bad_request}) do
send_resp(conn, 400, "Bad request")
end end
def errors(conn, e) do def errors(conn, e) do
Logger.debug(inspect(e)) Logger.debug(inspect(e))
conn send_resp(conn, 500, "Unknown Error")
|> put_status(500)
|> json("Unknown Error")
end end
@spec actor_collection(Conn.t(), String.t(), map()) :: Conn.t() @spec actor_collection(Conn.t(), String.t(), map()) :: Conn.t()
defp actor_collection(conn, collection, %{"name" => name, "page" => page}) do 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), 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 conn
|> put_resp_content_type("application/activity+json") |> put_resp_content_type("application/activity+json")
|> json( |> json(
@ -203,19 +203,29 @@ defmodule Mobilizon.Web.ActivityPubController do
actor_applicant: Map.get(conn.assigns, :actor) actor_applicant: Map.get(conn.assigns, :actor)
}) })
) )
else
{:page, _} ->
{:error, :bad_request}
{:actor, _} ->
{:error, :not_found}
end end
end end
defp actor_collection(conn, collection, %{"name" => name}) do defp actor_collection(conn, collection, %{"name" => name}) do
with %Actor{} = actor <- Actors.get_local_actor_by_name_with_preload(name) do case Actors.get_local_actor_by_name_with_preload(name) do
conn %Actor{} = actor ->
|> put_resp_content_type("application/activity+json") conn
|> json( |> put_resp_content_type("application/activity+json")
ActorView.render("#{collection}.json", %{ |> json(
actor: actor, ActorView.render("#{collection}.json", %{
actor_applicant: Map.get(conn.assigns, :actor) actor: actor,
}) actor_applicant: Map.get(conn.assigns, :actor)
) })
)
_ ->
{:error, :not_found}
end end
end end

View file

@ -6,7 +6,7 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do
alias Mobilizon.Discussions.Discussion alias Mobilizon.Discussions.Discussion
alias Mobilizon.Events.Event alias Mobilizon.Events.Event
alias Mobilizon.Federation.ActivityPub alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.{Activity, Utils} alias Mobilizon.Federation.ActivityPub.{Activity, Relay, Utils}
alias Mobilizon.Federation.ActivityStream.Convertible alias Mobilizon.Federation.ActivityStream.Convertible
alias Mobilizon.Posts.Post alias Mobilizon.Posts.Post
alias Mobilizon.Resources.Resource alias Mobilizon.Resources.Resource
@ -124,7 +124,21 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do
end end
defp fetch_collection(:outbox, actor, page) do 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 end
defp fetch_collection(_, _, _), do: @private_visibility_empty_collection 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(%Post{} = post), do: Convertible.model_to_as(post)
def item(%Event{} = event), do: Convertible.model_to_as(event) def item(%Event{} = event), do: Convertible.model_to_as(event)
def item(%TodoList{} = todo_list), do: Convertible.model_to_as(todo_list) 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() @spec actor_applicant_group_member?(Actor.t(), Actor.t()) :: boolean()
defp actor_applicant_group_member?(%Actor{id: group_id}, %Actor{id: actor_applicant_id}), defp actor_applicant_group_member?(%Actor{id: group_id}, %Actor{id: actor_applicant_id}),