1 defmodule Pleroma.Web.ActivityPub.SideEffects do
3 This module looks at an inserted object and executes the side effects that it
4 implies. For example, a `Like` activity will increase the like count on the
5 liked object, a `Follow` activity will add the user to the follower
10 alias Pleroma.Chat.MessageReference
11 alias Pleroma.Notification
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.ActivityPub.Pipeline
17 alias Pleroma.Web.ActivityPub.Utils
18 alias Pleroma.Web.Push
19 alias Pleroma.Web.Streamer
21 def handle(object, meta \\ [])
24 # - Add like to object
25 # - Set up notification
26 def handle(%{data: %{"type" => "Like"}} = object, meta) do
27 liked_object = Object.get_by_ap_id(object.data["object"])
28 Utils.add_like_to_object(object, liked_object)
30 Notification.create_notifications(object)
36 # - Actually create object
37 # - Rollback if we couldn't create it
38 # - Set up notifications
39 def handle(%{data: %{"type" => "Create"}} = activity, meta) do
40 with {:ok, _object, _meta} <- handle_object_creation(meta[:object_data], meta) do
41 {:ok, notifications} = Notification.create_notifications(activity, do_send: false)
45 |> add_notifications(notifications)
54 # - Add announce to object
55 # - Set up notification
56 # - Stream out the announce
57 def handle(%{data: %{"type" => "Announce"}} = object, meta) do
58 announced_object = Object.get_by_ap_id(object.data["object"])
59 user = User.get_cached_by_ap_id(object.data["actor"])
61 Utils.add_announce_to_object(object, announced_object)
63 if !User.is_internal_user?(user) do
64 Notification.create_notifications(object)
65 ActivityPub.stream_out(object)
71 def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
72 with undone_object <- Activity.get_by_ap_id(undone_object),
73 :ok <- handle_undoing(undone_object) do
79 # - Add reaction to object
80 # - Set up notification
81 def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
82 reacted_object = Object.get_by_ap_id(object.data["object"])
83 Utils.add_emoji_reaction_to_object(object, reacted_object)
85 Notification.create_notifications(object)
91 # - Delete and unpins the create activity
92 # - Replace object with Tombstone
93 # - Set up notification
94 # - Reduce the user note count
95 # - Reduce the reply count
96 # - Stream out the activity
97 def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
99 Object.normalize(deleted_object, false) || User.get_cached_by_ap_id(deleted_object)
102 case deleted_object do
104 with {:ok, deleted_object, activity} <- Object.delete(deleted_object),
105 %User{} = user <- User.get_cached_by_ap_id(deleted_object.data["actor"]) do
106 User.remove_pinnned_activity(user, activity)
108 {:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
110 if in_reply_to = deleted_object.data["inReplyTo"] do
111 Object.decrease_replies_count(in_reply_to)
114 MessageReference.delete_for_object(deleted_object)
116 ActivityPub.stream_out(object)
117 ActivityPub.stream_out_participations(deleted_object, user)
122 with {:ok, _} <- User.delete(deleted_object) do
128 Notification.create_notifications(object)
136 def handle(object, meta) do
140 def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
141 with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
142 actor = User.get_cached_by_ap_id(object.data["actor"])
143 recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
145 [[actor, recipient], [recipient, actor]]
146 |> Enum.each(fn [user, other_user] ->
148 {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
149 {:ok, cm_ref} = MessageReference.create(chat, object, user.ap_id != actor.ap_id)
151 # We add a cache of the unread value here so that it
152 # doesn't change when being streamed out
155 |> Map.put(:unread, MessageReference.unread_count_for_chat(chat))
158 ["user", "user:pleroma_chat"],
159 {user, %{cm_ref | chat: chat, object: object}}
169 def handle_object_creation(object) do
173 def handle_undoing(%{data: %{"type" => "Like"}} = object) do
174 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
175 {:ok, _} <- Utils.remove_like_from_object(object, liked_object),
176 {:ok, _} <- Repo.delete(object) do
181 def handle_undoing(%{data: %{"type" => "EmojiReact"}} = object) do
182 with %Object{} = reacted_object <- Object.get_by_ap_id(object.data["object"]),
183 {:ok, _} <- Utils.remove_emoji_reaction_from_object(object, reacted_object),
184 {:ok, _} <- Repo.delete(object) do
189 def handle_undoing(%{data: %{"type" => "Announce"}} = object) do
190 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
191 {:ok, _} <- Utils.remove_announce_from_object(object, liked_object),
192 {:ok, _} <- Repo.delete(object) do
198 %{data: %{"type" => "Block", "actor" => blocker, "object" => blocked}} = object
200 with %User{} = blocker <- User.get_cached_by_ap_id(blocker),
201 %User{} = blocked <- User.get_cached_by_ap_id(blocked),
202 {:ok, _} <- User.unblock(blocker, blocked),
203 {:ok, _} <- Repo.delete(object) do
208 def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
210 defp send_notifications(meta) do
211 Keyword.get(meta, :created_notifications, [])
212 |> Enum.each(fn notification ->
213 Streamer.stream(["user", "user:notification"], notification)
214 Push.send(notification)
220 defp add_notifications(meta, notifications) do
221 existing = Keyword.get(meta, :created_notifications, [])
224 |> Keyword.put(:created_notifications, notifications ++ existing)
227 def handle_after_transaction(meta) do
229 |> send_notifications()