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 "verify_credentials", %{conn: conn} do
41 |> assign(:user, user)
42 |> get("/api/v1/accounts/verify_credentials")
44 response = json_response(conn, 200)
46 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
47 assert response["pleroma"]["chat_token"]
48 assert id == to_string(user.id)
51 test "verify_credentials default scope unlisted", %{conn: conn} do
52 user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
56 |> assign(:user, user)
57 |> get("/api/v1/accounts/verify_credentials")
59 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
60 assert id == to_string(user.id)
63 test "apps/verify_credentials", %{conn: conn} do
64 token = insert(:oauth_token)
68 |> assign(:user, token.user)
69 |> assign(:token, token)
70 |> get("/api/v1/apps/verify_credentials")
72 app = Repo.preload(token, :app).app
75 "name" => app.client_name,
76 "website" => app.website,
77 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
80 assert expected == json_response(conn, 200)
83 test "user avatar can be set", %{conn: conn} do
85 avatar_image = File.read!("test/fixtures/avatar_data_uri")
89 |> assign(:user, user)
90 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
92 user = refresh_record(user)
106 assert %{"url" => _} = json_response(conn, 200)
109 test "user avatar can be reset", %{conn: conn} do
114 |> assign(:user, user)
115 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
117 user = User.get_cached_by_id(user.id)
119 assert user.avatar == nil
121 assert %{"url" => nil} = json_response(conn, 200)
124 test "can set profile banner", %{conn: conn} do
129 |> assign(:user, user)
130 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
132 user = refresh_record(user)
133 assert user.info.banner["type"] == "Image"
135 assert %{"url" => _} = json_response(conn, 200)
138 test "can reset profile banner", %{conn: conn} do
143 |> assign(:user, user)
144 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
146 user = refresh_record(user)
147 assert user.info.banner == %{}
149 assert %{"url" => nil} = json_response(conn, 200)
152 test "background image can be set", %{conn: conn} do
157 |> assign(:user, user)
158 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
160 user = refresh_record(user)
161 assert user.info.background["type"] == "Image"
162 assert %{"url" => _} = json_response(conn, 200)
165 test "background image can be reset", %{conn: conn} do
170 |> assign(:user, user)
171 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
173 user = refresh_record(user)
174 assert user.info.background == %{}
175 assert %{"url" => nil} = json_response(conn, 200)
178 test "creates an oauth app", %{conn: conn} do
180 app_attrs = build(:oauth_app)
184 |> assign(:user, user)
185 |> post("/api/v1/apps", %{
186 client_name: app_attrs.client_name,
187 redirect_uris: app_attrs.redirect_uris
190 [app] = Repo.all(App)
193 "name" => app.client_name,
194 "website" => app.website,
195 "client_id" => app.client_id,
196 "client_secret" => app.client_secret,
197 "id" => app.id |> to_string(),
198 "redirect_uri" => app.redirect_uris,
199 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
202 assert expected == json_response(conn, 200)
205 describe "user timelines" do
206 test "gets a users statuses", %{conn: conn} do
207 user_one = insert(:user)
208 user_two = insert(:user)
209 user_three = insert(:user)
211 {:ok, user_three} = User.follow(user_three, user_one)
213 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
215 {:ok, direct_activity} =
216 CommonAPI.post(user_one, %{
217 "status" => "Hi, @#{user_two.nickname}.",
218 "visibility" => "direct"
221 {:ok, private_activity} =
222 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
226 |> get("/api/v1/accounts/#{user_one.id}/statuses")
228 assert [%{"id" => id}] = json_response(resp, 200)
229 assert id == to_string(activity.id)
233 |> assign(:user, user_two)
234 |> get("/api/v1/accounts/#{user_one.id}/statuses")
236 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
237 assert id_one == to_string(direct_activity.id)
238 assert id_two == to_string(activity.id)
242 |> assign(:user, user_three)
243 |> get("/api/v1/accounts/#{user_one.id}/statuses")
245 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
246 assert id_one == to_string(private_activity.id)
247 assert id_two == to_string(activity.id)
250 test "unimplemented pinned statuses feature", %{conn: conn} do
251 note = insert(:note_activity)
252 user = User.get_cached_by_ap_id(note.data["actor"])
256 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
258 assert json_response(conn, 200) == []
261 test "gets an users media", %{conn: conn} do
262 note = insert(:note_activity)
263 user = User.get_cached_by_ap_id(note.data["actor"])
266 content_type: "image/jpg",
267 path: Path.absname("test/fixtures/image.jpg"),
268 filename: "an_image.jpg"
271 {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
273 {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
277 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
279 assert [%{"id" => id}] = json_response(conn, 200)
280 assert id == to_string(image_post.id)
284 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
286 assert [%{"id" => id}] = json_response(conn, 200)
287 assert id == to_string(image_post.id)
290 test "gets a user's statuses without reblogs", %{conn: conn} do
292 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
293 {:ok, _, _} = CommonAPI.repeat(post.id, user)
297 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
299 assert [%{"id" => id}] = json_response(conn, 200)
300 assert id == to_string(post.id)
304 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
306 assert [%{"id" => id}] = json_response(conn, 200)
307 assert id == to_string(post.id)
310 test "filters user's statuses by a hashtag", %{conn: conn} do
312 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
313 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
317 |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
319 assert [%{"id" => id}] = json_response(conn, 200)
320 assert id == to_string(post.id)
324 describe "user relationships" do
325 test "returns the relationships for the current user", %{conn: conn} do
327 other_user = insert(:user)
328 {:ok, user} = User.follow(user, other_user)
332 |> assign(:user, user)
333 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
335 assert [relationship] = json_response(conn, 200)
337 assert to_string(other_user.id) == relationship["id"]
340 test "returns an empty list on a bad request", %{conn: conn} do
345 |> assign(:user, user)
346 |> get("/api/v1/accounts/relationships", %{})
348 assert [] = json_response(conn, 200)
352 describe "media upload" do
358 |> assign(:user, user)
360 image = %Plug.Upload{
361 content_type: "image/jpg",
362 path: Path.absname("test/fixtures/image.jpg"),
363 filename: "an_image.jpg"
366 [conn: conn, image: image]
369 clear_config([:media_proxy])
370 clear_config([Pleroma.Upload])
372 test "returns uploaded image", %{conn: conn, image: image} do
373 desc = "Description of the image"
377 |> post("/api/v1/media", %{"file" => image, "description" => desc})
378 |> json_response(:ok)
380 assert media["type"] == "image"
381 assert media["description"] == desc
384 object = Repo.get(Object, media["id"])
385 assert object.data["actor"] == User.ap_id(conn.assigns[:user])
389 describe "locked accounts" do
390 test "verify_credentials", %{conn: conn} do
391 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
395 |> assign(:user, user)
396 |> get("/api/v1/accounts/verify_credentials")
398 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
399 assert id == to_string(user.id)
403 describe "account fetching" do
404 test "works by id" do
409 |> get("/api/v1/accounts/#{user.id}")
411 assert %{"id" => id} = json_response(conn, 200)
412 assert id == to_string(user.id)
416 |> get("/api/v1/accounts/-1")
418 assert %{"error" => "Can't find user"} = json_response(conn, 404)
421 test "works by nickname" do
426 |> get("/api/v1/accounts/#{user.nickname}")
428 assert %{"id" => id} = json_response(conn, 200)
432 test "works by nickname for remote users" do
433 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
434 Pleroma.Config.put([:instance, :limit_to_local_content], false)
435 user = insert(:user, nickname: "user@example.com", local: false)
439 |> get("/api/v1/accounts/#{user.nickname}")
441 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
442 assert %{"id" => id} = json_response(conn, 200)
446 test "respects limit_to_local_content == :all for remote user nicknames" do
447 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
448 Pleroma.Config.put([:instance, :limit_to_local_content], :all)
450 user = insert(:user, nickname: "user@example.com", local: false)
454 |> get("/api/v1/accounts/#{user.nickname}")
456 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
457 assert json_response(conn, 404)
460 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
461 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
462 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
464 user = insert(:user, nickname: "user@example.com", local: false)
465 reading_user = insert(:user)
469 |> get("/api/v1/accounts/#{user.nickname}")
471 assert json_response(conn, 404)
475 |> assign(:user, reading_user)
476 |> get("/api/v1/accounts/#{user.nickname}")
478 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
479 assert %{"id" => id} = json_response(conn, 200)
484 describe "/api/v1/pleroma/mascot" do
485 test "mascot upload", %{conn: conn} do
488 non_image_file = %Plug.Upload{
489 content_type: "audio/mpeg",
490 path: Path.absname("test/fixtures/sound.mp3"),
491 filename: "sound.mp3"
496 |> assign(:user, user)
497 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
499 assert json_response(conn, 415)
502 content_type: "image/jpg",
503 path: Path.absname("test/fixtures/image.jpg"),
504 filename: "an_image.jpg"
509 |> assign(:user, user)
510 |> put("/api/v1/pleroma/mascot", %{"file" => file})
512 assert %{"id" => _, "type" => image} = json_response(conn, 200)
515 test "mascot retrieving", %{conn: conn} do
517 # When user hasn't set a mascot, we should just get pleroma tan back
520 |> assign(:user, user)
521 |> get("/api/v1/pleroma/mascot")
523 assert %{"url" => url} = json_response(conn, 200)
524 assert url =~ "pleroma-fox-tan-smol"
526 # When a user sets their mascot, we should get that back
528 content_type: "image/jpg",
529 path: Path.absname("test/fixtures/image.jpg"),
530 filename: "an_image.jpg"
535 |> assign(:user, user)
536 |> put("/api/v1/pleroma/mascot", %{"file" => file})
538 assert json_response(conn, 200)
540 user = User.get_cached_by_id(user.id)
544 |> assign(:user, user)
545 |> get("/api/v1/pleroma/mascot")
547 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
548 assert url =~ "an_image"
552 test "getting followers", %{conn: conn} do
554 other_user = insert(:user)
555 {:ok, user} = User.follow(user, other_user)
559 |> get("/api/v1/accounts/#{other_user.id}/followers")
561 assert [%{"id" => id}] = json_response(conn, 200)
562 assert id == to_string(user.id)
565 test "getting followers, hide_followers", %{conn: conn} do
567 other_user = insert(:user, %{info: %{hide_followers: true}})
568 {:ok, _user} = User.follow(user, other_user)
572 |> get("/api/v1/accounts/#{other_user.id}/followers")
574 assert [] == json_response(conn, 200)
577 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
579 other_user = insert(:user, %{info: %{hide_followers: true}})
580 {:ok, _user} = User.follow(user, other_user)
584 |> assign(:user, other_user)
585 |> get("/api/v1/accounts/#{other_user.id}/followers")
587 refute [] == json_response(conn, 200)
590 test "getting followers, pagination", %{conn: conn} do
592 follower1 = insert(:user)
593 follower2 = insert(:user)
594 follower3 = insert(:user)
595 {:ok, _} = User.follow(follower1, user)
596 {:ok, _} = User.follow(follower2, user)
597 {:ok, _} = User.follow(follower3, user)
601 |> assign(:user, user)
605 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
607 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
608 assert id3 == follower3.id
609 assert id2 == follower2.id
613 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
615 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
616 assert id2 == follower2.id
617 assert id1 == follower1.id
621 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
623 assert [%{"id" => id2}] = json_response(res_conn, 200)
624 assert id2 == follower2.id
626 assert [link_header] = get_resp_header(res_conn, "link")
627 assert link_header =~ ~r/min_id=#{follower2.id}/
628 assert link_header =~ ~r/max_id=#{follower2.id}/
631 test "getting following", %{conn: conn} do
633 other_user = insert(:user)
634 {:ok, user} = User.follow(user, other_user)
638 |> get("/api/v1/accounts/#{user.id}/following")
640 assert [%{"id" => id}] = json_response(conn, 200)
641 assert id == to_string(other_user.id)
644 test "getting following, hide_follows", %{conn: conn} do
645 user = insert(:user, %{info: %{hide_follows: true}})
646 other_user = insert(:user)
647 {:ok, user} = User.follow(user, other_user)
651 |> get("/api/v1/accounts/#{user.id}/following")
653 assert [] == json_response(conn, 200)
656 test "getting following, hide_follows, same user requesting", %{conn: conn} do
657 user = insert(:user, %{info: %{hide_follows: true}})
658 other_user = insert(:user)
659 {:ok, user} = User.follow(user, other_user)
663 |> assign(:user, user)
664 |> get("/api/v1/accounts/#{user.id}/following")
666 refute [] == json_response(conn, 200)
669 test "getting following, pagination", %{conn: conn} do
671 following1 = insert(:user)
672 following2 = insert(:user)
673 following3 = insert(:user)
674 {:ok, _} = User.follow(user, following1)
675 {:ok, _} = User.follow(user, following2)
676 {:ok, _} = User.follow(user, following3)
680 |> assign(:user, user)
684 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
686 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
687 assert id3 == following3.id
688 assert id2 == following2.id
692 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
694 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
695 assert id2 == following2.id
696 assert id1 == following1.id
700 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
702 assert [%{"id" => id2}] = json_response(res_conn, 200)
703 assert id2 == following2.id
705 assert [link_header] = get_resp_header(res_conn, "link")
706 assert link_header =~ ~r/min_id=#{following2.id}/
707 assert link_header =~ ~r/max_id=#{following2.id}/
710 test "following / unfollowing a user", %{conn: conn} do
712 other_user = insert(:user)
716 |> assign(:user, user)
717 |> post("/api/v1/accounts/#{other_user.id}/follow")
719 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
721 user = User.get_cached_by_id(user.id)
725 |> assign(:user, user)
726 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
728 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
730 user = User.get_cached_by_id(user.id)
734 |> assign(:user, user)
735 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
737 assert %{"id" => id} = json_response(conn, 200)
738 assert id == to_string(other_user.id)
741 test "following without reblogs" do
742 follower = insert(:user)
743 followed = insert(:user)
744 other_user = insert(:user)
748 |> assign(:user, follower)
749 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
751 assert %{"showing_reblogs" => false} = json_response(conn, 200)
753 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
754 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
758 |> assign(:user, User.get_cached_by_id(follower.id))
759 |> get("/api/v1/timelines/home")
761 assert [] == json_response(conn, 200)
765 |> assign(:user, follower)
766 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
768 assert %{"showing_reblogs" => true} = json_response(conn, 200)
772 |> assign(:user, User.get_cached_by_id(follower.id))
773 |> get("/api/v1/timelines/home")
775 expected_activity_id = reblog.id
776 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
779 test "following / unfollowing errors" do
784 |> assign(:user, user)
787 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
788 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
791 user = User.get_cached_by_id(user.id)
792 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
793 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
795 # self follow via uri
796 user = User.get_cached_by_id(user.id)
797 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
798 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
800 # follow non existing user
801 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
802 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
804 # follow non existing user via uri
805 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
806 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
808 # unfollow non existing user
809 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
810 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
813 describe "mute/unmute" do
814 test "with notifications", %{conn: conn} do
816 other_user = insert(:user)
820 |> assign(:user, user)
821 |> post("/api/v1/accounts/#{other_user.id}/mute")
823 response = json_response(conn, 200)
825 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
826 user = User.get_cached_by_id(user.id)
830 |> assign(:user, user)
831 |> post("/api/v1/accounts/#{other_user.id}/unmute")
833 response = json_response(conn, 200)
834 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
837 test "without notifications", %{conn: conn} do
839 other_user = insert(:user)
843 |> assign(:user, user)
844 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
846 response = json_response(conn, 200)
848 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
849 user = User.get_cached_by_id(user.id)
853 |> assign(:user, user)
854 |> post("/api/v1/accounts/#{other_user.id}/unmute")
856 response = json_response(conn, 200)
857 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
861 describe "subscribing / unsubscribing" do
862 test "subscribing / unsubscribing to a user", %{conn: conn} do
864 subscription_target = insert(:user)
868 |> assign(:user, user)
869 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
871 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
875 |> assign(:user, user)
876 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
878 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
882 describe "subscribing" do
883 test "returns 404 when subscription_target not found", %{conn: conn} do
888 |> assign(:user, user)
889 |> post("/api/v1/pleroma/accounts/target_id/subscribe")
891 assert %{"error" => "Record not found"} = json_response(conn, 404)
895 describe "unsubscribing" do
896 test "returns 404 when subscription_target not found", %{conn: conn} do
901 |> assign(:user, user)
902 |> post("/api/v1/pleroma/accounts/target_id/unsubscribe")
904 assert %{"error" => "Record not found"} = json_response(conn, 404)
908 test "getting a list of mutes", %{conn: conn} do
910 other_user = insert(:user)
912 {:ok, user} = User.mute(user, other_user)
916 |> assign(:user, user)
917 |> get("/api/v1/mutes")
919 other_user_id = to_string(other_user.id)
920 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
923 test "blocking / unblocking a user", %{conn: conn} do
925 other_user = insert(:user)
929 |> assign(:user, user)
930 |> post("/api/v1/accounts/#{other_user.id}/block")
932 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
934 user = User.get_cached_by_id(user.id)
938 |> assign(:user, user)
939 |> post("/api/v1/accounts/#{other_user.id}/unblock")
941 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
944 test "getting a list of blocks", %{conn: conn} do
946 other_user = insert(:user)
948 {:ok, user} = User.block(user, other_user)
952 |> assign(:user, user)
953 |> get("/api/v1/blocks")
955 other_user_id = to_string(other_user.id)
956 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
959 test "unimplemented follow_requests, blocks, domain blocks" do
962 ["blocks", "domain_blocks", "follow_requests"]
963 |> Enum.each(fn endpoint ->
966 |> assign(:user, user)
967 |> get("/api/v1/#{endpoint}")
969 assert [] = json_response(conn, 200)
973 test "returns the favorites of a user", %{conn: conn} do
975 other_user = insert(:user)
977 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
978 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
980 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
984 |> assign(:user, user)
985 |> get("/api/v1/favourites")
987 assert [status] = json_response(first_conn, 200)
988 assert status["id"] == to_string(activity.id)
990 assert [{"link", _link_header}] =
991 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
993 # Honours query params
994 {:ok, second_activity} =
995 CommonAPI.post(other_user, %{
997 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1000 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1002 last_like = status["id"]
1006 |> assign(:user, user)
1007 |> get("/api/v1/favourites?since_id=#{last_like}")
1009 assert [second_status] = json_response(second_conn, 200)
1010 assert second_status["id"] == to_string(second_activity.id)
1014 |> assign(:user, user)
1015 |> get("/api/v1/favourites?limit=0")
1017 assert [] = json_response(third_conn, 200)
1020 describe "getting favorites timeline of specified user" do
1022 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
1023 [current_user: current_user, user: user]
1026 test "returns list of statuses favorited by specified user", %{
1028 current_user: current_user,
1031 [activity | _] = insert_pair(:note_activity)
1032 CommonAPI.favorite(activity.id, user)
1036 |> assign(:user, current_user)
1037 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1038 |> json_response(:ok)
1042 assert length(response) == 1
1043 assert like["id"] == activity.id
1046 test "returns favorites for specified user_id when user is not logged in", %{
1050 activity = insert(:note_activity)
1051 CommonAPI.favorite(activity.id, user)
1055 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1056 |> json_response(:ok)
1058 assert length(response) == 1
1061 test "returns favorited DM only when user is logged in and he is one of recipients", %{
1063 current_user: current_user,
1067 CommonAPI.post(current_user, %{
1068 "status" => "Hi @#{user.nickname}!",
1069 "visibility" => "direct"
1072 CommonAPI.favorite(direct.id, user)
1076 |> assign(:user, current_user)
1077 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1078 |> json_response(:ok)
1080 assert length(response) == 1
1082 anonymous_response =
1084 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1085 |> json_response(:ok)
1087 assert Enum.empty?(anonymous_response)
1090 test "does not return others' favorited DM when user is not one of recipients", %{
1092 current_user: current_user,
1095 user_two = insert(:user)
1098 CommonAPI.post(user_two, %{
1099 "status" => "Hi @#{user.nickname}!",
1100 "visibility" => "direct"
1103 CommonAPI.favorite(direct.id, user)
1107 |> assign(:user, current_user)
1108 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1109 |> json_response(:ok)
1111 assert Enum.empty?(response)
1114 test "paginates favorites using since_id and max_id", %{
1116 current_user: current_user,
1119 activities = insert_list(10, :note_activity)
1121 Enum.each(activities, fn activity ->
1122 CommonAPI.favorite(activity.id, user)
1125 third_activity = Enum.at(activities, 2)
1126 seventh_activity = Enum.at(activities, 6)
1130 |> assign(:user, current_user)
1131 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
1132 since_id: third_activity.id,
1133 max_id: seventh_activity.id
1135 |> json_response(:ok)
1137 assert length(response) == 3
1138 refute third_activity in response
1139 refute seventh_activity in response
1142 test "limits favorites using limit parameter", %{
1144 current_user: current_user,
1148 |> insert_list(:note_activity)
1149 |> Enum.each(fn activity ->
1150 CommonAPI.favorite(activity.id, user)
1155 |> assign(:user, current_user)
1156 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
1157 |> json_response(:ok)
1159 assert length(response) == 3
1162 test "returns empty response when user does not have any favorited statuses", %{
1164 current_user: current_user,
1169 |> assign(:user, current_user)
1170 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1171 |> json_response(:ok)
1173 assert Enum.empty?(response)
1176 test "returns 404 error when specified user is not exist", %{conn: conn} do
1177 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
1179 assert json_response(conn, 404) == %{"error" => "Record not found"}
1182 test "returns 403 error when user has hidden own favorites", %{
1184 current_user: current_user
1186 user = insert(:user, %{info: %{hide_favorites: true}})
1187 activity = insert(:note_activity)
1188 CommonAPI.favorite(activity.id, user)
1192 |> assign(:user, current_user)
1193 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1195 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1198 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
1199 user = insert(:user)
1200 activity = insert(:note_activity)
1201 CommonAPI.favorite(activity.id, user)
1205 |> assign(:user, current_user)
1206 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1208 assert user.info.hide_favorites
1209 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1213 test "get instance information", %{conn: conn} do
1214 conn = get(conn, "/api/v1/instance")
1215 assert result = json_response(conn, 200)
1217 email = Config.get([:instance, :email])
1218 # Note: not checking for "max_toot_chars" since it's optional
1224 "email" => from_config_email,
1226 "streaming_api" => _
1231 "registrations" => _,
1235 assert email == from_config_email
1238 test "get instance stats", %{conn: conn} do
1239 user = insert(:user, %{local: true})
1241 user2 = insert(:user, %{local: true})
1242 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1244 insert(:user, %{local: false, nickname: "u@peer1.com"})
1245 insert(:user, %{local: false, nickname: "u@peer2.com"})
1247 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
1249 # Stats should count users with missing or nil `info.deactivated` value
1253 |> User.get_cached_by_id()
1254 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
1256 Pleroma.Stats.force_update()
1258 conn = get(conn, "/api/v1/instance")
1260 assert result = json_response(conn, 200)
1262 stats = result["stats"]
1265 assert stats["user_count"] == 1
1266 assert stats["status_count"] == 1
1267 assert stats["domain_count"] == 2
1270 test "get peers", %{conn: conn} do
1271 insert(:user, %{local: false, nickname: "u@peer1.com"})
1272 insert(:user, %{local: false, nickname: "u@peer2.com"})
1274 Pleroma.Stats.force_update()
1276 conn = get(conn, "/api/v1/instance/peers")
1278 assert result = json_response(conn, 200)
1280 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1283 test "put settings", %{conn: conn} do
1284 user = insert(:user)
1288 |> assign(:user, user)
1289 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1291 assert _result = json_response(conn, 200)
1293 user = User.get_cached_by_ap_id(user.ap_id)
1294 assert user.info.settings == %{"programming" => "socks"}
1297 describe "pinned statuses" do
1299 user = insert(:user)
1300 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
1302 [user: user, activity: activity]
1305 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
1306 {:ok, _} = CommonAPI.pin(activity.id, user)
1310 |> assign(:user, user)
1311 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1312 |> json_response(200)
1314 id_str = to_string(activity.id)
1316 assert [%{"id" => ^id_str, "pinned" => true}] = result
1320 describe "reports" do
1322 reporter = insert(:user)
1323 target_user = insert(:user)
1325 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
1327 [reporter: reporter, target_user: target_user, activity: activity]
1330 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
1331 assert %{"action_taken" => false, "id" => _} =
1333 |> assign(:user, reporter)
1334 |> post("/api/v1/reports", %{"account_id" => target_user.id})
1335 |> json_response(200)
1338 test "submit a report with statuses and comment", %{
1341 target_user: target_user,
1344 assert %{"action_taken" => false, "id" => _} =
1346 |> assign(:user, reporter)
1347 |> post("/api/v1/reports", %{
1348 "account_id" => target_user.id,
1349 "status_ids" => [activity.id],
1350 "comment" => "bad status!",
1351 "forward" => "false"
1353 |> json_response(200)
1356 test "account_id is required", %{
1361 assert %{"error" => "Valid `account_id` required"} =
1363 |> assign(:user, reporter)
1364 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
1365 |> json_response(400)
1368 test "comment must be up to the size specified in the config", %{
1371 target_user: target_user
1373 max_size = Config.get([:instance, :max_report_comment_size], 1000)
1374 comment = String.pad_trailing("a", max_size + 1, "a")
1376 error = %{"error" => "Comment must be up to #{max_size} characters"}
1380 |> assign(:user, reporter)
1381 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
1382 |> json_response(400)
1385 test "returns error when account is not exist", %{
1392 |> assign(:user, reporter)
1393 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
1395 assert json_response(conn, 400) == %{"error" => "Account not found"}
1399 describe "link headers" do
1400 test "preserves parameters in link headers", %{conn: conn} do
1401 user = insert(:user)
1402 other_user = insert(:user)
1405 CommonAPI.post(other_user, %{
1406 "status" => "hi @#{user.nickname}",
1407 "visibility" => "public"
1411 CommonAPI.post(other_user, %{
1412 "status" => "hi @#{user.nickname}",
1413 "visibility" => "public"
1416 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
1417 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
1421 |> assign(:user, user)
1422 |> get("/api/v1/notifications", %{media_only: true})
1424 assert [link_header] = get_resp_header(conn, "link")
1425 assert link_header =~ ~r/media_only=true/
1426 assert link_header =~ ~r/min_id=#{notification2.id}/
1427 assert link_header =~ ~r/max_id=#{notification1.id}/
1431 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
1432 # Need to set an old-style integer ID to reproduce the problem
1433 # (these are no longer assigned to new accounts but were preserved
1434 # for existing accounts during the migration to flakeIDs)
1435 user_one = insert(:user, %{id: 1212})
1436 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
1440 |> get("/api/v1/accounts/#{user_one.id}")
1444 |> get("/api/v1/accounts/#{user_two.nickname}")
1448 |> get("/api/v1/accounts/#{user_two.id}")
1450 acc_one = json_response(resp_one, 200)
1451 acc_two = json_response(resp_two, 200)
1452 acc_three = json_response(resp_three, 200)
1453 refute acc_one == acc_two
1454 assert acc_two == acc_three
1457 describe "custom emoji" do
1458 test "with tags", %{conn: conn} do
1461 |> get("/api/v1/custom_emojis")
1462 |> json_response(200)
1464 assert Map.has_key?(emoji, "shortcode")
1465 assert Map.has_key?(emoji, "static_url")
1466 assert Map.has_key?(emoji, "tags")
1467 assert is_list(emoji["tags"])
1468 assert Map.has_key?(emoji, "category")
1469 assert Map.has_key?(emoji, "url")
1470 assert Map.has_key?(emoji, "visible_in_picker")
1474 describe "index/2 redirections" do
1475 setup %{conn: conn} do
1479 signing_salt: "cooldude"
1484 |> Plug.Session.call(Plug.Session.init(session_opts))
1487 test_path = "/web/statuses/test"
1488 %{conn: conn, path: test_path}
1491 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
1492 conn = get(conn, path)
1494 assert conn.status == 302
1495 assert redirected_to(conn) == "/web/login"
1498 test "redirects not logged-in users to the login page on private instances", %{
1502 Config.put([:instance, :public], false)
1504 conn = get(conn, path)
1506 assert conn.status == 302
1507 assert redirected_to(conn) == "/web/login"
1510 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
1511 token = insert(:oauth_token)
1515 |> assign(:user, token.user)
1516 |> put_session(:oauth_token, token.token)
1519 assert conn.status == 200
1522 test "saves referer path to session", %{conn: conn, path: path} do
1523 conn = get(conn, path)
1524 return_to = Plug.Conn.get_session(conn, :return_to)
1526 assert return_to == path
1529 test "redirects to the saved path after log in", %{conn: conn, path: path} do
1530 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1531 auth = insert(:oauth_authorization, app: app)
1535 |> put_session(:return_to, path)
1536 |> get("/web/login", %{code: auth.token})
1538 assert conn.status == 302
1539 assert redirected_to(conn) == path
1542 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
1543 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1544 auth = insert(:oauth_authorization, app: app)
1546 conn = get(conn, "/web/login", %{code: auth.token})
1548 assert conn.status == 302
1549 assert redirected_to(conn) == "/web/getting-started"
1553 describe "create account by app" do
1557 email: "lain@example.org",
1558 password: "PlzDontHackLain",
1562 [valid_params: valid_params]
1565 test "Account registration via Application", %{conn: conn} do
1568 |> post("/api/v1/apps", %{
1569 client_name: "client_name",
1570 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1571 scopes: "read, write, follow"
1575 "client_id" => client_id,
1576 "client_secret" => client_secret,
1578 "name" => "client_name",
1579 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1582 } = json_response(conn, 200)
1586 |> post("/oauth/token", %{
1587 grant_type: "client_credentials",
1588 client_id: client_id,
1589 client_secret: client_secret
1592 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1593 json_response(conn, 200)
1596 token_from_db = Repo.get_by(Token, token: token)
1597 assert token_from_db
1599 assert scope == "read write follow"
1603 |> put_req_header("authorization", "Bearer " <> token)
1604 |> post("/api/v1/accounts", %{
1606 email: "lain@example.org",
1607 password: "PlzDontHackLain",
1613 "access_token" => token,
1614 "created_at" => _created_at,
1616 "token_type" => "Bearer"
1617 } = json_response(conn, 200)
1619 token_from_db = Repo.get_by(Token, token: token)
1620 assert token_from_db
1621 token_from_db = Repo.preload(token_from_db, :user)
1622 assert token_from_db.user
1624 assert token_from_db.user.info.confirmation_pending
1627 test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
1628 _user = insert(:user, email: "lain@example.org")
1629 app_token = insert(:oauth_token, user: nil)
1633 |> put_req_header("authorization", "Bearer " <> app_token.token)
1635 res = post(conn, "/api/v1/accounts", valid_params)
1636 assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
1639 test "rate limit", %{conn: conn} do
1640 app_token = insert(:oauth_token, user: nil)
1643 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1644 |> Map.put(:remote_ip, {15, 15, 15, 15})
1649 |> post("/api/v1/accounts", %{
1650 username: "#{i}lain",
1651 email: "#{i}lain@example.org",
1652 password: "PlzDontHackLain",
1657 "access_token" => token,
1658 "created_at" => _created_at,
1660 "token_type" => "Bearer"
1661 } = json_response(conn, 200)
1663 token_from_db = Repo.get_by(Token, token: token)
1664 assert token_from_db
1665 token_from_db = Repo.preload(token_from_db, :user)
1666 assert token_from_db.user
1668 assert token_from_db.user.info.confirmation_pending
1673 |> post("/api/v1/accounts", %{
1675 email: "6lain@example.org",
1676 password: "PlzDontHackLain",
1680 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
1683 test "returns bad_request if missing required params", %{
1685 valid_params: valid_params
1687 app_token = insert(:oauth_token, user: nil)
1691 |> put_req_header("authorization", "Bearer " <> app_token.token)
1693 res = post(conn, "/api/v1/accounts", valid_params)
1694 assert json_response(res, 200)
1696 [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
1697 |> Stream.zip(valid_params)
1698 |> Enum.each(fn {ip, {attr, _}} ->
1701 |> Map.put(:remote_ip, ip)
1702 |> post("/api/v1/accounts", Map.delete(valid_params, attr))
1703 |> json_response(400)
1705 assert res == %{"error" => "Missing parameters"}
1709 test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
1712 |> put_req_header("authorization", "Bearer " <> "invalid-token")
1714 res = post(conn, "/api/v1/accounts", valid_params)
1715 assert json_response(res, 403) == %{"error" => "Invalid credentials"}
1719 describe "GET /api/v1/polls/:id" do
1720 test "returns poll entity for object id", %{conn: conn} do
1721 user = insert(:user)
1724 CommonAPI.post(user, %{
1725 "status" => "Pleroma does",
1726 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
1729 object = Object.normalize(activity)
1733 |> assign(:user, user)
1734 |> get("/api/v1/polls/#{object.id}")
1736 response = json_response(conn, 200)
1737 id = to_string(object.id)
1738 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
1741 test "does not expose polls for private statuses", %{conn: conn} do
1742 user = insert(:user)
1743 other_user = insert(:user)
1746 CommonAPI.post(user, %{
1747 "status" => "Pleroma does",
1748 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
1749 "visibility" => "private"
1752 object = Object.normalize(activity)
1756 |> assign(:user, other_user)
1757 |> get("/api/v1/polls/#{object.id}")
1759 assert json_response(conn, 404)
1763 describe "POST /api/v1/polls/:id/votes" do
1764 test "votes are added to the poll", %{conn: conn} do
1765 user = insert(:user)
1766 other_user = insert(:user)
1769 CommonAPI.post(user, %{
1770 "status" => "A very delicious sandwich",
1772 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
1778 object = Object.normalize(activity)
1782 |> assign(:user, other_user)
1783 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
1785 assert json_response(conn, 200)
1786 object = Object.get_by_id(object.id)
1788 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
1793 test "author can't vote", %{conn: conn} do
1794 user = insert(:user)
1797 CommonAPI.post(user, %{
1798 "status" => "Am I cute?",
1799 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
1802 object = Object.normalize(activity)
1805 |> assign(:user, user)
1806 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
1807 |> json_response(422) == %{"error" => "Poll's author can't vote"}
1809 object = Object.get_by_id(object.id)
1811 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
1814 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
1815 user = insert(:user)
1816 other_user = insert(:user)
1819 CommonAPI.post(user, %{
1820 "status" => "The glass is",
1821 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
1824 object = Object.normalize(activity)
1827 |> assign(:user, other_user)
1828 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
1829 |> json_response(422) == %{"error" => "Too many choices"}
1831 object = Object.get_by_id(object.id)
1833 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
1838 test "does not allow choice index to be greater than options count", %{conn: conn} do
1839 user = insert(:user)
1840 other_user = insert(:user)
1843 CommonAPI.post(user, %{
1844 "status" => "Am I cute?",
1845 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
1848 object = Object.normalize(activity)
1852 |> assign(:user, other_user)
1853 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
1855 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
1858 test "returns 404 error when object is not exist", %{conn: conn} do
1859 user = insert(:user)
1863 |> assign(:user, user)
1864 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
1866 assert json_response(conn, 404) == %{"error" => "Record not found"}
1869 test "returns 404 when poll is private and not available for user", %{conn: conn} do
1870 user = insert(:user)
1871 other_user = insert(:user)
1874 CommonAPI.post(user, %{
1875 "status" => "Am I cute?",
1876 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
1877 "visibility" => "private"
1880 object = Object.normalize(activity)
1884 |> assign(:user, other_user)
1885 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
1887 assert json_response(conn, 404) == %{"error" => "Record not found"}
1891 describe "POST /auth/password, with valid parameters" do
1892 setup %{conn: conn} do
1893 user = insert(:user)
1894 conn = post(conn, "/auth/password?email=#{user.email}")
1895 %{conn: conn, user: user}
1898 test "it returns 204", %{conn: conn} do
1899 assert json_response(conn, :no_content)
1902 test "it creates a PasswordResetToken record for user", %{user: user} do
1903 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1907 test "it sends an email to user", %{user: user} do
1908 ObanHelpers.perform_all()
1909 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1911 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
1912 notify_email = Config.get([:instance, :notify_email])
1913 instance_name = Config.get([:instance, :name])
1916 from: {instance_name, notify_email},
1917 to: {user.name, user.email},
1918 html_body: email.html_body
1923 describe "POST /auth/password, with invalid parameters" do
1925 user = insert(:user)
1929 test "it returns 404 when user is not found", %{conn: conn, user: user} do
1930 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
1931 assert conn.status == 404
1932 assert conn.resp_body == ""
1935 test "it returns 400 when user is not local", %{conn: conn, user: user} do
1936 {:ok, user} = Repo.update(Changeset.change(user, local: false))
1937 conn = post(conn, "/auth/password?email=#{user.email}")
1938 assert conn.status == 400
1939 assert conn.resp_body == ""
1943 describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
1947 |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true))
1950 assert user.info.confirmation_pending
1955 clear_config([:instance, :account_activation_required]) do
1956 Config.put([:instance, :account_activation_required], true)
1959 test "resend account confirmation email", %{conn: conn, user: user} do
1961 |> assign(:user, user)
1962 |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
1963 |> json_response(:no_content)
1965 ObanHelpers.perform_all()
1967 email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
1968 notify_email = Config.get([:instance, :notify_email])
1969 instance_name = Config.get([:instance, :name])
1972 from: {instance_name, notify_email},
1973 to: {user.name, user.email},
1974 html_body: email.html_body
1979 describe "GET /api/v1/suggestions" do
1981 user = insert(:user)
1982 other_user = insert(:user)
1983 host = Config.get([Pleroma.Web.Endpoint, :url, :host])
1984 url500 = "http://test500?#{host}&#{user.nickname}"
1985 url200 = "http://test200?#{host}&#{user.nickname}"
1988 %{method: :get, url: ^url500} ->
1989 %Tesla.Env{status: 500, body: "bad request"}
1991 %{method: :get, url: ^url200} ->
1995 ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
1997 }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
2001 [user: user, other_user: other_user]
2004 clear_config(:suggestions)
2006 test "returns empty result when suggestions disabled", %{conn: conn, user: user} do
2007 Config.put([:suggestions, :enabled], false)
2011 |> assign(:user, user)
2012 |> get("/api/v1/suggestions")
2013 |> json_response(200)
2018 test "returns error", %{conn: conn, user: user} do
2019 Config.put([:suggestions, :enabled], true)
2020 Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
2022 assert capture_log(fn ->
2025 |> assign(:user, user)
2026 |> get("/api/v1/suggestions")
2027 |> json_response(500)
2029 assert res == "Something went wrong"
2030 end) =~ "Could not retrieve suggestions"
2033 test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do
2034 Config.put([:suggestions, :enabled], true)
2035 Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
2039 |> assign(:user, user)
2040 |> get("/api/v1/suggestions")
2041 |> json_response(200)
2046 "avatar" => "https://social.heldscal.la/avatar/201.jpeg",
2047 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
2051 "acct" => other_user.ap_id,
2052 "avatar" => "https://social.heldscal.la/avatar/202.jpeg",
2053 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
2054 "id" => other_user.id
2060 describe "PUT /api/v1/media/:id" do
2062 actor = insert(:user)
2064 file = %Plug.Upload{
2065 content_type: "image/jpg",
2066 path: Path.absname("test/fixtures/image.jpg"),
2067 filename: "an_image.jpg"
2070 {:ok, %Object{} = object} =
2073 actor: User.ap_id(actor),
2074 description: "test-m"
2077 [actor: actor, object: object]
2080 test "updates name of media", %{conn: conn, actor: actor, object: object} do
2083 |> assign(:user, actor)
2084 |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"})
2085 |> json_response(:ok)
2087 assert media["description"] == "test-media"
2088 assert refresh_record(object).data["name"] == "test-media"
2091 test "returns error wheb request is bad", %{conn: conn, actor: actor, object: object} do
2094 |> assign(:user, actor)
2095 |> put("/api/v1/media/#{object.id}", %{})
2096 |> json_response(400)
2098 assert media == %{"error" => "bad_request"}
2102 describe "DELETE /auth/sign_out" do
2103 test "redirect to root page", %{conn: conn} do
2104 user = insert(:user)
2108 |> assign(:user, user)
2109 |> delete("/auth/sign_out")
2111 assert conn.status == 302
2112 assert redirected_to(conn) == "/"
2116 describe "GET /api/v1/accounts/:id/lists - account_lists" do
2117 test "returns lists to which the account belongs", %{conn: conn} do
2118 user = insert(:user)
2119 other_user = insert(:user)
2120 assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user)
2121 {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
2125 |> assign(:user, user)
2126 |> get("/api/v1/accounts/#{other_user.id}/lists")
2127 |> json_response(200)
2129 assert res == [%{"id" => to_string(list.id), "title" => "Test List"}]
2133 describe "empty_array, stubs for mastodon api" do
2134 test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
2135 user = insert(:user)
2139 |> assign(:user, user)
2140 |> get("/api/v1/accounts/#{user.id}/identity_proofs")
2141 |> json_response(200)
2146 test "GET /api/v1/endorsements", %{conn: conn} do
2147 user = insert(:user)
2151 |> assign(:user, user)
2152 |> get("/api/v1/endorsements")
2153 |> json_response(200)
2158 test "GET /api/v1/trends", %{conn: conn} do
2159 user = insert(:user)
2163 |> assign(:user, user)
2164 |> get("/api/v1/trends")
2165 |> json_response(200)