Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms
[akkoma] / test / web / activity_pub / side_effects_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
6 use Oban.Testing, repo: Pleroma.Repo
7 use Pleroma.DataCase
8
9 alias Pleroma.Activity
10 alias Pleroma.Chat
11 alias Pleroma.Notification
12 alias Pleroma.Object
13 alias Pleroma.Repo
14 alias Pleroma.Tests.ObanHelpers
15 alias Pleroma.User
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.ActivityPub.Builder
18 alias Pleroma.Web.ActivityPub.SideEffects
19 alias Pleroma.Web.CommonAPI
20
21 import Pleroma.Factory
22 import Mock
23
24 describe "delete objects" do
25 setup do
26 user = insert(:user)
27 other_user = insert(:user)
28
29 {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
30 {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
31 {:ok, favorite} = CommonAPI.favorite(user, post.id)
32 object = Object.normalize(post)
33 {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
34 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
35 {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
36 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
37
38 %{
39 user: user,
40 delete: delete,
41 post: post,
42 object: object,
43 delete_user: delete_user,
44 op: op,
45 favorite: favorite
46 }
47 end
48
49 test "it handles object deletions", %{
50 delete: delete,
51 post: post,
52 object: object,
53 user: user,
54 op: op,
55 favorite: favorite
56 } do
57 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
58 stream_out: fn _ -> nil end,
59 stream_out_participations: fn _, _ -> nil end do
60 {:ok, delete, _} = SideEffects.handle(delete)
61 user = User.get_cached_by_ap_id(object.data["actor"])
62
63 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
64 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
65 end
66
67 object = Object.get_by_id(object.id)
68 assert object.data["type"] == "Tombstone"
69 refute Activity.get_by_id(post.id)
70 refute Activity.get_by_id(favorite.id)
71
72 user = User.get_by_id(user.id)
73 assert user.note_count == 0
74
75 object = Object.normalize(op.data["object"], false)
76
77 assert object.data["repliesCount"] == 0
78 end
79
80 test "it handles object deletions when the object itself has been pruned", %{
81 delete: delete,
82 post: post,
83 object: object,
84 user: user,
85 op: op
86 } do
87 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
88 stream_out: fn _ -> nil end,
89 stream_out_participations: fn _, _ -> nil end do
90 {:ok, delete, _} = SideEffects.handle(delete)
91 user = User.get_cached_by_ap_id(object.data["actor"])
92
93 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
94 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
95 end
96
97 object = Object.get_by_id(object.id)
98 assert object.data["type"] == "Tombstone"
99 refute Activity.get_by_id(post.id)
100
101 user = User.get_by_id(user.id)
102 assert user.note_count == 0
103
104 object = Object.normalize(op.data["object"], false)
105
106 assert object.data["repliesCount"] == 0
107 end
108
109 test "it handles user deletions", %{delete_user: delete, user: user} do
110 {:ok, _delete, _} = SideEffects.handle(delete)
111 ObanHelpers.perform_all()
112
113 assert User.get_cached_by_ap_id(user.ap_id).deactivated
114 end
115 end
116
117 describe "EmojiReact objects" do
118 setup do
119 poster = insert(:user)
120 user = insert(:user)
121
122 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
123
124 {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
125 {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
126
127 %{emoji_react: emoji_react, user: user, poster: poster}
128 end
129
130 test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
131 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
132 object = Object.get_by_ap_id(emoji_react.data["object"])
133
134 assert object.data["reaction_count"] == 1
135 assert ["👌", [user.ap_id]] in object.data["reactions"]
136 end
137
138 test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
139 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
140 assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
141 end
142 end
143
144 describe "delete users with confirmation pending" do
145 setup do
146 user = insert(:user, confirmation_pending: true)
147 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
148 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
149 {:ok, delete: delete_user, user: user}
150 end
151
152 test "when activation is not required", %{delete: delete, user: user} do
153 clear_config([:instance, :account_activation_required], false)
154 {:ok, _, _} = SideEffects.handle(delete)
155 ObanHelpers.perform_all()
156
157 assert User.get_cached_by_id(user.id).deactivated
158 end
159
160 test "when activation is required", %{delete: delete, user: user} do
161 clear_config([:instance, :account_activation_required], true)
162 {:ok, _, _} = SideEffects.handle(delete)
163 ObanHelpers.perform_all()
164
165 refute User.get_cached_by_id(user.id)
166 end
167 end
168
169 describe "Undo objects" do
170 setup do
171 poster = insert(:user)
172 user = insert(:user)
173 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
174 {:ok, like} = CommonAPI.favorite(user, post.id)
175 {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
176 {:ok, announce, _} = CommonAPI.repeat(post.id, user)
177 {:ok, block} = ActivityPub.block(user, poster)
178 User.block(user, poster)
179
180 {:ok, undo_data, _meta} = Builder.undo(user, like)
181 {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
182
183 {:ok, undo_data, _meta} = Builder.undo(user, reaction)
184 {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
185
186 {:ok, undo_data, _meta} = Builder.undo(user, announce)
187 {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
188
189 {:ok, undo_data, _meta} = Builder.undo(user, block)
190 {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
191
192 %{
193 like_undo: like_undo,
194 post: post,
195 like: like,
196 reaction_undo: reaction_undo,
197 reaction: reaction,
198 announce_undo: announce_undo,
199 announce: announce,
200 block_undo: block_undo,
201 block: block,
202 poster: poster,
203 user: user
204 }
205 end
206
207 test "deletes the original block", %{block_undo: block_undo, block: block} do
208 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
209 refute Activity.get_by_id(block.id)
210 end
211
212 test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
213 blocker = User.get_by_ap_id(block.data["actor"])
214 blocked = User.get_by_ap_id(block.data["object"])
215
216 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
217 refute User.blocks?(blocker, blocked)
218 end
219
220 test "an announce undo removes the announce from the object", %{
221 announce_undo: announce_undo,
222 post: post
223 } do
224 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
225
226 object = Object.get_by_ap_id(post.data["object"])
227
228 assert object.data["announcement_count"] == 0
229 assert object.data["announcements"] == []
230 end
231
232 test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
233 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
234 refute Activity.get_by_id(announce.id)
235 end
236
237 test "a reaction undo removes the reaction from the object", %{
238 reaction_undo: reaction_undo,
239 post: post
240 } do
241 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
242
243 object = Object.get_by_ap_id(post.data["object"])
244
245 assert object.data["reaction_count"] == 0
246 assert object.data["reactions"] == []
247 end
248
249 test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
250 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
251 refute Activity.get_by_id(reaction.id)
252 end
253
254 test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
255 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
256
257 object = Object.get_by_ap_id(post.data["object"])
258
259 assert object.data["like_count"] == 0
260 assert object.data["likes"] == []
261 end
262
263 test "deletes the original like", %{like_undo: like_undo, like: like} do
264 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
265 refute Activity.get_by_id(like.id)
266 end
267 end
268
269 describe "like objects" do
270 setup do
271 poster = insert(:user)
272 user = insert(:user)
273 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
274
275 {:ok, like_data, _meta} = Builder.like(user, post.object)
276 {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
277
278 %{like: like, user: user, poster: poster}
279 end
280
281 test "add the like to the original object", %{like: like, user: user} do
282 {:ok, like, _} = SideEffects.handle(like)
283 object = Object.get_by_ap_id(like.data["object"])
284 assert object.data["like_count"] == 1
285 assert user.ap_id in object.data["likes"]
286 end
287
288 test "creates a notification", %{like: like, poster: poster} do
289 {:ok, like, _} = SideEffects.handle(like)
290 assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
291 end
292 end
293
294 describe "creation of ChatMessages" do
295 test "notifies the recipient" do
296 author = insert(:user, local: false)
297 recipient = insert(:user, local: true)
298
299 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
300
301 {:ok, create_activity_data, _meta} =
302 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
303
304 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
305
306 {:ok, _create_activity, _meta} =
307 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
308
309 assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
310 end
311
312 test "it creates a Chat for the local users and bumps the unread count, except for the author" do
313 author = insert(:user, local: true)
314 recipient = insert(:user, local: true)
315
316 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
317
318 {:ok, create_activity_data, _meta} =
319 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
320
321 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
322
323 {:ok, _create_activity, _meta} =
324 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
325
326 chat = Chat.get(author.id, recipient.ap_id)
327 assert chat.unread == 0
328
329 chat = Chat.get(recipient.id, author.ap_id)
330 assert chat.unread == 1
331 end
332
333 test "it creates a Chat for the local users and bumps the unread count" do
334 author = insert(:user, local: false)
335 recipient = insert(:user, local: true)
336
337 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
338
339 {:ok, create_activity_data, _meta} =
340 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
341
342 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
343
344 {:ok, _create_activity, _meta} =
345 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
346
347 # An object is created
348 assert Object.get_by_ap_id(chat_message_data["id"])
349
350 # The remote user won't get a chat
351 chat = Chat.get(author.id, recipient.ap_id)
352 refute chat
353
354 # The local user will get a chat
355 chat = Chat.get(recipient.id, author.ap_id)
356 assert chat
357
358 author = insert(:user, local: true)
359 recipient = insert(:user, local: true)
360
361 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
362
363 {:ok, create_activity_data, _meta} =
364 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
365
366 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
367
368 {:ok, _create_activity, _meta} =
369 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
370
371 # Both users are local and get the chat
372 chat = Chat.get(author.id, recipient.ap_id)
373 assert chat
374
375 chat = Chat.get(recipient.id, author.ap_id)
376 assert chat
377 end
378 end
379 end