logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

notification_test.exs (37893B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.NotificationTest do
  5. use Pleroma.DataCase, async: false
  6. import Pleroma.Factory
  7. alias Pleroma.FollowingRelationship
  8. alias Pleroma.Notification
  9. alias Pleroma.Repo
  10. alias Pleroma.Tests.ObanHelpers
  11. alias Pleroma.User
  12. alias Pleroma.Web.ActivityPub.ActivityPub
  13. alias Pleroma.Web.ActivityPub.Builder
  14. alias Pleroma.Web.ActivityPub.Transmogrifier
  15. alias Pleroma.Web.CommonAPI
  16. alias Pleroma.Web.MastodonAPI.NotificationView
  17. setup do
  18. Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
  19. :ok
  20. end
  21. describe "create_notifications" do
  22. test "never returns nil" do
  23. user = insert(:user)
  24. other_user = insert(:user, %{invisible: true})
  25. {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
  26. {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
  27. refute {:ok, [nil]} == Notification.create_notifications(activity)
  28. end
  29. test "creates a report notification only for privileged users" do
  30. reporting_user = insert(:user)
  31. reported_user = insert(:user)
  32. moderator_user = insert(:user, is_moderator: true)
  33. clear_config([:instance, :moderator_privileges], [])
  34. {:ok, activity1} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
  35. {:ok, []} = Notification.create_notifications(activity1)
  36. clear_config([:instance, :moderator_privileges], [:reports_manage_reports])
  37. {:ok, activity2} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
  38. {:ok, [notification]} = Notification.create_notifications(activity2)
  39. assert notification.user_id == moderator_user.id
  40. assert notification.type == "pleroma:report"
  41. end
  42. test "suppresses notifications for own reports" do
  43. clear_config([:instance, :admin_privileges], [:reports_manage_reports])
  44. reporting_admin = insert(:user, is_admin: true)
  45. reported_user = insert(:user)
  46. other_admin = insert(:user, is_admin: true)
  47. {:ok, activity} = CommonAPI.report(reporting_admin, %{account_id: reported_user.id})
  48. {:ok, [notification]} = Notification.create_notifications(activity)
  49. refute notification.user_id == reporting_admin.id
  50. assert notification.user_id == other_admin.id
  51. assert notification.type == "pleroma:report"
  52. end
  53. test "creates a notification for an emoji reaction" do
  54. user = insert(:user)
  55. other_user = insert(:user)
  56. {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
  57. {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
  58. {:ok, [notification]} = Notification.create_notifications(activity)
  59. assert notification.user_id == user.id
  60. assert notification.type == "pleroma:emoji_reaction"
  61. end
  62. test "notifies someone when they are directly addressed" do
  63. user = insert(:user)
  64. other_user = insert(:user)
  65. third_user = insert(:user)
  66. {:ok, activity} =
  67. CommonAPI.post(user, %{
  68. status: "hey @#{other_user.nickname} and @#{third_user.nickname}"
  69. })
  70. {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
  71. notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
  72. assert notified_ids == [other_user.id, third_user.id]
  73. assert notification.activity_id == activity.id
  74. assert notification.type == "mention"
  75. assert other_notification.activity_id == activity.id
  76. assert [%Pleroma.Marker{unread_count: 2}] =
  77. Pleroma.Marker.get_markers(other_user, ["notifications"])
  78. end
  79. test "it creates a notification for subscribed users" do
  80. user = insert(:user)
  81. subscriber = insert(:user)
  82. User.subscribe(subscriber, user)
  83. {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
  84. {:ok, [notification]} = Notification.create_notifications(status)
  85. assert notification.user_id == subscriber.id
  86. assert notification.type == "status"
  87. end
  88. test "does not create a notification for subscribed users if status is a reply" do
  89. user = insert(:user)
  90. other_user = insert(:user)
  91. subscriber = insert(:user)
  92. User.subscribe(subscriber, other_user)
  93. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  94. {:ok, _reply_activity} =
  95. CommonAPI.post(other_user, %{
  96. status: "test reply",
  97. in_reply_to_status_id: activity.id
  98. })
  99. user_notifications = Notification.for_user(user)
  100. assert length(user_notifications) == 1
  101. subscriber_notifications = Notification.for_user(subscriber)
  102. assert Enum.empty?(subscriber_notifications)
  103. end
  104. test "does not create subscriber notification if mentioned" do
  105. user = insert(:user)
  106. subscriber = insert(:user)
  107. User.subscribe(subscriber, user)
  108. {:ok, status} = CommonAPI.post(user, %{status: "mentioning @#{subscriber.nickname}"})
  109. {:ok, [notification] = notifications} = Notification.create_notifications(status)
  110. assert length(notifications) == 1
  111. assert notification.user_id == subscriber.id
  112. assert notification.type == "mention"
  113. end
  114. test "it sends edited notifications to those who repeated a status" do
  115. user = insert(:user)
  116. repeated_user = insert(:user)
  117. other_user = insert(:user)
  118. {:ok, activity_one} =
  119. CommonAPI.post(user, %{
  120. status: "hey @#{other_user.nickname}!"
  121. })
  122. {:ok, _activity_two} = CommonAPI.repeat(activity_one.id, repeated_user)
  123. {:ok, _edit_activity} =
  124. CommonAPI.update(user, activity_one, %{
  125. status: "hey @#{other_user.nickname}! mew mew"
  126. })
  127. assert [%{type: "reblog"}] = Notification.for_user(user)
  128. assert [%{type: "update"}] = Notification.for_user(repeated_user)
  129. assert [%{type: "mention"}] = Notification.for_user(other_user)
  130. end
  131. end
  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)
  136. {:ok, _, _} = CommonAPI.vote(user2, question, [0])
  137. {:ok, _, _} = CommonAPI.vote(user3, question, [1])
  138. {:ok, notifications} = Notification.create_poll_notifications(activity)
  139. assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
  140. end
  141. describe "create_notification" do
  142. test "it disables notifications from strangers" do
  143. follower = insert(:user)
  144. followed =
  145. insert(:user,
  146. notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
  147. )
  148. {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
  149. refute Notification.create_notification(activity, followed)
  150. end
  151. test "it disables notifications from non-followees" do
  152. follower = insert(:user)
  153. followed =
  154. insert(:user,
  155. notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
  156. )
  157. CommonAPI.follow(follower, followed)
  158. {:ok, activity} = CommonAPI.post(follower, %{status: "hey @#{followed.nickname}"})
  159. refute Notification.create_notification(activity, followed)
  160. end
  161. test "it allows notifications from followees" do
  162. poster = insert(:user)
  163. receiver =
  164. insert(:user,
  165. notification_settings: %Pleroma.User.NotificationSetting{block_from_strangers: true}
  166. )
  167. CommonAPI.follow(receiver, poster)
  168. {:ok, activity} = CommonAPI.post(poster, %{status: "hey @#{receiver.nickname}"})
  169. assert Notification.create_notification(activity, receiver)
  170. end
  171. test "it doesn't create a notification for user if he is the activity author" do
  172. activity = insert(:note_activity)
  173. author = User.get_cached_by_ap_id(activity.data["actor"])
  174. refute Notification.create_notification(activity, author)
  175. end
  176. test "it doesn't create duplicate notifications for follow+subscribed users" do
  177. user = insert(:user)
  178. subscriber = insert(:user)
  179. {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
  180. User.subscribe(subscriber, user)
  181. {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"})
  182. {:ok, [_notif]} = Notification.create_notifications(status)
  183. end
  184. test "it doesn't create subscription notifications if the recipient cannot see the status" do
  185. user = insert(:user)
  186. subscriber = insert(:user)
  187. User.subscribe(subscriber, user)
  188. {:ok, status} = CommonAPI.post(user, %{status: "inwisible", visibility: "direct"})
  189. assert {:ok, []} == Notification.create_notifications(status)
  190. end
  191. test "it disables notifications from people who are invisible" do
  192. author = insert(:user, invisible: true)
  193. user = insert(:user)
  194. {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
  195. refute Notification.create_notification(status, user)
  196. end
  197. test "it doesn't create notifications if content matches with an irreversible filter" do
  198. user = insert(:user)
  199. subscriber = insert(:user)
  200. User.subscribe(subscriber, user)
  201. insert(:filter, user: subscriber, phrase: "cofe", hide: true)
  202. {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
  203. assert {:ok, []} == Notification.create_notifications(status)
  204. end
  205. test "it creates notifications if content matches with a not irreversible filter" do
  206. user = insert(:user)
  207. subscriber = insert(:user)
  208. User.subscribe(subscriber, user)
  209. insert(:filter, user: subscriber, phrase: "cofe", hide: false)
  210. {:ok, status} = CommonAPI.post(user, %{status: "got cofe?"})
  211. {:ok, [notification]} = Notification.create_notifications(status)
  212. assert notification
  213. refute notification.seen
  214. end
  215. test "it creates notifications when someone likes user's status with a filtered word" do
  216. user = insert(:user)
  217. other_user = insert(:user)
  218. insert(:filter, user: user, phrase: "tesla", hide: true)
  219. {:ok, activity_one} = CommonAPI.post(user, %{status: "wow tesla"})
  220. {:ok, activity_two} = CommonAPI.favorite(other_user, activity_one.id)
  221. {:ok, [notification]} = Notification.create_notifications(activity_two)
  222. assert notification
  223. refute notification.seen
  224. end
  225. end
  226. describe "follow / follow_request notifications" do
  227. test "it creates `follow` notification for approved Follow activity" do
  228. user = insert(:user)
  229. followed_user = insert(:user, is_locked: false)
  230. {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
  231. assert FollowingRelationship.following?(user, followed_user)
  232. assert [notification] = Notification.for_user(followed_user)
  233. assert %{type: "follow"} =
  234. NotificationView.render("show.json", %{
  235. notification: notification,
  236. for: followed_user
  237. })
  238. end
  239. test "it creates `follow_request` notification for pending Follow activity" do
  240. user = insert(:user)
  241. followed_user = insert(:user, is_locked: true)
  242. {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
  243. refute FollowingRelationship.following?(user, followed_user)
  244. assert [notification] = Notification.for_user(followed_user)
  245. render_opts = %{notification: notification, for: followed_user}
  246. assert %{type: "follow_request"} = NotificationView.render("show.json", render_opts)
  247. # After request is accepted, the same notification is rendered with type "follow":
  248. assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
  249. notification =
  250. Repo.get(Notification, notification.id)
  251. |> Repo.preload(:activity)
  252. assert %{type: "follow"} =
  253. NotificationView.render("show.json", notification: notification, for: followed_user)
  254. end
  255. test "it doesn't create a notification for follow-unfollow-follow chains" do
  256. user = insert(:user)
  257. followed_user = insert(:user, is_locked: false)
  258. {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
  259. assert FollowingRelationship.following?(user, followed_user)
  260. assert [notification] = Notification.for_user(followed_user)
  261. CommonAPI.unfollow(user, followed_user)
  262. {:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
  263. notification_id = notification.id
  264. assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
  265. end
  266. test "dismisses the notification on follow request rejection" do
  267. user = insert(:user, is_locked: true)
  268. follower = insert(:user)
  269. {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
  270. assert [_notification] = Notification.for_user(user)
  271. {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
  272. assert [] = Notification.for_user(user)
  273. end
  274. end
  275. describe "get notification" do
  276. test "it gets a notification that belongs to the user" do
  277. user = insert(:user)
  278. other_user = insert(:user)
  279. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
  280. {:ok, [notification]} = Notification.create_notifications(activity)
  281. {:ok, notification} = Notification.get(other_user, notification.id)
  282. assert notification.user_id == other_user.id
  283. end
  284. test "it returns error if the notification doesn't belong to the user" do
  285. user = insert(:user)
  286. other_user = insert(:user)
  287. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
  288. {:ok, [notification]} = Notification.create_notifications(activity)
  289. {:error, _notification} = Notification.get(user, notification.id)
  290. end
  291. end
  292. describe "dismiss notification" do
  293. test "it dismisses a notification that belongs to the user" do
  294. user = insert(:user)
  295. other_user = insert(:user)
  296. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
  297. {:ok, [notification]} = Notification.create_notifications(activity)
  298. {:ok, notification} = Notification.dismiss(other_user, notification.id)
  299. assert notification.user_id == other_user.id
  300. end
  301. test "it returns error if the notification doesn't belong to the user" do
  302. user = insert(:user)
  303. other_user = insert(:user)
  304. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}"})
  305. {:ok, [notification]} = Notification.create_notifications(activity)
  306. {:error, _notification} = Notification.dismiss(user, notification.id)
  307. end
  308. end
  309. describe "clear notification" do
  310. test "it clears all notifications belonging to the user" do
  311. user = insert(:user)
  312. other_user = insert(:user)
  313. third_user = insert(:user)
  314. {:ok, activity} =
  315. CommonAPI.post(user, %{
  316. status: "hey @#{other_user.nickname} and @#{third_user.nickname} !"
  317. })
  318. {:ok, _notifs} = Notification.create_notifications(activity)
  319. {:ok, activity} =
  320. CommonAPI.post(user, %{
  321. status: "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
  322. })
  323. {:ok, _notifs} = Notification.create_notifications(activity)
  324. Notification.clear(other_user)
  325. assert Notification.for_user(other_user) == []
  326. assert Notification.for_user(third_user) != []
  327. end
  328. end
  329. describe "set_read_up_to()" do
  330. test "it sets all notifications as read up to a specified notification ID" do
  331. user = insert(:user)
  332. other_user = insert(:user)
  333. {:ok, _activity} =
  334. CommonAPI.post(user, %{
  335. status: "hey @#{other_user.nickname}!"
  336. })
  337. {:ok, _activity} =
  338. CommonAPI.post(user, %{
  339. status: "hey again @#{other_user.nickname}!"
  340. })
  341. [n2, n1] = Notification.for_user(other_user)
  342. assert n2.id > n1.id
  343. {:ok, _activity} =
  344. CommonAPI.post(user, %{
  345. status: "hey yet again @#{other_user.nickname}!"
  346. })
  347. Notification.set_read_up_to(other_user, n2.id)
  348. [n3, n2, n1] = Notification.for_user(other_user)
  349. assert n1.seen == true
  350. assert n2.seen == true
  351. assert n3.seen == false
  352. assert %Pleroma.Marker{} =
  353. m =
  354. Pleroma.Repo.get_by(
  355. Pleroma.Marker,
  356. user_id: other_user.id,
  357. timeline: "notifications"
  358. )
  359. assert m.last_read_id == to_string(n2.id)
  360. end
  361. end
  362. describe "for_user_since/2" do
  363. defp days_ago(days) do
  364. NaiveDateTime.add(
  365. NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
  366. -days * 60 * 60 * 24,
  367. :second
  368. )
  369. end
  370. test "Returns recent notifications" do
  371. user1 = insert(:user)
  372. user2 = insert(:user)
  373. Enum.each(0..10, fn i ->
  374. {:ok, _activity} =
  375. CommonAPI.post(user1, %{
  376. status: "hey ##{i} @#{user2.nickname}!"
  377. })
  378. end)
  379. {old, new} = Enum.split(Notification.for_user(user2), 5)
  380. Enum.each(old, fn notification ->
  381. notification
  382. |> cast(%{updated_at: days_ago(10)}, [:updated_at])
  383. |> Pleroma.Repo.update!()
  384. end)
  385. recent_notifications_ids =
  386. user2
  387. |> Notification.for_user_since(
  388. NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second)
  389. )
  390. |> Enum.map(& &1.id)
  391. Enum.each(old, fn %{id: id} ->
  392. refute id in recent_notifications_ids
  393. end)
  394. Enum.each(new, fn %{id: id} ->
  395. assert id in recent_notifications_ids
  396. end)
  397. end
  398. end
  399. describe "notification target determination / get_notified_from_activity/2" do
  400. test "it sends notifications to addressed users in new messages" do
  401. user = insert(:user)
  402. other_user = insert(:user)
  403. {:ok, activity} =
  404. CommonAPI.post(user, %{
  405. status: "hey @#{other_user.nickname}!"
  406. })
  407. enabled_receivers = Notification.get_notified_from_activity(activity)
  408. assert other_user in enabled_receivers
  409. end
  410. test "it sends notifications to mentioned users in new messages" do
  411. user = insert(:user)
  412. other_user = insert(:user)
  413. create_activity = %{
  414. "@context" => "https://www.w3.org/ns/activitystreams",
  415. "type" => "Create",
  416. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  417. "actor" => user.ap_id,
  418. "object" => %{
  419. "type" => "Note",
  420. "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
  421. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  422. "content" => "message with a Mention tag, but no explicit tagging",
  423. "tag" => [
  424. %{
  425. "type" => "Mention",
  426. "href" => other_user.ap_id,
  427. "name" => other_user.nickname
  428. }
  429. ],
  430. "attributedTo" => user.ap_id
  431. }
  432. }
  433. {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
  434. enabled_receivers = Notification.get_notified_from_activity(activity)
  435. assert other_user in enabled_receivers
  436. end
  437. test "it does not send notifications to users who are only cc in new messages" do
  438. user = insert(:user)
  439. other_user = insert(:user)
  440. create_activity = %{
  441. "@context" => "https://www.w3.org/ns/activitystreams",
  442. "type" => "Create",
  443. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  444. "cc" => [other_user.ap_id],
  445. "actor" => user.ap_id,
  446. "object" => %{
  447. "type" => "Note",
  448. "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
  449. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  450. "cc" => [other_user.ap_id],
  451. "content" => "hi everyone",
  452. "attributedTo" => user.ap_id
  453. }
  454. }
  455. {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
  456. enabled_receivers = Notification.get_notified_from_activity(activity)
  457. assert other_user not in enabled_receivers
  458. end
  459. test "it does not send notification to mentioned users in likes" do
  460. user = insert(:user)
  461. other_user = insert(:user)
  462. third_user = insert(:user)
  463. {:ok, activity_one} =
  464. CommonAPI.post(user, %{
  465. status: "hey @#{other_user.nickname}!"
  466. })
  467. {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
  468. enabled_receivers = Notification.get_notified_from_activity(activity_two)
  469. assert other_user not in enabled_receivers
  470. end
  471. test "it only notifies the post's author in likes" do
  472. user = insert(:user)
  473. other_user = insert(:user)
  474. third_user = insert(:user)
  475. {:ok, activity_one} =
  476. CommonAPI.post(user, %{
  477. status: "hey @#{other_user.nickname}!"
  478. })
  479. {:ok, like_data, _} = Builder.like(third_user, activity_one.object)
  480. {:ok, like, _} =
  481. like_data
  482. |> Map.put("to", [other_user.ap_id | like_data["to"]])
  483. |> ActivityPub.persist(local: true)
  484. enabled_receivers = Notification.get_notified_from_activity(like)
  485. assert other_user not in enabled_receivers
  486. end
  487. test "it does not send notification to mentioned users in announces" do
  488. user = insert(:user)
  489. other_user = insert(:user)
  490. third_user = insert(:user)
  491. {:ok, activity_one} =
  492. CommonAPI.post(user, %{
  493. status: "hey @#{other_user.nickname}!"
  494. })
  495. {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
  496. enabled_receivers = Notification.get_notified_from_activity(activity_two)
  497. assert other_user not in enabled_receivers
  498. end
  499. test "it does not return blocking recipient in recipients list" do
  500. user = insert(:user)
  501. other_user = insert(:user)
  502. {:ok, _user_relationship} = User.block(other_user, user)
  503. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
  504. enabled_receivers = Notification.get_notified_from_activity(activity)
  505. assert [] == enabled_receivers
  506. end
  507. test "it does not return notification-muting recipient in recipients list" do
  508. user = insert(:user)
  509. other_user = insert(:user)
  510. {:ok, _user_relationships} = User.mute(other_user, user)
  511. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
  512. enabled_receivers = Notification.get_notified_from_activity(activity)
  513. assert [] == enabled_receivers
  514. end
  515. test "it does not return thread-muting recipient in recipients list" do
  516. user = insert(:user)
  517. other_user = insert(:user)
  518. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
  519. {:ok, _} = CommonAPI.add_mute(other_user, activity)
  520. {:ok, same_context_activity} =
  521. CommonAPI.post(user, %{
  522. status: "hey-hey-hey @#{other_user.nickname}!",
  523. in_reply_to_status_id: activity.id
  524. })
  525. enabled_receivers = Notification.get_notified_from_activity(same_context_activity)
  526. refute other_user in enabled_receivers
  527. end
  528. test "it does not return non-following domain-blocking recipient in recipients list" do
  529. blocked_domain = "blocked.domain"
  530. user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
  531. other_user = insert(:user)
  532. {:ok, other_user} = User.block_domain(other_user, blocked_domain)
  533. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
  534. enabled_receivers = Notification.get_notified_from_activity(activity)
  535. assert [] == enabled_receivers
  536. end
  537. test "it returns following domain-blocking recipient in enabled recipients list" do
  538. blocked_domain = "blocked.domain"
  539. user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
  540. other_user = insert(:user)
  541. {:ok, other_user} = User.block_domain(other_user, blocked_domain)
  542. {:ok, other_user, user} = User.follow(other_user, user)
  543. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
  544. enabled_receivers = Notification.get_notified_from_activity(activity)
  545. assert [other_user] == enabled_receivers
  546. end
  547. test "it sends edited notifications to those who repeated a status" do
  548. user = insert(:user)
  549. repeated_user = insert(:user)
  550. other_user = insert(:user)
  551. {:ok, activity_one} =
  552. CommonAPI.post(user, %{
  553. status: "hey @#{other_user.nickname}!"
  554. })
  555. {:ok, _activity_two} = CommonAPI.repeat(activity_one.id, repeated_user)
  556. {:ok, edit_activity} =
  557. CommonAPI.update(user, activity_one, %{
  558. status: "hey @#{other_user.nickname}! mew mew"
  559. })
  560. enabled_receivers = Notification.get_notified_from_activity(edit_activity)
  561. assert repeated_user in enabled_receivers
  562. refute other_user in enabled_receivers
  563. end
  564. end
  565. describe "notification lifecycle" do
  566. test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
  567. user = insert(:user)
  568. other_user = insert(:user)
  569. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  570. assert Enum.empty?(Notification.for_user(user))
  571. {:ok, _} = CommonAPI.favorite(other_user, activity.id)
  572. assert length(Notification.for_user(user)) == 1
  573. {:ok, _} = CommonAPI.delete(activity.id, user)
  574. assert Enum.empty?(Notification.for_user(user))
  575. end
  576. test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
  577. user = insert(:user)
  578. other_user = insert(:user)
  579. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  580. assert Enum.empty?(Notification.for_user(user))
  581. {:ok, _} = CommonAPI.favorite(other_user, activity.id)
  582. assert length(Notification.for_user(user)) == 1
  583. {:ok, _} = CommonAPI.unfavorite(activity.id, other_user)
  584. assert Enum.empty?(Notification.for_user(user))
  585. end
  586. test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
  587. user = insert(:user)
  588. other_user = insert(:user)
  589. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  590. assert Enum.empty?(Notification.for_user(user))
  591. {:ok, _} = CommonAPI.repeat(activity.id, other_user)
  592. assert length(Notification.for_user(user)) == 1
  593. {:ok, _} = CommonAPI.delete(activity.id, user)
  594. assert Enum.empty?(Notification.for_user(user))
  595. end
  596. test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
  597. user = insert(:user)
  598. other_user = insert(:user)
  599. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  600. assert Enum.empty?(Notification.for_user(user))
  601. {:ok, _} = CommonAPI.repeat(activity.id, other_user)
  602. assert length(Notification.for_user(user)) == 1
  603. {:ok, _} = CommonAPI.unrepeat(activity.id, other_user)
  604. assert Enum.empty?(Notification.for_user(user))
  605. end
  606. test "liking an activity which is already deleted does not generate a notification" do
  607. user = insert(:user)
  608. other_user = insert(:user)
  609. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  610. assert Enum.empty?(Notification.for_user(user))
  611. {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
  612. assert Enum.empty?(Notification.for_user(user))
  613. {:error, :not_found} = CommonAPI.favorite(other_user, activity.id)
  614. assert Enum.empty?(Notification.for_user(user))
  615. end
  616. test "repeating an activity which is already deleted does not generate a notification" do
  617. user = insert(:user)
  618. other_user = insert(:user)
  619. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  620. assert Enum.empty?(Notification.for_user(user))
  621. {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
  622. assert Enum.empty?(Notification.for_user(user))
  623. {:error, _} = CommonAPI.repeat(activity.id, other_user)
  624. assert Enum.empty?(Notification.for_user(user))
  625. end
  626. test "replying to a deleted post without tagging does not generate a notification" do
  627. user = insert(:user)
  628. other_user = insert(:user)
  629. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  630. {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
  631. {:ok, _reply_activity} =
  632. CommonAPI.post(other_user, %{
  633. status: "test reply",
  634. in_reply_to_status_id: activity.id
  635. })
  636. assert Enum.empty?(Notification.for_user(user))
  637. end
  638. test "notifications are deleted if a local user is deleted" do
  639. user = insert(:user)
  640. other_user = insert(:user)
  641. {:ok, _activity} =
  642. CommonAPI.post(user, %{status: "hi @#{other_user.nickname}", visibility: "direct"})
  643. refute Enum.empty?(Notification.for_user(other_user))
  644. {:ok, job} = User.delete(user)
  645. ObanHelpers.perform(job)
  646. assert Enum.empty?(Notification.for_user(other_user))
  647. end
  648. test "notifications are deleted if a remote user is deleted" do
  649. remote_user = insert(:user)
  650. local_user = insert(:user)
  651. dm_message = %{
  652. "@context" => "https://www.w3.org/ns/activitystreams",
  653. "type" => "Create",
  654. "actor" => remote_user.ap_id,
  655. "id" => remote_user.ap_id <> "/activities/test",
  656. "to" => [local_user.ap_id],
  657. "cc" => [],
  658. "object" => %{
  659. "type" => "Note",
  660. "id" => remote_user.ap_id <> "/objects/test",
  661. "content" => "Hello!",
  662. "tag" => [
  663. %{
  664. "type" => "Mention",
  665. "href" => local_user.ap_id,
  666. "name" => "@#{local_user.nickname}"
  667. }
  668. ],
  669. "to" => [local_user.ap_id],
  670. "cc" => [],
  671. "attributedTo" => remote_user.ap_id
  672. }
  673. }
  674. {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
  675. refute Enum.empty?(Notification.for_user(local_user))
  676. delete_user_message = %{
  677. "@context" => "https://www.w3.org/ns/activitystreams",
  678. "id" => remote_user.ap_id <> "/activities/delete",
  679. "actor" => remote_user.ap_id,
  680. "type" => "Delete",
  681. "object" => remote_user.ap_id
  682. }
  683. remote_user_url = remote_user.ap_id
  684. Tesla.Mock.mock(fn
  685. %{method: :get, url: ^remote_user_url} ->
  686. %Tesla.Env{status: 404, body: ""}
  687. end)
  688. {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
  689. ObanHelpers.perform_all()
  690. assert Enum.empty?(Notification.for_user(local_user))
  691. end
  692. test "move activity generates a notification" do
  693. %{ap_id: old_ap_id} = old_user = insert(:user)
  694. %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
  695. follower = insert(:user)
  696. other_follower = insert(:user, %{allow_following_move: false})
  697. User.follow(follower, old_user)
  698. User.follow(other_follower, old_user)
  699. Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
  700. ObanHelpers.perform_all()
  701. assert [
  702. %{
  703. activity: %{
  704. data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
  705. }
  706. }
  707. ] = Notification.for_user(follower)
  708. assert [
  709. %{
  710. activity: %{
  711. data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
  712. }
  713. }
  714. ] = Notification.for_user(other_follower)
  715. end
  716. end
  717. describe "for_user" do
  718. setup do
  719. user = insert(:user)
  720. {:ok, %{user: user}}
  721. end
  722. test "it returns notifications for muted user without notifications", %{user: user} do
  723. muted = insert(:user)
  724. {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
  725. {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
  726. [notification] = Notification.for_user(user)
  727. assert notification.activity.object
  728. assert notification.seen
  729. end
  730. test "it doesn't return notifications for muted user with notifications", %{user: user} do
  731. muted = insert(:user)
  732. {:ok, _user_relationships} = User.mute(user, muted)
  733. {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
  734. assert Notification.for_user(user) == []
  735. end
  736. test "it doesn't return notifications for blocked user", %{user: user} do
  737. blocked = insert(:user)
  738. {:ok, _user_relationship} = User.block(user, blocked)
  739. {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
  740. assert Notification.for_user(user) == []
  741. end
  742. test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
  743. blocked = insert(:user, ap_id: "http://some-domain.com")
  744. {:ok, user} = User.block_domain(user, "some-domain.com")
  745. {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
  746. assert Notification.for_user(user) == []
  747. end
  748. test "it returns notifications for domain-blocked but followed user" do
  749. user = insert(:user)
  750. blocked = insert(:user, ap_id: "http://some-domain.com")
  751. {:ok, user} = User.block_domain(user, "some-domain.com")
  752. {:ok, _, _} = User.follow(user, blocked)
  753. {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
  754. assert length(Notification.for_user(user)) == 1
  755. end
  756. test "it doesn't return notifications for muted thread", %{user: user} do
  757. another_user = insert(:user)
  758. {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
  759. {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
  760. assert Notification.for_user(user) == []
  761. end
  762. test "it doesn't return notifications from a muted user when with_muted is set", %{user: user} do
  763. muted = insert(:user)
  764. {:ok, _user_relationships} = User.mute(user, muted)
  765. {:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
  766. assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
  767. end
  768. test "it doesn't return notifications from a blocked user when with_muted is set", %{
  769. user: user
  770. } do
  771. blocked = insert(:user)
  772. {:ok, _user_relationship} = User.block(user, blocked)
  773. {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
  774. assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
  775. end
  776. test "when with_muted is set, " <>
  777. "it doesn't return notifications from a domain-blocked non-followed user",
  778. %{user: user} do
  779. blocked = insert(:user, ap_id: "http://some-domain.com")
  780. {:ok, user} = User.block_domain(user, "some-domain.com")
  781. {:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
  782. assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
  783. end
  784. test "it returns notifications from muted threads when with_muted is set", %{user: user} do
  785. another_user = insert(:user)
  786. {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
  787. {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
  788. assert length(Notification.for_user(user, %{with_muted: true})) == 1
  789. end
  790. test "it doesn't return notifications about mentions with filtered word", %{user: user} do
  791. insert(:filter, user: user, phrase: "cofe", hide: true)
  792. another_user = insert(:user)
  793. {:ok, _activity} = CommonAPI.post(another_user, %{status: "@#{user.nickname} got cofe?"})
  794. assert Enum.empty?(Notification.for_user(user))
  795. end
  796. test "it returns notifications about mentions with not hidden filtered word", %{user: user} do
  797. insert(:filter, user: user, phrase: "test", hide: false)
  798. another_user = insert(:user)
  799. {:ok, _} = CommonAPI.post(another_user, %{status: "@#{user.nickname} test"})
  800. assert length(Notification.for_user(user)) == 1
  801. end
  802. test "it returns notifications about favorites with filtered word", %{user: user} do
  803. insert(:filter, user: user, phrase: "cofe", hide: true)
  804. another_user = insert(:user)
  805. {:ok, activity} = CommonAPI.post(user, %{status: "Give me my cofe!"})
  806. {:ok, _} = CommonAPI.favorite(another_user, activity.id)
  807. assert length(Notification.for_user(user)) == 1
  808. end
  809. test "it returns notifications when related object is without content and filters are defined",
  810. %{user: user} do
  811. followed_user = insert(:user, is_locked: true)
  812. insert(:filter, user: followed_user, phrase: "test", hide: true)
  813. {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
  814. refute FollowingRelationship.following?(user, followed_user)
  815. assert [notification] = Notification.for_user(followed_user)
  816. assert %{type: "follow_request"} =
  817. NotificationView.render("show.json", %{
  818. notification: notification,
  819. for: followed_user
  820. })
  821. assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user)
  822. assert [notification] = Notification.for_user(followed_user)
  823. assert %{type: "follow"} =
  824. NotificationView.render("show.json", %{
  825. notification: notification,
  826. for: followed_user
  827. })
  828. end
  829. end
  830. end