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"]
404 describe "media upload" do
410 |> assign(:user, user)
412 image = %Plug.Upload{
413 content_type: "image/jpg",
414 path: Path.absname("test/fixtures/image.jpg"),
415 filename: "an_image.jpg"
418 [conn: conn, image: image]
421 clear_config([:media_proxy])
422 clear_config([Pleroma.Upload])
424 test "returns uploaded image", %{conn: conn, image: image} do
425 desc = "Description of the image"
429 |> post("/api/v1/media", %{"file" => image, "description" => desc})
430 |> json_response(:ok)
432 assert media["type"] == "image"
433 assert media["description"] == desc
436 object = Repo.get(Object, media["id"])
437 assert object.data["actor"] == User.ap_id(conn.assigns[:user])
441 describe "locked accounts" do
442 test "verify_credentials", %{conn: conn} do
443 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
447 |> assign(:user, user)
448 |> get("/api/v1/accounts/verify_credentials")
450 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
451 assert id == to_string(user.id)
455 describe "account fetching" do
456 test "works by id" do
461 |> get("/api/v1/accounts/#{user.id}")
463 assert %{"id" => id} = json_response(conn, 200)
464 assert id == to_string(user.id)
468 |> get("/api/v1/accounts/-1")
470 assert %{"error" => "Can't find user"} = json_response(conn, 404)
473 test "works by nickname" do
478 |> get("/api/v1/accounts/#{user.nickname}")
480 assert %{"id" => id} = json_response(conn, 200)
484 test "works by nickname for remote users" do
485 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
486 Pleroma.Config.put([:instance, :limit_to_local_content], false)
487 user = insert(:user, nickname: "user@example.com", local: false)
491 |> get("/api/v1/accounts/#{user.nickname}")
493 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
494 assert %{"id" => id} = json_response(conn, 200)
498 test "respects limit_to_local_content == :all for remote user nicknames" do
499 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
500 Pleroma.Config.put([:instance, :limit_to_local_content], :all)
502 user = insert(:user, nickname: "user@example.com", local: false)
506 |> get("/api/v1/accounts/#{user.nickname}")
508 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
509 assert json_response(conn, 404)
512 test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
513 limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
514 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
516 user = insert(:user, nickname: "user@example.com", local: false)
517 reading_user = insert(:user)
521 |> get("/api/v1/accounts/#{user.nickname}")
523 assert json_response(conn, 404)
527 |> assign(:user, reading_user)
528 |> get("/api/v1/accounts/#{user.nickname}")
530 Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
531 assert %{"id" => id} = json_response(conn, 200)
536 test "mascot upload", %{conn: conn} do
539 non_image_file = %Plug.Upload{
540 content_type: "audio/mpeg",
541 path: Path.absname("test/fixtures/sound.mp3"),
542 filename: "sound.mp3"
547 |> assign(:user, user)
548 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
550 assert json_response(conn, 415)
553 content_type: "image/jpg",
554 path: Path.absname("test/fixtures/image.jpg"),
555 filename: "an_image.jpg"
560 |> assign(:user, user)
561 |> put("/api/v1/pleroma/mascot", %{"file" => file})
563 assert %{"id" => _, "type" => image} = json_response(conn, 200)
566 test "mascot retrieving", %{conn: conn} do
568 # When user hasn't set a mascot, we should just get pleroma tan back
571 |> assign(:user, user)
572 |> get("/api/v1/pleroma/mascot")
574 assert %{"url" => url} = json_response(conn, 200)
575 assert url =~ "pleroma-fox-tan-smol"
577 # When a user sets their mascot, we should get that back
579 content_type: "image/jpg",
580 path: Path.absname("test/fixtures/image.jpg"),
581 filename: "an_image.jpg"
586 |> assign(:user, user)
587 |> put("/api/v1/pleroma/mascot", %{"file" => file})
589 assert json_response(conn, 200)
591 user = User.get_cached_by_id(user.id)
595 |> assign(:user, user)
596 |> get("/api/v1/pleroma/mascot")
598 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
599 assert url =~ "an_image"
602 test "getting followers", %{conn: conn} do
604 other_user = insert(:user)
605 {:ok, user} = User.follow(user, other_user)
609 |> get("/api/v1/accounts/#{other_user.id}/followers")
611 assert [%{"id" => id}] = json_response(conn, 200)
612 assert id == to_string(user.id)
615 test "getting followers, hide_followers", %{conn: conn} do
617 other_user = insert(:user, %{info: %{hide_followers: true}})
618 {:ok, _user} = User.follow(user, other_user)
622 |> get("/api/v1/accounts/#{other_user.id}/followers")
624 assert [] == json_response(conn, 200)
627 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
629 other_user = insert(:user, %{info: %{hide_followers: true}})
630 {:ok, _user} = User.follow(user, other_user)
634 |> assign(:user, other_user)
635 |> get("/api/v1/accounts/#{other_user.id}/followers")
637 refute [] == json_response(conn, 200)
640 test "getting followers, pagination", %{conn: conn} do
642 follower1 = insert(:user)
643 follower2 = insert(:user)
644 follower3 = insert(:user)
645 {:ok, _} = User.follow(follower1, user)
646 {:ok, _} = User.follow(follower2, user)
647 {:ok, _} = User.follow(follower3, user)
651 |> assign(:user, user)
655 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
657 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
658 assert id3 == follower3.id
659 assert id2 == follower2.id
663 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
665 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
666 assert id2 == follower2.id
667 assert id1 == follower1.id
671 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
673 assert [%{"id" => id2}] = json_response(res_conn, 200)
674 assert id2 == follower2.id
676 assert [link_header] = get_resp_header(res_conn, "link")
677 assert link_header =~ ~r/min_id=#{follower2.id}/
678 assert link_header =~ ~r/max_id=#{follower2.id}/
681 test "getting following", %{conn: conn} do
683 other_user = insert(:user)
684 {:ok, user} = User.follow(user, other_user)
688 |> get("/api/v1/accounts/#{user.id}/following")
690 assert [%{"id" => id}] = json_response(conn, 200)
691 assert id == to_string(other_user.id)
694 test "getting following, hide_follows", %{conn: conn} do
695 user = insert(:user, %{info: %{hide_follows: true}})
696 other_user = insert(:user)
697 {:ok, user} = User.follow(user, other_user)
701 |> get("/api/v1/accounts/#{user.id}/following")
703 assert [] == json_response(conn, 200)
706 test "getting following, hide_follows, same user requesting", %{conn: conn} do
707 user = insert(:user, %{info: %{hide_follows: true}})
708 other_user = insert(:user)
709 {:ok, user} = User.follow(user, other_user)
713 |> assign(:user, user)
714 |> get("/api/v1/accounts/#{user.id}/following")
716 refute [] == json_response(conn, 200)
719 test "getting following, pagination", %{conn: conn} do
721 following1 = insert(:user)
722 following2 = insert(:user)
723 following3 = insert(:user)
724 {:ok, _} = User.follow(user, following1)
725 {:ok, _} = User.follow(user, following2)
726 {:ok, _} = User.follow(user, following3)
730 |> assign(:user, user)
734 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
736 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
737 assert id3 == following3.id
738 assert id2 == following2.id
742 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
744 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
745 assert id2 == following2.id
746 assert id1 == following1.id
750 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
752 assert [%{"id" => id2}] = json_response(res_conn, 200)
753 assert id2 == following2.id
755 assert [link_header] = get_resp_header(res_conn, "link")
756 assert link_header =~ ~r/min_id=#{following2.id}/
757 assert link_header =~ ~r/max_id=#{following2.id}/
760 test "following / unfollowing a user", %{conn: conn} do
762 other_user = insert(:user)
766 |> assign(:user, user)
767 |> post("/api/v1/accounts/#{other_user.id}/follow")
769 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
771 user = User.get_cached_by_id(user.id)
775 |> assign(:user, user)
776 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
778 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
780 user = User.get_cached_by_id(user.id)
784 |> assign(:user, user)
785 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
787 assert %{"id" => id} = json_response(conn, 200)
788 assert id == to_string(other_user.id)
791 test "following without reblogs" do
792 follower = insert(:user)
793 followed = insert(:user)
794 other_user = insert(:user)
798 |> assign(:user, follower)
799 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
801 assert %{"showing_reblogs" => false} = json_response(conn, 200)
803 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
804 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
808 |> assign(:user, User.get_cached_by_id(follower.id))
809 |> get("/api/v1/timelines/home")
811 assert [] == json_response(conn, 200)
815 |> assign(:user, follower)
816 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
818 assert %{"showing_reblogs" => true} = json_response(conn, 200)
822 |> assign(:user, User.get_cached_by_id(follower.id))
823 |> get("/api/v1/timelines/home")
825 expected_activity_id = reblog.id
826 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
829 test "following / unfollowing errors" do
834 |> assign(:user, user)
837 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
838 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
841 user = User.get_cached_by_id(user.id)
842 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
843 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
845 # self follow via uri
846 user = User.get_cached_by_id(user.id)
847 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
848 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
850 # follow non existing user
851 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
852 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
854 # follow non existing user via uri
855 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
856 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
858 # unfollow non existing user
859 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
860 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
863 describe "mute/unmute" do
864 test "with notifications", %{conn: conn} do
866 other_user = insert(:user)
870 |> assign(:user, user)
871 |> post("/api/v1/accounts/#{other_user.id}/mute")
873 response = json_response(conn, 200)
875 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
876 user = User.get_cached_by_id(user.id)
880 |> assign(:user, user)
881 |> post("/api/v1/accounts/#{other_user.id}/unmute")
883 response = json_response(conn, 200)
884 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
887 test "without notifications", %{conn: conn} do
889 other_user = insert(:user)
893 |> assign(:user, user)
894 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
896 response = json_response(conn, 200)
898 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
899 user = User.get_cached_by_id(user.id)
903 |> assign(:user, user)
904 |> post("/api/v1/accounts/#{other_user.id}/unmute")
906 response = json_response(conn, 200)
907 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
911 test "subscribing / unsubscribing to a user", %{conn: conn} do
913 subscription_target = insert(:user)
917 |> assign(:user, user)
918 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
920 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
924 |> assign(:user, user)
925 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
927 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
930 test "getting a list of mutes", %{conn: conn} do
932 other_user = insert(:user)
934 {:ok, user} = User.mute(user, other_user)
938 |> assign(:user, user)
939 |> get("/api/v1/mutes")
941 other_user_id = to_string(other_user.id)
942 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
945 test "blocking / unblocking a user", %{conn: conn} do
947 other_user = insert(:user)
951 |> assign(:user, user)
952 |> post("/api/v1/accounts/#{other_user.id}/block")
954 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
956 user = User.get_cached_by_id(user.id)
960 |> assign(:user, user)
961 |> post("/api/v1/accounts/#{other_user.id}/unblock")
963 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
966 test "getting a list of blocks", %{conn: conn} do
968 other_user = insert(:user)
970 {:ok, user} = User.block(user, other_user)
974 |> assign(:user, user)
975 |> get("/api/v1/blocks")
977 other_user_id = to_string(other_user.id)
978 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
981 test "unimplemented follow_requests, blocks, domain blocks" do
984 ["blocks", "domain_blocks", "follow_requests"]
985 |> Enum.each(fn endpoint ->
988 |> assign(:user, user)
989 |> get("/api/v1/#{endpoint}")
991 assert [] = json_response(conn, 200)
995 test "returns the favorites of a user", %{conn: conn} do
997 other_user = insert(:user)
999 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1000 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1002 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1006 |> assign(:user, user)
1007 |> get("/api/v1/favourites")
1009 assert [status] = json_response(first_conn, 200)
1010 assert status["id"] == to_string(activity.id)
1012 assert [{"link", _link_header}] =
1013 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1015 # Honours query params
1016 {:ok, second_activity} =
1017 CommonAPI.post(other_user, %{
1019 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1022 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1024 last_like = status["id"]
1028 |> assign(:user, user)
1029 |> get("/api/v1/favourites?since_id=#{last_like}")
1031 assert [second_status] = json_response(second_conn, 200)
1032 assert second_status["id"] == to_string(second_activity.id)
1036 |> assign(:user, user)
1037 |> get("/api/v1/favourites?limit=0")
1039 assert [] = json_response(third_conn, 200)
1042 describe "getting favorites timeline of specified user" do
1044 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
1045 [current_user: current_user, user: user]
1048 test "returns list of statuses favorited by specified user", %{
1050 current_user: current_user,
1053 [activity | _] = insert_pair(:note_activity)
1054 CommonAPI.favorite(activity.id, user)
1058 |> assign(:user, current_user)
1059 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1060 |> json_response(:ok)
1064 assert length(response) == 1
1065 assert like["id"] == activity.id
1068 test "returns favorites for specified user_id when user is not logged in", %{
1072 activity = insert(:note_activity)
1073 CommonAPI.favorite(activity.id, user)
1077 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1078 |> json_response(:ok)
1080 assert length(response) == 1
1083 test "returns favorited DM only when user is logged in and he is one of recipients", %{
1085 current_user: current_user,
1089 CommonAPI.post(current_user, %{
1090 "status" => "Hi @#{user.nickname}!",
1091 "visibility" => "direct"
1094 CommonAPI.favorite(direct.id, user)
1098 |> assign(:user, current_user)
1099 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1100 |> json_response(:ok)
1102 assert length(response) == 1
1104 anonymous_response =
1106 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1107 |> json_response(:ok)
1109 assert Enum.empty?(anonymous_response)
1112 test "does not return others' favorited DM when user is not one of recipients", %{
1114 current_user: current_user,
1117 user_two = insert(:user)
1120 CommonAPI.post(user_two, %{
1121 "status" => "Hi @#{user.nickname}!",
1122 "visibility" => "direct"
1125 CommonAPI.favorite(direct.id, user)
1129 |> assign(:user, current_user)
1130 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1131 |> json_response(:ok)
1133 assert Enum.empty?(response)
1136 test "paginates favorites using since_id and max_id", %{
1138 current_user: current_user,
1141 activities = insert_list(10, :note_activity)
1143 Enum.each(activities, fn activity ->
1144 CommonAPI.favorite(activity.id, user)
1147 third_activity = Enum.at(activities, 2)
1148 seventh_activity = Enum.at(activities, 6)
1152 |> assign(:user, current_user)
1153 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
1154 since_id: third_activity.id,
1155 max_id: seventh_activity.id
1157 |> json_response(:ok)
1159 assert length(response) == 3
1160 refute third_activity in response
1161 refute seventh_activity in response
1164 test "limits favorites using limit parameter", %{
1166 current_user: current_user,
1170 |> insert_list(:note_activity)
1171 |> Enum.each(fn activity ->
1172 CommonAPI.favorite(activity.id, user)
1177 |> assign(:user, current_user)
1178 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
1179 |> json_response(:ok)
1181 assert length(response) == 3
1184 test "returns empty response when user does not have any favorited statuses", %{
1186 current_user: current_user,
1191 |> assign(:user, current_user)
1192 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1193 |> json_response(:ok)
1195 assert Enum.empty?(response)
1198 test "returns 404 error when specified user is not exist", %{conn: conn} do
1199 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
1201 assert json_response(conn, 404) == %{"error" => "Record not found"}
1204 test "returns 403 error when user has hidden own favorites", %{
1206 current_user: current_user
1208 user = insert(:user, %{info: %{hide_favorites: true}})
1209 activity = insert(:note_activity)
1210 CommonAPI.favorite(activity.id, user)
1214 |> assign(:user, current_user)
1215 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1217 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1220 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
1221 user = insert(:user)
1222 activity = insert(:note_activity)
1223 CommonAPI.favorite(activity.id, user)
1227 |> assign(:user, current_user)
1228 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
1230 assert user.info.hide_favorites
1231 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
1235 test "get instance information", %{conn: conn} do
1236 conn = get(conn, "/api/v1/instance")
1237 assert result = json_response(conn, 200)
1239 email = Config.get([:instance, :email])
1240 # Note: not checking for "max_toot_chars" since it's optional
1246 "email" => from_config_email,
1248 "streaming_api" => _
1253 "registrations" => _,
1257 assert email == from_config_email
1260 test "get instance stats", %{conn: conn} do
1261 user = insert(:user, %{local: true})
1263 user2 = insert(:user, %{local: true})
1264 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1266 insert(:user, %{local: false, nickname: "u@peer1.com"})
1267 insert(:user, %{local: false, nickname: "u@peer2.com"})
1269 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
1271 # Stats should count users with missing or nil `info.deactivated` value
1275 |> User.get_cached_by_id()
1276 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
1278 Pleroma.Stats.force_update()
1280 conn = get(conn, "/api/v1/instance")
1282 assert result = json_response(conn, 200)
1284 stats = result["stats"]
1287 assert stats["user_count"] == 1
1288 assert stats["status_count"] == 1
1289 assert stats["domain_count"] == 2
1292 test "get peers", %{conn: conn} do
1293 insert(:user, %{local: false, nickname: "u@peer1.com"})
1294 insert(:user, %{local: false, nickname: "u@peer2.com"})
1296 Pleroma.Stats.force_update()
1298 conn = get(conn, "/api/v1/instance/peers")
1300 assert result = json_response(conn, 200)
1302 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1305 test "put settings", %{conn: conn} do
1306 user = insert(:user)
1310 |> assign(:user, user)
1311 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1313 assert _result = json_response(conn, 200)
1315 user = User.get_cached_by_ap_id(user.ap_id)
1316 assert user.info.settings == %{"programming" => "socks"}
1319 describe "pinned statuses" do
1321 user = insert(:user)
1322 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
1324 [user: user, activity: activity]
1327 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
1328 {:ok, _} = CommonAPI.pin(activity.id, user)
1332 |> assign(:user, user)
1333 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1334 |> json_response(200)
1336 id_str = to_string(activity.id)
1338 assert [%{"id" => ^id_str, "pinned" => true}] = result
1342 describe "reports" do
1344 reporter = insert(:user)
1345 target_user = insert(:user)
1347 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
1349 [reporter: reporter, target_user: target_user, activity: activity]
1352 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
1353 assert %{"action_taken" => false, "id" => _} =
1355 |> assign(:user, reporter)
1356 |> post("/api/v1/reports", %{"account_id" => target_user.id})
1357 |> json_response(200)
1360 test "submit a report with statuses and comment", %{
1363 target_user: target_user,
1366 assert %{"action_taken" => false, "id" => _} =
1368 |> assign(:user, reporter)
1369 |> post("/api/v1/reports", %{
1370 "account_id" => target_user.id,
1371 "status_ids" => [activity.id],
1372 "comment" => "bad status!",
1373 "forward" => "false"
1375 |> json_response(200)
1378 test "account_id is required", %{
1383 assert %{"error" => "Valid `account_id` required"} =
1385 |> assign(:user, reporter)
1386 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
1387 |> json_response(400)
1390 test "comment must be up to the size specified in the config", %{
1393 target_user: target_user
1395 max_size = Config.get([:instance, :max_report_comment_size], 1000)
1396 comment = String.pad_trailing("a", max_size + 1, "a")
1398 error = %{"error" => "Comment must be up to #{max_size} characters"}
1402 |> assign(:user, reporter)
1403 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
1404 |> json_response(400)
1407 test "returns error when account is not exist", %{
1414 |> assign(:user, reporter)
1415 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
1417 assert json_response(conn, 400) == %{"error" => "Account not found"}
1421 describe "link headers" do
1422 test "preserves parameters in link headers", %{conn: conn} do
1423 user = insert(:user)
1424 other_user = insert(:user)
1427 CommonAPI.post(other_user, %{
1428 "status" => "hi @#{user.nickname}",
1429 "visibility" => "public"
1433 CommonAPI.post(other_user, %{
1434 "status" => "hi @#{user.nickname}",
1435 "visibility" => "public"
1438 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
1439 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
1443 |> assign(:user, user)
1444 |> get("/api/v1/notifications", %{media_only: true})
1446 assert [link_header] = get_resp_header(conn, "link")
1447 assert link_header =~ ~r/media_only=true/
1448 assert link_header =~ ~r/min_id=#{notification2.id}/
1449 assert link_header =~ ~r/max_id=#{notification1.id}/
1453 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
1454 # Need to set an old-style integer ID to reproduce the problem
1455 # (these are no longer assigned to new accounts but were preserved
1456 # for existing accounts during the migration to flakeIDs)
1457 user_one = insert(:user, %{id: 1212})
1458 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
1462 |> get("/api/v1/accounts/#{user_one.id}")
1466 |> get("/api/v1/accounts/#{user_two.nickname}")
1470 |> get("/api/v1/accounts/#{user_two.id}")
1472 acc_one = json_response(resp_one, 200)
1473 acc_two = json_response(resp_two, 200)
1474 acc_three = json_response(resp_three, 200)
1475 refute acc_one == acc_two
1476 assert acc_two == acc_three
1479 describe "custom emoji" do
1480 test "with tags", %{conn: conn} do
1483 |> get("/api/v1/custom_emojis")
1484 |> json_response(200)
1486 assert Map.has_key?(emoji, "shortcode")
1487 assert Map.has_key?(emoji, "static_url")
1488 assert Map.has_key?(emoji, "tags")
1489 assert is_list(emoji["tags"])
1490 assert Map.has_key?(emoji, "category")
1491 assert Map.has_key?(emoji, "url")
1492 assert Map.has_key?(emoji, "visible_in_picker")
1496 describe "index/2 redirections" do
1497 setup %{conn: conn} do
1501 signing_salt: "cooldude"
1506 |> Plug.Session.call(Plug.Session.init(session_opts))
1509 test_path = "/web/statuses/test"
1510 %{conn: conn, path: test_path}
1513 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
1514 conn = get(conn, path)
1516 assert conn.status == 302
1517 assert redirected_to(conn) == "/web/login"
1520 test "redirects not logged-in users to the login page on private instances", %{
1524 Config.put([:instance, :public], false)
1526 conn = get(conn, path)
1528 assert conn.status == 302
1529 assert redirected_to(conn) == "/web/login"
1532 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
1533 token = insert(:oauth_token)
1537 |> assign(:user, token.user)
1538 |> put_session(:oauth_token, token.token)
1541 assert conn.status == 200
1544 test "saves referer path to session", %{conn: conn, path: path} do
1545 conn = get(conn, path)
1546 return_to = Plug.Conn.get_session(conn, :return_to)
1548 assert return_to == path
1551 test "redirects to the saved path after log in", %{conn: conn, path: path} do
1552 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1553 auth = insert(:oauth_authorization, app: app)
1557 |> put_session(:return_to, path)
1558 |> get("/web/login", %{code: auth.token})
1560 assert conn.status == 302
1561 assert redirected_to(conn) == path
1564 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
1565 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
1566 auth = insert(:oauth_authorization, app: app)
1568 conn = get(conn, "/web/login", %{code: auth.token})
1570 assert conn.status == 302
1571 assert redirected_to(conn) == "/web/getting-started"
1575 describe "create account by app" do
1576 test "Account registration via Application", %{conn: conn} do
1579 |> post("/api/v1/apps", %{
1580 client_name: "client_name",
1581 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
1582 scopes: "read, write, follow"
1586 "client_id" => client_id,
1587 "client_secret" => client_secret,
1589 "name" => "client_name",
1590 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
1593 } = json_response(conn, 200)
1597 |> post("/oauth/token", %{
1598 grant_type: "client_credentials",
1599 client_id: client_id,
1600 client_secret: client_secret
1603 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
1604 json_response(conn, 200)
1607 token_from_db = Repo.get_by(Token, token: token)
1608 assert token_from_db
1610 assert scope == "read write follow"
1614 |> put_req_header("authorization", "Bearer " <> token)
1615 |> post("/api/v1/accounts", %{
1617 email: "lain@example.org",
1618 password: "PlzDontHackLain",
1623 "access_token" => token,
1624 "created_at" => _created_at,
1626 "token_type" => "Bearer"
1627 } = json_response(conn, 200)
1629 token_from_db = Repo.get_by(Token, token: token)
1630 assert token_from_db
1631 token_from_db = Repo.preload(token_from_db, :user)
1632 assert token_from_db.user
1634 assert token_from_db.user.info.confirmation_pending
1637 test "rate limit", %{conn: conn} do
1638 app_token = insert(:oauth_token, user: nil)
1641 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
1642 |> Map.put(:remote_ip, {15, 15, 15, 15})
1647 |> post("/api/v1/accounts", %{
1648 username: "#{i}lain",
1649 email: "#{i}lain@example.org",
1650 password: "PlzDontHackLain",
1655 "access_token" => token,
1656 "created_at" => _created_at,
1658 "token_type" => "Bearer"
1659 } = json_response(conn, 200)
1661 token_from_db = Repo.get_by(Token, token: token)
1662 assert token_from_db
1663 token_from_db = Repo.preload(token_from_db, :user)
1664 assert token_from_db.user
1666 assert token_from_db.user.info.confirmation_pending
1671 |> post("/api/v1/accounts", %{
1673 email: "6lain@example.org",
1674 password: "PlzDontHackLain",
1678 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
1682 describe "GET /api/v1/polls/:id" do
1683 test "returns poll entity for object id", %{conn: conn} do
1684 user = insert(:user)
1687 CommonAPI.post(user, %{
1688 "status" => "Pleroma does",
1689 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
1692 object = Object.normalize(activity)
1696 |> assign(:user, user)
1697 |> get("/api/v1/polls/#{object.id}")
1699 response = json_response(conn, 200)
1700 id = to_string(object.id)
1701 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
1704 test "does not expose polls for private statuses", %{conn: conn} do
1705 user = insert(:user)
1706 other_user = insert(:user)
1709 CommonAPI.post(user, %{
1710 "status" => "Pleroma does",
1711 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
1712 "visibility" => "private"
1715 object = Object.normalize(activity)
1719 |> assign(:user, other_user)
1720 |> get("/api/v1/polls/#{object.id}")
1722 assert json_response(conn, 404)
1726 describe "POST /api/v1/polls/:id/votes" do
1727 test "votes are added to the poll", %{conn: conn} do
1728 user = insert(:user)
1729 other_user = insert(:user)
1732 CommonAPI.post(user, %{
1733 "status" => "A very delicious sandwich",
1735 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
1741 object = Object.normalize(activity)
1745 |> assign(:user, other_user)
1746 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
1748 assert json_response(conn, 200)
1749 object = Object.get_by_id(object.id)
1751 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
1756 test "author can't vote", %{conn: conn} do
1757 user = insert(:user)
1760 CommonAPI.post(user, %{
1761 "status" => "Am I cute?",
1762 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
1765 object = Object.normalize(activity)
1768 |> assign(:user, user)
1769 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
1770 |> json_response(422) == %{"error" => "Poll's author can't vote"}
1772 object = Object.get_by_id(object.id)
1774 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
1777 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
1778 user = insert(:user)
1779 other_user = insert(:user)
1782 CommonAPI.post(user, %{
1783 "status" => "The glass is",
1784 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
1787 object = Object.normalize(activity)
1790 |> assign(:user, other_user)
1791 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
1792 |> json_response(422) == %{"error" => "Too many choices"}
1794 object = Object.get_by_id(object.id)
1796 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
1801 test "does not allow choice index to be greater than options count", %{conn: conn} do
1802 user = insert(:user)
1803 other_user = insert(:user)
1806 CommonAPI.post(user, %{
1807 "status" => "Am I cute?",
1808 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
1811 object = Object.normalize(activity)
1815 |> assign(:user, other_user)
1816 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
1818 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
1821 test "returns 404 error when object is not exist", %{conn: conn} do
1822 user = insert(:user)
1826 |> assign(:user, user)
1827 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
1829 assert json_response(conn, 404) == %{"error" => "Record not found"}
1832 test "returns 404 when poll is private and not available for user", %{conn: conn} do
1833 user = insert(:user)
1834 other_user = insert(:user)
1837 CommonAPI.post(user, %{
1838 "status" => "Am I cute?",
1839 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
1840 "visibility" => "private"
1843 object = Object.normalize(activity)
1847 |> assign(:user, other_user)
1848 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
1850 assert json_response(conn, 404) == %{"error" => "Record not found"}
1854 describe "POST /auth/password, with valid parameters" do
1855 setup %{conn: conn} do
1856 user = insert(:user)
1857 conn = post(conn, "/auth/password?email=#{user.email}")
1858 %{conn: conn, user: user}
1861 test "it returns 204", %{conn: conn} do
1862 assert json_response(conn, :no_content)
1865 test "it creates a PasswordResetToken record for user", %{user: user} do
1866 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1870 test "it sends an email to user", %{user: user} do
1871 ObanHelpers.perform_all()
1872 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
1874 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
1875 notify_email = Config.get([:instance, :notify_email])
1876 instance_name = Config.get([:instance, :name])
1879 from: {instance_name, notify_email},
1880 to: {user.name, user.email},
1881 html_body: email.html_body
1886 describe "POST /auth/password, with invalid parameters" do
1888 user = insert(:user)
1892 test "it returns 404 when user is not found", %{conn: conn, user: user} do
1893 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
1894 assert conn.status == 404
1895 assert conn.resp_body == ""
1898 test "it returns 400 when user is not local", %{conn: conn, user: user} do
1899 {:ok, user} = Repo.update(Changeset.change(user, local: false))
1900 conn = post(conn, "/auth/password?email=#{user.email}")
1901 assert conn.status == 400
1902 assert conn.resp_body == ""
1906 describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
1910 |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true))
1913 assert user.info.confirmation_pending
1918 clear_config([:instance, :account_activation_required]) do
1919 Config.put([:instance, :account_activation_required], true)
1922 test "resend account confirmation email", %{conn: conn, user: user} do
1924 |> assign(:user, user)
1925 |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
1926 |> json_response(:no_content)
1928 ObanHelpers.perform_all()
1930 email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
1931 notify_email = Config.get([:instance, :notify_email])
1932 instance_name = Config.get([:instance, :name])
1935 from: {instance_name, notify_email},
1936 to: {user.name, user.email},
1937 html_body: email.html_body
1942 describe "GET /api/v1/suggestions" do
1944 user = insert(:user)
1945 other_user = insert(:user)
1946 host = Config.get([Pleroma.Web.Endpoint, :url, :host])
1947 url500 = "http://test500?#{host}&#{user.nickname}"
1948 url200 = "http://test200?#{host}&#{user.nickname}"
1951 %{method: :get, url: ^url500} ->
1952 %Tesla.Env{status: 500, body: "bad request"}
1954 %{method: :get, url: ^url200} ->
1958 ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
1960 }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
1964 [user: user, other_user: other_user]
1967 clear_config(:suggestions)
1969 test "returns empty result when suggestions disabled", %{conn: conn, user: user} do
1970 Config.put([:suggestions, :enabled], false)
1974 |> assign(:user, user)
1975 |> get("/api/v1/suggestions")
1976 |> json_response(200)
1981 test "returns error", %{conn: conn, user: user} do
1982 Config.put([:suggestions, :enabled], true)
1983 Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
1985 assert capture_log(fn ->
1988 |> assign(:user, user)
1989 |> get("/api/v1/suggestions")
1990 |> json_response(500)
1992 assert res == "Something went wrong"
1993 end) =~ "Could not retrieve suggestions"
1996 test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do
1997 Config.put([:suggestions, :enabled], true)
1998 Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
2002 |> assign(:user, user)
2003 |> get("/api/v1/suggestions")
2004 |> json_response(200)
2009 "avatar" => "https://social.heldscal.la/avatar/201.jpeg",
2010 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
2014 "acct" => other_user.ap_id,
2015 "avatar" => "https://social.heldscal.la/avatar/202.jpeg",
2016 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
2017 "id" => other_user.id