Change user.deactivated field to user.is_active
[akkoma] / test / pleroma / web / activity_pub / side_effects_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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.Chat.MessageReference
12 alias Pleroma.Notification
13 alias Pleroma.Object
14 alias Pleroma.Repo
15 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.User
17 alias Pleroma.Web.ActivityPub.ActivityPub
18 alias Pleroma.Web.ActivityPub.Builder
19 alias Pleroma.Web.ActivityPub.SideEffects
20 alias Pleroma.Web.CommonAPI
21
22 import Mock
23 import Pleroma.Factory
24
25 describe "handle_after_transaction" do
26 test "it streams out notifications and streams" do
27 author = insert(:user, local: true)
28 recipient = insert(:user, local: true)
29
30 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
31
32 {:ok, create_activity_data, _meta} =
33 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
34
35 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
36
37 {:ok, _create_activity, meta} =
38 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
39
40 assert [notification] = meta[:notifications]
41
42 with_mocks([
43 {
44 Pleroma.Web.Streamer,
45 [],
46 [
47 stream: fn _, _ -> nil end
48 ]
49 },
50 {
51 Pleroma.Web.Push,
52 [],
53 [
54 send: fn _ -> nil end
55 ]
56 }
57 ]) do
58 SideEffects.handle_after_transaction(meta)
59
60 assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
61 assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
62 assert called(Pleroma.Web.Push.send(notification))
63 end
64 end
65 end
66
67 describe "blocking users" do
68 setup do
69 user = insert(:user)
70 blocked = insert(:user)
71 User.follow(blocked, user)
72 User.follow(user, blocked)
73
74 {:ok, block_data, []} = Builder.block(user, blocked)
75 {:ok, block, _meta} = ActivityPub.persist(block_data, local: true)
76
77 %{user: user, blocked: blocked, block: block}
78 end
79
80 test "it unfollows and blocks", %{user: user, blocked: blocked, block: block} do
81 assert User.following?(user, blocked)
82 assert User.following?(blocked, user)
83
84 {:ok, _, _} = SideEffects.handle(block)
85
86 refute User.following?(user, blocked)
87 refute User.following?(blocked, user)
88 assert User.blocks?(user, blocked)
89 end
90
91 test "it blocks but does not unfollow if the relevant setting is set", %{
92 user: user,
93 blocked: blocked,
94 block: block
95 } do
96 clear_config([:activitypub, :unfollow_blocked], false)
97 assert User.following?(user, blocked)
98 assert User.following?(blocked, user)
99
100 {:ok, _, _} = SideEffects.handle(block)
101
102 refute User.following?(user, blocked)
103 assert User.following?(blocked, user)
104 assert User.blocks?(user, blocked)
105 end
106 end
107
108 describe "update users" do
109 setup do
110 user = insert(:user, local: false)
111 {:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"})
112 {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
113
114 %{user: user, update_data: update_data, update: update}
115 end
116
117 test "it updates the user", %{user: user, update: update} do
118 {:ok, _, _} = SideEffects.handle(update)
119 user = User.get_by_id(user.id)
120 assert user.name == "new name!"
121 end
122
123 test "it uses a given changeset to update", %{user: user, update: update} do
124 changeset = Ecto.Changeset.change(user, %{default_scope: "direct"})
125
126 assert user.default_scope == "public"
127 {:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset)
128 user = User.get_by_id(user.id)
129 assert user.default_scope == "direct"
130 end
131 end
132
133 describe "EmojiReact objects" do
134 setup do
135 poster = insert(:user)
136 user = insert(:user)
137
138 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
139
140 {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
141 {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
142
143 %{emoji_react: emoji_react, user: user, poster: poster}
144 end
145
146 test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
147 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
148 object = Object.get_by_ap_id(emoji_react.data["object"])
149
150 assert object.data["reaction_count"] == 1
151 assert ["👌", [user.ap_id]] in object.data["reactions"]
152 end
153
154 test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
155 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
156 assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
157 end
158 end
159
160 describe "delete users with confirmation pending" do
161 setup do
162 user = insert(:user, confirmation_pending: true)
163 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
164 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
165 {:ok, delete: delete_user, user: user}
166 end
167
168 test "when activation is not required", %{delete: delete, user: user} do
169 clear_config([:instance, :account_activation_required], false)
170 {:ok, _, _} = SideEffects.handle(delete)
171 ObanHelpers.perform_all()
172
173 refute User.get_cached_by_id(user.id).is_active
174 end
175
176 test "when activation is required", %{delete: delete, user: user} do
177 clear_config([:instance, :account_activation_required], true)
178 {:ok, _, _} = SideEffects.handle(delete)
179 ObanHelpers.perform_all()
180
181 refute User.get_cached_by_id(user.id)
182 end
183 end
184
185 describe "Undo objects" do
186 setup do
187 poster = insert(:user)
188 user = insert(:user)
189 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
190 {:ok, like} = CommonAPI.favorite(user, post.id)
191 {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
192 {:ok, announce} = CommonAPI.repeat(post.id, user)
193 {:ok, block} = CommonAPI.block(user, poster)
194
195 {:ok, undo_data, _meta} = Builder.undo(user, like)
196 {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
197
198 {:ok, undo_data, _meta} = Builder.undo(user, reaction)
199 {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
200
201 {:ok, undo_data, _meta} = Builder.undo(user, announce)
202 {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
203
204 {:ok, undo_data, _meta} = Builder.undo(user, block)
205 {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
206
207 %{
208 like_undo: like_undo,
209 post: post,
210 like: like,
211 reaction_undo: reaction_undo,
212 reaction: reaction,
213 announce_undo: announce_undo,
214 announce: announce,
215 block_undo: block_undo,
216 block: block,
217 poster: poster,
218 user: user
219 }
220 end
221
222 test "deletes the original block", %{
223 block_undo: block_undo,
224 block: block
225 } do
226 {:ok, _block_undo, _meta} = SideEffects.handle(block_undo)
227
228 refute Activity.get_by_id(block.id)
229 end
230
231 test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
232 blocker = User.get_by_ap_id(block.data["actor"])
233 blocked = User.get_by_ap_id(block.data["object"])
234
235 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
236 refute User.blocks?(blocker, blocked)
237 end
238
239 test "an announce undo removes the announce from the object", %{
240 announce_undo: announce_undo,
241 post: post
242 } do
243 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
244
245 object = Object.get_by_ap_id(post.data["object"])
246
247 assert object.data["announcement_count"] == 0
248 assert object.data["announcements"] == []
249 end
250
251 test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
252 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
253 refute Activity.get_by_id(announce.id)
254 end
255
256 test "a reaction undo removes the reaction from the object", %{
257 reaction_undo: reaction_undo,
258 post: post
259 } do
260 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
261
262 object = Object.get_by_ap_id(post.data["object"])
263
264 assert object.data["reaction_count"] == 0
265 assert object.data["reactions"] == []
266 end
267
268 test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
269 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
270 refute Activity.get_by_id(reaction.id)
271 end
272
273 test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
274 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
275
276 object = Object.get_by_ap_id(post.data["object"])
277
278 assert object.data["like_count"] == 0
279 assert object.data["likes"] == []
280 end
281
282 test "deletes the original like", %{like_undo: like_undo, like: like} do
283 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
284 refute Activity.get_by_id(like.id)
285 end
286 end
287
288 describe "like objects" do
289 setup do
290 poster = insert(:user)
291 user = insert(:user)
292 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
293
294 {:ok, like_data, _meta} = Builder.like(user, post.object)
295 {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
296
297 %{like: like, user: user, poster: poster}
298 end
299
300 test "add the like to the original object", %{like: like, user: user} do
301 {:ok, like, _} = SideEffects.handle(like)
302 object = Object.get_by_ap_id(like.data["object"])
303 assert object.data["like_count"] == 1
304 assert user.ap_id in object.data["likes"]
305 end
306
307 test "creates a notification", %{like: like, poster: poster} do
308 {:ok, like, _} = SideEffects.handle(like)
309 assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
310 end
311 end
312
313 describe "creation of ChatMessages" do
314 test "notifies the recipient" do
315 author = insert(:user, local: false)
316 recipient = insert(:user, local: true)
317
318 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
319
320 {:ok, create_activity_data, _meta} =
321 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
322
323 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
324
325 {:ok, _create_activity, _meta} =
326 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
327
328 assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
329 end
330
331 test "it streams the created ChatMessage" do
332 author = insert(:user, local: true)
333 recipient = insert(:user, local: true)
334
335 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
336
337 {:ok, create_activity_data, _meta} =
338 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
339
340 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
341
342 {:ok, _create_activity, meta} =
343 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
344
345 assert [_, _] = meta[:streamables]
346 end
347
348 test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do
349 author = insert(:user, local: true)
350 recipient = insert(:user, local: true)
351
352 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
353
354 {:ok, create_activity_data, _meta} =
355 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
356
357 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
358
359 with_mocks([
360 {
361 Pleroma.Web.Streamer,
362 [],
363 [
364 stream: fn _, _ -> nil end
365 ]
366 },
367 {
368 Pleroma.Web.Push,
369 [],
370 [
371 send: fn _ -> nil end
372 ]
373 }
374 ]) do
375 {:ok, _create_activity, meta} =
376 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
377
378 # The notification gets created
379 assert [notification] = meta[:notifications]
380 assert notification.activity_id == create_activity.id
381
382 # But it is not sent out
383 refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
384 refute called(Pleroma.Web.Push.send(notification))
385
386 # Same for the user chat stream
387 assert [{topics, _}, _] = meta[:streamables]
388 assert topics == ["user", "user:pleroma_chat"]
389 refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
390
391 chat = Chat.get(author.id, recipient.ap_id)
392
393 [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
394
395 assert cm_ref.object.data["content"] == "hey"
396 assert cm_ref.unread == false
397
398 chat = Chat.get(recipient.id, author.ap_id)
399
400 [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
401
402 assert cm_ref.object.data["content"] == "hey"
403 assert cm_ref.unread == true
404 end
405 end
406
407 test "it creates a Chat for the local users and bumps the unread count" do
408 author = insert(:user, local: false)
409 recipient = insert(:user, local: true)
410
411 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
412
413 {:ok, create_activity_data, _meta} =
414 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
415
416 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
417
418 {:ok, _create_activity, _meta} =
419 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
420
421 # An object is created
422 assert Object.get_by_ap_id(chat_message_data["id"])
423
424 # The remote user won't get a chat
425 chat = Chat.get(author.id, recipient.ap_id)
426 refute chat
427
428 # The local user will get a chat
429 chat = Chat.get(recipient.id, author.ap_id)
430 assert chat
431
432 author = insert(:user, local: true)
433 recipient = insert(:user, local: true)
434
435 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
436
437 {:ok, create_activity_data, _meta} =
438 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
439
440 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
441
442 {:ok, _create_activity, _meta} =
443 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
444
445 # Both users are local and get the chat
446 chat = Chat.get(author.id, recipient.ap_id)
447 assert chat
448
449 chat = Chat.get(recipient.id, author.ap_id)
450 assert chat
451 end
452 end
453
454 describe "announce objects" do
455 setup do
456 poster = insert(:user)
457 user = insert(:user)
458 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
459 {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
460
461 {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
462
463 {:ok, private_announce_data, _meta} =
464 Builder.announce(user, private_post.object, public: false)
465
466 {:ok, relay_announce_data, _meta} =
467 Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
468
469 {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
470 {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
471 {:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
472
473 %{
474 announce: announce,
475 user: user,
476 poster: poster,
477 private_announce: private_announce,
478 relay_announce: relay_announce
479 }
480 end
481
482 test "adds the announce to the original object", %{announce: announce, user: user} do
483 {:ok, announce, _} = SideEffects.handle(announce)
484 object = Object.get_by_ap_id(announce.data["object"])
485 assert object.data["announcement_count"] == 1
486 assert user.ap_id in object.data["announcements"]
487 end
488
489 test "does not add the announce to the original object if the actor is a service actor", %{
490 relay_announce: announce
491 } do
492 {:ok, announce, _} = SideEffects.handle(announce)
493 object = Object.get_by_ap_id(announce.data["object"])
494 assert object.data["announcement_count"] == nil
495 end
496
497 test "creates a notification", %{announce: announce, poster: poster} do
498 {:ok, announce, _} = SideEffects.handle(announce)
499 assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
500 end
501
502 test "it streams out the announce", %{announce: announce} do
503 with_mocks([
504 {
505 Pleroma.Web.Streamer,
506 [],
507 [
508 stream: fn _, _ -> nil end
509 ]
510 },
511 {
512 Pleroma.Web.Push,
513 [],
514 [
515 send: fn _ -> nil end
516 ]
517 }
518 ]) do
519 {:ok, announce, _} = SideEffects.handle(announce)
520
521 assert called(
522 Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], announce)
523 )
524
525 assert called(Pleroma.Web.Push.send(:_))
526 end
527 end
528 end
529 end