1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
6 use Pleroma.Web.ConnCase
8 alias Pleroma.Notification
11 alias Pleroma.Web.CommonAPI
13 import Pleroma.Factory
15 test "list of notifications" do
16 %{user: user, conn: conn} = oauth_access(["read:notifications"])
17 other_user = insert(:user)
19 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
21 {:ok, [_notification]} = Notification.create_notifications(activity)
25 |> assign(:user, user)
26 |> get("/api/v1/notifications")
29 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
31 }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
33 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
34 assert response == expected_response
37 test "getting a single notification" do
38 %{user: user, conn: conn} = oauth_access(["read:notifications"])
39 other_user = insert(:user)
41 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
43 {:ok, [notification]} = Notification.create_notifications(activity)
45 conn = get(conn, "/api/v1/notifications/#{notification.id}")
48 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
50 }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
52 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
53 assert response == expected_response
56 test "dismissing a single notification" do
57 %{user: user, conn: conn} = oauth_access(["write:notifications"])
58 other_user = insert(:user)
60 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
62 {:ok, [notification]} = Notification.create_notifications(activity)
66 |> assign(:user, user)
67 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
69 assert %{} = json_response(conn, 200)
72 test "clearing all notifications" do
73 %{user: user, conn: conn} = oauth_access(["write:notifications", "read:notifications"])
74 other_user = insert(:user)
76 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
78 {:ok, [_notification]} = Notification.create_notifications(activity)
80 ret_conn = post(conn, "/api/v1/notifications/clear")
82 assert %{} = json_response(ret_conn, 200)
84 ret_conn = get(conn, "/api/v1/notifications")
86 assert all = json_response(ret_conn, 200)
90 test "paginates notifications using min_id, since_id, max_id, and limit" do
91 %{user: user, conn: conn} = oauth_access(["read:notifications"])
92 other_user = insert(:user)
94 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
95 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
96 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
97 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
99 notification1_id = get_notification_id_by_activity(activity1)
100 notification2_id = get_notification_id_by_activity(activity2)
101 notification3_id = get_notification_id_by_activity(activity3)
102 notification4_id = get_notification_id_by_activity(activity4)
104 conn = assign(conn, :user, user)
109 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
110 |> json_response(:ok)
112 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
117 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
118 |> json_response(:ok)
120 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
125 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
126 |> json_response(:ok)
128 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
131 describe "exclude_visibilities" do
132 test "filters notifications for mentions" do
133 %{user: user, conn: conn} = oauth_access(["read:notifications"])
134 other_user = insert(:user)
136 {:ok, public_activity} =
137 CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "public"})
139 {:ok, direct_activity} =
140 CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "direct"})
142 {:ok, unlisted_activity} =
143 CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "unlisted"})
145 {:ok, private_activity} =
146 CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "private"})
149 get(conn, "/api/v1/notifications", %{
150 exclude_visibilities: ["public", "unlisted", "private"]
153 assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
154 assert id == direct_activity.id
157 get(conn, "/api/v1/notifications", %{
158 exclude_visibilities: ["public", "unlisted", "direct"]
161 assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
162 assert id == private_activity.id
165 get(conn, "/api/v1/notifications", %{
166 exclude_visibilities: ["public", "private", "direct"]
169 assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
170 assert id == unlisted_activity.id
173 get(conn, "/api/v1/notifications", %{
174 exclude_visibilities: ["unlisted", "private", "direct"]
177 assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
178 assert id == public_activity.id
181 test "filters notifications for Like activities" do
183 %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
185 {:ok, public_activity} =
186 CommonAPI.post(other_user, %{"status" => ".", "visibility" => "public"})
188 {:ok, direct_activity} =
189 CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "direct"})
191 {:ok, unlisted_activity} =
192 CommonAPI.post(other_user, %{"status" => ".", "visibility" => "unlisted"})
194 {:ok, private_activity} =
195 CommonAPI.post(other_user, %{"status" => ".", "visibility" => "private"})
197 {:ok, _, _} = CommonAPI.favorite(public_activity.id, user)
198 {:ok, _, _} = CommonAPI.favorite(direct_activity.id, user)
199 {:ok, _, _} = CommonAPI.favorite(unlisted_activity.id, user)
200 {:ok, _, _} = CommonAPI.favorite(private_activity.id, user)
204 |> get("/api/v1/notifications", %{exclude_visibilities: ["direct"]})
205 |> json_response(200)
206 |> Enum.map(& &1["status"]["id"])
208 assert public_activity.id in activity_ids
209 assert unlisted_activity.id in activity_ids
210 assert private_activity.id in activity_ids
211 refute direct_activity.id in activity_ids
215 |> get("/api/v1/notifications", %{exclude_visibilities: ["unlisted"]})
216 |> json_response(200)
217 |> Enum.map(& &1["status"]["id"])
219 assert public_activity.id in activity_ids
220 refute unlisted_activity.id in activity_ids
221 assert private_activity.id in activity_ids
222 assert direct_activity.id in activity_ids
226 |> get("/api/v1/notifications", %{exclude_visibilities: ["private"]})
227 |> json_response(200)
228 |> Enum.map(& &1["status"]["id"])
230 assert public_activity.id in activity_ids
231 assert unlisted_activity.id in activity_ids
232 refute private_activity.id in activity_ids
233 assert direct_activity.id in activity_ids
237 |> get("/api/v1/notifications", %{exclude_visibilities: ["public"]})
238 |> json_response(200)
239 |> Enum.map(& &1["status"]["id"])
241 refute public_activity.id in activity_ids
242 assert unlisted_activity.id in activity_ids
243 assert private_activity.id in activity_ids
244 assert direct_activity.id in activity_ids
247 test "filters notifications for Announce activities" do
249 %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
251 {:ok, public_activity} =
252 CommonAPI.post(other_user, %{"status" => ".", "visibility" => "public"})
254 {:ok, unlisted_activity} =
255 CommonAPI.post(other_user, %{"status" => ".", "visibility" => "unlisted"})
257 {:ok, _, _} = CommonAPI.repeat(public_activity.id, user)
258 {:ok, _, _} = CommonAPI.repeat(unlisted_activity.id, user)
262 |> get("/api/v1/notifications", %{exclude_visibilities: ["unlisted"]})
263 |> json_response(200)
264 |> Enum.map(& &1["status"]["id"])
266 assert public_activity.id in activity_ids
267 refute unlisted_activity.id in activity_ids
271 test "filters notifications using exclude_types" do
272 %{user: user, conn: conn} = oauth_access(["read:notifications"])
273 other_user = insert(:user)
275 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
276 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
277 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
278 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
279 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
281 mention_notification_id = get_notification_id_by_activity(mention_activity)
282 favorite_notification_id = get_notification_id_by_activity(favorite_activity)
283 reblog_notification_id = get_notification_id_by_activity(reblog_activity)
284 follow_notification_id = get_notification_id_by_activity(follow_activity)
287 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
289 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
292 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
294 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
297 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
299 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
302 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
304 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
307 test "destroy multiple" do
308 %{user: user, conn: conn} = oauth_access(["read:notifications", "write:notifications"])
309 other_user = insert(:user)
311 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
312 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
313 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
314 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
316 notification1_id = get_notification_id_by_activity(activity1)
317 notification2_id = get_notification_id_by_activity(activity2)
318 notification3_id = get_notification_id_by_activity(activity3)
319 notification4_id = get_notification_id_by_activity(activity4)
323 |> get("/api/v1/notifications")
324 |> json_response(:ok)
326 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
330 |> assign(:user, other_user)
331 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:notifications"]))
335 |> get("/api/v1/notifications")
336 |> json_response(:ok)
338 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
342 |> delete("/api/v1/notifications/destroy_multiple", %{
343 "ids" => [notification1_id, notification2_id]
346 assert json_response(conn_destroy, 200) == %{}
350 |> get("/api/v1/notifications")
351 |> json_response(:ok)
353 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
356 test "doesn't see notifications after muting user with notifications" do
357 %{user: user, conn: conn} = oauth_access(["read:notifications"])
358 user2 = insert(:user)
360 {:ok, _, _, _} = CommonAPI.follow(user, user2)
361 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
363 ret_conn = get(conn, "/api/v1/notifications")
365 assert length(json_response(ret_conn, 200)) == 1
367 {:ok, _user_relationships} = User.mute(user, user2)
369 conn = get(conn, "/api/v1/notifications")
371 assert json_response(conn, 200) == []
374 test "see notifications after muting user without notifications" do
375 %{user: user, conn: conn} = oauth_access(["read:notifications"])
376 user2 = insert(:user)
378 {:ok, _, _, _} = CommonAPI.follow(user, user2)
379 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
381 ret_conn = get(conn, "/api/v1/notifications")
383 assert length(json_response(ret_conn, 200)) == 1
385 {:ok, _user_relationships} = User.mute(user, user2, false)
387 conn = get(conn, "/api/v1/notifications")
389 assert length(json_response(conn, 200)) == 1
392 test "see notifications after muting user with notifications and with_muted parameter" do
393 %{user: user, conn: conn} = oauth_access(["read:notifications"])
394 user2 = insert(:user)
396 {:ok, _, _, _} = CommonAPI.follow(user, user2)
397 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
399 ret_conn = get(conn, "/api/v1/notifications")
401 assert length(json_response(ret_conn, 200)) == 1
403 {:ok, _user_relationships} = User.mute(user, user2)
405 conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"})
407 assert length(json_response(conn, 200)) == 1
410 test "see move notifications with `with_move` parameter" do
411 old_user = insert(:user)
412 new_user = insert(:user, also_known_as: [old_user.ap_id])
413 %{user: follower, conn: conn} = oauth_access(["read:notifications"])
415 User.follow(follower, old_user)
416 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
417 Pleroma.Tests.ObanHelpers.perform_all()
419 ret_conn = get(conn, "/api/v1/notifications")
421 assert json_response(ret_conn, 200) == []
423 conn = get(conn, "/api/v1/notifications", %{"with_move" => "true"})
425 assert length(json_response(conn, 200)) == 1
428 describe "link headers" do
429 test "preserves parameters in link headers" do
430 %{user: user, conn: conn} = oauth_access(["read:notifications"])
431 other_user = insert(:user)
434 CommonAPI.post(other_user, %{
435 "status" => "hi @#{user.nickname}",
436 "visibility" => "public"
440 CommonAPI.post(other_user, %{
441 "status" => "hi @#{user.nickname}",
442 "visibility" => "public"
445 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
446 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
450 |> assign(:user, user)
451 |> get("/api/v1/notifications", %{media_only: true})
453 assert [link_header] = get_resp_header(conn, "link")
454 assert link_header =~ ~r/media_only=true/
455 assert link_header =~ ~r/min_id=#{notification2.id}/
456 assert link_header =~ ~r/max_id=#{notification1.id}/
460 describe "from specified user" do
462 %{user: user, conn: conn} = oauth_access(["read:notifications"])
464 %{id: account_id} = other_user1 = insert(:user)
465 other_user2 = insert(:user)
467 {:ok, _activity} = CommonAPI.post(other_user1, %{"status" => "hi @#{user.nickname}"})
468 {:ok, _activity} = CommonAPI.post(other_user2, %{"status" => "bye @#{user.nickname}"})
470 assert [%{"account" => %{"id" => ^account_id}}] =
472 |> assign(:user, user)
473 |> get("/api/v1/notifications", %{account_id: account_id})
474 |> json_response(200)
476 assert %{"error" => "Account is not found"} =
478 |> assign(:user, user)
479 |> get("/api/v1/notifications", %{account_id: "cofe"})
480 |> json_response(404)
484 defp get_notification_id_by_activity(%{id: id}) do
486 |> Repo.get_by(activity_id: id)