Extract timeline actions from `MastodonAPIController` into `TimelineController`
authorEgor Kislitsyn <egor@kislitsyn.com>
Thu, 26 Sep 2019 03:53:42 +0000 (10:53 +0700)
committerEgor Kislitsyn <egor@kislitsyn.com>
Thu, 26 Sep 2019 03:53:42 +0000 (10:53 +0700)
lib/pleroma/web/controller_helper.ex
lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex [new file with mode: 0644]
lib/pleroma/web/router.ex
test/web/mastodon_api/controllers/timeline_controller_test.exs [new file with mode: 0644]
test/web/mastodon_api/mastodon_api_controller_test.exs

index b53a01955d3cf0c1b60a7072385ec3a8b4c0b3f9..e90bf842ee37bf625dea3da85accc85f4a227865 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.ControllerHelper do
   use Pleroma.Web, :controller
 
   # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
-  @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
+  @falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
   def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
   def truthy_param?(value), do: value not in @falsy_param_values
 
index 1e88ff7feec2c1dba5a2772911f0d8881e17a2c6..74a8b50556891408746fbc817a835f4749e4f0b9 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   use Pleroma.Web, :controller
 
   import Pleroma.Web.ControllerHelper,
-    only: [json_response: 3, add_link_headers: 2, add_link_headers: 3]
+    only: [json_response: 3, add_link_headers: 2, truthy_param?: 1]
 
   alias Ecto.Changeset
   alias Pleroma.Activity
@@ -44,7 +44,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   alias Pleroma.Web.OAuth.Token
   alias Pleroma.Web.TwitterAPI.TwitterAPI
 
-  alias Pleroma.Web.ControllerHelper
   import Ecto.Query
 
   require Logger
@@ -156,7 +155,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
       ]
       |> Enum.reduce(%{}, fn key, acc ->
         add_if_present(acc, params, to_string(key), key, fn value ->
-          {:ok, ControllerHelper.truthy_param?(value)}
+          {:ok, truthy_param?(value)}
         end)
       end)
       |> add_if_present(params, "default_scope", :default_scope)
@@ -344,43 +343,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     json(conn, mastodon_emoji)
   end
 
-  def home_timeline(%{assigns: %{user: user}} = conn, params) do
-    params =
-      params
-      |> Map.put("type", ["Create", "Announce"])
-      |> Map.put("blocking_user", user)
-      |> Map.put("muting_user", user)
-      |> Map.put("user", user)
-
-    activities =
-      [user.ap_id | user.following]
-      |> ActivityPub.fetch_activities(params)
-      |> Enum.reverse()
-
-    conn
-    |> add_link_headers(activities)
-    |> put_view(StatusView)
-    |> render("index.json", %{activities: activities, for: user, as: :activity})
-  end
-
-  def public_timeline(%{assigns: %{user: user}} = conn, params) do
-    local_only = params["local"] in [true, "True", "true", "1"]
-
-    activities =
-      params
-      |> Map.put("type", ["Create", "Announce"])
-      |> Map.put("local_only", local_only)
-      |> Map.put("blocking_user", user)
-      |> Map.put("muting_user", user)
-      |> ActivityPub.fetch_public_activities()
-      |> Enum.reverse()
-
-    conn
-    |> add_link_headers(activities, %{"local" => local_only})
-    |> put_view(StatusView)
-    |> render("index.json", %{activities: activities, for: user, as: :activity})
-  end
-
   def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
     with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
       params =
@@ -400,25 +362,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  def dm_timeline(%{assigns: %{user: user}} = conn, params) do
-    params =
-      params
-      |> Map.put("type", "Create")
-      |> Map.put("blocking_user", user)
-      |> Map.put("user", user)
-      |> Map.put(:visibility, "direct")
-
-    activities =
-      [user.ap_id]
-      |> ActivityPub.fetch_activities_query(params)
-      |> Pagination.fetch_paginated(params)
-
-    conn
-    |> add_link_headers(activities)
-    |> put_view(StatusView)
-    |> render("index.json", %{activities: activities, for: user, as: :activity})
-  end
-
   def get_statuses(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
     limit = 100
 
@@ -822,45 +765,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do
-    local_only = params["local"] in [true, "True", "true", "1"]
-
-    tags =
-      [params["tag"], params["any"]]
-      |> List.flatten()
-      |> Enum.uniq()
-      |> Enum.filter(& &1)
-      |> Enum.map(&String.downcase(&1))
-
-    tag_all =
-      params["all"] ||
-        []
-        |> Enum.map(&String.downcase(&1))
-
-    tag_reject =
-      params["none"] ||
-        []
-        |> Enum.map(&String.downcase(&1))
-
-    activities =
-      params
-      |> Map.put("type", "Create")
-      |> Map.put("local_only", local_only)
-      |> Map.put("blocking_user", user)
-      |> Map.put("muting_user", user)
-      |> Map.put("user", user)
-      |> Map.put("tag", tags)
-      |> Map.put("tag_all", tag_all)
-      |> Map.put("tag_reject", tag_reject)
-      |> ActivityPub.fetch_public_activities()
-      |> Enum.reverse()
-
-    conn
-    |> add_link_headers(activities, %{"local" => local_only})
-    |> put_view(StatusView)
-    |> render("index.json", %{activities: activities, for: user, as: :activity})
-  end
-
   def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
     with %User{} = user <- User.get_cached_by_id(id),
          followers <- MastodonAPI.get_followers(user, params) do
@@ -1173,31 +1077,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     json(conn, res)
   end
 
-  def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do
-    with %Pleroma.List{title: _title, following: following} <- Pleroma.List.get(id, user) do
-      params =
-        params
-        |> Map.put("type", "Create")
-        |> Map.put("blocking_user", user)
-        |> Map.put("user", user)
-        |> Map.put("muting_user", user)
-
-      # we must filter the following list for the user to avoid leaking statuses the user
-      # does not actually have permission to see (for more info, peruse security issue #270).
-      activities =
-        following
-        |> Enum.filter(fn x -> x in user.following end)
-        |> ActivityPub.fetch_activities_bounded(following, params)
-        |> Enum.reverse()
-
-      conn
-      |> put_view(StatusView)
-      |> render("index.json", %{activities: activities, for: user, as: :activity})
-    else
-      _e -> render_error(conn, :forbidden, "Error.")
-    end
-  end
-
   def index(%{assigns: %{user: user}} = conn, _params) do
     token = get_session(conn, :oauth_token)
 
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
new file mode 100644 (file)
index 0000000..bb8b0eb
--- /dev/null
@@ -0,0 +1,136 @@
+# 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.TimelineController do
+  use Pleroma.Web, :controller
+
+  import Pleroma.Web.ControllerHelper,
+    only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1]
+
+  alias Pleroma.Pagination
+  alias Pleroma.Web.ActivityPub.ActivityPub
+
+  plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
+
+  # GET /api/v1/timelines/home
+  def home(%{assigns: %{user: user}} = conn, params) do
+    params =
+      params
+      |> Map.put("type", ["Create", "Announce"])
+      |> Map.put("blocking_user", user)
+      |> Map.put("muting_user", user)
+      |> Map.put("user", user)
+
+    recipients = [user.ap_id | user.following]
+
+    activities =
+      recipients
+      |> ActivityPub.fetch_activities(params)
+      |> Enum.reverse()
+
+    conn
+    |> add_link_headers(activities)
+    |> render("index.json", activities: activities, for: user, as: :activity)
+  end
+
+  # GET /api/v1/timelines/direct
+  def direct(%{assigns: %{user: user}} = conn, params) do
+    params =
+      params
+      |> Map.put("type", "Create")
+      |> Map.put("blocking_user", user)
+      |> Map.put("user", user)
+      |> Map.put(:visibility, "direct")
+
+    activities =
+      [user.ap_id]
+      |> ActivityPub.fetch_activities_query(params)
+      |> Pagination.fetch_paginated(params)
+
+    conn
+    |> add_link_headers(activities)
+    |> render("index.json", activities: activities, for: user, as: :activity)
+  end
+
+  # GET /api/v1/timelines/public
+  def public(%{assigns: %{user: user}} = conn, params) do
+    local_only = truthy_param?(params["local"])
+
+    activities =
+      params
+      |> Map.put("type", ["Create", "Announce"])
+      |> Map.put("local_only", local_only)
+      |> Map.put("blocking_user", user)
+      |> Map.put("muting_user", user)
+      |> ActivityPub.fetch_public_activities()
+      |> Enum.reverse()
+
+    conn
+    |> add_link_headers(activities, %{"local" => local_only})
+    |> render("index.json", activities: activities, for: user, as: :activity)
+  end
+
+  # GET /api/v1/timelines/tag/:tag
+  def hashtag(%{assigns: %{user: user}} = conn, params) do
+    local_only = truthy_param?(params["local"])
+
+    tags =
+      [params["tag"], params["any"]]
+      |> List.flatten()
+      |> Enum.uniq()
+      |> Enum.filter(& &1)
+      |> Enum.map(&String.downcase(&1))
+
+    tag_all =
+      params
+      |> Map.get("all", [])
+      |> Enum.map(&String.downcase(&1))
+
+    tag_reject =
+      params
+      |> Map.get("none", [])
+      |> Enum.map(&String.downcase(&1))
+
+    activities =
+      params
+      |> Map.put("type", "Create")
+      |> Map.put("local_only", local_only)
+      |> Map.put("blocking_user", user)
+      |> Map.put("muting_user", user)
+      |> Map.put("user", user)
+      |> Map.put("tag", tags)
+      |> Map.put("tag_all", tag_all)
+      |> Map.put("tag_reject", tag_reject)
+      |> ActivityPub.fetch_public_activities()
+      |> Enum.reverse()
+
+    conn
+    |> add_link_headers(activities, %{"local" => local_only})
+    |> render("index.json", activities: activities, for: user, as: :activity)
+  end
+
+  # GET /api/v1/timelines/list/:list_id
+  def list(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do
+    with %Pleroma.List{title: _title, following: following} <- Pleroma.List.get(id, user) do
+      params =
+        params
+        |> Map.put("type", "Create")
+        |> Map.put("blocking_user", user)
+        |> Map.put("user", user)
+        |> Map.put("muting_user", user)
+
+      # we must filter the following list for the user to avoid leaking statuses the user
+      # does not actually have permission to see (for more info, peruse security issue #270).
+      activities =
+        following
+        |> Enum.filter(fn x -> x in user.following end)
+        |> ActivityPub.fetch_activities_bounded(following, params)
+        |> Enum.reverse()
+
+      render(conn, "index.json", activities: activities, for: user, as: :activity)
+    else
+      _e -> render_error(conn, :forbidden, "Error.")
+    end
+  end
+end
index 316c895eee3fb5af8f76bd40ea0f6771063c1240..2575481ff50021fe9b2f285863d2ef9d3f11833a 100644 (file)
@@ -319,8 +319,8 @@ defmodule Pleroma.Web.Router do
       get("/blocks", MastodonAPIController, :blocks)
       get("/mutes", MastodonAPIController, :mutes)
 
-      get("/timelines/home", MastodonAPIController, :home_timeline)
-      get("/timelines/direct", MastodonAPIController, :dm_timeline)
+      get("/timelines/home", TimelineController, :home)
+      get("/timelines/direct", TimelineController, :direct)
 
       get("/favourites", MastodonAPIController, :favourites)
       get("/bookmarks", MastodonAPIController, :bookmarks)
@@ -466,9 +466,9 @@ defmodule Pleroma.Web.Router do
     scope [] do
       pipe_through(:oauth_read_or_public)
 
-      get("/timelines/public", MastodonAPIController, :public_timeline)
-      get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline)
-      get("/timelines/list/:list_id", MastodonAPIController, :list_timeline)
+      get("/timelines/public", TimelineController, :public)
+      get("/timelines/tag/:tag", TimelineController, :hashtag)
+      get("/timelines/list/:list_id", TimelineController, :list)
 
       get("/statuses", MastodonAPIController, :get_statuses)
       get("/statuses/:id", MastodonAPIController, :get_status)
diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs
new file mode 100644 (file)
index 0000000..d3652d9
--- /dev/null
@@ -0,0 +1,291 @@
+# 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.TimelineControllerTest do
+  use Pleroma.Web.ConnCase
+
+  import Pleroma.Factory
+  import Tesla.Mock
+
+  alias Pleroma.Config
+  alias Pleroma.User
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.OStatus
+
+  clear_config([:instance, :public])
+
+  setup do
+    mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    :ok
+  end
+
+  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, :ok))
+
+    {:ok, user} = User.follow(user, following)
+
+    conn =
+      build_conn()
+      |> assign(:user, user)
+      |> get("/api/v1/timelines/home")
+
+    assert [%{"content" => "test"}] = json_response(conn, :ok)
+  end
+
+  describe "public" do
+    @tag capture_log: true
+    test "the public timeline", %{conn: conn} do
+      following = insert(:user)
+
+      {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
+
+      {:ok, [_activity]} =
+        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
+
+      conn = get(conn, "/api/v1/timelines/public", %{"local" => "False"})
+
+      assert length(json_response(conn, :ok)) == 2
+
+      conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "True"})
+
+      assert [%{"content" => "test"}] = json_response(conn, :ok)
+
+      conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "1"})
+
+      assert [%{"content" => "test"}] = json_response(conn, :ok)
+    end
+
+    test "the public timeline when public is set to false", %{conn: conn} do
+      Config.put([:instance, :public], false)
+
+      assert %{"error" => "This resource requires authentication."} ==
+               conn
+               |> get("/api/v1/timelines/public", %{"local" => "False"})
+               |> json_response(:forbidden)
+    end
+
+    test "the public timeline includes only public statuses for an authenticated user" do
+      user = insert(:user)
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+
+      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"})
+      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"})
+      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"})
+      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
+
+      res_conn = get(conn, "/api/v1/timelines/public")
+      assert length(json_response(res_conn, 200)) == 1
+    end
+  end
+
+  describe "direct" do
+    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, :ok)
+
+      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, :ok)
+
+      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, :ok)
+
+      # 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, :ok)
+      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, :ok)
+
+      assert status["url"] != direct.data["id"]
+    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, :ok)
+      assert status["id"] == direct.id
+    end
+  end
+
+  describe "list" 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, :ok)
+
+      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, :ok)
+
+      assert id == to_string(activity_one.id)
+    end
+  end
+
+  describe "hashtag" do
+    @tag capture_log: true
+    test "hashtag timeline", %{conn: conn} do
+      following = insert(:user)
+
+      {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
+
+      {:ok, [_activity]} =
+        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
+
+      nconn = get(conn, "/api/v1/timelines/tag/2hu")
+
+      assert [%{"id" => id}] = json_response(nconn, :ok)
+
+      assert id == to_string(activity.id)
+
+      # works for different capitalization too
+      nconn = get(conn, "/api/v1/timelines/tag/2HU")
+
+      assert [%{"id" => id}] = json_response(nconn, :ok)
+
+      assert id == to_string(activity.id)
+    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 = get(conn, "/api/v1/timelines/tag/test", %{"any" => ["test1"]})
+
+      [status_none, status_test1, status_test] = json_response(any_test, :ok)
+
+      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 =
+        get(conn, "/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
+
+      assert [status_test1] == json_response(restricted_test, :ok)
+
+      all_test = get(conn, "/api/v1/timelines/tag/test", %{"all" => ["none"]})
+
+      assert [status_none] == json_response(all_test, :ok)
+    end
+  end
+end
index cd672132bb6a0542488f83dab8fd50877427ddf6..7f7a89516d2d0b1e94cf4fe78876cb3868a41553 100644 (file)
@@ -20,12 +20,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   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 Pleroma.Factory
   import Swoosh.TestAssertions
+  import Tesla.Mock
 
   @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
 
@@ -37,82 +37,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   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
-
-  test "the public timeline includes only public statuses for an authenticated user" do
-    user = insert(:user)
-
-    conn =
-      build_conn()
-      |> assign(:user, user)
-
-    {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"})
-    {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"})
-    {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"})
-    {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
-
-    res_conn = get(conn, "/api/v1/timelines/public")
-    assert length(json_response(res_conn, 200)) == 1
-  end
-
   describe "posting statuses" do
     setup do
       user = insert(:user)
@@ -419,80 +343,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     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)
@@ -556,33 +406,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     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)
 
@@ -955,50 +778,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     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 "reblogging" do
     test "reblogs and returns the reblogged status", %{conn: conn} do
       activity = insert(:note_activity)
@@ -1554,62 +1333,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     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)