Merge branch 'develop' into issue/2099
authorMaksim Pechnikov <parallel588@gmail.com>
Fri, 18 Sep 2020 19:13:05 +0000 (22:13 +0300)
committerMaksim Pechnikov <parallel588@gmail.com>
Fri, 18 Sep 2020 19:13:05 +0000 (22:13 +0300)
13 files changed:
CHANGELOG.md
docs/API/pleroma_api.md
lib/pleroma/user.ex
lib/pleroma/user/import.ex [new file with mode: 0644]
lib/pleroma/web/api_spec/operations/user_import_operation.ex [new file with mode: 0644]
lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex [new file with mode: 0644]
lib/pleroma/web/router.ex
lib/pleroma/web/twitter_api/controllers/util_controller.ex
lib/pleroma/workers/background_worker.ex
test/user/import_test.exs [new file with mode: 0644]
test/user_test.exs
test/web/pleroma_api/controllers/user_import_controller_test.exs [new file with mode: 0644]
test/web/twitter_api/util_controller_test.exs

index 5a7e27fd3ab3e184a757014e3f09abed73951f69..e61b1d14443ac71247cea97215b5b3b13138d645 100644 (file)
@@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ### Added
 - Media preview proxy (requires media proxy be enabled; see `:media_preview_proxy` config for more details).
+- Pleroma API: Importing the mutes users from CSV files.
 
 ### Removed
 
@@ -27,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Removed `:managed_config` option. In practice, it was accidentally removed with 2.0.0 release when frontends were
 switched to a new configuration mechanism, however it was not officially removed until now.
 
+
 ## [2.1.2] - 2020-09-17
 
 ### Security
index 4e97d26c052d0e0969cbe33f21db507139a9880e..94b6a4fda5195e7f7b355a489e25136fe33766a6 100644 (file)
@@ -44,6 +44,22 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
 * Response: HTTP 200 on success, 500 on error
 * Note: Users that can't be followed are silently skipped.
 
+## `/api/pleroma/blocks_import`
+### Imports your blocks.
+* Method: `POST`
+* Authentication: required
+* Params:
+    * `list`: STRING or FILE containing a whitespace-separated list of accounts to block
+* Response: HTTP 200 on success, 500 on error
+
+## `/api/pleroma/mutes_import`
+### Imports your mutes.
+* Method: `POST`
+* Authentication: required
+* Params:
+    * `list`: STRING or FILE containing a whitespace-separated list of accounts to mute
+* Response: HTTP 200 on success, 500 on error
+
 ## `/api/pleroma/captcha`
 ### Get a new captcha
 * Method: `GET`
index d92484a40b9de23dcbd2a7737d269dc35b491a44..410c9cbac1a67cd78fd0c13a6098c66e16262d4e 100644 (file)
@@ -1685,42 +1685,6 @@ defmodule Pleroma.User do
 
   def perform(:deactivate_async, user, status), do: deactivate(user, status)
 
-  @spec perform(atom(), User.t(), list()) :: list() | {:error, any()}
-  def perform(:blocks_import, %User{} = blocker, blocked_identifiers)
-      when is_list(blocked_identifiers) do
-    Enum.map(
-      blocked_identifiers,
-      fn blocked_identifier ->
-        with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier),
-             {:ok, _block} <- CommonAPI.block(blocker, blocked) do
-          blocked
-        else
-          err ->
-            Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}")
-            err
-        end
-      end
-    )
-  end
-
-  def perform(:follow_import, %User{} = follower, followed_identifiers)
-      when is_list(followed_identifiers) do
-    Enum.map(
-      followed_identifiers,
-      fn followed_identifier ->
-        with {:ok, %User{} = followed} <- get_or_fetch(followed_identifier),
-             {:ok, follower} <- maybe_direct_follow(follower, followed),
-             {:ok, _, _, _} <- CommonAPI.follow(follower, followed) do
-          followed
-        else
-          err ->
-            Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}")
-            err
-        end
-      end
-    )
-  end
-
   @spec external_users_query() :: Ecto.Query.t()
   def external_users_query do
     User.Query.build(%{
@@ -1749,21 +1713,6 @@ defmodule Pleroma.User do
     Repo.all(query)
   end
 
-  def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do
-    BackgroundWorker.enqueue("blocks_import", %{
-      "blocker_id" => blocker.id,
-      "blocked_identifiers" => blocked_identifiers
-    })
-  end
-
-  def follow_import(%User{} = follower, followed_identifiers)
-      when is_list(followed_identifiers) do
-    BackgroundWorker.enqueue("follow_import", %{
-      "follower_id" => follower.id,
-      "followed_identifiers" => followed_identifiers
-    })
-  end
-
   def delete_notifications_from_user_activities(%User{ap_id: ap_id}) do
     Notification
     |> join(:inner, [n], activity in assoc(n, :activity))
diff --git a/lib/pleroma/user/import.ex b/lib/pleroma/user/import.ex
new file mode 100644 (file)
index 0000000..e458021
--- /dev/null
@@ -0,0 +1,85 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.Import do
+  use Ecto.Schema
+
+  alias Pleroma.User
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Workers.BackgroundWorker
+
+  require Logger
+
+  @spec perform(atom(), User.t(), list()) :: :ok | list() | {:error, any()}
+  def perform(:mutes_import, %User{} = user, [_ | _] = identifiers) do
+    Enum.map(
+      identifiers,
+      fn identifier ->
+        with {:ok, %User{} = muted_user} <- User.get_or_fetch(identifier),
+             {:ok, _} <- User.mute(user, muted_user) do
+          muted_user
+        else
+          error -> handle_error(:mutes_import, identifier, error)
+        end
+      end
+    )
+  end
+
+  def perform(:blocks_import, %User{} = blocker, [_ | _] = identifiers) do
+    Enum.map(
+      identifiers,
+      fn identifier ->
+        with {:ok, %User{} = blocked} <- User.get_or_fetch(identifier),
+             {:ok, _block} <- CommonAPI.block(blocker, blocked) do
+          blocked
+        else
+          error -> handle_error(:blocks_import, identifier, error)
+        end
+      end
+    )
+  end
+
+  def perform(:follow_import, %User{} = follower, [_ | _] = identifiers) do
+    Enum.map(
+      identifiers,
+      fn identifier ->
+        with {:ok, %User{} = followed} <- User.get_or_fetch(identifier),
+             {:ok, follower} <- User.maybe_direct_follow(follower, followed),
+             {:ok, _, _, _} <- CommonAPI.follow(follower, followed) do
+          followed
+        else
+          error -> handle_error(:follow_import, identifier, error)
+        end
+      end
+    )
+  end
+
+  def perform(_, _, _), do: :ok
+
+  defp handle_error(op, user_id, error) do
+    Logger.debug("#{op} failed for #{user_id} with: #{inspect(error)}")
+    error
+  end
+
+  def blocks_import(%User{} = blocker, [_ | _] = identifiers) do
+    BackgroundWorker.enqueue(
+      "blocks_import",
+      %{"user_id" => blocker.id, "identifiers" => identifiers}
+    )
+  end
+
+  def follow_import(%User{} = follower, [_ | _] = identifiers) do
+    BackgroundWorker.enqueue(
+      "follow_import",
+      %{"user_id" => follower.id, "identifiers" => identifiers}
+    )
+  end
+
+  def mutes_import(%User{} = user, [_ | _] = identifiers) do
+    BackgroundWorker.enqueue(
+      "mutes_import",
+      %{"user_id" => user.id, "identifiers" => identifiers}
+    )
+  end
+end
diff --git a/lib/pleroma/web/api_spec/operations/user_import_operation.ex b/lib/pleroma/web/api_spec/operations/user_import_operation.ex
new file mode 100644 (file)
index 0000000..a50314f
--- /dev/null
@@ -0,0 +1,80 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.UserImportOperation do
+  alias OpenApiSpex.Operation
+  alias OpenApiSpex.Schema
+  alias Pleroma.Web.ApiSpec.Schemas.ApiError
+
+  import Pleroma.Web.ApiSpec.Helpers
+
+  @spec open_api_operation(atom) :: Operation.t()
+  def open_api_operation(action) do
+    operation = String.to_existing_atom("#{action}_operation")
+    apply(__MODULE__, operation, [])
+  end
+
+  def follow_operation do
+    %Operation{
+      tags: ["follow_import"],
+      summary: "Imports your follows.",
+      operationId: "UserImportController.follow",
+      requestBody: request_body("Parameters", import_request(), required: true),
+      responses: %{
+        200 => ok_response(),
+        500 => Operation.response("Error", "application/json", ApiError)
+      },
+      security: [%{"oAuth" => ["write:follow"]}]
+    }
+  end
+
+  def blocks_operation do
+    %Operation{
+      tags: ["blocks_import"],
+      summary: "Imports your blocks.",
+      operationId: "UserImportController.blocks",
+      requestBody: request_body("Parameters", import_request(), required: true),
+      responses: %{
+        200 => ok_response(),
+        500 => Operation.response("Error", "application/json", ApiError)
+      },
+      security: [%{"oAuth" => ["write:blocks"]}]
+    }
+  end
+
+  def mutes_operation do
+    %Operation{
+      tags: ["mutes_import"],
+      summary: "Imports your mutes.",
+      operationId: "UserImportController.mutes",
+      requestBody: request_body("Parameters", import_request(), required: true),
+      responses: %{
+        200 => ok_response(),
+        500 => Operation.response("Error", "application/json", ApiError)
+      },
+      security: [%{"oAuth" => ["write:mutes"]}]
+    }
+  end
+
+  defp import_request do
+    %Schema{
+      type: :object,
+      required: [:list],
+      properties: %{
+        list: %Schema{
+          description:
+            "STRING or FILE containing a whitespace-separated list of accounts to import.",
+          anyOf: [
+            %Schema{type: :string, format: :binary},
+            %Schema{type: :string}
+          ]
+        }
+      }
+    }
+  end
+
+  defp ok_response do
+    Operation.response("Ok", "application/json", %Schema{type: :string, example: "ok"})
+  end
+end
diff --git a/lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex b/lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex
new file mode 100644 (file)
index 0000000..f10c457
--- /dev/null
@@ -0,0 +1,61 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.UserImportController do
+  use Pleroma.Web, :controller
+
+  require Logger
+
+  alias Pleroma.Plugs.OAuthScopesPlug
+  alias Pleroma.User
+  alias Pleroma.Web.ApiSpec
+
+  plug(OAuthScopesPlug, %{scopes: ["follow", "write:follows"]} when action == :follow)
+  plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks)
+  plug(OAuthScopesPlug, %{scopes: ["follow", "write:mutes"]} when action == :mutes)
+
+  plug(OpenApiSpex.Plug.CastAndValidate)
+  defdelegate open_api_operation(action), to: ApiSpec.UserImportOperation
+
+  def follow(%{body_params: %{list: %Plug.Upload{path: path}}} = conn, _) do
+    follow(%Plug.Conn{conn | body_params: %{list: File.read!(path)}}, %{})
+  end
+
+  def follow(%{assigns: %{user: follower}, body_params: %{list: list}} = conn, _) do
+    identifiers =
+      list
+      |> String.split("\n")
+      |> Enum.map(&(&1 |> String.split(",") |> List.first()))
+      |> List.delete("Account address")
+      |> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@")))
+      |> Enum.reject(&(&1 == ""))
+
+    User.Import.follow_import(follower, identifiers)
+    json(conn, "job started")
+  end
+
+  def blocks(%{body_params: %{list: %Plug.Upload{path: path}}} = conn, _) do
+    blocks(%Plug.Conn{conn | body_params: %{list: File.read!(path)}}, %{})
+  end
+
+  def blocks(%{assigns: %{user: blocker}, body_params: %{list: list}} = conn, _) do
+    User.Import.blocks_import(blocker, prepare_user_identifiers(list))
+    json(conn, "job started")
+  end
+
+  def mutes(%{body_params: %{list: %Plug.Upload{path: path}}} = conn, _) do
+    mutes(%Plug.Conn{conn | body_params: %{list: File.read!(path)}}, %{})
+  end
+
+  def mutes(%{assigns: %{user: user}, body_params: %{list: list}} = conn, _) do
+    User.Import.mutes_import(user, prepare_user_identifiers(list))
+    json(conn, "job started")
+  end
+
+  defp prepare_user_identifiers(list) do
+    list
+    |> String.split()
+    |> Enum.map(&String.trim_leading(&1, "@"))
+  end
+end
index 67fbbde9223e43dbf02faad2e3d17e98310edde5..f924e1e916967e966d3bc900096f6827bbae8379 100644 (file)
@@ -269,14 +269,15 @@ defmodule Pleroma.Web.Router do
     post("/delete_account", UtilController, :delete_account)
     put("/notification_settings", UtilController, :update_notificaton_settings)
     post("/disable_account", UtilController, :disable_account)
-
-    post("/blocks_import", UtilController, :blocks_import)
-    post("/follow_import", UtilController, :follow_import)
   end
 
   scope "/api/pleroma", Pleroma.Web.PleromaAPI do
     pipe_through(:authenticated_api)
 
+    post("/mutes_import", UserImportController, :mutes)
+    post("/blocks_import", UserImportController, :blocks)
+    post("/follow_import", UserImportController, :follow)
+
     get("/accounts/mfa", TwoFactorAuthenticationController, :settings)
     get("/accounts/mfa/backup_codes", TwoFactorAuthenticationController, :backup_codes)
     get("/accounts/mfa/setup/:method", TwoFactorAuthenticationController, :setup)
index f02c4075c404b320c73ae694bc38e865f421af3a..70b0fbd546f32ddaeb62a3110b83c7d81d5dfd94 100644 (file)
@@ -18,14 +18,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
 
   plug(Pleroma.Web.FederatingPlug when action == :remote_subscribe)
 
-  plug(
-    OAuthScopesPlug,
-    %{scopes: ["follow", "write:follows"]}
-    when action == :follow_import
-  )
-
-  plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks_import)
-
   plug(
     OAuthScopesPlug,
     %{scopes: ["write:accounts"]}
@@ -104,33 +96,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     end
   end
 
-  def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
-    follow_import(conn, %{"list" => File.read!(listfile.path)})
-  end
-
-  def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
-    followed_identifiers =
-      list
-      |> String.split("\n")
-      |> Enum.map(&(&1 |> String.split(",") |> List.first()))
-      |> List.delete("Account address")
-      |> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@")))
-      |> Enum.reject(&(&1 == ""))
-
-    User.follow_import(follower, followed_identifiers)
-    json(conn, "job started")
-  end
-
-  def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
-    blocks_import(conn, %{"list" => File.read!(listfile.path)})
-  end
-
-  def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
-    blocked_identifiers = list |> String.split() |> Enum.map(&String.trim_leading(&1, "@"))
-    User.blocks_import(blocker, blocked_identifiers)
-    json(conn, "job started")
-  end
-
   def change_password(%{assigns: %{user: user}} = conn, params) do
     case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
       {:ok, user} ->
index cec5a746294499f248f51980c1f10d681e0b10bf..55b5a13d9e451950a5bbf8560a3b7e0e3371a3fd 100644 (file)
@@ -26,26 +26,10 @@ defmodule Pleroma.Workers.BackgroundWorker do
     User.perform(:force_password_reset, user)
   end
 
-  def perform(%Job{
-        args: %{
-          "op" => "blocks_import",
-          "blocker_id" => blocker_id,
-          "blocked_identifiers" => blocked_identifiers
-        }
-      }) do
-    blocker = User.get_cached_by_id(blocker_id)
-    {:ok, User.perform(:blocks_import, blocker, blocked_identifiers)}
-  end
-
-  def perform(%Job{
-        args: %{
-          "op" => "follow_import",
-          "follower_id" => follower_id,
-          "followed_identifiers" => followed_identifiers
-        }
-      }) do
-    follower = User.get_cached_by_id(follower_id)
-    {:ok, User.perform(:follow_import, follower, followed_identifiers)}
+  def perform(%Job{args: %{"op" => op, "user_id" => user_id, "identifiers" => identifiers}})
+      when op in ["blocks_import", "follow_import", "mutes_import"] do
+    user = User.get_cached_by_id(user_id)
+    {:ok, User.Import.perform(String.to_atom(op), user, identifiers)}
   end
 
   def perform(%Job{args: %{"op" => "media_proxy_preload", "message" => message}}) do
diff --git a/test/user/import_test.exs b/test/user/import_test.exs
new file mode 100644 (file)
index 0000000..e404dee
--- /dev/null
@@ -0,0 +1,76 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.ImportTest do
+  alias Pleroma.Repo
+  alias Pleroma.Tests.ObanHelpers
+  alias Pleroma.User
+
+  use Pleroma.DataCase
+  use Oban.Testing, repo: Pleroma.Repo
+
+  import Pleroma.Factory
+
+  setup_all do
+    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    :ok
+  end
+
+  describe "follow_import" do
+    test "it imports user followings from list" do
+      [user1, user2, user3] = insert_list(3, :user)
+
+      identifiers = [
+        user2.ap_id,
+        user3.nickname
+      ]
+
+      {:ok, job} = User.Import.follow_import(user1, identifiers)
+
+      assert {:ok, result} = ObanHelpers.perform(job)
+      assert is_list(result)
+      assert result == [user2, user3]
+      assert User.following?(user1, user2)
+      assert User.following?(user1, user3)
+    end
+  end
+
+  describe "blocks_import" do
+    test "it imports user blocks from list" do
+      [user1, user2, user3] = insert_list(3, :user)
+
+      identifiers = [
+        user2.ap_id,
+        user3.nickname
+      ]
+
+      {:ok, job} = User.Import.blocks_import(user1, identifiers)
+
+      assert {:ok, result} = ObanHelpers.perform(job)
+      assert is_list(result)
+      assert result == [user2, user3]
+      assert User.blocks?(user1, user2)
+      assert User.blocks?(user1, user3)
+    end
+  end
+
+  describe "mutes_import" do
+    test "it imports user mutes from list" do
+      [user1, user2, user3] = insert_list(3, :user)
+
+      identifiers = [
+        user2.ap_id,
+        user3.nickname
+      ]
+
+      {:ok, job} = User.Import.mutes_import(user1, identifiers)
+
+      assert {:ok, result} = ObanHelpers.perform(job)
+      assert is_list(result)
+      assert result == [user2, user3]
+      assert User.mutes?(user1, user2)
+      assert User.mutes?(user1, user3)
+    end
+  end
+end
index 060918d71183655677435ab25744ccdc9160575e..cceb14eb9525cf94707b2f15999a5e4a068e6695 100644 (file)
@@ -971,23 +971,6 @@ defmodule Pleroma.UserTest do
     end
   end
 
-  describe "follow_import" do
-    test "it imports user followings from list" do
-      [user1, user2, user3] = insert_list(3, :user)
-
-      identifiers = [
-        user2.ap_id,
-        user3.nickname
-      ]
-
-      {:ok, job} = User.follow_import(user1, identifiers)
-
-      assert {:ok, result} = ObanHelpers.perform(job)
-      assert is_list(result)
-      assert result == [user2, user3]
-    end
-  end
-
   describe "mutes" do
     test "it mutes people" do
       user = insert(:user)
@@ -1194,23 +1177,6 @@ defmodule Pleroma.UserTest do
     end
   end
 
-  describe "blocks_import" do
-    test "it imports user blocks from list" do
-      [user1, user2, user3] = insert_list(3, :user)
-
-      identifiers = [
-        user2.ap_id,
-        user3.nickname
-      ]
-
-      {:ok, job} = User.blocks_import(user1, identifiers)
-
-      assert {:ok, result} = ObanHelpers.perform(job)
-      assert is_list(result)
-      assert result == [user2, user3]
-    end
-  end
-
   describe "get_recipients_from_activity" do
     test "works for announces" do
       actor = insert(:user)
diff --git a/test/web/pleroma_api/controllers/user_import_controller_test.exs b/test/web/pleroma_api/controllers/user_import_controller_test.exs
new file mode 100644 (file)
index 0000000..433c97e
--- /dev/null
@@ -0,0 +1,235 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
+  use Pleroma.Web.ConnCase
+  use Oban.Testing, repo: Pleroma.Repo
+
+  alias Pleroma.Config
+  alias Pleroma.Tests.ObanHelpers
+
+  import Pleroma.Factory
+  import Mock
+
+  setup do
+    Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    :ok
+  end
+
+  describe "POST /api/pleroma/follow_import" do
+    setup do: oauth_access(["follow"])
+
+    test "it returns HTTP 200", %{conn: conn} do
+      user2 = insert(:user)
+
+      assert "job started" ==
+               conn
+               |> put_req_header("content-type", "application/json")
+               |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"})
+               |> json_response_and_validate_schema(200)
+    end
+
+    test "it imports follow lists from file", %{conn: conn} do
+      user2 = insert(:user)
+
+      with_mocks([
+        {File, [],
+         read!: fn "follow_list.txt" ->
+           "Account address,Show boosts\n#{user2.ap_id},true"
+         end}
+      ]) do
+        assert "job started" ==
+                 conn
+                 |> put_req_header("content-type", "application/json")
+                 |> post("/api/pleroma/follow_import", %{
+                   "list" => %Plug.Upload{path: "follow_list.txt"}
+                 })
+                 |> json_response_and_validate_schema(200)
+
+        assert [{:ok, job_result}] = ObanHelpers.perform_all()
+        assert job_result == [user2]
+      end
+    end
+
+    test "it imports new-style mastodon follow lists", %{conn: conn} do
+      user2 = insert(:user)
+
+      response =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> post("/api/pleroma/follow_import", %{
+          "list" => "Account address,Show boosts\n#{user2.ap_id},true"
+        })
+        |> json_response_and_validate_schema(200)
+
+      assert response == "job started"
+    end
+
+    test "requires 'follow' or 'write:follows' permissions" do
+      token1 = insert(:oauth_token, scopes: ["read", "write"])
+      token2 = insert(:oauth_token, scopes: ["follow"])
+      token3 = insert(:oauth_token, scopes: ["something"])
+      another_user = insert(:user)
+
+      for token <- [token1, token2, token3] do
+        conn =
+          build_conn()
+          |> put_req_header("authorization", "Bearer #{token.token}")
+          |> put_req_header("content-type", "application/json")
+          |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"})
+
+        if token == token3 do
+          assert %{"error" => "Insufficient permissions: follow | write:follows."} ==
+                   json_response(conn, 403)
+        else
+          assert json_response(conn, 200)
+        end
+      end
+    end
+
+    test "it imports follows with different nickname variations", %{conn: conn} do
+      users = [user2, user3, user4, user5, user6] = insert_list(5, :user)
+
+      identifiers =
+        [
+          user2.ap_id,
+          user3.nickname,
+          "  ",
+          "@" <> user4.nickname,
+          user5.nickname <> "@localhost",
+          "@" <> user6.nickname <> "@localhost"
+        ]
+        |> Enum.join("\n")
+
+      assert "job started" ==
+               conn
+               |> put_req_header("content-type", "application/json")
+               |> post("/api/pleroma/follow_import", %{"list" => identifiers})
+               |> json_response_and_validate_schema(200)
+
+      assert [{:ok, job_result}] = ObanHelpers.perform_all()
+      assert job_result == users
+    end
+  end
+
+  describe "POST /api/pleroma/blocks_import" do
+    # Note: "follow" or "write:blocks" permission is required
+    setup do: oauth_access(["write:blocks"])
+
+    test "it returns HTTP 200", %{conn: conn} do
+      user2 = insert(:user)
+
+      assert "job started" ==
+               conn
+               |> put_req_header("content-type", "application/json")
+               |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"})
+               |> json_response_and_validate_schema(200)
+    end
+
+    test "it imports blocks users from file", %{conn: conn} do
+      users = [user2, user3] = insert_list(2, :user)
+
+      with_mocks([
+        {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
+      ]) do
+        assert "job started" ==
+                 conn
+                 |> put_req_header("content-type", "application/json")
+                 |> post("/api/pleroma/blocks_import", %{
+                   "list" => %Plug.Upload{path: "blocks_list.txt"}
+                 })
+                 |> json_response_and_validate_schema(200)
+
+        assert [{:ok, job_result}] = ObanHelpers.perform_all()
+        assert job_result == users
+      end
+    end
+
+    test "it imports blocks with different nickname variations", %{conn: conn} do
+      users = [user2, user3, user4, user5, user6] = insert_list(5, :user)
+
+      identifiers =
+        [
+          user2.ap_id,
+          user3.nickname,
+          "@" <> user4.nickname,
+          user5.nickname <> "@localhost",
+          "@" <> user6.nickname <> "@localhost"
+        ]
+        |> Enum.join(" ")
+
+      assert "job started" ==
+               conn
+               |> put_req_header("content-type", "application/json")
+               |> post("/api/pleroma/blocks_import", %{"list" => identifiers})
+               |> json_response_and_validate_schema(200)
+
+      assert [{:ok, job_result}] = ObanHelpers.perform_all()
+      assert job_result == users
+    end
+  end
+
+  describe "POST /api/pleroma/mutes_import" do
+    # Note: "follow" or "write:mutes" permission is required
+    setup do: oauth_access(["write:mutes"])
+
+    test "it returns HTTP 200", %{user: user, conn: conn} do
+      user2 = insert(:user)
+
+      assert "job started" ==
+               conn
+               |> put_req_header("content-type", "application/json")
+               |> post("/api/pleroma/mutes_import", %{"list" => "#{user2.ap_id}"})
+               |> json_response_and_validate_schema(200)
+
+      assert [{:ok, job_result}] = ObanHelpers.perform_all()
+      assert job_result == [user2]
+      assert Pleroma.User.mutes?(user, user2)
+    end
+
+    test "it imports mutes users from file", %{user: user, conn: conn} do
+      users = [user2, user3] = insert_list(2, :user)
+
+      with_mocks([
+        {File, [], read!: fn "mutes_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
+      ]) do
+        assert "job started" ==
+                 conn
+                 |> put_req_header("content-type", "application/json")
+                 |> post("/api/pleroma/mutes_import", %{
+                   "list" => %Plug.Upload{path: "mutes_list.txt"}
+                 })
+                 |> json_response_and_validate_schema(200)
+
+        assert [{:ok, job_result}] = ObanHelpers.perform_all()
+        assert job_result == users
+        assert Enum.all?(users, &Pleroma.User.mutes?(user, &1))
+      end
+    end
+
+    test "it imports mutes with different nickname variations", %{user: user, conn: conn} do
+      users = [user2, user3, user4, user5, user6] = insert_list(5, :user)
+
+      identifiers =
+        [
+          user2.ap_id,
+          user3.nickname,
+          "@" <> user4.nickname,
+          user5.nickname <> "@localhost",
+          "@" <> user6.nickname <> "@localhost"
+        ]
+        |> Enum.join(" ")
+
+      assert "job started" ==
+               conn
+               |> put_req_header("content-type", "application/json")
+               |> post("/api/pleroma/mutes_import", %{"list" => identifiers})
+               |> json_response_and_validate_schema(200)
+
+      assert [{:ok, job_result}] = ObanHelpers.perform_all()
+      assert job_result == users
+      assert Enum.all?(users, &Pleroma.User.mutes?(user, &1))
+    end
+  end
+end
index d164127eec448451706e6d965c7d84e50f42731c..60f2fb052292e6f8ca9a8636e0a6aa666efa0cf4 100644 (file)
@@ -21,170 +21,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
   setup do: clear_config([:instance])
   setup do: clear_config([:frontend_configurations, :pleroma_fe])
 
-  describe "POST /api/pleroma/follow_import" do
-    setup do: oauth_access(["follow"])
-
-    test "it returns HTTP 200", %{conn: conn} do
-      user2 = insert(:user)
-
-      response =
-        conn
-        |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"})
-        |> json_response(:ok)
-
-      assert response == "job started"
-    end
-
-    test "it imports follow lists from file", %{user: user1, conn: conn} do
-      user2 = insert(:user)
-
-      with_mocks([
-        {File, [],
-         read!: fn "follow_list.txt" ->
-           "Account address,Show boosts\n#{user2.ap_id},true"
-         end}
-      ]) do
-        response =
-          conn
-          |> post("/api/pleroma/follow_import", %{"list" => %Plug.Upload{path: "follow_list.txt"}})
-          |> json_response(:ok)
-
-        assert response == "job started"
-
-        assert ObanHelpers.member?(
-                 %{
-                   "op" => "follow_import",
-                   "follower_id" => user1.id,
-                   "followed_identifiers" => [user2.ap_id]
-                 },
-                 all_enqueued(worker: Pleroma.Workers.BackgroundWorker)
-               )
-      end
-    end
-
-    test "it imports new-style mastodon follow lists", %{conn: conn} do
-      user2 = insert(:user)
-
-      response =
-        conn
-        |> post("/api/pleroma/follow_import", %{
-          "list" => "Account address,Show boosts\n#{user2.ap_id},true"
-        })
-        |> json_response(:ok)
-
-      assert response == "job started"
-    end
-
-    test "requires 'follow' or 'write:follows' permissions" do
-      token1 = insert(:oauth_token, scopes: ["read", "write"])
-      token2 = insert(:oauth_token, scopes: ["follow"])
-      token3 = insert(:oauth_token, scopes: ["something"])
-      another_user = insert(:user)
-
-      for token <- [token1, token2, token3] do
-        conn =
-          build_conn()
-          |> put_req_header("authorization", "Bearer #{token.token}")
-          |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"})
-
-        if token == token3 do
-          assert %{"error" => "Insufficient permissions: follow | write:follows."} ==
-                   json_response(conn, 403)
-        else
-          assert json_response(conn, 200)
-        end
-      end
-    end
-
-    test "it imports follows with different nickname variations", %{conn: conn} do
-      [user2, user3, user4, user5, user6] = insert_list(5, :user)
-
-      identifiers =
-        [
-          user2.ap_id,
-          user3.nickname,
-          "  ",
-          "@" <> user4.nickname,
-          user5.nickname <> "@localhost",
-          "@" <> user6.nickname <> "@localhost"
-        ]
-        |> Enum.join("\n")
-
-      response =
-        conn
-        |> post("/api/pleroma/follow_import", %{"list" => identifiers})
-        |> json_response(:ok)
-
-      assert response == "job started"
-      assert [{:ok, job_result}] = ObanHelpers.perform_all()
-      assert job_result == [user2, user3, user4, user5, user6]
-    end
-  end
-
-  describe "POST /api/pleroma/blocks_import" do
-    # Note: "follow" or "write:blocks" permission is required
-    setup do: oauth_access(["write:blocks"])
-
-    test "it returns HTTP 200", %{conn: conn} do
-      user2 = insert(:user)
-
-      response =
-        conn
-        |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"})
-        |> json_response(:ok)
-
-      assert response == "job started"
-    end
-
-    test "it imports blocks users from file", %{user: user1, conn: conn} do
-      user2 = insert(:user)
-      user3 = insert(:user)
-
-      with_mocks([
-        {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
-      ]) do
-        response =
-          conn
-          |> post("/api/pleroma/blocks_import", %{"list" => %Plug.Upload{path: "blocks_list.txt"}})
-          |> json_response(:ok)
-
-        assert response == "job started"
-
-        assert ObanHelpers.member?(
-                 %{
-                   "op" => "blocks_import",
-                   "blocker_id" => user1.id,
-                   "blocked_identifiers" => [user2.ap_id, user3.ap_id]
-                 },
-                 all_enqueued(worker: Pleroma.Workers.BackgroundWorker)
-               )
-      end
-    end
-
-    test "it imports blocks with different nickname variations", %{conn: conn} do
-      [user2, user3, user4, user5, user6] = insert_list(5, :user)
-
-      identifiers =
-        [
-          user2.ap_id,
-          user3.nickname,
-          "@" <> user4.nickname,
-          user5.nickname <> "@localhost",
-          "@" <> user6.nickname <> "@localhost"
-        ]
-        |> Enum.join(" ")
-
-      response =
-        conn
-        |> post("/api/pleroma/blocks_import", %{"list" => identifiers})
-        |> json_response(:ok)
-
-      assert response == "job started"
-      assert [{:ok, job_result}] = ObanHelpers.perform_all()
-      assert job_result == [user2, user3, user4, user5, user6]
-    end
-  end
-
   describe "PUT /api/pleroma/notification_settings" do
     setup do: oauth_access(["write:accounts"])