1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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
10 alias Pleroma.Web.ActivityPub.ActivityPub
11 alias Pleroma.Web.ActivityPub.InternalFetchActor
12 alias Pleroma.Web.CommonAPI
13 alias Pleroma.Web.OAuth.Token
14 alias Pleroma.Web.Plugs.SetLocalePlug
16 import Pleroma.Factory
18 describe "account fetching" do
20 %User{id: user_id} = insert(:user)
22 assert %{"id" => ^user_id} =
24 |> get("/api/v1/accounts/#{user_id}")
25 |> json_response_and_validate_schema(200)
27 assert %{"error" => "Can't find user"} =
29 |> get("/api/v1/accounts/-1")
30 |> json_response_and_validate_schema(404)
33 test "relationship field" do
34 %{conn: conn, user: user} = oauth_access(["read"])
36 other_user = insert(:user)
40 |> get("/api/v1/accounts/#{other_user.id}")
41 |> json_response_and_validate_schema(200)
43 assert response["id"] == other_user.id
44 assert response["pleroma"]["relationship"] == %{}
46 assert %{"pleroma" => %{"relationship" => %{"following" => false, "followed_by" => false}}} =
48 |> get("/api/v1/accounts/#{other_user.id}?with_relationships=true")
49 |> json_response_and_validate_schema(200)
51 {:ok, _, %{id: other_id}} = User.follow(user, other_user)
55 "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => false}}
58 |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
59 |> json_response_and_validate_schema(200)
61 {:ok, _, _} = User.follow(other_user, user)
65 "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => true}}
68 |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
69 |> json_response_and_validate_schema(200)
72 test "works by nickname" do
75 assert %{"id" => _user_id} =
77 |> get("/api/v1/accounts/#{user.nickname}")
78 |> json_response_and_validate_schema(200)
81 test "works by nickname for remote users" do
82 clear_config([:instance, :limit_to_local_content], false)
84 user = insert(:user, nickname: "user@example.com", local: false)
86 assert %{"id" => _user_id} =
88 |> get("/api/v1/accounts/#{user.nickname}")
89 |> json_response_and_validate_schema(200)
92 test "respects limit_to_local_content == :all for remote user nicknames" do
93 clear_config([:instance, :limit_to_local_content], :all)
95 user = insert(:user, nickname: "user@example.com", local: false)
98 |> get("/api/v1/accounts/#{user.nickname}")
99 |> json_response_and_validate_schema(404)
102 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
103 clear_config([:instance, :limit_to_local_content], :unauthenticated)
105 user = insert(:user, nickname: "user@example.com", local: false)
106 reading_user = insert(:user)
110 |> get("/api/v1/accounts/#{user.nickname}")
112 assert json_response_and_validate_schema(conn, 404)
116 |> assign(:user, reading_user)
117 |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
118 |> get("/api/v1/accounts/#{user.nickname}")
120 assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
124 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
125 # Need to set an old-style integer ID to reproduce the problem
126 # (these are no longer assigned to new accounts but were preserved
127 # for existing accounts during the migration to flakeIDs)
128 user_one = insert(:user, %{id: 1212})
129 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
133 |> get("/api/v1/accounts/#{user_one.id}")
134 |> json_response_and_validate_schema(:ok)
138 |> get("/api/v1/accounts/#{user_two.nickname}")
139 |> json_response_and_validate_schema(:ok)
143 |> get("/api/v1/accounts/#{user_two.id}")
144 |> json_response_and_validate_schema(:ok)
146 refute acc_one == acc_two
147 assert acc_two == acc_three
150 test "returns 404 when user is invisible", %{conn: conn} do
151 user = insert(:user, %{invisible: true})
153 assert %{"error" => "Can't find user"} =
155 |> get("/api/v1/accounts/#{user.nickname}")
156 |> json_response_and_validate_schema(404)
159 test "returns 404 for internal.fetch actor", %{conn: conn} do
160 %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
162 assert %{"error" => "Can't find user"} =
164 |> get("/api/v1/accounts/internal.fetch")
165 |> json_response_and_validate_schema(404)
168 test "returns 404 for deactivated user", %{conn: conn} do
169 user = insert(:user, is_active: false)
171 assert %{"error" => "Can't find user"} =
173 |> get("/api/v1/accounts/#{user.id}")
174 |> json_response_and_validate_schema(:not_found)
178 defp local_and_remote_users do
179 local = insert(:user)
180 remote = insert(:user, local: false)
181 {:ok, local: local, remote: remote}
184 describe "user fetching with restrict unauthenticated profiles for local and remote" do
185 setup do: local_and_remote_users()
187 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
189 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
191 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
192 assert %{"error" => "This API requires an authenticated user"} ==
194 |> get("/api/v1/accounts/#{local.id}")
195 |> json_response_and_validate_schema(:unauthorized)
197 assert %{"error" => "This API requires an authenticated user"} ==
199 |> get("/api/v1/accounts/#{remote.id}")
200 |> json_response_and_validate_schema(:unauthorized)
203 test "if user is authenticated", %{local: local, remote: remote} do
204 %{conn: conn} = oauth_access(["read"])
206 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
207 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
209 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
210 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
214 describe "user fetching with restrict unauthenticated profiles for local" do
215 setup do: local_and_remote_users()
217 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
219 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
220 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
222 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
223 "error" => "This API requires an authenticated user"
226 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
227 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
230 test "if user is authenticated", %{local: local, remote: remote} do
231 %{conn: conn} = oauth_access(["read"])
233 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
234 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
236 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
237 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
241 describe "user fetching with restrict unauthenticated profiles for remote" do
242 setup do: local_and_remote_users()
244 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
246 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
247 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
248 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
250 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
252 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
253 "error" => "This API requires an authenticated user"
257 test "if user is authenticated", %{local: local, remote: remote} do
258 %{conn: conn} = oauth_access(["read"])
260 res_conn = get(conn, "/api/v1/accounts/#{local.id}")
261 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
263 res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
264 assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
268 describe "user timelines" do
269 setup do: oauth_access(["read:statuses"])
271 test "works with announces that are just addressed to public", %{conn: conn} do
272 user = insert(:user, ap_id: "https://honktest/u/test", local: false)
273 other_user = insert(:user)
275 {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
279 "@context" => "https://www.w3.org/ns/activitystreams",
280 "actor" => "https://honktest/u/test",
281 "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
282 "object" => post.data["object"],
283 "published" => "2019-06-25T19:33:58Z",
284 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
287 |> ActivityPub.persist(local: false)
291 |> get("/api/v1/accounts/#{user.id}/statuses")
292 |> json_response_and_validate_schema(200)
294 assert [%{"id" => id}] = resp
295 assert id == announce.id
298 test "deactivated user", %{conn: conn} do
299 user = insert(:user, is_active: false)
301 assert %{"error" => "Can't find user"} ==
303 |> get("/api/v1/accounts/#{user.id}/statuses")
304 |> json_response_and_validate_schema(:not_found)
307 test "returns 404 when user is invisible", %{conn: conn} do
308 user = insert(:user, %{invisible: true})
310 assert %{"error" => "Can't find user"} =
312 |> get("/api/v1/accounts/#{user.id}")
313 |> json_response_and_validate_schema(404)
316 test "respects blocks", %{user: user_one, conn: conn} do
317 user_two = insert(:user)
318 user_three = insert(:user)
320 User.block(user_one, user_two)
322 {:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"})
323 {:ok, repeat} = CommonAPI.repeat(activity.id, user_three)
327 |> get("/api/v1/accounts/#{user_two.id}/statuses")
328 |> json_response_and_validate_schema(200)
330 assert [%{"id" => id}] = resp
331 assert id == activity.id
333 # Even a blocked user will deliver the full user timeline, there would be
334 # no point in looking at a blocked users timeline otherwise
337 |> get("/api/v1/accounts/#{user_two.id}/statuses")
338 |> json_response_and_validate_schema(200)
340 assert [%{"id" => id}] = resp
341 assert id == activity.id
343 # Third user's timeline includes the repeat when viewed by unauthenticated user
346 |> get("/api/v1/accounts/#{user_three.id}/statuses")
347 |> json_response_and_validate_schema(200)
349 assert [%{"id" => id}] = resp
350 assert id == repeat.id
352 # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
353 resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
355 assert [] == json_response_and_validate_schema(resp, 200)
358 test "gets users statuses", %{conn: conn} do
359 user_one = insert(:user)
360 user_two = insert(:user)
361 user_three = insert(:user)
363 {:ok, _user_three, _user_one} = User.follow(user_three, user_one)
365 {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!"})
367 {:ok, direct_activity} =
368 CommonAPI.post(user_one, %{
369 status: "Hi, @#{user_two.nickname}.",
373 {:ok, private_activity} =
374 CommonAPI.post(user_one, %{status: "private", visibility: "private"})
379 |> get("/api/v1/accounts/#{user_one.id}/statuses")
380 |> json_response_and_validate_schema(200)
382 assert [%{"id" => id}] = resp
383 assert id == to_string(activity.id)
387 |> assign(:user, user_two)
388 |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
389 |> get("/api/v1/accounts/#{user_one.id}/statuses")
390 |> json_response_and_validate_schema(200)
392 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
393 assert id_one == to_string(direct_activity.id)
394 assert id_two == to_string(activity.id)
398 |> assign(:user, user_three)
399 |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
400 |> get("/api/v1/accounts/#{user_one.id}/statuses")
401 |> json_response_and_validate_schema(200)
403 assert [%{"id" => id_one}, %{"id" => id_two}] = resp
404 assert id_one == to_string(private_activity.id)
405 assert id_two == to_string(activity.id)
408 test "unimplemented pinned statuses feature", %{conn: conn} do
409 note = insert(:note_activity)
410 user = User.get_cached_by_ap_id(note.data["actor"])
412 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?pinned=true")
414 assert json_response_and_validate_schema(conn, 200) == []
417 test "gets an users media, excludes reblogs", %{conn: conn} do
418 note = insert(:note_activity)
419 user = User.get_cached_by_ap_id(note.data["actor"])
420 other_user = insert(:user)
423 content_type: "image/jpeg",
424 path: Path.absname("test/fixtures/image.jpg"),
425 filename: "an_image.jpg"
428 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
430 {:ok, %{id: image_post_id}} = CommonAPI.post(user, %{status: "cofe", media_ids: [media_id]})
432 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: other_user.ap_id)
434 {:ok, %{id: other_image_post_id}} =
435 CommonAPI.post(other_user, %{status: "cofe2", media_ids: [media_id]})
437 {:ok, _announce} = CommonAPI.repeat(other_image_post_id, user)
439 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true")
441 assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
443 conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1")
445 assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
448 test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
449 {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"})
450 {:ok, _} = CommonAPI.repeat(post_id, user)
452 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
453 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
455 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1")
456 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
459 test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
460 {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "#hashtag"})
461 {:ok, _post} = CommonAPI.post(user, %{status: "hashtag"})
463 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag")
464 assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
467 test "the user views their own timelines and excludes direct messages", %{
471 {:ok, %{id: public_activity_id}} =
472 CommonAPI.post(user, %{status: ".", visibility: "public"})
474 {:ok, _direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
476 conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
477 assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200)
480 test "muted reactions", %{user: user, conn: conn} do
481 user2 = insert(:user)
482 User.mute(user, user2)
483 {:ok, activity} = CommonAPI.post(user, %{status: "."})
484 {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅")
488 |> get("/api/v1/accounts/#{user.id}/statuses")
489 |> json_response_and_validate_schema(200)
494 "emoji_reactions" => []
501 |> get("/api/v1/accounts/#{user.id}/statuses?with_muted=true")
502 |> json_response_and_validate_schema(200)
507 "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
513 test "paginates a user's statuses", %{user: user, conn: conn} do
514 {:ok, post_1} = CommonAPI.post(user, %{status: "first post"})
515 {:ok, post_2} = CommonAPI.post(user, %{status: "second post"})
517 response_1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1")
518 assert [res] = json_response_and_validate_schema(response_1, 200)
519 assert res["id"] == post_2.id
521 response_2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&max_id=#{res["id"]}")
522 assert [res] = json_response_and_validate_schema(response_2, 200)
523 assert res["id"] == post_1.id
525 refute response_1 == response_2
529 defp local_and_remote_activities(%{local: local, remote: remote}) do
530 insert(:note_activity, user: local)
531 insert(:note_activity, user: remote, local: false)
536 describe "statuses with restrict unauthenticated profiles for local and remote" do
537 setup do: local_and_remote_users()
538 setup :local_and_remote_activities
540 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
542 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
544 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
545 assert %{"error" => "This API requires an authenticated user"} ==
547 |> get("/api/v1/accounts/#{local.id}/statuses")
548 |> json_response_and_validate_schema(:unauthorized)
550 assert %{"error" => "This API requires an authenticated user"} ==
552 |> get("/api/v1/accounts/#{remote.id}/statuses")
553 |> json_response_and_validate_schema(:unauthorized)
556 test "if user is authenticated", %{local: local, remote: remote} do
557 %{conn: conn} = oauth_access(["read"])
559 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
560 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
562 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
563 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
567 describe "statuses with restrict unauthenticated profiles for local" do
568 setup do: local_and_remote_users()
569 setup :local_and_remote_activities
571 setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
573 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
574 assert %{"error" => "This API requires an authenticated user"} ==
576 |> get("/api/v1/accounts/#{local.id}/statuses")
577 |> json_response_and_validate_schema(:unauthorized)
579 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
580 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
583 test "if user is authenticated", %{local: local, remote: remote} do
584 %{conn: conn} = oauth_access(["read"])
586 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
587 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
589 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
590 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
594 describe "statuses with restrict unauthenticated profiles for remote" do
595 setup do: local_and_remote_users()
596 setup :local_and_remote_activities
598 setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
600 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
601 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
602 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
604 assert %{"error" => "This API requires an authenticated user"} ==
606 |> get("/api/v1/accounts/#{remote.id}/statuses")
607 |> json_response_and_validate_schema(:unauthorized)
610 test "if user is authenticated", %{local: local, remote: remote} do
611 %{conn: conn} = oauth_access(["read"])
613 res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
614 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
616 res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
617 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
621 describe "followers" do
622 setup do: oauth_access(["read:accounts"])
624 test "getting followers", %{user: user, conn: conn} do
625 other_user = insert(:user)
626 {:ok, %{id: user_id}, other_user} = User.follow(user, other_user)
628 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
630 assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
633 test "following with relationship", %{conn: conn, user: user} do
634 other_user = insert(:user)
635 {:ok, %{id: id}, _} = User.follow(other_user, user)
643 "following" => false,
644 "followed_by" => true
650 |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
651 |> json_response_and_validate_schema(200)
653 {:ok, _, _} = User.follow(user, other_user)
662 "followed_by" => true
668 |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
669 |> json_response_and_validate_schema(200)
672 test "getting followers, hide_followers", %{user: user, conn: conn} do
673 other_user = insert(:user, hide_followers: true)
674 {:ok, _user, _other_user} = User.follow(user, other_user)
676 conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
678 assert [] == json_response_and_validate_schema(conn, 200)
681 test "getting followers, hide_followers, same user requesting" do
683 other_user = insert(:user, hide_followers: true)
684 {:ok, _user, _other_user} = User.follow(user, other_user)
688 |> assign(:user, other_user)
689 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
690 |> get("/api/v1/accounts/#{other_user.id}/followers")
692 refute [] == json_response_and_validate_schema(conn, 200)
695 test "getting followers, pagination", %{user: user, conn: conn} do
696 {:ok, %User{id: follower1_id}, _user} = :user |> insert() |> User.follow(user)
697 {:ok, %User{id: follower2_id}, _user} = :user |> insert() |> User.follow(user)
698 {:ok, %User{id: follower3_id}, _user} = :user |> insert() |> User.follow(user)
700 assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] =
702 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1_id}")
703 |> json_response_and_validate_schema(200)
705 assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
707 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}")
708 |> json_response_and_validate_schema(200)
710 assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
713 "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{follower3_id}"
715 |> json_response_and_validate_schema(200)
717 res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}")
719 assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200)
721 assert [link_header] = get_resp_header(res_conn, "link")
722 assert link_header =~ ~r/min_id=#{follower2_id}/
723 assert link_header =~ ~r/max_id=#{follower2_id}/
727 describe "following" do
728 setup do: oauth_access(["read:accounts"])
730 test "getting following", %{user: user, conn: conn} do
731 other_user = insert(:user)
732 {:ok, user, other_user} = User.follow(user, other_user)
734 conn = get(conn, "/api/v1/accounts/#{user.id}/following")
736 assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
737 assert id == to_string(other_user.id)
740 test "following with relationship", %{conn: conn, user: user} do
741 other_user = insert(:user)
742 {:ok, user, other_user} = User.follow(user, other_user)
744 conn = get(conn, "/api/v1/accounts/#{user.id}/following?with_relationships=true")
752 "relationship" => %{"id" => ^id, "following" => true, "followed_by" => false}
755 ] = json_response_and_validate_schema(conn, 200)
758 test "getting following, hide_follows, other user requesting" do
759 user = insert(:user, hide_follows: true)
760 other_user = insert(:user)
761 {:ok, user, other_user} = User.follow(user, other_user)
765 |> assign(:user, other_user)
766 |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
767 |> get("/api/v1/accounts/#{user.id}/following")
769 assert [] == json_response_and_validate_schema(conn, 200)
772 test "getting following, hide_follows, same user requesting" do
773 user = insert(:user, hide_follows: true)
774 other_user = insert(:user)
775 {:ok, user, _other_user} = User.follow(user, other_user)
779 |> assign(:user, user)
780 |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
781 |> get("/api/v1/accounts/#{user.id}/following")
783 refute [] == json_response_and_validate_schema(conn, 200)
786 test "getting following, pagination", %{user: user, conn: conn} do
787 following1 = insert(:user)
788 following2 = insert(:user)
789 following3 = insert(:user)
790 {:ok, _, _} = User.follow(user, following1)
791 {:ok, _, _} = User.follow(user, following2)
792 {:ok, _, _} = User.follow(user, following3)
794 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
796 assert [%{"id" => id3}, %{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
797 assert id3 == following3.id
798 assert id2 == following2.id
800 res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
802 assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
803 assert id2 == following2.id
804 assert id1 == following1.id
809 "/api/v1/accounts/#{user.id}/following?id=#{user.id}&limit=20&max_id=#{following3.id}"
812 assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
813 assert id2 == following2.id
814 assert id1 == following1.id
817 get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
819 assert [%{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
820 assert id2 == following2.id
822 assert [link_header] = get_resp_header(res_conn, "link")
823 assert link_header =~ ~r/min_id=#{following2.id}/
824 assert link_header =~ ~r/max_id=#{following2.id}/
828 describe "follow/unfollow" do
829 setup do: oauth_access(["follow"])
831 test "following / unfollowing a user", %{conn: conn} do
832 %{id: other_user_id, nickname: other_user_nickname} = insert(:user)
834 assert %{"id" => _id, "following" => true} =
836 |> post("/api/v1/accounts/#{other_user_id}/follow")
837 |> json_response_and_validate_schema(200)
839 assert %{"id" => _id, "following" => false} =
841 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
842 |> json_response_and_validate_schema(200)
844 assert %{"id" => ^other_user_id} =
846 |> put_req_header("content-type", "application/json")
847 |> post("/api/v1/follows", %{"uri" => other_user_nickname})
848 |> json_response_and_validate_schema(200)
851 test "cancelling follow request", %{conn: conn} do
852 %{id: other_user_id} = insert(:user, %{is_locked: true})
854 assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
856 |> post("/api/v1/accounts/#{other_user_id}/follow")
857 |> json_response_and_validate_schema(:ok)
859 assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
861 |> post("/api/v1/accounts/#{other_user_id}/unfollow")
862 |> json_response_and_validate_schema(:ok)
865 test "following without reblogs" do
866 %{conn: conn} = oauth_access(["follow", "read:statuses"])
867 followed = insert(:user)
868 other_user = insert(:user)
872 |> put_req_header("content-type", "application/json")
873 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
875 assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
877 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
878 {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
882 |> get("/api/v1/timelines/home")
883 |> json_response_and_validate_schema(200)
885 assert %{"showing_reblogs" => true} =
887 |> put_req_header("content-type", "application/json")
888 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true})
889 |> json_response_and_validate_schema(200)
891 assert [%{"id" => ^reblog_id}] =
893 |> get("/api/v1/timelines/home")
894 |> json_response_and_validate_schema(200)
897 test "following with reblogs" do
898 %{conn: conn} = oauth_access(["follow", "read:statuses"])
899 followed = insert(:user)
900 other_user = insert(:user)
902 ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow")
904 assert %{"showing_reblogs" => true} = json_response_and_validate_schema(ret_conn, 200)
906 {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
907 {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
909 assert [%{"id" => ^reblog_id}] =
911 |> get("/api/v1/timelines/home")
912 |> json_response_and_validate_schema(200)
914 assert %{"showing_reblogs" => false} =
916 |> put_req_header("content-type", "application/json")
917 |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
918 |> json_response_and_validate_schema(200)
922 |> get("/api/v1/timelines/home")
923 |> json_response_and_validate_schema(200)
926 test "following with subscription and unsubscribing" do
927 %{conn: conn} = oauth_access(["follow"])
928 followed = insert(:user)
932 |> put_req_header("content-type", "application/json")
933 |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true})
935 assert %{"id" => _id, "subscribing" => true} =
936 json_response_and_validate_schema(ret_conn, 200)
940 |> put_req_header("content-type", "application/json")
941 |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false})
943 assert %{"id" => _id, "subscribing" => false} =
944 json_response_and_validate_schema(ret_conn, 200)
947 test "following / unfollowing errors", %{user: user, conn: conn} do
949 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
951 assert %{"error" => "Can not follow yourself"} =
952 json_response_and_validate_schema(conn_res, 400)
955 user = User.get_cached_by_id(user.id)
956 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
958 assert %{"error" => "Can not unfollow yourself"} =
959 json_response_and_validate_schema(conn_res, 400)
961 # self follow via uri
962 user = User.get_cached_by_id(user.id)
964 assert %{"error" => "Can not follow yourself"} =
966 |> put_req_header("content-type", "multipart/form-data")
967 |> post("/api/v1/follows", %{"uri" => user.nickname})
968 |> json_response_and_validate_schema(400)
970 # follow non existing user
971 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
972 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
974 # follow non existing user via uri
977 |> put_req_header("content-type", "multipart/form-data")
978 |> post("/api/v1/follows", %{"uri" => "doesntexist"})
980 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
982 # unfollow non existing user
983 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
984 assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
988 describe "mute/unmute" do
989 setup do: oauth_access(["write:mutes"])
991 test "with notifications", %{conn: conn} do
992 other_user = insert(:user)
994 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
996 |> post("/api/v1/accounts/#{other_user.id}/mute")
997 |> json_response_and_validate_schema(200)
999 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
1001 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
1002 json_response_and_validate_schema(conn, 200)
1005 test "without notifications", %{conn: conn} do
1006 other_user = insert(:user)
1010 |> put_req_header("content-type", "multipart/form-data")
1011 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
1013 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} =
1014 json_response_and_validate_schema(ret_conn, 200)
1016 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
1018 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
1019 json_response_and_validate_schema(conn, 200)
1023 describe "pinned statuses" do
1025 user = insert(:user)
1026 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
1027 %{conn: conn} = oauth_access(["read:statuses"], user: user)
1029 [conn: conn, user: user, activity: activity]
1032 test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do
1033 {:ok, _} = CommonAPI.pin(activity_id, user)
1035 assert [%{"id" => ^activity_id, "pinned" => true}] =
1037 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1038 |> json_response_and_validate_schema(200)
1042 test "blocking / unblocking a user" do
1043 %{conn: conn} = oauth_access(["follow"])
1044 other_user = insert(:user)
1046 ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
1048 assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200)
1050 conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
1052 assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200)
1055 describe "create account by app" do
1059 email: "lain@example.org",
1060 password: "PlzDontHackLain",
1064 [valid_params: valid_params]
1067 test "registers and logs in without :account_activation_required / :account_approval_required",
1069 clear_config([:instance, :account_activation_required], false)
1070 clear_config([:instance, :account_approval_required], false)
1074 |> put_req_header("content-type", "application/json")
1075 |> post("/api/v1/apps", %{
1076 client_name: "client_name",
1077 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1078 scopes: "read, write, follow"
1082 "client_id" => client_id,
1083 "client_secret" => client_secret,
1085 "name" => "client_name",
1086 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1089 } = json_response_and_validate_schema(conn, 200)
1092 post(conn, "/oauth/token", %{
1093 grant_type: "client_credentials",
1094 client_id: client_id,
1095 client_secret: client_secret
1098 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1099 json_response(conn, 200)
1102 token_from_db = Repo.get_by(Token, token: token)
1103 assert token_from_db
1105 assert scope == "read write follow"
1107 clear_config([User, :email_blacklist], ["example.org"])
1111 email: "lain@example.org",
1112 password: "PlzDontHackLain",
1119 |> put_req_header("content-type", "multipart/form-data")
1120 |> put_req_header("authorization", "Bearer " <> token)
1121 |> post("/api/v1/accounts", params)
1123 assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
1124 json_response_and_validate_schema(conn, 400)
1126 clear_config([User, :email_blacklist], [])
1130 |> put_req_header("content-type", "multipart/form-data")
1131 |> put_req_header("authorization", "Bearer " <> token)
1132 |> post("/api/v1/accounts", params)
1135 "access_token" => token,
1136 "created_at" => _created_at,
1138 "token_type" => "Bearer"
1139 } = json_response_and_validate_schema(conn, 200)
1141 token_from_db = Repo.get_by(Token, token: token)
1142 assert token_from_db
1143 user = Repo.preload(token_from_db, :user).user
1146 assert user.is_confirmed
1147 assert user.is_approved
1150 test "registers but does not log in with :account_activation_required", %{conn: conn} do
1151 clear_config([:instance, :account_activation_required], true)
1152 clear_config([:instance, :account_approval_required], false)
1156 |> put_req_header("content-type", "application/json")
1157 |> post("/api/v1/apps", %{
1158 client_name: "client_name",
1159 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1160 scopes: "read, write, follow"
1164 "client_id" => client_id,
1165 "client_secret" => client_secret,
1167 "name" => "client_name",
1168 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1171 } = json_response_and_validate_schema(conn, 200)
1174 post(conn, "/oauth/token", %{
1175 grant_type: "client_credentials",
1176 client_id: client_id,
1177 client_secret: client_secret
1180 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1181 json_response(conn, 200)
1184 token_from_db = Repo.get_by(Token, token: token)
1185 assert token_from_db
1187 assert scope == "read write follow"
1191 |> put_req_header("content-type", "multipart/form-data")
1192 |> put_req_header("authorization", "Bearer " <> token)
1193 |> post("/api/v1/accounts", %{
1195 email: "lain@example.org",
1196 password: "PlzDontHackLain",
1201 response = json_response_and_validate_schema(conn, 200)
1202 assert %{"identifier" => "missing_confirmed_email"} = response
1203 refute response["access_token"]
1204 refute response["token_type"]
1206 user = Repo.get_by(User, email: "lain@example.org")
1207 refute user.is_confirmed
1210 test "registers but does not log in with :account_approval_required", %{conn: conn} do
1211 clear_config([:instance, :account_approval_required], true)
1212 clear_config([:instance, :account_activation_required], false)
1216 |> put_req_header("content-type", "application/json")
1217 |> post("/api/v1/apps", %{
1218 client_name: "client_name",
1219 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1220 scopes: "read, write, follow"
1224 "client_id" => client_id,
1225 "client_secret" => client_secret,
1227 "name" => "client_name",
1228 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1231 } = json_response_and_validate_schema(conn, 200)
1234 post(conn, "/oauth/token", %{
1235 grant_type: "client_credentials",
1236 client_id: client_id,
1237 client_secret: client_secret
1240 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1241 json_response(conn, 200)
1244 token_from_db = Repo.get_by(Token, token: token)
1245 assert token_from_db
1247 assert scope == "read write follow"
1251 |> put_req_header("content-type", "multipart/form-data")
1252 |> put_req_header("authorization", "Bearer " <> token)
1253 |> post("/api/v1/accounts", %{
1255 email: "lain@example.org",
1256 password: "PlzDontHackLain",
1259 reason: "I'm a cool dude, bro"
1262 response = json_response_and_validate_schema(conn, 200)
1263 assert %{"identifier" => "awaiting_approval"} = response
1264 refute response["access_token"]
1265 refute response["token_type"]
1267 user = Repo.get_by(User, email: "lain@example.org")
1269 refute user.is_approved
1270 assert user.registration_reason == "I'm a cool dude, bro"
1273 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
1274 _user = insert(:user, email: "lain@example.org")
1275 app_token = insert(:oauth_token, user: nil)
1279 |> put_req_header("authorization", "Bearer " <> app_token.token)
1280 |> put_req_header("content-type", "application/json")
1281 |> post("/api/v1/accounts", valid_params)
1283 assert json_response_and_validate_schema(res, 400) == %{
1284 "error" => "{\"email\":[\"has already been taken\"]}"
1288 test "returns bad_request if missing required params", %{
1290 valid_params: valid_params
1292 app_token = insert(:oauth_token, user: nil)
1296 |> put_req_header("authorization", "Bearer " <> app_token.token)
1297 |> put_req_header("content-type", "application/json")
1299 res = post(conn, "/api/v1/accounts", valid_params)
1300 assert json_response_and_validate_schema(res, 200)
1302 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
1303 |> Stream.zip(Map.delete(valid_params, :email))
1304 |> Enum.each(fn {ip, {attr, _}} ->
1307 |> Map.put(:remote_ip, ip)
1308 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
1309 |> json_response_and_validate_schema(400)
1312 "error" => "Missing field: #{attr}.",
1315 "message" => "Missing field: #{attr}",
1316 "source" => %{"pointer" => "/#{attr}"},
1317 "title" => "Invalid value"
1324 test "returns bad_request if missing email params when :account_activation_required is enabled",
1325 %{conn: conn, valid_params: valid_params} do
1326 clear_config([:instance, :account_activation_required], true)
1328 app_token = insert(:oauth_token, user: nil)
1332 |> put_req_header("authorization", "Bearer " <> app_token.token)
1333 |> put_req_header("content-type", "application/json")
1337 |> Map.put(:remote_ip, {127, 0, 0, 5})
1338 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1340 assert json_response_and_validate_schema(res, 400) ==
1341 %{"error" => "Missing parameter: email"}
1345 |> Map.put(:remote_ip, {127, 0, 0, 6})
1346 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1348 assert json_response_and_validate_schema(res, 400) == %{
1349 "error" => "{\"email\":[\"can't be blank\"]}"
1353 test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
1354 app_token = insert(:oauth_token, user: nil)
1355 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1359 |> put_req_header("content-type", "application/json")
1360 |> Map.put(:remote_ip, {127, 0, 0, 7})
1361 |> post("/api/v1/accounts", Map.delete(valid_params, :email))
1363 assert json_response_and_validate_schema(res, 200)
1366 test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
1367 app_token = insert(:oauth_token, user: nil)
1368 conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1372 |> put_req_header("content-type", "application/json")
1373 |> Map.put(:remote_ip, {127, 0, 0, 8})
1374 |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
1376 assert json_response_and_validate_schema(res, 200)
1379 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
1382 |> put_req_header("authorization", "Bearer " <> "invalid-token")
1383 |> put_req_header("content-type", "multipart/form-data")
1384 |> post("/api/v1/accounts", valid_params)
1386 assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"}
1389 test "registration from trusted app" do
1390 clear_config([Pleroma.Captcha, :enabled], true)
1391 app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"])
1395 |> post("/oauth/token", %{
1396 "grant_type" => "client_credentials",
1397 "client_id" => app.client_id,
1398 "client_secret" => app.client_secret
1401 assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200)
1405 |> Plug.Conn.put_req_header("authorization", "Bearer " <> token)
1406 |> put_req_header("content-type", "multipart/form-data")
1407 |> post("/api/v1/accounts", %{
1408 nickname: "nickanme",
1410 email: "email@example.com",
1413 password: "some_password",
1414 confirm: "some_password"
1416 |> json_response_and_validate_schema(200)
1419 "access_token" => access_token,
1421 "scope" => "read write follow push",
1422 "token_type" => "Bearer"
1427 |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token)
1428 |> get("/api/v1/accounts/verify_credentials")
1429 |> json_response_and_validate_schema(200)
1434 "display_name" => "Lain",
1435 "follow_requests_count" => 0,
1436 "followers_count" => 0,
1437 "following_count" => 0,
1444 "actor_type" => "Person",
1445 "discoverable" => false,
1446 "no_rich_text" => false,
1449 "privacy" => "public",
1450 "sensitive" => false
1452 "statuses_count" => 0,
1453 "username" => "Lain"
1458 describe "create account by app / rate limit" do
1459 setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
1461 test "respects rate limit setting", %{conn: conn} do
1462 app_token = insert(:oauth_token, user: nil)
1466 |> put_req_header("authorization", "Bearer " <> app_token.token)
1467 |> Map.put(:remote_ip, {15, 15, 15, 15})
1468 |> put_req_header("content-type", "multipart/form-data")
1473 |> post("/api/v1/accounts", %{
1474 username: "#{i}lain",
1475 email: "#{i}lain@example.org",
1476 password: "PlzDontHackLain",
1481 "access_token" => token,
1482 "created_at" => _created_at,
1484 "token_type" => "Bearer"
1485 } = json_response_and_validate_schema(conn, 200)
1487 token_from_db = Repo.get_by(Token, token: token)
1488 assert token_from_db
1489 token_from_db = Repo.preload(token_from_db, :user)
1490 assert token_from_db.user
1494 post(conn, "/api/v1/accounts", %{
1496 email: "6lain@example.org",
1497 password: "PlzDontHackLain",
1501 assert json_response_and_validate_schema(conn, :too_many_requests) == %{
1502 "error" => "Throttled"
1507 describe "create account with enabled captcha" do
1508 setup %{conn: conn} do
1509 app_token = insert(:oauth_token, user: nil)
1513 |> put_req_header("authorization", "Bearer " <> app_token.token)
1514 |> put_req_header("content-type", "multipart/form-data")
1519 setup do: clear_config([Pleroma.Captcha, :enabled], true)
1521 test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
1522 %{token: token, answer_data: answer_data} = Pleroma.Captcha.new()
1526 email: "lain@example.org",
1527 password: "PlzDontHackLain",
1529 captcha_solution: Pleroma.Captcha.Mock.solution(),
1530 captcha_token: token,
1531 captcha_answer_data: answer_data
1535 "access_token" => access_token,
1538 "token_type" => "Bearer"
1541 |> post("/api/v1/accounts", params)
1542 |> json_response_and_validate_schema(:ok)
1544 assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
1547 test "returns 400 if any captcha field is not provided", %{conn: conn} do
1548 captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data]
1552 email: "lain@example.org",
1553 password: "PlzDontHackLain",
1555 captcha_solution: "xx",
1556 captcha_token: "xx",
1557 captcha_answer_data: "xx"
1560 for field <- captcha_fields do
1562 "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}"
1567 |> post("/api/v1/accounts", Map.delete(valid_params, field))
1568 |> json_response_and_validate_schema(:bad_request)
1572 test "returns an error if captcha is invalid", %{conn: conn} do
1575 email: "lain@example.org",
1576 password: "PlzDontHackLain",
1578 captcha_solution: "cofe",
1579 captcha_token: "cofe",
1580 captcha_answer_data: "cofe"
1583 assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} ==
1585 |> post("/api/v1/accounts", params)
1586 |> json_response_and_validate_schema(:bad_request)
1590 describe "create account with language" do
1591 setup %{conn: conn} do
1592 app_token = insert(:oauth_token, user: nil)
1596 |> put_req_header("authorization", "Bearer " <> app_token.token)
1597 |> put_req_header("content-type", "multipart/form-data")
1598 |> put_req_cookie(SetLocalePlug.frontend_language_cookie_name(), "zh-Hans")
1599 |> SetLocalePlug.call([])
1604 test "creates an account with language parameter", %{conn: conn} do
1607 email: "foo@example.org",
1615 |> post("/api/v1/accounts", params)
1617 assert json_response_and_validate_schema(res, 200)
1619 assert %{language: "ru"} = Pleroma.User.get_by_nickname("foo")
1622 test "language parameter should be normalized", %{conn: conn} do
1625 email: "foo@example.org",
1633 |> post("/api/v1/accounts", params)
1635 assert json_response_and_validate_schema(res, 200)
1637 assert %{language: "ru_RU"} = Pleroma.User.get_by_nickname("foo")
1640 test "createing an account without language parameter should fallback to cookie/header language",
1644 email: "foo2@example.org",
1651 |> post("/api/v1/accounts", params)
1653 assert json_response_and_validate_schema(res, 200)
1655 assert %{language: "zh_Hans"} = Pleroma.User.get_by_nickname("foo2")
1659 describe "GET /api/v1/accounts/:id/lists - account_lists" do
1660 test "returns lists to which the account belongs" do
1661 %{user: user, conn: conn} = oauth_access(["read:lists"])
1662 other_user = insert(:user)
1663 assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
1664 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
1666 assert [%{"id" => _list_id, "title" => "Test List"}] =
1668 |> get("/api/v1/accounts/#{other_user.id}/lists")
1669 |> json_response_and_validate_schema(200)
1673 describe "verify_credentials" do
1674 test "verify_credentials" do
1675 %{user: user, conn: conn} = oauth_access(["read:accounts"])
1677 [notification | _] =
1678 insert_list(7, :notification, user: user, activity: insert(:note_activity))
1680 Pleroma.Notification.set_read_up_to(user, notification.id)
1681 conn = get(conn, "/api/v1/accounts/verify_credentials")
1683 response = json_response_and_validate_schema(conn, 200)
1685 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
1686 assert response["pleroma"]["unread_notifications_count"] == 6
1687 assert id == to_string(user.id)
1690 test "verify_credentials default scope unlisted" do
1691 user = insert(:user, default_scope: "unlisted")
1692 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1694 conn = get(conn, "/api/v1/accounts/verify_credentials")
1696 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} =
1697 json_response_and_validate_schema(conn, 200)
1699 assert id == to_string(user.id)
1702 test "locked accounts" do
1703 user = insert(:user, default_scope: "private")
1704 %{conn: conn} = oauth_access(["read:accounts"], user: user)
1706 conn = get(conn, "/api/v1/accounts/verify_credentials")
1708 assert %{"id" => id, "source" => %{"privacy" => "private"}} =
1709 json_response_and_validate_schema(conn, 200)
1711 assert id == to_string(user.id)
1715 describe "user relationships" do
1716 setup do: oauth_access(["read:follows"])
1718 test "returns the relationships for the current user", %{user: user, conn: conn} do
1719 %{id: other_user_id} = other_user = insert(:user)
1720 {:ok, _user, _other_user} = User.follow(user, other_user)
1722 assert [%{"id" => ^other_user_id}] =
1724 |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1725 |> json_response_and_validate_schema(200)
1727 assert [%{"id" => ^other_user_id}] =
1729 |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
1730 |> json_response_and_validate_schema(200)
1733 test "returns an empty list on a bad request", %{conn: conn} do
1734 conn = get(conn, "/api/v1/accounts/relationships", %{})
1736 assert [] = json_response_and_validate_schema(conn, 200)
1740 test "getting a list of mutes" do
1741 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1742 %{id: id1} = other_user1 = insert(:user)
1743 %{id: id2} = other_user2 = insert(:user)
1744 %{id: id3} = other_user3 = insert(:user)
1746 {:ok, _user_relationships} = User.mute(user, other_user1)
1747 {:ok, _user_relationships} = User.mute(user, other_user2)
1748 {:ok, _user_relationships} = User.mute(user, other_user3)
1752 |> get("/api/v1/mutes")
1753 |> json_response_and_validate_schema(200)
1755 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1759 |> get("/api/v1/mutes?limit=1")
1760 |> json_response_and_validate_schema(200)
1762 assert [%{"id" => ^id1}] = result
1766 |> get("/api/v1/mutes?since_id=#{id1}")
1767 |> json_response_and_validate_schema(200)
1769 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1773 |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
1774 |> json_response_and_validate_schema(200)
1776 assert [%{"id" => ^id2}] = result
1780 |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
1781 |> json_response_and_validate_schema(200)
1783 assert [%{"id" => ^id2}] = result
1786 test "list of mutes with with_relationships parameter" do
1787 %{user: user, conn: conn} = oauth_access(["read:mutes"])
1788 %{id: id1} = other_user1 = insert(:user)
1789 %{id: id2} = other_user2 = insert(:user)
1790 %{id: id3} = other_user3 = insert(:user)
1792 {:ok, _, _} = User.follow(other_user1, user)
1793 {:ok, _, _} = User.follow(other_user2, user)
1794 {:ok, _, _} = User.follow(other_user3, user)
1796 {:ok, _} = User.mute(user, other_user1)
1797 {:ok, _} = User.mute(user, other_user2)
1798 {:ok, _} = User.mute(user, other_user3)
1803 "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1807 "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1811 "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
1815 |> get("/api/v1/mutes?with_relationships=true")
1816 |> json_response_and_validate_schema(200)
1819 test "getting a list of blocks" do
1820 %{user: user, conn: conn} = oauth_access(["read:blocks"])
1821 %{id: id1} = other_user1 = insert(:user)
1822 %{id: id2} = other_user2 = insert(:user)
1823 %{id: id3} = other_user3 = insert(:user)
1825 {:ok, _user_relationship} = User.block(user, other_user1)
1826 {:ok, _user_relationship} = User.block(user, other_user3)
1827 {:ok, _user_relationship} = User.block(user, other_user2)
1831 |> assign(:user, user)
1832 |> get("/api/v1/blocks")
1833 |> json_response_and_validate_schema(200)
1835 assert [id1, id2, id3] == Enum.map(result, & &1["id"])
1839 |> assign(:user, user)
1840 |> get("/api/v1/blocks?limit=1")
1841 |> json_response_and_validate_schema(200)
1843 assert [%{"id" => ^id1}] = result
1847 |> assign(:user, user)
1848 |> get("/api/v1/blocks?since_id=#{id1}")
1849 |> json_response_and_validate_schema(200)
1851 assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
1855 |> assign(:user, user)
1856 |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}")
1857 |> json_response_and_validate_schema(200)
1859 assert [%{"id" => ^id2}] = result
1863 |> assign(:user, user)
1864 |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
1865 |> json_response_and_validate_schema(200)
1867 assert [%{"id" => ^id2}] = result
1870 test "account lookup", %{conn: conn} do
1871 %{nickname: acct} = insert(:user, %{nickname: "nickname"})
1872 %{nickname: acct_two} = insert(:user, %{nickname: "nickname@notlocaldoma.in"})
1876 |> get("/api/v1/accounts/lookup?acct=#{acct}")
1877 |> json_response_and_validate_schema(200)
1879 assert %{"acct" => ^acct} = result
1883 |> get("/api/v1/accounts/lookup?acct=#{acct_two}")
1884 |> json_response_and_validate_schema(200)
1886 assert %{"acct" => ^acct_two} = result
1890 |> get("/api/v1/accounts/lookup?acct=unexisting_nickname")
1891 |> json_response_and_validate_schema(404)
1894 test "create a note on a user" do
1895 %{conn: conn} = oauth_access(["write:accounts", "read:follows"])
1896 other_user = insert(:user)
1899 |> put_req_header("content-type", "application/json")
1900 |> post("/api/v1/accounts/#{other_user.id}/note", %{
1901 "comment" => "Example note"
1904 assert [%{"note" => "Example note"}] =
1906 |> put_req_header("content-type", "application/json")
1907 |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
1908 |> json_response_and_validate_schema(200)