1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
10 alias Pleroma.Notification
13 alias Pleroma.Tests.ObanHelpers
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Web.OAuth.App
18 alias Pleroma.Web.OAuth.Token
19 alias Pleroma.Web.Push
21 import ExUnit.CaptureLog
22 import Pleroma.Factory
23 import Swoosh.TestAssertions
26 @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
29 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
33 clear_config([:instance, :public])
34 clear_config([:rich_media, :enabled])
36 test "Conversations", %{conn: conn} do
37 user_one = insert(:user)
38 user_two = insert(:user)
39 user_three = insert(:user)
41 {:ok, user_two} = User.follow(user_two, user_one)
44 CommonAPI.post(user_one, %{
45 "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
46 "visibility" => "direct"
49 {:ok, _follower_only} =
50 CommonAPI.post(user_one, %{
51 "status" => "Hi @#{user_two.nickname}!",
52 "visibility" => "private"
57 |> assign(:user, user_one)
58 |> get("/api/v1/conversations")
60 assert response = json_response(res_conn, 200)
65 "accounts" => res_accounts,
66 "last_status" => res_last_status,
71 account_ids = Enum.map(res_accounts, & &1["id"])
72 assert length(res_accounts) == 2
73 assert user_two.id in account_ids
74 assert user_three.id in account_ids
75 assert is_binary(res_id)
77 assert res_last_status["id"] == direct.id
79 # Apparently undocumented API endpoint
82 |> assign(:user, user_one)
83 |> post("/api/v1/conversations/#{res_id}/read")
85 assert response = json_response(res_conn, 200)
86 assert length(response["accounts"]) == 2
87 assert response["last_status"]["id"] == direct.id
88 assert response["unread"] == false
90 # (vanilla) Mastodon frontend behaviour
93 |> assign(:user, user_one)
94 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
96 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
99 test "verify_credentials", %{conn: conn} do
104 |> assign(:user, user)
105 |> get("/api/v1/accounts/verify_credentials")
107 response = json_response(conn, 200)
109 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
110 assert response["pleroma"]["chat_token"]
111 assert id == to_string(user.id)
114 test "verify_credentials default scope unlisted", %{conn: conn} do
115 user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
119 |> assign(:user, user)
120 |> get("/api/v1/accounts/verify_credentials")
122 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
123 assert id == to_string(user.id)
126 test "apps/verify_credentials", %{conn: conn} do
127 token = insert(:oauth_token)
131 |> assign(:user, token.user)
132 |> assign(:token, token)
133 |> get("/api/v1/apps/verify_credentials")
135 app = Repo.preload(token, :app).app
138 "name" => app.client_name,
139 "website" => app.website,
140 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
143 assert expected == json_response(conn, 200)
146 test "user avatar can be set", %{conn: conn} do
148 avatar_image = File.read!("test/fixtures/avatar_data_uri")
152 |> assign(:user, user)
153 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
155 user = refresh_record(user)
169 assert %{"url" => _} = json_response(conn, 200)
172 test "user avatar can be reset", %{conn: conn} do
177 |> assign(:user, user)
178 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
180 user = User.get_cached_by_id(user.id)
182 assert user.avatar == nil
184 assert %{"url" => nil} = json_response(conn, 200)
187 test "can set profile banner", %{conn: conn} do
192 |> assign(:user, user)
193 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
195 user = refresh_record(user)
196 assert user.info.banner["type"] == "Image"
198 assert %{"url" => _} = json_response(conn, 200)
201 test "can reset profile banner", %{conn: conn} do
206 |> assign(:user, user)
207 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
209 user = refresh_record(user)
210 assert user.info.banner == %{}
212 assert %{"url" => nil} = json_response(conn, 200)
215 test "background image can be set", %{conn: conn} do
220 |> assign(:user, user)
221 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
223 user = refresh_record(user)
224 assert user.info.background["type"] == "Image"
225 assert %{"url" => _} = json_response(conn, 200)
228 test "background image can be reset", %{conn: conn} do
233 |> assign(:user, user)
234 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
236 user = refresh_record(user)
237 assert user.info.background == %{}
238 assert %{"url" => nil} = json_response(conn, 200)
241 test "creates an oauth app", %{conn: conn} do
243 app_attrs = build(:oauth_app)
247 |> assign(:user, user)
248 |> post("/api/v1/apps", %{
249 client_name: app_attrs.client_name,
250 redirect_uris: app_attrs.redirect_uris
253 [app] = Repo.all(App)
256 "name" => app.client_name,
257 "website" => app.website,
258 "client_id" => app.client_id,
259 "client_secret" => app.client_secret,
260 "id" => app.id |> to_string(),
261 "redirect_uri" => app.redirect_uris,
262 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
265 assert expected == json_response(conn, 200)
268 describe "user timelines" do
269 test "gets a users statuses", %{conn: conn} do
270 user_one = insert(:user)
271 user_two = insert(:user)
272 user_three = insert(:user)
274 {:ok, user_three} = User.follow(user_three, user_one)
276 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
278 {:ok, direct_activity} =
279 CommonAPI.post(user_one, %{
280 "status" => "Hi, @#{user_two.nickname}.",
281 "visibility" => "direct"
284 {:ok, private_activity} =
285 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
289 |> get("/api/v1/accounts/#{user_one.id}/statuses")
291 assert [%{"id" => id}] = json_response(resp, 200)
292 assert id == to_string(activity.id)
296 |> assign(:user, user_two)
297 |> get("/api/v1/accounts/#{user_one.id}/statuses")
299 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
300 assert id_one == to_string(direct_activity.id)
301 assert id_two == to_string(activity.id)
305 |> assign(:user, user_three)
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(private_activity.id)
310 assert id_two == to_string(activity.id)
313 test "unimplemented pinned statuses feature", %{conn: conn} do
314 note = insert(:note_activity)
315 user = User.get_cached_by_ap_id(note.data["actor"])
319 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
321 assert json_response(conn, 200) == []
324 test "gets an users media", %{conn: conn} do
325 note = insert(:note_activity)
326 user = User.get_cached_by_ap_id(note.data["actor"])
329 content_type: "image/jpg",
330 path: Path.absname("test/fixtures/image.jpg"),
331 filename: "an_image.jpg"
334 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
336 {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
340 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
342 assert [%{"id" => id}] = json_response(conn, 200)
343 assert id == to_string(image_post.id)
347 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
349 assert [%{"id" => id}] = json_response(conn, 200)
350 assert id == to_string(image_post.id)
353 test "gets a user's statuses without reblogs", %{conn: conn} do
355 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
356 {:ok, _, _} = CommonAPI.repeat(post.id, user)
360 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
362 assert [%{"id" => id}] = json_response(conn, 200)
363 assert id == to_string(post.id)
367 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
369 assert [%{"id" => id}] = json_response(conn, 200)
370 assert id == to_string(post.id)
373 test "filters user's statuses by a hashtag", %{conn: conn} do
375 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
376 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
380 |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
382 assert [%{"id" => id}] = json_response(conn, 200)
383 assert id == to_string(post.id)
387 describe "user relationships" do
388 test "returns the relationships for the current user", %{conn: conn} do
390 other_user = insert(:user)
391 {:ok, user} = User.follow(user, other_user)
395 |> assign(:user, user)
396 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
398 assert [relationship] = json_response(conn, 200)
400 assert to_string(other_user.id) == relationship["id"]
403 test "returns an empty list on a bad request", %{conn: conn} do
408 |> assign(:user, user)
409 |> get("/api/v1/accounts/relationships", %{})
411 assert [] = json_response(conn, 200)
415 describe "media upload" do
421 |> assign(:user, user)
423 image = %Plug.Upload{
424 content_type: "image/jpg",
425 path: Path.absname("test/fixtures/image.jpg"),
426 filename: "an_image.jpg"
429 [conn: conn, image: image]
432 clear_config([:media_proxy])
433 clear_config([Pleroma.Upload])
435 test "returns uploaded image", %{conn: conn, image: image} do
436 desc = "Description of the image"
440 |> post("/api/v1/media", %{"file" => image, "description" => desc})
441 |> json_response(:ok)
443 assert media["type"] == "image"
444 assert media["description"] == desc
447 object = Repo.get(Object, media["id"])
448 assert object.data["actor"] == User.ap_id(conn.assigns[:user])
452 describe "locked accounts" do
453 test "verify_credentials", %{conn: conn} do
454 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
458 |> assign(:user, user)
459 |> get("/api/v1/accounts/verify_credentials")
461 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
462 assert id == to_string(user.id)
466 describe "account fetching" do
467 test "works by id" do
472 |> get("/api/v1/accounts/#{user.id}")
474 assert %{"id" => id} = json_response(conn, 200)
475 assert id == to_string(user.id)
479 |> get("/api/v1/accounts/-1")
481 assert %{"error" => "Can't find user"} = json_response(conn, 404)
484 test "works by nickname" do
489 |> get("/api/v1/accounts/#{user.nickname}")
491 assert %{"id" => id} = json_response(conn, 200)
495 test "works by nickname for remote users" do
496 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
497 Pleroma.Config.put([:instance, :limit_to_local_content], false)
498 user = insert(:user, nickname: "user@example.com", local: false)
502 |> get("/api/v1/accounts/#{user.nickname}")
504 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
505 assert %{"id" => id} = json_response(conn, 200)
509 test "respects limit_to_local_content == :all for remote user nicknames" do
510 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
511 Pleroma.Config.put([:instance, :limit_to_local_content], :all)
513 user = insert(:user, nickname: "user@example.com", local: false)
517 |> get("/api/v1/accounts/#{user.nickname}")
519 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
520 assert json_response(conn, 404)
523 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
524 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
525 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
527 user = insert(:user, nickname: "user@example.com", local: false)
528 reading_user = insert(:user)
532 |> get("/api/v1/accounts/#{user.nickname}")
534 assert json_response(conn, 404)
538 |> assign(:user, reading_user)
539 |> get("/api/v1/accounts/#{user.nickname}")
541 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
542 assert %{"id" => id} = json_response(conn, 200)
547 describe "/api/v1/pleroma/mascot" do
548 test "mascot upload", %{conn: conn} do
551 non_image_file = %Plug.Upload{
552 content_type: "audio/mpeg",
553 path: Path.absname("test/fixtures/sound.mp3"),
554 filename: "sound.mp3"
559 |> assign(:user, user)
560 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
562 assert json_response(conn, 415)
565 content_type: "image/jpg",
566 path: Path.absname("test/fixtures/image.jpg"),
567 filename: "an_image.jpg"
572 |> assign(:user, user)
573 |> put("/api/v1/pleroma/mascot", %{"file" => file})
575 assert %{"id" => _, "type" => image} = json_response(conn, 200)
578 test "mascot retrieving", %{conn: conn} do
580 # When user hasn't set a mascot, we should just get pleroma tan back
583 |> assign(:user, user)
584 |> get("/api/v1/pleroma/mascot")
586 assert %{"url" => url} = json_response(conn, 200)
587 assert url =~ "pleroma-fox-tan-smol"
589 # When a user sets their mascot, we should get that back
591 content_type: "image/jpg",
592 path: Path.absname("test/fixtures/image.jpg"),
593 filename: "an_image.jpg"
598 |> assign(:user, user)
599 |> put("/api/v1/pleroma/mascot", %{"file" => file})
601 assert json_response(conn, 200)
603 user = User.get_cached_by_id(user.id)
607 |> assign(:user, user)
608 |> get("/api/v1/pleroma/mascot")
610 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
611 assert url =~ "an_image"
615 test "getting followers", %{conn: conn} do
617 other_user = insert(:user)
618 {:ok, user} = User.follow(user, other_user)
622 |> get("/api/v1/accounts/#{other_user.id}/followers")
624 assert [%{"id" => id}] = json_response(conn, 200)
625 assert id == to_string(user.id)
628 test "getting followers, hide_followers", %{conn: conn} do
630 other_user = insert(:user, %{info: %{hide_followers: true}})
631 {:ok, _user} = User.follow(user, other_user)
635 |> get("/api/v1/accounts/#{other_user.id}/followers")
637 assert [] == json_response(conn, 200)
640 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
642 other_user = insert(:user, %{info: %{hide_followers: true}})
643 {:ok, _user} = User.follow(user, other_user)
647 |> assign(:user, other_user)
648 |> get("/api/v1/accounts/#{other_user.id}/followers")
650 refute [] == json_response(conn, 200)
653 test "getting followers, pagination", %{conn: conn} do
655 follower1 = insert(:user)
656 follower2 = insert(:user)
657 follower3 = insert(:user)
658 {:ok, _} = User.follow(follower1, user)
659 {:ok, _} = User.follow(follower2, user)
660 {:ok, _} = User.follow(follower3, user)
664 |> assign(:user, user)
668 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
670 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
671 assert id3 == follower3.id
672 assert id2 == follower2.id
676 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
678 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
679 assert id2 == follower2.id
680 assert id1 == follower1.id
684 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
686 assert [%{"id" => id2}] = json_response(res_conn, 200)
687 assert id2 == follower2.id
689 assert [link_header] = get_resp_header(res_conn, "link")
690 assert link_header =~ ~r/min_id=#{follower2.id}/
691 assert link_header =~ ~r/max_id=#{follower2.id}/
694 test "getting following", %{conn: conn} do
696 other_user = insert(:user)
697 {:ok, user} = User.follow(user, other_user)
701 |> get("/api/v1/accounts/#{user.id}/following")
703 assert [%{"id" => id}] = json_response(conn, 200)
704 assert id == to_string(other_user.id)
707 test "getting following, hide_follows", %{conn: conn} do
708 user = insert(:user, %{info: %{hide_follows: true}})
709 other_user = insert(:user)
710 {:ok, user} = User.follow(user, other_user)
714 |> get("/api/v1/accounts/#{user.id}/following")
716 assert [] == json_response(conn, 200)
719 test "getting following, hide_follows, same user requesting", %{conn: conn} do
720 user = insert(:user, %{info: %{hide_follows: true}})
721 other_user = insert(:user)
722 {:ok, user} = User.follow(user, other_user)
726 |> assign(:user, user)
727 |> get("/api/v1/accounts/#{user.id}/following")
729 refute [] == json_response(conn, 200)
732 test "getting following, pagination", %{conn: conn} do
734 following1 = insert(:user)
735 following2 = insert(:user)
736 following3 = insert(:user)
737 {:ok, _} = User.follow(user, following1)
738 {:ok, _} = User.follow(user, following2)
739 {:ok, _} = User.follow(user, following3)
743 |> assign(:user, user)
747 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
749 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
750 assert id3 == following3.id
751 assert id2 == following2.id
755 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
757 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
758 assert id2 == following2.id
759 assert id1 == following1.id
763 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
765 assert [%{"id" => id2}] = json_response(res_conn, 200)
766 assert id2 == following2.id
768 assert [link_header] = get_resp_header(res_conn, "link")
769 assert link_header =~ ~r/min_id=#{following2.id}/
770 assert link_header =~ ~r/max_id=#{following2.id}/
773 test "following / unfollowing a user", %{conn: conn} do
775 other_user = insert(:user)
779 |> assign(:user, user)
780 |> post("/api/v1/accounts/#{other_user.id}/follow")
782 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
784 user = User.get_cached_by_id(user.id)
788 |> assign(:user, user)
789 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
791 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
793 user = User.get_cached_by_id(user.id)
797 |> assign(:user, user)
798 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
800 assert %{"id" => id} = json_response(conn, 200)
801 assert id == to_string(other_user.id)
804 test "following without reblogs" do
805 follower = insert(:user)
806 followed = insert(:user)
807 other_user = insert(:user)
811 |> assign(:user, follower)
812 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
814 assert %{"showing_reblogs" => false} = json_response(conn, 200)
816 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
817 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
821 |> assign(:user, User.get_cached_by_id(follower.id))
822 |> get("/api/v1/timelines/home")
824 assert [] == json_response(conn, 200)
828 |> assign(:user, follower)
829 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
831 assert %{"showing_reblogs" => true} = json_response(conn, 200)
835 |> assign(:user, User.get_cached_by_id(follower.id))
836 |> get("/api/v1/timelines/home")
838 expected_activity_id = reblog.id
839 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
842 test "following / unfollowing errors" do
847 |> assign(:user, user)
850 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
851 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
854 user = User.get_cached_by_id(user.id)
855 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
856 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
858 # self follow via uri
859 user = User.get_cached_by_id(user.id)
860 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
861 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
863 # follow non existing user
864 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
865 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
867 # follow non existing user via uri
868 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
869 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
871 # unfollow non existing user
872 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
873 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
876 describe "mute/unmute" do
877 test "with notifications", %{conn: conn} do
879 other_user = insert(:user)
883 |> assign(:user, user)
884 |> post("/api/v1/accounts/#{other_user.id}/mute")
886 response = json_response(conn, 200)
888 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
889 user = User.get_cached_by_id(user.id)
893 |> assign(:user, user)
894 |> post("/api/v1/accounts/#{other_user.id}/unmute")
896 response = json_response(conn, 200)
897 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
900 test "without notifications", %{conn: conn} do
902 other_user = insert(:user)
906 |> assign(:user, user)
907 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
909 response = json_response(conn, 200)
911 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
912 user = User.get_cached_by_id(user.id)
916 |> assign(:user, user)
917 |> post("/api/v1/accounts/#{other_user.id}/unmute")
919 response = json_response(conn, 200)
920 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
924 describe "subscribing / unsubscribing" do
925 test "subscribing / unsubscribing to a user", %{conn: conn} do
927 subscription_target = insert(:user)
931 |> assign(:user, user)
932 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
934 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
938 |> assign(:user, user)
939 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
941 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
945 describe "subscribing" do
946 test "returns 404 when subscription_target not found", %{conn: conn} do
951 |> assign(:user, user)
952 |> post("/api/v1/pleroma/accounts/target_id/subscribe")
954 assert %{"error" => "Record not found"} = json_response(conn, 404)
958 describe "unsubscribing" do
959 test "returns 404 when subscription_target not found", %{conn: conn} do
964 |> assign(:user, user)
965 |> post("/api/v1/pleroma/accounts/target_id/unsubscribe")
967 assert %{"error" => "Record not found"} = json_response(conn, 404)
971 test "getting a list of mutes", %{conn: conn} do
973 other_user = insert(:user)
975 {:ok, user} = User.mute(user, other_user)
979 |> assign(:user, user)
980 |> get("/api/v1/mutes")
982 other_user_id = to_string(other_user.id)
983 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
986 test "blocking / unblocking a user", %{conn: conn} do
988 other_user = insert(:user)
992 |> assign(:user, user)
993 |> post("/api/v1/accounts/#{other_user.id}/block")
995 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
997 user = User.get_cached_by_id(user.id)
1001 |> assign(:user, user)
1002 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1004 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1007 test "getting a list of blocks", %{conn: conn} do
1008 user = insert(:user)
1009 other_user = insert(:user)
1011 {:ok, user} = User.block(user, other_user)
1015 |> assign(:user, user)
1016 |> get("/api/v1/blocks")
1018 other_user_id = to_string(other_user.id)
1019 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1022 test "unimplemented follow_requests, blocks, domain blocks" do
1023 user = insert(:user)
1025 ["blocks", "domain_blocks", "follow_requests"]
1026 |> Enum.each(fn endpoint ->
1029 |> assign(:user, user)
1030 |> get("/api/v1/#{endpoint}")
1032 assert [] = json_response(conn, 200)
1036 test "returns the favorites of a user", %{conn: conn} do
1037 user = insert(:user)
1038 other_user = insert(:user)
1040 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1041 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1043 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1047 |> assign(:user, user)
1048 |> get("/api/v1/favourites")
1050 assert [status] = json_response(first_conn, 200)
1051 assert status["id"] == to_string(activity.id)
1053 assert [{"link", _link_header}] =
1054 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1056 # Honours query params
1057 {:ok, second_activity} =
1058 CommonAPI.post(other_user, %{
1060 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1063 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1065 last_like = status["id"]
1069 |> assign(:user, user)
1070 |> get("/api/v1/favourites?since_id=#{last_like}")
1072 assert [second_status] = json_response(second_conn, 200)
1073 assert second_status["id"] == to_string(second_activity.id)
1077 |> assign(:user, user)
1078 |> get("/api/v1/favourites?limit=0")
1080 assert [] = json_response(third_conn, 200)
1083 describe "getting favorites timeline of specified user" do
1085 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
1086 [current_user: current_user, user: user]
1089 test "returns list of statuses favorited by specified user", %{
1091 current_user: current_user,
1094 [activity | _] = insert_pair(:note_activity)
1095 CommonAPI.favorite(activity.id, user)
1099 |> assign(:user, current_user)
1100 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1101 |> json_response(:ok)
1105 assert length(response) == 1
1106 assert like["id"] == activity.id
1109 test "returns favorites for specified user_id when user is not logged in", %{
1113 activity = insert(:note_activity)
1114 CommonAPI.favorite(activity.id, user)
1118 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1119 |> json_response(:ok)
1121 assert length(response) == 1
1124 test "returns favorited DM only when user is logged in and he is one of recipients", %{
1126 current_user: current_user,
1130 CommonAPI.post(current_user, %{
1131 "status" => "Hi @#{user.nickname}!",
1132 "visibility" => "direct"
1135 CommonAPI.favorite(direct.id, user)
1139 |> assign(:user, current_user)
1140 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1141 |> json_response(:ok)
1143 assert length(response) == 1
1145 anonymous_response =
1147 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1148 |> json_response(:ok)
1150 assert Enum.empty?(anonymous_response)
1153 test "does not return others' favorited DM when user is not one of recipients", %{
1155 current_user: current_user,
1158 user_two = insert(:user)
1161 CommonAPI.post(user_two, %{
1162 "status" => "Hi @#{user.nickname}!",
1163 "visibility" => "direct"
1166 CommonAPI.favorite(direct.id, user)
1170 |> assign(:user, current_user)
1171 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1172 |> json_response(:ok)
1174 assert Enum.empty?(response)
1177 test "paginates favorites using since_id and max_id", %{
1179 current_user: current_user,
1182 activities = insert_list(10, :note_activity)
1184 Enum.each(activities, fn activity ->
1185 CommonAPI.favorite(activity.id, user)
1188 third_activity = Enum.at(activities, 2)
1189 seventh_activity = Enum.at(activities, 6)
1193 |> assign(:user, current_user)
1194 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
1195 since_id: third_activity.id,
1196 max_id: seventh_activity.id
1198 |> json_response(:ok)
1200 assert length(response) == 3
1201 refute third_activity in response
1202 refute seventh_activity in response
1205 test "limits favorites using limit parameter", %{
1207 current_user: current_user,
1211 |> insert_list(:note_activity)
1212 |> Enum.each(fn activity ->
1213 CommonAPI.favorite(activity.id, user)
1218 |> assign(:user, current_user)
1219 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
1220 |> json_response(:ok)
1222 assert length(response) == 3
1225 test "returns empty response when user does not have any favorited statuses", %{
1227 current_user: current_user,
1232 |> assign(:user, current_user)
1233 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1234 |> json_response(:ok)
1236 assert Enum.empty?(response)
1239 test "returns 404 error when specified user is not exist", %{conn: conn} do
1240 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
1242 assert json_response(conn, 404) == %{"error" => "Record not found"}
1245 test "returns 403 error when user has hidden own favorites", %{
1247 current_user: current_user
1249 user = insert(:user, %{info: %{hide_favorites: true}})
1250 activity = insert(:note_activity)
1251 CommonAPI.favorite(activity.id, user)
1255 |> assign(:user, current_user)
1256 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1258 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1261 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
1262 user = insert(:user)
1263 activity = insert(:note_activity)
1264 CommonAPI.favorite(activity.id, user)
1268 |> assign(:user, current_user)
1269 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1271 assert user.info.hide_favorites
1272 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1276 test "get instance information", %{conn: conn} do
1277 conn = get(conn, "/api/v1/instance")
1278 assert result = json_response(conn, 200)
1280 email = Config.get([:instance, :email])
1281 # Note: not checking for "max_toot_chars" since it's optional
1287 "email" => from_config_email,
1289 "streaming_api" => _
1294 "registrations" => _,
1298 assert email == from_config_email
1301 test "get instance stats", %{conn: conn} do
1302 user = insert(:user, %{local: true})
1304 user2 = insert(:user, %{local: true})
1305 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1307 insert(:user, %{local: false, nickname: "u@peer1.com"})
1308 insert(:user, %{local: false, nickname: "u@peer2.com"})
1310 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
1312 # Stats should count users with missing or nil `info.deactivated` value
1316 |> User.get_cached_by_id()
1317 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
1319 Pleroma.Stats.force_update()
1321 conn = get(conn, "/api/v1/instance")
1323 assert result = json_response(conn, 200)
1325 stats = result["stats"]
1328 assert stats["user_count"] == 1
1329 assert stats["status_count"] == 1
1330 assert stats["domain_count"] == 2
1333 test "get peers", %{conn: conn} do
1334 insert(:user, %{local: false, nickname: "u@peer1.com"})
1335 insert(:user, %{local: false, nickname: "u@peer2.com"})
1337 Pleroma.Stats.force_update()
1339 conn = get(conn, "/api/v1/instance/peers")
1341 assert result = json_response(conn, 200)
1343 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1346 test "put settings", %{conn: conn} do
1347 user = insert(:user)
1351 |> assign(:user, user)
1352 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1354 assert _result = json_response(conn, 200)
1356 user = User.get_cached_by_ap_id(user.ap_id)
1357 assert user.info.settings == %{"programming" => "socks"}
1360 describe "pinned statuses" do
1362 user = insert(:user)
1363 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
1365 [user: user, activity: activity]
1368 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
1369 {:ok, _} = CommonAPI.pin(activity.id, user)
1373 |> assign(:user, user)
1374 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1375 |> json_response(200)
1377 id_str = to_string(activity.id)
1379 assert [%{"id" => ^id_str, "pinned" => true}] = result
1383 describe "reports" do
1385 reporter = insert(:user)
1386 target_user = insert(:user)
1388 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
1390 [reporter: reporter, target_user: target_user, activity: activity]
1393 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
1394 assert %{"action_taken" => false, "id" => _} =
1396 |> assign(:user, reporter)
1397 |> post("/api/v1/reports", %{"account_id" => target_user.id})
1398 |> json_response(200)
1401 test "submit a report with statuses and comment", %{
1404 target_user: target_user,
1407 assert %{"action_taken" => false, "id" => _} =
1409 |> assign(:user, reporter)
1410 |> post("/api/v1/reports", %{
1411 "account_id" => target_user.id,
1412 "status_ids" => [activity.id],
1413 "comment" => "bad status!",
1414 "forward" => "false"
1416 |> json_response(200)
1419 test "account_id is required", %{
1424 assert %{"error" => "Valid `account_id` required"} =
1426 |> assign(:user, reporter)
1427 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
1428 |> json_response(400)
1431 test "comment must be up to the size specified in the config", %{
1434 target_user: target_user
1436 max_size = Config.get([:instance, :max_report_comment_size], 1000)
1437 comment = String.pad_trailing("a", max_size + 1, "a")
1439 error = %{"error" => "Comment must be up to #{max_size} characters"}
1443 |> assign(:user, reporter)
1444 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
1445 |> json_response(400)
1448 test "returns error when account is not exist", %{
1455 |> assign(:user, reporter)
1456 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
1458 assert json_response(conn, 400) == %{"error" => "Account not found"}
1462 describe "link headers" do
1463 test "preserves parameters in link headers", %{conn: conn} do
1464 user = insert(:user)
1465 other_user = insert(:user)
1468 CommonAPI.post(other_user, %{
1469 "status" => "hi @#{user.nickname}",
1470 "visibility" => "public"
1474 CommonAPI.post(other_user, %{
1475 "status" => "hi @#{user.nickname}",
1476 "visibility" => "public"
1479 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
1480 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
1484 |> assign(:user, user)
1485 |> get("/api/v1/notifications", %{media_only: true})
1487 assert [link_header] = get_resp_header(conn, "link")
1488 assert link_header =~ ~r/media_only=true/
1489 assert link_header =~ ~r/min_id=#{notification2.id}/
1490 assert link_header =~ ~r/max_id=#{notification1.id}/
1494 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
1495 # Need to set an old-style integer ID to reproduce the problem
1496 # (these are no longer assigned to new accounts but were preserved
1497 # for existing accounts during the migration to flakeIDs)
1498 user_one = insert(:user, %{id: 1212})
1499 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
1503 |> get("/api/v1/accounts/#{user_one.id}")
1507 |> get("/api/v1/accounts/#{user_two.nickname}")
1511 |> get("/api/v1/accounts/#{user_two.id}")
1513 acc_one = json_response(resp_one, 200)
1514 acc_two = json_response(resp_two, 200)
1515 acc_three = json_response(resp_three, 200)
1516 refute acc_one == acc_two
1517 assert acc_two == acc_three
1520 describe "custom emoji" do
1521 test "with tags", %{conn: conn} do
1524 |> get("/api/v1/custom_emojis")
1525 |> json_response(200)
1527 assert Map.has_key?(emoji, "shortcode")
1528 assert Map.has_key?(emoji, "static_url")
1529 assert Map.has_key?(emoji, "tags")
1530 assert is_list(emoji["tags"])
1531 assert Map.has_key?(emoji, "category")
1532 assert Map.has_key?(emoji, "url")
1533 assert Map.has_key?(emoji, "visible_in_picker")
1537 describe "index/2 redirections" do
1538 setup %{conn: conn} do
1542 signing_salt: "cooldude"
1547 |> Plug.Session.call(Plug.Session.init(session_opts))
1550 test_path = "/web/statuses/test"
1551 %{conn: conn, path: test_path}
1554 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
1555 conn = get(conn, path)
1557 assert conn.status == 302
1558 assert redirected_to(conn) == "/web/login"
1561 test "redirects not logged-in users to the login page on private instances", %{
1565 Config.put([:instance, :public], false)
1567 conn = get(conn, path)
1569 assert conn.status == 302
1570 assert redirected_to(conn) == "/web/login"
1573 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
1574 token = insert(:oauth_token)
1578 |> assign(:user, token.user)
1579 |> put_session(:oauth_token, token.token)
1582 assert conn.status == 200
1585 test "saves referer path to session", %{conn: conn, path: path} do
1586 conn = get(conn, path)
1587 return_to = Plug.Conn.get_session(conn, :return_to)
1589 assert return_to == path
1592 test "redirects to the saved path after log in", %{conn: conn, path: path} do
1593 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1594 auth = insert(:oauth_authorization, app: app)
1598 |> put_session(:return_to, path)
1599 |> get("/web/login", %{code: auth.token})
1601 assert conn.status == 302
1602 assert redirected_to(conn) == path
1605 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
1606 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1607 auth = insert(:oauth_authorization, app: app)
1609 conn = get(conn, "/web/login", %{code: auth.token})
1611 assert conn.status == 302
1612 assert redirected_to(conn) == "/web/getting-started"
1616 describe "create account by app" do
1620 email: "lain@example.org",
1621 password: "PlzDontHackLain",
1625 [valid_params: valid_params]
1628 test "Account registration via Application", %{conn: conn} do
1631 |> post("/api/v1/apps", %{
1632 client_name: "client_name",
1633 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1634 scopes: "read, write, follow"
1638 "client_id" => client_id,
1639 "client_secret" => client_secret,
1641 "name" => "client_name",
1642 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1645 } = json_response(conn, 200)
1649 |> post("/oauth/token", %{
1650 grant_type: "client_credentials",
1651 client_id: client_id,
1652 client_secret: client_secret
1655 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1656 json_response(conn, 200)
1659 token_from_db = Repo.get_by(Token, token: token)
1660 assert token_from_db
1662 assert scope == "read write follow"
1666 |> put_req_header("authorization", "Bearer " <> token)
1667 |> post("/api/v1/accounts", %{
1669 email: "lain@example.org",
1670 password: "PlzDontHackLain",
1676 "access_token" => token,
1677 "created_at" => _created_at,
1679 "token_type" => "Bearer"
1680 } = json_response(conn, 200)
1682 token_from_db = Repo.get_by(Token, token: token)
1683 assert token_from_db
1684 token_from_db = Repo.preload(token_from_db, :user)
1685 assert token_from_db.user
1687 assert token_from_db.user.info.confirmation_pending
1690 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
1691 _user = insert(:user, email: "lain@example.org")
1692 app_token = insert(:oauth_token, user: nil)
1696 |> put_req_header("authorization", "Bearer " <> app_token.token)
1698 res = post(conn, "/api/v1/accounts", valid_params)
1699 assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
1702 test "rate limit", %{conn: conn} do
1703 app_token = insert(:oauth_token, user: nil)
1706 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1707 |> Map.put(:remote_ip, {15, 15, 15, 15})
1712 |> post("/api/v1/accounts", %{
1713 username: "#{i}lain",
1714 email: "#{i}lain@example.org",
1715 password: "PlzDontHackLain",
1720 "access_token" => token,
1721 "created_at" => _created_at,
1723 "token_type" => "Bearer"
1724 } = json_response(conn, 200)
1726 token_from_db = Repo.get_by(Token, token: token)
1727 assert token_from_db
1728 token_from_db = Repo.preload(token_from_db, :user)
1729 assert token_from_db.user
1731 assert token_from_db.user.info.confirmation_pending
1736 |> post("/api/v1/accounts", %{
1738 email: "6lain@example.org",
1739 password: "PlzDontHackLain",
1743 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
1746 test "returns bad_request if missing required params", %{
1748 valid_params: valid_params
1750 app_token = insert(:oauth_token, user: nil)
1754 |> put_req_header("authorization", "Bearer " <> app_token.token)
1756 res = post(conn, "/api/v1/accounts", valid_params)
1757 assert json_response(res, 200)
1759 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
1760 |> Stream.zip(valid_params)
1761 |> Enum.each(fn {ip, {attr, _}} ->
1764 |> Map.put(:remote_ip, ip)
1765 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
1766 |> json_response(400)
1768 assert res == %{"error" => "Missing parameters"}
1772 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
1775 |> put_req_header("authorization", "Bearer " <> "invalid-token")
1777 res = post(conn, "/api/v1/accounts", valid_params)
1778 assert json_response(res, 403) == %{"error" => "Invalid credentials"}
1782 describe "GET /api/v1/polls/:id" do
1783 test "returns poll entity for object id", %{conn: conn} do
1784 user = insert(:user)
1787 CommonAPI.post(user, %{
1788 "status" => "Pleroma does",
1789 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
1792 object = Object.normalize(activity)
1796 |> assign(:user, user)
1797 |> get("/api/v1/polls/#{object.id}")
1799 response = json_response(conn, 200)
1800 id = to_string(object.id)
1801 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
1804 test "does not expose polls for private statuses", %{conn: conn} do
1805 user = insert(:user)
1806 other_user = insert(:user)
1809 CommonAPI.post(user, %{
1810 "status" => "Pleroma does",
1811 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
1812 "visibility" => "private"
1815 object = Object.normalize(activity)
1819 |> assign(:user, other_user)
1820 |> get("/api/v1/polls/#{object.id}")
1822 assert json_response(conn, 404)
1826 describe "POST /api/v1/polls/:id/votes" do
1827 test "votes are added to the poll", %{conn: conn} do
1828 user = insert(:user)
1829 other_user = insert(:user)
1832 CommonAPI.post(user, %{
1833 "status" => "A very delicious sandwich",
1835 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
1841 object = Object.normalize(activity)
1845 |> assign(:user, other_user)
1846 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
1848 assert json_response(conn, 200)
1849 object = Object.get_by_id(object.id)
1851 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
1856 test "author can't vote", %{conn: conn} do
1857 user = insert(:user)
1860 CommonAPI.post(user, %{
1861 "status" => "Am I cute?",
1862 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
1865 object = Object.normalize(activity)
1868 |> assign(:user, user)
1869 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
1870 |> json_response(422) == %{"error" => "Poll's author can't vote"}
1872 object = Object.get_by_id(object.id)
1874 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
1877 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
1878 user = insert(:user)
1879 other_user = insert(:user)
1882 CommonAPI.post(user, %{
1883 "status" => "The glass is",
1884 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
1887 object = Object.normalize(activity)
1890 |> assign(:user, other_user)
1891 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
1892 |> json_response(422) == %{"error" => "Too many choices"}
1894 object = Object.get_by_id(object.id)
1896 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
1901 test "does not allow choice index to be greater than options count", %{conn: conn} do
1902 user = insert(:user)
1903 other_user = insert(:user)
1906 CommonAPI.post(user, %{
1907 "status" => "Am I cute?",
1908 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
1911 object = Object.normalize(activity)
1915 |> assign(:user, other_user)
1916 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
1918 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
1921 test "returns 404 error when object is not exist", %{conn: conn} do
1922 user = insert(:user)
1926 |> assign(:user, user)
1927 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
1929 assert json_response(conn, 404) == %{"error" => "Record not found"}
1932 test "returns 404 when poll is private and not available for user", %{conn: conn} do
1933 user = insert(:user)
1934 other_user = insert(:user)
1937 CommonAPI.post(user, %{
1938 "status" => "Am I cute?",
1939 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
1940 "visibility" => "private"
1943 object = Object.normalize(activity)
1947 |> assign(:user, other_user)
1948 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
1950 assert json_response(conn, 404) == %{"error" => "Record not found"}
1954 describe "POST /auth/password, with valid parameters" do
1955 setup %{conn: conn} do
1956 user = insert(:user)
1957 conn = post(conn, "/auth/password?email=#{user.email}")
1958 %{conn: conn, user: user}
1961 test "it returns 204", %{conn: conn} do
1962 assert json_response(conn, :no_content)
1965 test "it creates a PasswordResetToken record for user", %{user: user} do
1966 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1970 test "it sends an email to user", %{user: user} do
1971 ObanHelpers.perform_all()
1972 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1974 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
1975 notify_email = Config.get([:instance, :notify_email])
1976 instance_name = Config.get([:instance, :name])
1979 from: {instance_name, notify_email},
1980 to: {user.name, user.email},
1981 html_body: email.html_body
1986 describe "POST /auth/password, with invalid parameters" do
1988 user = insert(:user)
1992 test "it returns 404 when user is not found", %{conn: conn, user: user} do
1993 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
1994 assert conn.status == 404
1995 assert conn.resp_body == ""
1998 test "it returns 400 when user is not local", %{conn: conn, user: user} do
1999 {:ok, user} = Repo.update(Changeset.change(user, local: false))
2000 conn = post(conn, "/auth/password?email=#{user.email}")
2001 assert conn.status == 400
2002 assert conn.resp_body == ""
2006 describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
2010 |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true))
2013 assert user.info.confirmation_pending
2018 clear_config([:instance, :account_activation_required]) do
2019 Config.put([:instance, :account_activation_required], true)
2022 test "resend account confirmation email", %{conn: conn, user: user} do
2024 |> assign(:user, user)
2025 |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
2026 |> json_response(:no_content)
2028 ObanHelpers.perform_all()
2030 email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
2031 notify_email = Config.get([:instance, :notify_email])
2032 instance_name = Config.get([:instance, :name])
2035 from: {instance_name, notify_email},
2036 to: {user.name, user.email},
2037 html_body: email.html_body
2042 describe "GET /api/v1/suggestions" do
2044 user = insert(:user)
2045 other_user = insert(:user)
2046 host = Config.get([Pleroma.Web.Endpoint, :url, :host])
2047 url500 = "http://test500?#{host}&#{user.nickname}"
2048 url200 = "http://test200?#{host}&#{user.nickname}"
2051 %{method: :get, url: ^url500} ->
2052 %Tesla.Env{status: 500, body: "bad request"}
2054 %{method: :get, url: ^url200} ->
2058 ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
2060 }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
2064 [user: user, other_user: other_user]
2067 clear_config(:suggestions)
2069 test "returns empty result when suggestions disabled", %{conn: conn, user: user} do
2070 Config.put([:suggestions, :enabled], false)
2074 |> assign(:user, user)
2075 |> get("/api/v1/suggestions")
2076 |> json_response(200)
2081 test "returns error", %{conn: conn, user: user} do
2082 Config.put([:suggestions, :enabled], true)
2083 Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
2085 assert capture_log(fn ->
2088 |> assign(:user, user)
2089 |> get("/api/v1/suggestions")
2090 |> json_response(500)
2092 assert res == "Something went wrong"
2093 end) =~ "Could not retrieve suggestions"
2096 test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do
2097 Config.put([:suggestions, :enabled], true)
2098 Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
2102 |> assign(:user, user)
2103 |> get("/api/v1/suggestions")
2104 |> json_response(200)
2109 "avatar" => "https://social.heldscal.la/avatar/201.jpeg",
2110 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
2114 "acct" => other_user.ap_id,
2115 "avatar" => "https://social.heldscal.la/avatar/202.jpeg",
2116 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
2117 "id" => other_user.id
2123 describe "PUT /api/v1/media/:id" do
2125 actor = insert(:user)
2127 file = %Plug.Upload{
2128 content_type: "image/jpg",
2129 path: Path.absname("test/fixtures/image.jpg"),
2130 filename: "an_image.jpg"
2133 {:ok, %Object{} = object} =
2136 actor: User.ap_id(actor),
2137 description: "test-m"
2140 [actor: actor, object: object]
2143 test "updates name of media", %{conn: conn, actor: actor, object: object} do
2146 |> assign(:user, actor)
2147 |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"})
2148 |> json_response(:ok)
2150 assert media["description"] == "test-media"
2151 assert refresh_record(object).data["name"] == "test-media"
2154 test "returns error wheb request is bad", %{conn: conn, actor: actor, object: object} do
2157 |> assign(:user, actor)
2158 |> put("/api/v1/media/#{object.id}", %{})
2159 |> json_response(400)
2161 assert media == %{"error" => "bad_request"}
2165 describe "DELETE /auth/sign_out" do
2166 test "redirect to root page", %{conn: conn} do
2167 user = insert(:user)
2171 |> assign(:user, user)
2172 |> delete("/auth/sign_out")
2174 assert conn.status == 302
2175 assert redirected_to(conn) == "/"
2179 describe "GET /api/v1/accounts/:id/lists - account_lists" do
2180 test "returns lists to which the account belongs", %{conn: conn} do
2181 user = insert(:user)
2182 other_user = insert(:user)
2183 assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user)
2184 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
2188 |> assign(:user, user)
2189 |> get("/api/v1/accounts/#{other_user.id}/lists")
2190 |> json_response(200)
2192 assert res == [%{"id" => to_string(list.id), "title" => "Test List"}]
2196 describe "empty_array, stubs for mastodon api" do
2197 test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
2198 user = insert(:user)
2202 |> assign(:user, user)
2203 |> get("/api/v1/accounts/#{user.id}/identity_proofs")
2204 |> json_response(200)
2209 test "GET /api/v1/endorsements", %{conn: conn} do
2210 user = insert(:user)
2214 |> assign(:user, user)
2215 |> get("/api/v1/endorsements")
2216 |> json_response(200)
2221 test "GET /api/v1/trends", %{conn: conn} do
2222 user = insert(:user)
2226 |> assign(:user, user)
2227 |> get("/api/v1/trends")
2228 |> json_response(200)