Allow to refresh instance outbox when they accept subscription

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2020-09-02 08:59:59 +02:00
parent c011a988a8
commit 489fd74545
20 changed files with 427 additions and 227 deletions

View File

@@ -51,6 +51,8 @@ defmodule Mobilizon.Federation.ActivityPub do
require Logger
@public_ap_adress "https://www.w3.org/ns/activitystreams#Public"
@doc """
Wraps an object into an activity
"""
@@ -111,10 +113,18 @@ defmodule Mobilizon.Federation.ActivityPub do
{:ok, entity}
end
with {:ok, entity} <- res do
Logger.debug("Going to preload an existing entity")
Logger.debug("Going to preload an existing entity")
Preloader.maybe_preload(entity)
case res do
{:ok, entity} ->
Preloader.maybe_preload(entity)
{:error, status, entity} ->
{:ok, entity} = Preloader.maybe_preload(entity)
{:error, status, entity}
err ->
err
end
e ->
@@ -303,7 +313,8 @@ defmodule Mobilizon.Federation.ActivityPub do
Make an actor follow another
"""
def follow(%Actor{} = follower, %Actor{} = followed, activity_id \\ nil, local \\ true) do
with {:ok, %Follower{} = follower} <-
with {:different_actors, true} <- {:different_actors, followed.id != follower.id},
{:ok, %Follower{} = follower} <-
Actors.follow(followed, follower, activity_id, false),
follower_as_data <- Convertible.model_to_as(follower),
{:ok, activity} <- create_activity(follower_as_data, local),
@@ -312,6 +323,9 @@ defmodule Mobilizon.Federation.ActivityPub do
else
{:error, err, msg} when err in [:already_following, :suspended] ->
{:error, msg}
{:different_actors, _} ->
{:error, "Can't follow yourself"}
end
end
@@ -649,7 +663,7 @@ defmodule Mobilizon.Federation.ActivityPub do
defp convert_followers_in_recipients(recipients) do
Enum.reduce(recipients, {recipients, []}, fn recipient, {recipients, follower_actors} = acc ->
case Actors.get_group_by_followers_url(recipient) do
case Actors.get_actor_by_followers_url(recipient) do
%Actor{} = group ->
{Enum.filter(recipients, fn recipient -> recipient != group.followers_url end),
follower_actors ++ Actors.list_external_followers_for_actor(group)}
@@ -797,9 +811,9 @@ defmodule Mobilizon.Federation.ActivityPub do
@spec event_to_activity(%Event{}, boolean()) :: Activity.t()
defp event_to_activity(%Event{} = event, local \\ true) do
%Activity{
recipients: ["https://www.w3.org/ns/activitystreams#Public"],
recipients: [@public_ap_adress],
actor: event.organizer_actor.url,
data: Converter.Event.model_to_as(event),
data: event |> Convertible.model_to_as() |> make_create_data(%{"to" => @public_ap_adress}),
local: local
}
end
@@ -808,9 +822,10 @@ defmodule Mobilizon.Federation.ActivityPub do
@spec comment_to_activity(%Comment{}, boolean()) :: Activity.t()
defp comment_to_activity(%Comment{} = comment, local \\ true) do
%Activity{
recipients: ["https://www.w3.org/ns/activitystreams#Public"],
recipients: [@public_ap_adress],
actor: comment.actor.url,
data: Converter.Comment.model_to_as(comment),
data:
comment |> Convertible.model_to_as() |> make_create_data(%{"to" => @public_ap_adress}),
local: local
}
end

View File

@@ -29,6 +29,7 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do
{:ok, data}
else
{:ok, %Tesla.Env{status: 410}} ->
Logger.warn("Resource at #{url} is 410 Gone")
{:error, "Gone"}
{:ok, %Tesla.Env{} = res} ->

View File

@@ -6,9 +6,13 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
alias Mobilizon.Actors
alias Mobilizon.Actors.Actor
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.{Fetcher, Relay, Transmogrifier}
alias Mobilizon.Federation.ActivityPub.{Fetcher, Relay, Transmogrifier, Utils}
require Logger
@doc """
Refresh a remote profile
"""
@spec refresh_profile(Actor.t()) :: {:ok, Actor.t()}
def refresh_profile(%Actor{domain: nil}), do: {:error, "Can only refresh remote actors"}
def refresh_profile(%Actor{type: :Group, url: url, id: group_id} = group) do
@@ -26,8 +30,11 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
end
end
def refresh_profile(%Actor{type: :Person, url: url}) do
ActivityPub.make_actor_from_url(url)
def refresh_profile(%Actor{type: type, url: url}) when type in [:Person, :Application] do
with {:ok, %Actor{outbox_url: outbox_url}} <- ActivityPub.make_actor_from_url(url),
:ok <- fetch_collection(outbox_url, Relay.get_actor()) do
:ok
end
end
@spec fetch_group(String.t(), Actor.t()) :: :ok
@@ -112,22 +119,13 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
defp process_collection(_, _), do: :error
defp handling_element(data) when is_map(data) do
id = Map.get(data, "id")
object = get_in(data, ["object"])
if id do
Mobilizon.Tombstone.delete_uri_tombstone(id)
if object do
object |> Utils.get_url() |> Mobilizon.Tombstone.delete_uri_tombstone()
end
activity = %{
"type" => "Create",
"to" => data["to"],
"cc" => data["cc"],
"actor" => data["actor"],
"attributedTo" => data["attributedTo"],
"object" => data
}
Transmogrifier.handle_incoming(activity)
Transmogrifier.handle_incoming(data)
end
defp handling_element(uri) when is_binary(uri) do

View File

@@ -42,6 +42,10 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do
Logger.info("Relay: followed instance #{target_instance}; id=#{activity.data["id"]}")
{:ok, activity, follow}
else
{:error, e} ->
Logger.warn("Error while following remote instance: #{inspect(e)}")
{:error, e}
e ->
Logger.warn("Error while following remote instance: #{inspect(e)}")
{:error, e}

View File

@@ -17,7 +17,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
alias Mobilizon.Todos.{Todo, TodoList}
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.{Activity, Relay, Utils}
alias Mobilizon.Federation.ActivityPub.{Activity, Refresher, Relay, Utils}
alias Mobilizon.Federation.ActivityPub.Types.Ownable
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
alias Mobilizon.Tombstone
@@ -656,7 +656,8 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
Handle incoming `Accept` activities wrapping a `Follow` activity
"""
def do_handle_incoming_accept_following(follow_object, %Actor{} = actor) do
with {:follow, {:ok, %Follower{approved: false, target_actor: followed} = follow}} <-
with {:follow,
{:ok, %Follower{approved: false, target_actor: followed, actor: follower} = follow}} <-
{:follow, get_follow(follow_object)},
{:same_actor, true} <- {:same_actor, actor.id == followed.id},
{:ok, %Activity{} = activity, %Follower{approved: true} = follow} <-
@@ -665,6 +666,13 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
follow,
false
) do
relay_actor = Relay.get_actor()
# If this is an instance follow, refresh the followed profile (especially their outbox)
if follower.id == relay_actor.id do
Refresher.refresh_profile(followed)
end
{:ok, activity, follow}
else
{:follow, _} ->

View File

@@ -107,15 +107,19 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
do: ["https://www.w3.org/ns/activitystreams#Public"],
else: [event.organizer_actor.followers_url]
res = %{
%{
"type" => "Event",
"to" => to,
"cc" => [],
"attributedTo" =>
if(is_nil(event.attributed_to), do: nil, else: event.attributed_to.url) ||
if(is_nil(event.attributed_to) or not Ecto.assoc_loaded?(event.attributed_to),
do: nil,
else: event.attributed_to.url
) ||
event.organizer_actor.url,
"name" => event.title,
"actor" => event.organizer_actor.url,
"actor" =>
if(Ecto.assoc_loaded?(event.organizer_actor), do: event.organizer_actor.url, else: nil),
"uuid" => event.uuid,
"category" => event.category,
"content" => event.description,
@@ -136,40 +140,9 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
"id" => event.url,
"url" => event.url
}
res =
if is_nil(event.physical_address),
do: res,
else: Map.put(res, "location", AddressConverter.model_to_as(event.physical_address))
res =
if is_nil(event.picture),
do: res,
else:
Map.update(
res,
"attachment",
[],
&(&1 ++ [PictureConverter.model_to_as(event.picture)])
)
if is_nil(event.online_address),
do: res,
else:
Map.update(
res,
"attachment",
[],
&(&1 ++
[
%{
"type" => "Link",
"href" => event.online_address,
"mediaType" => "text/html",
"name" => "Website"
}
])
)
|> maybe_add_physical_address(event)
|> maybe_add_event_picture(event)
|> maybe_add_online_address(event)
end
# Get only elements that we have in EventOptions
@@ -249,4 +222,45 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
end
end)
end
@spec maybe_add_physical_address(map(), Event.t()) :: map()
defp maybe_add_physical_address(res, event) do
if is_nil(event.physical_address),
do: res,
else: Map.put(res, "location", AddressConverter.model_to_as(event.physical_address))
end
@spec maybe_add_event_picture(map(), Event.t()) :: map()
defp maybe_add_event_picture(res, event) do
if is_nil(event.picture),
do: res,
else:
Map.update(
res,
"attachment",
[],
&(&1 ++ [PictureConverter.model_to_as(event.picture)])
)
end
@spec maybe_add_online_address(map(), Event.t()) :: map()
defp maybe_add_online_address(res, event) do
if is_nil(event.online_address),
do: res,
else:
Map.update(
res,
"attachment",
[],
&(&1 ++
[
%{
"type" => "Link",
"href" => event.online_address,
"mediaType" => "text/html",
"name" => "Website"
}
])
)
end
end

View File

@@ -16,6 +16,10 @@ defmodule Mobilizon.GraphQL.API.Follows do
{:ok, activity, follow} ->
{:ok, activity, follow}
{:error, e} ->
Logger.warn("Error while following actor: #{inspect(e)}")
{:error, e}
e ->
Logger.warn("Error while following actor: #{inspect(e)}")
{:error, e}

View File

@@ -249,7 +249,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
{:ok, _activity, follow} ->
{:ok, follow}
{:error, {:error, err}} when is_bitstring(err) ->
{:error, err} when is_binary(err) ->
{:error, err}
end
end

View File

@@ -561,9 +561,9 @@ defmodule Mobilizon.Actors do
|> Repo.one()
end
@spec get_group_by_followers_url(String.t()) :: Actor.t()
def get_group_by_followers_url(followers_url) do
group_query()
@spec get_actor_by_followers_url(String.t()) :: Actor.t()
def get_actor_by_followers_url(followers_url) do
Actor
|> where([q], q.followers_url == ^followers_url)
|> Repo.one()
end

View File

@@ -251,8 +251,9 @@ defmodule Mobilizon.Events do
def create_event(attrs \\ %{}) do
with {:ok, %{insert: %Event{} = event}} <- do_create_event(attrs),
%Event{} = event <- Repo.preload(event, @event_preloads) do
unless event.draft,
do: Workers.BuildSearch.enqueue(:insert_search_event, %{"event_id" => event.id})
unless event.draft do
Workers.BuildSearch.enqueue(:insert_search_event, %{"event_id" => event.id})
end
{:ok, event}
else

View File

@@ -41,7 +41,10 @@ defmodule Mobilizon.Tombstone do
@spec find_tombstone(String.t()) :: Ecto.Schema.t() | nil
def find_tombstone(uri) do
Repo.get_by(__MODULE__, uri: uri)
__MODULE__
|> Ecto.Query.where([t], t.uri == ^uri)
|> Ecto.Query.preload([t], [:actor])
|> Repo.one()
end
@spec delete_actor_tombstones(String.t() | integer()) :: {integer(), nil}

View File

@@ -30,11 +30,13 @@ defmodule Mobilizon.Service.Formatter.HTML do
`<h1>test</h1>next` thing becomes `test next` instead of `testnext`
"""
@spec strip_tags_and_insert_spaces(String.t()) :: String.t()
def strip_tags_and_insert_spaces(html) do
def strip_tags_and_insert_spaces(html) when is_binary(html) do
html
|> String.replace("</", " </")
|> strip_tags()
end
def strip_tags_and_insert_spaces(html), do: html
def filter_tags_for_oembed(html), do: Sanitizer.scrub(html, OEmbed)
end

View File

@@ -37,6 +37,8 @@ defmodule Mobilizon.Service.Workers.Helper do
queue: unquote(queue),
max_attempts: 1
alias Oban.Job
def enqueue(operation, params, worker_args \\ []) do
params = Map.merge(%{"op" => operation}, params)
queue_atom = String.to_existing_atom(unquote(queue))

View File

@@ -160,7 +160,7 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do
map
end
def item(%Activity{data: %{"id" => id}}), do: id
def item(%Activity{data: data}), do: data
def item(%Actor{url: url}), do: url
def item(%Member{} = member), do: Convertible.model_to_as(member)
def item(%Resource{} = resource), do: Convertible.model_to_as(resource)