0c81f0b56cbb3531d48be834747a15b0be66a9a1
[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 def fetch_collection_by_ap_id(ap_id) when is_binary(ap_id) do
15 fetch_collection(ap_id)
16 end
17
18 def fetch_collection(ap_id) when is_binary(ap_id) do
19 with {:ok, page} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id) do
20 {:ok, objects_from_collection(page)}
21 else
22 e ->
23 Logger.error("Could not fetch collection #{ap_id} - #{inspect(e)}")
24 e
25 end
26 end
27
28 def fetch_collection(%{"type" => type} = page)
29 when type in ["Collection", "OrderedCollection"] do
30 {:ok, objects_from_collection(page)}
31 end
32
33 defp items_in_page(%{"type" => type, "orderedItems" => items})
34 when is_list(items) and type in ["OrderedCollection", "OrderedCollectionPage"],
35 do: items
36
37 defp items_in_page(%{"type" => type, "items" => items})
38 when is_list(items) and type in ["Collection", "CollectionPage"],
39 do: items
40
41 defp objects_from_collection(%{"type" => "OrderedCollection", "orderedItems" => items})
42 when is_list(items),
43 do: items
44
45 defp objects_from_collection(%{"type" => "Collection", "items" => items}) when is_list(items),
46 do: items
47
48 defp objects_from_collection(%{"type" => type, "first" => first})
49 when is_binary(first) and type in ["Collection", "OrderedCollection"] do
50 fetch_page_items(first)
51 end
52
53 defp objects_from_collection(%{"type" => type, "first" => %{"id" => id}})
54 when is_binary(id) and type in ["Collection", "OrderedCollection"] do
55 fetch_page_items(id)
56 end
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 {:ok, page} = Fetcher.fetch_and_contain_remote_object_from_id(id)
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 end
71 end
72
73 defp maybe_next_page(%{"next" => id}, items) when is_binary(id) do
74 fetch_page_items(id, items)
75 end
76
77 defp maybe_next_page(_, items), do: items
78 end