Merge branch 'features/openrc-console' into 'develop'
[akkoma] / lib / pleroma / web / activity_pub / builder.ex
1 defmodule Pleroma.Web.ActivityPub.Builder do
2 @moduledoc """
3 This module builds the objects. Meant to be used for creating local objects.
4
5 This module encodes our addressing policies and general shape of our objects.
6 """
7
8 alias Pleroma.Object
9 alias Pleroma.User
10 alias Pleroma.Web.ActivityPub.Utils
11 alias Pleroma.Web.ActivityPub.Visibility
12
13 @spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
14 def emoji_react(actor, object, emoji) do
15 with {:ok, data, meta} <- object_action(actor, object) do
16 data =
17 data
18 |> Map.put("content", emoji)
19 |> Map.put("type", "EmojiReact")
20
21 {:ok, data, meta}
22 end
23 end
24
25 @spec undo(User.t(), Activity.t()) :: {:ok, map(), keyword()}
26 def undo(actor, object) do
27 {:ok,
28 %{
29 "id" => Utils.generate_activity_id(),
30 "actor" => actor.ap_id,
31 "type" => "Undo",
32 "object" => object.data["id"],
33 "to" => object.data["to"] || [],
34 "cc" => object.data["cc"] || []
35 }, []}
36 end
37
38 @spec delete(User.t(), String.t()) :: {:ok, map(), keyword()}
39 def delete(actor, object_id) do
40 object = Object.normalize(object_id, false)
41
42 user = !object && User.get_cached_by_ap_id(object_id)
43
44 to =
45 case {object, user} do
46 {%Object{}, _} ->
47 # We are deleting an object, address everyone who was originally mentioned
48 (object.data["to"] || []) ++ (object.data["cc"] || [])
49
50 {_, %User{follower_address: follower_address}} ->
51 # We are deleting a user, address the followers of that user
52 [follower_address]
53 end
54
55 {:ok,
56 %{
57 "id" => Utils.generate_activity_id(),
58 "actor" => actor.ap_id,
59 "object" => object_id,
60 "to" => to,
61 "type" => "Delete"
62 }, []}
63 end
64
65 @spec tombstone(String.t(), String.t()) :: {:ok, map(), keyword()}
66 def tombstone(actor, id) do
67 {:ok,
68 %{
69 "id" => id,
70 "actor" => actor,
71 "type" => "Tombstone"
72 }, []}
73 end
74
75 @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
76 def like(actor, object) do
77 with {:ok, data, meta} <- object_action(actor, object) do
78 data =
79 data
80 |> Map.put("type", "Like")
81
82 {:ok, data, meta}
83 end
84 end
85
86 @spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()}
87 defp object_action(actor, object) do
88 object_actor = User.get_cached_by_ap_id(object.data["actor"])
89
90 # Address the actor of the object, and our actor's follower collection if the post is public.
91 to =
92 if Visibility.is_public?(object) do
93 [actor.follower_address, object.data["actor"]]
94 else
95 [object.data["actor"]]
96 end
97
98 # CC everyone who's been addressed in the object, except ourself and the object actor's
99 # follower collection
100 cc =
101 (object.data["to"] ++ (object.data["cc"] || []))
102 |> List.delete(actor.ap_id)
103 |> List.delete(object_actor.follower_address)
104
105 {:ok,
106 %{
107 "id" => Utils.generate_activity_id(),
108 "actor" => actor.ap_id,
109 "object" => object.data["id"],
110 "to" => to,
111 "cc" => cc,
112 "context" => object.data["context"]
113 }, []}
114 end
115 end