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.CommonAPI
14 alias Pleroma.Web.OAuth.Token
16 import Pleroma.Factory
18 describe "account fetching" do
19 clear_config([:instance, :limit_to_local_content])
26 |> get("/api/v1/accounts/#{user.id}")
28 assert %{"id" => id} = json_response(conn, 200)
29 assert id == to_string(user.id)
33 |> get("/api/v1/accounts/-1")
35 assert %{"error" => "Can't find user"} = json_response(conn, 404)
38 test "works by nickname" do
43 |> get("/api/v1/accounts/#{user.nickname}")
45 assert %{"id" => id} = json_response(conn, 200)
49 test "works by nickname for remote users" do
50 Config.put([:instance, :limit_to_local_content], false)
51 user = insert(:user, nickname: "user@example.com", local: false)
55 |> get("/api/v1/accounts/#{user.nickname}")
57 assert %{"id" => id} = json_response(conn, 200)
61 test "respects limit_to_local_content == :all for remote user nicknames" do
62 Config.put([:instance, :limit_to_local_content], :all)
64 user = insert(:user, nickname: "user@example.com", local: false)
68 |> get("/api/v1/accounts/#{user.nickname}")
70 assert json_response(conn, 404)
73 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
74 Config.put([:instance, :limit_to_local_content], :unauthenticated)
76 user = insert(:user, nickname: "user@example.com", local: false)
77 reading_user = insert(:user)
81 |> get("/api/v1/accounts/#{user.nickname}")
83 assert json_response(conn, 404)
87 |> assign(:user, reading_user)
88 |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
89 |> get("/api/v1/accounts/#{user.nickname}")
91 assert %{"id" => id} = json_response(conn, 200)
95 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
96 # Need to set an old-style integer ID to reproduce the problem
97 # (these are no longer assigned to new accounts but were preserved
98 # for existing accounts during the migration to flakeIDs)
99 user_one = insert(:user, %{id: 1212})
100 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
104 |> get("/api/v1/accounts/#{user_one.id}")
108 |> get("/api/v1/accounts/#{user_two.nickname}")
112 |> get("/api/v1/accounts/#{user_two.id}")
114 acc_one = json_response(resp_one, 200)
115 acc_two = json_response(resp_two, 200)
116 acc_three = json_response(resp_three, 200)
117 refute acc_one == acc_two
118 assert acc_two == acc_three
121 test "returns 404 when user is invisible", %{conn: conn} do
122 user = insert(:user, %{invisible: true})
126 |> get("/api/v1/accounts/#{user.nickname}")
127 |> json_response(404)
129 assert %{"error" => "Can't find user"} = resp
132 test "returns 404 for internal.fetch actor", %{conn: conn} do
133 %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
137 |> get("/api/v1/accounts/internal.fetch")
138 |> json_response(404)
140 assert %{"error" => "Can't find user"} = resp
144 defp local_and_remote_users do
145 local = insert(:user)
146 remote = insert(:user, local: false)
147 {:ok, local: local, remote: remote}
150 describe "user fetching with restrict unauthenticated profiles for local and remote" do
151 setup do: local_and_remote_users()
153 clear_config([:restrict_unauthenticated, :profiles, :local]) do
154 Config.put([:restrict_unauthenticated, :profiles, :local], true)
157 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
158 Config.put([:restrict_unauthenticated, :profiles, :remote], true)
161 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
162 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
164 assert json_response(res_conn, :not_found) == %{
165 "error" => "Can't find user"
168 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
170 assert json_response(res_conn, :not_found) == %{
171 "error" => "Can't find user"
175 test "if user is authenticated", %{local: local, remote: remote} do
176 %{conn: conn} = oauth_access(["read"])
178 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
179 assert %{"id" => _} = json_response(res_conn, 200)
181 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
182 assert %{"id" => _} = json_response(res_conn, 200)
186 describe "user fetching with restrict unauthenticated profiles for local" do
187 setup do: local_and_remote_users()
189 clear_config([:restrict_unauthenticated, :profiles, :local]) do
190 Config.put([:restrict_unauthenticated, :profiles, :local], true)
193 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
194 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
196 assert json_response(res_conn, :not_found) == %{
197 "error" => "Can't find user"
200 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
201 assert %{"id" => _} = json_response(res_conn, 200)
204 test "if user is authenticated", %{local: local, remote: remote} do
205 %{conn: conn} = oauth_access(["read"])
207 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
208 assert %{"id" => _} = json_response(res_conn, 200)
210 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
211 assert %{"id" => _} = json_response(res_conn, 200)
215 describe "user fetching with restrict unauthenticated profiles for remote" do
216 setup do: local_and_remote_users()
218 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
219 Config.put([:restrict_unauthenticated, :profiles, :remote], true)
222 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
223 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
224 assert %{"id" => _} = json_response(res_conn, 200)
226 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
228 assert json_response(res_conn, :not_found) == %{
229 "error" => "Can't find user"
233 test "if user is authenticated", %{local: local, remote: remote} do
234 %{conn: conn} = oauth_access(["read"])
236 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
237 assert %{"id" => _} = json_response(res_conn, 200)
239 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
240 assert %{"id" => _} = json_response(res_conn, 200)
244 describe "user timelines" do
245 setup do: oauth_access(["read:statuses"])
247 test "respects blocks", %{user: user_one, conn: conn} do
248 user_two = insert(:user)
249 user_three = insert(:user)
251 User.block(user_one, user_two)
253 {:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"})
254 {:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three)
256 resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses")
258 assert [%{"id" => id}] = json_response(resp, 200)
259 assert id == activity.id
261 # Even a blocked user will deliver the full user timeline, there would be
262 # no point in looking at a blocked users timeline otherwise
263 resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses")
265 assert [%{"id" => id}] = json_response(resp, 200)
266 assert id == activity.id
268 # Third user's timeline includes the repeat when viewed by unauthenticated user
269 resp = get(build_conn(), "/api/v1/accounts/#{user_three.id}/statuses")
270 assert [%{"id" => id}] = json_response(resp, 200)
271 assert id == repeat.id
273 # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
274 resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
276 assert [] = json_response(resp, 200)
279 test "gets users statuses", %{conn: conn} do
280 user_one = insert(:user)
281 user_two = insert(:user)
282 user_three = insert(:user)
284 {:ok, _user_three} = User.follow(user_three, user_one)
286 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
288 {:ok, direct_activity} =
289 CommonAPI.post(user_one, %{
290 "status" => "Hi, @#{user_two.nickname}.",
291 "visibility" => "direct"
294 {:ok, private_activity} =
295 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
297 resp = get(conn, "/api/v1/accounts/#{user_one.id}/statuses")
299 assert [%{"id" => id}] = json_response(resp, 200)
300 assert id == to_string(activity.id)
304 |> assign(:user, user_two)
305 |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
306 |> get("/api/v1/accounts/#{user_one.id}/statuses")
308 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
309 assert id_one == to_string(direct_activity.id)
310 assert id_two == to_string(activity.id)
314 |> assign(:user, user_three)
315 |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
316 |> get("/api/v1/accounts/#{user_one.id}/statuses")
318 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
319 assert id_one == to_string(private_activity.id)
320 assert id_two == to_string(activity.id)
323 test "unimplemented pinned statuses feature", %{conn: conn} do
324 note = insert(:note_activity)
325 user = User.get_cached_by_ap_id(note.data["actor"])
327 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?pinned=true")
329 assert json_response(conn, 200) == []
332 test "gets an users media", %{conn: conn} do
333 note = insert(:note_activity)
334 user = User.get_cached_by_ap_id(note.data["actor"])
337 content_type: "image/jpg",
338 path: Path.absname("test/fixtures/image.jpg"),
339 filename: "an_image.jpg"
342 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
344 {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
346 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
348 assert [%{"id" => id}] = json_response(conn, 200)
349 assert id == to_string(image_post.id)
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)
357 test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
358 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
359 {:ok, _, _} = CommonAPI.repeat(post.id, user)
361 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
363 assert [%{"id" => id}] = json_response(conn, 200)
364 assert id == to_string(post.id)
366 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
368 assert [%{"id" => id}] = json_response(conn, 200)
369 assert id == to_string(post.id)
372 test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
373 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
374 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
376 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
378 assert [%{"id" => id}] = json_response(conn, 200)
379 assert id == to_string(post.id)
382 test "the user views their own timelines and excludes direct messages", %{
386 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
387 {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
390 get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_visibilities" => ["direct"]})
392 assert [%{"id" => id}] = json_response(conn, 200)
393 assert id == to_string(public_activity.id)
397 defp local_and_remote_activities(%{local: local, remote: remote}) do
398 insert(:note_activity, user: local)
399 insert(:note_activity, user: remote, local: false)
404 describe "statuses with restrict unauthenticated profiles for local and remote" do
405 setup do: local_and_remote_users()
406 setup :local_and_remote_activities
408 clear_config([:restrict_unauthenticated, :profiles, :local]) do
409 Config.put([:restrict_unauthenticated, :profiles, :local], true)
412 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
413 Config.put([: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
436 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
437 assert length(json_response(res_conn, 200)) == 1
441 describe "statuses with restrict unauthenticated profiles for local" do
442 setup do: local_and_remote_users()
443 setup :local_and_remote_activities
445 clear_config([:restrict_unauthenticated, :profiles, :local]) do
446 Config.put([: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
460 test "if user is authenticated", %{local: local, remote: remote} do
461 %{conn: conn} = oauth_access(["read"])
463 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
464 assert length(json_response(res_conn, 200)) == 1
466 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
467 assert length(json_response(res_conn, 200)) == 1
471 describe "statuses with restrict unauthenticated profiles for remote" do
472 setup do: local_and_remote_users()
473 setup :local_and_remote_activities
475 clear_config([:restrict_unauthenticated, :profiles, :remote]) do
476 Config.put([:restrict_unauthenticated, :profiles, :remote], true)
479 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
480 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
481 assert length(json_response(res_conn, 200)) == 1
483 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
485 assert json_response(res_conn, :not_found) == %{
486 "error" => "Can't find user"
490 test "if user is authenticated", %{local: local, remote: remote} do
491 %{conn: conn} = oauth_access(["read"])
493 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
494 assert length(json_response(res_conn, 200)) == 1
496 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
497 assert length(json_response(res_conn, 200)) == 1
501 describe "followers" do
502 setup do: oauth_access(["read:accounts"])
504 test "getting followers", %{user: user, conn: conn} do
505 other_user = insert(:user)
506 {:ok, user} = User.follow(user, other_user)
508 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
510 assert [%{"id" => id}] = json_response(conn, 200)
511 assert id == to_string(user.id)
514 test "getting followers, hide_followers", %{user: user, conn: conn} do
515 other_user = insert(:user, hide_followers: true)
516 {:ok, _user} = User.follow(user, other_user)
518 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
520 assert [] == json_response(conn, 200)
523 test "getting followers, hide_followers, same user requesting" do
525 other_user = insert(:user, hide_followers: true)
526 {:ok, _user} = User.follow(user, other_user)
530 |> assign(:user, other_user)
531 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
532 |> get("/api/v1/accounts/#{other_user.id}/followers")
534 refute [] == json_response(conn, 200)
537 test "getting followers, pagination", %{user: user, conn: conn} do
538 follower1 = insert(:user)
539 follower2 = insert(:user)
540 follower3 = insert(:user)
541 {:ok, _} = User.follow(follower1, user)
542 {:ok, _} = User.follow(follower2, user)
543 {:ok, _} = User.follow(follower3, user)
545 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
547 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
548 assert id3 == follower3.id
549 assert id2 == follower2.id
551 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
553 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
554 assert id2 == follower2.id
555 assert id1 == follower1.id
557 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
559 assert [%{"id" => id2}] = json_response(res_conn, 200)
560 assert id2 == follower2.id
562 assert [link_header] = get_resp_header(res_conn, "link")
563 assert link_header =~ ~r/min_id=#{follower2.id}/
564 assert link_header =~ ~r/max_id=#{follower2.id}/
568 describe "following" do
569 setup do: oauth_access(["read:accounts"])
571 test "getting following", %{user: user, conn: conn} do
572 other_user = insert(:user)
573 {:ok, user} = User.follow(user, other_user)
575 conn = get(conn, "/api/v1/accounts/#{user.id}/following")
577 assert [%{"id" => id}] = json_response(conn, 200)
578 assert id == to_string(other_user.id)
581 test "getting following, hide_follows, other user requesting" do
582 user = insert(:user, hide_follows: true)
583 other_user = insert(:user)
584 {:ok, user} = User.follow(user, other_user)
588 |> assign(:user, other_user)
589 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
590 |> get("/api/v1/accounts/#{user.id}/following")
592 assert [] == json_response(conn, 200)
595 test "getting following, hide_follows, same user requesting" do
596 user = insert(:user, hide_follows: true)
597 other_user = insert(:user)
598 {:ok, user} = User.follow(user, other_user)
602 |> assign(:user, user)
603 |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
604 |> get("/api/v1/accounts/#{user.id}/following")
606 refute [] == json_response(conn, 200)
609 test "getting following, pagination", %{user: user, conn: conn} do
610 following1 = insert(:user)
611 following2 = insert(:user)
612 following3 = insert(:user)
613 {:ok, _} = User.follow(user, following1)
614 {:ok, _} = User.follow(user, following2)
615 {:ok, _} = User.follow(user, following3)
617 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
619 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
620 assert id3 == following3.id
621 assert id2 == following2.id
623 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
625 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
626 assert id2 == following2.id
627 assert id1 == following1.id
630 get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
632 assert [%{"id" => id2}] = json_response(res_conn, 200)
633 assert id2 == following2.id
635 assert [link_header] = get_resp_header(res_conn, "link")
636 assert link_header =~ ~r/min_id=#{following2.id}/
637 assert link_header =~ ~r/max_id=#{following2.id}/
641 describe "follow/unfollow" do
642 setup do: oauth_access(["follow"])
644 test "following / unfollowing a user", %{conn: conn} do
645 other_user = insert(:user)
647 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/follow")
649 assert %{"id" => _id, "following" => true} = json_response(ret_conn, 200)
651 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/unfollow")
653 assert %{"id" => _id, "following" => false} = json_response(ret_conn, 200)
655 conn = post(conn, "/api/v1/follows", %{"uri" => other_user.nickname})
657 assert %{"id" => id} = json_response(conn, 200)
658 assert id == to_string(other_user.id)
661 test "cancelling follow request", %{conn: conn} do
662 %{id: other_user_id} = insert(:user, %{locked: true})
664 assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
665 conn |> post("/api/v1/accounts/#{other_user_id}/follow") |> json_response(:ok)
667 assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
668 conn |> post("/api/v1/accounts/#{other_user_id}/unfollow") |> json_response(:ok)
671 test "following without reblogs" do
672 %{conn: conn} = oauth_access(["follow", "read:statuses"])
673 followed = insert(:user)
674 other_user = insert(:user)
676 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=false")
678 assert %{"showing_reblogs" => false} = json_response(ret_conn, 200)
680 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
681 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
683 ret_conn = get(conn, "/api/v1/timelines/home")
685 assert [] == json_response(ret_conn, 200)
687 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=true")
689 assert %{"showing_reblogs" => true} = json_response(ret_conn, 200)
691 conn = get(conn, "/api/v1/timelines/home")
693 expected_activity_id = reblog.id
694 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
697 test "following / unfollowing errors", %{user: user, conn: conn} do
699 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
700 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
703 user = User.get_cached_by_id(user.id)
704 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
705 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
707 # self follow via uri
708 user = User.get_cached_by_id(user.id)
709 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
710 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
712 # follow non existing user
713 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
714 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
716 # follow non existing user via uri
717 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
718 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
720 # unfollow non existing user
721 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
722 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
726 describe "mute/unmute" do
727 setup do: oauth_access(["write:mutes"])
729 test "with notifications", %{conn: conn} do
730 other_user = insert(:user)
732 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/mute")
734 response = json_response(ret_conn, 200)
736 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
738 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
740 response = json_response(conn, 200)
741 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
744 test "without notifications", %{conn: conn} do
745 other_user = insert(:user)
748 post(conn, "/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
750 response = json_response(ret_conn, 200)
752 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
754 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
756 response = json_response(conn, 200)
757 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
761 describe "pinned statuses" do
764 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
765 %{conn: conn} = oauth_access(["read:statuses"], user: user)
767 [conn: conn, user: user, activity: activity]
770 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
771 {:ok, _} = CommonAPI.pin(activity.id, user)
775 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
776 |> json_response(200)
778 id_str = to_string(activity.id)
780 assert [%{"id" => ^id_str, "pinned" => true}] = result
784 test "blocking / unblocking a user" do
785 %{conn: conn} = oauth_access(["follow"])
786 other_user = insert(:user)
788 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
790 assert %{"id" => _id, "blocking" => true} = json_response(ret_conn, 200)
792 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
794 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
797 describe "create account by app" do
801 email: "lain@example.org",
802 password: "PlzDontHackLain",
806 [valid_params: valid_params]
809 clear_config([:instance, :account_activation_required])
811 test "Account registration via Application", %{conn: conn} do
813 post(conn, "/api/v1/apps", %{
814 client_name: "client_name",
815 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
816 scopes: "read, write, follow"
820 "client_id" => client_id,
821 "client_secret" => client_secret,
823 "name" => "client_name",
824 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
827 } = json_response(conn, 200)
830 post(conn, "/oauth/token", %{
831 grant_type: "client_credentials",
832 client_id: client_id,
833 client_secret: client_secret
836 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
837 json_response(conn, 200)
840 token_from_db = Repo.get_by(Token, token: token)
843 assert scope == "read write follow"
847 |> put_req_header("authorization", "Bearer " <> token)
848 |> post("/api/v1/accounts", %{
850 email: "lain@example.org",
851 password: "PlzDontHackLain",
857 "access_token" => token,
858 "created_at" => _created_at,
860 "token_type" => "Bearer"
861 } = json_response(conn, 200)
863 token_from_db = Repo.get_by(Token, token: token)
865 token_from_db = Repo.preload(token_from_db, :user)
866 assert token_from_db.user
868 assert token_from_db.user.confirmation_pending
871 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
872 _user = insert(:user, email: "lain@example.org")
873 app_token = insert(:oauth_token, user: nil)
877 |> put_req_header("authorization", "Bearer " <> app_token.token)
879 res = post(conn, "/api/v1/accounts", valid_params)
880 assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
883 test "returns bad_request if missing required params", %{
885 valid_params: valid_params
887 app_token = insert(:oauth_token, user: nil)
889 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
891 res = post(conn, "/api/v1/accounts", valid_params)
892 assert json_response(res, 200)
894 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
895 |> Stream.zip(Map.delete(valid_params, :email))
896 |> Enum.each(fn {ip, {attr, _}} ->
899 |> Map.put(:remote_ip, ip)
900 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
901 |> json_response(400)
903 assert res == %{"error" => "Missing parameters"}
907 clear_config([:instance, :account_activation_required])
909 test "returns bad_request if missing email params when :account_activation_required is enabled",
910 %{conn: conn, valid_params: valid_params} do
911 Pleroma.Config.put([:instance, :account_activation_required], true)
913 app_token = insert(:oauth_token, user: nil)
914 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
918 |> Map.put(:remote_ip, {127, 0, 0, 5})
919 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
921 assert json_response(res, 400) == %{"error" => "Missing parameters"}
925 |> Map.put(:remote_ip, {127, 0, 0, 6})
926 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
928 assert json_response(res, 400) == %{"error" => "{\"email\":[\"can't be blank\"]}"}
931 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
932 app_token = insert(:oauth_token, user: nil)
933 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
937 |> Map.put(:remote_ip, {127, 0, 0, 7})
938 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
940 assert json_response(res, 200)
943 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
944 app_token = insert(:oauth_token, user: nil)
945 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
949 |> Map.put(:remote_ip, {127, 0, 0, 8})
950 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
952 assert json_response(res, 200)
955 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
956 conn = put_req_header(conn, "authorization", "Bearer " <> "invalid-token")
958 res = post(conn, "/api/v1/accounts", valid_params)
959 assert json_response(res, 403) == %{"error" => "Invalid credentials"}
963 describe "create account by app / rate limit" do
964 clear_config([:rate_limit, :app_account_creation]) do
965 Config.put([:rate_limit, :app_account_creation], {10_000, 2})
968 test "respects rate limit setting", %{conn: conn} do
969 app_token = insert(:oauth_token, user: nil)
973 |> put_req_header("authorization", "Bearer " <> app_token.token)
974 |> Map.put(:remote_ip, {15, 15, 15, 15})
978 post(conn, "/api/v1/accounts", %{
979 username: "#{i}lain",
980 email: "#{i}lain@example.org",
981 password: "PlzDontHackLain",
986 "access_token" => token,
987 "created_at" => _created_at,
989 "token_type" => "Bearer"
990 } = json_response(conn, 200)
992 token_from_db = Repo.get_by(Token, token: token)
994 token_from_db = Repo.preload(token_from_db, :user)
995 assert token_from_db.user
997 assert token_from_db.user.confirmation_pending
1001 post(conn, "/api/v1/accounts", %{
1003 email: "6lain@example.org",
1004 password: "PlzDontHackLain",
1008 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
1012 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1013 test "returns lists to which the account belongs" do
1014 %{user: user, conn: conn} = oauth_access(["read:lists"])
1015 other_user = insert(:user)
1016 assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user)
1017 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1021 |> get("/api/v1/accounts/#{other_user.id}/lists")
1022 |> json_response(200)
1024 assert res == [%{"id" => to_string(list.id), "title" => "Test List"}]
1028 describe "verify_credentials" do
1029 test "verify_credentials" do
1030 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1031 conn = get(conn, "/api/v1/accounts/verify_credentials")
1033 response = json_response(conn, 200)
1035 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1036 assert response["pleroma"]["chat_token"]
1037 assert id == to_string(user.id)
1040 test "verify_credentials default scope unlisted" do
1041 user = insert(:user, default_scope: "unlisted")
1042 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1044 conn = get(conn, "/api/v1/accounts/verify_credentials")
1046 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
1047 assert id == to_string(user.id)
1050 test "locked accounts" do
1051 user = insert(:user, default_scope: "private")
1052 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1054 conn = get(conn, "/api/v1/accounts/verify_credentials")
1056 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1057 assert id == to_string(user.id)
1061 describe "user relationships" do
1062 setup do: oauth_access(["read:follows"])
1064 test "returns the relationships for the current user", %{user: user, conn: conn} do
1065 other_user = insert(:user)
1066 {:ok, _user} = User.follow(user, other_user)
1068 conn = get(conn, "/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1070 assert [relationship] = json_response(conn, 200)
1072 assert to_string(other_user.id) == relationship["id"]
1075 test "returns an empty list on a bad request", %{conn: conn} do
1076 conn = get(conn, "/api/v1/accounts/relationships", %{})
1078 assert [] = json_response(conn, 200)
1082 test "getting a list of mutes" do
1083 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1084 other_user = insert(:user)
1086 {:ok, _user_relationships} = User.mute(user, other_user)
1088 conn = get(conn, "/api/v1/mutes")
1090 other_user_id = to_string(other_user.id)
1091 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1094 test "getting a list of blocks" do
1095 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1096 other_user = insert(:user)
1098 {:ok, _user_relationship} = User.block(user, other_user)
1102 |> assign(:user, user)
1103 |> get("/api/v1/blocks")
1105 other_user_id = to_string(other_user.id)
1106 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)