Merge branch 'plug-if-unless-func-options-refactoring' into 'develop'
[akkoma] / test / web / mastodon_api / controllers / account_controller_test.exs
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
5 defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
6 use Pleroma.Web.ConnCase
7
8 alias Pleroma.Config
9 alias Pleroma.Repo
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.ActivityPub.InternalFetchActor
13 alias Pleroma.Web.CommonAPI
14 alias Pleroma.Web.OAuth.Token
15
16 import Pleroma.Factory
17
18 describe "account fetching" do
19 setup do: clear_config([:instance, :limit_to_local_content])
20
21 test "works by id" do
22 %User{id: user_id} = insert(:user)
23
24 assert %{"id" => ^user_id} =
25 build_conn()
26 |> get("/api/v1/accounts/#{user_id}")
27 |> json_response_and_validate_schema(200)
28
29 assert %{"error" => "Can't find user"} =
30 build_conn()
31 |> get("/api/v1/accounts/-1")
32 |> json_response_and_validate_schema(404)
33 end
34
35 test "works by nickname" do
36 user = insert(:user)
37
38 assert %{"id" => user_id} =
39 build_conn()
40 |> get("/api/v1/accounts/#{user.nickname}")
41 |> json_response_and_validate_schema(200)
42 end
43
44 test "works by nickname for remote users" do
45 Config.put([:instance, :limit_to_local_content], false)
46
47 user = insert(:user, nickname: "user@example.com", local: false)
48
49 assert %{"id" => user_id} =
50 build_conn()
51 |> get("/api/v1/accounts/#{user.nickname}")
52 |> json_response_and_validate_schema(200)
53 end
54
55 test "respects limit_to_local_content == :all for remote user nicknames" do
56 Config.put([:instance, :limit_to_local_content], :all)
57
58 user = insert(:user, nickname: "user@example.com", local: false)
59
60 assert build_conn()
61 |> get("/api/v1/accounts/#{user.nickname}")
62 |> json_response_and_validate_schema(404)
63 end
64
65 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
66 Config.put([:instance, :limit_to_local_content], :unauthenticated)
67
68 user = insert(:user, nickname: "user@example.com", local: false)
69 reading_user = insert(:user)
70
71 conn =
72 build_conn()
73 |> get("/api/v1/accounts/#{user.nickname}")
74
75 assert json_response_and_validate_schema(conn, 404)
76
77 conn =
78 build_conn()
79 |> assign(:user, reading_user)
80 |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
81 |> get("/api/v1/accounts/#{user.nickname}")
82
83 assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
84 assert id == user.id
85 end
86
87 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
88 # Need to set an old-style integer ID to reproduce the problem
89 # (these are no longer assigned to new accounts but were preserved
90 # for existing accounts during the migration to flakeIDs)
91 user_one = insert(:user, %{id: 1212})
92 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
93
94 acc_one =
95 conn
96 |> get("/api/v1/accounts/#{user_one.id}")
97 |> json_response_and_validate_schema(:ok)
98
99 acc_two =
100 conn
101 |> get("/api/v1/accounts/#{user_two.nickname}")
102 |> json_response_and_validate_schema(:ok)
103
104 acc_three =
105 conn
106 |> get("/api/v1/accounts/#{user_two.id}")
107 |> json_response_and_validate_schema(:ok)
108
109 refute acc_one == acc_two
110 assert acc_two == acc_three
111 end
112
113 test "returns 404 when user is invisible", %{conn: conn} do
114 user = insert(:user, %{invisible: true})
115
116 assert %{"error" => "Can't find user"} =
117 conn
118 |> get("/api/v1/accounts/#{user.nickname}")
119 |> json_response_and_validate_schema(404)
120 end
121
122 test "returns 404 for internal.fetch actor", %{conn: conn} do
123 %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
124
125 assert %{"error" => "Can't find user"} =
126 conn
127 |> get("/api/v1/accounts/internal.fetch")
128 |> json_response_and_validate_schema(404)
129 end
130 end
131
132 defp local_and_remote_users do
133 local = insert(:user)
134 remote = insert(:user, local: false)
135 {:ok, local: local, remote: remote}
136 end
137
138 describe "user fetching with restrict unauthenticated profiles for local and remote" do
139 setup do: local_and_remote_users()
140
141 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
142
143 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
144
145 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
146 assert %{"error" => "Can't find user"} ==
147 conn
148 |> get("/api/v1/accounts/#{local.id}")
149 |> json_response_and_validate_schema(:not_found)
150
151 assert %{"error" => "Can't find user"} ==
152 conn
153 |> get("/api/v1/accounts/#{remote.id}")
154 |> json_response_and_validate_schema(:not_found)
155 end
156
157 test "if user is authenticated", %{local: local, remote: remote} do
158 %{conn: conn} = oauth_access(["read"])
159
160 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
161 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
162
163 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
164 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
165 end
166 end
167
168 describe "user fetching with restrict unauthenticated profiles for local" do
169 setup do: local_and_remote_users()
170
171 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
172
173 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
174 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
175
176 assert json_response_and_validate_schema(res_conn, :not_found) == %{
177 "error" => "Can't find user"
178 }
179
180 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
181 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
182 end
183
184 test "if user is authenticated", %{local: local, remote: remote} do
185 %{conn: conn} = oauth_access(["read"])
186
187 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
188 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
189
190 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
191 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
192 end
193 end
194
195 describe "user fetching with restrict unauthenticated profiles for remote" do
196 setup do: local_and_remote_users()
197
198 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
199
200 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
201 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
202 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
203
204 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
205
206 assert json_response_and_validate_schema(res_conn, :not_found) == %{
207 "error" => "Can't find user"
208 }
209 end
210
211 test "if user is authenticated", %{local: local, remote: remote} do
212 %{conn: conn} = oauth_access(["read"])
213
214 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
215 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
216
217 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
218 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
219 end
220 end
221
222 describe "user timelines" do
223 setup do: oauth_access(["read:statuses"])
224
225 test "respects blocks", %{user: user_one, conn: conn} do
226 user_two = insert(:user)
227 user_three = insert(:user)
228
229 User.block(user_one, user_two)
230
231 {:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"})
232 {:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three)
233
234 assert resp =
235 conn
236 |> get("/api/v1/accounts/#{user_two.id}/statuses")
237 |> json_response_and_validate_schema(200)
238
239 assert [%{"id" => id}] = resp
240 assert id == activity.id
241
242 # Even a blocked user will deliver the full user timeline, there would be
243 # no point in looking at a blocked users timeline otherwise
244 assert resp =
245 conn
246 |> get("/api/v1/accounts/#{user_two.id}/statuses")
247 |> json_response_and_validate_schema(200)
248
249 assert [%{"id" => id}] = resp
250 assert id == activity.id
251
252 # Third user's timeline includes the repeat when viewed by unauthenticated user
253 resp =
254 build_conn()
255 |> get("/api/v1/accounts/#{user_three.id}/statuses")
256 |> json_response_and_validate_schema(200)
257
258 assert [%{"id" => id}] = resp
259 assert id == repeat.id
260
261 # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
262 resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
263
264 assert [] == json_response_and_validate_schema(resp, 200)
265 end
266
267 test "gets users statuses", %{conn: conn} do
268 user_one = insert(:user)
269 user_two = insert(:user)
270 user_three = insert(:user)
271
272 {:ok, _user_three} = User.follow(user_three, user_one)
273
274 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
275
276 {:ok, direct_activity} =
277 CommonAPI.post(user_one, %{
278 "status" => "Hi, @#{user_two.nickname}.",
279 "visibility" => "direct"
280 })
281
282 {:ok, private_activity} =
283 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
284
285 # TODO!!!
286 resp =
287 conn
288 |> get("/api/v1/accounts/#{user_one.id}/statuses")
289 |> json_response_and_validate_schema(200)
290
291 assert [%{"id" => id}] = resp
292 assert id == to_string(activity.id)
293
294 resp =
295 conn
296 |> assign(:user, user_two)
297 |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
298 |> get("/api/v1/accounts/#{user_one.id}/statuses")
299 |> json_response_and_validate_schema(200)
300
301 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
302 assert id_one == to_string(direct_activity.id)
303 assert id_two == to_string(activity.id)
304
305 resp =
306 conn
307 |> assign(:user, user_three)
308 |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
309 |> get("/api/v1/accounts/#{user_one.id}/statuses")
310 |> json_response_and_validate_schema(200)
311
312 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
313 assert id_one == to_string(private_activity.id)
314 assert id_two == to_string(activity.id)
315 end
316
317 test "unimplemented pinned statuses feature", %{conn: conn} do
318 note = insert(:note_activity)
319 user = User.get_cached_by_ap_id(note.data["actor"])
320
321 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?pinned=true")
322
323 assert json_response_and_validate_schema(conn, 200) == []
324 end
325
326 test "gets an users media", %{conn: conn} do
327 note = insert(:note_activity)
328 user = User.get_cached_by_ap_id(note.data["actor"])
329
330 file = %Plug.Upload{
331 content_type: "image/jpg",
332 path: Path.absname("test/fixtures/image.jpg"),
333 filename: "an_image.jpg"
334 }
335
336 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
337
338 {:ok, %{id: image_post_id}} =
339 CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
340
341 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true")
342
343 assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
344
345 conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1")
346
347 assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
348 end
349
350 test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
351 {:ok, %{id: post_id}} = CommonAPI.post(user, %{"status" => "HI!!!"})
352 {:ok, _, _} = CommonAPI.repeat(post_id, user)
353
354 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
355 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
356
357 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1")
358 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
359 end
360
361 test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
362 {:ok, %{id: post_id}} = CommonAPI.post(user, %{"status" => "#hashtag"})
363 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
364
365 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag")
366 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
367 end
368
369 test "the user views their own timelines and excludes direct messages", %{
370 user: user,
371 conn: conn
372 } do
373 {:ok, %{id: public_activity_id}} =
374 CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
375
376 {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
377
378 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
379 assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200)
380 end
381 end
382
383 defp local_and_remote_activities(%{local: local, remote: remote}) do
384 insert(:note_activity, user: local)
385 insert(:note_activity, user: remote, local: false)
386
387 :ok
388 end
389
390 describe "statuses with restrict unauthenticated profiles for local and remote" do
391 setup do: local_and_remote_users()
392 setup :local_and_remote_activities
393
394 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
395
396 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
397
398 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
399 assert %{"error" => "Can't find user"} ==
400 conn
401 |> get("/api/v1/accounts/#{local.id}/statuses")
402 |> json_response_and_validate_schema(:not_found)
403
404 assert %{"error" => "Can't find user"} ==
405 conn
406 |> get("/api/v1/accounts/#{remote.id}/statuses")
407 |> json_response_and_validate_schema(:not_found)
408 end
409
410 test "if user is authenticated", %{local: local, remote: remote} do
411 %{conn: conn} = oauth_access(["read"])
412
413 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
414 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
415
416 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
417 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
418 end
419 end
420
421 describe "statuses with restrict unauthenticated profiles for local" do
422 setup do: local_and_remote_users()
423 setup :local_and_remote_activities
424
425 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
426
427 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
428 assert %{"error" => "Can't find user"} ==
429 conn
430 |> get("/api/v1/accounts/#{local.id}/statuses")
431 |> json_response_and_validate_schema(:not_found)
432
433 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
434 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
435 end
436
437 test "if user is authenticated", %{local: local, remote: remote} do
438 %{conn: conn} = oauth_access(["read"])
439
440 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
441 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
442
443 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
444 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
445 end
446 end
447
448 describe "statuses with restrict unauthenticated profiles for remote" do
449 setup do: local_and_remote_users()
450 setup :local_and_remote_activities
451
452 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
453
454 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
455 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
456 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
457
458 assert %{"error" => "Can't find user"} ==
459 conn
460 |> get("/api/v1/accounts/#{remote.id}/statuses")
461 |> json_response_and_validate_schema(:not_found)
462 end
463
464 test "if user is authenticated", %{local: local, remote: remote} do
465 %{conn: conn} = oauth_access(["read"])
466
467 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
468 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
469
470 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
471 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
472 end
473 end
474
475 describe "followers" do
476 setup do: oauth_access(["read:accounts"])
477
478 test "getting followers", %{user: user, conn: conn} do
479 other_user = insert(:user)
480 {:ok, %{id: user_id}} = User.follow(user, other_user)
481
482 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
483
484 assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
485 end
486
487 test "getting followers, hide_followers", %{user: user, conn: conn} do
488 other_user = insert(:user, hide_followers: true)
489 {:ok, _user} = User.follow(user, other_user)
490
491 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
492
493 assert [] == json_response_and_validate_schema(conn, 200)
494 end
495
496 test "getting followers, hide_followers, same user requesting" do
497 user = insert(:user)
498 other_user = insert(:user, hide_followers: true)
499 {:ok, _user} = User.follow(user, other_user)
500
501 conn =
502 build_conn()
503 |> assign(:user, other_user)
504 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
505 |> get("/api/v1/accounts/#{other_user.id}/followers")
506
507 refute [] == json_response_and_validate_schema(conn, 200)
508 end
509
510 test "getting followers, pagination", %{user: user, conn: conn} do
511 {:ok, %User{id: follower1_id}} = :user |> insert() |> User.follow(user)
512 {:ok, %User{id: follower2_id}} = :user |> insert() |> User.follow(user)
513 {:ok, %User{id: follower3_id}} = :user |> insert() |> User.follow(user)
514
515 assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] =
516 conn
517 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1_id}")
518 |> json_response_and_validate_schema(200)
519
520 assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
521 conn
522 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}")
523 |> json_response_and_validate_schema(200)
524
525 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}")
526
527 assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200)
528
529 assert [link_header] = get_resp_header(res_conn, "link")
530 assert link_header =~ ~r/min_id=#{follower2_id}/
531 assert link_header =~ ~r/max_id=#{follower2_id}/
532 end
533 end
534
535 describe "following" do
536 setup do: oauth_access(["read:accounts"])
537
538 test "getting following", %{user: user, conn: conn} do
539 other_user = insert(:user)
540 {:ok, user} = User.follow(user, other_user)
541
542 conn = get(conn, "/api/v1/accounts/#{user.id}/following")
543
544 assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
545 assert id == to_string(other_user.id)
546 end
547
548 test "getting following, hide_follows, other user requesting" do
549 user = insert(:user, hide_follows: true)
550 other_user = insert(:user)
551 {:ok, user} = User.follow(user, other_user)
552
553 conn =
554 build_conn()
555 |> assign(:user, other_user)
556 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
557 |> get("/api/v1/accounts/#{user.id}/following")
558
559 assert [] == json_response_and_validate_schema(conn, 200)
560 end
561
562 test "getting following, hide_follows, same user requesting" do
563 user = insert(:user, hide_follows: true)
564 other_user = insert(:user)
565 {:ok, user} = User.follow(user, other_user)
566
567 conn =
568 build_conn()
569 |> assign(:user, user)
570 |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
571 |> get("/api/v1/accounts/#{user.id}/following")
572
573 refute [] == json_response_and_validate_schema(conn, 200)
574 end
575
576 test "getting following, pagination", %{user: user, conn: conn} do
577 following1 = insert(:user)
578 following2 = insert(:user)
579 following3 = insert(:user)
580 {:ok, _} = User.follow(user, following1)
581 {:ok, _} = User.follow(user, following2)
582 {:ok, _} = User.follow(user, following3)
583
584 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
585
586 assert [%{"id" => id3}, %{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
587 assert id3 == following3.id
588 assert id2 == following2.id
589
590 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
591
592 assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
593 assert id2 == following2.id
594 assert id1 == following1.id
595
596 res_conn =
597 get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
598
599 assert [%{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
600 assert id2 == following2.id
601
602 assert [link_header] = get_resp_header(res_conn, "link")
603 assert link_header =~ ~r/min_id=#{following2.id}/
604 assert link_header =~ ~r/max_id=#{following2.id}/
605 end
606 end
607
608 describe "follow/unfollow" do
609 setup do: oauth_access(["follow"])
610
611 test "following / unfollowing a user", %{conn: conn} do
612 %{id: other_user_id, nickname: other_user_nickname} = insert(:user)
613
614 assert %{"id" => _id, "following" => true} =
615 conn
616 |> post("/api/v1/accounts/#{other_user_id}/follow")
617 |> json_response_and_validate_schema(200)
618
619 assert %{"id" => _id, "following" => false} =
620 conn
621 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
622 |> json_response_and_validate_schema(200)
623
624 assert %{"id" => ^other_user_id} =
625 conn
626 |> put_req_header("content-type", "application/json")
627 |> post("/api/v1/follows", %{"uri" => other_user_nickname})
628 |> json_response_and_validate_schema(200)
629 end
630
631 test "cancelling follow request", %{conn: conn} do
632 %{id: other_user_id} = insert(:user, %{locked: true})
633
634 assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
635 conn
636 |> post("/api/v1/accounts/#{other_user_id}/follow")
637 |> json_response_and_validate_schema(:ok)
638
639 assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
640 conn
641 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
642 |> json_response_and_validate_schema(:ok)
643 end
644
645 test "following without reblogs" do
646 %{conn: conn} = oauth_access(["follow", "read:statuses"])
647 followed = insert(:user)
648 other_user = insert(:user)
649
650 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=false")
651
652 assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
653
654 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
655 {:ok, %{id: reblog_id}, _} = CommonAPI.repeat(activity.id, followed)
656
657 assert [] ==
658 conn
659 |> get("/api/v1/timelines/home")
660 |> json_response(200)
661
662 assert %{"showing_reblogs" => true} =
663 conn
664 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
665 |> json_response_and_validate_schema(200)
666
667 assert [%{"id" => ^reblog_id}] =
668 conn
669 |> get("/api/v1/timelines/home")
670 |> json_response(200)
671 end
672
673 test "following / unfollowing errors", %{user: user, conn: conn} do
674 # self follow
675 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
676
677 assert %{"error" => "Can not follow yourself"} =
678 json_response_and_validate_schema(conn_res, 400)
679
680 # self unfollow
681 user = User.get_cached_by_id(user.id)
682 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
683
684 assert %{"error" => "Can not unfollow yourself"} =
685 json_response_and_validate_schema(conn_res, 400)
686
687 # self follow via uri
688 user = User.get_cached_by_id(user.id)
689
690 assert %{"error" => "Can not follow yourself"} =
691 conn
692 |> put_req_header("content-type", "multipart/form-data")
693 |> post("/api/v1/follows", %{"uri" => user.nickname})
694 |> json_response_and_validate_schema(400)
695
696 # follow non existing user
697 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
698 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
699
700 # follow non existing user via uri
701 conn_res =
702 conn
703 |> put_req_header("content-type", "multipart/form-data")
704 |> post("/api/v1/follows", %{"uri" => "doesntexist"})
705
706 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
707
708 # unfollow non existing user
709 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
710 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
711 end
712 end
713
714 describe "mute/unmute" do
715 setup do: oauth_access(["write:mutes"])
716
717 test "with notifications", %{conn: conn} do
718 other_user = insert(:user)
719
720 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
721 conn
722 |> put_req_header("content-type", "application/json")
723 |> post("/api/v1/accounts/#{other_user.id}/mute")
724 |> json_response_and_validate_schema(200)
725
726 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
727
728 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
729 json_response_and_validate_schema(conn, 200)
730 end
731
732 test "without notifications", %{conn: conn} do
733 other_user = insert(:user)
734
735 ret_conn =
736 conn
737 |> put_req_header("content-type", "multipart/form-data")
738 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
739
740 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} =
741 json_response_and_validate_schema(ret_conn, 200)
742
743 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
744
745 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
746 json_response_and_validate_schema(conn, 200)
747 end
748 end
749
750 describe "pinned statuses" do
751 setup do
752 user = insert(:user)
753 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
754 %{conn: conn} = oauth_access(["read:statuses"], user: user)
755
756 [conn: conn, user: user, activity: activity]
757 end
758
759 test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do
760 {:ok, _} = CommonAPI.pin(activity_id, user)
761
762 assert [%{"id" => ^activity_id, "pinned" => true}] =
763 conn
764 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
765 |> json_response_and_validate_schema(200)
766 end
767 end
768
769 test "blocking / unblocking a user" do
770 %{conn: conn} = oauth_access(["follow"])
771 other_user = insert(:user)
772
773 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
774
775 assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200)
776
777 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
778
779 assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200)
780 end
781
782 describe "create account by app" do
783 setup do
784 valid_params = %{
785 username: "lain",
786 email: "lain@example.org",
787 password: "PlzDontHackLain",
788 agreement: true
789 }
790
791 [valid_params: valid_params]
792 end
793
794 setup do: clear_config([:instance, :account_activation_required])
795
796 test "Account registration via Application", %{conn: conn} do
797 conn =
798 conn
799 |> put_req_header("content-type", "application/json")
800 |> post("/api/v1/apps", %{
801 client_name: "client_name",
802 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
803 scopes: "read, write, follow"
804 })
805
806 assert %{
807 "client_id" => client_id,
808 "client_secret" => client_secret,
809 "id" => _,
810 "name" => "client_name",
811 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
812 "vapid_key" => _,
813 "website" => nil
814 } = json_response_and_validate_schema(conn, 200)
815
816 conn =
817 post(conn, "/oauth/token", %{
818 grant_type: "client_credentials",
819 client_id: client_id,
820 client_secret: client_secret
821 })
822
823 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
824 json_response(conn, 200)
825
826 assert token
827 token_from_db = Repo.get_by(Token, token: token)
828 assert token_from_db
829 assert refresh
830 assert scope == "read write follow"
831
832 conn =
833 build_conn()
834 |> put_req_header("content-type", "multipart/form-data")
835 |> put_req_header("authorization", "Bearer " <> token)
836 |> post("/api/v1/accounts", %{
837 username: "lain",
838 email: "lain@example.org",
839 password: "PlzDontHackLain",
840 bio: "Test Bio",
841 agreement: true
842 })
843
844 %{
845 "access_token" => token,
846 "created_at" => _created_at,
847 "scope" => _scope,
848 "token_type" => "Bearer"
849 } = json_response_and_validate_schema(conn, 200)
850
851 token_from_db = Repo.get_by(Token, token: token)
852 assert token_from_db
853 token_from_db = Repo.preload(token_from_db, :user)
854 assert token_from_db.user
855
856 assert token_from_db.user.confirmation_pending
857 end
858
859 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
860 _user = insert(:user, email: "lain@example.org")
861 app_token = insert(:oauth_token, user: nil)
862
863 res =
864 conn
865 |> put_req_header("authorization", "Bearer " <> app_token.token)
866 |> put_req_header("content-type", "application/json")
867 |> post("/api/v1/accounts", valid_params)
868
869 assert json_response_and_validate_schema(res, 400) == %{
870 "error" => "{\"email\":[\"has already been taken\"]}"
871 }
872 end
873
874 test "returns bad_request if missing required params", %{
875 conn: conn,
876 valid_params: valid_params
877 } do
878 app_token = insert(:oauth_token, user: nil)
879
880 conn =
881 conn
882 |> put_req_header("authorization", "Bearer " <> app_token.token)
883 |> put_req_header("content-type", "application/json")
884
885 res = post(conn, "/api/v1/accounts", valid_params)
886 assert json_response_and_validate_schema(res, 200)
887
888 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
889 |> Stream.zip(Map.delete(valid_params, :email))
890 |> Enum.each(fn {ip, {attr, _}} ->
891 res =
892 conn
893 |> Map.put(:remote_ip, ip)
894 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
895 |> json_response_and_validate_schema(400)
896
897 assert res == %{
898 "error" => "Missing field: #{attr}.",
899 "errors" => [
900 %{
901 "message" => "Missing field: #{attr}",
902 "source" => %{"pointer" => "/#{attr}"},
903 "title" => "Invalid value"
904 }
905 ]
906 }
907 end)
908 end
909
910 setup do: clear_config([:instance, :account_activation_required])
911
912 test "returns bad_request if missing email params when :account_activation_required is enabled",
913 %{conn: conn, valid_params: valid_params} do
914 Pleroma.Config.put([:instance, :account_activation_required], true)
915
916 app_token = insert(:oauth_token, user: nil)
917
918 conn =
919 conn
920 |> put_req_header("authorization", "Bearer " <> app_token.token)
921 |> put_req_header("content-type", "application/json")
922
923 res =
924 conn
925 |> Map.put(:remote_ip, {127, 0, 0, 5})
926 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
927
928 assert json_response_and_validate_schema(res, 400) ==
929 %{"error" => "Missing parameter: email"}
930
931 res =
932 conn
933 |> Map.put(:remote_ip, {127, 0, 0, 6})
934 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
935
936 assert json_response_and_validate_schema(res, 400) == %{
937 "error" => "{\"email\":[\"can't be blank\"]}"
938 }
939 end
940
941 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
942 app_token = insert(:oauth_token, user: nil)
943 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
944
945 res =
946 conn
947 |> put_req_header("content-type", "application/json")
948 |> Map.put(:remote_ip, {127, 0, 0, 7})
949 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
950
951 assert json_response_and_validate_schema(res, 200)
952 end
953
954 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
955 app_token = insert(:oauth_token, user: nil)
956 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
957
958 res =
959 conn
960 |> put_req_header("content-type", "application/json")
961 |> Map.put(:remote_ip, {127, 0, 0, 8})
962 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
963
964 assert json_response_and_validate_schema(res, 200)
965 end
966
967 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
968 res =
969 conn
970 |> put_req_header("authorization", "Bearer " <> "invalid-token")
971 |> put_req_header("content-type", "multipart/form-data")
972 |> post("/api/v1/accounts", valid_params)
973
974 assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"}
975 end
976
977 test "registration from trusted app" do
978 clear_config([Pleroma.Captcha, :enabled], true)
979 app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"])
980
981 conn =
982 build_conn()
983 |> post("/oauth/token", %{
984 "grant_type" => "client_credentials",
985 "client_id" => app.client_id,
986 "client_secret" => app.client_secret
987 })
988
989 assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200)
990
991 response =
992 build_conn()
993 |> Plug.Conn.put_req_header("authorization", "Bearer " <> token)
994 |> put_req_header("content-type", "multipart/form-data")
995 |> post("/api/v1/accounts", %{
996 nickname: "nickanme",
997 agreement: true,
998 email: "email@example.com",
999 fullname: "Lain",
1000 username: "Lain",
1001 password: "some_password",
1002 confirm: "some_password"
1003 })
1004 |> json_response_and_validate_schema(200)
1005
1006 assert %{
1007 "access_token" => access_token,
1008 "created_at" => _,
1009 "scope" => ["read", "write", "follow", "push"],
1010 "token_type" => "Bearer"
1011 } = response
1012
1013 response =
1014 build_conn()
1015 |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token)
1016 |> get("/api/v1/accounts/verify_credentials")
1017 |> json_response_and_validate_schema(200)
1018
1019 assert %{
1020 "acct" => "Lain",
1021 "bot" => false,
1022 "display_name" => "Lain",
1023 "follow_requests_count" => 0,
1024 "followers_count" => 0,
1025 "following_count" => 0,
1026 "locked" => false,
1027 "note" => "",
1028 "source" => %{
1029 "fields" => [],
1030 "note" => "",
1031 "pleroma" => %{
1032 "actor_type" => "Person",
1033 "discoverable" => false,
1034 "no_rich_text" => false,
1035 "show_role" => true
1036 },
1037 "privacy" => "public",
1038 "sensitive" => false
1039 },
1040 "statuses_count" => 0,
1041 "username" => "Lain"
1042 } = response
1043 end
1044 end
1045
1046 describe "create account by app / rate limit" do
1047 setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
1048
1049 test "respects rate limit setting", %{conn: conn} do
1050 app_token = insert(:oauth_token, user: nil)
1051
1052 conn =
1053 conn
1054 |> put_req_header("authorization", "Bearer " <> app_token.token)
1055 |> Map.put(:remote_ip, {15, 15, 15, 15})
1056 |> put_req_header("content-type", "multipart/form-data")
1057
1058 for i <- 1..2 do
1059 conn =
1060 conn
1061 |> post("/api/v1/accounts", %{
1062 username: "#{i}lain",
1063 email: "#{i}lain@example.org",
1064 password: "PlzDontHackLain",
1065 agreement: true
1066 })
1067
1068 %{
1069 "access_token" => token,
1070 "created_at" => _created_at,
1071 "scope" => _scope,
1072 "token_type" => "Bearer"
1073 } = json_response_and_validate_schema(conn, 200)
1074
1075 token_from_db = Repo.get_by(Token, token: token)
1076 assert token_from_db
1077 token_from_db = Repo.preload(token_from_db, :user)
1078 assert token_from_db.user
1079
1080 assert token_from_db.user.confirmation_pending
1081 end
1082
1083 conn =
1084 post(conn, "/api/v1/accounts", %{
1085 username: "6lain",
1086 email: "6lain@example.org",
1087 password: "PlzDontHackLain",
1088 agreement: true
1089 })
1090
1091 assert json_response_and_validate_schema(conn, :too_many_requests) == %{
1092 "error" => "Throttled"
1093 }
1094 end
1095 end
1096
1097 describe "create account with enabled captcha" do
1098 setup %{conn: conn} do
1099 app_token = insert(:oauth_token, user: nil)
1100
1101 conn =
1102 conn
1103 |> put_req_header("authorization", "Bearer " <> app_token.token)
1104 |> put_req_header("content-type", "multipart/form-data")
1105
1106 [conn: conn]
1107 end
1108
1109 setup do: clear_config([Pleroma.Captcha, :enabled], true)
1110
1111 test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
1112 %{token: token, answer_data: answer_data} = Pleroma.Captcha.new()
1113
1114 params = %{
1115 username: "lain",
1116 email: "lain@example.org",
1117 password: "PlzDontHackLain",
1118 agreement: true,
1119 captcha_solution: Pleroma.Captcha.Mock.solution(),
1120 captcha_token: token,
1121 captcha_answer_data: answer_data
1122 }
1123
1124 assert %{
1125 "access_token" => access_token,
1126 "created_at" => _,
1127 "scope" => ["read"],
1128 "token_type" => "Bearer"
1129 } =
1130 conn
1131 |> post("/api/v1/accounts", params)
1132 |> json_response_and_validate_schema(:ok)
1133
1134 assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
1135
1136 Cachex.del(:used_captcha_cache, token)
1137 end
1138
1139 test "returns 400 if any captcha field is not provided", %{conn: conn} do
1140 captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data]
1141
1142 valid_params = %{
1143 username: "lain",
1144 email: "lain@example.org",
1145 password: "PlzDontHackLain",
1146 agreement: true,
1147 captcha_solution: "xx",
1148 captcha_token: "xx",
1149 captcha_answer_data: "xx"
1150 }
1151
1152 for field <- captcha_fields do
1153 expected = %{
1154 "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}"
1155 }
1156
1157 assert expected ==
1158 conn
1159 |> post("/api/v1/accounts", Map.delete(valid_params, field))
1160 |> json_response_and_validate_schema(:bad_request)
1161 end
1162 end
1163
1164 test "returns an error if captcha is invalid", %{conn: conn} do
1165 params = %{
1166 username: "lain",
1167 email: "lain@example.org",
1168 password: "PlzDontHackLain",
1169 agreement: true,
1170 captcha_solution: "cofe",
1171 captcha_token: "cofe",
1172 captcha_answer_data: "cofe"
1173 }
1174
1175 assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} ==
1176 conn
1177 |> post("/api/v1/accounts", params)
1178 |> json_response_and_validate_schema(:bad_request)
1179 end
1180 end
1181
1182 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1183 test "returns lists to which the account belongs" do
1184 %{user: user, conn: conn} = oauth_access(["read:lists"])
1185 other_user = insert(:user)
1186 assert {:ok, %Pleroma.List{id: list_id} = list} = Pleroma.List.create("Test List", user)
1187 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1188
1189 assert [%{"id" => list_id, "title" => "Test List"}] =
1190 conn
1191 |> get("/api/v1/accounts/#{other_user.id}/lists")
1192 |> json_response_and_validate_schema(200)
1193 end
1194 end
1195
1196 describe "verify_credentials" do
1197 test "verify_credentials" do
1198 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1199 conn = get(conn, "/api/v1/accounts/verify_credentials")
1200
1201 response = json_response_and_validate_schema(conn, 200)
1202
1203 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1204 assert response["pleroma"]["chat_token"]
1205 assert id == to_string(user.id)
1206 end
1207
1208 test "verify_credentials default scope unlisted" do
1209 user = insert(:user, default_scope: "unlisted")
1210 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1211
1212 conn = get(conn, "/api/v1/accounts/verify_credentials")
1213
1214 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} =
1215 json_response_and_validate_schema(conn, 200)
1216
1217 assert id == to_string(user.id)
1218 end
1219
1220 test "locked accounts" do
1221 user = insert(:user, default_scope: "private")
1222 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1223
1224 conn = get(conn, "/api/v1/accounts/verify_credentials")
1225
1226 assert %{"id" => id, "source" => %{"privacy" => "private"}} =
1227 json_response_and_validate_schema(conn, 200)
1228
1229 assert id == to_string(user.id)
1230 end
1231 end
1232
1233 describe "user relationships" do
1234 setup do: oauth_access(["read:follows"])
1235
1236 test "returns the relationships for the current user", %{user: user, conn: conn} do
1237 %{id: other_user_id} = other_user = insert(:user)
1238 {:ok, _user} = User.follow(user, other_user)
1239
1240 assert [%{"id" => ^other_user_id}] =
1241 conn
1242 |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1243 |> json_response_and_validate_schema(200)
1244
1245 assert [%{"id" => ^other_user_id}] =
1246 conn
1247 |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
1248 |> json_response_and_validate_schema(200)
1249 end
1250
1251 test "returns an empty list on a bad request", %{conn: conn} do
1252 conn = get(conn, "/api/v1/accounts/relationships", %{})
1253
1254 assert [] = json_response_and_validate_schema(conn, 200)
1255 end
1256 end
1257
1258 test "getting a list of mutes" do
1259 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1260 other_user = insert(:user)
1261
1262 {:ok, _user_relationships} = User.mute(user, other_user)
1263
1264 conn = get(conn, "/api/v1/mutes")
1265
1266 other_user_id = to_string(other_user.id)
1267 assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200)
1268 end
1269
1270 test "getting a list of blocks" do
1271 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1272 other_user = insert(:user)
1273
1274 {:ok, _user_relationship} = User.block(user, other_user)
1275
1276 conn =
1277 conn
1278 |> assign(:user, user)
1279 |> get("/api/v1/blocks")
1280
1281 other_user_id = to_string(other_user.id)
1282 assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200)
1283 end
1284 end