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
15 alias Pleroma.Web.OAuth.App
16 alias Pleroma.Web.Push
18 import Pleroma.Factory
19 import Swoosh.TestAssertions
23 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
27 clear_config([:instance, :public])
28 clear_config([:rich_media, :enabled])
30 test "apps/verify_credentials", %{conn: conn} do
31 token = insert(:oauth_token)
35 |> assign(:user, token.user)
36 |> assign(:token, token)
37 |> get("/api/v1/apps/verify_credentials")
39 app = Repo.preload(token, :app).app
42 "name" => app.client_name,
43 "website" => app.website,
44 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
47 assert expected == json_response(conn, 200)
50 test "creates an oauth app", %{conn: conn} do
52 app_attrs = build(:oauth_app)
56 |> assign(:user, user)
57 |> post("/api/v1/apps", %{
58 client_name: app_attrs.client_name,
59 redirect_uris: app_attrs.redirect_uris
65 "name" => app.client_name,
66 "website" => app.website,
67 "client_id" => app.client_id,
68 "client_secret" => app.client_secret,
69 "id" => app.id |> to_string(),
70 "redirect_uri" => app.redirect_uris,
71 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
74 assert expected == json_response(conn, 200)
77 test "getting a list of mutes", %{conn: conn} do
79 other_user = insert(:user)
81 {:ok, user} = User.mute(user, other_user)
85 |> assign(:user, user)
86 |> get("/api/v1/mutes")
88 other_user_id = to_string(other_user.id)
89 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
92 test "getting a list of blocks", %{conn: conn} do
94 other_user = insert(:user)
96 {:ok, user} = User.block(user, other_user)
100 |> assign(:user, user)
101 |> get("/api/v1/blocks")
103 other_user_id = to_string(other_user.id)
104 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
107 test "unimplemented follow_requests, blocks, domain blocks" do
110 ["blocks", "domain_blocks", "follow_requests"]
111 |> Enum.each(fn endpoint ->
114 |> assign(:user, user)
115 |> get("/api/v1/#{endpoint}")
117 assert [] = json_response(conn, 200)
121 test "returns the favorites of a user", %{conn: conn} do
123 other_user = insert(:user)
125 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
126 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
128 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
132 |> assign(:user, user)
133 |> get("/api/v1/favourites")
135 assert [status] = json_response(first_conn, 200)
136 assert status["id"] == to_string(activity.id)
138 assert [{"link", _link_header}] =
139 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
141 # Honours query params
142 {:ok, second_activity} =
143 CommonAPI.post(other_user, %{
145 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
148 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
150 last_like = status["id"]
154 |> assign(:user, user)
155 |> get("/api/v1/favourites?since_id=#{last_like}")
157 assert [second_status] = json_response(second_conn, 200)
158 assert second_status["id"] == to_string(second_activity.id)
162 |> assign(:user, user)
163 |> get("/api/v1/favourites?limit=0")
165 assert [] = json_response(third_conn, 200)
168 test "get instance information", %{conn: conn} do
169 conn = get(conn, "/api/v1/instance")
170 assert result = json_response(conn, 200)
172 email = Config.get([:instance, :email])
173 # Note: not checking for "max_toot_chars" since it's optional
179 "email" => from_config_email,
186 "registrations" => _,
190 assert email == from_config_email
193 test "get instance stats", %{conn: conn} do
194 user = insert(:user, %{local: true})
196 user2 = insert(:user, %{local: true})
197 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
199 insert(:user, %{local: false, nickname: "u@peer1.com"})
200 insert(:user, %{local: false, nickname: "u@peer2.com"})
202 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
204 # Stats should count users with missing or nil `info.deactivated` value
208 |> User.get_cached_by_id()
209 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
211 Pleroma.Stats.force_update()
213 conn = get(conn, "/api/v1/instance")
215 assert result = json_response(conn, 200)
217 stats = result["stats"]
220 assert stats["user_count"] == 1
221 assert stats["status_count"] == 1
222 assert stats["domain_count"] == 2
225 test "get peers", %{conn: conn} do
226 insert(:user, %{local: false, nickname: "u@peer1.com"})
227 insert(:user, %{local: false, nickname: "u@peer2.com"})
229 Pleroma.Stats.force_update()
231 conn = get(conn, "/api/v1/instance/peers")
233 assert result = json_response(conn, 200)
235 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
238 test "put settings", %{conn: conn} do
243 |> assign(:user, user)
244 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
246 assert _result = json_response(conn, 200)
248 user = User.get_cached_by_ap_id(user.ap_id)
249 assert user.info.settings == %{"programming" => "socks"}
252 describe "link headers" do
253 test "preserves parameters in link headers", %{conn: conn} do
255 other_user = insert(:user)
258 CommonAPI.post(other_user, %{
259 "status" => "hi @#{user.nickname}",
260 "visibility" => "public"
264 CommonAPI.post(other_user, %{
265 "status" => "hi @#{user.nickname}",
266 "visibility" => "public"
269 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
270 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
274 |> assign(:user, user)
275 |> get("/api/v1/notifications", %{media_only: true})
277 assert [link_header] = get_resp_header(conn, "link")
278 assert link_header =~ ~r/media_only=true/
279 assert link_header =~ ~r/min_id=#{notification2.id}/
280 assert link_header =~ ~r/max_id=#{notification1.id}/
284 describe "custom emoji" do
285 test "with tags", %{conn: conn} do
288 |> get("/api/v1/custom_emojis")
289 |> json_response(200)
291 assert Map.has_key?(emoji, "shortcode")
292 assert Map.has_key?(emoji, "static_url")
293 assert Map.has_key?(emoji, "tags")
294 assert is_list(emoji["tags"])
295 assert Map.has_key?(emoji, "category")
296 assert Map.has_key?(emoji, "url")
297 assert Map.has_key?(emoji, "visible_in_picker")
301 describe "index/2 redirections" do
302 setup %{conn: conn} do
306 signing_salt: "cooldude"
311 |> Plug.Session.call(Plug.Session.init(session_opts))
314 test_path = "/web/statuses/test"
315 %{conn: conn, path: test_path}
318 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
319 conn = get(conn, path)
321 assert conn.status == 302
322 assert redirected_to(conn) == "/web/login"
325 test "redirects not logged-in users to the login page on private instances", %{
329 Config.put([:instance, :public], false)
331 conn = get(conn, path)
333 assert conn.status == 302
334 assert redirected_to(conn) == "/web/login"
337 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
338 token = insert(:oauth_token)
342 |> assign(:user, token.user)
343 |> put_session(:oauth_token, token.token)
346 assert conn.status == 200
349 test "saves referer path to session", %{conn: conn, path: path} do
350 conn = get(conn, path)
351 return_to = Plug.Conn.get_session(conn, :return_to)
353 assert return_to == path
356 test "redirects to the saved path after log in", %{conn: conn, path: path} do
357 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
358 auth = insert(:oauth_authorization, app: app)
362 |> put_session(:return_to, path)
363 |> get("/web/login", %{code: auth.token})
365 assert conn.status == 302
366 assert redirected_to(conn) == path
369 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
370 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
371 auth = insert(:oauth_authorization, app: app)
373 conn = get(conn, "/web/login", %{code: auth.token})
375 assert conn.status == 302
376 assert redirected_to(conn) == "/web/getting-started"
380 describe "POST /auth/password, with valid parameters" do
381 setup %{conn: conn} do
383 conn = post(conn, "/auth/password?email=#{user.email}")
384 %{conn: conn, user: user}
387 test "it returns 204", %{conn: conn} do
388 assert json_response(conn, :no_content)
391 test "it creates a PasswordResetToken record for user", %{user: user} do
392 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
396 test "it sends an email to user", %{user: user} do
397 ObanHelpers.perform_all()
398 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
400 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
401 notify_email = Config.get([:instance, :notify_email])
402 instance_name = Config.get([:instance, :name])
405 from: {instance_name, notify_email},
406 to: {user.name, user.email},
407 html_body: email.html_body
412 describe "POST /auth/password, with invalid parameters" do
418 test "it returns 404 when user is not found", %{conn: conn, user: user} do
419 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
420 assert conn.status == 404
421 assert conn.resp_body == ""
424 test "it returns 400 when user is not local", %{conn: conn, user: user} do
425 {:ok, user} = Repo.update(Changeset.change(user, local: false))
426 conn = post(conn, "/auth/password?email=#{user.email}")
427 assert conn.status == 400
428 assert conn.resp_body == ""
432 describe "DELETE /auth/sign_out" do
433 test "redirect to root page", %{conn: conn} do
438 |> assign(:user, user)
439 |> delete("/auth/sign_out")
441 assert conn.status == 302
442 assert redirected_to(conn) == "/"
446 describe "empty_array, stubs for mastodon api" do
447 test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
452 |> assign(:user, user)
453 |> get("/api/v1/accounts/#{user.id}/identity_proofs")
454 |> json_response(200)
459 test "GET /api/v1/endorsements", %{conn: conn} do
464 |> assign(:user, user)
465 |> get("/api/v1/endorsements")
466 |> json_response(200)
471 test "GET /api/v1/trends", %{conn: conn} do
476 |> assign(:user, user)
477 |> get("/api/v1/trends")
478 |> json_response(200)