1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.NotificationTest do
11 alias Pleroma.FollowingRelationship
12 alias Pleroma.Notification
14 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.ActivityPub.Builder
18 alias Pleroma.Web.ActivityPub.Transmogrifier
19 alias Pleroma.Web.CommonAPI
20 alias Pleroma.Web.MastodonAPI.NotificationView
21 alias Pleroma.Web.Push
22 alias Pleroma.Web.Streamer
24 describe "create_notifications" do
25 test "never returns nil" do
27 other_user = insert(:user, %{invisible: true})
29 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
30 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
32 refute {:ok, [nil]} == Notification.create_notifications(activity)
35 test "creates a notification for a report" do
36 reporting_user = insert(:user)
37 reported_user = insert(:user)
38 {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true})
40 {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
42 {:ok, [notification]} = Notification.create_notifications(activity)
44 assert notification.user_id == moderator_user.id
45 assert notification.type == "pleroma:report"
48 test "suppresses notification to reporter if reporter is an admin" do
49 reporting_admin = insert(:user, is_admin: true)
50 reported_user = insert(:user)
51 other_admin = insert(:user, is_admin: true)
53 {:ok, activity} = CommonAPI.report(reporting_admin, %{account_id: reported_user.id})
55 {:ok, [notification]} = Notification.create_notifications(activity)
57 refute notification.user_id == reporting_admin.id
58 assert notification.user_id == other_admin.id
59 assert notification.type == "pleroma:report"
62 test "creates a notification for an emoji reaction" do
64 other_user = insert(:user)
66 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
67 {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
69 {:ok, [notification]} = Notification.create_notifications(activity)
71 assert notification.user_id == user.id
72 assert notification.type == "pleroma:emoji_reaction"
75 test "notifies someone when they are directly addressed" do
77 other_user = insert(:user)
78 third_user = insert(:user)
81 CommonAPI.post(user, %{
82 status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
85 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
87 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
88 assert notified_ids == [other_user.id, third_user.id]
89 assert notification.activity_id == activity.id
90 assert notification.type == "mention"
91 assert other_notification.activity_id == activity.id
93 assert [%Pleroma.Marker{unread_count: 2}] =
94 Pleroma.Marker.get_markers(other_user, ["notifications"])
97 test "it creates a notification for subscribed users" do
99 subscriber = insert(:user)
101 User.subscribe(subscriber, user)
103 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
104 {:ok, [notification]} = Notification.create_notifications(status)
106 assert notification.user_id == subscriber.id
109 test "does not create a notification for subscribed users if status is a reply" do
111 other_user = insert(:user)
112 subscriber = insert(:user)
114 User.subscribe(subscriber, other_user)
116 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
118 {:ok, _reply_activity} =
119 CommonAPI.post(other_user, %{
120 status: "test reply",
121 in_reply_to_status_id: activity.id
124 user_notifications = Notification.for_user(user)
125 assert length(user_notifications) == 1
127 subscriber_notifications = Notification.for_user(subscriber)
128 assert Enum.empty?(subscriber_notifications)
132 describe "CommonApi.post/2 notification-related functionality" do
133 test_with_mock "creates but does NOT send notification to blocker user",
138 blocker = insert(:user)
139 {:ok, _user_relationship} = User.block(blocker, user)
141 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
143 blocker_id = blocker.id
144 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
145 refute called(Push.send(:_))
148 test_with_mock "creates but does NOT send notification to notification-muter user",
153 muter = insert(:user)
154 {:ok, _user_relationships} = User.mute(muter, user)
156 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
159 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
160 refute called(Push.send(:_))
163 test_with_mock "creates but does NOT send notification to thread-muter user",
168 thread_muter = insert(:user)
170 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
172 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
174 {:ok, _same_context_activity} =
175 CommonAPI.post(user, %{
176 status: "hey-hey-hey @#{thread_muter.nickname}!",
177 in_reply_to_status_id: activity.id
180 [pre_mute_notification, post_mute_notification] =
181 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
183 pre_mute_notification_id = pre_mute_notification.id
184 post_mute_notification_id = post_mute_notification.id
189 %Notification{id: ^pre_mute_notification_id} -> true
198 %Notification{id: ^post_mute_notification_id} -> true
206 describe "create_notification" do
207 @tag needs_streamer: true
208 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
209 %{user: user, token: oauth_token} = oauth_access(["read"])
213 {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
214 assert_receive {:render_with_user, _, _, _}, 4_000
217 task_user_notification =
220 Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
222 assert_receive {:render_with_user, _, _, _}, 4_000
225 activity = insert(:note_activity)
227 notify = Notification.create_notification(activity, user)
228 assert notify.user_id == user.id
230 Task.await(task_user_notification)
233 test "it creates a notification for user if the user blocks the activity author" do
234 activity = insert(:note_activity)
235 author = User.get_cached_by_ap_id(activity.data["actor"])
237 {:ok, _user_relationship} = User.block(user, author)
239 assert Notification.create_notification(activity, user)
242 test "it creates a notification for the user if the user mutes the activity author" do
243 muter = insert(:user)
244 muted = insert(:user)
245 {:ok, _} = User.mute(muter, muted)
246 muter = Repo.get(User, muter.id)
247 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
249 notification = Notification.create_notification(activity, muter)
251 assert notification.id
252 assert notification.seen
255 test "notification created if user is muted without notifications" do
256 muter = insert(:user)
257 muted = insert(:user)
259 {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
261 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
263 assert Notification.create_notification(activity, muter)
266 test "it creates a notification for an activity from a muted thread" do
267 muter = insert(:user)
268 other_user = insert(:user)
269 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
270 CommonAPI.add_mute(muter, activity)
273 CommonAPI.post(other_user, %{
274 status: "Hi @#{muter.nickname}",
275 in_reply_to_status_id: activity.id
278 notification = Notification.create_notification(activity, muter)
280 assert notification.id
281 assert notification.seen
284 test "it disables notifications from strangers" do
285 follower = insert(:user)
289 notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
292 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
293 refute Notification.create_notification(activity, followed)
296 test "it doesn't create a notification for user if he is the activity author" do
297 activity = insert(:note_activity)
298 author = User.get_cached_by_ap_id(activity.data["actor"])
300 refute Notification.create_notification(activity, author)
303 test "it doesn't create duplicate notifications for follow+subscribed users" do
305 subscriber = insert(:user)
307 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
308 User.subscribe(subscriber, user)
309 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
310 {:ok, [_notif]} = Notification.create_notifications(status)
313 test "it doesn't create subscription notifications if the recipient cannot see the status" do
315 subscriber = insert(:user)
317 User.subscribe(subscriber, user)
319 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
321 assert {:ok, []} == Notification.create_notifications(status)
324 test "it disables notifications from people who are invisible" do
325 author = insert(:user, invisible: true)
328 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
329 refute Notification.create_notification(status, user)
332 test "it doesn't create notifications if content matches with an irreversible filter" do
334 subscriber = insert(:user)
336 User.subscribe(subscriber, user)
337 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
339 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
341 assert {:ok, []} == Notification.create_notifications(status)
344 test "it creates notifications if content matches with a not irreversible filter" do
346 subscriber = insert(:user)
348 User.subscribe(subscriber, user)
349 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
351 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
352 {:ok, [notification]} = Notification.create_notifications(status)
355 refute notification.seen
358 test "it creates notifications when someone likes user's status with a filtered word" do
360 other_user = insert(:user)
361 insert(:filter, user: user, phrase: "tesla", hide: true)
363 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
364 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
366 {:ok, [notification]} = Notification.create_notifications(activity_two)
369 refute notification.seen
373 describe "follow / follow_request notifications" do
374 test "it creates `follow` notification for approved Follow activity" do
376 followed_user = insert(:user, is_locked: false)
378 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
379 assert FollowingRelationship.following?(user, followed_user)
380 assert [notification] = Notification.for_user(followed_user)
382 assert %{type: "follow"} =
383 NotificationView.render("show.json", %{
384 notification: notification,
389 test "it creates `follow_request` notification for pending Follow activity" do
391 followed_user = insert(:user, is_locked: true)
393 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
394 refute FollowingRelationship.following?(user, followed_user)
395 assert [notification] = Notification.for_user(followed_user)
397 render_opts = %{notification: notification, for: followed_user}
398 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
400 # After request is accepted, the same notification is rendered with type "follow":
401 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
404 Repo.get(Notification, notification.id)
405 |> Repo.preload(:activity)
407 assert %{type: "follow"} =
408 NotificationView.render("show.json", notification: notification, for: followed_user)
411 test "it doesn't create a notification for follow-unfollow-follow chains" do
413 followed_user = insert(:user, is_locked: false)
415 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
416 assert FollowingRelationship.following?(user, followed_user)
417 assert [notification] = Notification.for_user(followed_user)
419 CommonAPI.unfollow(user, followed_user)
420 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
422 notification_id = notification.id
423 assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
426 test "dismisses the notification on follow request rejection" do
427 user = insert(:user, is_locked: true)
428 follower = insert(:user)
429 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
430 assert [_notification] = Notification.for_user(user)
431 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
432 assert [] = Notification.for_user(user)
436 describe "get notification" do
437 test "it gets a notification that belongs to the user" do
439 other_user = insert(:user)
441 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
443 {:ok, [notification]} = Notification.create_notifications(activity)
444 {:ok, notification} = Notification.get(other_user, notification.id)
446 assert notification.user_id == other_user.id
449 test "it returns error if the notification doesn't belong to the user" do
451 other_user = insert(:user)
453 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
455 {:ok, [notification]} = Notification.create_notifications(activity)
456 {:error, _notification} = Notification.get(user, notification.id)
460 describe "dismiss notification" do
461 test "it dismisses a notification that belongs to the user" do
463 other_user = insert(:user)
465 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
467 {:ok, [notification]} = Notification.create_notifications(activity)
468 {:ok, notification} = Notification.dismiss(other_user, notification.id)
470 assert notification.user_id == other_user.id
473 test "it returns error if the notification doesn't belong to the user" do
475 other_user = insert(:user)
477 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
479 {:ok, [notification]} = Notification.create_notifications(activity)
480 {:error, _notification} = Notification.dismiss(user, notification.id)
484 describe "clear notification" do
485 test "it clears all notifications belonging to the user" do
487 other_user = insert(:user)
488 third_user = insert(:user)
491 CommonAPI.post(user, %{
492 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
495 {:ok, _notifs} = Notification.create_notifications(activity)
498 CommonAPI.post(user, %{
499 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
502 {:ok, _notifs} = Notification.create_notifications(activity)
503 Notification.clear(other_user)
505 assert Notification.for_user(other_user) == []
506 assert Notification.for_user(third_user) != []
510 describe "set_read_up_to()" do
511 test "it sets all notifications as read up to a specified notification ID" do
513 other_user = insert(:user)
516 CommonAPI.post(user, %{
517 status: "hey @#{other_user.nickname}!"
521 CommonAPI.post(user, %{
522 status: "hey again @#{other_user.nickname}!"
525 [n2, n1] = Notification.for_user(other_user)
530 CommonAPI.post(user, %{
531 status: "hey yet again @#{other_user.nickname}!"
534 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
536 assert read_notification.activity.object
538 [n3, n2, n1] = Notification.for_user(other_user)
540 assert n1.seen == true
541 assert n2.seen == true
542 assert n3.seen == false
544 assert %Pleroma.Marker{} =
548 user_id: other_user.id,
549 timeline: "notifications"
552 assert m.last_read_id == to_string(n2.id)
556 describe "for_user_since/2" do
557 defp days_ago(days) do
559 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
560 -days * 60 * 60 * 24,
565 test "Returns recent notifications" do
566 user1 = insert(:user)
567 user2 = insert(:user)
569 Enum.each(0..10, fn i ->
571 CommonAPI.post(user1, %{
572 status: "hey ##{i} @#{user2.nickname}!"
576 {old, new} = Enum.split(Notification.for_user(user2), 5)
578 Enum.each(old, fn notification ->
580 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
581 |> Pleroma.Repo.update!()
584 recent_notifications_ids =
586 |> Notification.for_user_since(
587 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
591 Enum.each(old, fn %{id: id} ->
592 refute id in recent_notifications_ids
595 Enum.each(new, fn %{id: id} ->
596 assert id in recent_notifications_ids
601 describe "notification target determination / get_notified_from_activity/2" do
602 test "it sends notifications to addressed users in new messages" do
604 other_user = insert(:user)
607 CommonAPI.post(user, %{
608 status: "hey @#{other_user.nickname}!"
611 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
613 assert other_user in enabled_receivers
616 test "it sends notifications to mentioned users in new messages" do
618 other_user = insert(:user)
621 "@context" => "https://www.w3.org/ns/activitystreams",
623 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
624 "actor" => user.ap_id,
627 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
628 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
629 "content" => "message with a Mention tag, but no explicit tagging",
633 "href" => other_user.ap_id,
634 "name" => other_user.nickname
637 "attributedTo" => user.ap_id
641 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
643 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
645 assert other_user in enabled_receivers
648 test "it does not send notifications to users who are only cc in new messages" do
650 other_user = insert(:user)
653 "@context" => "https://www.w3.org/ns/activitystreams",
655 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
656 "cc" => [other_user.ap_id],
657 "actor" => user.ap_id,
660 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
661 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
662 "cc" => [other_user.ap_id],
663 "content" => "hi everyone",
664 "attributedTo" => user.ap_id
668 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
670 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
672 assert other_user not in enabled_receivers
675 test "it does not send notification to mentioned users in likes" do
677 other_user = insert(:user)
678 third_user = insert(:user)
680 {:ok, activity_one} =
681 CommonAPI.post(user, %{
682 status: "hey @#{other_user.nickname}!"
685 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
687 {enabled_receivers, _disabled_receivers} =
688 Notification.get_notified_from_activity(activity_two)
690 assert other_user not in enabled_receivers
693 test "it only notifies the post's author in likes" do
695 other_user = insert(:user)
696 third_user = insert(:user)
698 {:ok, activity_one} =
699 CommonAPI.post(user, %{
700 status: "hey @#{other_user.nickname}!"
703 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
707 |> Map.put("to", [other_user.ap_id | like_data["to"]])
708 |> ActivityPub.persist(local: true)
710 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
712 assert other_user not in enabled_receivers
715 test "it does not send notification to mentioned users in announces" do
717 other_user = insert(:user)
718 third_user = insert(:user)
720 {:ok, activity_one} =
721 CommonAPI.post(user, %{
722 status: "hey @#{other_user.nickname}!"
725 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
727 {enabled_receivers, _disabled_receivers} =
728 Notification.get_notified_from_activity(activity_two)
730 assert other_user not in enabled_receivers
733 test "it returns blocking recipient in disabled recipients list" do
735 other_user = insert(:user)
736 {:ok, _user_relationship} = User.block(other_user, user)
738 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
740 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
742 assert [] == enabled_receivers
743 assert [other_user] == disabled_receivers
746 test "it returns notification-muting recipient in disabled recipients list" do
748 other_user = insert(:user)
749 {:ok, _user_relationships} = User.mute(other_user, user)
751 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
753 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
755 assert [] == enabled_receivers
756 assert [other_user] == disabled_receivers
759 test "it returns thread-muting recipient in disabled recipients list" do
761 other_user = insert(:user)
763 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
765 {:ok, _} = CommonAPI.add_mute(other_user, activity)
767 {:ok, same_context_activity} =
768 CommonAPI.post(user, %{
769 status: "hey-hey-hey @#{other_user.nickname}!",
770 in_reply_to_status_id: activity.id
773 {enabled_receivers, disabled_receivers} =
774 Notification.get_notified_from_activity(same_context_activity)
776 assert [other_user] == disabled_receivers
777 refute other_user in enabled_receivers
780 test "it returns non-following domain-blocking recipient in disabled recipients list" do
781 blocked_domain = "blocked.domain"
782 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
783 other_user = insert(:user)
785 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
787 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
789 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
791 assert [] == enabled_receivers
792 assert [other_user] == disabled_receivers
795 test "it returns following domain-blocking recipient in enabled recipients list" do
796 blocked_domain = "blocked.domain"
797 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
798 other_user = insert(:user)
800 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
801 {:ok, other_user, user} = User.follow(other_user, user)
803 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
805 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
807 assert [other_user] == enabled_receivers
808 assert [] == disabled_receivers
812 describe "notification lifecycle" do
813 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
815 other_user = insert(:user)
817 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
819 assert Enum.empty?(Notification.for_user(user))
821 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
823 assert length(Notification.for_user(user)) == 1
825 {:ok, _} = CommonAPI.delete(activity.id, user)
827 assert Enum.empty?(Notification.for_user(user))
830 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
832 other_user = insert(:user)
834 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
836 assert Enum.empty?(Notification.for_user(user))
838 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
840 assert length(Notification.for_user(user)) == 1
842 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
844 assert Enum.empty?(Notification.for_user(user))
847 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
849 other_user = insert(:user)
851 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
853 assert Enum.empty?(Notification.for_user(user))
855 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
857 assert length(Notification.for_user(user)) == 1
859 {:ok, _} = CommonAPI.delete(activity.id, user)
861 assert Enum.empty?(Notification.for_user(user))
864 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
866 other_user = insert(:user)
868 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
870 assert Enum.empty?(Notification.for_user(user))
872 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
874 assert length(Notification.for_user(user)) == 1
876 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
878 assert Enum.empty?(Notification.for_user(user))
881 test "liking an activity which is already deleted does not generate a notification" do
883 other_user = insert(:user)
885 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
887 assert Enum.empty?(Notification.for_user(user))
889 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
891 assert Enum.empty?(Notification.for_user(user))
893 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
895 assert Enum.empty?(Notification.for_user(user))
898 test "repeating an activity which is already deleted does not generate a notification" do
900 other_user = insert(:user)
902 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
904 assert Enum.empty?(Notification.for_user(user))
906 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
908 assert Enum.empty?(Notification.for_user(user))
910 {:error, _} = CommonAPI.repeat(activity.id, other_user)
912 assert Enum.empty?(Notification.for_user(user))
915 test "replying to a deleted post without tagging does not generate a notification" do
917 other_user = insert(:user)
919 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
920 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
922 {:ok, _reply_activity} =
923 CommonAPI.post(other_user, %{
924 status: "test reply",
925 in_reply_to_status_id: activity.id
928 assert Enum.empty?(Notification.for_user(user))
931 test "notifications are deleted if a local user is deleted" do
933 other_user = insert(:user)
936 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
938 refute Enum.empty?(Notification.for_user(other_user))
940 {:ok, job} = User.delete(user)
941 ObanHelpers.perform(job)
943 assert Enum.empty?(Notification.for_user(other_user))
946 test "notifications are deleted if a remote user is deleted" do
947 remote_user = insert(:user)
948 local_user = insert(:user)
951 "@context" => "https://www.w3.org/ns/activitystreams",
953 "actor" => remote_user.ap_id,
954 "id" => remote_user.ap_id <> "/activities/test",
955 "to" => [local_user.ap_id],
959 "id" => remote_user.ap_id <> "/objects/test",
960 "content" => "Hello!",
964 "href" => local_user.ap_id,
965 "name" => "@#{local_user.nickname}"
968 "to" => [local_user.ap_id],
970 "attributedTo" => remote_user.ap_id
974 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
976 refute Enum.empty?(Notification.for_user(local_user))
978 delete_user_message = %{
979 "@context" => "https://www.w3.org/ns/activitystreams",
980 "id" => remote_user.ap_id <> "/activities/delete",
981 "actor" => remote_user.ap_id,
983 "object" => remote_user.ap_id
986 remote_user_url = remote_user.ap_id
989 %{method: :get, url: ^remote_user_url} ->
990 %Tesla.Env{status: 404, body: ""}
993 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
994 ObanHelpers.perform_all()
996 assert Enum.empty?(Notification.for_user(local_user))
999 test "move activity generates a notification" do
1000 %{ap_id: old_ap_id} = old_user = insert(:user)
1001 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
1002 follower = insert(:user)
1003 other_follower = insert(:user, %{allow_following_move: false})
1005 User.follow(follower, old_user)
1006 User.follow(other_follower, old_user)
1008 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1009 ObanHelpers.perform_all()
1014 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1017 ] = Notification.for_user(follower)
1022 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1025 ] = Notification.for_user(other_follower)
1029 describe "for_user" do
1031 user = insert(:user)
1033 {:ok, %{user: user}}
1036 test "it returns notifications for muted user without notifications", %{user: user} do
1037 muted = insert(:user)
1038 {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
1040 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1042 [notification] = Notification.for_user(user)
1044 assert notification.activity.object
1045 assert notification.seen
1048 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1049 muted = insert(:user)
1050 {:ok, _user_relationships} = User.mute(user, muted)
1052 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1054 assert Notification.for_user(user) == []
1057 test "it doesn't return notifications for blocked user", %{user: user} do
1058 blocked = insert(:user)
1059 {:ok, _user_relationship} = User.block(user, blocked)
1061 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1063 assert Notification.for_user(user) == []
1066 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1067 blocked = insert(:user, ap_id: "http://some-domain.com")
1068 {:ok, user} = User.block_domain(user, "some-domain.com")
1070 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1072 assert Notification.for_user(user) == []
1075 test "it returns notifications for domain-blocked but followed user" do
1076 user = insert(:user)
1077 blocked = insert(:user, ap_id: "http://some-domain.com")
1079 {:ok, user} = User.block_domain(user, "some-domain.com")
1080 {:ok, _, _} = User.follow(user, blocked)
1082 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1084 assert length(Notification.for_user(user)) == 1
1087 test "it doesn't return notifications for muted thread", %{user: user} do
1088 another_user = insert(:user)
1090 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1092 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1093 assert Notification.for_user(user) == []
1096 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1097 muted = insert(:user)
1098 {:ok, _user_relationships} = User.mute(user, muted)
1100 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1102 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1105 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1108 blocked = insert(:user)
1109 {:ok, _user_relationship} = User.block(user, blocked)
1111 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1113 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1116 test "when with_muted is set, " <>
1117 "it doesn't return notifications from a domain-blocked non-followed user",
1119 blocked = insert(:user, ap_id: "http://some-domain.com")
1120 {:ok, user} = User.block_domain(user, "some-domain.com")
1122 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1124 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1127 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1128 another_user = insert(:user)
1130 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1132 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1133 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1136 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1137 insert(:filter, user: user, phrase: "cofe", hide: true)
1138 another_user = insert(:user)
1140 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1142 assert Enum.empty?(Notification.for_user(user))
1145 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1146 insert(:filter, user: user, phrase: "test", hide: false)
1147 another_user = insert(:user)
1149 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1151 assert length(Notification.for_user(user)) == 1
1154 test "it returns notifications about favorites with filtered word", %{user: user} do
1155 insert(:filter, user: user, phrase: "cofe", hide: true)
1156 another_user = insert(:user)
1158 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1159 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1161 assert length(Notification.for_user(user)) == 1