logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

notification_controller_test.exs (22627B)


  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. defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
  5. use Pleroma.Web.ConnCase
  6. alias Pleroma.Notification
  7. alias Pleroma.Repo
  8. alias Pleroma.User
  9. alias Pleroma.Web.CommonAPI
  10. import Pleroma.Factory
  11. test "does NOT render account/pleroma/relationship by default" do
  12. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  13. other_user = insert(:user)
  14. {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  15. {:ok, [_notification]} = Notification.create_notifications(activity)
  16. response =
  17. conn
  18. |> assign(:user, user)
  19. |> get("/api/v1/notifications")
  20. |> json_response_and_validate_schema(200)
  21. assert Enum.all?(response, fn n ->
  22. get_in(n, ["account", "pleroma", "relationship"]) == %{}
  23. end)
  24. end
  25. test "list of notifications" do
  26. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  27. other_user = insert(:user)
  28. {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  29. {:ok, [_notification]} = Notification.create_notifications(activity)
  30. conn =
  31. conn
  32. |> assign(:user, user)
  33. |> get("/api/v1/notifications")
  34. expected_response =
  35. "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{
  36. user.ap_id
  37. }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
  38. assert [%{"status" => %{"content" => response}} | _rest] =
  39. json_response_and_validate_schema(conn, 200)
  40. assert response == expected_response
  41. end
  42. test "by default, does not contain pleroma:chat_mention" do
  43. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  44. other_user = insert(:user)
  45. {:ok, _activity} = CommonAPI.post_chat_message(other_user, user, "hey")
  46. result =
  47. conn
  48. |> get("/api/v1/notifications")
  49. |> json_response_and_validate_schema(200)
  50. assert [] == result
  51. result =
  52. conn
  53. |> get("/api/v1/notifications?include_types[]=pleroma:chat_mention")
  54. |> json_response_and_validate_schema(200)
  55. assert [_] = result
  56. end
  57. test "getting a single notification" do
  58. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  59. other_user = insert(:user)
  60. {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  61. {:ok, [notification]} = Notification.create_notifications(activity)
  62. conn = get(conn, "/api/v1/notifications/#{notification.id}")
  63. expected_response =
  64. "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{
  65. user.ap_id
  66. }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
  67. assert %{"status" => %{"content" => response}} = json_response_and_validate_schema(conn, 200)
  68. assert response == expected_response
  69. end
  70. test "dismissing a single notification (deprecated endpoint)" do
  71. %{user: user, conn: conn} = oauth_access(["write:notifications"])
  72. other_user = insert(:user)
  73. {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  74. {:ok, [notification]} = Notification.create_notifications(activity)
  75. conn =
  76. conn
  77. |> assign(:user, user)
  78. |> put_req_header("content-type", "application/json")
  79. |> post("/api/v1/notifications/dismiss", %{"id" => to_string(notification.id)})
  80. assert %{} = json_response_and_validate_schema(conn, 200)
  81. end
  82. test "dismissing a single notification" do
  83. %{user: user, conn: conn} = oauth_access(["write:notifications"])
  84. other_user = insert(:user)
  85. {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  86. {:ok, [notification]} = Notification.create_notifications(activity)
  87. conn =
  88. conn
  89. |> assign(:user, user)
  90. |> post("/api/v1/notifications/#{notification.id}/dismiss")
  91. assert %{} = json_response_and_validate_schema(conn, 200)
  92. end
  93. test "clearing all notifications" do
  94. %{user: user, conn: conn} = oauth_access(["write:notifications", "read:notifications"])
  95. other_user = insert(:user)
  96. {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  97. {:ok, [_notification]} = Notification.create_notifications(activity)
  98. ret_conn = post(conn, "/api/v1/notifications/clear")
  99. assert %{} = json_response_and_validate_schema(ret_conn, 200)
  100. ret_conn = get(conn, "/api/v1/notifications")
  101. assert all = json_response_and_validate_schema(ret_conn, 200)
  102. assert all == []
  103. end
  104. test "paginates notifications using min_id, since_id, max_id, and limit" do
  105. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  106. other_user = insert(:user)
  107. {:ok, activity1} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  108. {:ok, activity2} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  109. {:ok, activity3} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  110. {:ok, activity4} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  111. notification1_id = get_notification_id_by_activity(activity1)
  112. notification2_id = get_notification_id_by_activity(activity2)
  113. notification3_id = get_notification_id_by_activity(activity3)
  114. notification4_id = get_notification_id_by_activity(activity4)
  115. conn = assign(conn, :user, user)
  116. # min_id
  117. result =
  118. conn
  119. |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
  120. |> json_response_and_validate_schema(:ok)
  121. assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
  122. # since_id
  123. result =
  124. conn
  125. |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
  126. |> json_response_and_validate_schema(:ok)
  127. assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
  128. # max_id
  129. result =
  130. conn
  131. |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
  132. |> json_response_and_validate_schema(:ok)
  133. assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
  134. end
  135. describe "exclude_visibilities" do
  136. test "filters notifications for mentions" do
  137. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  138. other_user = insert(:user)
  139. {:ok, public_activity} =
  140. CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "public"})
  141. {:ok, direct_activity} =
  142. CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "direct"})
  143. {:ok, unlisted_activity} =
  144. CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "unlisted"})
  145. {:ok, private_activity} =
  146. CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "private"})
  147. query = params_to_query(%{exclude_visibilities: ["public", "unlisted", "private"]})
  148. conn_res = get(conn, "/api/v1/notifications?" <> query)
  149. assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
  150. assert id == direct_activity.id
  151. query = params_to_query(%{exclude_visibilities: ["public", "unlisted", "direct"]})
  152. conn_res = get(conn, "/api/v1/notifications?" <> query)
  153. assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
  154. assert id == private_activity.id
  155. query = params_to_query(%{exclude_visibilities: ["public", "private", "direct"]})
  156. conn_res = get(conn, "/api/v1/notifications?" <> query)
  157. assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
  158. assert id == unlisted_activity.id
  159. query = params_to_query(%{exclude_visibilities: ["unlisted", "private", "direct"]})
  160. conn_res = get(conn, "/api/v1/notifications?" <> query)
  161. assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200)
  162. assert id == public_activity.id
  163. end
  164. test "filters notifications for Like activities" do
  165. user = insert(:user)
  166. %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
  167. {:ok, public_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "public"})
  168. {:ok, direct_activity} =
  169. CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "direct"})
  170. {:ok, unlisted_activity} =
  171. CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"})
  172. {:ok, private_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "private"})
  173. {:ok, _} = CommonAPI.favorite(user, public_activity.id)
  174. {:ok, _} = CommonAPI.favorite(user, direct_activity.id)
  175. {:ok, _} = CommonAPI.favorite(user, unlisted_activity.id)
  176. {:ok, _} = CommonAPI.favorite(user, private_activity.id)
  177. activity_ids =
  178. conn
  179. |> get("/api/v1/notifications?exclude_visibilities[]=direct")
  180. |> json_response_and_validate_schema(200)
  181. |> Enum.map(& &1["status"]["id"])
  182. assert public_activity.id in activity_ids
  183. assert unlisted_activity.id in activity_ids
  184. assert private_activity.id in activity_ids
  185. refute direct_activity.id in activity_ids
  186. activity_ids =
  187. conn
  188. |> get("/api/v1/notifications?exclude_visibilities[]=unlisted")
  189. |> json_response_and_validate_schema(200)
  190. |> Enum.map(& &1["status"]["id"])
  191. assert public_activity.id in activity_ids
  192. refute unlisted_activity.id in activity_ids
  193. assert private_activity.id in activity_ids
  194. assert direct_activity.id in activity_ids
  195. activity_ids =
  196. conn
  197. |> get("/api/v1/notifications?exclude_visibilities[]=private")
  198. |> json_response_and_validate_schema(200)
  199. |> Enum.map(& &1["status"]["id"])
  200. assert public_activity.id in activity_ids
  201. assert unlisted_activity.id in activity_ids
  202. refute private_activity.id in activity_ids
  203. assert direct_activity.id in activity_ids
  204. activity_ids =
  205. conn
  206. |> get("/api/v1/notifications?exclude_visibilities[]=public")
  207. |> json_response_and_validate_schema(200)
  208. |> Enum.map(& &1["status"]["id"])
  209. refute public_activity.id in activity_ids
  210. assert unlisted_activity.id in activity_ids
  211. assert private_activity.id in activity_ids
  212. assert direct_activity.id in activity_ids
  213. end
  214. test "filters notifications for Announce activities" do
  215. user = insert(:user)
  216. %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
  217. {:ok, public_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "public"})
  218. {:ok, unlisted_activity} =
  219. CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"})
  220. {:ok, _} = CommonAPI.repeat(public_activity.id, user)
  221. {:ok, _} = CommonAPI.repeat(unlisted_activity.id, user)
  222. activity_ids =
  223. conn
  224. |> get("/api/v1/notifications?exclude_visibilities[]=unlisted")
  225. |> json_response_and_validate_schema(200)
  226. |> Enum.map(& &1["status"]["id"])
  227. assert public_activity.id in activity_ids
  228. refute unlisted_activity.id in activity_ids
  229. end
  230. test "doesn't return less than the requested amount of records when the user's reply is liked" do
  231. user = insert(:user)
  232. %{user: other_user, conn: conn} = oauth_access(["read:notifications"])
  233. {:ok, mention} =
  234. CommonAPI.post(user, %{status: "@#{other_user.nickname}", visibility: "public"})
  235. {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
  236. {:ok, reply} =
  237. CommonAPI.post(other_user, %{
  238. status: ".",
  239. visibility: "public",
  240. in_reply_to_status_id: activity.id
  241. })
  242. {:ok, _favorite} = CommonAPI.favorite(user, reply.id)
  243. activity_ids =
  244. conn
  245. |> get("/api/v1/notifications?exclude_visibilities[]=direct&limit=2")
  246. |> json_response_and_validate_schema(200)
  247. |> Enum.map(& &1["status"]["id"])
  248. assert [reply.id, mention.id] == activity_ids
  249. end
  250. end
  251. test "filters notifications using exclude_types" do
  252. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  253. other_user = insert(:user)
  254. {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
  255. {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
  256. {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
  257. {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
  258. {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
  259. mention_notification_id = get_notification_id_by_activity(mention_activity)
  260. favorite_notification_id = get_notification_id_by_activity(favorite_activity)
  261. reblog_notification_id = get_notification_id_by_activity(reblog_activity)
  262. follow_notification_id = get_notification_id_by_activity(follow_activity)
  263. query = params_to_query(%{exclude_types: ["mention", "favourite", "reblog"]})
  264. conn_res = get(conn, "/api/v1/notifications?" <> query)
  265. assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200)
  266. query = params_to_query(%{exclude_types: ["favourite", "reblog", "follow"]})
  267. conn_res = get(conn, "/api/v1/notifications?" <> query)
  268. assert [%{"id" => ^mention_notification_id}] =
  269. json_response_and_validate_schema(conn_res, 200)
  270. query = params_to_query(%{exclude_types: ["reblog", "follow", "mention"]})
  271. conn_res = get(conn, "/api/v1/notifications?" <> query)
  272. assert [%{"id" => ^favorite_notification_id}] =
  273. json_response_and_validate_schema(conn_res, 200)
  274. query = params_to_query(%{exclude_types: ["follow", "mention", "favourite"]})
  275. conn_res = get(conn, "/api/v1/notifications?" <> query)
  276. assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200)
  277. end
  278. test "filters notifications using include_types" do
  279. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  280. other_user = insert(:user)
  281. {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
  282. {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
  283. {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
  284. {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
  285. {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
  286. mention_notification_id = get_notification_id_by_activity(mention_activity)
  287. favorite_notification_id = get_notification_id_by_activity(favorite_activity)
  288. reblog_notification_id = get_notification_id_by_activity(reblog_activity)
  289. follow_notification_id = get_notification_id_by_activity(follow_activity)
  290. conn_res = get(conn, "/api/v1/notifications?include_types[]=follow")
  291. assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200)
  292. conn_res = get(conn, "/api/v1/notifications?include_types[]=mention")
  293. assert [%{"id" => ^mention_notification_id}] =
  294. json_response_and_validate_schema(conn_res, 200)
  295. conn_res = get(conn, "/api/v1/notifications?include_types[]=favourite")
  296. assert [%{"id" => ^favorite_notification_id}] =
  297. json_response_and_validate_schema(conn_res, 200)
  298. conn_res = get(conn, "/api/v1/notifications?include_types[]=reblog")
  299. assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200)
  300. result = conn |> get("/api/v1/notifications") |> json_response_and_validate_schema(200)
  301. assert length(result) == 4
  302. query = params_to_query(%{include_types: ["follow", "mention", "favourite", "reblog"]})
  303. result =
  304. conn
  305. |> get("/api/v1/notifications?" <> query)
  306. |> json_response_and_validate_schema(200)
  307. assert length(result) == 4
  308. end
  309. test "destroy multiple" do
  310. %{user: user, conn: conn} = oauth_access(["read:notifications", "write:notifications"])
  311. other_user = insert(:user)
  312. {:ok, activity1} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  313. {:ok, activity2} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
  314. {:ok, activity3} = CommonAPI.post(user, %{status: "hi @#{other_user.nickname}"})
  315. {: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)
  320. result =
  321. conn
  322. |> get("/api/v1/notifications")
  323. |> json_response_and_validate_schema(:ok)
  324. assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
  325. conn2 =
  326. conn
  327. |> assign(:user, other_user)
  328. |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:notifications"]))
  329. result =
  330. conn2
  331. |> get("/api/v1/notifications")
  332. |> json_response_and_validate_schema(:ok)
  333. assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
  334. query = params_to_query(%{ids: [notification1_id, notification2_id]})
  335. conn_destroy = delete(conn, "/api/v1/notifications/destroy_multiple?" <> query)
  336. assert json_response_and_validate_schema(conn_destroy, 200) == %{}
  337. result =
  338. conn2
  339. |> get("/api/v1/notifications")
  340. |> json_response_and_validate_schema(:ok)
  341. assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
  342. end
  343. test "doesn't see notifications after muting user with notifications" do
  344. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  345. user2 = insert(:user)
  346. {:ok, _, _, _} = CommonAPI.follow(user, user2)
  347. {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"})
  348. ret_conn = get(conn, "/api/v1/notifications")
  349. assert length(json_response_and_validate_schema(ret_conn, 200)) == 1
  350. {:ok, _user_relationships} = User.mute(user, user2)
  351. conn = get(conn, "/api/v1/notifications")
  352. assert json_response_and_validate_schema(conn, 200) == []
  353. end
  354. test "see notifications after muting user without notifications" do
  355. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  356. user2 = insert(:user)
  357. {:ok, _, _, _} = CommonAPI.follow(user, user2)
  358. {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"})
  359. ret_conn = get(conn, "/api/v1/notifications")
  360. assert length(json_response_and_validate_schema(ret_conn, 200)) == 1
  361. {:ok, _user_relationships} = User.mute(user, user2, false)
  362. conn = get(conn, "/api/v1/notifications")
  363. assert length(json_response_and_validate_schema(conn, 200)) == 1
  364. end
  365. test "see notifications after muting user with notifications and with_muted parameter" do
  366. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  367. user2 = insert(:user)
  368. {:ok, _, _, _} = CommonAPI.follow(user, user2)
  369. {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"})
  370. ret_conn = get(conn, "/api/v1/notifications")
  371. assert length(json_response_and_validate_schema(ret_conn, 200)) == 1
  372. {:ok, _user_relationships} = User.mute(user, user2)
  373. conn = get(conn, "/api/v1/notifications?with_muted=true")
  374. assert length(json_response_and_validate_schema(conn, 200)) == 1
  375. end
  376. @tag capture_log: true
  377. test "see move notifications" do
  378. old_user = insert(:user)
  379. new_user = insert(:user, also_known_as: [old_user.ap_id])
  380. %{user: follower, conn: conn} = oauth_access(["read:notifications"])
  381. old_user_url = old_user.ap_id
  382. body =
  383. File.read!("test/fixtures/users_mock/localhost.json")
  384. |> String.replace("{{nickname}}", old_user.nickname)
  385. |> Jason.encode!()
  386. Tesla.Mock.mock(fn
  387. %{method: :get, url: ^old_user_url} ->
  388. %Tesla.Env{status: 200, body: body}
  389. end)
  390. User.follow(follower, old_user)
  391. Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
  392. Pleroma.Tests.ObanHelpers.perform_all()
  393. conn = get(conn, "/api/v1/notifications")
  394. assert length(json_response_and_validate_schema(conn, 200)) == 1
  395. end
  396. describe "link headers" do
  397. test "preserves parameters in link headers" do
  398. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  399. other_user = insert(:user)
  400. {:ok, activity1} =
  401. CommonAPI.post(other_user, %{
  402. status: "hi @#{user.nickname}",
  403. visibility: "public"
  404. })
  405. {:ok, activity2} =
  406. CommonAPI.post(other_user, %{
  407. status: "hi @#{user.nickname}",
  408. visibility: "public"
  409. })
  410. notification1 = Repo.get_by(Notification, activity_id: activity1.id)
  411. notification2 = Repo.get_by(Notification, activity_id: activity2.id)
  412. conn =
  413. conn
  414. |> assign(:user, user)
  415. |> get("/api/v1/notifications?limit=5")
  416. assert [link_header] = get_resp_header(conn, "link")
  417. assert link_header =~ ~r/limit=5/
  418. assert link_header =~ ~r/min_id=#{notification2.id}/
  419. assert link_header =~ ~r/max_id=#{notification1.id}/
  420. end
  421. end
  422. describe "from specified user" do
  423. test "account_id" do
  424. %{user: user, conn: conn} = oauth_access(["read:notifications"])
  425. %{id: account_id} = other_user1 = insert(:user)
  426. other_user2 = insert(:user)
  427. {:ok, _activity} = CommonAPI.post(other_user1, %{status: "hi @#{user.nickname}"})
  428. {:ok, _activity} = CommonAPI.post(other_user2, %{status: "bye @#{user.nickname}"})
  429. assert [%{"account" => %{"id" => ^account_id}}] =
  430. conn
  431. |> assign(:user, user)
  432. |> get("/api/v1/notifications?account_id=#{account_id}")
  433. |> json_response_and_validate_schema(200)
  434. assert %{"error" => "Account is not found"} =
  435. conn
  436. |> assign(:user, user)
  437. |> get("/api/v1/notifications?account_id=cofe")
  438. |> json_response_and_validate_schema(404)
  439. end
  440. end
  441. defp get_notification_id_by_activity(%{id: id}) do
  442. Notification
  443. |> Repo.get_by(activity_id: id)
  444. |> Map.get(:id)
  445. |> to_string()
  446. end
  447. defp params_to_query(%{} = params) do
  448. Enum.map_join(params, "&", fn
  449. {k, v} when is_list(v) -> Enum.map_join(v, "&", &"#{k}[]=#{&1}")
  450. {k, v} -> k <> "=" <> v
  451. end)
  452. end
  453. end