1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 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, async: false
8 alias Pleroma.Notification
11 alias Pleroma.Web.CommonAPI
13 import Pleroma.Factory
16 Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
20 test "does NOT render account/pleroma/relationship by default" do
21 %{user: user, conn: conn} = oauth_access(["read:notifications"])
22 other_user = insert(:user)
24 {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
25 {:ok, [_notification]} = Notification.create_notifications(activity)
29 |> assign(:user, user)
30 |> get("/api/v1/notifications")
31 |> json_response_and_validate_schema(200)
33 assert Enum.all?(response, fn n ->
34 get_in(n, ["account", "pleroma", "relationship"]) == %{}
38 test "list of notifications" do
39 %{user: user, conn: conn} = oauth_access(["read:notifications"])
40 other_user = insert(:user)
42 {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
44 {:ok, [_notification]} = Notification.create_notifications(activity)
48 |> assign(:user, user)
49 |> get("/api/v1/notifications")
52 "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{user.ap_id}\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
54 assert [%{"status" => %{"content" => response}} | _rest] =
55 json_response_and_validate_schema(conn, 200)
57 assert response == expected_response
60 test "by default, does not contain pleroma:chat_mention" do
61 %{user: user, conn: conn} = oauth_access(["read:notifications"])
62 other_user = insert(:user)
64 {:ok, _activity} = CommonAPI.post_chat_message(other_user, user, "hey")
68 |> get("/api/v1/notifications")
69 |> json_response_and_validate_schema(200)
75 |> get("/api/v1/notifications?include_types[]=pleroma:chat_mention")
76 |> json_response_and_validate_schema(200)
81 test "by default, does not contain pleroma:report" do
82 clear_config([:instance, :moderator_privileges], [:reports_manage_reports])
85 other_user = insert(:user)
86 third_user = insert(:user)
88 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true})
90 %{conn: conn} = oauth_access(["read:notifications"], user: user)
92 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
95 CommonAPI.report(third_user, %{account_id: other_user.id, status_ids: [activity.id]})
99 |> get("/api/v1/notifications")
100 |> json_response_and_validate_schema(200)
106 |> get("/api/v1/notifications?include_types[]=pleroma:report")
107 |> json_response_and_validate_schema(200)
112 test "Pleroma:report is hidden for non-privileged users" do
113 clear_config([:instance, :moderator_privileges], [:reports_manage_reports])
116 other_user = insert(:user)
117 third_user = insert(:user)
119 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true})
121 %{conn: conn} = oauth_access(["read:notifications"], user: user)
123 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
126 CommonAPI.report(third_user, %{account_id: other_user.id, status_ids: [activity.id]})
130 |> get("/api/v1/notifications?include_types[]=pleroma:report")
131 |> json_response_and_validate_schema(200)
135 clear_config([:instance, :moderator_privileges], [])
139 |> get("/api/v1/notifications?include_types[]=pleroma:report")
140 |> json_response_and_validate_schema(200)
145 test "excludes mentions from blockers when blockers_visible is false" do
146 clear_config([:activitypub, :blockers_visible], false)
148 %{user: user, conn: conn} = oauth_access(["read:notifications"])
149 blocker = insert(:user)
151 {:ok, _} = CommonAPI.block(blocker, user)
152 {:ok, activity} = CommonAPI.post(blocker, %{status: "hi @#{user.nickname}"})
154 {:ok, [_notification]} = Notification.create_notifications(activity)
158 |> assign(:user, user)
159 |> get("/api/v1/notifications")
161 assert [] == json_response_and_validate_schema(conn, 200)
164 test "getting a single notification" do
165 %{user: user, conn: conn} = oauth_access(["read:notifications"])
166 other_user = insert(:user)
168 {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
170 {:ok, [notification]} = Notification.create_notifications(activity)
172 conn = get(conn, "/api/v1/notifications/#{notification.id}")
175 "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{user.ap_id}\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
177 assert %{"status" => %{"content" => response}} = json_response_and_validate_schema(conn, 200)
178 assert response == expected_response
181 test "dismissing a single notification (deprecated endpoint)" do
182 %{user: user, conn: conn} = oauth_access(["write:notifications"])
183 other_user = insert(:user)
185 {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
187 {:ok, [notification]} = Notification.create_notifications(activity)
191 |> assign(:user, user)
192 |> put_req_header("content-type", "application/json")
193 |> post("/api/v1/notifications/dismiss", %{"id" => to_string(notification.id)})
195 assert %{} = json_response_and_validate_schema(conn, 200)
198 test "dismissing a single notification" do
199 %{user: user, conn: conn} = oauth_access(["write:notifications"])
200 other_user = insert(:user)
202 {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
204 {:ok, [notification]} = Notification.create_notifications(activity)
208 |> assign(:user, user)
209 |> post("/api/v1/notifications/#{notification.id}/dismiss")
211 assert %{} = json_response_and_validate_schema(conn, 200)
214 test "clearing all notifications" do
215 %{user: user, conn: conn} = oauth_access(["write:notifications", "read:notifications"])
216 other_user = insert(:user)
218 {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
220 {:ok, [_notification]} = Notification.create_notifications(activity)
222 ret_conn = post(conn, "/api/v1/notifications/clear")
224 assert %{} = json_response_and_validate_schema(ret_conn, 200)
226 ret_conn = get(conn, "/api/v1/notifications")
228 assert all = json_response_and_validate_schema(ret_conn, 200)
232 test "paginates notifications using min_id, since_id, max_id, and limit" do
233 %{user: user, conn: conn} = oauth_access(["read:notifications"])
234 other_user = insert(:user)
236 {:ok, activity1} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
237 {:ok, activity2} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
238 {:ok, activity3} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
239 {:ok, activity4} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
241 notification1_id = get_notification_id_by_activity(activity1)
242 notification2_id = get_notification_id_by_activity(activity2)
243 notification3_id = get_notification_id_by_activity(activity3)
244 notification4_id = get_notification_id_by_activity(activity4)
246 conn = assign(conn, :user, user)
251 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
252 |> json_response_and_validate_schema(:ok)
254 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
259 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
260 |> json_response_and_validate_schema(:ok)
262 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
267 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
268 |> json_response_and_validate_schema(:ok)
270 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
273 describe "exclude_visibilities" do
274 test "filters notifications for mentions" do
275 %{user: user, conn: conn} = oauth_access(["read:notifications"])
276 other_user = insert(:user)
278 {:ok, public_activity} =
279 CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "public"})
281 {:ok, direct_activity} =
282 CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "direct"})
284 {:ok, unlisted_activity} =
285 CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "unlisted"})
287 {:ok, private_activity} =
288 CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "private"})
290 query = params_to_query(%{exclude_visibilities: ["public", "unlisted", "private"]})
291 conn_res = get(conn, "/api/v1/notifications?" <> query)
293 assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
294 assert id == direct_activity.id
296 query = params_to_query(%{exclude_visibilities: ["public", "unlisted", "direct"]})
297 conn_res = get(conn, "/api/v1/notifications?" <> query)
299 assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
300 assert id == private_activity.id
302 query = params_to_query(%{exclude_visibilities: ["public", "private", "direct"]})
303 conn_res = get(conn, "/api/v1/notifications?" <> query)
305 assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
306 assert id == unlisted_activity.id
308 query = params_to_query(%{exclude_visibilities: ["unlisted", "private", "direct"]})
309 conn_res = get(conn, "/api/v1/notifications?" <> query)
311 assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
312 assert id == public_activity.id
315 test "filters notifications for Like activities" do
317 %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
319 {:ok, public_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "public"})
321 {:ok, direct_activity} =
322 CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "direct"})
324 {:ok, unlisted_activity} =
325 CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"})
327 {:ok, private_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "private"})
329 {:ok, _} = CommonAPI.favorite(user, public_activity.id)
330 {:ok, _} = CommonAPI.favorite(user, direct_activity.id)
331 {:ok, _} = CommonAPI.favorite(user, unlisted_activity.id)
332 {:ok, _} = CommonAPI.favorite(user, private_activity.id)
336 |> get("/api/v1/notifications?exclude_visibilities[]=direct")
337 |> json_response_and_validate_schema(200)
338 |> Enum.map(& &1["status"]["id"])
340 assert public_activity.id in activity_ids
341 assert unlisted_activity.id in activity_ids
342 assert private_activity.id in activity_ids
343 refute direct_activity.id in activity_ids
347 |> get("/api/v1/notifications?exclude_visibilities[]=unlisted")
348 |> json_response_and_validate_schema(200)
349 |> Enum.map(& &1["status"]["id"])
351 assert public_activity.id in activity_ids
352 refute unlisted_activity.id in activity_ids
353 assert private_activity.id in activity_ids
354 assert direct_activity.id in activity_ids
358 |> get("/api/v1/notifications?exclude_visibilities[]=private")
359 |> json_response_and_validate_schema(200)
360 |> Enum.map(& &1["status"]["id"])
362 assert public_activity.id in activity_ids
363 assert unlisted_activity.id in activity_ids
364 refute private_activity.id in activity_ids
365 assert direct_activity.id in activity_ids
369 |> get("/api/v1/notifications?exclude_visibilities[]=public")
370 |> json_response_and_validate_schema(200)
371 |> Enum.map(& &1["status"]["id"])
373 refute public_activity.id in activity_ids
374 assert unlisted_activity.id in activity_ids
375 assert private_activity.id in activity_ids
376 assert direct_activity.id in activity_ids
379 test "filters notifications for Announce activities" do
381 %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
383 {:ok, public_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "public"})
385 {:ok, unlisted_activity} =
386 CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"})
388 {:ok, _} = CommonAPI.repeat(public_activity.id, user)
389 {:ok, _} = CommonAPI.repeat(unlisted_activity.id, user)
393 |> get("/api/v1/notifications?exclude_visibilities[]=unlisted")
394 |> json_response_and_validate_schema(200)
395 |> Enum.map(& &1["status"]["id"])
397 assert public_activity.id in activity_ids
398 refute unlisted_activity.id in activity_ids
401 test "doesn't return less than the requested amount of records when the user's reply is liked" do
403 %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
406 CommonAPI.post(user, %{status: "@#{other_user.nickname}", visibility: "public"})
408 {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
411 CommonAPI.post(other_user, %{
413 visibility: "public",
414 in_reply_to_status_id: activity.id
417 {:ok, _favorite} = CommonAPI.favorite(user, reply.id)
421 |> get("/api/v1/notifications?exclude_visibilities[]=direct&limit=2")
422 |> json_response_and_validate_schema(200)
423 |> Enum.map(& &1["status"]["id"])
425 assert [reply.id, mention.id] == activity_ids
429 test "filters notifications using exclude_types" do
430 %{user: user, conn: conn} = oauth_access(["read:notifications"])
431 other_user = insert(:user)
433 {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
434 {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
435 {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
436 {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
437 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
439 mention_notification_id = get_notification_id_by_activity(mention_activity)
440 favorite_notification_id = get_notification_id_by_activity(favorite_activity)
441 reblog_notification_id = get_notification_id_by_activity(reblog_activity)
442 follow_notification_id = get_notification_id_by_activity(follow_activity)
444 query = params_to_query(%{exclude_types: ["mention", "favourite", "reblog"]})
445 conn_res = get(conn, "/api/v1/notifications?" <> query)
447 assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200)
449 query = params_to_query(%{exclude_types: ["favourite", "reblog", "follow"]})
450 conn_res = get(conn, "/api/v1/notifications?" <> query)
452 assert [%{"id" => ^mention_notification_id}] =
453 json_response_and_validate_schema(conn_res, 200)
455 query = params_to_query(%{exclude_types: ["reblog", "follow", "mention"]})
456 conn_res = get(conn, "/api/v1/notifications?" <> query)
458 assert [%{"id" => ^favorite_notification_id}] =
459 json_response_and_validate_schema(conn_res, 200)
461 query = params_to_query(%{exclude_types: ["follow", "mention", "favourite"]})
462 conn_res = get(conn, "/api/v1/notifications?" <> query)
464 assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200)
467 test "filters notifications using types" do
468 %{user: user, conn: conn} = oauth_access(["read:notifications"])
469 other_user = insert(:user)
471 {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
472 {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
473 {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
474 {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
475 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
477 mention_notification_id = get_notification_id_by_activity(mention_activity)
478 favorite_notification_id = get_notification_id_by_activity(favorite_activity)
479 reblog_notification_id = get_notification_id_by_activity(reblog_activity)
480 follow_notification_id = get_notification_id_by_activity(follow_activity)
482 conn_res = get(conn, "/api/v1/notifications?types[]=follow")
484 assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200)
486 conn_res = get(conn, "/api/v1/notifications?types[]=mention")
488 assert [%{"id" => ^mention_notification_id}] =
489 json_response_and_validate_schema(conn_res, 200)
491 conn_res = get(conn, "/api/v1/notifications?types[]=favourite")
493 assert [%{"id" => ^favorite_notification_id}] =
494 json_response_and_validate_schema(conn_res, 200)
496 conn_res = get(conn, "/api/v1/notifications?types[]=reblog")
498 assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200)
500 result = conn |> get("/api/v1/notifications") |> json_response_and_validate_schema(200)
502 assert length(result) == 4
504 query = params_to_query(%{types: ["follow", "mention", "favourite", "reblog"]})
508 |> get("/api/v1/notifications?" <> query)
509 |> json_response_and_validate_schema(200)
511 assert length(result) == 4
514 test "filtering falls back to include_types" do
515 %{user: user, conn: conn} = oauth_access(["read:notifications"])
516 other_user = insert(:user)
518 {:ok, _activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
519 {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
520 {:ok, _activity} = CommonAPI.favorite(other_user, create_activity.id)
521 {:ok, _activity} = CommonAPI.repeat(create_activity.id, other_user)
522 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
524 follow_notification_id = get_notification_id_by_activity(follow_activity)
526 conn_res = get(conn, "/api/v1/notifications?include_types[]=follow")
528 assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200)
531 test "destroy multiple" do
532 %{user: user, conn: conn} = oauth_access(["read:notifications", "write:notifications"])
533 other_user = insert(:user)
535 {:ok, activity1} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
536 {:ok, activity2} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
537 {:ok, activity3} = CommonAPI.post(user, %{status: "hi @#{other_user.nickname}"})
538 {:ok, activity4} = CommonAPI.post(user, %{status: "hi @#{other_user.nickname}"})
540 notification1_id = get_notification_id_by_activity(activity1)
541 notification2_id = get_notification_id_by_activity(activity2)
542 notification3_id = get_notification_id_by_activity(activity3)
543 notification4_id = get_notification_id_by_activity(activity4)
547 |> get("/api/v1/notifications")
548 |> json_response_and_validate_schema(:ok)
550 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
554 |> assign(:user, other_user)
555 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:notifications"]))
559 |> get("/api/v1/notifications")
560 |> json_response_and_validate_schema(:ok)
562 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
564 query = params_to_query(%{ids: [notification1_id, notification2_id]})
565 conn_destroy = delete(conn, "/api/v1/notifications/destroy_multiple?" <> query)
567 assert json_response_and_validate_schema(conn_destroy, 200) == %{}
571 |> get("/api/v1/notifications")
572 |> json_response_and_validate_schema(:ok)
574 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
577 test "doesn't see notifications after muting user with notifications" do
578 %{user: user, conn: conn} = oauth_access(["read:notifications"])
579 user2 = insert(:user)
581 {:ok, _, _, _} = CommonAPI.follow(user, user2)
582 {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"})
584 ret_conn = get(conn, "/api/v1/notifications")
586 assert length(json_response_and_validate_schema(ret_conn, 200)) == 1
588 {:ok, _user_relationships} = User.mute(user, user2)
590 conn = get(conn, "/api/v1/notifications")
592 assert json_response_and_validate_schema(conn, 200) == []
595 test "see notifications after muting user without notifications" do
596 %{user: user, conn: conn} = oauth_access(["read:notifications"])
597 user2 = insert(:user)
599 {:ok, _, _, _} = CommonAPI.follow(user, user2)
600 {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"})
602 ret_conn = get(conn, "/api/v1/notifications")
604 assert length(json_response_and_validate_schema(ret_conn, 200)) == 1
606 {:ok, _user_relationships} = User.mute(user, user2, %{notifications: false})
608 conn = get(conn, "/api/v1/notifications")
610 assert length(json_response_and_validate_schema(conn, 200)) == 1
613 test "see notifications after muting user with notifications and with_muted parameter" do
614 %{user: user, conn: conn} = oauth_access(["read:notifications"])
615 user2 = insert(:user)
617 {:ok, _, _, _} = CommonAPI.follow(user, user2)
618 {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"})
620 ret_conn = get(conn, "/api/v1/notifications")
622 assert length(json_response_and_validate_schema(ret_conn, 200)) == 1
624 {:ok, _user_relationships} = User.mute(user, user2)
626 conn = get(conn, "/api/v1/notifications?with_muted=true")
628 assert length(json_response_and_validate_schema(conn, 200)) == 1
631 test "see move notifications" do
632 old_user = insert(:user)
633 new_user = insert(:user, also_known_as: [old_user.ap_id])
634 %{user: follower, conn: conn} = oauth_access(["read:notifications"])
636 User.follow(follower, old_user)
637 Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
638 Pleroma.Tests.ObanHelpers.perform_all()
640 conn = get(conn, "/api/v1/notifications")
642 assert length(json_response_and_validate_schema(conn, 200)) == 1
645 describe "link headers" do
646 test "preserves parameters in link headers" do
647 %{user: user, conn: conn} = oauth_access(["read:notifications"])
648 other_user = insert(:user)
651 CommonAPI.post(other_user, %{
652 status: "hi @#{user.nickname}",
657 CommonAPI.post(other_user, %{
658 status: "hi @#{user.nickname}",
662 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
663 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
667 |> assign(:user, user)
668 |> get("/api/v1/notifications?limit=5")
670 assert [link_header] = get_resp_header(conn, "link")
671 assert link_header =~ ~r/limit=5/
672 assert link_header =~ ~r/min_id=#{notification2.id}/
673 assert link_header =~ ~r/max_id=#{notification1.id}/
677 describe "from specified user" do
679 %{user: user, conn: conn} = oauth_access(["read:notifications"])
681 %{id: account_id} = other_user1 = insert(:user)
682 other_user2 = insert(:user)
684 {:ok, _activity} = CommonAPI.post(other_user1, %{status: "hi @#{user.nickname}"})
685 {:ok, _activity} = CommonAPI.post(other_user2, %{status: "bye @#{user.nickname}"})
687 assert [%{"account" => %{"id" => ^account_id}}] =
689 |> assign(:user, user)
690 |> get("/api/v1/notifications?account_id=#{account_id}")
691 |> json_response_and_validate_schema(200)
693 assert %{"error" => "Account is not found"} =
695 |> assign(:user, user)
696 |> get("/api/v1/notifications?account_id=cofe")
697 |> json_response_and_validate_schema(404)
701 defp get_notification_id_by_activity(%{id: id}) do
703 |> Repo.get_by(activity_id: id)
708 defp params_to_query(%{} = params) do
709 Enum.map_join(params, "&", fn
710 {k, v} when is_list(v) -> Enum.map_join(v, "&", &"#{k}[]=#{&1}")
711 {k, v} -> k <> "=" <> v