1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
10 alias Pleroma.Notification
12 alias Pleroma.Tests.ObanHelpers
14 alias Pleroma.Web.CommonAPI
16 import Pleroma.Factory
17 import Swoosh.TestAssertions
21 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
25 clear_config([:instance, :public])
26 clear_config([:rich_media, :enabled])
28 test "getting a list of mutes", %{conn: conn} do
30 other_user = insert(:user)
32 {:ok, user} = User.mute(user, other_user)
36 |> assign(:user, user)
37 |> get("/api/v1/mutes")
39 other_user_id = to_string(other_user.id)
40 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
43 test "getting a list of blocks", %{conn: conn} do
45 other_user = insert(:user)
47 {:ok, user} = User.block(user, other_user)
51 |> assign(:user, user)
52 |> get("/api/v1/blocks")
54 other_user_id = to_string(other_user.id)
55 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
58 test "unimplemented follow_requests, blocks, domain blocks" do
61 ["blocks", "domain_blocks", "follow_requests"]
62 |> Enum.each(fn endpoint ->
65 |> assign(:user, user)
66 |> get("/api/v1/#{endpoint}")
68 assert [] = json_response(conn, 200)
72 test "returns the favorites of a user", %{conn: conn} do
74 other_user = insert(:user)
76 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
77 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
79 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
83 |> assign(:user, user)
84 |> get("/api/v1/favourites")
86 assert [status] = json_response(first_conn, 200)
87 assert status["id"] == to_string(activity.id)
89 assert [{"link", _link_header}] =
90 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
92 # Honours query params
93 {:ok, second_activity} =
94 CommonAPI.post(other_user, %{
96 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
99 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
101 last_like = status["id"]
105 |> assign(:user, user)
106 |> get("/api/v1/favourites?since_id=#{last_like}")
108 assert [second_status] = json_response(second_conn, 200)
109 assert second_status["id"] == to_string(second_activity.id)
113 |> assign(:user, user)
114 |> get("/api/v1/favourites?limit=0")
116 assert [] = json_response(third_conn, 200)
119 test "get instance information", %{conn: conn} do
120 conn = get(conn, "/api/v1/instance")
121 assert result = json_response(conn, 200)
123 email = Config.get([:instance, :email])
124 # Note: not checking for "max_toot_chars" since it's optional
130 "email" => from_config_email,
137 "registrations" => _,
140 "avatar_upload_limit" => _,
141 "background_upload_limit" => _,
142 "banner_upload_limit" => _
145 assert email == from_config_email
148 test "get instance stats", %{conn: conn} do
149 user = insert(:user, %{local: true})
151 user2 = insert(:user, %{local: true})
152 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
154 insert(:user, %{local: false, nickname: "u@peer1.com"})
155 insert(:user, %{local: false, nickname: "u@peer2.com"})
157 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
159 # Stats should count users with missing or nil `info.deactivated` value
163 |> User.get_cached_by_id()
164 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
166 Pleroma.Stats.force_update()
168 conn = get(conn, "/api/v1/instance")
170 assert result = json_response(conn, 200)
172 stats = result["stats"]
175 assert stats["user_count"] == 1
176 assert stats["status_count"] == 1
177 assert stats["domain_count"] == 2
180 test "get peers", %{conn: conn} do
181 insert(:user, %{local: false, nickname: "u@peer1.com"})
182 insert(:user, %{local: false, nickname: "u@peer2.com"})
184 Pleroma.Stats.force_update()
186 conn = get(conn, "/api/v1/instance/peers")
188 assert result = json_response(conn, 200)
190 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
193 test "put settings", %{conn: conn} do
198 |> assign(:user, user)
199 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
201 assert _result = json_response(conn, 200)
203 user = User.get_cached_by_ap_id(user.ap_id)
204 assert user.info.settings == %{"programming" => "socks"}
207 describe "link headers" do
208 test "preserves parameters in link headers", %{conn: conn} do
210 other_user = insert(:user)
213 CommonAPI.post(other_user, %{
214 "status" => "hi @#{user.nickname}",
215 "visibility" => "public"
219 CommonAPI.post(other_user, %{
220 "status" => "hi @#{user.nickname}",
221 "visibility" => "public"
224 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
225 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
229 |> assign(:user, user)
230 |> get("/api/v1/notifications", %{media_only: true})
232 assert [link_header] = get_resp_header(conn, "link")
233 assert link_header =~ ~r/media_only=true/
234 assert link_header =~ ~r/min_id=#{notification2.id}/
235 assert link_header =~ ~r/max_id=#{notification1.id}/
239 describe "custom emoji" do
240 test "with tags", %{conn: conn} do
243 |> get("/api/v1/custom_emojis")
244 |> json_response(200)
246 assert Map.has_key?(emoji, "shortcode")
247 assert Map.has_key?(emoji, "static_url")
248 assert Map.has_key?(emoji, "tags")
249 assert is_list(emoji["tags"])
250 assert Map.has_key?(emoji, "category")
251 assert Map.has_key?(emoji, "url")
252 assert Map.has_key?(emoji, "visible_in_picker")
256 describe "index/2 redirections" do
257 setup %{conn: conn} do
261 signing_salt: "cooldude"
266 |> Plug.Session.call(Plug.Session.init(session_opts))
269 test_path = "/web/statuses/test"
270 %{conn: conn, path: test_path}
273 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
274 conn = get(conn, path)
276 assert conn.status == 302
277 assert redirected_to(conn) == "/web/login"
280 test "redirects not logged-in users to the login page on private instances", %{
284 Config.put([:instance, :public], false)
286 conn = get(conn, path)
288 assert conn.status == 302
289 assert redirected_to(conn) == "/web/login"
292 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
293 token = insert(:oauth_token)
297 |> assign(:user, token.user)
298 |> put_session(:oauth_token, token.token)
301 assert conn.status == 200
304 test "saves referer path to session", %{conn: conn, path: path} do
305 conn = get(conn, path)
306 return_to = Plug.Conn.get_session(conn, :return_to)
308 assert return_to == path
311 test "redirects to the saved path after log in", %{conn: conn, path: path} do
312 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
313 auth = insert(:oauth_authorization, app: app)
317 |> put_session(:return_to, path)
318 |> get("/web/login", %{code: auth.token})
320 assert conn.status == 302
321 assert redirected_to(conn) == path
324 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
325 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
326 auth = insert(:oauth_authorization, app: app)
328 conn = get(conn, "/web/login", %{code: auth.token})
330 assert conn.status == 302
331 assert redirected_to(conn) == "/web/getting-started"
335 describe "POST /auth/password, with valid parameters" do
336 setup %{conn: conn} do
338 conn = post(conn, "/auth/password?email=#{user.email}")
339 %{conn: conn, user: user}
342 test "it returns 204", %{conn: conn} do
343 assert json_response(conn, :no_content)
346 test "it creates a PasswordResetToken record for user", %{user: user} do
347 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
351 test "it sends an email to user", %{user: user} do
352 ObanHelpers.perform_all()
353 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
355 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
356 notify_email = Config.get([:instance, :notify_email])
357 instance_name = Config.get([:instance, :name])
360 from: {instance_name, notify_email},
361 to: {user.name, user.email},
362 html_body: email.html_body
367 describe "POST /auth/password, with invalid parameters" do
373 test "it returns 404 when user is not found", %{conn: conn, user: user} do
374 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
375 assert conn.status == 404
376 assert conn.resp_body == ""
379 test "it returns 400 when user is not local", %{conn: conn, user: user} do
380 {:ok, user} = Repo.update(Changeset.change(user, local: false))
381 conn = post(conn, "/auth/password?email=#{user.email}")
382 assert conn.status == 400
383 assert conn.resp_body == ""
387 describe "DELETE /auth/sign_out" do
388 test "redirect to root page", %{conn: conn} do
393 |> assign(:user, user)
394 |> delete("/auth/sign_out")
396 assert conn.status == 302
397 assert redirected_to(conn) == "/"
401 describe "empty_array, stubs for mastodon api" do
402 test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
407 |> assign(:user, user)
408 |> get("/api/v1/accounts/#{user.id}/identity_proofs")
409 |> json_response(200)
414 test "GET /api/v1/endorsements", %{conn: conn} do
419 |> assign(:user, user)
420 |> get("/api/v1/endorsements")
421 |> json_response(200)
426 test "GET /api/v1/trends", %{conn: conn} do
431 |> assign(:user, user)
432 |> get("/api/v1/trends")
433 |> json_response(200)