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