47357863c852ee012fae77462496db1bf223a7f4
[akkoma] / test / web / mastodon_api / mastodon_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
7
8 alias Ecto.Changeset
9 alias Pleroma.Config
10 alias Pleroma.Notification
11 alias Pleroma.Repo
12 alias Pleroma.Tests.ObanHelpers
13 alias Pleroma.User
14 alias Pleroma.Web.CommonAPI
15 alias Pleroma.Web.OAuth.App
16 alias Pleroma.Web.Push
17
18 import Pleroma.Factory
19 import Swoosh.TestAssertions
20 import Tesla.Mock
21
22 setup do
23 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
24 :ok
25 end
26
27 clear_config([:instance, :public])
28 clear_config([:rich_media, :enabled])
29
30 test "apps/verify_credentials", %{conn: conn} do
31 token = insert(:oauth_token)
32
33 conn =
34 conn
35 |> assign(:user, token.user)
36 |> assign(:token, token)
37 |> get("/api/v1/apps/verify_credentials")
38
39 app = Repo.preload(token, :app).app
40
41 expected = %{
42 "name" => app.client_name,
43 "website" => app.website,
44 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
45 }
46
47 assert expected == json_response(conn, 200)
48 end
49
50 test "creates an oauth app", %{conn: conn} do
51 user = insert(:user)
52 app_attrs = build(:oauth_app)
53
54 conn =
55 conn
56 |> assign(:user, user)
57 |> post("/api/v1/apps", %{
58 client_name: app_attrs.client_name,
59 redirect_uris: app_attrs.redirect_uris
60 })
61
62 [app] = Repo.all(App)
63
64 expected = %{
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)
72 }
73
74 assert expected == json_response(conn, 200)
75 end
76
77 test "getting a list of mutes", %{conn: conn} do
78 user = insert(:user)
79 other_user = insert(:user)
80
81 {:ok, user} = User.mute(user, other_user)
82
83 conn =
84 conn
85 |> assign(:user, user)
86 |> get("/api/v1/mutes")
87
88 other_user_id = to_string(other_user.id)
89 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
90 end
91
92 test "getting a list of blocks", %{conn: conn} do
93 user = insert(:user)
94 other_user = insert(:user)
95
96 {:ok, user} = User.block(user, other_user)
97
98 conn =
99 conn
100 |> assign(:user, user)
101 |> get("/api/v1/blocks")
102
103 other_user_id = to_string(other_user.id)
104 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
105 end
106
107 test "unimplemented follow_requests, blocks, domain blocks" do
108 user = insert(:user)
109
110 ["blocks", "domain_blocks", "follow_requests"]
111 |> Enum.each(fn endpoint ->
112 conn =
113 build_conn()
114 |> assign(:user, user)
115 |> get("/api/v1/#{endpoint}")
116
117 assert [] = json_response(conn, 200)
118 end)
119 end
120
121 test "returns the favorites of a user", %{conn: conn} do
122 user = insert(:user)
123 other_user = insert(:user)
124
125 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
126 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
127
128 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
129
130 first_conn =
131 conn
132 |> assign(:user, user)
133 |> get("/api/v1/favourites")
134
135 assert [status] = json_response(first_conn, 200)
136 assert status["id"] == to_string(activity.id)
137
138 assert [{"link", _link_header}] =
139 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
140
141 # Honours query params
142 {:ok, second_activity} =
143 CommonAPI.post(other_user, %{
144 "status" =>
145 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
146 })
147
148 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
149
150 last_like = status["id"]
151
152 second_conn =
153 conn
154 |> assign(:user, user)
155 |> get("/api/v1/favourites?since_id=#{last_like}")
156
157 assert [second_status] = json_response(second_conn, 200)
158 assert second_status["id"] == to_string(second_activity.id)
159
160 third_conn =
161 conn
162 |> assign(:user, user)
163 |> get("/api/v1/favourites?limit=0")
164
165 assert [] = json_response(third_conn, 200)
166 end
167
168 test "get instance information", %{conn: conn} do
169 conn = get(conn, "/api/v1/instance")
170 assert result = json_response(conn, 200)
171
172 email = Config.get([:instance, :email])
173 # Note: not checking for "max_toot_chars" since it's optional
174 assert %{
175 "uri" => _,
176 "title" => _,
177 "description" => _,
178 "version" => _,
179 "email" => from_config_email,
180 "urls" => %{
181 "streaming_api" => _
182 },
183 "stats" => _,
184 "thumbnail" => _,
185 "languages" => _,
186 "registrations" => _,
187 "poll_limits" => _
188 } = result
189
190 assert email == from_config_email
191 end
192
193 test "get instance stats", %{conn: conn} do
194 user = insert(:user, %{local: true})
195
196 user2 = insert(:user, %{local: true})
197 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
198
199 insert(:user, %{local: false, nickname: "u@peer1.com"})
200 insert(:user, %{local: false, nickname: "u@peer2.com"})
201
202 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
203
204 # Stats should count users with missing or nil `info.deactivated` value
205
206 {:ok, _user} =
207 user.id
208 |> User.get_cached_by_id()
209 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
210
211 Pleroma.Stats.force_update()
212
213 conn = get(conn, "/api/v1/instance")
214
215 assert result = json_response(conn, 200)
216
217 stats = result["stats"]
218
219 assert stats
220 assert stats["user_count"] == 1
221 assert stats["status_count"] == 1
222 assert stats["domain_count"] == 2
223 end
224
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"})
228
229 Pleroma.Stats.force_update()
230
231 conn = get(conn, "/api/v1/instance/peers")
232
233 assert result = json_response(conn, 200)
234
235 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
236 end
237
238 test "put settings", %{conn: conn} do
239 user = insert(:user)
240
241 conn =
242 conn
243 |> assign(:user, user)
244 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
245
246 assert _result = json_response(conn, 200)
247
248 user = User.get_cached_by_ap_id(user.ap_id)
249 assert user.info.settings == %{"programming" => "socks"}
250 end
251
252 describe "link headers" do
253 test "preserves parameters in link headers", %{conn: conn} do
254 user = insert(:user)
255 other_user = insert(:user)
256
257 {:ok, activity1} =
258 CommonAPI.post(other_user, %{
259 "status" => "hi @#{user.nickname}",
260 "visibility" => "public"
261 })
262
263 {:ok, activity2} =
264 CommonAPI.post(other_user, %{
265 "status" => "hi @#{user.nickname}",
266 "visibility" => "public"
267 })
268
269 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
270 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
271
272 conn =
273 conn
274 |> assign(:user, user)
275 |> get("/api/v1/notifications", %{media_only: true})
276
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}/
281 end
282 end
283
284 describe "custom emoji" do
285 test "with tags", %{conn: conn} do
286 [emoji | _body] =
287 conn
288 |> get("/api/v1/custom_emojis")
289 |> json_response(200)
290
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")
298 end
299 end
300
301 describe "index/2 redirections" do
302 setup %{conn: conn} do
303 session_opts = [
304 store: :cookie,
305 key: "_test",
306 signing_salt: "cooldude"
307 ]
308
309 conn =
310 conn
311 |> Plug.Session.call(Plug.Session.init(session_opts))
312 |> fetch_session()
313
314 test_path = "/web/statuses/test"
315 %{conn: conn, path: test_path}
316 end
317
318 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
319 conn = get(conn, path)
320
321 assert conn.status == 302
322 assert redirected_to(conn) == "/web/login"
323 end
324
325 test "redirects not logged-in users to the login page on private instances", %{
326 conn: conn,
327 path: path
328 } do
329 Config.put([:instance, :public], false)
330
331 conn = get(conn, path)
332
333 assert conn.status == 302
334 assert redirected_to(conn) == "/web/login"
335 end
336
337 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
338 token = insert(:oauth_token)
339
340 conn =
341 conn
342 |> assign(:user, token.user)
343 |> put_session(:oauth_token, token.token)
344 |> get(path)
345
346 assert conn.status == 200
347 end
348
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)
352
353 assert return_to == path
354 end
355
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)
359
360 conn =
361 conn
362 |> put_session(:return_to, path)
363 |> get("/web/login", %{code: auth.token})
364
365 assert conn.status == 302
366 assert redirected_to(conn) == path
367 end
368
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)
372
373 conn = get(conn, "/web/login", %{code: auth.token})
374
375 assert conn.status == 302
376 assert redirected_to(conn) == "/web/getting-started"
377 end
378 end
379
380 describe "POST /auth/password, with valid parameters" do
381 setup %{conn: conn} do
382 user = insert(:user)
383 conn = post(conn, "/auth/password?email=#{user.email}")
384 %{conn: conn, user: user}
385 end
386
387 test "it returns 204", %{conn: conn} do
388 assert json_response(conn, :no_content)
389 end
390
391 test "it creates a PasswordResetToken record for user", %{user: user} do
392 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
393 assert token_record
394 end
395
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)
399
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])
403
404 assert_email_sent(
405 from: {instance_name, notify_email},
406 to: {user.name, user.email},
407 html_body: email.html_body
408 )
409 end
410 end
411
412 describe "POST /auth/password, with invalid parameters" do
413 setup do
414 user = insert(:user)
415 {:ok, user: user}
416 end
417
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 == ""
422 end
423
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 == ""
429 end
430 end
431
432 describe "DELETE /auth/sign_out" do
433 test "redirect to root page", %{conn: conn} do
434 user = insert(:user)
435
436 conn =
437 conn
438 |> assign(:user, user)
439 |> delete("/auth/sign_out")
440
441 assert conn.status == 302
442 assert redirected_to(conn) == "/"
443 end
444 end
445
446 describe "empty_array, stubs for mastodon api" do
447 test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
448 user = insert(:user)
449
450 res =
451 conn
452 |> assign(:user, user)
453 |> get("/api/v1/accounts/#{user.id}/identity_proofs")
454 |> json_response(200)
455
456 assert res == []
457 end
458
459 test "GET /api/v1/endorsements", %{conn: conn} do
460 user = insert(:user)
461
462 res =
463 conn
464 |> assign(:user, user)
465 |> get("/api/v1/endorsements")
466 |> json_response(200)
467
468 assert res == []
469 end
470
471 test "GET /api/v1/trends", %{conn: conn} do
472 user = insert(:user)
473
474 res =
475 conn
476 |> assign(:user, user)
477 |> get("/api/v1/trends")
478 |> json_response(200)
479
480 assert res == []
481 end
482 end
483 end