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 test "create_poll_notifications/1" do
133 [user1, user2, user3, _, _] = insert_list(5, :user)
134 question = insert(:question, user: user1)
135 activity = insert(:question_activity, question: question)
137 {:ok, _, _} = CommonAPI.vote(user2, question, [0])
138 {:ok, _, _} = CommonAPI.vote(user3, question, [1])
140 {:ok, notifications} = Notification.create_poll_notifications(activity)
142 assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
145 describe "CommonApi.post/2 notification-related functionality" do
146 test_with_mock "creates but does NOT send notification to blocker user",
151 blocker = insert(:user)
152 {:ok, _user_relationship} = User.block(blocker, user)
154 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
156 blocker_id = blocker.id
157 assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
158 refute called(Push.send(:_))
161 test_with_mock "creates but does NOT send notification to notification-muter user",
166 muter = insert(:user)
167 {:ok, _user_relationships} = User.mute(muter, user)
169 {:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
172 assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
173 refute called(Push.send(:_))
176 test_with_mock "creates but does NOT send notification to thread-muter user",
181 thread_muter = insert(:user)
183 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
185 {:ok, _} = CommonAPI.add_mute(thread_muter, activity)
187 {:ok, _same_context_activity} =
188 CommonAPI.post(user, %{
189 status: "hey-hey-hey @#{thread_muter.nickname}!",
190 in_reply_to_status_id: activity.id
193 [pre_mute_notification, post_mute_notification] =
194 Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
196 pre_mute_notification_id = pre_mute_notification.id
197 post_mute_notification_id = post_mute_notification.id
202 %Notification{id: ^pre_mute_notification_id} -> true
211 %Notification{id: ^post_mute_notification_id} -> true
219 describe "create_notification" do
220 @tag needs_streamer: true
221 test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
222 %{user: user, token: oauth_token} = oauth_access(["read"])
226 {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
227 assert_receive {:render_with_user, _, _, _, "user"}, 4_000
230 task_user_notification =
233 Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
235 assert_receive {:render_with_user, _, _, _, "user:notification"}, 4_000
238 activity = insert(:note_activity)
240 notify = Notification.create_notification(activity, user)
241 assert notify.user_id == user.id
243 Task.await(task_user_notification)
246 test "it creates a notification for user if the user blocks the activity author" do
247 activity = insert(:note_activity)
248 author = User.get_cached_by_ap_id(activity.data["actor"])
250 {:ok, _user_relationship} = User.block(user, author)
252 assert Notification.create_notification(activity, user)
255 test "it creates a notification for the user if the user mutes the activity author" do
256 muter = insert(:user)
257 muted = insert(:user)
258 {:ok, _} = User.mute(muter, muted)
259 muter = Repo.get(User, muter.id)
260 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
262 notification = Notification.create_notification(activity, muter)
264 assert notification.id
265 assert notification.seen
268 test "notification created if user is muted without notifications" do
269 muter = insert(:user)
270 muted = insert(:user)
272 {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
274 {:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
276 assert Notification.create_notification(activity, muter)
279 test "it creates a notification for an activity from a muted thread" do
280 muter = insert(:user)
281 other_user = insert(:user)
282 {:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
283 CommonAPI.add_mute(muter, activity)
286 CommonAPI.post(other_user, %{
287 status: "Hi @#{muter.nickname}",
288 in_reply_to_status_id: activity.id
291 notification = Notification.create_notification(activity, muter)
293 assert notification.id
294 assert notification.seen
297 test "it disables notifications from strangers" do
298 follower = insert(:user)
302 notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
305 {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
306 refute Notification.create_notification(activity, followed)
309 test "it doesn't create a notification for user if he is the activity author" do
310 activity = insert(:note_activity)
311 author = User.get_cached_by_ap_id(activity.data["actor"])
313 refute Notification.create_notification(activity, author)
316 test "it doesn't create duplicate notifications for follow+subscribed users" do
318 subscriber = insert(:user)
320 {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
321 User.subscribe(subscriber, user)
322 {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
323 {:ok, [_notif]} = Notification.create_notifications(status)
326 test "it doesn't create subscription notifications if the recipient cannot see the status" do
328 subscriber = insert(:user)
330 User.subscribe(subscriber, user)
332 {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
334 assert {:ok, []} == Notification.create_notifications(status)
337 test "it disables notifications from people who are invisible" do
338 author = insert(:user, invisible: true)
341 {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
342 refute Notification.create_notification(status, user)
345 test "it doesn't create notifications if content matches with an irreversible filter" do
347 subscriber = insert(:user)
349 User.subscribe(subscriber, user)
350 insert(:filter, user: subscriber, phrase: "cofe", hide: true)
352 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
354 assert {:ok, []} == Notification.create_notifications(status)
357 test "it creates notifications if content matches with a not irreversible filter" do
359 subscriber = insert(:user)
361 User.subscribe(subscriber, user)
362 insert(:filter, user: subscriber, phrase: "cofe", hide: false)
364 {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
365 {:ok, [notification]} = Notification.create_notifications(status)
368 refute notification.seen
371 test "it creates notifications when someone likes user's status with a filtered word" do
373 other_user = insert(:user)
374 insert(:filter, user: user, phrase: "tesla", hide: true)
376 {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
377 {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
379 {:ok, [notification]} = Notification.create_notifications(activity_two)
382 refute notification.seen
386 describe "follow / follow_request notifications" do
387 test "it creates `follow` notification for approved Follow activity" do
389 followed_user = insert(:user, is_locked: false)
391 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
392 assert FollowingRelationship.following?(user, followed_user)
393 assert [notification] = Notification.for_user(followed_user)
395 assert %{type: "follow"} =
396 NotificationView.render("show.json", %{
397 notification: notification,
402 test "it creates `follow_request` notification for pending Follow activity" do
404 followed_user = insert(:user, is_locked: true)
406 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
407 refute FollowingRelationship.following?(user, followed_user)
408 assert [notification] = Notification.for_user(followed_user)
410 render_opts = %{notification: notification, for: followed_user}
411 assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
413 # After request is accepted, the same notification is rendered with type "follow":
414 assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
417 Repo.get(Notification, notification.id)
418 |> Repo.preload(:activity)
420 assert %{type: "follow"} =
421 NotificationView.render("show.json", notification: notification, for: followed_user)
424 test "it doesn't create a notification for follow-unfollow-follow chains" do
426 followed_user = insert(:user, is_locked: false)
428 {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
429 assert FollowingRelationship.following?(user, followed_user)
430 assert [_notification] = Notification.for_user(followed_user)
432 CommonAPI.unfollow(user, followed_user)
433 {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
435 assert Enum.count(Notification.for_user(followed_user)) == 1
438 test "dismisses the notification on follow request rejection" do
439 user = insert(:user, is_locked: true)
440 follower = insert(:user)
441 {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
442 assert [_notification] = Notification.for_user(user)
443 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
444 assert [] = Notification.for_user(user)
448 describe "get notification" do
449 test "it gets a notification that belongs 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 {:ok, notification} = Notification.get(other_user, notification.id)
458 assert notification.user_id == other_user.id
461 test "it returns error if the notification doesn't belong 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 {:error, _notification} = Notification.get(user, notification.id)
472 describe "dismiss notification" do
473 test "it dismisses a notification that belongs 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 {:ok, notification} = Notification.dismiss(other_user, notification.id)
482 assert notification.user_id == other_user.id
485 test "it returns error if the notification doesn't belong to the user" do
487 other_user = insert(:user)
489 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
491 {:ok, [notification]} = Notification.create_notifications(activity)
492 {:error, _notification} = Notification.dismiss(user, notification.id)
496 describe "clear notification" do
497 test "it clears all notifications belonging to the user" do
499 other_user = insert(:user)
500 third_user = insert(:user)
503 CommonAPI.post(user, %{
504 status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
507 {:ok, _notifs} = Notification.create_notifications(activity)
510 CommonAPI.post(user, %{
511 status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
514 {:ok, _notifs} = Notification.create_notifications(activity)
515 Notification.clear(other_user)
517 assert Notification.for_user(other_user) == []
518 assert Notification.for_user(third_user) != []
522 describe "destroy_multiple_from_types/2" do
523 test "clears all notifications of a certain type for a given user" do
524 report_activity = insert(:report_activity)
525 user1 = insert(:user, is_moderator: true, is_admin: true)
526 user2 = insert(:user, is_moderator: true, is_admin: true)
527 {:ok, _} = Notification.create_notifications(report_activity)
530 CommonAPI.post(user2, %{
531 status: "hey @#{user1.nickname} !"
534 Notification.destroy_multiple_from_types(user1, ["pleroma:report"])
536 assert [%Pleroma.Notification{type: "mention"}] = Notification.for_user(user1)
537 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user2)
541 describe "set_read_up_to()" do
542 test "it sets all notifications as read up to a specified notification ID" do
544 other_user = insert(:user)
547 CommonAPI.post(user, %{
548 status: "hey @#{other_user.nickname}!"
552 CommonAPI.post(user, %{
553 status: "hey again @#{other_user.nickname}!"
556 [n2, n1] = Notification.for_user(other_user)
561 CommonAPI.post(user, %{
562 status: "hey yet again @#{other_user.nickname}!"
565 [_, read_notification] = Notification.set_read_up_to(other_user, n2.id)
567 assert read_notification.activity.object
569 [n3, n2, n1] = Notification.for_user(other_user)
571 assert n1.seen == true
572 assert n2.seen == true
573 assert n3.seen == false
575 assert %Pleroma.Marker{} =
579 user_id: other_user.id,
580 timeline: "notifications"
583 assert m.last_read_id == to_string(n2.id)
587 describe "for_user_since/2" do
588 defp days_ago(days) do
590 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
591 -days * 60 * 60 * 24,
596 test "Returns recent notifications" do
597 user1 = insert(:user)
598 user2 = insert(:user)
600 Enum.each(0..10, fn i ->
602 CommonAPI.post(user1, %{
603 status: "hey ##{i} @#{user2.nickname}!"
607 {old, new} = Enum.split(Notification.for_user(user2), 5)
609 Enum.each(old, fn notification ->
611 |> cast(%{updated_at: days_ago(10)}, [:updated_at])
612 |> Pleroma.Repo.update!()
615 recent_notifications_ids =
617 |> Notification.for_user_since(
618 NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
622 Enum.each(old, fn %{id: id} ->
623 refute id in recent_notifications_ids
626 Enum.each(new, fn %{id: id} ->
627 assert id in recent_notifications_ids
632 describe "notification target determination / get_notified_from_activity/2" do
633 test "it sends notifications to addressed users in new messages" do
635 other_user = insert(:user)
638 CommonAPI.post(user, %{
639 status: "hey @#{other_user.nickname}!"
642 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
644 assert other_user in enabled_receivers
647 test "it sends notifications to mentioned users in new messages" do
649 other_user = insert(:user)
652 "@context" => "https://www.w3.org/ns/activitystreams",
654 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
655 "actor" => user.ap_id,
658 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
659 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
660 "content" => "message with a Mention tag, but no explicit tagging",
664 "href" => other_user.ap_id,
665 "name" => other_user.nickname
668 "attributedTo" => user.ap_id
672 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
674 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
676 assert other_user in enabled_receivers
679 test "it does not send notifications to users who are only cc in new messages" do
681 other_user = insert(:user)
684 "@context" => "https://www.w3.org/ns/activitystreams",
686 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
687 "cc" => [other_user.ap_id],
688 "actor" => user.ap_id,
691 "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
692 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
693 "cc" => [other_user.ap_id],
694 "content" => "hi everyone",
695 "attributedTo" => user.ap_id
699 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
701 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
703 assert other_user not in enabled_receivers
706 test "it does not send notification to mentioned users in likes" do
708 other_user = insert(:user)
709 third_user = insert(:user)
711 {:ok, activity_one} =
712 CommonAPI.post(user, %{
713 status: "hey @#{other_user.nickname}!"
716 {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
718 {enabled_receivers, _disabled_receivers} =
719 Notification.get_notified_from_activity(activity_two)
721 assert other_user not in enabled_receivers
724 test "it only notifies the post's author in likes" do
726 other_user = insert(:user)
727 third_user = insert(:user)
729 {:ok, activity_one} =
730 CommonAPI.post(user, %{
731 status: "hey @#{other_user.nickname}!"
734 {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
738 |> Map.put("to", [other_user.ap_id | like_data["to"]])
739 |> ActivityPub.persist(local: true)
741 {enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
743 assert other_user not in enabled_receivers
746 test "it does not send notification to mentioned users in announces" do
748 other_user = insert(:user)
749 third_user = insert(:user)
751 {:ok, activity_one} =
752 CommonAPI.post(user, %{
753 status: "hey @#{other_user.nickname}!"
756 {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
758 {enabled_receivers, _disabled_receivers} =
759 Notification.get_notified_from_activity(activity_two)
761 assert other_user not in enabled_receivers
764 test "it returns blocking recipient in disabled recipients list" do
766 other_user = insert(:user)
767 {:ok, _user_relationship} = User.block(other_user, user)
769 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
771 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
773 assert [] == enabled_receivers
774 assert [other_user] == disabled_receivers
777 test "it returns notification-muting recipient in disabled recipients list" do
779 other_user = insert(:user)
780 {:ok, _user_relationships} = User.mute(other_user, user)
782 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
784 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
786 assert [] == enabled_receivers
787 assert [other_user] == disabled_receivers
790 test "it returns thread-muting recipient in disabled recipients list" do
792 other_user = insert(:user)
794 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
796 {:ok, _} = CommonAPI.add_mute(other_user, activity)
798 {:ok, same_context_activity} =
799 CommonAPI.post(user, %{
800 status: "hey-hey-hey @#{other_user.nickname}!",
801 in_reply_to_status_id: activity.id
804 {enabled_receivers, disabled_receivers} =
805 Notification.get_notified_from_activity(same_context_activity)
807 assert [other_user] == disabled_receivers
808 refute other_user in enabled_receivers
811 test "it returns non-following domain-blocking recipient in disabled recipients list" do
812 blocked_domain = "blocked.domain"
813 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
814 other_user = insert(:user)
816 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
818 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
820 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
822 assert [] == enabled_receivers
823 assert [other_user] == disabled_receivers
826 test "it returns following domain-blocking recipient in enabled recipients list" do
827 blocked_domain = "blocked.domain"
828 user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
829 other_user = insert(:user)
831 {:ok, other_user} = User.block_domain(other_user, blocked_domain)
832 {:ok, other_user, user} = User.follow(other_user, user)
834 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
836 {enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
838 assert [other_user] == enabled_receivers
839 assert [] == disabled_receivers
843 describe "notification lifecycle" do
844 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
846 other_user = insert(:user)
848 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
850 assert Enum.empty?(Notification.for_user(user))
852 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
854 assert length(Notification.for_user(user)) == 1
856 {:ok, _} = CommonAPI.delete(activity.id, user)
858 assert Enum.empty?(Notification.for_user(user))
861 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
863 other_user = insert(:user)
865 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
867 assert Enum.empty?(Notification.for_user(user))
869 {:ok, _} = CommonAPI.favorite(other_user, activity.id)
871 assert length(Notification.for_user(user)) == 1
873 {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
875 assert Enum.empty?(Notification.for_user(user))
878 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
880 other_user = insert(:user)
882 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
884 assert Enum.empty?(Notification.for_user(user))
886 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
888 assert length(Notification.for_user(user)) == 1
890 {:ok, _} = CommonAPI.delete(activity.id, user)
892 assert Enum.empty?(Notification.for_user(user))
895 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
897 other_user = insert(:user)
899 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
901 assert Enum.empty?(Notification.for_user(user))
903 {:ok, _} = CommonAPI.repeat(activity.id, other_user)
905 assert length(Notification.for_user(user)) == 1
907 {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
909 assert Enum.empty?(Notification.for_user(user))
912 test "liking an activity which is already deleted does not generate a notification" do
914 other_user = insert(:user)
916 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
918 assert Enum.empty?(Notification.for_user(user))
920 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
922 assert Enum.empty?(Notification.for_user(user))
924 {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
926 assert Enum.empty?(Notification.for_user(user))
929 test "repeating an activity which is already deleted does not generate a notification" do
931 other_user = insert(:user)
933 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
935 assert Enum.empty?(Notification.for_user(user))
937 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
939 assert Enum.empty?(Notification.for_user(user))
941 {:error, _} = CommonAPI.repeat(activity.id, other_user)
943 assert Enum.empty?(Notification.for_user(user))
946 test "replying to a deleted post without tagging does not generate a notification" do
948 other_user = insert(:user)
950 {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
951 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
953 {:ok, _reply_activity} =
954 CommonAPI.post(other_user, %{
955 status: "test reply",
956 in_reply_to_status_id: activity.id
959 assert Enum.empty?(Notification.for_user(user))
962 test "notifications are deleted if a local user is deleted" do
964 other_user = insert(:user)
967 CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
969 refute Enum.empty?(Notification.for_user(other_user))
971 {:ok, job} = User.delete(user)
972 ObanHelpers.perform(job)
974 assert Enum.empty?(Notification.for_user(other_user))
977 test "notifications are deleted if a remote user is deleted" do
978 remote_user = insert(:user)
979 local_user = insert(:user)
982 "@context" => "https://www.w3.org/ns/activitystreams",
984 "actor" => remote_user.ap_id,
985 "id" => remote_user.ap_id <> "/activities/test",
986 "to" => [local_user.ap_id],
990 "id" => remote_user.ap_id <> "/objects/test",
991 "content" => "Hello!",
995 "href" => local_user.ap_id,
996 "name" => "@#{local_user.nickname}"
999 "to" => [local_user.ap_id],
1001 "attributedTo" => remote_user.ap_id
1005 {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
1007 refute Enum.empty?(Notification.for_user(local_user))
1009 delete_user_message = %{
1010 "@context" => "https://www.w3.org/ns/activitystreams",
1011 "id" => remote_user.ap_id <> "/activities/delete",
1012 "actor" => remote_user.ap_id,
1014 "object" => remote_user.ap_id
1017 remote_user_url = remote_user.ap_id
1020 %{method: :get, url: ^remote_user_url} ->
1021 %Tesla.Env{status: 404, body: ""}
1024 {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
1025 ObanHelpers.perform_all()
1027 assert Enum.empty?(Notification.for_user(local_user))
1030 test "move activity generates a notification" do
1031 %{ap_id: old_ap_id} = old_user = insert(:user)
1032 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
1033 follower = insert(:user)
1034 other_follower = insert(:user, %{allow_following_move: false})
1036 User.follow(follower, old_user)
1037 User.follow(other_follower, old_user)
1039 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
1040 ObanHelpers.perform_all()
1045 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1048 ] = Notification.for_user(follower)
1053 data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
1056 ] = Notification.for_user(other_follower)
1060 describe "for_user" do
1062 user = insert(:user)
1064 {:ok, %{user: user}}
1067 test "it returns notifications for muted user without notifications", %{user: user} do
1068 muted = insert(:user)
1069 {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
1071 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1073 [notification] = Notification.for_user(user)
1075 assert notification.activity.object
1076 assert notification.seen
1079 test "it doesn't return notifications for muted user with notifications", %{user: user} do
1080 muted = insert(:user)
1081 {:ok, _user_relationships} = User.mute(user, muted)
1083 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1085 assert Notification.for_user(user) == []
1088 test "it doesn't return notifications for blocked user", %{user: user} do
1089 blocked = insert(:user)
1090 {:ok, _user_relationship} = User.block(user, blocked)
1092 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1094 assert Notification.for_user(user) == []
1097 test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
1098 blocked = insert(:user, ap_id: "http://some-domain.com")
1099 {:ok, user} = User.block_domain(user, "some-domain.com")
1101 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1103 assert Notification.for_user(user) == []
1106 test "it returns notifications for domain-blocked but followed user" do
1107 user = insert(:user)
1108 blocked = insert(:user, ap_id: "http://some-domain.com")
1110 {:ok, user} = User.block_domain(user, "some-domain.com")
1111 {:ok, _, _} = User.follow(user, blocked)
1113 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1115 assert length(Notification.for_user(user)) == 1
1118 test "it doesn't return notifications for muted thread", %{user: user} do
1119 another_user = insert(:user)
1121 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1123 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1124 assert Notification.for_user(user) == []
1127 test "it returns notifications from a muted user when with_muted is set", %{user: user} do
1128 muted = insert(:user)
1129 {:ok, _user_relationships} = User.mute(user, muted)
1131 {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
1133 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1136 test "it doesn't return notifications from a blocked user when with_muted is set", %{
1139 blocked = insert(:user)
1140 {:ok, _user_relationship} = User.block(user, blocked)
1142 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1144 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1147 test "when with_muted is set, " <>
1148 "it doesn't return notifications from a domain-blocked non-followed user",
1150 blocked = insert(:user, ap_id: "http://some-domain.com")
1151 {:ok, user} = User.block_domain(user, "some-domain.com")
1153 {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
1155 assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
1158 test "it returns notifications from muted threads when with_muted is set", %{user: user} do
1159 another_user = insert(:user)
1161 {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
1163 {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
1164 assert length(Notification.for_user(user, %{with_muted: true})) == 1
1167 test "it doesn't return notifications about mentions with filtered word", %{user: user} do
1168 insert(:filter, user: user, phrase: "cofe", hide: true)
1169 another_user = insert(:user)
1171 {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
1173 assert Enum.empty?(Notification.for_user(user))
1176 test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
1177 insert(:filter, user: user, phrase: "test", hide: false)
1178 another_user = insert(:user)
1180 {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
1182 assert length(Notification.for_user(user)) == 1
1185 test "it returns notifications about favorites with filtered word", %{user: user} do
1186 insert(:filter, user: user, phrase: "cofe", hide: true)
1187 another_user = insert(:user)
1189 {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
1190 {:ok, _} = CommonAPI.favorite(another_user, activity.id)
1192 assert length(Notification.for_user(user)) == 1