Move StatusController tests from MastodonAPIControllerTest to StatusControllerTest
authorEgor Kislitsyn <egor@kislitsyn.com>
Thu, 26 Sep 2019 06:38:45 +0000 (13:38 +0700)
committerEgor Kislitsyn <egor@kislitsyn.com>
Fri, 27 Sep 2019 03:52:47 +0000 (10:52 +0700)
test/web/mastodon_api/controllers/status_controller_test.exs [new file with mode: 0644]
test/web/mastodon_api/mastodon_api_controller_test.exs

diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs
new file mode 100644 (file)
index 0000000..f80ce77
--- /dev/null
@@ -0,0 +1,1056 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
+  use Pleroma.Web.ConnCase
+
+  alias Pleroma.Activity
+  alias Pleroma.ActivityExpiration
+  alias Pleroma.Config
+  alias Pleroma.Object
+  alias Pleroma.User
+  alias Pleroma.Web.CommonAPI
+
+  import Pleroma.Factory
+
+  describe "posting statuses" do
+    setup do
+      user = insert(:user)
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+
+      [conn: conn]
+    end
+
+    test "posting a status", %{conn: conn} do
+      idempotency_key = "Pikachu rocks!"
+
+      conn_one =
+        conn
+        |> put_req_header("idempotency-key", idempotency_key)
+        |> post("/api/v1/statuses", %{
+          "status" => "cofe",
+          "spoiler_text" => "2hu",
+          "sensitive" => "false"
+        })
+
+      {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
+      # Six hours
+      assert ttl > :timer.seconds(6 * 60 * 60 - 1)
+
+      assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
+               json_response(conn_one, 200)
+
+      assert Activity.get_by_id(id)
+
+      conn_two =
+        conn
+        |> put_req_header("idempotency-key", idempotency_key)
+        |> post("/api/v1/statuses", %{
+          "status" => "cofe",
+          "spoiler_text" => "2hu",
+          "sensitive" => "false"
+        })
+
+      assert %{"id" => second_id} = json_response(conn_two, 200)
+      assert id == second_id
+
+      conn_three =
+        conn
+        |> post("/api/v1/statuses", %{
+          "status" => "cofe",
+          "spoiler_text" => "2hu",
+          "sensitive" => "false"
+        })
+
+      assert %{"id" => third_id} = json_response(conn_three, 200)
+      refute id == third_id
+
+      # An activity that will expire:
+      # 2 hours
+      expires_in = 120 * 60
+
+      conn_four =
+        conn
+        |> post("api/v1/statuses", %{
+          "status" => "oolong",
+          "expires_in" => expires_in
+        })
+
+      assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200)
+      assert activity = Activity.get_by_id(fourth_id)
+      assert expiration = ActivityExpiration.get_by_activity_id(fourth_id)
+
+      estimated_expires_at =
+        NaiveDateTime.utc_now()
+        |> NaiveDateTime.add(expires_in)
+        |> NaiveDateTime.truncate(:second)
+
+      # This assert will fail if the test takes longer than a minute. I sure hope it never does:
+      assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60
+
+      assert fourth_response["pleroma"]["expires_at"] ==
+               NaiveDateTime.to_iso8601(expiration.scheduled_at)
+    end
+
+    test "replying to a status", %{conn: conn} do
+      user = insert(:user)
+      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
+
+      conn =
+        conn
+        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
+
+      assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
+
+      activity = Activity.get_by_id(id)
+
+      assert activity.data["context"] == replied_to.data["context"]
+      assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
+    end
+
+    test "replying to a direct message with visibility other than direct", %{conn: conn} do
+      user = insert(:user)
+      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
+
+      Enum.each(["public", "private", "unlisted"], fn visibility ->
+        conn =
+          conn
+          |> post("/api/v1/statuses", %{
+            "status" => "@#{user.nickname} hey",
+            "in_reply_to_id" => replied_to.id,
+            "visibility" => visibility
+          })
+
+        assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
+      end)
+    end
+
+    test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
+      conn =
+        conn
+        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
+
+      assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
+      assert Activity.get_by_id(id)
+    end
+
+    test "posting a sensitive status", %{conn: conn} do
+      conn =
+        conn
+        |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
+
+      assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
+      assert Activity.get_by_id(id)
+    end
+
+    test "posting a fake status", %{conn: conn} do
+      real_conn =
+        conn
+        |> post("/api/v1/statuses", %{
+          "status" =>
+            "\"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"
+        })
+
+      real_status = json_response(real_conn, 200)
+
+      assert real_status
+      assert Object.get_by_ap_id(real_status["uri"])
+
+      real_status =
+        real_status
+        |> Map.put("id", nil)
+        |> Map.put("url", nil)
+        |> Map.put("uri", nil)
+        |> Map.put("created_at", nil)
+        |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+      fake_conn =
+        conn
+        |> post("/api/v1/statuses", %{
+          "status" =>
+            "\"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",
+          "preview" => true
+        })
+
+      fake_status = json_response(fake_conn, 200)
+
+      assert fake_status
+      refute Object.get_by_ap_id(fake_status["uri"])
+
+      fake_status =
+        fake_status
+        |> Map.put("id", nil)
+        |> Map.put("url", nil)
+        |> Map.put("uri", nil)
+        |> Map.put("created_at", nil)
+        |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+      assert real_status == fake_status
+    end
+
+    test "posting a status with OGP link preview", %{conn: conn} do
+      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+      Config.put([:rich_media, :enabled], true)
+
+      conn =
+        conn
+        |> post("/api/v1/statuses", %{
+          "status" => "https://example.com/ogp"
+        })
+
+      assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
+      assert Activity.get_by_id(id)
+    end
+
+    test "posting a direct status", %{conn: conn} do
+      user2 = insert(:user)
+      content = "direct cofe @#{user2.nickname}"
+
+      conn =
+        conn
+        |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
+
+      assert %{"id" => id} = response = json_response(conn, 200)
+      assert response["visibility"] == "direct"
+      assert response["pleroma"]["direct_conversation_id"]
+      assert activity = Activity.get_by_id(id)
+      assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
+      assert activity.data["to"] == [user2.ap_id]
+      assert activity.data["cc"] == []
+    end
+  end
+
+  describe "posting polls" do
+    test "posting a poll", %{conn: conn} do
+      user = insert(:user)
+      time = NaiveDateTime.utc_now()
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses", %{
+          "status" => "Who is the #bestgrill?",
+          "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
+        })
+
+      response = json_response(conn, 200)
+
+      assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
+               title in ["Rei", "Asuka", "Misato"]
+             end)
+
+      assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
+      refute response["poll"]["expred"]
+    end
+
+    test "option limit is enforced", %{conn: conn} do
+      user = insert(:user)
+      limit = Config.get([:instance, :poll_limits, :max_options])
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses", %{
+          "status" => "desu~",
+          "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
+        })
+
+      %{"error" => error} = json_response(conn, 422)
+      assert error == "Poll can't contain more than #{limit} options"
+    end
+
+    test "option character limit is enforced", %{conn: conn} do
+      user = insert(:user)
+      limit = Config.get([:instance, :poll_limits, :max_option_chars])
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses", %{
+          "status" => "...",
+          "poll" => %{
+            "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
+            "expires_in" => 1
+          }
+        })
+
+      %{"error" => error} = json_response(conn, 422)
+      assert error == "Poll options cannot be longer than #{limit} characters each"
+    end
+
+    test "minimal date limit is enforced", %{conn: conn} do
+      user = insert(:user)
+      limit = Config.get([:instance, :poll_limits, :min_expiration])
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses", %{
+          "status" => "imagine arbitrary limits",
+          "poll" => %{
+            "options" => ["this post was made by pleroma gang"],
+            "expires_in" => limit - 1
+          }
+        })
+
+      %{"error" => error} = json_response(conn, 422)
+      assert error == "Expiration date is too soon"
+    end
+
+    test "maximum date limit is enforced", %{conn: conn} do
+      user = insert(:user)
+      limit = Config.get([:instance, :poll_limits, :max_expiration])
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses", %{
+          "status" => "imagine arbitrary limits",
+          "poll" => %{
+            "options" => ["this post was made by pleroma gang"],
+            "expires_in" => limit + 1
+          }
+        })
+
+      %{"error" => error} = json_response(conn, 422)
+      assert error == "Expiration date is too far in the future"
+    end
+  end
+
+  test "get a status", %{conn: conn} do
+    activity = insert(:note_activity)
+
+    conn =
+      conn
+      |> get("/api/v1/statuses/#{activity.id}")
+
+    assert %{"id" => id} = json_response(conn, 200)
+    assert id == to_string(activity.id)
+  end
+
+  test "get statuses by IDs", %{conn: conn} do
+    %{id: id1} = insert(:note_activity)
+    %{id: id2} = insert(:note_activity)
+
+    query_string = "ids[]=#{id1}&ids[]=#{id2}"
+    conn = get(conn, "/api/v1/statuses/?#{query_string}")
+
+    assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"])
+  end
+
+  describe "deleting a status" do
+    test "when you created it", %{conn: conn} do
+      activity = insert(:note_activity)
+      author = User.get_cached_by_ap_id(activity.data["actor"])
+
+      conn =
+        conn
+        |> assign(:user, author)
+        |> delete("/api/v1/statuses/#{activity.id}")
+
+      assert %{} = json_response(conn, 200)
+
+      refute Activity.get_by_id(activity.id)
+    end
+
+    test "when you didn't create it", %{conn: conn} do
+      activity = insert(:note_activity)
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> delete("/api/v1/statuses/#{activity.id}")
+
+      assert %{"error" => _} = json_response(conn, 403)
+
+      assert Activity.get_by_id(activity.id) == activity
+    end
+
+    test "when you're an admin or moderator", %{conn: conn} do
+      activity1 = insert(:note_activity)
+      activity2 = insert(:note_activity)
+      admin = insert(:user, info: %{is_admin: true})
+      moderator = insert(:user, info: %{is_moderator: true})
+
+      res_conn =
+        conn
+        |> assign(:user, admin)
+        |> delete("/api/v1/statuses/#{activity1.id}")
+
+      assert %{} = json_response(res_conn, 200)
+
+      res_conn =
+        conn
+        |> assign(:user, moderator)
+        |> delete("/api/v1/statuses/#{activity2.id}")
+
+      assert %{} = json_response(res_conn, 200)
+
+      refute Activity.get_by_id(activity1.id)
+      refute Activity.get_by_id(activity2.id)
+    end
+  end
+
+  describe "reblogging" do
+    test "reblogs and returns the reblogged status", %{conn: conn} do
+      activity = insert(:note_activity)
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/#{activity.id}/reblog")
+
+      assert %{
+               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
+               "reblogged" => true
+             } = json_response(conn, 200)
+
+      assert to_string(activity.id) == id
+    end
+
+    test "reblogged status for another user", %{conn: conn} do
+      activity = insert(:note_activity)
+      user1 = insert(:user)
+      user2 = insert(:user)
+      user3 = insert(:user)
+      CommonAPI.favorite(activity.id, user2)
+      {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
+      {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
+      {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
+
+      conn_res =
+        conn
+        |> assign(:user, user3)
+        |> get("/api/v1/statuses/#{reblog_activity1.id}")
+
+      assert %{
+               "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
+               "reblogged" => false,
+               "favourited" => false,
+               "bookmarked" => false
+             } = json_response(conn_res, 200)
+
+      conn_res =
+        conn
+        |> assign(:user, user2)
+        |> get("/api/v1/statuses/#{reblog_activity1.id}")
+
+      assert %{
+               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
+               "reblogged" => true,
+               "favourited" => true,
+               "bookmarked" => true
+             } = json_response(conn_res, 200)
+
+      assert to_string(activity.id) == id
+    end
+
+    test "returns 400 error when activity is not exist", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/foo/reblog")
+
+      assert json_response(conn, 400) == %{"error" => "Could not repeat"}
+    end
+  end
+
+  describe "unreblogging" do
+    test "unreblogs and returns the unreblogged status", %{conn: conn} do
+      activity = insert(:note_activity)
+      user = insert(:user)
+
+      {:ok, _, _} = CommonAPI.repeat(activity.id, user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/#{activity.id}/unreblog")
+
+      assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
+
+      assert to_string(activity.id) == id
+    end
+
+    test "returns 400 error when activity is not exist", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/foo/unreblog")
+
+      assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
+    end
+  end
+
+  describe "favoriting" do
+    test "favs a status and returns it", %{conn: conn} do
+      activity = insert(:note_activity)
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/#{activity.id}/favourite")
+
+      assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
+               json_response(conn, 200)
+
+      assert to_string(activity.id) == id
+    end
+
+    test "returns 400 error for a wrong id", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/1/favourite")
+
+      assert json_response(conn, 400) == %{"error" => "Could not favorite"}
+    end
+  end
+
+  describe "unfavoriting" do
+    test "unfavorites a status and returns it", %{conn: conn} do
+      activity = insert(:note_activity)
+      user = insert(:user)
+
+      {:ok, _, _} = CommonAPI.favorite(activity.id, user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/#{activity.id}/unfavourite")
+
+      assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
+               json_response(conn, 200)
+
+      assert to_string(activity.id) == id
+    end
+
+    test "returns 400 error for a wrong id", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/1/unfavourite")
+
+      assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
+    end
+  end
+
+  describe "pinned statuses" do
+    setup do
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+      [user: user, activity: activity]
+    end
+
+    clear_config([:instance, :max_pinned_statuses]) do
+      Config.put([:instance, :max_pinned_statuses], 1)
+    end
+
+    test "pin status", %{conn: conn, user: user, activity: activity} do
+      id_str = to_string(activity.id)
+
+      assert %{"id" => ^id_str, "pinned" => true} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity.id}/pin")
+               |> json_response(200)
+
+      assert [%{"id" => ^id_str, "pinned" => true}] =
+               conn
+               |> assign(:user, user)
+               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+               |> json_response(200)
+    end
+
+    test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
+      {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/#{dm.id}/pin")
+
+      assert json_response(conn, 400) == %{"error" => "Could not pin"}
+    end
+
+    test "unpin status", %{conn: conn, user: user, activity: activity} do
+      {:ok, _} = CommonAPI.pin(activity.id, user)
+
+      id_str = to_string(activity.id)
+      user = refresh_record(user)
+
+      assert %{"id" => ^id_str, "pinned" => false} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity.id}/unpin")
+               |> json_response(200)
+
+      assert [] =
+               conn
+               |> assign(:user, user)
+               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+               |> json_response(200)
+    end
+
+    test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/1/unpin")
+
+      assert json_response(conn, 400) == %{"error" => "Could not unpin"}
+    end
+
+    test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
+      {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+      id_str_one = to_string(activity_one.id)
+
+      assert %{"id" => ^id_str_one, "pinned" => true} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{id_str_one}/pin")
+               |> json_response(200)
+
+      user = refresh_record(user)
+
+      assert %{"error" => "You have already pinned the maximum number of statuses"} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity_two.id}/pin")
+               |> json_response(400)
+    end
+  end
+
+  describe "cards" do
+    setup do
+      Config.put([:rich_media, :enabled], true)
+
+      user = insert(:user)
+      %{user: user}
+    end
+
+    test "returns rich-media card", %{conn: conn, user: user} do
+      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
+
+      card_data = %{
+        "image" => "http://ia.media-imdb.com/images/rock.jpg",
+        "provider_name" => "example.com",
+        "provider_url" => "https://example.com",
+        "title" => "The Rock",
+        "type" => "link",
+        "url" => "https://example.com/ogp",
+        "description" =>
+          "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
+        "pleroma" => %{
+          "opengraph" => %{
+            "image" => "http://ia.media-imdb.com/images/rock.jpg",
+            "title" => "The Rock",
+            "type" => "video.movie",
+            "url" => "https://example.com/ogp",
+            "description" =>
+              "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
+          }
+        }
+      }
+
+      response =
+        conn
+        |> get("/api/v1/statuses/#{activity.id}/card")
+        |> json_response(200)
+
+      assert response == card_data
+
+      # works with private posts
+      {:ok, activity} =
+        CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
+
+      response_two =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/statuses/#{activity.id}/card")
+        |> json_response(200)
+
+      assert response_two == card_data
+    end
+
+    test "replaces missing description with an empty string", %{conn: conn, user: user} do
+      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
+
+      response =
+        conn
+        |> get("/api/v1/statuses/#{activity.id}/card")
+        |> json_response(:ok)
+
+      assert response == %{
+               "type" => "link",
+               "title" => "Pleroma",
+               "description" => "",
+               "image" => nil,
+               "provider_name" => "example.com",
+               "provider_url" => "https://example.com",
+               "url" => "https://example.com/ogp-missing-data",
+               "pleroma" => %{
+                 "opengraph" => %{
+                   "title" => "Pleroma",
+                   "type" => "website",
+                   "url" => "https://example.com/ogp-missing-data"
+                 }
+               }
+             }
+    end
+  end
+
+  test "bookmarks" do
+    user = insert(:user)
+    for_user = insert(:user)
+
+    {:ok, activity1} =
+      CommonAPI.post(user, %{
+        "status" => "heweoo?"
+      })
+
+    {:ok, activity2} =
+      CommonAPI.post(user, %{
+        "status" => "heweoo!"
+      })
+
+    response1 =
+      build_conn()
+      |> assign(:user, for_user)
+      |> post("/api/v1/statuses/#{activity1.id}/bookmark")
+
+    assert json_response(response1, 200)["bookmarked"] == true
+
+    response2 =
+      build_conn()
+      |> assign(:user, for_user)
+      |> post("/api/v1/statuses/#{activity2.id}/bookmark")
+
+    assert json_response(response2, 200)["bookmarked"] == true
+
+    bookmarks =
+      build_conn()
+      |> assign(:user, for_user)
+      |> get("/api/v1/bookmarks")
+
+    assert [json_response(response2, 200), json_response(response1, 200)] ==
+             json_response(bookmarks, 200)
+
+    response1 =
+      build_conn()
+      |> assign(:user, for_user)
+      |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
+
+    assert json_response(response1, 200)["bookmarked"] == false
+
+    bookmarks =
+      build_conn()
+      |> assign(:user, for_user)
+      |> get("/api/v1/bookmarks")
+
+    assert [json_response(response2, 200)] == json_response(bookmarks, 200)
+  end
+
+  describe "conversation muting" do
+    setup do
+      post_user = insert(:user)
+      user = insert(:user)
+
+      {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"})
+
+      [user: user, activity: activity]
+    end
+
+    test "mute conversation", %{conn: conn, user: user, activity: activity} do
+      id_str = to_string(activity.id)
+
+      assert %{"id" => ^id_str, "muted" => true} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity.id}/mute")
+               |> json_response(200)
+    end
+
+    test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
+      {:ok, _} = CommonAPI.add_mute(user, activity)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/statuses/#{activity.id}/mute")
+
+      assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
+    end
+
+    test "unmute conversation", %{conn: conn, user: user, activity: activity} do
+      {:ok, _} = CommonAPI.add_mute(user, activity)
+
+      id_str = to_string(activity.id)
+      user = refresh_record(user)
+
+      assert %{"id" => ^id_str, "muted" => false} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity.id}/unmute")
+               |> json_response(200)
+    end
+  end
+
+  test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
+    user1 = insert(:user)
+    user2 = insert(:user)
+    user3 = insert(:user)
+
+    {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
+
+    # Reply to status from another user
+    conn1 =
+      conn
+      |> assign(:user, user2)
+      |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
+
+    assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
+
+    activity = Activity.get_by_id_with_object(id)
+
+    assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
+    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
+
+    # Reblog from the third user
+    conn2 =
+      conn
+      |> assign(:user, user3)
+      |> post("/api/v1/statuses/#{activity.id}/reblog")
+
+    assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
+             json_response(conn2, 200)
+
+    assert to_string(activity.id) == id
+
+    # Getting third user status
+    conn3 =
+      conn
+      |> assign(:user, user3)
+      |> get("api/v1/timelines/home")
+
+    [reblogged_activity] = json_response(conn3, 200)
+
+    assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
+
+    replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
+    assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
+  end
+
+  describe "GET /api/v1/statuses/:id/favourited_by" do
+    setup do
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+
+      [conn: conn, activity: activity, user: user]
+    end
+
+    test "returns users who have favorited the status", %{conn: conn, activity: activity} do
+      other_user = insert(:user)
+      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+      response =
+        conn
+        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+        |> json_response(:ok)
+
+      [%{"id" => id}] = response
+
+      assert id == other_user.id
+    end
+
+    test "returns empty array when status has not been favorited yet", %{
+      conn: conn,
+      activity: activity
+    } do
+      response =
+        conn
+        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+        |> json_response(:ok)
+
+      assert Enum.empty?(response)
+    end
+
+    test "does not return users who have favorited the status but are blocked", %{
+      conn: %{assigns: %{user: user}} = conn,
+      activity: activity
+    } do
+      other_user = insert(:user)
+      {:ok, user} = User.block(user, other_user)
+
+      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+        |> json_response(:ok)
+
+      assert Enum.empty?(response)
+    end
+
+    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
+      other_user = insert(:user)
+      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+      response =
+        conn
+        |> assign(:user, nil)
+        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+        |> json_response(:ok)
+
+      [%{"id" => id}] = response
+      assert id == other_user.id
+    end
+
+    test "requires authentification for private posts", %{conn: conn, user: user} do
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "@#{other_user.nickname} wanna get some #cofe together?",
+          "visibility" => "direct"
+        })
+
+      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+      conn
+      |> assign(:user, nil)
+      |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+      |> json_response(404)
+
+      response =
+        build_conn()
+        |> assign(:user, other_user)
+        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+        |> json_response(200)
+
+      [%{"id" => id}] = response
+      assert id == other_user.id
+    end
+  end
+
+  describe "GET /api/v1/statuses/:id/reblogged_by" do
+    setup do
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+
+      [conn: conn, activity: activity, user: user]
+    end
+
+    test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
+      other_user = insert(:user)
+      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
+
+      response =
+        conn
+        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+        |> json_response(:ok)
+
+      [%{"id" => id}] = response
+
+      assert id == other_user.id
+    end
+
+    test "returns empty array when status has not been reblogged yet", %{
+      conn: conn,
+      activity: activity
+    } do
+      response =
+        conn
+        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+        |> json_response(:ok)
+
+      assert Enum.empty?(response)
+    end
+
+    test "does not return users who have reblogged the status but are blocked", %{
+      conn: %{assigns: %{user: user}} = conn,
+      activity: activity
+    } do
+      other_user = insert(:user)
+      {:ok, user} = User.block(user, other_user)
+
+      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+        |> json_response(:ok)
+
+      assert Enum.empty?(response)
+    end
+
+    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
+      other_user = insert(:user)
+      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
+
+      response =
+        conn
+        |> assign(:user, nil)
+        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+        |> json_response(:ok)
+
+      [%{"id" => id}] = response
+      assert id == other_user.id
+    end
+
+    test "requires authentification for private posts", %{conn: conn, user: user} do
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "@#{other_user.nickname} wanna get some #cofe together?",
+          "visibility" => "direct"
+        })
+
+      conn
+      |> assign(:user, nil)
+      |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+      |> json_response(404)
+
+      response =
+        build_conn()
+        |> assign(:user, other_user)
+        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+        |> json_response(200)
+
+      assert [] == response
+    end
+  end
+end
index 7f7a89516d2d0b1e94cf4fe78876cb3868a41553..6435ad7a95100c65f4cfc3f7fc04f824665d1ae3 100644 (file)
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
   alias Ecto.Changeset
   alias Pleroma.Activity
-  alias Pleroma.ActivityExpiration
   alias Pleroma.Config
   alias Pleroma.Notification
   alias Pleroma.Object
@@ -37,312 +36,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   clear_config([:instance, :public])
   clear_config([:rich_media, :enabled])
 
-  describe "posting statuses" do
-    setup do
-      user = insert(:user)
-
-      conn =
-        build_conn()
-        |> assign(:user, user)
-
-      [conn: conn]
-    end
-
-    test "posting a status", %{conn: conn} do
-      idempotency_key = "Pikachu rocks!"
-
-      conn_one =
-        conn
-        |> put_req_header("idempotency-key", idempotency_key)
-        |> post("/api/v1/statuses", %{
-          "status" => "cofe",
-          "spoiler_text" => "2hu",
-          "sensitive" => "false"
-        })
-
-      {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
-      # Six hours
-      assert ttl > :timer.seconds(6 * 60 * 60 - 1)
-
-      assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
-               json_response(conn_one, 200)
-
-      assert Activity.get_by_id(id)
-
-      conn_two =
-        conn
-        |> put_req_header("idempotency-key", idempotency_key)
-        |> post("/api/v1/statuses", %{
-          "status" => "cofe",
-          "spoiler_text" => "2hu",
-          "sensitive" => "false"
-        })
-
-      assert %{"id" => second_id} = json_response(conn_two, 200)
-      assert id == second_id
-
-      conn_three =
-        conn
-        |> post("/api/v1/statuses", %{
-          "status" => "cofe",
-          "spoiler_text" => "2hu",
-          "sensitive" => "false"
-        })
-
-      assert %{"id" => third_id} = json_response(conn_three, 200)
-      refute id == third_id
-
-      # An activity that will expire:
-      # 2 hours
-      expires_in = 120 * 60
-
-      conn_four =
-        conn
-        |> post("api/v1/statuses", %{
-          "status" => "oolong",
-          "expires_in" => expires_in
-        })
-
-      assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200)
-      assert activity = Activity.get_by_id(fourth_id)
-      assert expiration = ActivityExpiration.get_by_activity_id(fourth_id)
-
-      estimated_expires_at =
-        NaiveDateTime.utc_now()
-        |> NaiveDateTime.add(expires_in)
-        |> NaiveDateTime.truncate(:second)
-
-      # This assert will fail if the test takes longer than a minute. I sure hope it never does:
-      assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60
-
-      assert fourth_response["pleroma"]["expires_at"] ==
-               NaiveDateTime.to_iso8601(expiration.scheduled_at)
-    end
-
-    test "replying to a status", %{conn: conn} do
-      user = insert(:user)
-      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
-
-      conn =
-        conn
-        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
-
-      assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
-
-      activity = Activity.get_by_id(id)
-
-      assert activity.data["context"] == replied_to.data["context"]
-      assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
-    end
-
-    test "replying to a direct message with visibility other than direct", %{conn: conn} do
-      user = insert(:user)
-      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
-
-      Enum.each(["public", "private", "unlisted"], fn visibility ->
-        conn =
-          conn
-          |> post("/api/v1/statuses", %{
-            "status" => "@#{user.nickname} hey",
-            "in_reply_to_id" => replied_to.id,
-            "visibility" => visibility
-          })
-
-        assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
-      end)
-    end
-
-    test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
-      conn =
-        conn
-        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
-
-      assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
-      assert Activity.get_by_id(id)
-    end
-
-    test "posting a sensitive status", %{conn: conn} do
-      conn =
-        conn
-        |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
-
-      assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
-      assert Activity.get_by_id(id)
-    end
-
-    test "posting a fake status", %{conn: conn} do
-      real_conn =
-        conn
-        |> post("/api/v1/statuses", %{
-          "status" =>
-            "\"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"
-        })
-
-      real_status = json_response(real_conn, 200)
-
-      assert real_status
-      assert Object.get_by_ap_id(real_status["uri"])
-
-      real_status =
-        real_status
-        |> Map.put("id", nil)
-        |> Map.put("url", nil)
-        |> Map.put("uri", nil)
-        |> Map.put("created_at", nil)
-        |> Kernel.put_in(["pleroma", "conversation_id"], nil)
-
-      fake_conn =
-        conn
-        |> post("/api/v1/statuses", %{
-          "status" =>
-            "\"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",
-          "preview" => true
-        })
-
-      fake_status = json_response(fake_conn, 200)
-
-      assert fake_status
-      refute Object.get_by_ap_id(fake_status["uri"])
-
-      fake_status =
-        fake_status
-        |> Map.put("id", nil)
-        |> Map.put("url", nil)
-        |> Map.put("uri", nil)
-        |> Map.put("created_at", nil)
-        |> Kernel.put_in(["pleroma", "conversation_id"], nil)
-
-      assert real_status == fake_status
-    end
-
-    test "posting a status with OGP link preview", %{conn: conn} do
-      Config.put([:rich_media, :enabled], true)
-
-      conn =
-        conn
-        |> post("/api/v1/statuses", %{
-          "status" => "https://example.com/ogp"
-        })
-
-      assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
-      assert Activity.get_by_id(id)
-    end
-
-    test "posting a direct status", %{conn: conn} do
-      user2 = insert(:user)
-      content = "direct cofe @#{user2.nickname}"
-
-      conn =
-        conn
-        |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
-
-      assert %{"id" => id} = response = json_response(conn, 200)
-      assert response["visibility"] == "direct"
-      assert response["pleroma"]["direct_conversation_id"]
-      assert activity = Activity.get_by_id(id)
-      assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
-      assert activity.data["to"] == [user2.ap_id]
-      assert activity.data["cc"] == []
-    end
-  end
-
-  describe "posting polls" do
-    test "posting a poll", %{conn: conn} do
-      user = insert(:user)
-      time = NaiveDateTime.utc_now()
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses", %{
-          "status" => "Who is the #bestgrill?",
-          "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
-        })
-
-      response = json_response(conn, 200)
-
-      assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
-               title in ["Rei", "Asuka", "Misato"]
-             end)
-
-      assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
-      refute response["poll"]["expred"]
-    end
-
-    test "option limit is enforced", %{conn: conn} do
-      user = insert(:user)
-      limit = Config.get([:instance, :poll_limits, :max_options])
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses", %{
-          "status" => "desu~",
-          "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
-        })
-
-      %{"error" => error} = json_response(conn, 422)
-      assert error == "Poll can't contain more than #{limit} options"
-    end
-
-    test "option character limit is enforced", %{conn: conn} do
-      user = insert(:user)
-      limit = Config.get([:instance, :poll_limits, :max_option_chars])
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses", %{
-          "status" => "...",
-          "poll" => %{
-            "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
-            "expires_in" => 1
-          }
-        })
-
-      %{"error" => error} = json_response(conn, 422)
-      assert error == "Poll options cannot be longer than #{limit} characters each"
-    end
-
-    test "minimal date limit is enforced", %{conn: conn} do
-      user = insert(:user)
-      limit = Config.get([:instance, :poll_limits, :min_expiration])
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses", %{
-          "status" => "imagine arbitrary limits",
-          "poll" => %{
-            "options" => ["this post was made by pleroma gang"],
-            "expires_in" => limit - 1
-          }
-        })
-
-      %{"error" => error} = json_response(conn, 422)
-      assert error == "Expiration date is too soon"
-    end
-
-    test "maximum date limit is enforced", %{conn: conn} do
-      user = insert(:user)
-      limit = Config.get([:instance, :poll_limits, :max_expiration])
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses", %{
-          "status" => "imagine arbitrary limits",
-          "poll" => %{
-            "options" => ["this post was made by pleroma gang"],
-            "expires_in" => limit + 1
-          }
-        })
-
-      %{"error" => error} = json_response(conn, 422)
-      assert error == "Expiration date is too far in the future"
-    end
-  end
-
   test "Conversations", %{conn: conn} do
     user_one = insert(:user)
     user_two = insert(:user)
@@ -575,81 +268,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     assert expected == json_response(conn, 200)
   end
 
-  test "get a status", %{conn: conn} do
-    activity = insert(:note_activity)
-
-    conn =
-      conn
-      |> get("/api/v1/statuses/#{activity.id}")
-
-    assert %{"id" => id} = json_response(conn, 200)
-    assert id == to_string(activity.id)
-  end
-
-  test "get statuses by IDs", %{conn: conn} do
-    %{id: id1} = insert(:note_activity)
-    %{id: id2} = insert(:note_activity)
-
-    query_string = "ids[]=#{id1}&ids[]=#{id2}"
-    conn = get(conn, "/api/v1/statuses/?#{query_string}")
-
-    assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"])
-  end
-
-  describe "deleting a status" do
-    test "when you created it", %{conn: conn} do
-      activity = insert(:note_activity)
-      author = User.get_cached_by_ap_id(activity.data["actor"])
-
-      conn =
-        conn
-        |> assign(:user, author)
-        |> delete("/api/v1/statuses/#{activity.id}")
-
-      assert %{} = json_response(conn, 200)
-
-      refute Activity.get_by_id(activity.id)
-    end
-
-    test "when you didn't create it", %{conn: conn} do
-      activity = insert(:note_activity)
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> delete("/api/v1/statuses/#{activity.id}")
-
-      assert %{"error" => _} = json_response(conn, 403)
-
-      assert Activity.get_by_id(activity.id) == activity
-    end
-
-    test "when you're an admin or moderator", %{conn: conn} do
-      activity1 = insert(:note_activity)
-      activity2 = insert(:note_activity)
-      admin = insert(:user, info: %{is_admin: true})
-      moderator = insert(:user, info: %{is_moderator: true})
-
-      res_conn =
-        conn
-        |> assign(:user, admin)
-        |> delete("/api/v1/statuses/#{activity1.id}")
-
-      assert %{} = json_response(res_conn, 200)
-
-      res_conn =
-        conn
-        |> assign(:user, moderator)
-        |> delete("/api/v1/statuses/#{activity2.id}")
-
-      assert %{} = json_response(res_conn, 200)
-
-      refute Activity.get_by_id(activity1.id)
-      refute Activity.get_by_id(activity2.id)
-    end
-  end
-
   describe "filters" do
     test "creating a filter", %{conn: conn} do
       user = insert(:user)
@@ -778,160 +396,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
-  describe "reblogging" do
-    test "reblogs and returns the reblogged status", %{conn: conn} do
-      activity = insert(:note_activity)
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/#{activity.id}/reblog")
-
-      assert %{
-               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
-               "reblogged" => true
-             } = json_response(conn, 200)
-
-      assert to_string(activity.id) == id
-    end
-
-    test "reblogged status for another user", %{conn: conn} do
-      activity = insert(:note_activity)
-      user1 = insert(:user)
-      user2 = insert(:user)
-      user3 = insert(:user)
-      CommonAPI.favorite(activity.id, user2)
-      {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
-      {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
-      {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
-
-      conn_res =
-        conn
-        |> assign(:user, user3)
-        |> get("/api/v1/statuses/#{reblog_activity1.id}")
-
-      assert %{
-               "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
-               "reblogged" => false,
-               "favourited" => false,
-               "bookmarked" => false
-             } = json_response(conn_res, 200)
-
-      conn_res =
-        conn
-        |> assign(:user, user2)
-        |> get("/api/v1/statuses/#{reblog_activity1.id}")
-
-      assert %{
-               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
-               "reblogged" => true,
-               "favourited" => true,
-               "bookmarked" => true
-             } = json_response(conn_res, 200)
-
-      assert to_string(activity.id) == id
-    end
-
-    test "returns 400 error when activity is not exist", %{conn: conn} do
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/foo/reblog")
-
-      assert json_response(conn, 400) == %{"error" => "Could not repeat"}
-    end
-  end
-
-  describe "unreblogging" do
-    test "unreblogs and returns the unreblogged status", %{conn: conn} do
-      activity = insert(:note_activity)
-      user = insert(:user)
-
-      {:ok, _, _} = CommonAPI.repeat(activity.id, user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/#{activity.id}/unreblog")
-
-      assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
-
-      assert to_string(activity.id) == id
-    end
-
-    test "returns 400 error when activity is not exist", %{conn: conn} do
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/foo/unreblog")
-
-      assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
-    end
-  end
-
-  describe "favoriting" do
-    test "favs a status and returns it", %{conn: conn} do
-      activity = insert(:note_activity)
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/#{activity.id}/favourite")
-
-      assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
-               json_response(conn, 200)
-
-      assert to_string(activity.id) == id
-    end
-
-    test "returns 400 error for a wrong id", %{conn: conn} do
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/1/favourite")
-
-      assert json_response(conn, 400) == %{"error" => "Could not favorite"}
-    end
-  end
-
-  describe "unfavoriting" do
-    test "unfavorites a status and returns it", %{conn: conn} do
-      activity = insert(:note_activity)
-      user = insert(:user)
-
-      {:ok, _, _} = CommonAPI.favorite(activity.id, user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/#{activity.id}/unfavourite")
-
-      assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
-               json_response(conn, 200)
-
-      assert to_string(activity.id) == id
-    end
-
-    test "returns 400 error for a wrong id", %{conn: conn} do
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/1/unfavourite")
-
-      assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
-    end
-  end
-
   describe "user timelines" do
     test "gets a users statuses", %{conn: conn} do
       user_one = insert(:user)
@@ -2025,346 +1489,91 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
              "thumbnail" => _,
              "languages" => _,
              "registrations" => _,
-             "poll_limits" => _
-           } = result
-
-    assert email == from_config_email
-  end
-
-  test "get instance stats", %{conn: conn} do
-    user = insert(:user, %{local: true})
-
-    user2 = insert(:user, %{local: true})
-    {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
-
-    insert(:user, %{local: false, nickname: "u@peer1.com"})
-    insert(:user, %{local: false, nickname: "u@peer2.com"})
-
-    {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
-
-    # Stats should count users with missing or nil `info.deactivated` value
-
-    {:ok, _user} =
-      user.id
-      |> User.get_cached_by_id()
-      |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
-
-    Pleroma.Stats.force_update()
-
-    conn = get(conn, "/api/v1/instance")
-
-    assert result = json_response(conn, 200)
-
-    stats = result["stats"]
-
-    assert stats
-    assert stats["user_count"] == 1
-    assert stats["status_count"] == 1
-    assert stats["domain_count"] == 2
-  end
-
-  test "get peers", %{conn: conn} do
-    insert(:user, %{local: false, nickname: "u@peer1.com"})
-    insert(:user, %{local: false, nickname: "u@peer2.com"})
-
-    Pleroma.Stats.force_update()
-
-    conn = get(conn, "/api/v1/instance/peers")
-
-    assert result = json_response(conn, 200)
-
-    assert ["peer1.com", "peer2.com"] == Enum.sort(result)
-  end
-
-  test "put settings", %{conn: conn} do
-    user = insert(:user)
-
-    conn =
-      conn
-      |> assign(:user, user)
-      |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
-
-    assert _result = json_response(conn, 200)
-
-    user = User.get_cached_by_ap_id(user.ap_id)
-    assert user.info.settings == %{"programming" => "socks"}
-  end
-
-  describe "pinned statuses" do
-    setup do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
-
-      [user: user, activity: activity]
-    end
-
-    clear_config([:instance, :max_pinned_statuses]) do
-      Config.put([:instance, :max_pinned_statuses], 1)
-    end
-
-    test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
-      {:ok, _} = CommonAPI.pin(activity.id, user)
-
-      result =
-        conn
-        |> assign(:user, user)
-        |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
-        |> json_response(200)
-
-      id_str = to_string(activity.id)
-
-      assert [%{"id" => ^id_str, "pinned" => true}] = result
-    end
-
-    test "pin status", %{conn: conn, user: user, activity: activity} do
-      id_str = to_string(activity.id)
-
-      assert %{"id" => ^id_str, "pinned" => true} =
-               conn
-               |> assign(:user, user)
-               |> post("/api/v1/statuses/#{activity.id}/pin")
-               |> json_response(200)
-
-      assert [%{"id" => ^id_str, "pinned" => true}] =
-               conn
-               |> assign(:user, user)
-               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
-               |> json_response(200)
-    end
-
-    test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
-      {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/#{dm.id}/pin")
-
-      assert json_response(conn, 400) == %{"error" => "Could not pin"}
-    end
-
-    test "unpin status", %{conn: conn, user: user, activity: activity} do
-      {:ok, _} = CommonAPI.pin(activity.id, user)
-
-      id_str = to_string(activity.id)
-      user = refresh_record(user)
-
-      assert %{"id" => ^id_str, "pinned" => false} =
-               conn
-               |> assign(:user, user)
-               |> post("/api/v1/statuses/#{activity.id}/unpin")
-               |> json_response(200)
-
-      assert [] =
-               conn
-               |> assign(:user, user)
-               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
-               |> json_response(200)
-    end
+             "poll_limits" => _
+           } = result
 
-    test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/statuses/1/unpin")
+    assert email == from_config_email
+  end
 
-      assert json_response(conn, 400) == %{"error" => "Could not unpin"}
-    end
+  test "get instance stats", %{conn: conn} do
+    user = insert(:user, %{local: true})
 
-    test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
-      {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
+    user2 = insert(:user, %{local: true})
+    {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
 
-      id_str_one = to_string(activity_one.id)
+    insert(:user, %{local: false, nickname: "u@peer1.com"})
+    insert(:user, %{local: false, nickname: "u@peer2.com"})
 
-      assert %{"id" => ^id_str_one, "pinned" => true} =
-               conn
-               |> assign(:user, user)
-               |> post("/api/v1/statuses/#{id_str_one}/pin")
-               |> json_response(200)
+    {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
 
-      user = refresh_record(user)
+    # Stats should count users with missing or nil `info.deactivated` value
 
-      assert %{"error" => "You have already pinned the maximum number of statuses"} =
-               conn
-               |> assign(:user, user)
-               |> post("/api/v1/statuses/#{activity_two.id}/pin")
-               |> json_response(400)
-    end
-  end
+    {:ok, _user} =
+      user.id
+      |> User.get_cached_by_id()
+      |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
 
-  describe "cards" do
-    setup do
-      Config.put([:rich_media, :enabled], true)
+    Pleroma.Stats.force_update()
 
-      user = insert(:user)
-      %{user: user}
-    end
-
-    test "returns rich-media card", %{conn: conn, user: user} do
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
-
-      card_data = %{
-        "image" => "http://ia.media-imdb.com/images/rock.jpg",
-        "provider_name" => "example.com",
-        "provider_url" => "https://example.com",
-        "title" => "The Rock",
-        "type" => "link",
-        "url" => "https://example.com/ogp",
-        "description" =>
-          "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
-        "pleroma" => %{
-          "opengraph" => %{
-            "image" => "http://ia.media-imdb.com/images/rock.jpg",
-            "title" => "The Rock",
-            "type" => "video.movie",
-            "url" => "https://example.com/ogp",
-            "description" =>
-              "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
-          }
-        }
-      }
+    conn = get(conn, "/api/v1/instance")
 
-      response =
-        conn
-        |> get("/api/v1/statuses/#{activity.id}/card")
-        |> json_response(200)
+    assert result = json_response(conn, 200)
 
-      assert response == card_data
+    stats = result["stats"]
 
-      # works with private posts
-      {:ok, activity} =
-        CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
+    assert stats
+    assert stats["user_count"] == 1
+    assert stats["status_count"] == 1
+    assert stats["domain_count"] == 2
+  end
 
-      response_two =
-        conn
-        |> assign(:user, user)
-        |> get("/api/v1/statuses/#{activity.id}/card")
-        |> json_response(200)
+  test "get peers", %{conn: conn} do
+    insert(:user, %{local: false, nickname: "u@peer1.com"})
+    insert(:user, %{local: false, nickname: "u@peer2.com"})
 
-      assert response_two == card_data
-    end
+    Pleroma.Stats.force_update()
 
-    test "replaces missing description with an empty string", %{conn: conn, user: user} do
-      {:ok, activity} =
-        CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
+    conn = get(conn, "/api/v1/instance/peers")
 
-      response =
-        conn
-        |> get("/api/v1/statuses/#{activity.id}/card")
-        |> json_response(:ok)
+    assert result = json_response(conn, 200)
 
-      assert response == %{
-               "type" => "link",
-               "title" => "Pleroma",
-               "description" => "",
-               "image" => nil,
-               "provider_name" => "example.com",
-               "provider_url" => "https://example.com",
-               "url" => "https://example.com/ogp-missing-data",
-               "pleroma" => %{
-                 "opengraph" => %{
-                   "title" => "Pleroma",
-                   "type" => "website",
-                   "url" => "https://example.com/ogp-missing-data"
-                 }
-               }
-             }
-    end
+    assert ["peer1.com", "peer2.com"] == Enum.sort(result)
   end
 
-  test "bookmarks" do
+  test "put settings", %{conn: conn} do
     user = insert(:user)
-    for_user = insert(:user)
-
-    {:ok, activity1} =
-      CommonAPI.post(user, %{
-        "status" => "heweoo?"
-      })
 
-    {:ok, activity2} =
-      CommonAPI.post(user, %{
-        "status" => "heweoo!"
-      })
-
-    response1 =
-      build_conn()
-      |> assign(:user, for_user)
-      |> post("/api/v1/statuses/#{activity1.id}/bookmark")
-
-    assert json_response(response1, 200)["bookmarked"] == true
-
-    response2 =
-      build_conn()
-      |> assign(:user, for_user)
-      |> post("/api/v1/statuses/#{activity2.id}/bookmark")
-
-    assert json_response(response2, 200)["bookmarked"] == true
-
-    bookmarks =
-      build_conn()
-      |> assign(:user, for_user)
-      |> get("/api/v1/bookmarks")
-
-    assert [json_response(response2, 200), json_response(response1, 200)] ==
-             json_response(bookmarks, 200)
-
-    response1 =
-      build_conn()
-      |> assign(:user, for_user)
-      |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
-
-    assert json_response(response1, 200)["bookmarked"] == false
+    conn =
+      conn
+      |> assign(:user, user)
+      |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
 
-    bookmarks =
-      build_conn()
-      |> assign(:user, for_user)
-      |> get("/api/v1/bookmarks")
+    assert _result = json_response(conn, 200)
 
-    assert [json_response(response2, 200)] == json_response(bookmarks, 200)
+    user = User.get_cached_by_ap_id(user.ap_id)
+    assert user.info.settings == %{"programming" => "socks"}
   end
 
-  describe "conversation muting" do
+  describe "pinned statuses" do
     setup do
-      post_user = insert(:user)
       user = insert(:user)
-
-      {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"})
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
 
       [user: user, activity: activity]
     end
 
-    test "mute conversation", %{conn: conn, user: user, activity: activity} do
-      id_str = to_string(activity.id)
-
-      assert %{"id" => ^id_str, "muted" => true} =
-               conn
-               |> assign(:user, user)
-               |> post("/api/v1/statuses/#{activity.id}/mute")
-               |> json_response(200)
-    end
-
-    test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
-      {:ok, _} = CommonAPI.add_mute(user, activity)
+    test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
+      {:ok, _} = CommonAPI.pin(activity.id, user)
 
-      conn =
+      result =
         conn
         |> assign(:user, user)
-        |> post("/api/v1/statuses/#{activity.id}/mute")
-
-      assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
-    end
-
-    test "unmute conversation", %{conn: conn, user: user, activity: activity} do
-      {:ok, _} = CommonAPI.add_mute(user, activity)
+        |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+        |> json_response(200)
 
       id_str = to_string(activity.id)
-      user = refresh_record(user)
 
-      assert %{"id" => ^id_str, "muted" => false} =
-               conn
-               |> assign(:user, user)
-               |> post("/api/v1/statuses/#{activity.id}/unmute")
-               |> json_response(200)
+      assert [%{"id" => ^id_str, "pinned" => true}] = result
     end
   end
 
@@ -2811,51 +2020,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
-  test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
-    user1 = insert(:user)
-    user2 = insert(:user)
-    user3 = insert(:user)
-
-    {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
-
-    # Reply to status from another user
-    conn1 =
-      conn
-      |> assign(:user, user2)
-      |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
-
-    assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
-
-    activity = Activity.get_by_id_with_object(id)
-
-    assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
-    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
-
-    # Reblog from the third user
-    conn2 =
-      conn
-      |> assign(:user, user3)
-      |> post("/api/v1/statuses/#{activity.id}/reblog")
-
-    assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
-             json_response(conn2, 200)
-
-    assert to_string(activity.id) == id
-
-    # Getting third user status
-    conn3 =
-      conn
-      |> assign(:user, user3)
-      |> get("api/v1/timelines/home")
-
-    [reblogged_activity] = json_response(conn3, 200)
-
-    assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
-
-    replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
-    assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
-  end
-
   describe "create account by app" do
     test "Account registration via Application", %{conn: conn} do
       conn =
@@ -3135,197 +2299,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
-  describe "GET /api/v1/statuses/:id/favourited_by" do
-    setup do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
-
-      conn =
-        build_conn()
-        |> assign(:user, user)
-
-      [conn: conn, activity: activity, user: user]
-    end
-
-    test "returns users who have favorited the status", %{conn: conn, activity: activity} do
-      other_user = insert(:user)
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
-      response =
-        conn
-        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
-        |> json_response(:ok)
-
-      [%{"id" => id}] = response
-
-      assert id == other_user.id
-    end
-
-    test "returns empty array when status has not been favorited yet", %{
-      conn: conn,
-      activity: activity
-    } do
-      response =
-        conn
-        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
-        |> json_response(:ok)
-
-      assert Enum.empty?(response)
-    end
-
-    test "does not return users who have favorited the status but are blocked", %{
-      conn: %{assigns: %{user: user}} = conn,
-      activity: activity
-    } do
-      other_user = insert(:user)
-      {:ok, user} = User.block(user, other_user)
-
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
-      response =
-        conn
-        |> assign(:user, user)
-        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
-        |> json_response(:ok)
-
-      assert Enum.empty?(response)
-    end
-
-    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
-      other_user = insert(:user)
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
-      response =
-        conn
-        |> assign(:user, nil)
-        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
-        |> json_response(:ok)
-
-      [%{"id" => id}] = response
-      assert id == other_user.id
-    end
-
-    test "requires authentification for private posts", %{conn: conn, user: user} do
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "@#{other_user.nickname} wanna get some #cofe together?",
-          "visibility" => "direct"
-        })
-
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
-      conn
-      |> assign(:user, nil)
-      |> get("/api/v1/statuses/#{activity.id}/favourited_by")
-      |> json_response(404)
-
-      response =
-        build_conn()
-        |> assign(:user, other_user)
-        |> get("/api/v1/statuses/#{activity.id}/favourited_by")
-        |> json_response(200)
-
-      [%{"id" => id}] = response
-      assert id == other_user.id
-    end
-  end
-
-  describe "GET /api/v1/statuses/:id/reblogged_by" do
-    setup do
-      user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
-
-      conn =
-        build_conn()
-        |> assign(:user, user)
-
-      [conn: conn, activity: activity, user: user]
-    end
-
-    test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
-      other_user = insert(:user)
-      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
-
-      response =
-        conn
-        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
-        |> json_response(:ok)
-
-      [%{"id" => id}] = response
-
-      assert id == other_user.id
-    end
-
-    test "returns empty array when status has not been reblogged yet", %{
-      conn: conn,
-      activity: activity
-    } do
-      response =
-        conn
-        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
-        |> json_response(:ok)
-
-      assert Enum.empty?(response)
-    end
-
-    test "does not return users who have reblogged the status but are blocked", %{
-      conn: %{assigns: %{user: user}} = conn,
-      activity: activity
-    } do
-      other_user = insert(:user)
-      {:ok, user} = User.block(user, other_user)
-
-      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
-
-      response =
-        conn
-        |> assign(:user, user)
-        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
-        |> json_response(:ok)
-
-      assert Enum.empty?(response)
-    end
-
-    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
-      other_user = insert(:user)
-      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
-
-      response =
-        conn
-        |> assign(:user, nil)
-        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
-        |> json_response(:ok)
-
-      [%{"id" => id}] = response
-      assert id == other_user.id
-    end
-
-    test "requires authentification for private posts", %{conn: conn, user: user} do
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "@#{other_user.nickname} wanna get some #cofe together?",
-          "visibility" => "direct"
-        })
-
-      conn
-      |> assign(:user, nil)
-      |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
-      |> json_response(404)
-
-      response =
-        build_conn()
-        |> assign(:user, other_user)
-        |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
-        |> json_response(200)
-
-      assert [] == response
-    end
-  end
-
   describe "POST /auth/password, with valid parameters" do
     setup %{conn: conn} do
       user = insert(:user)