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