cda52b00e92e6c5173423dd95109c929dbd785fd
[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 if user.ap_id == actor.ap_id do
143 {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
144 ChatMessageReference.create(chat, object, true)
145 else
146 {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
147 ChatMessageReference.create(chat, object, false)
148 end
149 end
150 end)
151
152 Streamer.stream(["user", "user:pleroma_chat"], object)
153 {:ok, object, meta}
154 end
155 end
156
157 # Nothing to do
158 def handle_object_creation(object) do
159 {:ok, object}
160 end
161
162 def handle_undoing(%{data: %{"type" => "Like"}} = object) do
163 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
164 {:ok, _} <- Utils.remove_like_from_object(object, liked_object),
165 {:ok, _} <- Repo.delete(object) do
166 :ok
167 end
168 end
169
170 def handle_undoing(%{data: %{"type" => "EmojiReact"}} = object) do
171 with %Object{} = reacted_object <- Object.get_by_ap_id(object.data["object"]),
172 {:ok, _} <- Utils.remove_emoji_reaction_from_object(object, reacted_object),
173 {:ok, _} <- Repo.delete(object) do
174 :ok
175 end
176 end
177
178 def handle_undoing(%{data: %{"type" => "Announce"}} = object) do
179 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
180 {:ok, _} <- Utils.remove_announce_from_object(object, liked_object),
181 {:ok, _} <- Repo.delete(object) do
182 :ok
183 end
184 end
185
186 def handle_undoing(
187 %{data: %{"type" => "Block", "actor" => blocker, "object" => blocked}} = object
188 ) do
189 with %User{} = blocker <- User.get_cached_by_ap_id(blocker),
190 %User{} = blocked <- User.get_cached_by_ap_id(blocked),
191 {:ok, _} <- User.unblock(blocker, blocked),
192 {:ok, _} <- Repo.delete(object) do
193 :ok
194 end
195 end
196
197 def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
198 end