# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors 
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
  use Pleroma.Web.ConnCase
  alias Ecto.Changeset
  alias Pleroma.Activity
  alias Pleroma.ActivityExpiration
  alias Pleroma.Config
  alias Pleroma.Notification
  alias Pleroma.Object
  alias Pleroma.Repo
  alias Pleroma.ScheduledActivity
  alias Pleroma.User
  alias Pleroma.Web.ActivityPub.ActivityPub
  alias Pleroma.Web.CommonAPI
  alias Pleroma.Web.MastodonAPI.FilterView
  alias Pleroma.Web.OAuth.App
  alias Pleroma.Web.OAuth.Token
  alias Pleroma.Web.OStatus
  alias Pleroma.Web.Push
  import Pleroma.Factory
  import ExUnit.CaptureLog
  import Tesla.Mock
  import Swoosh.TestAssertions
  @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
  setup do
    mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
    :ok
  end
  clear_config([:instance, :public])
  clear_config([:rich_media, :enabled])
  test "the home timeline", %{conn: conn} do
    user = insert(:user)
    following = insert(:user)
    {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/timelines/home")
    assert Enum.empty?(json_response(conn, 200))
    {:ok, user} = User.follow(user, following)
    conn =
      build_conn()
      |> assign(:user, user)
      |> get("/api/v1/timelines/home")
    assert [%{"content" => "test"}] = json_response(conn, 200)
  end
  test "the public timeline", %{conn: conn} do
    following = insert(:user)
    capture_log(fn ->
      {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
      {:ok, [_activity]} =
        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
      conn =
        conn
        |> get("/api/v1/timelines/public", %{"local" => "False"})
      assert length(json_response(conn, 200)) == 2
      conn =
        build_conn()
        |> get("/api/v1/timelines/public", %{"local" => "True"})
      assert [%{"content" => "test"}] = json_response(conn, 200)
      conn =
        build_conn()
        |> get("/api/v1/timelines/public", %{"local" => "1"})
      assert [%{"content" => "test"}] = json_response(conn, 200)
    end)
  end
  test "the public timeline when public is set to false", %{conn: conn} do
    Config.put([:instance, :public], false)
    assert conn
           |> get("/api/v1/timelines/public", %{"local" => "False"})
           |> json_response(403) == %{"error" => "This resource requires authentication."}
  end
  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, "visibility" => "direct"} = json_response(conn, 200)
      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 "direct timeline", %{conn: conn} do
    user_one = insert(:user)
    user_two = insert(:user)
    {:ok, user_two} = User.follow(user_two, user_one)
    {:ok, direct} =
      CommonAPI.post(user_one, %{
        "status" => "Hi @#{user_two.nickname}!",
        "visibility" => "direct"
      })
    {:ok, _follower_only} =
      CommonAPI.post(user_one, %{
        "status" => "Hi @#{user_two.nickname}!",
        "visibility" => "private"
      })
    # Only direct should be visible here
    res_conn =
      conn
      |> assign(:user, user_two)
      |> get("api/v1/timelines/direct")
    [status] = json_response(res_conn, 200)
    assert %{"visibility" => "direct"} = status
    assert status["url"] != direct.data["id"]
    # User should be able to see their own direct message
    res_conn =
      build_conn()
      |> assign(:user, user_one)
      |> get("api/v1/timelines/direct")
    [status] = json_response(res_conn, 200)
    assert %{"visibility" => "direct"} = status
    # Both should be visible here
    res_conn =
      conn
      |> assign(:user, user_two)
      |> get("api/v1/timelines/home")
    [_s1, _s2] = json_response(res_conn, 200)
    # Test pagination
    Enum.each(1..20, fn _ ->
      {:ok, _} =
        CommonAPI.post(user_one, %{
          "status" => "Hi @#{user_two.nickname}!",
          "visibility" => "direct"
        })
    end)
    res_conn =
      conn
      |> assign(:user, user_two)
      |> get("api/v1/timelines/direct")
    statuses = json_response(res_conn, 200)
    assert length(statuses) == 20
    res_conn =
      conn
      |> assign(:user, user_two)
      |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
    [status] = json_response(res_conn, 200)
    assert status["url"] != direct.data["id"]
  end
  test "Conversations", %{conn: conn} do
    user_one = insert(:user)
    user_two = insert(:user)
    user_three = insert(:user)
    {:ok, user_two} = User.follow(user_two, user_one)
    {:ok, direct} =
      CommonAPI.post(user_one, %{
        "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
        "visibility" => "direct"
      })
    {:ok, _follower_only} =
      CommonAPI.post(user_one, %{
        "status" => "Hi @#{user_two.nickname}!",
        "visibility" => "private"
      })
    res_conn =
      conn
      |> assign(:user, user_one)
      |> get("/api/v1/conversations")
    assert response = json_response(res_conn, 200)
    assert [
             %{
               "id" => res_id,
               "accounts" => res_accounts,
               "last_status" => res_last_status,
               "unread" => unread
             }
           ] = response
    account_ids = Enum.map(res_accounts, & &1["id"])
    assert length(res_accounts) == 2
    assert user_two.id in account_ids
    assert user_three.id in account_ids
    assert is_binary(res_id)
    assert unread == true
    assert res_last_status["id"] == direct.id
    # Apparently undocumented API endpoint
    res_conn =
      conn
      |> assign(:user, user_one)
      |> post("/api/v1/conversations/#{res_id}/read")
    assert response = json_response(res_conn, 200)
    assert length(response["accounts"]) == 2
    assert response["last_status"]["id"] == direct.id
    assert response["unread"] == false
    # (vanilla) Mastodon frontend behaviour
    res_conn =
      conn
      |> assign(:user, user_one)
      |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
    assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
  end
  test "doesn't include DMs from blocked users", %{conn: conn} do
    blocker = insert(:user)
    blocked = insert(:user)
    user = insert(:user)
    {:ok, blocker} = User.block(blocker, blocked)
    {:ok, _blocked_direct} =
      CommonAPI.post(blocked, %{
        "status" => "Hi @#{blocker.nickname}!",
        "visibility" => "direct"
      })
    {:ok, direct} =
      CommonAPI.post(user, %{
        "status" => "Hi @#{blocker.nickname}!",
        "visibility" => "direct"
      })
    res_conn =
      conn
      |> assign(:user, user)
      |> get("api/v1/timelines/direct")
    [status] = json_response(res_conn, 200)
    assert status["id"] == direct.id
  end
  test "verify_credentials", %{conn: conn} do
    user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/accounts/verify_credentials")
    response = json_response(conn, 200)
    assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
    assert response["pleroma"]["chat_token"]
    assert id == to_string(user.id)
  end
  test "verify_credentials default scope unlisted", %{conn: conn} do
    user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/accounts/verify_credentials")
    assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
    assert id == to_string(user.id)
  end
  test "apps/verify_credentials", %{conn: conn} do
    token = insert(:oauth_token)
    conn =
      conn
      |> assign(:user, token.user)
      |> assign(:token, token)
      |> get("/api/v1/apps/verify_credentials")
    app = Repo.preload(token, :app).app
    expected = %{
      "name" => app.client_name,
      "website" => app.website,
      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
    }
    assert expected == json_response(conn, 200)
  end
  test "user avatar can be set", %{conn: conn} do
    user = insert(:user)
    avatar_image = File.read!("test/fixtures/avatar_data_uri")
    conn =
      conn
      |> assign(:user, user)
      |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
    user = refresh_record(user)
    assert %{
             "name" => _,
             "type" => _,
             "url" => [
               %{
                 "href" => _,
                 "mediaType" => _,
                 "type" => _
               }
             ]
           } = user.avatar
    assert %{"url" => _} = json_response(conn, 200)
  end
  test "user avatar can be reset", %{conn: conn} do
    user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
    user = User.get_cached_by_id(user.id)
    assert user.avatar == nil
    assert %{"url" => nil} = json_response(conn, 200)
  end
  test "can set profile banner", %{conn: conn} do
    user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
    user = refresh_record(user)
    assert user.info.banner["type"] == "Image"
    assert %{"url" => _} = json_response(conn, 200)
  end
  test "can reset profile banner", %{conn: conn} do
    user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
    user = refresh_record(user)
    assert user.info.banner == %{}
    assert %{"url" => nil} = json_response(conn, 200)
  end
  test "background image can be set", %{conn: conn} do
    user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
    user = refresh_record(user)
    assert user.info.background["type"] == "Image"
    assert %{"url" => _} = json_response(conn, 200)
  end
  test "background image can be reset", %{conn: conn} do
    user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
    user = refresh_record(user)
    assert user.info.background == %{}
    assert %{"url" => nil} = json_response(conn, 200)
  end
  test "creates an oauth app", %{conn: conn} do
    user = insert(:user)
    app_attrs = build(:oauth_app)
    conn =
      conn
      |> assign(:user, user)
      |> post("/api/v1/apps", %{
        client_name: app_attrs.client_name,
        redirect_uris: app_attrs.redirect_uris
      })
    [app] = Repo.all(App)
    expected = %{
      "name" => app.client_name,
      "website" => app.website,
      "client_id" => app.client_id,
      "client_secret" => app.client_secret,
      "id" => app.id |> to_string(),
      "redirect_uri" => app.redirect_uris,
      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
    }
    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}] = json_response(conn, :ok)
  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)
      filter = %Pleroma.Filter{
        phrase: "knights",
        context: ["home"]
      }
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
      assert response = json_response(conn, 200)
      assert response["phrase"] == filter.phrase
      assert response["context"] == filter.context
      assert response["irreversible"] == false
      assert response["id"] != nil
      assert response["id"] != ""
    end
    test "fetching a list of filters", %{conn: conn} do
      user = insert(:user)
      query_one = %Pleroma.Filter{
        user_id: user.id,
        filter_id: 1,
        phrase: "knights",
        context: ["home"]
      }
      query_two = %Pleroma.Filter{
        user_id: user.id,
        filter_id: 2,
        phrase: "who",
        context: ["home"]
      }
      {:ok, filter_one} = Pleroma.Filter.create(query_one)
      {:ok, filter_two} = Pleroma.Filter.create(query_two)
      response =
        conn
        |> assign(:user, user)
        |> get("/api/v1/filters")
        |> json_response(200)
      assert response ==
               render_json(
                 FilterView,
                 "filters.json",
                 filters: [filter_two, filter_one]
               )
    end
    test "get a filter", %{conn: conn} do
      user = insert(:user)
      query = %Pleroma.Filter{
        user_id: user.id,
        filter_id: 2,
        phrase: "knight",
        context: ["home"]
      }
      {:ok, filter} = Pleroma.Filter.create(query)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/filters/#{filter.filter_id}")
      assert _response = json_response(conn, 200)
    end
    test "update a filter", %{conn: conn} do
      user = insert(:user)
      query = %Pleroma.Filter{
        user_id: user.id,
        filter_id: 2,
        phrase: "knight",
        context: ["home"]
      }
      {:ok, _filter} = Pleroma.Filter.create(query)
      new = %Pleroma.Filter{
        phrase: "nii",
        context: ["home"]
      }
      conn =
        conn
        |> assign(:user, user)
        |> put("/api/v1/filters/#{query.filter_id}", %{
          phrase: new.phrase,
          context: new.context
        })
      assert response = json_response(conn, 200)
      assert response["phrase"] == new.phrase
      assert response["context"] == new.context
    end
    test "delete a filter", %{conn: conn} do
      user = insert(:user)
      query = %Pleroma.Filter{
        user_id: user.id,
        filter_id: 2,
        phrase: "knight",
        context: ["home"]
      }
      {:ok, filter} = Pleroma.Filter.create(query)
      conn =
        conn
        |> assign(:user, user)
        |> delete("/api/v1/filters/#{filter.filter_id}")
      assert response = json_response(conn, 200)
      assert response == %{}
    end
  end
  describe "list timelines" do
    test "list timeline", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."})
      {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
      {:ok, list} = Pleroma.List.create("name", user)
      {:ok, list} = Pleroma.List.follow(list, other_user)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/timelines/list/#{list.id}")
      assert [%{"id" => id}] = json_response(conn, 200)
      assert id == to_string(activity_two.id)
    end
    test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
      {:ok, _activity_two} =
        CommonAPI.post(other_user, %{
          "status" => "Marisa is cute.",
          "visibility" => "private"
        })
      {:ok, list} = Pleroma.List.create("name", user)
      {:ok, list} = Pleroma.List.follow(list, other_user)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/timelines/list/#{list.id}")
      assert [%{"id" => id}] = json_response(conn, 200)
      assert id == to_string(activity_one.id)
    end
  end
  describe "notifications" do
    test "list of notifications", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, [_notification]} = Notification.create_notifications(activity)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/notifications")
      expected_response =
        "hi @#{user.nickname}"
      assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
      assert response == expected_response
    end
    test "getting a single notification", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, [notification]} = Notification.create_notifications(activity)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/notifications/#{notification.id}")
      expected_response =
        "hi @#{user.nickname}"
      assert %{"status" => %{"content" => response}} = json_response(conn, 200)
      assert response == expected_response
    end
    test "dismissing a single notification", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, [notification]} = Notification.create_notifications(activity)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
      assert %{} = json_response(conn, 200)
    end
    test "clearing all notifications", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, [_notification]} = Notification.create_notifications(activity)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/notifications/clear")
      assert %{} = json_response(conn, 200)
      conn =
        build_conn()
        |> assign(:user, user)
        |> get("/api/v1/notifications")
      assert all = json_response(conn, 200)
      assert all == []
    end
    test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
      notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
      notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
      notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
      conn =
        conn
        |> assign(:user, user)
      # min_id
      conn_res =
        conn
        |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
      # since_id
      conn_res =
        conn
        |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
      # max_id
      conn_res =
        conn
        |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
    end
    test "filters notifications using exclude_types", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
      {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
      {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
      {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
      {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
      mention_notification_id =
        Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
      favorite_notification_id =
        Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
      reblog_notification_id =
        Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
      follow_notification_id =
        Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
      conn =
        conn
        |> assign(:user, user)
      conn_res =
        get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
      assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
      conn_res =
        get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
      assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
      conn_res =
        get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
      assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
      conn_res =
        get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
      assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
    end
    test "destroy multiple", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
      {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
      {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
      notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
      notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
      notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
      notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
      conn =
        conn
        |> assign(:user, user)
      conn_res =
        conn
        |> get("/api/v1/notifications")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
      conn2 =
        conn
        |> assign(:user, other_user)
      conn_res =
        conn2
        |> get("/api/v1/notifications")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
      conn_destroy =
        conn
        |> delete("/api/v1/notifications/destroy_multiple", %{
          "ids" => [notification1_id, notification2_id]
        })
      assert json_response(conn_destroy, 200) == %{}
      conn_res =
        conn2
        |> get("/api/v1/notifications")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
    end
    test "doesn't see notifications after muting user with notifications", %{conn: conn} do
      user = insert(:user)
      user2 = insert(:user)
      {:ok, _, _, _} = CommonAPI.follow(user, user2)
      {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
      conn = assign(conn, :user, user)
      conn = get(conn, "/api/v1/notifications")
      assert length(json_response(conn, 200)) == 1
      {:ok, user} = User.mute(user, user2)
      conn = assign(build_conn(), :user, user)
      conn = get(conn, "/api/v1/notifications")
      assert json_response(conn, 200) == []
    end
    test "see notifications after muting user without notifications", %{conn: conn} do
      user = insert(:user)
      user2 = insert(:user)
      {:ok, _, _, _} = CommonAPI.follow(user, user2)
      {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
      conn = assign(conn, :user, user)
      conn = get(conn, "/api/v1/notifications")
      assert length(json_response(conn, 200)) == 1
      {:ok, user} = User.mute(user, user2, false)
      conn = assign(build_conn(), :user, user)
      conn = get(conn, "/api/v1/notifications")
      assert length(json_response(conn, 200)) == 1
    end
    test "see notifications after muting user with notifications and with_muted parameter", %{
      conn: conn
    } do
      user = insert(:user)
      user2 = insert(:user)
      {:ok, _, _, _} = CommonAPI.follow(user, user2)
      {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
      conn = assign(conn, :user, user)
      conn = get(conn, "/api/v1/notifications")
      assert length(json_response(conn, 200)) == 1
      {:ok, user} = User.mute(user, user2)
      conn = assign(build_conn(), :user, user)
      conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"})
      assert length(json_response(conn, 200)) == 1
    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)
      user_two = insert(:user)
      user_three = insert(:user)
      {:ok, user_three} = User.follow(user_three, user_one)
      {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
      {:ok, direct_activity} =
        CommonAPI.post(user_one, %{
          "status" => "Hi, @#{user_two.nickname}.",
          "visibility" => "direct"
        })
      {:ok, private_activity} =
        CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
      resp =
        conn
        |> get("/api/v1/accounts/#{user_one.id}/statuses")
      assert [%{"id" => id}] = json_response(resp, 200)
      assert id == to_string(activity.id)
      resp =
        conn
        |> assign(:user, user_two)
        |> get("/api/v1/accounts/#{user_one.id}/statuses")
      assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
      assert id_one == to_string(direct_activity.id)
      assert id_two == to_string(activity.id)
      resp =
        conn
        |> assign(:user, user_three)
        |> get("/api/v1/accounts/#{user_one.id}/statuses")
      assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
      assert id_one == to_string(private_activity.id)
      assert id_two == to_string(activity.id)
    end
    test "unimplemented pinned statuses feature", %{conn: conn} do
      note = insert(:note_activity)
      user = User.get_cached_by_ap_id(note.data["actor"])
      conn =
        conn
        |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
      assert json_response(conn, 200) == []
    end
    test "gets an users media", %{conn: conn} do
      note = insert(:note_activity)
      user = User.get_cached_by_ap_id(note.data["actor"])
      file = %Plug.Upload{
        content_type: "image/jpg",
        path: Path.absname("test/fixtures/image.jpg"),
        filename: "an_image.jpg"
      }
      {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
      {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
      conn =
        conn
        |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
      assert [%{"id" => id}] = json_response(conn, 200)
      assert id == to_string(image_post.id)
      conn =
        build_conn()
        |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
      assert [%{"id" => id}] = json_response(conn, 200)
      assert id == to_string(image_post.id)
    end
    test "gets a user's statuses without reblogs", %{conn: conn} do
      user = insert(:user)
      {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
      {:ok, _, _} = CommonAPI.repeat(post.id, user)
      conn =
        conn
        |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
      assert [%{"id" => id}] = json_response(conn, 200)
      assert id == to_string(post.id)
      conn =
        conn
        |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
      assert [%{"id" => id}] = json_response(conn, 200)
      assert id == to_string(post.id)
    end
    test "filters user's statuses by a hashtag", %{conn: conn} do
      user = insert(:user)
      {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
      {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
      conn =
        conn
        |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
      assert [%{"id" => id}] = json_response(conn, 200)
      assert id == to_string(post.id)
    end
  end
  describe "user relationships" do
    test "returns the relationships for the current user", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, user} = User.follow(user, other_user)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
      assert [relationship] = json_response(conn, 200)
      assert to_string(other_user.id) == relationship["id"]
    end
  end
  describe "media upload" do
    setup do
      user = insert(:user)
      conn =
        build_conn()
        |> assign(:user, user)
      image = %Plug.Upload{
        content_type: "image/jpg",
        path: Path.absname("test/fixtures/image.jpg"),
        filename: "an_image.jpg"
      }
      [conn: conn, image: image]
    end
    clear_config([:media_proxy])
    clear_config([Pleroma.Upload])
    test "returns uploaded image", %{conn: conn, image: image} do
      desc = "Description of the image"
      media =
        conn
        |> post("/api/v1/media", %{"file" => image, "description" => desc})
        |> json_response(:ok)
      assert media["type"] == "image"
      assert media["description"] == desc
      assert media["id"]
      object = Repo.get(Object, media["id"])
      assert object.data["actor"] == User.ap_id(conn.assigns[:user])
    end
  end
  describe "locked accounts" do
    test "/api/v1/follow_requests works" do
      user = insert(:user, %{info: %User.Info{locked: true}})
      other_user = insert(:user)
      {:ok, _activity} = ActivityPub.follow(other_user, user)
      user = User.get_cached_by_id(user.id)
      other_user = User.get_cached_by_id(other_user.id)
      assert User.following?(other_user, user) == false
      conn =
        build_conn()
        |> assign(:user, user)
        |> get("/api/v1/follow_requests")
      assert [relationship] = json_response(conn, 200)
      assert to_string(other_user.id) == relationship["id"]
    end
    test "/api/v1/follow_requests/:id/authorize works" do
      user = insert(:user, %{info: %User.Info{locked: true}})
      other_user = insert(:user)
      {:ok, _activity} = ActivityPub.follow(other_user, user)
      user = User.get_cached_by_id(user.id)
      other_user = User.get_cached_by_id(other_user.id)
      assert User.following?(other_user, user) == false
      conn =
        build_conn()
        |> assign(:user, user)
        |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
      assert relationship = json_response(conn, 200)
      assert to_string(other_user.id) == relationship["id"]
      user = User.get_cached_by_id(user.id)
      other_user = User.get_cached_by_id(other_user.id)
      assert User.following?(other_user, user) == true
    end
    test "verify_credentials", %{conn: conn} do
      user = insert(:user, %{info: %User.Info{default_scope: "private"}})
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/accounts/verify_credentials")
      assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
      assert id == to_string(user.id)
    end
    test "/api/v1/follow_requests/:id/reject works" do
      user = insert(:user, %{info: %User.Info{locked: true}})
      other_user = insert(:user)
      {:ok, _activity} = ActivityPub.follow(other_user, user)
      user = User.get_cached_by_id(user.id)
      conn =
        build_conn()
        |> assign(:user, user)
        |> post("/api/v1/follow_requests/#{other_user.id}/reject")
      assert relationship = json_response(conn, 200)
      assert to_string(other_user.id) == relationship["id"]
      user = User.get_cached_by_id(user.id)
      other_user = User.get_cached_by_id(other_user.id)
      assert User.following?(other_user, user) == false
    end
  end
  describe "account fetching" do
    test "works by id" do
      user = insert(:user)
      conn =
        build_conn()
        |> get("/api/v1/accounts/#{user.id}")
      assert %{"id" => id} = json_response(conn, 200)
      assert id == to_string(user.id)
      conn =
        build_conn()
        |> get("/api/v1/accounts/-1")
      assert %{"error" => "Can't find user"} = json_response(conn, 404)
    end
    test "works by nickname" do
      user = insert(:user)
      conn =
        build_conn()
        |> get("/api/v1/accounts/#{user.nickname}")
      assert %{"id" => id} = json_response(conn, 200)
      assert id == user.id
    end
    test "works by nickname for remote users" do
      limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
      Pleroma.Config.put([:instance, :limit_to_local_content], false)
      user = insert(:user, nickname: "user@example.com", local: false)
      conn =
        build_conn()
        |> get("/api/v1/accounts/#{user.nickname}")
      Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
      assert %{"id" => id} = json_response(conn, 200)
      assert id == user.id
    end
    test "respects limit_to_local_content == :all for remote user nicknames" do
      limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
      Pleroma.Config.put([:instance, :limit_to_local_content], :all)
      user = insert(:user, nickname: "user@example.com", local: false)
      conn =
        build_conn()
        |> get("/api/v1/accounts/#{user.nickname}")
      Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
      assert json_response(conn, 404)
    end
    test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
      limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
      Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
      user = insert(:user, nickname: "user@example.com", local: false)
      reading_user = insert(:user)
      conn =
        build_conn()
        |> get("/api/v1/accounts/#{user.nickname}")
      assert json_response(conn, 404)
      conn =
        build_conn()
        |> assign(:user, reading_user)
        |> get("/api/v1/accounts/#{user.nickname}")
      Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
      assert %{"id" => id} = json_response(conn, 200)
      assert id == user.id
    end
  end
  test "mascot upload", %{conn: conn} do
    user = insert(:user)
    non_image_file = %Plug.Upload{
      content_type: "audio/mpeg",
      path: Path.absname("test/fixtures/sound.mp3"),
      filename: "sound.mp3"
    }
    conn =
      conn
      |> assign(:user, user)
      |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
    assert json_response(conn, 415)
    file = %Plug.Upload{
      content_type: "image/jpg",
      path: Path.absname("test/fixtures/image.jpg"),
      filename: "an_image.jpg"
    }
    conn =
      build_conn()
      |> assign(:user, user)
      |> put("/api/v1/pleroma/mascot", %{"file" => file})
    assert %{"id" => _, "type" => image} = json_response(conn, 200)
  end
  test "mascot retrieving", %{conn: conn} do
    user = insert(:user)
    # When user hasn't set a mascot, we should just get pleroma tan back
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/pleroma/mascot")
    assert %{"url" => url} = json_response(conn, 200)
    assert url =~ "pleroma-fox-tan-smol"
    # When a user sets their mascot, we should get that back
    file = %Plug.Upload{
      content_type: "image/jpg",
      path: Path.absname("test/fixtures/image.jpg"),
      filename: "an_image.jpg"
    }
    conn =
      build_conn()
      |> assign(:user, user)
      |> put("/api/v1/pleroma/mascot", %{"file" => file})
    assert json_response(conn, 200)
    user = User.get_cached_by_id(user.id)
    conn =
      build_conn()
      |> assign(:user, user)
      |> get("/api/v1/pleroma/mascot")
    assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
    assert url =~ "an_image"
  end
  test "hashtag timeline", %{conn: conn} do
    following = insert(:user)
    capture_log(fn ->
      {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
      {:ok, [_activity]} =
        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
      nconn =
        conn
        |> get("/api/v1/timelines/tag/2hu")
      assert [%{"id" => id}] = json_response(nconn, 200)
      assert id == to_string(activity.id)
      # works for different capitalization too
      nconn =
        conn
        |> get("/api/v1/timelines/tag/2HU")
      assert [%{"id" => id}] = json_response(nconn, 200)
      assert id == to_string(activity.id)
    end)
  end
  test "multi-hashtag timeline", %{conn: conn} do
    user = insert(:user)
    {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
    {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
    {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
    any_test =
      conn
      |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
    [status_none, status_test1, status_test] = json_response(any_test, 200)
    assert to_string(activity_test.id) == status_test["id"]
    assert to_string(activity_test1.id) == status_test1["id"]
    assert to_string(activity_none.id) == status_none["id"]
    restricted_test =
      conn
      |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
    assert [status_test1] == json_response(restricted_test, 200)
    all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
    assert [status_none] == json_response(all_test, 200)
  end
  test "getting followers", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user)
    {:ok, user} = User.follow(user, other_user)
    conn =
      conn
      |> get("/api/v1/accounts/#{other_user.id}/followers")
    assert [%{"id" => id}] = json_response(conn, 200)
    assert id == to_string(user.id)
  end
  test "getting followers, hide_followers", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user, %{info: %{hide_followers: true}})
    {:ok, _user} = User.follow(user, other_user)
    conn =
      conn
      |> get("/api/v1/accounts/#{other_user.id}/followers")
    assert [] == json_response(conn, 200)
  end
  test "getting followers, hide_followers, same user requesting", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user, %{info: %{hide_followers: true}})
    {:ok, _user} = User.follow(user, other_user)
    conn =
      conn
      |> assign(:user, other_user)
      |> get("/api/v1/accounts/#{other_user.id}/followers")
    refute [] == json_response(conn, 200)
  end
  test "getting followers, pagination", %{conn: conn} do
    user = insert(:user)
    follower1 = insert(:user)
    follower2 = insert(:user)
    follower3 = insert(:user)
    {:ok, _} = User.follow(follower1, user)
    {:ok, _} = User.follow(follower2, user)
    {:ok, _} = User.follow(follower3, user)
    conn =
      conn
      |> assign(:user, user)
    res_conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
    assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
    assert id3 == follower3.id
    assert id2 == follower2.id
    res_conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
    assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
    assert id2 == follower2.id
    assert id1 == follower1.id
    res_conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
    assert [%{"id" => id2}] = json_response(res_conn, 200)
    assert id2 == follower2.id
    assert [link_header] = get_resp_header(res_conn, "link")
    assert link_header =~ ~r/min_id=#{follower2.id}/
    assert link_header =~ ~r/max_id=#{follower2.id}/
  end
  test "getting following", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user)
    {:ok, user} = User.follow(user, other_user)
    conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/following")
    assert [%{"id" => id}] = json_response(conn, 200)
    assert id == to_string(other_user.id)
  end
  test "getting following, hide_follows", %{conn: conn} do
    user = insert(:user, %{info: %{hide_follows: true}})
    other_user = insert(:user)
    {:ok, user} = User.follow(user, other_user)
    conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/following")
    assert [] == json_response(conn, 200)
  end
  test "getting following, hide_follows, same user requesting", %{conn: conn} do
    user = insert(:user, %{info: %{hide_follows: true}})
    other_user = insert(:user)
    {:ok, user} = User.follow(user, other_user)
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/accounts/#{user.id}/following")
    refute [] == json_response(conn, 200)
  end
  test "getting following, pagination", %{conn: conn} do
    user = insert(:user)
    following1 = insert(:user)
    following2 = insert(:user)
    following3 = insert(:user)
    {:ok, _} = User.follow(user, following1)
    {:ok, _} = User.follow(user, following2)
    {:ok, _} = User.follow(user, following3)
    conn =
      conn
      |> assign(:user, user)
    res_conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
    assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
    assert id3 == following3.id
    assert id2 == following2.id
    res_conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
    assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
    assert id2 == following2.id
    assert id1 == following1.id
    res_conn =
      conn
      |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
    assert [%{"id" => id2}] = json_response(res_conn, 200)
    assert id2 == following2.id
    assert [link_header] = get_resp_header(res_conn, "link")
    assert link_header =~ ~r/min_id=#{following2.id}/
    assert link_header =~ ~r/max_id=#{following2.id}/
  end
  test "following / unfollowing a user", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> post("/api/v1/accounts/#{other_user.id}/follow")
    assert %{"id" => _id, "following" => true} = json_response(conn, 200)
    user = User.get_cached_by_id(user.id)
    conn =
      build_conn()
      |> assign(:user, user)
      |> post("/api/v1/accounts/#{other_user.id}/unfollow")
    assert %{"id" => _id, "following" => false} = json_response(conn, 200)
    user = User.get_cached_by_id(user.id)
    conn =
      build_conn()
      |> assign(:user, user)
      |> post("/api/v1/follows", %{"uri" => other_user.nickname})
    assert %{"id" => id} = json_response(conn, 200)
    assert id == to_string(other_user.id)
  end
  test "following without reblogs" do
    follower = insert(:user)
    followed = insert(:user)
    other_user = insert(:user)
    conn =
      build_conn()
      |> assign(:user, follower)
      |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
    assert %{"showing_reblogs" => false} = json_response(conn, 200)
    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
    {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
    conn =
      build_conn()
      |> assign(:user, User.get_cached_by_id(follower.id))
      |> get("/api/v1/timelines/home")
    assert [] == json_response(conn, 200)
    conn =
      build_conn()
      |> assign(:user, follower)
      |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
    assert %{"showing_reblogs" => true} = json_response(conn, 200)
    conn =
      build_conn()
      |> assign(:user, User.get_cached_by_id(follower.id))
      |> get("/api/v1/timelines/home")
    expected_activity_id = reblog.id
    assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
  end
  test "following / unfollowing errors" do
    user = insert(:user)
    conn =
      build_conn()
      |> assign(:user, user)
    # self follow
    conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
    # self unfollow
    user = User.get_cached_by_id(user.id)
    conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
    # self follow via uri
    user = User.get_cached_by_id(user.id)
    conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
    # follow non existing user
    conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
    # follow non existing user via uri
    conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
    # unfollow non existing user
    conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
  end
  describe "mute/unmute" do
    test "with notifications", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/accounts/#{other_user.id}/mute")
      response = json_response(conn, 200)
      assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
      user = User.get_cached_by_id(user.id)
      conn =
        build_conn()
        |> assign(:user, user)
        |> post("/api/v1/accounts/#{other_user.id}/unmute")
      response = json_response(conn, 200)
      assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
    end
    test "without notifications", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
      response = json_response(conn, 200)
      assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
      user = User.get_cached_by_id(user.id)
      conn =
        build_conn()
        |> assign(:user, user)
        |> post("/api/v1/accounts/#{other_user.id}/unmute")
      response = json_response(conn, 200)
      assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
    end
  end
  test "subscribing / unsubscribing to a user", %{conn: conn} do
    user = insert(:user)
    subscription_target = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
    assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
    conn =
      build_conn()
      |> assign(:user, user)
      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
    assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
  end
  test "getting a list of mutes", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user)
    {:ok, user} = User.mute(user, other_user)
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/mutes")
    other_user_id = to_string(other_user.id)
    assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
  end
  test "blocking / unblocking a user", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user)
    conn =
      conn
      |> assign(:user, user)
      |> post("/api/v1/accounts/#{other_user.id}/block")
    assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
    user = User.get_cached_by_id(user.id)
    conn =
      build_conn()
      |> assign(:user, user)
      |> post("/api/v1/accounts/#{other_user.id}/unblock")
    assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
  end
  test "getting a list of blocks", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user)
    {:ok, user} = User.block(user, other_user)
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/blocks")
    other_user_id = to_string(other_user.id)
    assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
  end
  test "blocking / unblocking a domain", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
    conn =
      conn
      |> assign(:user, user)
      |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
    assert %{} = json_response(conn, 200)
    user = User.get_cached_by_ap_id(user.ap_id)
    assert User.blocks?(user, other_user)
    conn =
      build_conn()
      |> assign(:user, user)
      |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
    assert %{} = json_response(conn, 200)
    user = User.get_cached_by_ap_id(user.ap_id)
    refute User.blocks?(user, other_user)
  end
  test "getting a list of domain blocks", %{conn: conn} do
    user = insert(:user)
    {:ok, user} = User.block_domain(user, "bad.site")
    {:ok, user} = User.block_domain(user, "even.worse.site")
    conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/domain_blocks")
    domain_blocks = json_response(conn, 200)
    assert "bad.site" in domain_blocks
    assert "even.worse.site" in domain_blocks
  end
  test "unimplemented follow_requests, blocks, domain blocks" do
    user = insert(:user)
    ["blocks", "domain_blocks", "follow_requests"]
    |> Enum.each(fn endpoint ->
      conn =
        build_conn()
        |> assign(:user, user)
        |> get("/api/v1/#{endpoint}")
      assert [] = json_response(conn, 200)
    end)
  end
  test "returns the favorites of a user", %{conn: conn} do
    user = insert(:user)
    other_user = insert(:user)
    {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
    {:ok, _, _} = CommonAPI.favorite(activity.id, user)
    first_conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/favourites")
    assert [status] = json_response(first_conn, 200)
    assert status["id"] == to_string(activity.id)
    assert [{"link", _link_header}] =
             Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
    # Honours query params
    {:ok, second_activity} =
      CommonAPI.post(other_user, %{
        "status" =>
          "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
      })
    {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
    last_like = status["id"]
    second_conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/favourites?since_id=#{last_like}")
    assert [second_status] = json_response(second_conn, 200)
    assert second_status["id"] == to_string(second_activity.id)
    third_conn =
      conn
      |> assign(:user, user)
      |> get("/api/v1/favourites?limit=0")
    assert [] = json_response(third_conn, 200)
  end
  describe "getting favorites timeline of specified user" do
    setup do
      [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
      [current_user: current_user, user: user]
    end
    test "returns list of statuses favorited by specified user", %{
      conn: conn,
      current_user: current_user,
      user: user
    } do
      [activity | _] = insert_pair(:note_activity)
      CommonAPI.favorite(activity.id, user)
      response =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
        |> json_response(:ok)
      [like] = response
      assert length(response) == 1
      assert like["id"] == activity.id
    end
    test "returns favorites for specified user_id when user is not logged in", %{
      conn: conn,
      user: user
    } do
      activity = insert(:note_activity)
      CommonAPI.favorite(activity.id, user)
      response =
        conn
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
        |> json_response(:ok)
      assert length(response) == 1
    end
    test "returns favorited DM only when user is logged in and he is one of recipients", %{
      conn: conn,
      current_user: current_user,
      user: user
    } do
      {:ok, direct} =
        CommonAPI.post(current_user, %{
          "status" => "Hi @#{user.nickname}!",
          "visibility" => "direct"
        })
      CommonAPI.favorite(direct.id, user)
      response =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
        |> json_response(:ok)
      assert length(response) == 1
      anonymous_response =
        conn
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
        |> json_response(:ok)
      assert Enum.empty?(anonymous_response)
    end
    test "does not return others' favorited DM when user is not one of recipients", %{
      conn: conn,
      current_user: current_user,
      user: user
    } do
      user_two = insert(:user)
      {:ok, direct} =
        CommonAPI.post(user_two, %{
          "status" => "Hi @#{user.nickname}!",
          "visibility" => "direct"
        })
      CommonAPI.favorite(direct.id, user)
      response =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
        |> json_response(:ok)
      assert Enum.empty?(response)
    end
    test "paginates favorites using since_id and max_id", %{
      conn: conn,
      current_user: current_user,
      user: user
    } do
      activities = insert_list(10, :note_activity)
      Enum.each(activities, fn activity ->
        CommonAPI.favorite(activity.id, user)
      end)
      third_activity = Enum.at(activities, 2)
      seventh_activity = Enum.at(activities, 6)
      response =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
          since_id: third_activity.id,
          max_id: seventh_activity.id
        })
        |> json_response(:ok)
      assert length(response) == 3
      refute third_activity in response
      refute seventh_activity in response
    end
    test "limits favorites using limit parameter", %{
      conn: conn,
      current_user: current_user,
      user: user
    } do
      7
      |> insert_list(:note_activity)
      |> Enum.each(fn activity ->
        CommonAPI.favorite(activity.id, user)
      end)
      response =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
        |> json_response(:ok)
      assert length(response) == 3
    end
    test "returns empty response when user does not have any favorited statuses", %{
      conn: conn,
      current_user: current_user,
      user: user
    } do
      response =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
        |> json_response(:ok)
      assert Enum.empty?(response)
    end
    test "returns 404 error when specified user is not exist", %{conn: conn} do
      conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
      assert json_response(conn, 404) == %{"error" => "Record not found"}
    end
    test "returns 403 error when user has hidden own favorites", %{
      conn: conn,
      current_user: current_user
    } do
      user = insert(:user, %{info: %{hide_favorites: true}})
      activity = insert(:note_activity)
      CommonAPI.favorite(activity.id, user)
      conn =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
      assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
    end
    test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
      user = insert(:user)
      activity = insert(:note_activity)
      CommonAPI.favorite(activity.id, user)
      conn =
        conn
        |> assign(:user, current_user)
        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
      assert user.info.hide_favorites
      assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
    end
  end
  test "get instance information", %{conn: conn} do
    conn = get(conn, "/api/v1/instance")
    assert result = json_response(conn, 200)
    email = Config.get([:instance, :email])
    # Note: not checking for "max_toot_chars" since it's optional
    assert %{
             "uri" => _,
             "title" => _,
             "description" => _,
             "version" => _,
             "email" => from_config_email,
             "urls" => %{
               "streaming_api" => _
             },
             "stats" => _,
             "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
    user = User.get_cached_by_id(user.id)
    info_change = Changeset.change(user.info, %{deactivated: nil})
    {:ok, _user} =
      user
      |> Changeset.change()
      |> Changeset.put_embed(:info, info_change)
      |> User.update_and_set_cache()
    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
    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
      {: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
      {: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
  describe "reports" do
    setup do
      reporter = insert(:user)
      target_user = insert(:user)
      {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
      [reporter: reporter, target_user: target_user, activity: activity]
    end
    test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
      assert %{"action_taken" => false, "id" => _} =
               conn
               |> assign(:user, reporter)
               |> post("/api/v1/reports", %{"account_id" => target_user.id})
               |> json_response(200)
    end
    test "submit a report with statuses and comment", %{
      conn: conn,
      reporter: reporter,
      target_user: target_user,
      activity: activity
    } do
      assert %{"action_taken" => false, "id" => _} =
               conn
               |> assign(:user, reporter)
               |> post("/api/v1/reports", %{
                 "account_id" => target_user.id,
                 "status_ids" => [activity.id],
                 "comment" => "bad status!",
                 "forward" => "false"
               })
               |> json_response(200)
    end
    test "account_id is required", %{
      conn: conn,
      reporter: reporter,
      activity: activity
    } do
      assert %{"error" => "Valid `account_id` required"} =
               conn
               |> assign(:user, reporter)
               |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
               |> json_response(400)
    end
    test "comment must be up to the size specified in the config", %{
      conn: conn,
      reporter: reporter,
      target_user: target_user
    } do
      max_size = Config.get([:instance, :max_report_comment_size], 1000)
      comment = String.pad_trailing("a", max_size + 1, "a")
      error = %{"error" => "Comment must be up to #{max_size} characters"}
      assert ^error =
               conn
               |> assign(:user, reporter)
               |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
               |> json_response(400)
    end
    test "returns error when account is not exist", %{
      conn: conn,
      reporter: reporter,
      activity: activity
    } do
      conn =
        conn
        |> assign(:user, reporter)
        |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
      assert json_response(conn, 400) == %{"error" => "Account not found"}
    end
  end
  describe "link headers" do
    test "preserves parameters in link headers", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity1} =
        CommonAPI.post(other_user, %{
          "status" => "hi @#{user.nickname}",
          "visibility" => "public"
        })
      {:ok, activity2} =
        CommonAPI.post(other_user, %{
          "status" => "hi @#{user.nickname}",
          "visibility" => "public"
        })
      notification1 = Repo.get_by(Notification, activity_id: activity1.id)
      notification2 = Repo.get_by(Notification, activity_id: activity2.id)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/notifications", %{media_only: true})
      assert [link_header] = get_resp_header(conn, "link")
      assert link_header =~ ~r/media_only=true/
      assert link_header =~ ~r/min_id=#{notification2.id}/
      assert link_header =~ ~r/max_id=#{notification1.id}/
    end
  end
  test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
    # Need to set an old-style integer ID to reproduce the problem
    # (these are no longer assigned to new accounts but were preserved
    # for existing accounts during the migration to flakeIDs)
    user_one = insert(:user, %{id: 1212})
    user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
    resp_one =
      conn
      |> get("/api/v1/accounts/#{user_one.id}")
    resp_two =
      conn
      |> get("/api/v1/accounts/#{user_two.nickname}")
    resp_three =
      conn
      |> get("/api/v1/accounts/#{user_two.id}")
    acc_one = json_response(resp_one, 200)
    acc_two = json_response(resp_two, 200)
    acc_three = json_response(resp_three, 200)
    refute acc_one == acc_two
    assert acc_two == acc_three
  end
  describe "custom emoji" do
    test "with tags", %{conn: conn} do
      [emoji | _body] =
        conn
        |> get("/api/v1/custom_emojis")
        |> json_response(200)
      assert Map.has_key?(emoji, "shortcode")
      assert Map.has_key?(emoji, "static_url")
      assert Map.has_key?(emoji, "tags")
      assert is_list(emoji["tags"])
      assert Map.has_key?(emoji, "category")
      assert Map.has_key?(emoji, "url")
      assert Map.has_key?(emoji, "visible_in_picker")
    end
  end
  describe "index/2 redirections" do
    setup %{conn: conn} do
      session_opts = [
        store: :cookie,
        key: "_test",
        signing_salt: "cooldude"
      ]
      conn =
        conn
        |> Plug.Session.call(Plug.Session.init(session_opts))
        |> fetch_session()
      test_path = "/web/statuses/test"
      %{conn: conn, path: test_path}
    end
    test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
      conn = get(conn, path)
      assert conn.status == 302
      assert redirected_to(conn) == "/web/login"
    end
    test "redirects not logged-in users to the login page on private instances", %{
      conn: conn,
      path: path
    } do
      Config.put([:instance, :public], false)
      conn = get(conn, path)
      assert conn.status == 302
      assert redirected_to(conn) == "/web/login"
    end
    test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
      token = insert(:oauth_token)
      conn =
        conn
        |> assign(:user, token.user)
        |> put_session(:oauth_token, token.token)
        |> get(path)
      assert conn.status == 200
    end
    test "saves referer path to session", %{conn: conn, path: path} do
      conn = get(conn, path)
      return_to = Plug.Conn.get_session(conn, :return_to)
      assert return_to == path
    end
    test "redirects to the saved path after log in", %{conn: conn, path: path} do
      app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
      auth = insert(:oauth_authorization, app: app)
      conn =
        conn
        |> put_session(:return_to, path)
        |> get("/web/login", %{code: auth.token})
      assert conn.status == 302
      assert redirected_to(conn) == path
    end
    test "redirects to the getting-started page when referer is not present", %{conn: conn} do
      app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
      auth = insert(:oauth_authorization, app: app)
      conn = get(conn, "/web/login", %{code: auth.token})
      assert conn.status == 302
      assert redirected_to(conn) == "/web/getting-started"
    end
  end
  describe "scheduled activities" do
    test "creates a scheduled activity", %{conn: conn} do
      user = insert(:user)
      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/statuses", %{
          "status" => "scheduled",
          "scheduled_at" => scheduled_at
        })
      assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
      assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
      assert [] == Repo.all(Activity)
    end
    test "creates a scheduled activity with a media attachment", %{conn: conn} do
      user = insert(:user)
      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
      file = %Plug.Upload{
        content_type: "image/jpg",
        path: Path.absname("test/fixtures/image.jpg"),
        filename: "an_image.jpg"
      }
      {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/statuses", %{
          "media_ids" => [to_string(upload.id)],
          "status" => "scheduled",
          "scheduled_at" => scheduled_at
        })
      assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
      assert %{"type" => "image"} = media_attachment
    end
    test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
         %{conn: conn} do
      user = insert(:user)
      scheduled_at =
        NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/statuses", %{
          "status" => "not scheduled",
          "scheduled_at" => scheduled_at
        })
      assert %{"content" => "not scheduled"} = json_response(conn, 200)
      assert [] == Repo.all(ScheduledActivity)
    end
    test "returns error when daily user limit is exceeded", %{conn: conn} do
      user = insert(:user)
      today =
        NaiveDateTime.utc_now()
        |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
        |> NaiveDateTime.to_iso8601()
      attrs = %{params: %{}, scheduled_at: today}
      {:ok, _} = ScheduledActivity.create(user, attrs)
      {:ok, _} = ScheduledActivity.create(user, attrs)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
      assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
    end
    test "returns error when total user limit is exceeded", %{conn: conn} do
      user = insert(:user)
      today =
        NaiveDateTime.utc_now()
        |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
        |> NaiveDateTime.to_iso8601()
      tomorrow =
        NaiveDateTime.utc_now()
        |> NaiveDateTime.add(:timer.hours(36), :millisecond)
        |> NaiveDateTime.to_iso8601()
      attrs = %{params: %{}, scheduled_at: today}
      {:ok, _} = ScheduledActivity.create(user, attrs)
      {:ok, _} = ScheduledActivity.create(user, attrs)
      {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
      assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
    end
    test "shows scheduled activities", %{conn: conn} do
      user = insert(:user)
      scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
      scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
      scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
      scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
      conn =
        conn
        |> assign(:user, user)
      # min_id
      conn_res =
        conn
        |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
      # since_id
      conn_res =
        conn
        |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
      # max_id
      conn_res =
        conn
        |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
      result = json_response(conn_res, 200)
      assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
    end
    test "shows a scheduled activity", %{conn: conn} do
      user = insert(:user)
      scheduled_activity = insert(:scheduled_activity, user: user)
      res_conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
      assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
      assert scheduled_activity_id == scheduled_activity.id |> to_string()
      res_conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/scheduled_statuses/404")
      assert %{"error" => "Record not found"} = json_response(res_conn, 404)
    end
    test "updates a scheduled activity", %{conn: conn} do
      user = insert(:user)
      scheduled_activity = insert(:scheduled_activity, user: user)
      new_scheduled_at =
        NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
      res_conn =
        conn
        |> assign(:user, user)
        |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
          scheduled_at: new_scheduled_at
        })
      assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
      assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
      res_conn =
        conn
        |> assign(:user, user)
        |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
      assert %{"error" => "Record not found"} = json_response(res_conn, 404)
    end
    test "deletes a scheduled activity", %{conn: conn} do
      user = insert(:user)
      scheduled_activity = insert(:scheduled_activity, user: user)
      res_conn =
        conn
        |> assign(:user, user)
        |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
      assert %{} = json_response(res_conn, 200)
      assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
      res_conn =
        conn
        |> assign(:user, user)
        |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
      assert %{"error" => "Record not found"} = json_response(res_conn, 404)
    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 =
        conn
        |> post("/api/v1/apps", %{
          client_name: "client_name",
          redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
          scopes: "read, write, follow"
        })
      %{
        "client_id" => client_id,
        "client_secret" => client_secret,
        "id" => _,
        "name" => "client_name",
        "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
        "vapid_key" => _,
        "website" => nil
      } = json_response(conn, 200)
      conn =
        conn
        |> post("/oauth/token", %{
          grant_type: "client_credentials",
          client_id: client_id,
          client_secret: client_secret
        })
      assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
               json_response(conn, 200)
      assert token
      token_from_db = Repo.get_by(Token, token: token)
      assert token_from_db
      assert refresh
      assert scope == "read write follow"
      conn =
        build_conn()
        |> put_req_header("authorization", "Bearer " <> token)
        |> post("/api/v1/accounts", %{
          username: "lain",
          email: "lain@example.org",
          password: "PlzDontHackLain",
          agreement: true
        })
      %{
        "access_token" => token,
        "created_at" => _created_at,
        "scope" => _scope,
        "token_type" => "Bearer"
      } = json_response(conn, 200)
      token_from_db = Repo.get_by(Token, token: token)
      assert token_from_db
      token_from_db = Repo.preload(token_from_db, :user)
      assert token_from_db.user
      assert token_from_db.user.info.confirmation_pending
    end
    test "rate limit", %{conn: conn} do
      app_token = insert(:oauth_token, user: nil)
      conn =
        put_req_header(conn, "authorization", "Bearer " <> app_token.token)
        |> Map.put(:remote_ip, {15, 15, 15, 15})
      for i <- 1..5 do
        conn =
          conn
          |> post("/api/v1/accounts", %{
            username: "#{i}lain",
            email: "#{i}lain@example.org",
            password: "PlzDontHackLain",
            agreement: true
          })
        %{
          "access_token" => token,
          "created_at" => _created_at,
          "scope" => _scope,
          "token_type" => "Bearer"
        } = json_response(conn, 200)
        token_from_db = Repo.get_by(Token, token: token)
        assert token_from_db
        token_from_db = Repo.preload(token_from_db, :user)
        assert token_from_db.user
        assert token_from_db.user.info.confirmation_pending
      end
      conn =
        conn
        |> post("/api/v1/accounts", %{
          username: "6lain",
          email: "6lain@example.org",
          password: "PlzDontHackLain",
          agreement: true
        })
      assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
    end
  end
  describe "GET /api/v1/polls/:id" do
    test "returns poll entity for object id", %{conn: conn} do
      user = insert(:user)
      {:ok, activity} =
        CommonAPI.post(user, %{
          "status" => "Pleroma does",
          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
        })
      object = Object.normalize(activity)
      conn =
        conn
        |> assign(:user, user)
        |> get("/api/v1/polls/#{object.id}")
      response = json_response(conn, 200)
      id = to_string(object.id)
      assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
    end
    test "does not expose polls for private statuses", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} =
        CommonAPI.post(user, %{
          "status" => "Pleroma does",
          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
          "visibility" => "private"
        })
      object = Object.normalize(activity)
      conn =
        conn
        |> assign(:user, other_user)
        |> get("/api/v1/polls/#{object.id}")
      assert json_response(conn, 404)
    end
  end
  describe "POST /api/v1/polls/:id/votes" do
    test "votes are added to the poll", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} =
        CommonAPI.post(user, %{
          "status" => "A very delicious sandwich",
          "poll" => %{
            "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
            "expires_in" => 20,
            "multiple" => true
          }
        })
      object = Object.normalize(activity)
      conn =
        conn
        |> assign(:user, other_user)
        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
      assert json_response(conn, 200)
      object = Object.get_by_id(object.id)
      assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
               total_items == 1
             end)
    end
    test "author can't vote", %{conn: conn} do
      user = insert(:user)
      {:ok, activity} =
        CommonAPI.post(user, %{
          "status" => "Am I cute?",
          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
        })
      object = Object.normalize(activity)
      assert conn
             |> assign(:user, user)
             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
             |> json_response(422) == %{"error" => "Poll's author can't vote"}
      object = Object.get_by_id(object.id)
      refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
    end
    test "does not allow multiple choices on a single-choice question", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} =
        CommonAPI.post(user, %{
          "status" => "The glass is",
          "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
        })
      object = Object.normalize(activity)
      assert conn
             |> assign(:user, other_user)
             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
             |> json_response(422) == %{"error" => "Too many choices"}
      object = Object.get_by_id(object.id)
      refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
               total_items == 1
             end)
    end
    test "does not allow choice index to be greater than options count", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} =
        CommonAPI.post(user, %{
          "status" => "Am I cute?",
          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
        })
      object = Object.normalize(activity)
      conn =
        conn
        |> assign(:user, other_user)
        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
      assert json_response(conn, 422) == %{"error" => "Invalid indices"}
    end
    test "returns 404 error when object is not exist", %{conn: conn} do
      user = insert(:user)
      conn =
        conn
        |> assign(:user, user)
        |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
      assert json_response(conn, 404) == %{"error" => "Record not found"}
    end
    test "returns 404 when poll is private and not available for user", %{conn: conn} do
      user = insert(:user)
      other_user = insert(:user)
      {:ok, activity} =
        CommonAPI.post(user, %{
          "status" => "Am I cute?",
          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
          "visibility" => "private"
        })
      object = Object.normalize(activity)
      conn =
        conn
        |> assign(:user, other_user)
        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
      assert json_response(conn, 404) == %{"error" => "Record not found"}
    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)
      conn = post(conn, "/auth/password?email=#{user.email}")
      %{conn: conn, user: user}
    end
    test "it returns 204", %{conn: conn} do
      assert json_response(conn, :no_content)
    end
    test "it creates a PasswordResetToken record for user", %{user: user} do
      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
      assert token_record
    end
    test "it sends an email to user", %{user: user} do
      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
      email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
      notify_email = Config.get([:instance, :notify_email])
      instance_name = Config.get([:instance, :name])
      assert_email_sent(
        from: {instance_name, notify_email},
        to: {user.name, user.email},
        html_body: email.html_body
      )
    end
  end
  describe "POST /auth/password, with invalid parameters" do
    setup do
      user = insert(:user)
      {:ok, user: user}
    end
    test "it returns 404 when user is not found", %{conn: conn, user: user} do
      conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
      assert conn.status == 404
      assert conn.resp_body == ""
    end
    test "it returns 400 when user is not local", %{conn: conn, user: user} do
      {:ok, user} = Repo.update(Changeset.change(user, local: false))
      conn = post(conn, "/auth/password?email=#{user.email}")
      assert conn.status == 400
      assert conn.resp_body == ""
    end
  end
  describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
    setup do
      user = insert(:user)
      info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true)
      {:ok, user} =
        user
        |> Changeset.change()
        |> Changeset.put_embed(:info, info_change)
        |> Repo.update()
      assert user.info.confirmation_pending
      [user: user]
    end
    clear_config([:instance, :account_activation_required]) do
      Config.put([:instance, :account_activation_required], true)
    end
    test "resend account confirmation email", %{conn: conn, user: user} do
      conn
      |> assign(:user, user)
      |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
      |> json_response(:no_content)
      email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
      notify_email = Config.get([:instance, :notify_email])
      instance_name = Config.get([:instance, :name])
      assert_email_sent(
        from: {instance_name, notify_email},
        to: {user.name, user.email},
        html_body: email.html_body
      )
    end
  end
  describe "GET /api/v1/suggestions" do
    setup do
      user = insert(:user)
      other_user = insert(:user)
      host = Config.get([Pleroma.Web.Endpoint, :url, :host])
      url500 = "http://test500?#{host}{user.nickname}"
      url200 = "http://test200?#{host}{user.nickname}"
      mock(fn
        %{method: :get, url: ^url500} ->
          %Tesla.Env{status: 500, body: "bad request"}
        %{method: :get, url: ^url200} ->
          %Tesla.Env{
            status: 200,
            body:
              ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
                other_user.ap_id
              }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
          }
      end)
      [user: user, other_user: other_user]
    end
    clear_config(:suggestions)
    test "returns empty result when suggestions disabled", %{conn: conn, user: user} do
      Config.put([:suggestions, :enabled], false)
      res =
        conn
        |> assign(:user, user)
        |> get("/api/v1/suggestions")
        |> json_response(200)
      assert res == []
    end
    test "returns error", %{conn: conn, user: user} do
      Config.put([:suggestions, :enabled], true)
      Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
      res =
        conn
        |> assign(:user, user)
        |> get("/api/v1/suggestions")
        |> json_response(500)
      assert res == "Something went wrong"
    end
    test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do
      Config.put([:suggestions, :enabled], true)
      Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
      res =
        conn
        |> assign(:user, user)
        |> get("/api/v1/suggestions")
        |> json_response(200)
      assert res == [
               %{
                 "acct" => "yj455",
                 "avatar" => "https://social.heldscal.la/avatar/201.jpeg",
                 "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
                 "id" => 0
               },
               %{
                 "acct" => other_user.ap_id,
                 "avatar" => "https://social.heldscal.la/avatar/202.jpeg",
                 "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
                 "id" => other_user.id
               }
             ]
    end
  end
end