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