110 lines
3.6 KiB
Elixir
110 lines
3.6 KiB
Elixir
|
defmodule Mobilizon.Federation.ActivityPub.Refresher do
|
||
|
@moduledoc """
|
||
|
Module that provides functions to explore and fetch collections on a group
|
||
|
"""
|
||
|
|
||
|
alias Mobilizon.Actors
|
||
|
alias Mobilizon.Actors.Actor
|
||
|
alias Mobilizon.Federation.ActivityPub
|
||
|
alias Mobilizon.Federation.ActivityStream.Converter.Member, as: MemberConverter
|
||
|
alias Mobilizon.Federation.ActivityStream.Converter.Resource, as: ResourceConverter
|
||
|
alias Mobilizon.Federation.HTTPSignatures.Signature
|
||
|
alias Mobilizon.Resources
|
||
|
require Logger
|
||
|
|
||
|
import Mobilizon.Federation.ActivityPub.Utils,
|
||
|
only: [maybe_date_fetch: 2, sign_fetch: 4]
|
||
|
|
||
|
@spec fetch_group(String.t(), Actor.t()) :: :ok
|
||
|
def fetch_group(group_url, %Actor{} = on_behalf_of) do
|
||
|
with {:ok, %Actor{resources_url: resources_url, members_url: members_url}} <-
|
||
|
ActivityPub.get_or_fetch_actor_by_url(group_url) do
|
||
|
fetch_collection(members_url, on_behalf_of)
|
||
|
fetch_collection(resources_url, on_behalf_of)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def fetch_collection(nil, _on_behalf_of), do: :error
|
||
|
|
||
|
def fetch_collection(collection_url, on_behalf_of) do
|
||
|
Logger.debug("Fetching and preparing collection from url")
|
||
|
Logger.debug(inspect(collection_url))
|
||
|
|
||
|
with {:ok, data} <- fetch(collection_url, on_behalf_of) do
|
||
|
Logger.debug("Fetch ok, passing to process_collection")
|
||
|
process_collection(data, on_behalf_of)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
defp process_collection(%{"type" => type, "orderedItems" => items}, _on_behalf_of)
|
||
|
when type in ["OrderedCollection", "OrderedCollectionPage"] do
|
||
|
Logger.debug(
|
||
|
"Processing an OrderedCollection / OrderedCollectionPage with has direct orderedItems"
|
||
|
)
|
||
|
|
||
|
Logger.debug(inspect(items))
|
||
|
|
||
|
Enum.each(items, &handling_element/1)
|
||
|
end
|
||
|
|
||
|
defp process_collection(%{"type" => "OrderedCollection", "first" => first}, on_behalf_of)
|
||
|
when is_map(first),
|
||
|
do: process_collection(first, on_behalf_of)
|
||
|
|
||
|
defp process_collection(%{"type" => "OrderedCollection", "first" => first}, on_behalf_of)
|
||
|
when is_bitstring(first) do
|
||
|
Logger.debug("OrderedCollection has a first property pointing to an URI")
|
||
|
|
||
|
with {:ok, data} <- fetch(first, on_behalf_of) do
|
||
|
Logger.debug("Fetched the collection for first property")
|
||
|
process_collection(data, on_behalf_of)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
defp handling_element(%{"type" => "Member"} = data) do
|
||
|
Logger.debug("Handling Member element")
|
||
|
|
||
|
data
|
||
|
|> MemberConverter.as_to_model_data()
|
||
|
|> Actors.create_member()
|
||
|
end
|
||
|
|
||
|
defp handling_element(%{"type" => type} = data)
|
||
|
when type in ["Document", "ResourceCollection"] do
|
||
|
Logger.debug("Handling Resource element")
|
||
|
|
||
|
data
|
||
|
|> ResourceConverter.as_to_model_data()
|
||
|
|> Resources.create_resource()
|
||
|
end
|
||
|
|
||
|
defp fetch(url, %Actor{} = on_behalf_of) do
|
||
|
with date <- Signature.generate_date_header(),
|
||
|
headers <-
|
||
|
[{:Accept, "application/activity+json"}]
|
||
|
|> maybe_date_fetch(date)
|
||
|
|> sign_fetch(on_behalf_of, url, date),
|
||
|
%HTTPoison.Response{status_code: 200, body: body} <-
|
||
|
HTTPoison.get!(url, headers,
|
||
|
follow_redirect: true,
|
||
|
ssl: [{:versions, [:"tlsv1.2"]}]
|
||
|
),
|
||
|
{:ok, data} <-
|
||
|
Jason.decode(body) do
|
||
|
{:ok, data}
|
||
|
else
|
||
|
# Actor is gone, probably deleted
|
||
|
{:ok, %HTTPoison.Response{status_code: 410}} ->
|
||
|
Logger.info("Response HTTP 410")
|
||
|
{:error, :actor_deleted}
|
||
|
|
||
|
{:origin_check, false} ->
|
||
|
{:error, "Origin check failed"}
|
||
|
|
||
|
e ->
|
||
|
Logger.warn("Could not decode actor at fetch #{url}, #{inspect(e)}")
|
||
|
{:error, e}
|
||
|
end
|
||
|
end
|
||
|
end
|