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" => _,
141 assert email == from_config_email
144 test "get instance stats", %{conn: conn} do
145 user = insert(:user, %{local: true})
147 user2 = insert(:user, %{local: true})
148 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
150 insert(:user, %{local: false, nickname: "u@peer1.com"})
151 insert(:user, %{local: false, nickname: "u@peer2.com"})
153 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
155 # Stats should count users with missing or nil `info.deactivated` value
159 |> User.get_cached_by_id()
160 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
162 Pleroma.Stats.force_update()
164 conn = get(conn, "/api/v1/instance")
166 assert result = json_response(conn, 200)
168 stats = result["stats"]
171 assert stats["user_count"] == 1
172 assert stats["status_count"] == 1
173 assert stats["domain_count"] == 2
176 test "get peers", %{conn: conn} do
177 insert(:user, %{local: false, nickname: "u@peer1.com"})
178 insert(:user, %{local: false, nickname: "u@peer2.com"})
180 Pleroma.Stats.force_update()
182 conn = get(conn, "/api/v1/instance/peers")
184 assert result = json_response(conn, 200)
186 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
189 test "put settings", %{conn: conn} do
194 |> assign(:user, user)
195 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
197 assert _result = json_response(conn, 200)
199 user = User.get_cached_by_ap_id(user.ap_id)
200 assert user.info.settings == %{"programming" => "socks"}
203 describe "link headers" do
204 test "preserves parameters in link headers", %{conn: conn} do
206 other_user = insert(:user)
209 CommonAPI.post(other_user, %{
210 "status" => "hi @#{user.nickname}",
211 "visibility" => "public"
215 CommonAPI.post(other_user, %{
216 "status" => "hi @#{user.nickname}",
217 "visibility" => "public"
220 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
221 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
225 |> assign(:user, user)
226 |> get("/api/v1/notifications", %{media_only: true})
228 assert [link_header] = get_resp_header(conn, "link")
229 assert link_header =~ ~r/media_only=true/
230 assert link_header =~ ~r/min_id=#{notification2.id}/
231 assert link_header =~ ~r/max_id=#{notification1.id}/
235 describe "custom emoji" do
236 test "with tags", %{conn: conn} do
239 |> get("/api/v1/custom_emojis")
240 |> json_response(200)
242 assert Map.has_key?(emoji, "shortcode")
243 assert Map.has_key?(emoji, "static_url")
244 assert Map.has_key?(emoji, "tags")
245 assert is_list(emoji["tags"])
246 assert Map.has_key?(emoji, "category")
247 assert Map.has_key?(emoji, "url")
248 assert Map.has_key?(emoji, "visible_in_picker")
252 describe "index/2 redirections" do
253 setup %{conn: conn} do
257 signing_salt: "cooldude"
262 |> Plug.Session.call(Plug.Session.init(session_opts))
265 test_path = "/web/statuses/test"
266 %{conn: conn, path: test_path}
269 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
270 conn = get(conn, path)
272 assert conn.status == 302
273 assert redirected_to(conn) == "/web/login"
276 test "redirects not logged-in users to the login page on private instances", %{
280 Config.put([:instance, :public], false)
282 conn = get(conn, path)
284 assert conn.status == 302
285 assert redirected_to(conn) == "/web/login"
288 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
289 token = insert(:oauth_token)
293 |> assign(:user, token.user)
294 |> put_session(:oauth_token, token.token)
297 assert conn.status == 200
300 test "saves referer path to session", %{conn: conn, path: path} do
301 conn = get(conn, path)
302 return_to = Plug.Conn.get_session(conn, :return_to)
304 assert return_to == path
307 test "redirects to the saved path after log in", %{conn: conn, path: path} do
308 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
309 auth = insert(:oauth_authorization, app: app)
313 |> put_session(:return_to, path)
314 |> get("/web/login", %{code: auth.token})
316 assert conn.status == 302
317 assert redirected_to(conn) == path
320 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
321 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
322 auth = insert(:oauth_authorization, app: app)
324 conn = get(conn, "/web/login", %{code: auth.token})
326 assert conn.status == 302
327 assert redirected_to(conn) == "/web/getting-started"
331 describe "POST /auth/password, with valid parameters" do
332 setup %{conn: conn} do
334 conn = post(conn, "/auth/password?email=#{user.email}")
335 %{conn: conn, user: user}
338 test "it returns 204", %{conn: conn} do
339 assert json_response(conn, :no_content)
342 test "it creates a PasswordResetToken record for user", %{user: user} do
343 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
347 test "it sends an email to user", %{user: user} do
348 ObanHelpers.perform_all()
349 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
351 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
352 notify_email = Config.get([:instance, :notify_email])
353 instance_name = Config.get([:instance, :name])
356 from: {instance_name, notify_email},
357 to: {user.name, user.email},
358 html_body: email.html_body
363 describe "POST /auth/password, with invalid parameters" do
369 test "it returns 404 when user is not found", %{conn: conn, user: user} do
370 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
371 assert conn.status == 404
372 assert conn.resp_body == ""
375 test "it returns 400 when user is not local", %{conn: conn, user: user} do
376 {:ok, user} = Repo.update(Changeset.change(user, local: false))
377 conn = post(conn, "/auth/password?email=#{user.email}")
378 assert conn.status == 400
379 assert conn.resp_body == ""
383 describe "DELETE /auth/sign_out" do
384 test "redirect to root page", %{conn: conn} do
389 |> assign(:user, user)
390 |> delete("/auth/sign_out")
392 assert conn.status == 302
393 assert redirected_to(conn) == "/"
397 describe "empty_array, stubs for mastodon api" do
398 test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
403 |> assign(:user, user)
404 |> get("/api/v1/accounts/#{user.id}/identity_proofs")
405 |> json_response(200)
410 test "GET /api/v1/endorsements", %{conn: conn} do
415 |> assign(:user, user)
416 |> get("/api/v1/endorsements")
417 |> json_response(200)
422 test "GET /api/v1/trends", %{conn: conn} do
427 |> assign(:user, user)
428 |> get("/api/v1/trends")
429 |> json_response(200)