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 def accept_or_reject(actor, activity, type) do
19 "id" => Utils.generate_activity_id(),
20 "actor" => actor.ap_id,
22 "object" => activity.data["id"],
23 "to" => [activity.actor]
29 @spec reject(User.t(), Activity.t()) :: {:ok, map(), keyword()}
30 def reject(actor, rejected_activity) do
31 accept_or_reject(actor, rejected_activity, "Reject")
34 @spec accept(User.t(), Activity.t()) :: {:ok, map(), keyword()}
35 def accept(actor, accepted_activity) do
36 accept_or_reject(actor, accepted_activity, "Accept")
39 @spec follow(User.t(), User.t()) :: {:ok, map(), keyword()}
40 def follow(follower, followed) do
42 "id" => Utils.generate_activity_id(),
43 "actor" => follower.ap_id,
45 "object" => followed.ap_id,
46 "to" => [followed.ap_id]
52 @spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
53 def emoji_react(actor, object, emoji) do
54 with {:ok, data, meta} <- object_action(actor, object) do
57 |> Map.put("content", emoji)
58 |> Map.put("type", "EmojiReact")
64 @spec undo(User.t(), Activity.t()) :: {:ok, map(), keyword()}
65 def undo(actor, object) do
68 "id" => Utils.generate_activity_id(),
69 "actor" => actor.ap_id,
71 "object" => object.data["id"],
72 "to" => object.data["to"] || [],
73 "cc" => object.data["cc"] || []
77 @spec delete(User.t(), String.t()) :: {:ok, map(), keyword()}
78 def delete(actor, object_id) do
79 object = Object.normalize(object_id, false)
81 user = !object && User.get_cached_by_ap_id(object_id)
84 case {object, user} do
86 # We are deleting an object, address everyone who was originally mentioned
87 (object.data["to"] || []) ++ (object.data["cc"] || [])
89 {_, %User{follower_address: follower_address}} ->
90 # We are deleting a user, address the followers of that user
96 "id" => Utils.generate_activity_id(),
97 "actor" => actor.ap_id,
98 "object" => object_id,
104 def create(actor, object, recipients) do
114 "id" => Utils.generate_activity_id(),
115 "actor" => actor.ap_id,
119 "published" => DateTime.utc_now() |> DateTime.to_iso8601()
121 |> Pleroma.Maps.put_if_present("context", context), []}
124 def chat_message(actor, recipient, content, opts \\ []) do
126 "id" => Utils.generate_object_id(),
127 "actor" => actor.ap_id,
128 "type" => "ChatMessage",
130 "content" => content,
131 "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
132 "emoji" => Emoji.Formatter.get_emoji_map(content)
135 case opts[:attachment] do
136 %Object{data: attachment_data} ->
139 Map.put(basic, "attachment", attachment_data),
148 def answer(user, object, name) do
152 "actor" => user.ap_id,
153 "attributedTo" => user.ap_id,
154 "cc" => [object.data["actor"]],
157 "inReplyTo" => object.data["id"],
158 "context" => object.data["context"],
159 "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
160 "id" => Utils.generate_object_id()
164 @spec tombstone(String.t(), String.t()) :: {:ok, map(), keyword()}
165 def tombstone(actor, id) do
170 "type" => "Tombstone"
174 @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
175 def like(actor, object) do
176 with {:ok, data, meta} <- object_action(actor, object) do
179 |> Map.put("type", "Like")
185 # Retricted to user updates for now, always public
186 @spec update(User.t(), Object.t()) :: {:ok, map(), keyword()}
187 def update(actor, object) do
188 to = [Pleroma.Constants.as_public(), actor.follower_address]
192 "id" => Utils.generate_activity_id(),
194 "actor" => actor.ap_id,
200 @spec block(User.t(), User.t()) :: {:ok, map(), keyword()}
201 def block(blocker, blocked) do
204 "id" => Utils.generate_activity_id(),
206 "actor" => blocker.ap_id,
207 "object" => blocked.ap_id,
208 "to" => [blocked.ap_id]
212 @spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()}
213 def announce(actor, object, options \\ []) do
214 public? = Keyword.get(options, :public, false)
218 actor.ap_id == Relay.ap_id() ->
219 [actor.follower_address]
222 [actor.follower_address, object.data["actor"], Pleroma.Constants.as_public()]
225 [actor.follower_address, object.data["actor"]]
230 "id" => Utils.generate_activity_id(),
231 "actor" => actor.ap_id,
232 "object" => object.data["id"],
234 "context" => object.data["context"],
235 "type" => "Announce",
236 "published" => Utils.make_date()
240 @spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()}
241 defp object_action(actor, object) do
242 object_actor = User.get_cached_by_ap_id(object.data["actor"])
244 # Address the actor of the object, and our actor's follower collection if the post is public.
246 if Visibility.is_public?(object) do
247 [actor.follower_address, object.data["actor"]]
249 [object.data["actor"]]
252 # CC everyone who's been addressed in the object, except ourself and the object actor's
253 # follower collection
255 (object.data["to"] ++ (object.data["cc"] || []))
256 |> List.delete(actor.ap_id)
257 |> List.delete(object_actor.follower_address)
261 "id" => Utils.generate_activity_id(),
262 "actor" => actor.ap_id,
263 "object" => object.data["id"],
266 "context" => object.data["context"]