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.ScheduledActivity
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Web.MastodonAPI.FilterView
18 alias Pleroma.Web.OAuth.App
19 alias Pleroma.Web.OAuth.Token
20 alias Pleroma.Web.OStatus
21 alias Pleroma.Web.Push
22 alias Pleroma.Web.TwitterAPI.TwitterAPI
23 import Pleroma.Factory
24 import ExUnit.CaptureLog
26 import Swoosh.TestAssertions
28 @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
31 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
35 test "the home timeline", %{conn: conn} do
37 following = insert(:user)
39 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
43 |> assign(:user, user)
44 |> get("/api/v1/timelines/home")
46 assert Enum.empty?(json_response(conn, 200))
48 {:ok, user} = User.follow(user, following)
52 |> assign(:user, user)
53 |> get("/api/v1/timelines/home")
55 assert [%{"content" => "test"}] = json_response(conn, 200)
58 test "the public timeline", %{conn: conn} do
59 following = insert(:user)
62 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
65 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
69 |> get("/api/v1/timelines/public", %{"local" => "False"})
71 assert length(json_response(conn, 200)) == 2
75 |> get("/api/v1/timelines/public", %{"local" => "True"})
77 assert [%{"content" => "test"}] = json_response(conn, 200)
81 |> get("/api/v1/timelines/public", %{"local" => "1"})
83 assert [%{"content" => "test"}] = json_response(conn, 200)
87 test "the public timeline when public is set to false", %{conn: conn} do
88 public = Pleroma.Config.get([:instance, :public])
89 Pleroma.Config.put([:instance, :public], false)
92 Pleroma.Config.put([:instance, :public], public)
96 |> get("/api/v1/timelines/public", %{"local" => "False"})
97 |> json_response(403) == %{"error" => "This resource requires authentication."}
100 describe "posting statuses" do
106 |> assign(:user, user)
111 test "posting a status", %{conn: conn} do
112 idempotency_key = "Pikachu rocks!"
116 |> put_req_header("idempotency-key", idempotency_key)
117 |> post("/api/v1/statuses", %{
119 "spoiler_text" => "2hu",
120 "sensitive" => "false"
123 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
125 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
127 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
128 json_response(conn_one, 200)
130 assert Activity.get_by_id(id)
134 |> put_req_header("idempotency-key", idempotency_key)
135 |> post("/api/v1/statuses", %{
137 "spoiler_text" => "2hu",
138 "sensitive" => "false"
141 assert %{"id" => second_id} = json_response(conn_two, 200)
142 assert id == second_id
146 |> post("/api/v1/statuses", %{
148 "spoiler_text" => "2hu",
149 "sensitive" => "false"
152 assert %{"id" => third_id} = json_response(conn_three, 200)
153 refute id == third_id
156 test "replying to a status", %{conn: conn} do
158 {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
162 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
164 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
166 activity = Activity.get_by_id(id)
168 assert activity.data["context"] == replied_to.data["context"]
169 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
172 test "replying to a direct message with visibility other than direct", %{conn: conn} do
174 {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
176 Enum.each(["public", "private", "unlisted"], fn visibility ->
179 |> post("/api/v1/statuses", %{
180 "status" => "@#{user.nickname} hey",
181 "in_reply_to_id" => replied_to.id,
182 "visibility" => visibility
185 assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
189 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
192 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
194 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
195 assert Activity.get_by_id(id)
198 test "posting a sensitive status", %{conn: conn} do
201 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
203 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
204 assert Activity.get_by_id(id)
207 test "posting a fake status", %{conn: conn} do
210 |> post("/api/v1/statuses", %{
212 "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
215 real_status = json_response(real_conn, 200)
218 assert Object.get_by_ap_id(real_status["uri"])
222 |> Map.put("id", nil)
223 |> Map.put("url", nil)
224 |> Map.put("uri", nil)
225 |> Map.put("created_at", nil)
226 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
230 |> post("/api/v1/statuses", %{
232 "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
236 fake_status = json_response(fake_conn, 200)
239 refute Object.get_by_ap_id(fake_status["uri"])
243 |> Map.put("id", nil)
244 |> Map.put("url", nil)
245 |> Map.put("uri", nil)
246 |> Map.put("created_at", nil)
247 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
249 assert real_status == fake_status
252 test "posting a status with OGP link preview", %{conn: conn} do
253 Pleroma.Config.put([:rich_media, :enabled], true)
257 |> post("/api/v1/statuses", %{
258 "status" => "https://example.com/ogp"
261 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
262 assert Activity.get_by_id(id)
263 Pleroma.Config.put([:rich_media, :enabled], false)
266 test "posting a direct status", %{conn: conn} do
267 user2 = insert(:user)
268 content = "direct cofe @#{user2.nickname}"
272 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
274 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
275 assert activity = Activity.get_by_id(id)
276 assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
277 assert activity.data["to"] == [user2.ap_id]
278 assert activity.data["cc"] == []
282 describe "posting polls" do
283 test "posting a poll", %{conn: conn} do
285 time = NaiveDateTime.utc_now()
289 |> assign(:user, user)
290 |> post("/api/v1/statuses", %{
291 "status" => "Who is the #bestgrill?",
292 "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
295 response = json_response(conn, 200)
297 assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
298 title in ["Rei", "Asuka", "Misato"]
301 assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
302 refute response["poll"]["expred"]
305 test "option limit is enforced", %{conn: conn} do
307 limit = Pleroma.Config.get([:instance, :poll_limits, :max_options])
311 |> assign(:user, user)
312 |> post("/api/v1/statuses", %{
314 "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
317 %{"error" => error} = json_response(conn, 422)
318 assert error == "Poll can't contain more than #{limit} options"
321 test "option character limit is enforced", %{conn: conn} do
323 limit = Pleroma.Config.get([:instance, :poll_limits, :max_option_chars])
327 |> assign(:user, user)
328 |> post("/api/v1/statuses", %{
331 "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
336 %{"error" => error} = json_response(conn, 422)
337 assert error == "Poll options cannot be longer than #{limit} characters each"
340 test "minimal date limit is enforced", %{conn: conn} do
342 limit = Pleroma.Config.get([:instance, :poll_limits, :min_expiration])
346 |> assign(:user, user)
347 |> post("/api/v1/statuses", %{
348 "status" => "imagine arbitrary limits",
350 "options" => ["this post was made by pleroma gang"],
351 "expires_in" => limit - 1
355 %{"error" => error} = json_response(conn, 422)
356 assert error == "Expiration date is too soon"
359 test "maximum date limit is enforced", %{conn: conn} do
361 limit = Pleroma.Config.get([:instance, :poll_limits, :max_expiration])
365 |> assign(:user, user)
366 |> post("/api/v1/statuses", %{
367 "status" => "imagine arbitrary limits",
369 "options" => ["this post was made by pleroma gang"],
370 "expires_in" => limit + 1
374 %{"error" => error} = json_response(conn, 422)
375 assert error == "Expiration date is too far in the future"
379 test "direct timeline", %{conn: conn} do
380 user_one = insert(:user)
381 user_two = insert(:user)
383 {:ok, user_two} = User.follow(user_two, user_one)
386 CommonAPI.post(user_one, %{
387 "status" => "Hi @#{user_two.nickname}!",
388 "visibility" => "direct"
391 {:ok, _follower_only} =
392 CommonAPI.post(user_one, %{
393 "status" => "Hi @#{user_two.nickname}!",
394 "visibility" => "private"
397 # Only direct should be visible here
400 |> assign(:user, user_two)
401 |> get("api/v1/timelines/direct")
403 [status] = json_response(res_conn, 200)
405 assert %{"visibility" => "direct"} = status
406 assert status["url"] != direct.data["id"]
408 # User should be able to see his own direct message
411 |> assign(:user, user_one)
412 |> get("api/v1/timelines/direct")
414 [status] = json_response(res_conn, 200)
416 assert %{"visibility" => "direct"} = status
418 # Both should be visible here
421 |> assign(:user, user_two)
422 |> get("api/v1/timelines/home")
424 [_s1, _s2] = json_response(res_conn, 200)
427 Enum.each(1..20, fn _ ->
429 CommonAPI.post(user_one, %{
430 "status" => "Hi @#{user_two.nickname}!",
431 "visibility" => "direct"
437 |> assign(:user, user_two)
438 |> get("api/v1/timelines/direct")
440 statuses = json_response(res_conn, 200)
441 assert length(statuses) == 20
445 |> assign(:user, user_two)
446 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
448 [status] = json_response(res_conn, 200)
450 assert status["url"] != direct.data["id"]
453 test "Conversations", %{conn: conn} do
454 user_one = insert(:user)
455 user_two = insert(:user)
456 user_three = insert(:user)
458 {:ok, user_two} = User.follow(user_two, user_one)
461 CommonAPI.post(user_one, %{
462 "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
463 "visibility" => "direct"
466 {:ok, _follower_only} =
467 CommonAPI.post(user_one, %{
468 "status" => "Hi @#{user_two.nickname}!",
469 "visibility" => "private"
474 |> assign(:user, user_one)
475 |> get("/api/v1/conversations")
477 assert response = json_response(res_conn, 200)
482 "accounts" => res_accounts,
483 "last_status" => res_last_status,
488 account_ids = Enum.map(res_accounts, & &1["id"])
489 assert length(res_accounts) == 2
490 assert user_two.id in account_ids
491 assert user_three.id in account_ids
492 assert is_binary(res_id)
493 assert unread == true
494 assert res_last_status["id"] == direct.id
496 # Apparently undocumented API endpoint
499 |> assign(:user, user_one)
500 |> post("/api/v1/conversations/#{res_id}/read")
502 assert response = json_response(res_conn, 200)
503 assert length(response["accounts"]) == 2
504 assert response["last_status"]["id"] == direct.id
505 assert response["unread"] == false
507 # (vanilla) Mastodon frontend behaviour
510 |> assign(:user, user_one)
511 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
513 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
516 test "doesn't include DMs from blocked users", %{conn: conn} do
517 blocker = insert(:user)
518 blocked = insert(:user)
520 {:ok, blocker} = User.block(blocker, blocked)
522 {:ok, _blocked_direct} =
523 CommonAPI.post(blocked, %{
524 "status" => "Hi @#{blocker.nickname}!",
525 "visibility" => "direct"
529 CommonAPI.post(user, %{
530 "status" => "Hi @#{blocker.nickname}!",
531 "visibility" => "direct"
536 |> assign(:user, user)
537 |> get("api/v1/timelines/direct")
539 [status] = json_response(res_conn, 200)
540 assert status["id"] == direct.id
543 test "verify_credentials", %{conn: conn} do
548 |> assign(:user, user)
549 |> get("/api/v1/accounts/verify_credentials")
551 response = json_response(conn, 200)
553 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
554 assert response["pleroma"]["chat_token"]
555 assert id == to_string(user.id)
558 test "verify_credentials default scope unlisted", %{conn: conn} do
559 user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
563 |> assign(:user, user)
564 |> get("/api/v1/accounts/verify_credentials")
566 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
567 assert id == to_string(user.id)
570 test "apps/verify_credentials", %{conn: conn} do
571 token = insert(:oauth_token)
575 |> assign(:user, token.user)
576 |> assign(:token, token)
577 |> get("/api/v1/apps/verify_credentials")
579 app = Repo.preload(token, :app).app
582 "name" => app.client_name,
583 "website" => app.website,
584 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
587 assert expected == json_response(conn, 200)
590 test "user avatar can be set", %{conn: conn} do
592 avatar_image = File.read!("test/fixtures/avatar_data_uri")
596 |> assign(:user, user)
597 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
599 user = refresh_record(user)
613 assert %{"url" => _} = json_response(conn, 200)
616 test "user avatar can be reset", %{conn: conn} do
621 |> assign(:user, user)
622 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
624 user = User.get_cached_by_id(user.id)
626 assert user.avatar == nil
628 assert %{"url" => nil} = json_response(conn, 200)
631 test "can set profile banner", %{conn: conn} do
636 |> assign(:user, user)
637 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
639 user = refresh_record(user)
640 assert user.info.banner["type"] == "Image"
642 assert %{"url" => _} = json_response(conn, 200)
645 test "can reset profile banner", %{conn: conn} do
650 |> assign(:user, user)
651 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
653 user = refresh_record(user)
654 assert user.info.banner == %{}
656 assert %{"url" => nil} = json_response(conn, 200)
659 test "background image can be set", %{conn: conn} do
664 |> assign(:user, user)
665 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
667 user = refresh_record(user)
668 assert user.info.background["type"] == "Image"
669 assert %{"url" => _} = json_response(conn, 200)
672 test "background image can be reset", %{conn: conn} do
677 |> assign(:user, user)
678 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
680 user = refresh_record(user)
681 assert user.info.background == %{}
682 assert %{"url" => nil} = json_response(conn, 200)
685 test "creates an oauth app", %{conn: conn} do
687 app_attrs = build(:oauth_app)
691 |> assign(:user, user)
692 |> post("/api/v1/apps", %{
693 client_name: app_attrs.client_name,
694 redirect_uris: app_attrs.redirect_uris
697 [app] = Repo.all(App)
700 "name" => app.client_name,
701 "website" => app.website,
702 "client_id" => app.client_id,
703 "client_secret" => app.client_secret,
704 "id" => app.id |> to_string(),
705 "redirect_uri" => app.redirect_uris,
706 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
709 assert expected == json_response(conn, 200)
712 test "get a status", %{conn: conn} do
713 activity = insert(:note_activity)
717 |> get("/api/v1/statuses/#{activity.id}")
719 assert %{"id" => id} = json_response(conn, 200)
720 assert id == to_string(activity.id)
723 describe "deleting a status" do
724 test "when you created it", %{conn: conn} do
725 activity = insert(:note_activity)
726 author = User.get_cached_by_ap_id(activity.data["actor"])
730 |> assign(:user, author)
731 |> delete("/api/v1/statuses/#{activity.id}")
733 assert %{} = json_response(conn, 200)
735 refute Activity.get_by_id(activity.id)
738 test "when you didn't create it", %{conn: conn} do
739 activity = insert(:note_activity)
744 |> assign(:user, user)
745 |> delete("/api/v1/statuses/#{activity.id}")
747 assert %{"error" => _} = json_response(conn, 403)
749 assert Activity.get_by_id(activity.id) == activity
752 test "when you're an admin or moderator", %{conn: conn} do
753 activity1 = insert(:note_activity)
754 activity2 = insert(:note_activity)
755 admin = insert(:user, info: %{is_admin: true})
756 moderator = insert(:user, info: %{is_moderator: true})
760 |> assign(:user, admin)
761 |> delete("/api/v1/statuses/#{activity1.id}")
763 assert %{} = json_response(res_conn, 200)
767 |> assign(:user, moderator)
768 |> delete("/api/v1/statuses/#{activity2.id}")
770 assert %{} = json_response(res_conn, 200)
772 refute Activity.get_by_id(activity1.id)
773 refute Activity.get_by_id(activity2.id)
777 describe "filters" do
778 test "creating a filter", %{conn: conn} do
781 filter = %Pleroma.Filter{
788 |> assign(:user, user)
789 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
791 assert response = json_response(conn, 200)
792 assert response["phrase"] == filter.phrase
793 assert response["context"] == filter.context
794 assert response["irreversible"] == false
795 assert response["id"] != nil
796 assert response["id"] != ""
799 test "fetching a list of filters", %{conn: conn} do
802 query_one = %Pleroma.Filter{
809 query_two = %Pleroma.Filter{
816 {:ok, filter_one} = Pleroma.Filter.create(query_one)
817 {:ok, filter_two} = Pleroma.Filter.create(query_two)
821 |> assign(:user, user)
822 |> get("/api/v1/filters")
823 |> json_response(200)
829 filters: [filter_two, filter_one]
833 test "get a filter", %{conn: conn} do
836 query = %Pleroma.Filter{
843 {:ok, filter} = Pleroma.Filter.create(query)
847 |> assign(:user, user)
848 |> get("/api/v1/filters/#{filter.filter_id}")
850 assert _response = json_response(conn, 200)
853 test "update a filter", %{conn: conn} do
856 query = %Pleroma.Filter{
863 {:ok, _filter} = Pleroma.Filter.create(query)
865 new = %Pleroma.Filter{
872 |> assign(:user, user)
873 |> put("/api/v1/filters/#{query.filter_id}", %{
878 assert response = json_response(conn, 200)
879 assert response["phrase"] == new.phrase
880 assert response["context"] == new.context
883 test "delete a filter", %{conn: conn} do
886 query = %Pleroma.Filter{
893 {:ok, filter} = Pleroma.Filter.create(query)
897 |> assign(:user, user)
898 |> delete("/api/v1/filters/#{filter.filter_id}")
900 assert response = json_response(conn, 200)
901 assert response == %{}
906 test "creating a list", %{conn: conn} do
911 |> assign(:user, user)
912 |> post("/api/v1/lists", %{"title" => "cuties"})
914 assert %{"title" => title} = json_response(conn, 200)
915 assert title == "cuties"
918 test "adding users to a list", %{conn: conn} do
920 other_user = insert(:user)
921 {:ok, list} = Pleroma.List.create("name", user)
925 |> assign(:user, user)
926 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
928 assert %{} == json_response(conn, 200)
929 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
930 assert following == [other_user.follower_address]
933 test "removing users from a list", %{conn: conn} do
935 other_user = insert(:user)
936 third_user = insert(:user)
937 {:ok, list} = Pleroma.List.create("name", user)
938 {:ok, list} = Pleroma.List.follow(list, other_user)
939 {:ok, list} = Pleroma.List.follow(list, third_user)
943 |> assign(:user, user)
944 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
946 assert %{} == json_response(conn, 200)
947 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
948 assert following == [third_user.follower_address]
951 test "listing users in a list", %{conn: conn} do
953 other_user = insert(:user)
954 {:ok, list} = Pleroma.List.create("name", user)
955 {:ok, list} = Pleroma.List.follow(list, other_user)
959 |> assign(:user, user)
960 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
962 assert [%{"id" => id}] = json_response(conn, 200)
963 assert id == to_string(other_user.id)
966 test "retrieving a list", %{conn: conn} do
968 {:ok, list} = Pleroma.List.create("name", user)
972 |> assign(:user, user)
973 |> get("/api/v1/lists/#{list.id}")
975 assert %{"id" => id} = json_response(conn, 200)
976 assert id == to_string(list.id)
979 test "renaming a list", %{conn: conn} do
981 {:ok, list} = Pleroma.List.create("name", user)
985 |> assign(:user, user)
986 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
988 assert %{"title" => name} = json_response(conn, 200)
989 assert name == "newname"
992 test "deleting a list", %{conn: conn} do
994 {:ok, list} = Pleroma.List.create("name", user)
998 |> assign(:user, user)
999 |> delete("/api/v1/lists/#{list.id}")
1001 assert %{} = json_response(conn, 200)
1002 assert is_nil(Repo.get(Pleroma.List, list.id))
1005 test "list timeline", %{conn: conn} do
1006 user = insert(:user)
1007 other_user = insert(:user)
1008 {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."})
1009 {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
1010 {:ok, list} = Pleroma.List.create("name", user)
1011 {:ok, list} = Pleroma.List.follow(list, other_user)
1015 |> assign(:user, user)
1016 |> get("/api/v1/timelines/list/#{list.id}")
1018 assert [%{"id" => id}] = json_response(conn, 200)
1020 assert id == to_string(activity_two.id)
1023 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
1024 user = insert(:user)
1025 other_user = insert(:user)
1026 {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
1028 {:ok, _activity_two} =
1029 CommonAPI.post(other_user, %{
1030 "status" => "Marisa is cute.",
1031 "visibility" => "private"
1034 {:ok, list} = Pleroma.List.create("name", user)
1035 {:ok, list} = Pleroma.List.follow(list, other_user)
1039 |> assign(:user, user)
1040 |> get("/api/v1/timelines/list/#{list.id}")
1042 assert [%{"id" => id}] = json_response(conn, 200)
1044 assert id == to_string(activity_one.id)
1048 describe "notifications" do
1049 test "list of notifications", %{conn: conn} do
1050 user = insert(:user)
1051 other_user = insert(:user)
1053 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1055 {:ok, [_notification]} = Notification.create_notifications(activity)
1059 |> assign(:user, user)
1060 |> get("/api/v1/notifications")
1063 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
1065 }\">@<span>#{user.nickname}</span></a></span>"
1067 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
1068 assert response == expected_response
1071 test "getting a single notification", %{conn: conn} do
1072 user = insert(:user)
1073 other_user = insert(:user)
1075 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1077 {:ok, [notification]} = Notification.create_notifications(activity)
1081 |> assign(:user, user)
1082 |> get("/api/v1/notifications/#{notification.id}")
1085 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
1087 }\">@<span>#{user.nickname}</span></a></span>"
1089 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
1090 assert response == expected_response
1093 test "dismissing a single notification", %{conn: conn} do
1094 user = insert(:user)
1095 other_user = insert(:user)
1097 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1099 {:ok, [notification]} = Notification.create_notifications(activity)
1103 |> assign(:user, user)
1104 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
1106 assert %{} = json_response(conn, 200)
1109 test "clearing all notifications", %{conn: conn} do
1110 user = insert(:user)
1111 other_user = insert(:user)
1113 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1115 {:ok, [_notification]} = Notification.create_notifications(activity)
1119 |> assign(:user, user)
1120 |> post("/api/v1/notifications/clear")
1122 assert %{} = json_response(conn, 200)
1126 |> assign(:user, user)
1127 |> get("/api/v1/notifications")
1129 assert all = json_response(conn, 200)
1133 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
1134 user = insert(:user)
1135 other_user = insert(:user)
1137 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1138 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1139 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1140 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1142 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1143 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1144 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1145 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1149 |> assign(:user, user)
1154 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
1156 result = json_response(conn_res, 200)
1157 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
1162 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
1164 result = json_response(conn_res, 200)
1165 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1170 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
1172 result = json_response(conn_res, 200)
1173 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
1176 test "filters notifications using exclude_types", %{conn: conn} do
1177 user = insert(:user)
1178 other_user = insert(:user)
1180 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
1181 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
1182 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
1183 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
1184 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
1186 mention_notification_id =
1187 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
1189 favorite_notification_id =
1190 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
1192 reblog_notification_id =
1193 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
1195 follow_notification_id =
1196 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
1200 |> assign(:user, user)
1203 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
1205 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
1208 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
1210 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
1213 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
1215 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1218 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1220 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1223 test "destroy multiple", %{conn: conn} do
1224 user = insert(:user)
1225 other_user = insert(:user)
1227 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1228 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1229 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1230 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1232 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1233 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1234 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1235 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1239 |> assign(:user, user)
1243 |> get("/api/v1/notifications")
1245 result = json_response(conn_res, 200)
1246 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1250 |> assign(:user, other_user)
1254 |> get("/api/v1/notifications")
1256 result = json_response(conn_res, 200)
1257 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1261 |> delete("/api/v1/notifications/destroy_multiple", %{
1262 "ids" => [notification1_id, notification2_id]
1265 assert json_response(conn_destroy, 200) == %{}
1269 |> get("/api/v1/notifications")
1271 result = json_response(conn_res, 200)
1272 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1275 test "doesn't see notifications after muting user with notifications", %{conn: conn} do
1276 user = insert(:user)
1277 user2 = insert(:user)
1279 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1280 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1282 conn = assign(conn, :user, user)
1284 conn = get(conn, "/api/v1/notifications")
1286 assert length(json_response(conn, 200)) == 1
1288 {:ok, user} = User.mute(user, user2)
1290 conn = assign(build_conn(), :user, user)
1291 conn = get(conn, "/api/v1/notifications")
1293 assert json_response(conn, 200) == []
1296 test "see notifications after muting user without notifications", %{conn: conn} do
1297 user = insert(:user)
1298 user2 = insert(:user)
1300 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1301 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1303 conn = assign(conn, :user, user)
1305 conn = get(conn, "/api/v1/notifications")
1307 assert length(json_response(conn, 200)) == 1
1309 {:ok, user} = User.mute(user, user2, false)
1311 conn = assign(build_conn(), :user, user)
1312 conn = get(conn, "/api/v1/notifications")
1314 assert length(json_response(conn, 200)) == 1
1317 test "see notifications after muting user with notifications and with_muted parameter", %{
1320 user = insert(:user)
1321 user2 = insert(:user)
1323 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1324 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1326 conn = assign(conn, :user, user)
1328 conn = get(conn, "/api/v1/notifications")
1330 assert length(json_response(conn, 200)) == 1
1332 {:ok, user} = User.mute(user, user2)
1334 conn = assign(build_conn(), :user, user)
1335 conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"})
1337 assert length(json_response(conn, 200)) == 1
1341 describe "reblogging" do
1342 test "reblogs and returns the reblogged status", %{conn: conn} do
1343 activity = insert(:note_activity)
1344 user = insert(:user)
1348 |> assign(:user, user)
1349 |> post("/api/v1/statuses/#{activity.id}/reblog")
1352 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1354 } = json_response(conn, 200)
1356 assert to_string(activity.id) == id
1359 test "reblogged status for another user", %{conn: conn} do
1360 activity = insert(:note_activity)
1361 user1 = insert(:user)
1362 user2 = insert(:user)
1363 user3 = insert(:user)
1364 CommonAPI.favorite(activity.id, user2)
1365 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1366 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1367 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1371 |> assign(:user, user3)
1372 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1375 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1376 "reblogged" => false,
1377 "favourited" => false,
1378 "bookmarked" => false
1379 } = json_response(conn_res, 200)
1383 |> assign(:user, user2)
1384 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1387 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1388 "reblogged" => true,
1389 "favourited" => true,
1390 "bookmarked" => true
1391 } = json_response(conn_res, 200)
1393 assert to_string(activity.id) == id
1396 test "returns 400 error when activity is not exist", %{conn: conn} do
1397 user = insert(:user)
1401 |> assign(:user, user)
1402 |> post("/api/v1/statuses/foo/reblog")
1404 assert json_response(conn, 400) == %{"error" => "Could not repeat"}
1408 describe "unreblogging" do
1409 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1410 activity = insert(:note_activity)
1411 user = insert(:user)
1413 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1417 |> assign(:user, user)
1418 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1420 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1422 assert to_string(activity.id) == id
1425 test "returns 400 error when activity is not exist", %{conn: conn} do
1426 user = insert(:user)
1430 |> assign(:user, user)
1431 |> post("/api/v1/statuses/foo/unreblog")
1433 assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
1437 describe "favoriting" do
1438 test "favs a status and returns it", %{conn: conn} do
1439 activity = insert(:note_activity)
1440 user = insert(:user)
1444 |> assign(:user, user)
1445 |> post("/api/v1/statuses/#{activity.id}/favourite")
1447 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1448 json_response(conn, 200)
1450 assert to_string(activity.id) == id
1453 test "returns 400 error for a wrong id", %{conn: conn} do
1454 user = insert(:user)
1458 |> assign(:user, user)
1459 |> post("/api/v1/statuses/1/favourite")
1461 assert json_response(conn, 400) == %{"error" => "Could not favorite"}
1465 describe "unfavoriting" do
1466 test "unfavorites a status and returns it", %{conn: conn} do
1467 activity = insert(:note_activity)
1468 user = insert(:user)
1470 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1474 |> assign(:user, user)
1475 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1477 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1478 json_response(conn, 200)
1480 assert to_string(activity.id) == id
1483 test "returns 400 error for a wrong id", %{conn: conn} do
1484 user = insert(:user)
1488 |> assign(:user, user)
1489 |> post("/api/v1/statuses/1/unfavourite")
1491 assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
1495 describe "user timelines" do
1496 test "gets a users statuses", %{conn: conn} do
1497 user_one = insert(:user)
1498 user_two = insert(:user)
1499 user_three = insert(:user)
1501 {:ok, user_three} = User.follow(user_three, user_one)
1503 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1505 {:ok, direct_activity} =
1506 CommonAPI.post(user_one, %{
1507 "status" => "Hi, @#{user_two.nickname}.",
1508 "visibility" => "direct"
1511 {:ok, private_activity} =
1512 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1516 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1518 assert [%{"id" => id}] = json_response(resp, 200)
1519 assert id == to_string(activity.id)
1523 |> assign(:user, user_two)
1524 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1526 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1527 assert id_one == to_string(direct_activity.id)
1528 assert id_two == to_string(activity.id)
1532 |> assign(:user, user_three)
1533 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1535 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1536 assert id_one == to_string(private_activity.id)
1537 assert id_two == to_string(activity.id)
1540 test "unimplemented pinned statuses feature", %{conn: conn} do
1541 note = insert(:note_activity)
1542 user = User.get_cached_by_ap_id(note.data["actor"])
1546 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1548 assert json_response(conn, 200) == []
1551 test "gets an users media", %{conn: conn} do
1552 note = insert(:note_activity)
1553 user = User.get_cached_by_ap_id(note.data["actor"])
1555 file = %Plug.Upload{
1556 content_type: "image/jpg",
1557 path: Path.absname("test/fixtures/image.jpg"),
1558 filename: "an_image.jpg"
1562 TwitterAPI.upload(file, user, "json")
1566 CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1570 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1572 assert [%{"id" => id}] = json_response(conn, 200)
1573 assert id == to_string(image_post.id)
1577 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1579 assert [%{"id" => id}] = json_response(conn, 200)
1580 assert id == to_string(image_post.id)
1583 test "gets a user's statuses without reblogs", %{conn: conn} do
1584 user = insert(:user)
1585 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1586 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1590 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1592 assert [%{"id" => id}] = json_response(conn, 200)
1593 assert id == to_string(post.id)
1597 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1599 assert [%{"id" => id}] = json_response(conn, 200)
1600 assert id == to_string(post.id)
1603 test "filters user's statuses by a hashtag", %{conn: conn} do
1604 user = insert(:user)
1605 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
1606 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
1610 |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
1612 assert [%{"id" => id}] = json_response(conn, 200)
1613 assert id == to_string(post.id)
1617 describe "user relationships" do
1618 test "returns the relationships for the current user", %{conn: conn} do
1619 user = insert(:user)
1620 other_user = insert(:user)
1621 {:ok, user} = User.follow(user, other_user)
1625 |> assign(:user, user)
1626 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1628 assert [relationship] = json_response(conn, 200)
1630 assert to_string(other_user.id) == relationship["id"]
1634 describe "media upload" do
1636 upload_config = Pleroma.Config.get([Pleroma.Upload])
1637 proxy_config = Pleroma.Config.get([:media_proxy])
1640 Pleroma.Config.put([Pleroma.Upload], upload_config)
1641 Pleroma.Config.put([:media_proxy], proxy_config)
1644 user = insert(:user)
1648 |> assign(:user, user)
1650 image = %Plug.Upload{
1651 content_type: "image/jpg",
1652 path: Path.absname("test/fixtures/image.jpg"),
1653 filename: "an_image.jpg"
1656 [conn: conn, image: image]
1659 test "returns uploaded image", %{conn: conn, image: image} do
1660 desc = "Description of the image"
1664 |> post("/api/v1/media", %{"file" => image, "description" => desc})
1665 |> json_response(:ok)
1667 assert media["type"] == "image"
1668 assert media["description"] == desc
1671 object = Repo.get(Object, media["id"])
1672 assert object.data["actor"] == User.ap_id(conn.assigns[:user])
1675 test "returns proxied url when media proxy is enabled", %{conn: conn, image: image} do
1676 Pleroma.Config.put([Pleroma.Upload, :base_url], "https://media.pleroma.social")
1678 proxy_url = "https://cache.pleroma.social"
1679 Pleroma.Config.put([:media_proxy, :enabled], true)
1680 Pleroma.Config.put([:media_proxy, :base_url], proxy_url)
1684 |> post("/api/v1/media", %{"file" => image})
1685 |> json_response(:ok)
1687 assert String.starts_with?(media["url"], proxy_url)
1690 test "returns media url when proxy is enabled but media url is whitelisted", %{
1694 media_url = "https://media.pleroma.social"
1695 Pleroma.Config.put([Pleroma.Upload, :base_url], media_url)
1697 Pleroma.Config.put([:media_proxy, :enabled], true)
1698 Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social")
1699 Pleroma.Config.put([:media_proxy, :whitelist], ["media.pleroma.social"])
1703 |> post("/api/v1/media", %{"file" => image})
1704 |> json_response(:ok)
1706 assert String.starts_with?(media["url"], media_url)
1710 describe "locked accounts" do
1711 test "/api/v1/follow_requests works" do
1712 user = insert(:user, %{info: %User.Info{locked: true}})
1713 other_user = insert(:user)
1715 {:ok, _activity} = ActivityPub.follow(other_user, user)
1717 user = User.get_cached_by_id(user.id)
1718 other_user = User.get_cached_by_id(other_user.id)
1720 assert User.following?(other_user, user) == false
1724 |> assign(:user, user)
1725 |> get("/api/v1/follow_requests")
1727 assert [relationship] = json_response(conn, 200)
1728 assert to_string(other_user.id) == relationship["id"]
1731 test "/api/v1/follow_requests/:id/authorize works" do
1732 user = insert(:user, %{info: %User.Info{locked: true}})
1733 other_user = insert(:user)
1735 {:ok, _activity} = ActivityPub.follow(other_user, user)
1737 user = User.get_cached_by_id(user.id)
1738 other_user = User.get_cached_by_id(other_user.id)
1740 assert User.following?(other_user, user) == false
1744 |> assign(:user, user)
1745 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1747 assert relationship = json_response(conn, 200)
1748 assert to_string(other_user.id) == relationship["id"]
1750 user = User.get_cached_by_id(user.id)
1751 other_user = User.get_cached_by_id(other_user.id)
1753 assert User.following?(other_user, user) == true
1756 test "verify_credentials", %{conn: conn} do
1757 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
1761 |> assign(:user, user)
1762 |> get("/api/v1/accounts/verify_credentials")
1764 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1765 assert id == to_string(user.id)
1768 test "/api/v1/follow_requests/:id/reject works" do
1769 user = insert(:user, %{info: %User.Info{locked: true}})
1770 other_user = insert(:user)
1772 {:ok, _activity} = ActivityPub.follow(other_user, user)
1774 user = User.get_cached_by_id(user.id)
1778 |> assign(:user, user)
1779 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1781 assert relationship = json_response(conn, 200)
1782 assert to_string(other_user.id) == relationship["id"]
1784 user = User.get_cached_by_id(user.id)
1785 other_user = User.get_cached_by_id(other_user.id)
1787 assert User.following?(other_user, user) == false
1791 test "account fetching", %{conn: conn} do
1792 user = insert(:user)
1796 |> get("/api/v1/accounts/#{user.id}")
1798 assert %{"id" => id} = json_response(conn, 200)
1799 assert id == to_string(user.id)
1803 |> get("/api/v1/accounts/-1")
1805 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1808 test "account fetching also works nickname", %{conn: conn} do
1809 user = insert(:user)
1813 |> get("/api/v1/accounts/#{user.nickname}")
1815 assert %{"id" => id} = json_response(conn, 200)
1816 assert id == user.id
1819 test "mascot upload", %{conn: conn} do
1820 user = insert(:user)
1822 non_image_file = %Plug.Upload{
1823 content_type: "audio/mpeg",
1824 path: Path.absname("test/fixtures/sound.mp3"),
1825 filename: "sound.mp3"
1830 |> assign(:user, user)
1831 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
1833 assert json_response(conn, 415)
1835 file = %Plug.Upload{
1836 content_type: "image/jpg",
1837 path: Path.absname("test/fixtures/image.jpg"),
1838 filename: "an_image.jpg"
1843 |> assign(:user, user)
1844 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1846 assert %{"id" => _, "type" => image} = json_response(conn, 200)
1849 test "mascot retrieving", %{conn: conn} do
1850 user = insert(:user)
1851 # When user hasn't set a mascot, we should just get pleroma tan back
1854 |> assign(:user, user)
1855 |> get("/api/v1/pleroma/mascot")
1857 assert %{"url" => url} = json_response(conn, 200)
1858 assert url =~ "pleroma-fox-tan-smol"
1860 # When a user sets their mascot, we should get that back
1861 file = %Plug.Upload{
1862 content_type: "image/jpg",
1863 path: Path.absname("test/fixtures/image.jpg"),
1864 filename: "an_image.jpg"
1869 |> assign(:user, user)
1870 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1872 assert json_response(conn, 200)
1874 user = User.get_cached_by_id(user.id)
1878 |> assign(:user, user)
1879 |> get("/api/v1/pleroma/mascot")
1881 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
1882 assert url =~ "an_image"
1885 test "hashtag timeline", %{conn: conn} do
1886 following = insert(:user)
1889 {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
1891 {:ok, [_activity]} =
1892 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1896 |> get("/api/v1/timelines/tag/2hu")
1898 assert [%{"id" => id}] = json_response(nconn, 200)
1900 assert id == to_string(activity.id)
1902 # works for different capitalization too
1905 |> get("/api/v1/timelines/tag/2HU")
1907 assert [%{"id" => id}] = json_response(nconn, 200)
1909 assert id == to_string(activity.id)
1913 test "multi-hashtag timeline", %{conn: conn} do
1914 user = insert(:user)
1916 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1917 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1918 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1922 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1924 [status_none, status_test1, status_test] = json_response(any_test, 200)
1926 assert to_string(activity_test.id) == status_test["id"]
1927 assert to_string(activity_test1.id) == status_test1["id"]
1928 assert to_string(activity_none.id) == status_none["id"]
1932 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1934 assert [status_test1] == json_response(restricted_test, 200)
1936 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1938 assert [status_none] == json_response(all_test, 200)
1941 test "getting followers", %{conn: conn} do
1942 user = insert(:user)
1943 other_user = insert(:user)
1944 {:ok, user} = User.follow(user, other_user)
1948 |> get("/api/v1/accounts/#{other_user.id}/followers")
1950 assert [%{"id" => id}] = json_response(conn, 200)
1951 assert id == to_string(user.id)
1954 test "getting followers, hide_followers", %{conn: conn} do
1955 user = insert(:user)
1956 other_user = insert(:user, %{info: %{hide_followers: true}})
1957 {:ok, _user} = User.follow(user, other_user)
1961 |> get("/api/v1/accounts/#{other_user.id}/followers")
1963 assert [] == json_response(conn, 200)
1966 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1967 user = insert(:user)
1968 other_user = insert(:user, %{info: %{hide_followers: true}})
1969 {:ok, _user} = User.follow(user, other_user)
1973 |> assign(:user, other_user)
1974 |> get("/api/v1/accounts/#{other_user.id}/followers")
1976 refute [] == json_response(conn, 200)
1979 test "getting followers, pagination", %{conn: conn} do
1980 user = insert(:user)
1981 follower1 = insert(:user)
1982 follower2 = insert(:user)
1983 follower3 = insert(:user)
1984 {:ok, _} = User.follow(follower1, user)
1985 {:ok, _} = User.follow(follower2, user)
1986 {:ok, _} = User.follow(follower3, user)
1990 |> assign(:user, user)
1994 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1996 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1997 assert id3 == follower3.id
1998 assert id2 == follower2.id
2002 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
2004 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
2005 assert id2 == follower2.id
2006 assert id1 == follower1.id
2010 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
2012 assert [%{"id" => id2}] = json_response(res_conn, 200)
2013 assert id2 == follower2.id
2015 assert [link_header] = get_resp_header(res_conn, "link")
2016 assert link_header =~ ~r/min_id=#{follower2.id}/
2017 assert link_header =~ ~r/max_id=#{follower2.id}/
2020 test "getting following", %{conn: conn} do
2021 user = insert(:user)
2022 other_user = insert(:user)
2023 {:ok, user} = User.follow(user, other_user)
2027 |> get("/api/v1/accounts/#{user.id}/following")
2029 assert [%{"id" => id}] = json_response(conn, 200)
2030 assert id == to_string(other_user.id)
2033 test "getting following, hide_follows", %{conn: conn} do
2034 user = insert(:user, %{info: %{hide_follows: true}})
2035 other_user = insert(:user)
2036 {:ok, user} = User.follow(user, other_user)
2040 |> get("/api/v1/accounts/#{user.id}/following")
2042 assert [] == json_response(conn, 200)
2045 test "getting following, hide_follows, same user requesting", %{conn: conn} do
2046 user = insert(:user, %{info: %{hide_follows: true}})
2047 other_user = insert(:user)
2048 {:ok, user} = User.follow(user, other_user)
2052 |> assign(:user, user)
2053 |> get("/api/v1/accounts/#{user.id}/following")
2055 refute [] == json_response(conn, 200)
2058 test "getting following, pagination", %{conn: conn} do
2059 user = insert(:user)
2060 following1 = insert(:user)
2061 following2 = insert(:user)
2062 following3 = insert(:user)
2063 {:ok, _} = User.follow(user, following1)
2064 {:ok, _} = User.follow(user, following2)
2065 {:ok, _} = User.follow(user, following3)
2069 |> assign(:user, user)
2073 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
2075 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
2076 assert id3 == following3.id
2077 assert id2 == following2.id
2081 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
2083 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
2084 assert id2 == following2.id
2085 assert id1 == following1.id
2089 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
2091 assert [%{"id" => id2}] = json_response(res_conn, 200)
2092 assert id2 == following2.id
2094 assert [link_header] = get_resp_header(res_conn, "link")
2095 assert link_header =~ ~r/min_id=#{following2.id}/
2096 assert link_header =~ ~r/max_id=#{following2.id}/
2099 test "following / unfollowing a user", %{conn: conn} do
2100 user = insert(:user)
2101 other_user = insert(:user)
2105 |> assign(:user, user)
2106 |> post("/api/v1/accounts/#{other_user.id}/follow")
2108 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
2110 user = User.get_cached_by_id(user.id)
2114 |> assign(:user, user)
2115 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
2117 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
2119 user = User.get_cached_by_id(user.id)
2123 |> assign(:user, user)
2124 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
2126 assert %{"id" => id} = json_response(conn, 200)
2127 assert id == to_string(other_user.id)
2130 test "following without reblogs" do
2131 follower = insert(:user)
2132 followed = insert(:user)
2133 other_user = insert(:user)
2137 |> assign(:user, follower)
2138 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
2140 assert %{"showing_reblogs" => false} = json_response(conn, 200)
2142 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
2143 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
2147 |> assign(:user, User.get_cached_by_id(follower.id))
2148 |> get("/api/v1/timelines/home")
2150 assert [] == json_response(conn, 200)
2154 |> assign(:user, follower)
2155 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
2157 assert %{"showing_reblogs" => true} = json_response(conn, 200)
2161 |> assign(:user, User.get_cached_by_id(follower.id))
2162 |> get("/api/v1/timelines/home")
2164 expected_activity_id = reblog.id
2165 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
2168 test "following / unfollowing errors" do
2169 user = insert(:user)
2173 |> assign(:user, user)
2176 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
2177 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2180 user = User.get_cached_by_id(user.id)
2181 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
2182 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2184 # self follow via uri
2185 user = User.get_cached_by_id(user.id)
2186 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
2187 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2189 # follow non existing user
2190 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
2191 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2193 # follow non existing user via uri
2194 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
2195 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2197 # unfollow non existing user
2198 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
2199 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2202 describe "mute/unmute" do
2203 test "with notifications", %{conn: conn} do
2204 user = insert(:user)
2205 other_user = insert(:user)
2209 |> assign(:user, user)
2210 |> post("/api/v1/accounts/#{other_user.id}/mute")
2212 response = json_response(conn, 200)
2214 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
2215 user = User.get_cached_by_id(user.id)
2219 |> assign(:user, user)
2220 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2222 response = json_response(conn, 200)
2223 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2226 test "without notifications", %{conn: conn} do
2227 user = insert(:user)
2228 other_user = insert(:user)
2232 |> assign(:user, user)
2233 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
2235 response = json_response(conn, 200)
2237 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
2238 user = User.get_cached_by_id(user.id)
2242 |> assign(:user, user)
2243 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2245 response = json_response(conn, 200)
2246 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2250 test "subscribing / unsubscribing to a user", %{conn: conn} do
2251 user = insert(:user)
2252 subscription_target = insert(:user)
2256 |> assign(:user, user)
2257 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
2259 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
2263 |> assign(:user, user)
2264 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
2266 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
2269 test "getting a list of mutes", %{conn: conn} do
2270 user = insert(:user)
2271 other_user = insert(:user)
2273 {:ok, user} = User.mute(user, other_user)
2277 |> assign(:user, user)
2278 |> get("/api/v1/mutes")
2280 other_user_id = to_string(other_user.id)
2281 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2284 test "blocking / unblocking a user", %{conn: conn} do
2285 user = insert(:user)
2286 other_user = insert(:user)
2290 |> assign(:user, user)
2291 |> post("/api/v1/accounts/#{other_user.id}/block")
2293 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
2295 user = User.get_cached_by_id(user.id)
2299 |> assign(:user, user)
2300 |> post("/api/v1/accounts/#{other_user.id}/unblock")
2302 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
2305 test "getting a list of blocks", %{conn: conn} do
2306 user = insert(:user)
2307 other_user = insert(:user)
2309 {:ok, user} = User.block(user, other_user)
2313 |> assign(:user, user)
2314 |> get("/api/v1/blocks")
2316 other_user_id = to_string(other_user.id)
2317 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2320 test "blocking / unblocking a domain", %{conn: conn} do
2321 user = insert(:user)
2322 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
2326 |> assign(:user, user)
2327 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2329 assert %{} = json_response(conn, 200)
2330 user = User.get_cached_by_ap_id(user.ap_id)
2331 assert User.blocks?(user, other_user)
2335 |> assign(:user, user)
2336 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2338 assert %{} = json_response(conn, 200)
2339 user = User.get_cached_by_ap_id(user.ap_id)
2340 refute User.blocks?(user, other_user)
2343 test "getting a list of domain blocks", %{conn: conn} do
2344 user = insert(:user)
2346 {:ok, user} = User.block_domain(user, "bad.site")
2347 {:ok, user} = User.block_domain(user, "even.worse.site")
2351 |> assign(:user, user)
2352 |> get("/api/v1/domain_blocks")
2354 domain_blocks = json_response(conn, 200)
2356 assert "bad.site" in domain_blocks
2357 assert "even.worse.site" in domain_blocks
2360 test "unimplemented follow_requests, blocks, domain blocks" do
2361 user = insert(:user)
2363 ["blocks", "domain_blocks", "follow_requests"]
2364 |> Enum.each(fn endpoint ->
2367 |> assign(:user, user)
2368 |> get("/api/v1/#{endpoint}")
2370 assert [] = json_response(conn, 200)
2374 test "returns the favorites of a user", %{conn: conn} do
2375 user = insert(:user)
2376 other_user = insert(:user)
2378 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2379 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2381 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2385 |> assign(:user, user)
2386 |> get("/api/v1/favourites")
2388 assert [status] = json_response(first_conn, 200)
2389 assert status["id"] == to_string(activity.id)
2391 assert [{"link", _link_header}] =
2392 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2394 # Honours query params
2395 {:ok, second_activity} =
2396 CommonAPI.post(other_user, %{
2398 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2401 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2403 last_like = status["id"]
2407 |> assign(:user, user)
2408 |> get("/api/v1/favourites?since_id=#{last_like}")
2410 assert [second_status] = json_response(second_conn, 200)
2411 assert second_status["id"] == to_string(second_activity.id)
2415 |> assign(:user, user)
2416 |> get("/api/v1/favourites?limit=0")
2418 assert [] = json_response(third_conn, 200)
2421 describe "getting favorites timeline of specified user" do
2423 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2424 [current_user: current_user, user: user]
2427 test "returns list of statuses favorited by specified user", %{
2429 current_user: current_user,
2432 [activity | _] = insert_pair(:note_activity)
2433 CommonAPI.favorite(activity.id, user)
2437 |> assign(:user, current_user)
2438 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2439 |> json_response(:ok)
2443 assert length(response) == 1
2444 assert like["id"] == activity.id
2447 test "returns favorites for specified user_id when user is not logged in", %{
2451 activity = insert(:note_activity)
2452 CommonAPI.favorite(activity.id, user)
2456 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2457 |> json_response(:ok)
2459 assert length(response) == 1
2462 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2464 current_user: current_user,
2468 CommonAPI.post(current_user, %{
2469 "status" => "Hi @#{user.nickname}!",
2470 "visibility" => "direct"
2473 CommonAPI.favorite(direct.id, user)
2477 |> assign(:user, current_user)
2478 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2479 |> json_response(:ok)
2481 assert length(response) == 1
2483 anonymous_response =
2485 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2486 |> json_response(:ok)
2488 assert Enum.empty?(anonymous_response)
2491 test "does not return others' favorited DM when user is not one of recipients", %{
2493 current_user: current_user,
2496 user_two = insert(:user)
2499 CommonAPI.post(user_two, %{
2500 "status" => "Hi @#{user.nickname}!",
2501 "visibility" => "direct"
2504 CommonAPI.favorite(direct.id, user)
2508 |> assign(:user, current_user)
2509 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2510 |> json_response(:ok)
2512 assert Enum.empty?(response)
2515 test "paginates favorites using since_id and max_id", %{
2517 current_user: current_user,
2520 activities = insert_list(10, :note_activity)
2522 Enum.each(activities, fn activity ->
2523 CommonAPI.favorite(activity.id, user)
2526 third_activity = Enum.at(activities, 2)
2527 seventh_activity = Enum.at(activities, 6)
2531 |> assign(:user, current_user)
2532 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2533 since_id: third_activity.id,
2534 max_id: seventh_activity.id
2536 |> json_response(:ok)
2538 assert length(response) == 3
2539 refute third_activity in response
2540 refute seventh_activity in response
2543 test "limits favorites using limit parameter", %{
2545 current_user: current_user,
2549 |> insert_list(:note_activity)
2550 |> Enum.each(fn activity ->
2551 CommonAPI.favorite(activity.id, user)
2556 |> assign(:user, current_user)
2557 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2558 |> json_response(:ok)
2560 assert length(response) == 3
2563 test "returns empty response when user does not have any favorited statuses", %{
2565 current_user: current_user,
2570 |> assign(:user, current_user)
2571 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2572 |> json_response(:ok)
2574 assert Enum.empty?(response)
2577 test "returns 404 error when specified user is not exist", %{conn: conn} do
2578 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2580 assert json_response(conn, 404) == %{"error" => "Record not found"}
2583 test "returns 403 error when user has hidden own favorites", %{
2585 current_user: current_user
2587 user = insert(:user, %{info: %{hide_favorites: true}})
2588 activity = insert(:note_activity)
2589 CommonAPI.favorite(activity.id, user)
2593 |> assign(:user, current_user)
2594 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2596 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2599 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2600 user = insert(:user)
2601 activity = insert(:note_activity)
2602 CommonAPI.favorite(activity.id, user)
2606 |> assign(:user, current_user)
2607 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2609 assert user.info.hide_favorites
2610 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2614 test "get instance information", %{conn: conn} do
2615 conn = get(conn, "/api/v1/instance")
2616 assert result = json_response(conn, 200)
2618 email = Pleroma.Config.get([:instance, :email])
2619 # Note: not checking for "max_toot_chars" since it's optional
2625 "email" => from_config_email,
2627 "streaming_api" => _
2632 "registrations" => _,
2636 assert email == from_config_email
2639 test "get instance stats", %{conn: conn} do
2640 user = insert(:user, %{local: true})
2642 user2 = insert(:user, %{local: true})
2643 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2645 insert(:user, %{local: false, nickname: "u@peer1.com"})
2646 insert(:user, %{local: false, nickname: "u@peer2.com"})
2648 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
2650 # Stats should count users with missing or nil `info.deactivated` value
2651 user = User.get_cached_by_id(user.id)
2652 info_change = Changeset.change(user.info, %{deactivated: nil})
2656 |> Changeset.change()
2657 |> Changeset.put_embed(:info, info_change)
2658 |> User.update_and_set_cache()
2660 Pleroma.Stats.update_stats()
2662 conn = get(conn, "/api/v1/instance")
2664 assert result = json_response(conn, 200)
2666 stats = result["stats"]
2669 assert stats["user_count"] == 1
2670 assert stats["status_count"] == 1
2671 assert stats["domain_count"] == 2
2674 test "get peers", %{conn: conn} do
2675 insert(:user, %{local: false, nickname: "u@peer1.com"})
2676 insert(:user, %{local: false, nickname: "u@peer2.com"})
2678 Pleroma.Stats.update_stats()
2680 conn = get(conn, "/api/v1/instance/peers")
2682 assert result = json_response(conn, 200)
2684 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2687 test "put settings", %{conn: conn} do
2688 user = insert(:user)
2692 |> assign(:user, user)
2693 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2695 assert _result = json_response(conn, 200)
2697 user = User.get_cached_by_ap_id(user.ap_id)
2698 assert user.info.settings == %{"programming" => "socks"}
2701 describe "pinned statuses" do
2703 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2705 user = insert(:user)
2706 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2708 [user: user, activity: activity]
2711 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2712 {:ok, _} = CommonAPI.pin(activity.id, user)
2716 |> assign(:user, user)
2717 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2718 |> json_response(200)
2720 id_str = to_string(activity.id)
2722 assert [%{"id" => ^id_str, "pinned" => true}] = result
2725 test "pin status", %{conn: conn, user: user, activity: activity} do
2726 id_str = to_string(activity.id)
2728 assert %{"id" => ^id_str, "pinned" => true} =
2730 |> assign(:user, user)
2731 |> post("/api/v1/statuses/#{activity.id}/pin")
2732 |> json_response(200)
2734 assert [%{"id" => ^id_str, "pinned" => true}] =
2736 |> assign(:user, user)
2737 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2738 |> json_response(200)
2741 test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
2742 {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
2746 |> assign(:user, user)
2747 |> post("/api/v1/statuses/#{dm.id}/pin")
2749 assert json_response(conn, 400) == %{"error" => "Could not pin"}
2752 test "unpin status", %{conn: conn, user: user, activity: activity} do
2753 {:ok, _} = CommonAPI.pin(activity.id, user)
2755 id_str = to_string(activity.id)
2756 user = refresh_record(user)
2758 assert %{"id" => ^id_str, "pinned" => false} =
2760 |> assign(:user, user)
2761 |> post("/api/v1/statuses/#{activity.id}/unpin")
2762 |> json_response(200)
2766 |> assign(:user, user)
2767 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2768 |> json_response(200)
2771 test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
2774 |> assign(:user, user)
2775 |> post("/api/v1/statuses/1/unpin")
2777 assert json_response(conn, 400) == %{"error" => "Could not unpin"}
2780 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2781 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2783 id_str_one = to_string(activity_one.id)
2785 assert %{"id" => ^id_str_one, "pinned" => true} =
2787 |> assign(:user, user)
2788 |> post("/api/v1/statuses/#{id_str_one}/pin")
2789 |> json_response(200)
2791 user = refresh_record(user)
2793 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2795 |> assign(:user, user)
2796 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2797 |> json_response(400)
2803 Pleroma.Config.put([:rich_media, :enabled], true)
2806 Pleroma.Config.put([:rich_media, :enabled], false)
2809 user = insert(:user)
2813 test "returns rich-media card", %{conn: conn, user: user} do
2814 {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
2817 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2818 "provider_name" => "www.imdb.com",
2819 "provider_url" => "http://www.imdb.com",
2820 "title" => "The Rock",
2822 "url" => "http://www.imdb.com/title/tt0117500/",
2824 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
2827 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2828 "title" => "The Rock",
2829 "type" => "video.movie",
2830 "url" => "http://www.imdb.com/title/tt0117500/",
2832 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
2839 |> get("/api/v1/statuses/#{activity.id}/card")
2840 |> json_response(200)
2842 assert response == card_data
2844 # works with private posts
2846 CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
2850 |> assign(:user, user)
2851 |> get("/api/v1/statuses/#{activity.id}/card")
2852 |> json_response(200)
2854 assert response_two == card_data
2857 test "replaces missing description with an empty string", %{conn: conn, user: user} do
2859 CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
2863 |> get("/api/v1/statuses/#{activity.id}/card")
2864 |> json_response(:ok)
2866 assert response == %{
2868 "title" => "Pleroma",
2869 "description" => "",
2871 "provider_name" => "pleroma.social",
2872 "provider_url" => "https://pleroma.social",
2873 "url" => "https://pleroma.social/",
2876 "title" => "Pleroma",
2877 "type" => "website",
2878 "url" => "https://pleroma.social/"
2886 user = insert(:user)
2887 for_user = insert(:user)
2890 CommonAPI.post(user, %{
2891 "status" => "heweoo?"
2895 CommonAPI.post(user, %{
2896 "status" => "heweoo!"
2901 |> assign(:user, for_user)
2902 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2904 assert json_response(response1, 200)["bookmarked"] == true
2908 |> assign(:user, for_user)
2909 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2911 assert json_response(response2, 200)["bookmarked"] == true
2915 |> assign(:user, for_user)
2916 |> get("/api/v1/bookmarks")
2918 assert [json_response(response2, 200), json_response(response1, 200)] ==
2919 json_response(bookmarks, 200)
2923 |> assign(:user, for_user)
2924 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2926 assert json_response(response1, 200)["bookmarked"] == false
2930 |> assign(:user, for_user)
2931 |> get("/api/v1/bookmarks")
2933 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2936 describe "conversation muting" do
2938 user = insert(:user)
2939 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2941 [user: user, activity: activity]
2944 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2945 id_str = to_string(activity.id)
2947 assert %{"id" => ^id_str, "muted" => true} =
2949 |> assign(:user, user)
2950 |> post("/api/v1/statuses/#{activity.id}/mute")
2951 |> json_response(200)
2954 test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
2955 {:ok, _} = CommonAPI.add_mute(user, activity)
2959 |> assign(:user, user)
2960 |> post("/api/v1/statuses/#{activity.id}/mute")
2962 assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
2965 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2966 {:ok, _} = CommonAPI.add_mute(user, activity)
2968 id_str = to_string(activity.id)
2969 user = refresh_record(user)
2971 assert %{"id" => ^id_str, "muted" => false} =
2973 |> assign(:user, user)
2974 |> post("/api/v1/statuses/#{activity.id}/unmute")
2975 |> json_response(200)
2979 describe "reports" do
2981 reporter = insert(:user)
2982 target_user = insert(:user)
2984 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2986 [reporter: reporter, target_user: target_user, activity: activity]
2989 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2990 assert %{"action_taken" => false, "id" => _} =
2992 |> assign(:user, reporter)
2993 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2994 |> json_response(200)
2997 test "submit a report with statuses and comment", %{
3000 target_user: target_user,
3003 assert %{"action_taken" => false, "id" => _} =
3005 |> assign(:user, reporter)
3006 |> post("/api/v1/reports", %{
3007 "account_id" => target_user.id,
3008 "status_ids" => [activity.id],
3009 "comment" => "bad status!",
3010 "forward" => "false"
3012 |> json_response(200)
3015 test "account_id is required", %{
3020 assert %{"error" => "Valid `account_id` required"} =
3022 |> assign(:user, reporter)
3023 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
3024 |> json_response(400)
3027 test "comment must be up to the size specified in the config", %{
3030 target_user: target_user
3032 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
3033 comment = String.pad_trailing("a", max_size + 1, "a")
3035 error = %{"error" => "Comment must be up to #{max_size} characters"}
3039 |> assign(:user, reporter)
3040 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
3041 |> json_response(400)
3044 test "returns error when account is not exist", %{
3051 |> assign(:user, reporter)
3052 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
3054 assert json_response(conn, 400) == %{"error" => "Account not found"}
3058 describe "link headers" do
3059 test "preserves parameters in link headers", %{conn: conn} do
3060 user = insert(:user)
3061 other_user = insert(:user)
3064 CommonAPI.post(other_user, %{
3065 "status" => "hi @#{user.nickname}",
3066 "visibility" => "public"
3070 CommonAPI.post(other_user, %{
3071 "status" => "hi @#{user.nickname}",
3072 "visibility" => "public"
3075 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
3076 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
3080 |> assign(:user, user)
3081 |> get("/api/v1/notifications", %{media_only: true})
3083 assert [link_header] = get_resp_header(conn, "link")
3084 assert link_header =~ ~r/media_only=true/
3085 assert link_header =~ ~r/min_id=#{notification2.id}/
3086 assert link_header =~ ~r/max_id=#{notification1.id}/
3090 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
3091 # Need to set an old-style integer ID to reproduce the problem
3092 # (these are no longer assigned to new accounts but were preserved
3093 # for existing accounts during the migration to flakeIDs)
3094 user_one = insert(:user, %{id: 1212})
3095 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
3099 |> get("/api/v1/accounts/#{user_one.id}")
3103 |> get("/api/v1/accounts/#{user_two.nickname}")
3107 |> get("/api/v1/accounts/#{user_two.id}")
3109 acc_one = json_response(resp_one, 200)
3110 acc_two = json_response(resp_two, 200)
3111 acc_three = json_response(resp_three, 200)
3112 refute acc_one == acc_two
3113 assert acc_two == acc_three
3116 describe "custom emoji" do
3117 test "with tags", %{conn: conn} do
3120 |> get("/api/v1/custom_emojis")
3121 |> json_response(200)
3123 assert Map.has_key?(emoji, "shortcode")
3124 assert Map.has_key?(emoji, "static_url")
3125 assert Map.has_key?(emoji, "tags")
3126 assert is_list(emoji["tags"])
3127 assert Map.has_key?(emoji, "category")
3128 assert Map.has_key?(emoji, "url")
3129 assert Map.has_key?(emoji, "visible_in_picker")
3133 describe "index/2 redirections" do
3134 setup %{conn: conn} do
3138 signing_salt: "cooldude"
3143 |> Plug.Session.call(Plug.Session.init(session_opts))
3146 test_path = "/web/statuses/test"
3147 %{conn: conn, path: test_path}
3150 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
3151 conn = get(conn, path)
3153 assert conn.status == 302
3154 assert redirected_to(conn) == "/web/login"
3157 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
3158 token = insert(:oauth_token)
3162 |> assign(:user, token.user)
3163 |> put_session(:oauth_token, token.token)
3166 assert conn.status == 200
3169 test "saves referer path to session", %{conn: conn, path: path} do
3170 conn = get(conn, path)
3171 return_to = Plug.Conn.get_session(conn, :return_to)
3173 assert return_to == path
3176 test "redirects to the saved path after log in", %{conn: conn, path: path} do
3177 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3178 auth = insert(:oauth_authorization, app: app)
3182 |> put_session(:return_to, path)
3183 |> get("/web/login", %{code: auth.token})
3185 assert conn.status == 302
3186 assert redirected_to(conn) == path
3189 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
3190 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3191 auth = insert(:oauth_authorization, app: app)
3193 conn = get(conn, "/web/login", %{code: auth.token})
3195 assert conn.status == 302
3196 assert redirected_to(conn) == "/web/getting-started"
3200 describe "scheduled activities" do
3201 test "creates a scheduled activity", %{conn: conn} do
3202 user = insert(:user)
3203 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3207 |> assign(:user, user)
3208 |> post("/api/v1/statuses", %{
3209 "status" => "scheduled",
3210 "scheduled_at" => scheduled_at
3213 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
3214 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
3215 assert [] == Repo.all(Activity)
3218 test "creates a scheduled activity with a media attachment", %{conn: conn} do
3219 user = insert(:user)
3220 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3222 file = %Plug.Upload{
3223 content_type: "image/jpg",
3224 path: Path.absname("test/fixtures/image.jpg"),
3225 filename: "an_image.jpg"
3228 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
3232 |> assign(:user, user)
3233 |> post("/api/v1/statuses", %{
3234 "media_ids" => [to_string(upload.id)],
3235 "status" => "scheduled",
3236 "scheduled_at" => scheduled_at
3239 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3240 assert %{"type" => "image"} = media_attachment
3243 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3245 user = insert(:user)
3248 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3252 |> assign(:user, user)
3253 |> post("/api/v1/statuses", %{
3254 "status" => "not scheduled",
3255 "scheduled_at" => scheduled_at
3258 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3259 assert [] == Repo.all(ScheduledActivity)
3262 test "returns error when daily user limit is exceeded", %{conn: conn} do
3263 user = insert(:user)
3266 NaiveDateTime.utc_now()
3267 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3268 |> NaiveDateTime.to_iso8601()
3270 attrs = %{params: %{}, scheduled_at: today}
3271 {:ok, _} = ScheduledActivity.create(user, attrs)
3272 {:ok, _} = ScheduledActivity.create(user, attrs)
3276 |> assign(:user, user)
3277 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3279 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3282 test "returns error when total user limit is exceeded", %{conn: conn} do
3283 user = insert(:user)
3286 NaiveDateTime.utc_now()
3287 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3288 |> NaiveDateTime.to_iso8601()
3291 NaiveDateTime.utc_now()
3292 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3293 |> NaiveDateTime.to_iso8601()
3295 attrs = %{params: %{}, scheduled_at: today}
3296 {:ok, _} = ScheduledActivity.create(user, attrs)
3297 {:ok, _} = ScheduledActivity.create(user, attrs)
3298 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3302 |> assign(:user, user)
3303 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3305 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3308 test "shows scheduled activities", %{conn: conn} do
3309 user = insert(:user)
3310 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3311 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3312 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3313 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3317 |> assign(:user, user)
3322 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3324 result = json_response(conn_res, 200)
3325 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3330 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3332 result = json_response(conn_res, 200)
3333 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3338 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3340 result = json_response(conn_res, 200)
3341 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3344 test "shows a scheduled activity", %{conn: conn} do
3345 user = insert(:user)
3346 scheduled_activity = insert(:scheduled_activity, user: user)
3350 |> assign(:user, user)
3351 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3353 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3354 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3358 |> assign(:user, user)
3359 |> get("/api/v1/scheduled_statuses/404")
3361 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3364 test "updates a scheduled activity", %{conn: conn} do
3365 user = insert(:user)
3366 scheduled_activity = insert(:scheduled_activity, user: user)
3369 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3373 |> assign(:user, user)
3374 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3375 scheduled_at: new_scheduled_at
3378 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3379 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3383 |> assign(:user, user)
3384 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3386 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3389 test "deletes a scheduled activity", %{conn: conn} do
3390 user = insert(:user)
3391 scheduled_activity = insert(:scheduled_activity, user: user)
3395 |> assign(:user, user)
3396 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3398 assert %{} = json_response(res_conn, 200)
3399 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3403 |> assign(:user, user)
3404 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3406 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3410 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3411 user1 = insert(:user)
3412 user2 = insert(:user)
3413 user3 = insert(:user)
3415 {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
3417 # Reply to status from another user
3420 |> assign(:user, user2)
3421 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3423 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3425 activity = Activity.get_by_id_with_object(id)
3427 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3428 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3430 # Reblog from the third user
3433 |> assign(:user, user3)
3434 |> post("/api/v1/statuses/#{activity.id}/reblog")
3436 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3437 json_response(conn2, 200)
3439 assert to_string(activity.id) == id
3441 # Getting third user status
3444 |> assign(:user, user3)
3445 |> get("api/v1/timelines/home")
3447 [reblogged_activity] = json_response(conn3, 200)
3449 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3451 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3452 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
3455 describe "create account by app" do
3456 test "Account registration via Application", %{conn: conn} do
3459 |> post("/api/v1/apps", %{
3460 client_name: "client_name",
3461 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
3462 scopes: "read, write, follow"
3466 "client_id" => client_id,
3467 "client_secret" => client_secret,
3469 "name" => "client_name",
3470 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
3473 } = json_response(conn, 200)
3477 |> post("/oauth/token", %{
3478 grant_type: "client_credentials",
3479 client_id: client_id,
3480 client_secret: client_secret
3483 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
3484 json_response(conn, 200)
3487 token_from_db = Repo.get_by(Token, token: token)
3488 assert token_from_db
3490 assert scope == "read write follow"
3494 |> put_req_header("authorization", "Bearer " <> token)
3495 |> post("/api/v1/accounts", %{
3497 email: "lain@example.org",
3498 password: "PlzDontHackLain",
3503 "access_token" => token,
3504 "created_at" => _created_at,
3506 "token_type" => "Bearer"
3507 } = json_response(conn, 200)
3509 token_from_db = Repo.get_by(Token, token: token)
3510 assert token_from_db
3511 token_from_db = Repo.preload(token_from_db, :user)
3512 assert token_from_db.user
3514 assert token_from_db.user.info.confirmation_pending
3517 test "rate limit", %{conn: conn} do
3518 app_token = insert(:oauth_token, user: nil)
3521 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
3522 |> Map.put(:remote_ip, {15, 15, 15, 15})
3527 |> post("/api/v1/accounts", %{
3528 username: "#{i}lain",
3529 email: "#{i}lain@example.org",
3530 password: "PlzDontHackLain",
3535 "access_token" => token,
3536 "created_at" => _created_at,
3538 "token_type" => "Bearer"
3539 } = json_response(conn, 200)
3541 token_from_db = Repo.get_by(Token, token: token)
3542 assert token_from_db
3543 token_from_db = Repo.preload(token_from_db, :user)
3544 assert token_from_db.user
3546 assert token_from_db.user.info.confirmation_pending
3551 |> post("/api/v1/accounts", %{
3553 email: "6lain@example.org",
3554 password: "PlzDontHackLain",
3558 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
3562 describe "GET /api/v1/polls/:id" do
3563 test "returns poll entity for object id", %{conn: conn} do
3564 user = insert(:user)
3567 CommonAPI.post(user, %{
3568 "status" => "Pleroma does",
3569 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
3572 object = Object.normalize(activity)
3576 |> assign(:user, user)
3577 |> get("/api/v1/polls/#{object.id}")
3579 response = json_response(conn, 200)
3580 id = to_string(object.id)
3581 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
3584 test "does not expose polls for private statuses", %{conn: conn} do
3585 user = insert(:user)
3586 other_user = insert(:user)
3589 CommonAPI.post(user, %{
3590 "status" => "Pleroma does",
3591 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
3592 "visibility" => "private"
3595 object = Object.normalize(activity)
3599 |> assign(:user, other_user)
3600 |> get("/api/v1/polls/#{object.id}")
3602 assert json_response(conn, 404)
3606 describe "POST /api/v1/polls/:id/votes" do
3607 test "votes are added to the poll", %{conn: conn} do
3608 user = insert(:user)
3609 other_user = insert(:user)
3612 CommonAPI.post(user, %{
3613 "status" => "A very delicious sandwich",
3615 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
3621 object = Object.normalize(activity)
3625 |> assign(:user, other_user)
3626 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
3628 assert json_response(conn, 200)
3629 object = Object.get_by_id(object.id)
3631 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3636 test "author can't vote", %{conn: conn} do
3637 user = insert(:user)
3640 CommonAPI.post(user, %{
3641 "status" => "Am I cute?",
3642 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3645 object = Object.normalize(activity)
3648 |> assign(:user, user)
3649 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
3650 |> json_response(422) == %{"error" => "Poll's author can't vote"}
3652 object = Object.get_by_id(object.id)
3654 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
3657 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
3658 user = insert(:user)
3659 other_user = insert(:user)
3662 CommonAPI.post(user, %{
3663 "status" => "The glass is",
3664 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
3667 object = Object.normalize(activity)
3670 |> assign(:user, other_user)
3671 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
3672 |> json_response(422) == %{"error" => "Too many choices"}
3674 object = Object.get_by_id(object.id)
3676 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3681 test "does not allow choice index to be greater than options count", %{conn: conn} do
3682 user = insert(:user)
3683 other_user = insert(:user)
3686 CommonAPI.post(user, %{
3687 "status" => "Am I cute?",
3688 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3691 object = Object.normalize(activity)
3695 |> assign(:user, other_user)
3696 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
3698 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
3701 test "returns 404 error when object is not exist", %{conn: conn} do
3702 user = insert(:user)
3706 |> assign(:user, user)
3707 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
3709 assert json_response(conn, 404) == %{"error" => "Record not found"}
3712 test "returns 404 when poll is private and not available for user", %{conn: conn} do
3713 user = insert(:user)
3714 other_user = insert(:user)
3717 CommonAPI.post(user, %{
3718 "status" => "Am I cute?",
3719 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
3720 "visibility" => "private"
3723 object = Object.normalize(activity)
3727 |> assign(:user, other_user)
3728 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
3730 assert json_response(conn, 404) == %{"error" => "Record not found"}
3734 describe "GET /api/v1/statuses/:id/favourited_by" do
3736 user = insert(:user)
3737 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3741 |> assign(:user, user)
3743 [conn: conn, activity: activity]
3746 test "returns users who have favorited the status", %{conn: conn, activity: activity} do
3747 other_user = insert(:user)
3748 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3752 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3753 |> json_response(:ok)
3755 [%{"id" => id}] = response
3757 assert id == other_user.id
3760 test "returns empty array when status has not been favorited yet", %{
3766 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3767 |> json_response(:ok)
3769 assert Enum.empty?(response)
3772 test "does not return users who have favorited the status but are blocked", %{
3773 conn: %{assigns: %{user: user}} = conn,
3776 other_user = insert(:user)
3777 {:ok, user} = User.block(user, other_user)
3779 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3783 |> assign(:user, user)
3784 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3785 |> json_response(:ok)
3787 assert Enum.empty?(response)
3790 test "does not fail on an unauthententicated request", %{conn: conn, activity: activity} do
3791 other_user = insert(:user)
3792 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3796 |> assign(:user, nil)
3797 |> get("/api/v1/#{activity.id}/favourited_by")
3798 |> json_response(:ok)
3800 [%{"id" => id}] = response
3801 assert id == other_user.id
3805 describe "GET /api/v1/statuses/:id/reblogged_by" do
3807 user = insert(:user)
3808 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3812 |> assign(:user, user)
3814 [conn: conn, activity: activity]
3817 test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
3818 other_user = insert(:user)
3819 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3823 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3824 |> json_response(:ok)
3826 [%{"id" => id}] = response
3828 assert id == other_user.id
3831 test "returns empty array when status has not been reblogged yet", %{
3837 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3838 |> json_response(:ok)
3840 assert Enum.empty?(response)
3843 test "does not return users who have reblogged the status but are blocked", %{
3844 conn: %{assigns: %{user: user}} = conn,
3847 other_user = insert(:user)
3848 {:ok, user} = User.block(user, other_user)
3850 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3854 |> assign(:user, user)
3855 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3856 |> json_response(:ok)
3858 assert Enum.empty?(response)
3861 test "does not fail on an unauthententicated request", %{conn: conn, activity: activity} do
3862 other_user = insert(:user)
3863 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3867 |> assign(:user, nil)
3868 |> get("/api/v1/#{activity.id}/reblogged_by")
3869 |> json_response(:ok)
3871 [%{"id" => id}] = response
3872 assert id == other_user.id
3876 describe "POST /auth/password, with valid parameters" do
3877 setup %{conn: conn} do
3878 user = insert(:user)
3879 conn = post(conn, "/auth/password?email=#{user.email}")
3880 %{conn: conn, user: user}
3883 test "it returns 204", %{conn: conn} do
3884 assert json_response(conn, :no_content)
3887 test "it creates a PasswordResetToken record for user", %{user: user} do
3888 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3892 test "it sends an email to user", %{user: user} do
3893 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3895 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
3896 notify_email = Pleroma.Config.get([:instance, :notify_email])
3897 instance_name = Pleroma.Config.get([:instance, :name])
3900 from: {instance_name, notify_email},
3901 to: {user.name, user.email},
3902 html_body: email.html_body
3907 describe "POST /auth/password, with invalid parameters" do
3909 user = insert(:user)
3913 test "it returns 404 when user is not found", %{conn: conn, user: user} do
3914 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
3915 assert conn.status == 404
3916 assert conn.resp_body == ""
3919 test "it returns 400 when user is not local", %{conn: conn, user: user} do
3920 {:ok, user} = Repo.update(Changeset.change(user, local: false))
3921 conn = post(conn, "/auth/password?email=#{user.email}")
3922 assert conn.status == 400
3923 assert conn.resp_body == ""