ab69f4b848e05f8062f9b71e286b6589b0a4d865
[akkoma] / lib / pleroma / collections / fetcher.ex
1 # Akkoma: The cooler fediverse server
2 # Copyright © 2022- Akkoma Authors <https://akkoma.dev/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Akkoma.Collections.Fetcher do
6 @moduledoc """
7 Activitypub Collections fetching functions
8 see: https://www.w3.org/TR/activitystreams-core/#paging
9 """
10 alias Pleroma.Object.Fetcher
11 alias Pleroma.Config
12 require Logger
13
14 @spec fetch_collection(String.t() | map()) :: {:ok, [Pleroma.Object.t()]} | {:error, any()}
15 def fetch_collection(ap_id) when is_binary(ap_id) do
16 with {:ok, page} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id) do
17 {:ok, objects_from_collection(page)}
18 else
19 e ->
20 Logger.error("Could not fetch collection #{ap_id} - #{inspect(e)}")
21 e
22 end
23 end
24
25 def fetch_collection(%{"type" => type} = page)
26 when type in ["Collection", "OrderedCollection", "CollectionPage", "OrderedCollectionPage"] do
27 {:ok, objects_from_collection(page)}
28 end
29
30 defp items_in_page(%{"type" => type, "orderedItems" => items})
31 when is_list(items) and type in ["OrderedCollection", "OrderedCollectionPage"],
32 do: items
33
34 defp items_in_page(%{"type" => type, "items" => items})
35 when is_list(items) and type in ["Collection", "CollectionPage"],
36 do: items
37
38 defp objects_from_collection(%{"type" => type, "orderedItems" => items} = page)
39 when is_list(items) and type in ["OrderedCollection", "OrderedCollectionPage"],
40 do: maybe_next_page(page, items)
41
42 defp objects_from_collection(%{"type" => type, "items" => items} = page)
43 when is_list(items) and type in ["Collection", "CollectionPage"],
44 do: maybe_next_page(page, items)
45
46 defp objects_from_collection(%{"type" => type, "first" => first})
47 when is_binary(first) and type in ["Collection", "OrderedCollection"] do
48 fetch_page_items(first)
49 end
50
51 defp objects_from_collection(%{"type" => type, "first" => %{"id" => id}})
52 when is_binary(id) and type in ["Collection", "OrderedCollection"] do
53 fetch_page_items(id)
54 end
55
56 defp objects_from_collection(_page), do: []
57
58 defp fetch_page_items(id, items \\ []) do
59 if Enum.count(items) >= Config.get([:activitypub, :max_collection_objects]) do
60 items
61 else
62 with {:ok, page} <- Fetcher.fetch_and_contain_remote_object_from_id(id) do
63 objects = items_in_page(page)
64
65 if Enum.count(objects) > 0 do
66 maybe_next_page(page, items ++ objects)
67 else
68 items
69 end
70 else
71 {:error, "Object has been deleted"} ->
72 items
73
74 {:error, error} ->
75 Logger.error("Could not fetch page #{id} - #{inspect(error)}")
76 {:error, error}
77 end
78 end
79 end
80
81 defp maybe_next_page(%{"next" => id}, items) when is_binary(id) do
82 fetch_page_items(id, items)
83 end
84
85 defp maybe_next_page(_, items), do: items
86 end