Merge branch 'feature/jobs' into 'develop'
[akkoma] / test / web / mastodon_api / mastodon_api_controller_test.exs
index 3f9324fccc76f4fad1bf74d257b974feca714c29..e43bc4508e9e3a9c6d0357afd0910ee444b33958 100644 (file)
@@ -1,13 +1,29 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   use Pleroma.Web.ConnCase
 
   alias Pleroma.Web.TwitterAPI.TwitterAPI
-  alias Pleroma.{Repo, User, Activity, Notification}
-  alias Pleroma.Web.{OStatus, CommonAPI}
+  alias Pleroma.Repo
+  alias Pleroma.User
+  alias Pleroma.Object
+  alias Pleroma.Activity
+  alias Pleroma.Notification
+  alias Pleroma.Web.OStatus
+  alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.ActivityPub.ActivityPub
-
+  alias Pleroma.Web.MastodonAPI.FilterView
+  alias Ecto.Changeset
   import Pleroma.Factory
   import ExUnit.CaptureLog
+  import Tesla.Mock
+
+  setup do
+    mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    :ok
+  end
 
   test "the home timeline", %{conn: conn} do
     user = insert(:user)
@@ -20,7 +36,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       |> assign(:user, user)
       |> get("/api/v1/timelines/home")
 
-    assert length(json_response(conn, 200)) == 0
+    assert Enum.empty?(json_response(conn, 200))
 
     {:ok, user} = User.follow(user, following)
 
@@ -125,6 +141,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     assert Repo.get(Activity, id)
   end
 
+  test "posting a status with OGP link preview", %{conn: conn} do
+    Pleroma.Config.put([:rich_media, :enabled], true)
+    user = insert(:user)
+
+    conn =
+      conn
+      |> assign(:user, user)
+      |> post("/api/v1/statuses", %{
+        "status" => "http://example.com/ogp"
+      })
+
+    assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
+    assert Repo.get(Activity, id)
+    Pleroma.Config.put([:rich_media, :enabled], false)
+  end
+
   test "posting a direct status", %{conn: conn} do
     user1 = insert(:user)
     user2 = insert(:user)
@@ -137,7 +169,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
     assert activity = Repo.get(Activity, id)
-    assert activity.recipients == [user2.ap_id]
+    assert activity.recipients == [user2.ap_id, user1.ap_id]
     assert activity.data["to"] == [user2.ap_id]
     assert activity.data["cc"] == []
   end
@@ -171,6 +203,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     assert %{"visibility" => "direct"} = status
     assert status["url"] != direct.data["id"]
 
+    # User should be able to see his 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
@@ -178,6 +220,32 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       |> 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 "replying to a status", %{conn: conn} do
@@ -226,7 +294,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   end
 
   test "verify_credentials default scope unlisted", %{conn: conn} do
-    user = insert(:user, %{info: %{"default_scope" => "unlisted"}})
+    user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
 
     conn =
       conn
@@ -260,7 +328,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert %{} = json_response(conn, 200)
 
-      assert Repo.get(Activity, activity.id) == nil
+      refute Repo.get(Activity, activity.id)
     end
 
     test "when you didn't create it", %{conn: conn} do
@@ -319,12 +387,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       {:ok, filter_one} = Pleroma.Filter.create(query_one)
       {:ok, filter_two} = Pleroma.Filter.create(query_two)
 
-      conn =
+      response =
         conn
         |> assign(:user, user)
         |> get("/api/v1/filters")
-
-      assert response = json_response(conn, 200)
+        |> json_response(200)
+
+      assert response ==
+               render_json(
+                 FilterView,
+                 "filters.json",
+                 filters: [filter_two, filter_one]
+               )
     end
 
     test "get a filter", %{conn: conn} do
@@ -344,7 +418,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
         |> assign(:user, user)
         |> get("/api/v1/filters/#{filter.filter_id}")
 
-      assert response = json_response(conn, 200)
+      assert _response = json_response(conn, 200)
     end
 
     test "update a filter", %{conn: conn} do
@@ -357,7 +431,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
         context: ["home"]
       }
 
-      {:ok, filter} = Pleroma.Filter.create(query)
+      {:ok, _filter} = Pleroma.Filter.create(query)
 
       new = %Pleroma.Filter{
         phrase: "nii",
@@ -522,7 +596,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       other_user = insert(:user)
       {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
 
-      {:ok, activity_two} =
+      {:ok, _activity_two} =
         TwitterAPI.create_status(other_user, %{
           "status" => "Marisa is cute.",
           "visibility" => "private"
@@ -558,7 +632,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
         |> get("/api/v1/notifications")
 
       expected_response =
-        "hi <span><a href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
+        "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
+          user.ap_id
+        }\">@<span>#{user.nickname}</span></a></span>"
 
       assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
       assert response == expected_response
@@ -579,7 +655,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
         |> get("/api/v1/notifications/#{notification.id}")
 
       expected_response =
-        "hi <span><a href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
+        "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
+          user.ap_id
+        }\">@<span>#{user.nickname}</span></a></span>"
 
       assert %{"status" => %{"content" => response}} = json_response(conn, 200)
       assert response == expected_response
@@ -778,7 +856,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       }
 
       media =
-        TwitterAPI.upload(file, "json")
+        TwitterAPI.upload(file, user, "json")
         |> Poison.decode!()
 
       {:ok, image_post} =
@@ -798,6 +876,26 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       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
   end
 
   describe "user relationships" do
@@ -819,10 +917,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
   describe "locked accounts" do
     test "/api/v1/follow_requests works" do
-      user = insert(:user, %{info: %{"locked" => true}})
+      user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
       other_user = insert(:user)
 
-      {:ok, activity} = ActivityPub.follow(other_user, user)
+      {:ok, _activity} = ActivityPub.follow(other_user, user)
 
       user = Repo.get(User, user.id)
       other_user = Repo.get(User, other_user.id)
@@ -839,15 +937,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
 
     test "/api/v1/follow_requests/:id/authorize works" do
-      user = insert(:user, %{info: %{"locked" => true}})
+      user = insert(:user, %{info: %User.Info{locked: true}})
       other_user = insert(:user)
 
-      {:ok, activity} = ActivityPub.follow(other_user, user)
+      {:ok, _activity} = ActivityPub.follow(other_user, user)
 
       user = Repo.get(User, user.id)
       other_user = Repo.get(User, other_user.id)
 
       assert User.following?(other_user, user) == false
+      assert user.info.follow_request_count == 1
 
       conn =
         build_conn()
@@ -861,10 +960,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       other_user = Repo.get(User, other_user.id)
 
       assert User.following?(other_user, user) == true
+      assert user.info.follow_request_count == 0
     end
 
     test "verify_credentials", %{conn: conn} do
-      user = insert(:user, %{info: %{"default_scope" => "private"}})
+      user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
 
       conn =
         conn
@@ -876,10 +976,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
 
     test "/api/v1/follow_requests/:id/reject works" do
-      user = insert(:user, %{info: %{"locked" => true}})
+      user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
       other_user = insert(:user)
 
-      {:ok, activity} = ActivityPub.follow(other_user, user)
+      {:ok, _activity} = ActivityPub.follow(other_user, user)
+
+      user = Repo.get(User, user.id)
+      assert user.info.follow_request_count == 1
 
       conn =
         build_conn()
@@ -893,6 +996,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       other_user = Repo.get(User, other_user.id)
 
       assert User.following?(other_user, user) == false
+      assert user.info.follow_request_count == 0
     end
   end
 
@@ -933,6 +1037,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert media["type"] == "image"
     assert media["description"] == desc
+    assert media["id"]
+
+    object = Repo.get(Object, media["id"])
+    assert object.data["actor"] == User.ap_id(user)
   end
 
   test "hashtag timeline", %{conn: conn} do
@@ -963,6 +1071,34 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     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)
@@ -976,6 +1112,31 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     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 following", %{conn: conn} do
     user = insert(:user)
     other_user = insert(:user)
@@ -989,6 +1150,31 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     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 "following / unfollowing a user", %{conn: conn} do
     user = insert(:user)
     other_user = insert(:user)
@@ -1079,7 +1265,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     refute User.blocks?(user, other_user)
   end
 
-  test "getting a list of domain blocks" do
+  test "getting a list of domain blocks", %{conn: conn} do
     user = insert(:user)
 
     {:ok, user} = User.block_domain(user, "bad.site")
@@ -1196,6 +1382,24 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end)
   end
 
+  test "search doesn't show statuses that it shouldn't", %{conn: conn} do
+    {:ok, activity} =
+      CommonAPI.post(insert(:user), %{
+        "status" => "This is about 2hu, but private",
+        "visibility" => "private"
+      })
+
+    capture_log(fn ->
+      conn =
+        conn
+        |> get("/api/v1/search", %{"q" => activity.data["object"]["id"]})
+
+      assert results = json_response(conn, 200)
+
+      [] = results["statuses"]
+    end)
+  end
+
   test "search fetches remote accounts", %{conn: conn} do
     conn =
       conn
@@ -1215,26 +1419,74 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     {:ok, _, _} = CommonAPI.favorite(activity.id, user)
 
-    conn =
+    first_conn =
       conn
       |> assign(:user, user)
       |> get("/api/v1/favourites")
 
-    assert [status] = json_response(conn, 200)
+    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 "updating credentials" do
     test "updates the user's bio", %{conn: conn} do
       user = insert(:user)
+      user2 = insert(:user)
 
       conn =
         conn
         |> assign(:user, user)
-        |> patch("/api/v1/accounts/update_credentials", %{"note" => "I drink #cofe"})
+        |> patch("/api/v1/accounts/update_credentials", %{
+          "note" => "I drink #cofe with @#{user2.nickname}"
+        })
 
       assert user = json_response(conn, 200)
-      assert user["note"] == "I drink #cofe"
+
+      assert user["note"] ==
+               "I drink <a class=\"hashtag\" data-tag=\"cofe\" href=\"http://localhost:4001/tag/cofe\">#cofe</a> with <span class=\"h-card\"><a data-user=\"#{
+                 user2.id
+               }\" class=\"u-url mention\" href=\"#{user2.ap_id}\">@<span>#{user2.nickname}</span></a></span>"
+    end
+
+    test "updates the user's locking status", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
+
+      assert user = json_response(conn, 200)
+      assert user["locked"] == true
     end
 
     test "updates the user's name", %{conn: conn} do
@@ -1263,8 +1515,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
         |> assign(:user, user)
         |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
 
-      assert user = json_response(conn, 200)
-      assert user["avatar"] != "https://placehold.it/48x48"
+      assert user_response = json_response(conn, 200)
+      assert user_response["avatar"] != User.avatar_url(user)
     end
 
     test "updates the user's banner", %{conn: conn} do
@@ -1281,27 +1533,288 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
         |> assign(:user, user)
         |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
 
-      assert user = json_response(conn, 200)
-      assert user["header"] != "https://placehold.it/700x335"
+      assert user_response = json_response(conn, 200)
+      assert user_response["header"] != User.banner_url(user)
     end
   end
 
   test "get instance information", %{conn: conn} do
-    insert(:user, %{local: true})
     user = insert(:user, %{local: true})
-    insert(:user, %{local: false})
+
+    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, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
 
+    # Stats should count users with missing or nil `info.deactivated` value
+    user = Repo.get(User, 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.update_stats()
 
+    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.update_stats()
+
+    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
-      |> get("/api/v1/instance")
+      |> assign(:user, user)
+      |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
 
-    assert result = json_response(conn, 200)
+    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
+      Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+      [user: user, activity: activity]
+    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 "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 "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
+
+    test "Status rich-media Card", %{conn: conn, user: user} do
+      Pleroma.Config.put([:rich_media, :enabled], true)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
+
+      response =
+        conn
+        |> get("/api/v1/statuses/#{activity.id}/card")
+        |> json_response(200)
+
+      assert response == %{
+               "image" => "http://ia.media-imdb.com/images/rock.jpg",
+               "provider_name" => "www.imdb.com",
+               "provider_url" => "http://www.imdb.com",
+               "title" => "The Rock",
+               "type" => "link",
+               "url" => "http://www.imdb.com/title/tt0117500/",
+               "description" => nil,
+               "pleroma" => %{
+                 "opengraph" => %{
+                   "image" => "http://ia.media-imdb.com/images/rock.jpg",
+                   "title" => "The Rock",
+                   "type" => "video.movie",
+                   "url" => "http://www.imdb.com/title/tt0117500/"
+                 }
+               }
+             }
+
+      Pleroma.Config.put([:rich_media, :enabled], false)
+    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
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.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 "unmute conversation", %{conn: conn, user: user, activity: activity} do
+      {:ok, _} = CommonAPI.add_mute(user, activity)
+
+      id_str = to_string(activity.id)
+      user = refresh_record(user)
+
+      assert %{"id" => ^id_str, "muted" => false} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity.id}/unmute")
+               |> json_response(200)
+    end
+  end
+
+  test "flavours switching (Pleroma Extension)", %{conn: conn} do
+    user = insert(:user)
+
+    get_old_flavour =
+      conn
+      |> assign(:user, user)
+      |> get("/api/v1/pleroma/flavour")
+
+    assert "glitch" == json_response(get_old_flavour, 200)
+
+    set_flavour =
+      conn
+      |> assign(:user, user)
+      |> post("/api/v1/pleroma/flavour/vanilla")
+
+    assert "vanilla" == json_response(set_flavour, 200)
+
+    get_new_flavour =
+      conn
+      |> assign(:user, user)
+      |> post("/api/v1/pleroma/flavour/vanilla")
 
-    assert result["stats"]["user_count"] == 2
-    assert result["stats"]["status_count"] == 1
+    assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
   end
 end