Merge remote-tracking branch 'remotes/origin/develop' into 1364-no-pushes-from-blocke...
[akkoma] / test / notification_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.NotificationTest do
6 use Pleroma.DataCase
7
8 import Pleroma.Factory
9 import Mock
10
11 alias Pleroma.FollowingRelationship
12 alias Pleroma.Notification
13 alias Pleroma.Tests.ObanHelpers
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.Transmogrifier
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Web.MastodonAPI.NotificationView
18 alias Pleroma.Web.Push
19 alias Pleroma.Web.Streamer
20
21 describe "create_notifications" do
22 test "creates a notification for an emoji reaction" do
23 user = insert(:user)
24 other_user = insert(:user)
25
26 {:ok, activity} = CommonAPI.post(user, %{"status" => "yeah"})
27 {:ok, activity, _object} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
28
29 {:ok, [notification]} = Notification.create_notifications(activity)
30
31 assert notification.user_id == user.id
32 end
33
34 test "notifies someone when they are directly addressed" do
35 user = insert(:user)
36 other_user = insert(:user)
37 third_user = insert(:user)
38
39 {:ok, activity} =
40 CommonAPI.post(user, %{
41 "status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"
42 })
43
44 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
45
46 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
47 assert notified_ids == [other_user.id, third_user.id]
48 assert notification.activity_id == activity.id
49 assert other_notification.activity_id == activity.id
50 end
51
52 test "it creates a notification for subscribed users" do
53 user = insert(:user)
54 subscriber = insert(:user)
55
56 User.subscribe(subscriber, user)
57
58 {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
59 {:ok, [notification]} = Notification.create_notifications(status)
60
61 assert notification.user_id == subscriber.id
62 end
63
64 test "does not create a notification for subscribed users if status is a reply" do
65 user = insert(:user)
66 other_user = insert(:user)
67 subscriber = insert(:user)
68
69 User.subscribe(subscriber, other_user)
70
71 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
72
73 {:ok, _reply_activity} =
74 CommonAPI.post(other_user, %{
75 "status" => "test reply",
76 "in_reply_to_status_id" => activity.id
77 })
78
79 user_notifications = Notification.for_user(user)
80 assert length(user_notifications) == 1
81
82 subscriber_notifications = Notification.for_user(subscriber)
83 assert Enum.empty?(subscriber_notifications)
84 end
85 end
86
87 describe "CommonApi.post/2 notification-related functionality" do
88 test_with_mock "creates but does NOT send notification to blocker user",
89 Push,
90 [:passthrough],
91 [] do
92 user = insert(:user)
93 blocker = insert(:user)
94 {:ok, _user_relationship} = User.block(blocker, user)
95
96 {:ok, _activity} = CommonAPI.post(user, %{"status" => "hey @#{blocker.nickname}!"})
97
98 blocker_id = blocker.id
99 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
100 refute called(Push.send(:_))
101 end
102
103 test_with_mock "creates but does NOT send notification to notification-muter user",
104 Push,
105 [:passthrough],
106 [] do
107 user = insert(:user)
108 muter = insert(:user)
109 {:ok, _user_relationships} = User.mute(muter, user)
110
111 {:ok, _activity} = CommonAPI.post(user, %{"status" => "hey @#{muter.nickname}!"})
112
113 muter_id = muter.id
114 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
115 refute called(Push.send(:_))
116 end
117
118 test_with_mock "creates but does NOT send notification to thread-muter user",
119 Push,
120 [:passthrough],
121 [] do
122 user = insert(:user)
123 thread_muter = insert(:user)
124
125 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{thread_muter.nickname}!"})
126
127 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
128
129 {:ok, _same_context_activity} =
130 CommonAPI.post(user, %{
131 "status" => "hey-hey-hey @#{thread_muter.nickname}!",
132 "in_reply_to_status_id" => activity.id
133 })
134
135 [pre_mute_notification, post_mute_notification] =
136 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
137
138 pre_mute_notification_id = pre_mute_notification.id
139 post_mute_notification_id = post_mute_notification.id
140
141 assert called(
142 Push.send(
143 :meck.is(fn
144 %Notification{id: ^pre_mute_notification_id} -> true
145 _ -> false
146 end)
147 )
148 )
149
150 refute called(
151 Push.send(
152 :meck.is(fn
153 %Notification{id: ^post_mute_notification_id} -> true
154 _ -> false
155 end)
156 )
157 )
158 end
159 end
160
161 describe "create_notification" do
162 @tag needs_streamer: true
163 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
164 user = insert(:user)
165 task = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
166 task_user_notification = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
167 Streamer.add_socket("user", %{transport_pid: task.pid, assigns: %{user: user}})
168
169 Streamer.add_socket(
170 "user:notification",
171 %{transport_pid: task_user_notification.pid, assigns: %{user: user}}
172 )
173
174 activity = insert(:note_activity)
175
176 notify = Notification.create_notification(activity, user)
177 assert notify.user_id == user.id
178 Task.await(task)
179 Task.await(task_user_notification)
180 end
181
182 test "it creates a notification for user if the user blocks the activity author" do
183 activity = insert(:note_activity)
184 author = User.get_cached_by_ap_id(activity.data["actor"])
185 user = insert(:user)
186 {:ok, _user_relationship} = User.block(user, author)
187
188 assert Notification.create_notification(activity, user)
189 end
190
191 test "it creates a notification for the user if the user mutes the activity author" do
192 muter = insert(:user)
193 muted = insert(:user)
194 {:ok, _} = User.mute(muter, muted)
195 muter = Repo.get(User, muter.id)
196 {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
197
198 assert Notification.create_notification(activity, muter)
199 end
200
201 test "notification created if user is muted without notifications" do
202 muter = insert(:user)
203 muted = insert(:user)
204
205 {:ok, _user_relationships} = User.mute(muter, muted, false)
206
207 {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
208
209 assert Notification.create_notification(activity, muter)
210 end
211
212 test "it creates a notification for an activity from a muted thread" do
213 muter = insert(:user)
214 other_user = insert(:user)
215 {:ok, activity} = CommonAPI.post(muter, %{"status" => "hey"})
216 CommonAPI.add_mute(muter, activity)
217
218 {:ok, activity} =
219 CommonAPI.post(other_user, %{
220 "status" => "Hi @#{muter.nickname}",
221 "in_reply_to_status_id" => activity.id
222 })
223
224 assert Notification.create_notification(activity, muter)
225 end
226
227 test "it disables notifications from followers" do
228 follower = insert(:user)
229
230 followed =
231 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{followers: false})
232
233 User.follow(follower, followed)
234 {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
235 refute Notification.create_notification(activity, followed)
236 end
237
238 test "it disables notifications from non-followers" do
239 follower = insert(:user)
240
241 followed =
242 insert(:user,
243 notification_settings: %Pleroma.User.NotificationSetting{non_followers: false}
244 )
245
246 {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
247 refute Notification.create_notification(activity, followed)
248 end
249
250 test "it disables notifications from people the user follows" do
251 follower =
252 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{follows: false})
253
254 followed = insert(:user)
255 User.follow(follower, followed)
256 follower = Repo.get(User, follower.id)
257 {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
258 refute Notification.create_notification(activity, follower)
259 end
260
261 test "it disables notifications from people the user does not follow" do
262 follower =
263 insert(:user, notification_settings: %Pleroma.User.NotificationSetting{non_follows: false})
264
265 followed = insert(:user)
266 {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
267 refute Notification.create_notification(activity, follower)
268 end
269
270 test "it doesn't create a notification for user if he is the activity author" do
271 activity = insert(:note_activity)
272 author = User.get_cached_by_ap_id(activity.data["actor"])
273
274 refute Notification.create_notification(activity, author)
275 end
276
277 test "it doesn't create duplicate notifications for follow+subscribed users" do
278 user = insert(:user)
279 subscriber = insert(:user)
280
281 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
282 User.subscribe(subscriber, user)
283 {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
284 {:ok, [_notif]} = Notification.create_notifications(status)
285 end
286
287 test "it doesn't create subscription notifications if the recipient cannot see the status" do
288 user = insert(:user)
289 subscriber = insert(:user)
290
291 User.subscribe(subscriber, user)
292
293 {:ok, status} = CommonAPI.post(user, %{"status" => "inwisible", "visibility" => "direct"})
294
295 assert {:ok, []} == Notification.create_notifications(status)
296 end
297 end
298
299 describe "follow / follow_request notifications" do
300 test "it creates `follow` notification for approved Follow activity" do
301 user = insert(:user)
302 followed_user = insert(:user, locked: false)
303
304 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
305 assert FollowingRelationship.following?(user, followed_user)
306 assert [notification] = Notification.for_user(followed_user)
307
308 assert %{type: "follow"} =
309 NotificationView.render("show.json", %{
310 notification: notification,
311 for: followed_user
312 })
313 end
314
315 test "if `follow_request` notifications are enabled, " <>
316 "it creates `follow_request` notification for pending Follow activity" do
317 clear_config([:notifications, :enable_follow_request_notifications], true)
318 user = insert(:user)
319 followed_user = insert(:user, locked: true)
320
321 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
322 refute FollowingRelationship.following?(user, followed_user)
323 assert [notification] = Notification.for_user(followed_user)
324
325 render_opts = %{notification: notification, for: followed_user}
326 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
327
328 # After request is accepted, the same notification is rendered with type "follow":
329 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
330
331 notification_id = notification.id
332 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
333 assert %{type: "follow"} = NotificationView.render("show.json", render_opts)
334 end
335
336 test "if `follow_request` notifications are disabled, " <>
337 "it does NOT create `follow*` notification for pending Follow activity" do
338 clear_config([:notifications, :enable_follow_request_notifications], false)
339 user = insert(:user)
340 followed_user = insert(:user, locked: true)
341
342 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
343 refute FollowingRelationship.following?(user, followed_user)
344 assert [] = Notification.for_user(followed_user)
345
346 # After request is accepted, no new notifications are generated:
347 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
348 assert [] = Notification.for_user(followed_user)
349 end
350
351 test "it doesn't create a notification for follow-unfollow-follow chains" do
352 user = insert(:user)
353 followed_user = insert(:user, locked: false)
354
355 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
356 assert FollowingRelationship.following?(user, followed_user)
357 assert [notification] = Notification.for_user(followed_user)
358
359 CommonAPI.unfollow(user, followed_user)
360 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
361
362 notification_id = notification.id
363 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
364 end
365 end
366
367 describe "get notification" do
368 test "it gets a notification that belongs to the user" do
369 user = insert(:user)
370 other_user = insert(:user)
371
372 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
373
374 {:ok, [notification]} = Notification.create_notifications(activity)
375 {:ok, notification} = Notification.get(other_user, notification.id)
376
377 assert notification.user_id == other_user.id
378 end
379
380 test "it returns error if the notification doesn't belong to the user" do
381 user = insert(:user)
382 other_user = insert(:user)
383
384 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
385
386 {:ok, [notification]} = Notification.create_notifications(activity)
387 {:error, _notification} = Notification.get(user, notification.id)
388 end
389 end
390
391 describe "dismiss notification" do
392 test "it dismisses a notification that belongs to the user" do
393 user = insert(:user)
394 other_user = insert(:user)
395
396 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
397
398 {:ok, [notification]} = Notification.create_notifications(activity)
399 {:ok, notification} = Notification.dismiss(other_user, notification.id)
400
401 assert notification.user_id == other_user.id
402 end
403
404 test "it returns error if the notification doesn't belong to the user" do
405 user = insert(:user)
406 other_user = insert(:user)
407
408 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
409
410 {:ok, [notification]} = Notification.create_notifications(activity)
411 {:error, _notification} = Notification.dismiss(user, notification.id)
412 end
413 end
414
415 describe "clear notification" do
416 test "it clears all notifications belonging to the user" do
417 user = insert(:user)
418 other_user = insert(:user)
419 third_user = insert(:user)
420
421 {:ok, activity} =
422 CommonAPI.post(user, %{
423 "status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"
424 })
425
426 {:ok, _notifs} = Notification.create_notifications(activity)
427
428 {:ok, activity} =
429 CommonAPI.post(user, %{
430 "status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
431 })
432
433 {:ok, _notifs} = Notification.create_notifications(activity)
434 Notification.clear(other_user)
435
436 assert Notification.for_user(other_user) == []
437 assert Notification.for_user(third_user) != []
438 end
439 end
440
441 describe "set_read_up_to()" do
442 test "it sets all notifications as read up to a specified notification ID" do
443 user = insert(:user)
444 other_user = insert(:user)
445
446 {:ok, _activity} =
447 CommonAPI.post(user, %{
448 "status" => "hey @#{other_user.nickname}!"
449 })
450
451 {:ok, _activity} =
452 CommonAPI.post(user, %{
453 "status" => "hey again @#{other_user.nickname}!"
454 })
455
456 [n2, n1] = notifs = Notification.for_user(other_user)
457 assert length(notifs) == 2
458
459 assert n2.id > n1.id
460
461 {:ok, _activity} =
462 CommonAPI.post(user, %{
463 "status" => "hey yet again @#{other_user.nickname}!"
464 })
465
466 Notification.set_read_up_to(other_user, n2.id)
467
468 [n3, n2, n1] = Notification.for_user(other_user)
469
470 assert n1.seen == true
471 assert n2.seen == true
472 assert n3.seen == false
473 end
474 end
475
476 describe "for_user_since/2" do
477 defp days_ago(days) do
478 NaiveDateTime.add(
479 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
480 -days * 60 * 60 * 24,
481 :second
482 )
483 end
484
485 test "Returns recent notifications" do
486 user1 = insert(:user)
487 user2 = insert(:user)
488
489 Enum.each(0..10, fn i ->
490 {:ok, _activity} =
491 CommonAPI.post(user1, %{
492 "status" => "hey ##{i} @#{user2.nickname}!"
493 })
494 end)
495
496 {old, new} = Enum.split(Notification.for_user(user2), 5)
497
498 Enum.each(old, fn notification ->
499 notification
500 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
501 |> Pleroma.Repo.update!()
502 end)
503
504 recent_notifications_ids =
505 user2
506 |> Notification.for_user_since(
507 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
508 )
509 |> Enum.map(& &1.id)
510
511 Enum.each(old, fn %{id: id} ->
512 refute id in recent_notifications_ids
513 end)
514
515 Enum.each(new, fn %{id: id} ->
516 assert id in recent_notifications_ids
517 end)
518 end
519 end
520
521 describe "notification target determination / get_notified_from_activity/2" do
522 test "it sends notifications to addressed users in new messages" do
523 user = insert(:user)
524 other_user = insert(:user)
525
526 {:ok, activity} =
527 CommonAPI.post(user, %{
528 "status" => "hey @#{other_user.nickname}!"
529 })
530
531 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
532
533 assert other_user in enabled_receivers
534 end
535
536 test "it sends notifications to mentioned users in new messages" do
537 user = insert(:user)
538 other_user = insert(:user)
539
540 create_activity = %{
541 "@context" => "https://www.w3.org/ns/activitystreams",
542 "type" => "Create",
543 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
544 "actor" => user.ap_id,
545 "object" => %{
546 "type" => "Note",
547 "content" => "message with a Mention tag, but no explicit tagging",
548 "tag" => [
549 %{
550 "type" => "Mention",
551 "href" => other_user.ap_id,
552 "name" => other_user.nickname
553 }
554 ],
555 "attributedTo" => user.ap_id
556 }
557 }
558
559 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
560
561 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
562
563 assert other_user in enabled_receivers
564 end
565
566 test "it does not send notifications to users who are only cc in new messages" do
567 user = insert(:user)
568 other_user = insert(:user)
569
570 create_activity = %{
571 "@context" => "https://www.w3.org/ns/activitystreams",
572 "type" => "Create",
573 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
574 "cc" => [other_user.ap_id],
575 "actor" => user.ap_id,
576 "object" => %{
577 "type" => "Note",
578 "content" => "hi everyone",
579 "attributedTo" => user.ap_id
580 }
581 }
582
583 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
584
585 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
586
587 assert other_user not in enabled_receivers
588 end
589
590 test "it does not send notification to mentioned users in likes" do
591 user = insert(:user)
592 other_user = insert(:user)
593 third_user = insert(:user)
594
595 {:ok, activity_one} =
596 CommonAPI.post(user, %{
597 "status" => "hey @#{other_user.nickname}!"
598 })
599
600 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
601
602 {enabled_receivers, _disabled_receivers} =
603 Notification.get_notified_from_activity(activity_two)
604
605 assert other_user not in enabled_receivers
606 end
607
608 test "it does not send notification to mentioned users in announces" do
609 user = insert(:user)
610 other_user = insert(:user)
611 third_user = insert(:user)
612
613 {:ok, activity_one} =
614 CommonAPI.post(user, %{
615 "status" => "hey @#{other_user.nickname}!"
616 })
617
618 {:ok, activity_two, _} = CommonAPI.repeat(activity_one.id, third_user)
619
620 {enabled_receivers, _disabled_receivers} =
621 Notification.get_notified_from_activity(activity_two)
622
623 assert other_user not in enabled_receivers
624 end
625
626 test "it returns blocking recipient in disabled recipients list" do
627 user = insert(:user)
628 other_user = insert(:user)
629 {:ok, _user_relationship} = User.block(other_user, user)
630
631 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
632
633 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
634
635 assert [] == enabled_receivers
636 assert [other_user] == disabled_receivers
637 end
638
639 test "it returns notification-muting recipient in disabled recipients list" do
640 user = insert(:user)
641 other_user = insert(:user)
642 {:ok, _user_relationships} = User.mute(other_user, user)
643
644 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
645
646 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
647
648 assert [] == enabled_receivers
649 assert [other_user] == disabled_receivers
650 end
651
652 test "it returns thread-muting recipient in disabled recipients list" do
653 user = insert(:user)
654 other_user = insert(:user)
655
656 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
657
658 {:ok, _} = CommonAPI.add_mute(other_user, activity)
659
660 {:ok, same_context_activity} =
661 CommonAPI.post(user, %{
662 "status" => "hey-hey-hey @#{other_user.nickname}!",
663 "in_reply_to_status_id" => activity.id
664 })
665
666 {enabled_receivers, disabled_receivers} =
667 Notification.get_notified_from_activity(same_context_activity)
668
669 assert [other_user] == disabled_receivers
670 refute other_user in enabled_receivers
671 end
672
673 test "it returns non-following domain-blocking recipient in disabled recipients list" do
674 blocked_domain = "blocked.domain"
675 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
676 other_user = insert(:user)
677
678 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
679
680 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
681
682 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
683
684 assert [] == enabled_receivers
685 assert [other_user] == disabled_receivers
686 end
687
688 test "it returns following domain-blocking recipient in enabled recipients list" do
689 blocked_domain = "blocked.domain"
690 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
691 other_user = insert(:user)
692
693 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
694 {:ok, other_user} = User.follow(other_user, user)
695
696 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}!"})
697
698 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
699
700 assert [other_user] == enabled_receivers
701 assert [] == disabled_receivers
702 end
703 end
704
705 describe "notification lifecycle" do
706 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
707 user = insert(:user)
708 other_user = insert(:user)
709
710 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
711
712 assert Enum.empty?(Notification.for_user(user))
713
714 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
715
716 assert length(Notification.for_user(user)) == 1
717
718 {:ok, _} = CommonAPI.delete(activity.id, user)
719
720 assert Enum.empty?(Notification.for_user(user))
721 end
722
723 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
724 user = insert(:user)
725 other_user = insert(:user)
726
727 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
728
729 assert Enum.empty?(Notification.for_user(user))
730
731 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
732
733 assert length(Notification.for_user(user)) == 1
734
735 {:ok, _, _, _} = CommonAPI.unfavorite(activity.id, other_user)
736
737 assert Enum.empty?(Notification.for_user(user))
738 end
739
740 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
741 user = insert(:user)
742 other_user = insert(:user)
743
744 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
745
746 assert Enum.empty?(Notification.for_user(user))
747
748 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
749
750 assert length(Notification.for_user(user)) == 1
751
752 {:ok, _} = CommonAPI.delete(activity.id, user)
753
754 assert Enum.empty?(Notification.for_user(user))
755 end
756
757 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
758 user = insert(:user)
759 other_user = insert(:user)
760
761 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
762
763 assert Enum.empty?(Notification.for_user(user))
764
765 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
766
767 assert length(Notification.for_user(user)) == 1
768
769 {:ok, _, _} = CommonAPI.unrepeat(activity.id, other_user)
770
771 assert Enum.empty?(Notification.for_user(user))
772 end
773
774 test "liking an activity which is already deleted does not generate a notification" do
775 user = insert(:user)
776 other_user = insert(:user)
777
778 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
779
780 assert Enum.empty?(Notification.for_user(user))
781
782 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
783
784 assert Enum.empty?(Notification.for_user(user))
785
786 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
787
788 assert Enum.empty?(Notification.for_user(user))
789 end
790
791 test "repeating an activity which is already deleted does not generate a notification" do
792 user = insert(:user)
793 other_user = insert(:user)
794
795 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
796
797 assert Enum.empty?(Notification.for_user(user))
798
799 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
800
801 assert Enum.empty?(Notification.for_user(user))
802
803 {:error, _} = CommonAPI.repeat(activity.id, other_user)
804
805 assert Enum.empty?(Notification.for_user(user))
806 end
807
808 test "replying to a deleted post without tagging does not generate a notification" do
809 user = insert(:user)
810 other_user = insert(:user)
811
812 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
813 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
814
815 {:ok, _reply_activity} =
816 CommonAPI.post(other_user, %{
817 "status" => "test reply",
818 "in_reply_to_status_id" => activity.id
819 })
820
821 assert Enum.empty?(Notification.for_user(user))
822 end
823
824 test "notifications are deleted if a local user is deleted" do
825 user = insert(:user)
826 other_user = insert(:user)
827
828 {:ok, _activity} =
829 CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}", "visibility" => "direct"})
830
831 refute Enum.empty?(Notification.for_user(other_user))
832
833 {:ok, job} = User.delete(user)
834 ObanHelpers.perform(job)
835
836 assert Enum.empty?(Notification.for_user(other_user))
837 end
838
839 test "notifications are deleted if a remote user is deleted" do
840 remote_user = insert(:user)
841 local_user = insert(:user)
842
843 dm_message = %{
844 "@context" => "https://www.w3.org/ns/activitystreams",
845 "type" => "Create",
846 "actor" => remote_user.ap_id,
847 "id" => remote_user.ap_id <> "/activities/test",
848 "to" => [local_user.ap_id],
849 "cc" => [],
850 "object" => %{
851 "type" => "Note",
852 "content" => "Hello!",
853 "tag" => [
854 %{
855 "type" => "Mention",
856 "href" => local_user.ap_id,
857 "name" => "@#{local_user.nickname}"
858 }
859 ],
860 "to" => [local_user.ap_id],
861 "cc" => [],
862 "attributedTo" => remote_user.ap_id
863 }
864 }
865
866 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
867
868 refute Enum.empty?(Notification.for_user(local_user))
869
870 delete_user_message = %{
871 "@context" => "https://www.w3.org/ns/activitystreams",
872 "id" => remote_user.ap_id <> "/activities/delete",
873 "actor" => remote_user.ap_id,
874 "type" => "Delete",
875 "object" => remote_user.ap_id
876 }
877
878 remote_user_url = remote_user.ap_id
879
880 Tesla.Mock.mock(fn
881 %{method: :get, url: ^remote_user_url} ->
882 %Tesla.Env{status: 404, body: ""}
883 end)
884
885 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
886 ObanHelpers.perform_all()
887
888 assert Enum.empty?(Notification.for_user(local_user))
889 end
890
891 @tag capture_log: true
892 test "move activity generates a notification" do
893 %{ap_id: old_ap_id} = old_user = insert(:user)
894 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
895 follower = insert(:user)
896 other_follower = insert(:user, %{allow_following_move: false})
897
898 User.follow(follower, old_user)
899 User.follow(other_follower, old_user)
900
901 old_user_url = old_user.ap_id
902
903 body =
904 File.read!("test/fixtures/users_mock/localhost.json")
905 |> String.replace("{{nickname}}", old_user.nickname)
906 |> Jason.encode!()
907
908 Tesla.Mock.mock(fn
909 %{method: :get, url: ^old_user_url} ->
910 %Tesla.Env{status: 200, body: body}
911 end)
912
913 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
914 ObanHelpers.perform_all()
915
916 assert [
917 %{
918 activity: %{
919 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
920 }
921 }
922 ] = Notification.for_user(follower)
923
924 assert [
925 %{
926 activity: %{
927 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
928 }
929 }
930 ] = Notification.for_user(other_follower)
931 end
932 end
933
934 describe "for_user" do
935 test "it returns notifications for muted user without notifications" do
936 user = insert(:user)
937 muted = insert(:user)
938 {:ok, _user_relationships} = User.mute(user, muted, false)
939
940 {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
941
942 assert length(Notification.for_user(user)) == 1
943 end
944
945 test "it doesn't return notifications for muted user with notifications" do
946 user = insert(:user)
947 muted = insert(:user)
948 {:ok, _user_relationships} = User.mute(user, muted)
949
950 {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
951
952 assert Notification.for_user(user) == []
953 end
954
955 test "it doesn't return notifications for blocked user" do
956 user = insert(:user)
957 blocked = insert(:user)
958 {:ok, _user_relationship} = User.block(user, blocked)
959
960 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
961
962 assert Notification.for_user(user) == []
963 end
964
965 test "it doesn't return notifications for domain-blocked non-followed user" do
966 user = insert(:user)
967 blocked = insert(:user, ap_id: "http://some-domain.com")
968 {:ok, user} = User.block_domain(user, "some-domain.com")
969
970 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
971
972 assert Notification.for_user(user) == []
973 end
974
975 test "it returns notifications for domain-blocked but followed user" do
976 user = insert(:user)
977 blocked = insert(:user, ap_id: "http://some-domain.com")
978
979 {:ok, user} = User.block_domain(user, "some-domain.com")
980 {:ok, _} = User.follow(user, blocked)
981
982 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
983
984 assert length(Notification.for_user(user)) == 1
985 end
986
987 test "it doesn't return notifications for muted thread" do
988 user = insert(:user)
989 another_user = insert(:user)
990
991 {:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
992
993 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
994 assert Notification.for_user(user) == []
995 end
996
997 test "it returns notifications from a muted user when with_muted is set" do
998 user = insert(:user)
999 muted = insert(:user)
1000 {:ok, _user_relationships} = User.mute(user, muted)
1001
1002 {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
1003
1004 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1005 end
1006
1007 test "it doesn't return notifications from a blocked user when with_muted is set" do
1008 user = insert(:user)
1009 blocked = insert(:user)
1010 {:ok, _user_relationship} = User.block(user, blocked)
1011
1012 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
1013
1014 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1015 end
1016
1017 test "when with_muted is set, " <>
1018 "it doesn't return notifications from a domain-blocked non-followed user" do
1019 user = insert(:user)
1020 blocked = insert(:user, ap_id: "http://some-domain.com")
1021 {:ok, user} = User.block_domain(user, "some-domain.com")
1022
1023 {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
1024
1025 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1026 end
1027
1028 test "it returns notifications from muted threads when with_muted is set" do
1029 user = insert(:user)
1030 another_user = insert(:user)
1031
1032 {:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
1033
1034 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1035 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1036 end
1037 end
1038 end