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