1 defmodule Pleroma.Web.ActivityPub.Builder do
3 This module builds the objects. Meant to be used for creating local objects.
5 This module encodes our addressing policies and general shape of our objects.
11 alias Pleroma.Web.ActivityPub.Relay
12 alias Pleroma.Web.ActivityPub.Utils
13 alias Pleroma.Web.ActivityPub.Visibility
15 require Pleroma.Constants
17 @spec follow(User.t(), User.t()) :: {:ok, map(), keyword()}
18 def follow(follower, followed) do
20 "id" => Utils.generate_activity_id(),
21 "actor" => follower.ap_id,
23 "object" => followed.ap_id,
24 "to" => [followed.ap_id]
30 @spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
31 def emoji_react(actor, object, emoji) do
32 with {:ok, data, meta} <- object_action(actor, object) do
35 |> Map.put("content", emoji)
36 |> Map.put("type", "EmojiReact")
42 @spec undo(User.t(), Activity.t()) :: {:ok, map(), keyword()}
43 def undo(actor, object) do
46 "id" => Utils.generate_activity_id(),
47 "actor" => actor.ap_id,
49 "object" => object.data["id"],
50 "to" => object.data["to"] || [],
51 "cc" => object.data["cc"] || []
55 @spec delete(User.t(), String.t()) :: {:ok, map(), keyword()}
56 def delete(actor, object_id) do
57 object = Object.normalize(object_id, false)
59 user = !object && User.get_cached_by_ap_id(object_id)
62 case {object, user} do
64 # We are deleting an object, address everyone who was originally mentioned
65 (object.data["to"] || []) ++ (object.data["cc"] || [])
67 {_, %User{follower_address: follower_address}} ->
68 # We are deleting a user, address the followers of that user
74 "id" => Utils.generate_activity_id(),
75 "actor" => actor.ap_id,
76 "object" => object_id,
82 def create(actor, object, recipients) do
85 "id" => Utils.generate_activity_id(),
86 "actor" => actor.ap_id,
90 "published" => DateTime.utc_now() |> DateTime.to_iso8601()
94 def chat_message(actor, recipient, content, opts \\ []) do
96 "id" => Utils.generate_object_id(),
97 "actor" => actor.ap_id,
98 "type" => "ChatMessage",
100 "content" => content,
101 "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
102 "emoji" => Emoji.Formatter.get_emoji_map(content)
105 case opts[:attachment] do
106 %Object{data: attachment_data} ->
109 Map.put(basic, "attachment", attachment_data),
118 def answer(user, object, name) do
122 "actor" => user.ap_id,
123 "attributedTo" => user.ap_id,
124 "cc" => [object.data["actor"]],
127 "inReplyTo" => object.data["id"],
128 "context" => object.data["context"],
129 "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
130 "id" => Utils.generate_object_id()
134 @spec tombstone(String.t(), String.t()) :: {:ok, map(), keyword()}
135 def tombstone(actor, id) do
140 "type" => "Tombstone"
144 @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
145 def like(actor, object) do
146 with {:ok, data, meta} <- object_action(actor, object) do
149 |> Map.put("type", "Like")
155 # Retricted to user updates for now, always public
156 @spec update(User.t(), Object.t()) :: {:ok, map(), keyword()}
157 def update(actor, object) do
158 to = [Pleroma.Constants.as_public(), actor.follower_address]
162 "id" => Utils.generate_activity_id(),
164 "actor" => actor.ap_id,
170 @spec block(User.t(), User.t()) :: {:ok, map(), keyword()}
171 def block(blocker, blocked) do
174 "id" => Utils.generate_activity_id(),
176 "actor" => blocker.ap_id,
177 "object" => blocked.ap_id,
178 "to" => [blocked.ap_id]
182 @spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()}
183 def announce(actor, object, options \\ []) do
184 public? = Keyword.get(options, :public, false)
188 actor.ap_id == Relay.relay_ap_id() ->
189 [actor.follower_address]
192 [actor.follower_address, object.data["actor"], Pleroma.Constants.as_public()]
195 [actor.follower_address, object.data["actor"]]
200 "id" => Utils.generate_activity_id(),
201 "actor" => actor.ap_id,
202 "object" => object.data["id"],
204 "context" => object.data["context"],
205 "type" => "Announce",
206 "published" => Utils.make_date()
210 @spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()}
211 defp object_action(actor, object) do
212 object_actor = User.get_cached_by_ap_id(object.data["actor"])
214 # Address the actor of the object, and our actor's follower collection if the post is public.
216 if Visibility.is_public?(object) do
217 [actor.follower_address, object.data["actor"]]
219 [object.data["actor"]]
222 # CC everyone who's been addressed in the object, except ourself and the object actor's
223 # follower collection
225 (object.data["to"] ++ (object.data["cc"] || []))
226 |> List.delete(actor.ap_id)
227 |> List.delete(object_actor.follower_address)
231 "id" => Utils.generate_activity_id(),
232 "actor" => actor.ap_id,
233 "object" => object.data["id"],
236 "context" => object.data["context"]