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 \\ [])
26 # For a local user, we also get a changeset with the full information, so we
27 # can update non-federating, non-activitypub settings as well.
28 def handle(%{data: %{"type" => "Update", "object" => updated_object}} = object, meta) do
29 if changeset = Keyword.get(meta, :user_update_changeset) do
31 |> User.update_and_set_cache()
33 {:ok, new_user_data} = ActivityPub.user_data_from_user_object(updated_object)
35 User.get_by_ap_id(updated_object["id"])
36 |> User.remote_user_changeset(new_user_data)
37 |> User.update_and_set_cache()
44 # - Add like to object
45 # - Set up notification
46 def handle(%{data: %{"type" => "Like"}} = object, meta) do
47 liked_object = Object.get_by_ap_id(object.data["object"])
48 Utils.add_like_to_object(object, liked_object)
50 Notification.create_notifications(object)
56 # - Actually create object
57 # - Rollback if we couldn't create it
58 # - Set up notifications
59 def handle(%{data: %{"type" => "Create"}} = activity, meta) do
60 with {:ok, _object, meta} <- handle_object_creation(meta[:object_data], meta) do
61 {:ok, notifications} = Notification.create_notifications(activity, do_send: false)
65 |> add_notifications(notifications)
74 # - Add announce to object
75 # - Set up notification
76 # - Stream out the announce
77 def handle(%{data: %{"type" => "Announce"}} = object, meta) do
78 announced_object = Object.get_by_ap_id(object.data["object"])
79 user = User.get_cached_by_ap_id(object.data["actor"])
81 Utils.add_announce_to_object(object, announced_object)
83 if !User.is_internal_user?(user) do
84 Notification.create_notifications(object)
85 ActivityPub.stream_out(object)
91 def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
92 with undone_object <- Activity.get_by_ap_id(undone_object),
93 :ok <- handle_undoing(undone_object) do
99 # - Add reaction to object
100 # - Set up notification
101 def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
102 reacted_object = Object.get_by_ap_id(object.data["object"])
103 Utils.add_emoji_reaction_to_object(object, reacted_object)
105 Notification.create_notifications(object)
110 # Tasks this handles:
111 # - Delete and unpins the create activity
112 # - Replace object with Tombstone
113 # - Set up notification
114 # - Reduce the user note count
115 # - Reduce the reply count
116 # - Stream out the activity
117 def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
119 Object.normalize(deleted_object, false) || User.get_cached_by_ap_id(deleted_object)
122 case deleted_object do
124 with {:ok, deleted_object, activity} <- Object.delete(deleted_object),
125 %User{} = user <- User.get_cached_by_ap_id(deleted_object.data["actor"]) do
126 User.remove_pinnned_activity(user, activity)
128 {:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
130 if in_reply_to = deleted_object.data["inReplyTo"] do
131 Object.decrease_replies_count(in_reply_to)
134 MessageReference.delete_for_object(deleted_object)
136 ActivityPub.stream_out(object)
137 ActivityPub.stream_out_participations(deleted_object, user)
142 with {:ok, _} <- User.delete(deleted_object) do
148 Notification.create_notifications(object)
156 def handle(object, meta) do
160 def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
161 with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
162 actor = User.get_cached_by_ap_id(object.data["actor"])
163 recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
166 [[actor, recipient], [recipient, actor]]
167 |> Enum.map(fn [user, other_user] ->
169 {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
170 {:ok, cm_ref} = MessageReference.create(chat, object, user.ap_id != actor.ap_id)
173 ["user", "user:pleroma_chat"],
174 {user, %{cm_ref | chat: chat, object: object}}
182 |> add_streamables(streamables)
189 def handle_object_creation(object) do
193 def handle_undoing(%{data: %{"type" => "Like"}} = object) do
194 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
195 {:ok, _} <- Utils.remove_like_from_object(object, liked_object),
196 {:ok, _} <- Repo.delete(object) do
201 def handle_undoing(%{data: %{"type" => "EmojiReact"}} = object) do
202 with %Object{} = reacted_object <- Object.get_by_ap_id(object.data["object"]),
203 {:ok, _} <- Utils.remove_emoji_reaction_from_object(object, reacted_object),
204 {:ok, _} <- Repo.delete(object) do
209 def handle_undoing(%{data: %{"type" => "Announce"}} = object) do
210 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
211 {:ok, _} <- Utils.remove_announce_from_object(object, liked_object),
212 {:ok, _} <- Repo.delete(object) do
218 %{data: %{"type" => "Block", "actor" => blocker, "object" => blocked}} = object
220 with %User{} = blocker <- User.get_cached_by_ap_id(blocker),
221 %User{} = blocked <- User.get_cached_by_ap_id(blocked),
222 {:ok, _} <- User.unblock(blocker, blocked),
223 {:ok, _} <- Repo.delete(object) do
228 def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
230 defp send_notifications(meta) do
231 Keyword.get(meta, :notifications, [])
232 |> Enum.each(fn notification ->
233 Streamer.stream(["user", "user:notification"], notification)
234 Push.send(notification)
240 defp send_streamables(meta) do
241 Keyword.get(meta, :streamables, [])
242 |> Enum.each(fn {topics, items} ->
243 Streamer.stream(topics, items)
249 defp add_streamables(meta, streamables) do
250 existing = Keyword.get(meta, :streamables, [])
253 |> Keyword.put(:streamables, streamables ++ existing)
256 defp add_notifications(meta, notifications) do
257 existing = Keyword.get(meta, :notifications, [])
260 |> Keyword.put(:notifications, notifications ++ existing)
263 def handle_after_transaction(meta) do
265 |> send_notifications()
266 |> send_streamables()