1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
6 use Pleroma.Web.ConnCase
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.ActivityPub.InternalFetchActor
13 alias Pleroma.Web.ApiSpec
14 alias Pleroma.Web.CommonAPI
15 alias Pleroma.Web.OAuth.Token
17 import OpenApiSpex.TestAssertions
18 import Pleroma.Factory
20 describe "account fetching" do
21 setup do: clear_config([:instance, :limit_to_local_content])
28 |> get("/api/v1/accounts/#{user.id}")
30 assert %{"id" => id} = json_response(conn, 200)
31 assert id == to_string(user.id)
35 |> get("/api/v1/accounts/-1")
37 assert %{"error" => "Can't find user"} = json_response(conn, 404)
40 test "works by nickname" do
45 |> get("/api/v1/accounts/#{user.nickname}")
47 assert %{"id" => id} = json_response(conn, 200)
51 test "works by nickname for remote users" do
52 Config.put([:instance, :limit_to_local_content], false)
53 user = insert(:user, nickname: "user@example.com", local: false)
57 |> get("/api/v1/accounts/#{user.nickname}")
59 assert %{"id" => id} = json_response(conn, 200)
63 test "respects limit_to_local_content == :all for remote user nicknames" do
64 Config.put([:instance, :limit_to_local_content], :all)
66 user = insert(:user, nickname: "user@example.com", local: false)
70 |> get("/api/v1/accounts/#{user.nickname}")
72 assert json_response(conn, 404)
75 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
76 Config.put([:instance, :limit_to_local_content], :unauthenticated)
78 user = insert(:user, nickname: "user@example.com", local: false)
79 reading_user = insert(:user)
83 |> get("/api/v1/accounts/#{user.nickname}")
85 assert json_response(conn, 404)
89 |> assign(:user, reading_user)
90 |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
91 |> get("/api/v1/accounts/#{user.nickname}")
93 assert %{"id" => id} = json_response(conn, 200)
97 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
98 # Need to set an old-style integer ID to reproduce the problem
99 # (these are no longer assigned to new accounts but were preserved
100 # for existing accounts during the migration to flakeIDs)
101 user_one = insert(:user, %{id: 1212})
102 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
106 |> get("/api/v1/accounts/#{user_one.id}")
110 |> get("/api/v1/accounts/#{user_two.nickname}")
114 |> get("/api/v1/accounts/#{user_two.id}")
116 acc_one = json_response(resp_one, 200)
117 acc_two = json_response(resp_two, 200)
118 acc_three = json_response(resp_three, 200)
119 refute acc_one == acc_two
120 assert acc_two == acc_three
123 test "returns 404 when user is invisible", %{conn: conn} do
124 user = insert(:user, %{invisible: true})
128 |> get("/api/v1/accounts/#{user.nickname}")
129 |> json_response(404)
131 assert %{"error" => "Can't find user"} = resp
134 test "returns 404 for internal.fetch actor", %{conn: conn} do
135 %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
139 |> get("/api/v1/accounts/internal.fetch")
140 |> json_response(404)
142 assert %{"error" => "Can't find user"} = resp
146 defp local_and_remote_users do
147 local = insert(:user)
148 remote = insert(:user, local: false)
149 {:ok, local: local, remote: remote}
152 describe "user fetching with restrict unauthenticated profiles for local and remote" do
153 setup do: local_and_remote_users()
155 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
157 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
159 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
160 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
162 assert json_response(res_conn, :not_found) == %{
163 "error" => "Can't find user"
166 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
168 assert json_response(res_conn, :not_found) == %{
169 "error" => "Can't find user"
173 test "if user is authenticated", %{local: local, remote: remote} do
174 %{conn: conn} = oauth_access(["read"])
176 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
177 assert %{"id" => _} = json_response(res_conn, 200)
179 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
180 assert %{"id" => _} = json_response(res_conn, 200)
184 describe "user fetching with restrict unauthenticated profiles for local" do
185 setup do: local_and_remote_users()
187 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
189 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
190 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
192 assert json_response(res_conn, :not_found) == %{
193 "error" => "Can't find user"
196 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
197 assert %{"id" => _} = json_response(res_conn, 200)
200 test "if user is authenticated", %{local: local, remote: remote} do
201 %{conn: conn} = oauth_access(["read"])
203 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
204 assert %{"id" => _} = json_response(res_conn, 200)
206 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
207 assert %{"id" => _} = json_response(res_conn, 200)
211 describe "user fetching with restrict unauthenticated profiles for remote" do
212 setup do: local_and_remote_users()
214 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
216 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
217 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
218 assert %{"id" => _} = json_response(res_conn, 200)
220 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
222 assert json_response(res_conn, :not_found) == %{
223 "error" => "Can't find user"
227 test "if user is authenticated", %{local: local, remote: remote} do
228 %{conn: conn} = oauth_access(["read"])
230 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
231 assert %{"id" => _} = json_response(res_conn, 200)
233 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
234 assert %{"id" => _} = json_response(res_conn, 200)
238 describe "user timelines" do
239 setup do: oauth_access(["read:statuses"])
241 test "respects blocks", %{user: user_one, conn: conn} do
242 user_two = insert(:user)
243 user_three = insert(:user)
245 User.block(user_one, user_two)
247 {:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"})
248 {:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three)
250 assert resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") |> json_response(200)
251 assert [%{"id" => id}] = resp
252 assert_schema(resp, "StatusesResponse", ApiSpec.spec())
253 assert id == activity.id
255 # Even a blocked user will deliver the full user timeline, there would be
256 # no point in looking at a blocked users timeline otherwise
257 assert resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") |> json_response(200)
258 assert [%{"id" => id}] = resp
259 assert id == activity.id
260 assert_schema(resp, "StatusesResponse", ApiSpec.spec())
262 # Third user's timeline includes the repeat when viewed by unauthenticated user
263 resp = get(build_conn(), "/api/v1/accounts/#{user_three.id}/statuses") |> json_response(200)
264 assert [%{"id" => id}] = resp
265 assert id == repeat.id
266 assert_schema(resp, "StatusesResponse", ApiSpec.spec())
268 # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
269 resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
271 assert [] = json_response(resp, 200)
274 test "gets users statuses", %{conn: conn} do
275 user_one = insert(:user)
276 user_two = insert(:user)
277 user_three = insert(:user)
279 {:ok, _user_three} = User.follow(user_three, user_one)
281 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
283 {:ok, direct_activity} =
284 CommonAPI.post(user_one, %{
285 "status" => "Hi, @#{user_two.nickname}.",
286 "visibility" => "direct"
289 {:ok, private_activity} =
290 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
292 resp = get(conn, "/api/v1/accounts/#{user_one.id}/statuses") |> json_response(200)
293 assert [%{"id" => id}] = resp
294 assert id == to_string(activity.id)
295 assert_schema(resp, "StatusesResponse", ApiSpec.spec())
299 |> assign(:user, user_two)
300 |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
301 |> get("/api/v1/accounts/#{user_one.id}/statuses")
302 |> json_response(200)
304 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
305 assert id_one == to_string(direct_activity.id)
306 assert id_two == to_string(activity.id)
307 assert_schema(resp, "StatusesResponse", ApiSpec.spec())
311 |> assign(:user, user_three)
312 |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
313 |> get("/api/v1/accounts/#{user_one.id}/statuses")
314 |> json_response(200)
316 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
317 assert id_one == to_string(private_activity.id)
318 assert id_two == to_string(activity.id)
319 assert_schema(resp, "StatusesResponse", ApiSpec.spec())
322 test "unimplemented pinned statuses feature", %{conn: conn} do
323 note = insert(:note_activity)
324 user = User.get_cached_by_ap_id(note.data["actor"])
326 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?pinned=true")
328 assert json_response(conn, 200) == []
331 test "gets an users media", %{conn: conn} do
332 note = insert(:note_activity)
333 user = User.get_cached_by_ap_id(note.data["actor"])
336 content_type: "image/jpg",
337 path: Path.absname("test/fixtures/image.jpg"),
338 filename: "an_image.jpg"
341 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
343 {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
345 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true")
347 assert [%{"id" => id}] = json_response(conn, 200)
348 assert id == to_string(image_post.id)
349 assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
351 conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1")
353 assert [%{"id" => id}] = json_response(conn, 200)
354 assert id == to_string(image_post.id)
355 assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
358 test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
359 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
360 {:ok, _, _} = CommonAPI.repeat(post.id, user)
362 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
364 assert [%{"id" => id}] = json_response(conn, 200)
365 assert id == to_string(post.id)
366 assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
368 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1")
370 assert [%{"id" => id}] = json_response(conn, 200)
371 assert id == to_string(post.id)
372 assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
375 test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
376 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
377 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
379 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag")
381 assert [%{"id" => id}] = json_response(conn, 200)
382 assert id == to_string(post.id)
383 assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
386 test "the user views their own timelines and excludes direct messages", %{
390 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
391 {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
393 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
395 assert [%{"id" => id}] = json_response(conn, 200)
396 assert id == to_string(public_activity.id)
397 assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
401 defp local_and_remote_activities(%{local: local, remote: remote}) do
402 insert(:note_activity, user: local)
403 insert(:note_activity, user: remote, local: false)
408 describe "statuses with restrict unauthenticated profiles for local and remote" do
409 setup do: local_and_remote_users()
410 setup :local_and_remote_activities
412 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
414 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
416 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
417 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
419 assert json_response(res_conn, :not_found) == %{
420 "error" => "Can't find user"
423 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
425 assert json_response(res_conn, :not_found) == %{
426 "error" => "Can't find user"
430 test "if user is authenticated", %{local: local, remote: remote} do
431 %{conn: conn} = oauth_access(["read"])
433 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
434 assert length(json_response(res_conn, 200)) == 1
435 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
437 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
438 assert length(json_response(res_conn, 200)) == 1
439 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
443 describe "statuses with restrict unauthenticated profiles for local" do
444 setup do: local_and_remote_users()
445 setup :local_and_remote_activities
447 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
449 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
450 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
452 assert json_response(res_conn, :not_found) == %{
453 "error" => "Can't find user"
456 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
457 assert length(json_response(res_conn, 200)) == 1
458 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
461 test "if user is authenticated", %{local: local, remote: remote} do
462 %{conn: conn} = oauth_access(["read"])
464 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
465 assert length(json_response(res_conn, 200)) == 1
466 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
468 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
469 assert length(json_response(res_conn, 200)) == 1
470 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
474 describe "statuses with restrict unauthenticated profiles for remote" do
475 setup do: local_and_remote_users()
476 setup :local_and_remote_activities
478 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
480 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
481 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
482 assert length(json_response(res_conn, 200)) == 1
483 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
485 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
487 assert json_response(res_conn, :not_found) == %{
488 "error" => "Can't find user"
492 test "if user is authenticated", %{local: local, remote: remote} do
493 %{conn: conn} = oauth_access(["read"])
495 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
496 assert length(json_response(res_conn, 200)) == 1
497 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
499 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
500 assert length(json_response(res_conn, 200)) == 1
501 assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
505 describe "followers" do
506 setup do: oauth_access(["read:accounts"])
508 test "getting followers", %{user: user, conn: conn} do
509 other_user = insert(:user)
510 {:ok, user} = User.follow(user, other_user)
512 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
514 assert [%{"id" => id}] = json_response(conn, 200)
515 assert id == to_string(user.id)
518 test "getting followers, hide_followers", %{user: user, conn: conn} do
519 other_user = insert(:user, hide_followers: true)
520 {:ok, _user} = User.follow(user, other_user)
522 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
524 assert [] == json_response(conn, 200)
527 test "getting followers, hide_followers, same user requesting" do
529 other_user = insert(:user, hide_followers: true)
530 {:ok, _user} = User.follow(user, other_user)
534 |> assign(:user, other_user)
535 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
536 |> get("/api/v1/accounts/#{other_user.id}/followers")
538 refute [] == json_response(conn, 200)
541 test "getting followers, pagination", %{user: user, conn: conn} do
542 follower1 = insert(:user)
543 follower2 = insert(:user)
544 follower3 = insert(:user)
545 {:ok, _} = User.follow(follower1, user)
546 {:ok, _} = User.follow(follower2, user)
547 {:ok, _} = User.follow(follower3, user)
549 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
551 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
552 assert id3 == follower3.id
553 assert id2 == follower2.id
555 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
557 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
558 assert id2 == follower2.id
559 assert id1 == follower1.id
561 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
563 assert [%{"id" => id2}] = json_response(res_conn, 200)
564 assert id2 == follower2.id
566 assert [link_header] = get_resp_header(res_conn, "link")
567 assert link_header =~ ~r/min_id=#{follower2.id}/
568 assert link_header =~ ~r/max_id=#{follower2.id}/
572 describe "following" do
573 setup do: oauth_access(["read:accounts"])
575 test "getting following", %{user: user, conn: conn} do
576 other_user = insert(:user)
577 {:ok, user} = User.follow(user, other_user)
579 conn = get(conn, "/api/v1/accounts/#{user.id}/following")
581 assert [%{"id" => id}] = json_response(conn, 200)
582 assert id == to_string(other_user.id)
585 test "getting following, hide_follows, other user requesting" do
586 user = insert(:user, hide_follows: true)
587 other_user = insert(:user)
588 {:ok, user} = User.follow(user, other_user)
592 |> assign(:user, other_user)
593 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
594 |> get("/api/v1/accounts/#{user.id}/following")
596 assert [] == json_response(conn, 200)
599 test "getting following, hide_follows, same user requesting" do
600 user = insert(:user, hide_follows: true)
601 other_user = insert(:user)
602 {:ok, user} = User.follow(user, other_user)
606 |> assign(:user, user)
607 |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
608 |> get("/api/v1/accounts/#{user.id}/following")
610 refute [] == json_response(conn, 200)
613 test "getting following, pagination", %{user: user, conn: conn} do
614 following1 = insert(:user)
615 following2 = insert(:user)
616 following3 = insert(:user)
617 {:ok, _} = User.follow(user, following1)
618 {:ok, _} = User.follow(user, following2)
619 {:ok, _} = User.follow(user, following3)
621 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
623 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
624 assert id3 == following3.id
625 assert id2 == following2.id
627 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
629 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
630 assert id2 == following2.id
631 assert id1 == following1.id
634 get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
636 assert [%{"id" => id2}] = json_response(res_conn, 200)
637 assert id2 == following2.id
639 assert [link_header] = get_resp_header(res_conn, "link")
640 assert link_header =~ ~r/min_id=#{following2.id}/
641 assert link_header =~ ~r/max_id=#{following2.id}/
645 describe "follow/unfollow" do
646 setup do: oauth_access(["follow"])
648 test "following / unfollowing a user", %{conn: conn} do
649 other_user = insert(:user)
651 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/follow")
653 assert %{"id" => _id, "following" => true} = json_response(ret_conn, 200)
655 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/unfollow")
657 assert %{"id" => _id, "following" => false} = json_response(ret_conn, 200)
659 conn = post(conn, "/api/v1/follows", %{"uri" => other_user.nickname})
661 assert %{"id" => id} = json_response(conn, 200)
662 assert id == to_string(other_user.id)
665 test "cancelling follow request", %{conn: conn} do
666 %{id: other_user_id} = insert(:user, %{locked: true})
668 assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
669 conn |> post("/api/v1/accounts/#{other_user_id}/follow") |> json_response(:ok)
671 assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
672 conn |> post("/api/v1/accounts/#{other_user_id}/unfollow") |> json_response(:ok)
675 test "following without reblogs" do
676 %{conn: conn} = oauth_access(["follow", "read:statuses"])
677 followed = insert(:user)
678 other_user = insert(:user)
680 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=false")
682 assert %{"showing_reblogs" => false} = json_response(ret_conn, 200)
684 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
685 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
687 ret_conn = get(conn, "/api/v1/timelines/home")
689 assert [] == json_response(ret_conn, 200)
691 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=true")
693 assert %{"showing_reblogs" => true} = json_response(ret_conn, 200)
695 conn = get(conn, "/api/v1/timelines/home")
697 expected_activity_id = reblog.id
698 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
701 test "following / unfollowing errors", %{user: user, conn: conn} do
703 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
704 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
707 user = User.get_cached_by_id(user.id)
708 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
709 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
711 # self follow via uri
712 user = User.get_cached_by_id(user.id)
713 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
714 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
716 # follow non existing user
717 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
718 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
720 # follow non existing user via uri
721 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
722 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
724 # unfollow non existing user
725 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
726 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
730 describe "mute/unmute" do
731 setup do: oauth_access(["write:mutes"])
733 test "with notifications", %{conn: conn} do
734 other_user = insert(:user)
736 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/mute")
738 response = json_response(ret_conn, 200)
740 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
742 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
744 response = json_response(conn, 200)
745 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
748 test "without notifications", %{conn: conn} do
749 other_user = insert(:user)
752 post(conn, "/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
754 response = json_response(ret_conn, 200)
756 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
758 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
760 response = json_response(conn, 200)
761 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
765 describe "pinned statuses" do
768 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
769 %{conn: conn} = oauth_access(["read:statuses"], user: user)
771 [conn: conn, user: user, activity: activity]
774 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
775 {:ok, _} = CommonAPI.pin(activity.id, user)
779 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
780 |> json_response(200)
782 id_str = to_string(activity.id)
784 assert [%{"id" => ^id_str, "pinned" => true}] = result
788 test "blocking / unblocking a user" do
789 %{conn: conn} = oauth_access(["follow"])
790 other_user = insert(:user)
792 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
794 assert %{"id" => _id, "blocking" => true} = json_response(ret_conn, 200)
796 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
798 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
801 describe "create account by app" do
805 email: "lain@example.org",
806 password: "PlzDontHackLain",
810 [valid_params: valid_params]
813 setup do: clear_config([:instance, :account_activation_required])
815 test "Account registration via Application", %{conn: conn} do
818 |> put_req_header("content-type", "application/json")
819 |> post("/api/v1/apps", %{
820 client_name: "client_name",
821 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
822 scopes: "read, write, follow"
826 "client_id" => client_id,
827 "client_secret" => client_secret,
829 "name" => "client_name",
830 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
833 } = json_response(conn, 200)
836 post(conn, "/oauth/token", %{
837 grant_type: "client_credentials",
838 client_id: client_id,
839 client_secret: client_secret
842 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
843 json_response(conn, 200)
846 token_from_db = Repo.get_by(Token, token: token)
849 assert scope == "read write follow"
853 |> put_req_header("content-type", "multipart/form-data")
854 |> put_req_header("authorization", "Bearer " <> token)
855 |> post("/api/v1/accounts", %{
857 email: "lain@example.org",
858 password: "PlzDontHackLain",
864 "access_token" => token,
865 "created_at" => _created_at,
867 "token_type" => "Bearer"
868 } = json_response(conn, 200)
870 token_from_db = Repo.get_by(Token, token: token)
872 token_from_db = Repo.preload(token_from_db, :user)
873 assert token_from_db.user
875 assert token_from_db.user.confirmation_pending
878 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
879 _user = insert(:user, email: "lain@example.org")
880 app_token = insert(:oauth_token, user: nil)
884 |> put_req_header("authorization", "Bearer " <> app_token.token)
885 |> put_req_header("content-type", "application/json")
886 |> post("/api/v1/accounts", valid_params)
888 assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
891 test "returns bad_request if missing required params", %{
893 valid_params: valid_params
895 app_token = insert(:oauth_token, user: nil)
899 |> put_req_header("authorization", "Bearer " <> app_token.token)
900 |> put_req_header("content-type", "application/json")
902 res = post(conn, "/api/v1/accounts", valid_params)
903 assert json_response(res, 200)
905 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
906 |> Stream.zip(Map.delete(valid_params, :email))
907 |> Enum.each(fn {ip, {attr, _}} ->
910 |> Map.put(:remote_ip, ip)
911 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
912 |> json_response(400)
914 assert res == %{"error" => "Missing parameters"}
918 setup do: clear_config([:instance, :account_activation_required])
920 test "returns bad_request if missing email params when :account_activation_required is enabled",
921 %{conn: conn, valid_params: valid_params} do
922 Pleroma.Config.put([:instance, :account_activation_required], true)
924 app_token = insert(:oauth_token, user: nil)
928 |> put_req_header("authorization", "Bearer " <> app_token.token)
929 |> put_req_header("content-type", "application/json")
933 |> Map.put(:remote_ip, {127, 0, 0, 5})
934 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
936 assert json_response(res, 400) == %{"error" => "Missing parameters"}
940 |> Map.put(:remote_ip, {127, 0, 0, 6})
941 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
943 assert json_response(res, 400) == %{"error" => "{\"email\":[\"can't be blank\"]}"}
946 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
947 app_token = insert(:oauth_token, user: nil)
948 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
952 |> put_req_header("content-type", "application/json")
953 |> Map.put(:remote_ip, {127, 0, 0, 7})
954 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
956 assert json_response(res, 200)
959 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
960 app_token = insert(:oauth_token, user: nil)
961 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
965 |> put_req_header("content-type", "application/json")
966 |> Map.put(:remote_ip, {127, 0, 0, 8})
967 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
969 assert json_response(res, 200)
972 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
975 |> put_req_header("authorization", "Bearer " <> "invalid-token")
976 |> put_req_header("content-type", "multipart/form-data")
977 |> post("/api/v1/accounts", valid_params)
979 assert json_response(res, 403) == %{"error" => "Invalid credentials"}
983 describe "create account by app / rate limit" do
984 setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
986 test "respects rate limit setting", %{conn: conn} do
987 app_token = insert(:oauth_token, user: nil)
991 |> put_req_header("authorization", "Bearer " <> app_token.token)
992 |> Map.put(:remote_ip, {15, 15, 15, 15})
993 |> put_req_header("content-type", "multipart/form-data")
998 |> post("/api/v1/accounts", %{
999 username: "#{i}lain",
1000 email: "#{i}lain@example.org",
1001 password: "PlzDontHackLain",
1006 "access_token" => token,
1007 "created_at" => _created_at,
1009 "token_type" => "Bearer"
1010 } = json_response(conn, 200)
1012 token_from_db = Repo.get_by(Token, token: token)
1013 assert token_from_db
1014 token_from_db = Repo.preload(token_from_db, :user)
1015 assert token_from_db.user
1017 assert token_from_db.user.confirmation_pending
1021 post(conn, "/api/v1/accounts", %{
1023 email: "6lain@example.org",
1024 password: "PlzDontHackLain",
1028 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
1032 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1033 test "returns lists to which the account belongs" do
1034 %{user: user, conn: conn} = oauth_access(["read:lists"])
1035 other_user = insert(:user)
1036 assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user)
1037 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1041 |> get("/api/v1/accounts/#{other_user.id}/lists")
1042 |> json_response(200)
1044 assert res == [%{"id" => to_string(list.id), "title" => "Test List"}]
1048 describe "verify_credentials" do
1049 test "verify_credentials" do
1050 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1051 conn = get(conn, "/api/v1/accounts/verify_credentials")
1053 response = json_response(conn, 200)
1055 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1056 assert response["pleroma"]["chat_token"]
1057 assert id == to_string(user.id)
1060 test "verify_credentials default scope unlisted" do
1061 user = insert(:user, default_scope: "unlisted")
1062 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1064 conn = get(conn, "/api/v1/accounts/verify_credentials")
1066 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
1067 assert id == to_string(user.id)
1070 test "locked accounts" do
1071 user = insert(:user, default_scope: "private")
1072 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1074 conn = get(conn, "/api/v1/accounts/verify_credentials")
1076 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1077 assert id == to_string(user.id)
1081 describe "user relationships" do
1082 setup do: oauth_access(["read:follows"])
1084 test "returns the relationships for the current user", %{user: user, conn: conn} do
1085 %{id: other_user_id} = other_user = insert(:user)
1086 {:ok, _user} = User.follow(user, other_user)
1088 assert [%{"id" => ^other_user_id}] =
1090 |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1091 |> json_response(200)
1093 assert [%{"id" => ^other_user_id}] =
1095 |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
1096 |> json_response(200)
1099 test "returns an empty list on a bad request", %{conn: conn} do
1100 conn = get(conn, "/api/v1/accounts/relationships", %{})
1102 assert [] = json_response(conn, 200)
1106 test "getting a list of mutes" do
1107 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1108 other_user = insert(:user)
1110 {:ok, _user_relationships} = User.mute(user, other_user)
1112 conn = get(conn, "/api/v1/mutes")
1114 other_user_id = to_string(other_user.id)
1115 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1118 test "getting a list of blocks" do
1119 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1120 other_user = insert(:user)
1122 {:ok, _user_relationship} = User.block(user, other_user)
1126 |> assign(:user, user)
1127 |> get("/api/v1/blocks")
1129 other_user_id = to_string(other_user.id)
1130 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)