884d399d043e542545dfbd930d536c78f04b5638
[akkoma] / lib / pleroma / web / activity_pub / side_effects.ex
1 defmodule Pleroma.Web.ActivityPub.SideEffects do
2 @moduledoc """
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
6 collection, and so on.
7 """
8 alias Pleroma.Activity
9 alias Pleroma.Chat
10 alias Pleroma.ChatMessageReference
11 alias Pleroma.Notification
12 alias Pleroma.Object
13 alias Pleroma.Repo
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.ActivityPub.Pipeline
17 alias Pleroma.Web.ActivityPub.Utils
18 alias Pleroma.Web.Streamer
19
20 def handle(object, meta \\ [])
21
22 # Tasks this handles:
23 # - Add like to object
24 # - Set up notification
25 def handle(%{data: %{"type" => "Like"}} = object, meta) do
26 liked_object = Object.get_by_ap_id(object.data["object"])
27 Utils.add_like_to_object(object, liked_object)
28
29 Notification.create_notifications(object)
30
31 {:ok, object, meta}
32 end
33
34 # Tasks this handles
35 # - Actually create object
36 # - Rollback if we couldn't create it
37 # - Set up notifications
38 def handle(%{data: %{"type" => "Create"}} = activity, meta) do
39 with {:ok, _object, _meta} <- handle_object_creation(meta[:object_data], meta) do
40 Notification.create_notifications(activity)
41 {:ok, activity, meta}
42 else
43 e -> Repo.rollback(e)
44 end
45 end
46
47 # Tasks this handles:
48 # - Add announce to object
49 # - Set up notification
50 # - Stream out the announce
51 def handle(%{data: %{"type" => "Announce"}} = object, meta) do
52 announced_object = Object.get_by_ap_id(object.data["object"])
53 user = User.get_cached_by_ap_id(object.data["actor"])
54
55 Utils.add_announce_to_object(object, announced_object)
56
57 if !User.is_internal_user?(user) do
58 Notification.create_notifications(object)
59 ActivityPub.stream_out(object)
60 end
61
62 {:ok, object, meta}
63 end
64
65 def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
66 with undone_object <- Activity.get_by_ap_id(undone_object),
67 :ok <- handle_undoing(undone_object) do
68 {:ok, object, meta}
69 end
70 end
71
72 # Tasks this handles:
73 # - Add reaction to object
74 # - Set up notification
75 def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
76 reacted_object = Object.get_by_ap_id(object.data["object"])
77 Utils.add_emoji_reaction_to_object(object, reacted_object)
78
79 Notification.create_notifications(object)
80
81 {:ok, object, meta}
82 end
83
84 # Tasks this handles:
85 # - Delete and unpins the create activity
86 # - Replace object with Tombstone
87 # - Set up notification
88 # - Reduce the user note count
89 # - Reduce the reply count
90 # - Stream out the activity
91 def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
92 deleted_object =
93 Object.normalize(deleted_object, false) || User.get_cached_by_ap_id(deleted_object)
94
95 result =
96 case deleted_object do
97 %Object{} ->
98 with {:ok, deleted_object, activity} <- Object.delete(deleted_object),
99 %User{} = user <- User.get_cached_by_ap_id(deleted_object.data["actor"]) do
100 User.remove_pinnned_activity(user, activity)
101
102 {:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
103
104 if in_reply_to = deleted_object.data["inReplyTo"] do
105 Object.decrease_replies_count(in_reply_to)
106 end
107
108 ChatMessageReference.delete_for_object(deleted_object)
109
110 ActivityPub.stream_out(object)
111 ActivityPub.stream_out_participations(deleted_object, user)
112 :ok
113 end
114
115 %User{} ->
116 with {:ok, _} <- User.delete(deleted_object) do
117 :ok
118 end
119 end
120
121 if result == :ok do
122 Notification.create_notifications(object)
123 {:ok, object, meta}
124 else
125 {:error, result}
126 end
127 end
128
129 # Nothing to do
130 def handle(object, meta) do
131 {:ok, object, meta}
132 end
133
134 def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
135 with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
136 actor = User.get_cached_by_ap_id(object.data["actor"])
137 recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
138
139 [[actor, recipient], [recipient, actor]]
140 |> Enum.each(fn [user, other_user] ->
141 if user.local do
142 {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
143 ChatMessageReference.create(chat, object, user.ap_id == actor.ap_id)
144 end
145 end)
146
147 Streamer.stream(["user", "user:pleroma_chat"], object)
148 {:ok, object, meta}
149 end
150 end
151
152 # Nothing to do
153 def handle_object_creation(object) do
154 {:ok, object}
155 end
156
157 def handle_undoing(%{data: %{"type" => "Like"}} = object) do
158 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
159 {:ok, _} <- Utils.remove_like_from_object(object, liked_object),
160 {:ok, _} <- Repo.delete(object) do
161 :ok
162 end
163 end
164
165 def handle_undoing(%{data: %{"type" => "EmojiReact"}} = object) do
166 with %Object{} = reacted_object <- Object.get_by_ap_id(object.data["object"]),
167 {:ok, _} <- Utils.remove_emoji_reaction_from_object(object, reacted_object),
168 {:ok, _} <- Repo.delete(object) do
169 :ok
170 end
171 end
172
173 def handle_undoing(%{data: %{"type" => "Announce"}} = object) do
174 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
175 {:ok, _} <- Utils.remove_announce_from_object(object, liked_object),
176 {:ok, _} <- Repo.delete(object) do
177 :ok
178 end
179 end
180
181 def handle_undoing(
182 %{data: %{"type" => "Block", "actor" => blocker, "object" => blocked}} = object
183 ) do
184 with %User{} = blocker <- User.get_cached_by_ap_id(blocker),
185 %User{} = blocked <- User.get_cached_by_ap_id(blocked),
186 {:ok, _} <- User.unblock(blocker, blocked),
187 {:ok, _} <- Repo.delete(object) do
188 :ok
189 end
190 end
191
192 def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
193 end