Merge branch 'issue/2099' into 'develop'

[#2099] Import/export mutes [BE]

See merge request pleroma/pleroma!2965
This commit is contained in:
lain 2020-09-21 16:25:17 +00:00
commit b36b6259d8
13 changed files with 563 additions and 307 deletions

View File

@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Media preview proxy (requires media proxy be enabled; see `:media_preview_proxy` config for more details). - 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 ### 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 - 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. switched to a new configuration mechanism, however it was not officially removed until now.
## [2.1.2] - 2020-09-17 ## [2.1.2] - 2020-09-17
### Security ### Security

View 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 * Response: HTTP 200 on success, 500 on error
* Note: Users that can't be followed are silently skipped. * 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` ## `/api/pleroma/captcha`
### Get a new captcha ### Get a new captcha
* Method: `GET` * Method: `GET`

View File

@ -1685,42 +1685,6 @@ def perform(:delete, %User{} = user) do
def perform(:deactivate_async, user, status), do: deactivate(user, status) 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() @spec external_users_query() :: Ecto.Query.t()
def external_users_query do def external_users_query do
User.Query.build(%{ User.Query.build(%{
@ -1749,21 +1713,6 @@ def external_users(opts \\ []) do
Repo.all(query) Repo.all(query)
end 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 def delete_notifications_from_user_activities(%User{ap_id: ap_id}) do
Notification Notification
|> join(:inner, [n], activity in assoc(n, :activity)) |> join(:inner, [n], activity in assoc(n, :activity))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -269,14 +269,15 @@ defmodule Pleroma.Web.Router do
post("/delete_account", UtilController, :delete_account) post("/delete_account", UtilController, :delete_account)
put("/notification_settings", UtilController, :update_notificaton_settings) put("/notification_settings", UtilController, :update_notificaton_settings)
post("/disable_account", UtilController, :disable_account) post("/disable_account", UtilController, :disable_account)
post("/blocks_import", UtilController, :blocks_import)
post("/follow_import", UtilController, :follow_import)
end end
scope "/api/pleroma", Pleroma.Web.PleromaAPI do scope "/api/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:authenticated_api) 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", TwoFactorAuthenticationController, :settings)
get("/accounts/mfa/backup_codes", TwoFactorAuthenticationController, :backup_codes) get("/accounts/mfa/backup_codes", TwoFactorAuthenticationController, :backup_codes)
get("/accounts/mfa/setup/:method", TwoFactorAuthenticationController, :setup) get("/accounts/mfa/setup/:method", TwoFactorAuthenticationController, :setup)

View File

@ -18,14 +18,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
plug(Pleroma.Web.FederatingPlug when action == :remote_subscribe) 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( plug(
OAuthScopesPlug, OAuthScopesPlug,
%{scopes: ["write:accounts"]} %{scopes: ["write:accounts"]}
@ -104,33 +96,6 @@ def update_notificaton_settings(%{assigns: %{user: user}} = conn, params) do
end end
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 def change_password(%{assigns: %{user: user}} = conn, params) do
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
{:ok, user} -> {:ok, user} ->

View File

@ -26,26 +26,10 @@ def perform(%Job{args: %{"op" => "force_password_reset", "user_id" => user_id}})
User.perform(:force_password_reset, user) User.perform(:force_password_reset, user)
end end
def perform(%Job{ def perform(%Job{args: %{"op" => op, "user_id" => user_id, "identifiers" => identifiers}})
args: %{ when op in ["blocks_import", "follow_import", "mutes_import"] do
"op" => "blocks_import", user = User.get_cached_by_id(user_id)
"blocker_id" => blocker_id, {:ok, User.Import.perform(String.to_atom(op), user, identifiers)}
"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)}
end end
def perform(%Job{args: %{"op" => "media_proxy_preload", "message" => message}}) do def perform(%Job{args: %{"op" => "media_proxy_preload", "message" => message}}) do

76
test/user/import_test.exs Normal file
View File

@ -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

View File

@ -971,23 +971,6 @@ test "it sets the follower_count property" do
end end
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 describe "mutes" do
test "it mutes people" do test "it mutes people" do
user = insert(:user) user = insert(:user)
@ -1194,23 +1177,6 @@ test "follows take precedence over domain blocks" do
end end
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 describe "get_recipients_from_activity" do
test "works for announces" do test "works for announces" do
actor = insert(:user) actor = insert(:user)

View File

@ -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

View File

@ -21,170 +21,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
setup do: clear_config([:instance]) setup do: clear_config([:instance])
setup do: clear_config([:frontend_configurations, :pleroma_fe]) 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 describe "PUT /api/pleroma/notification_settings" do
setup do: oauth_access(["write:accounts"]) setup do: oauth_access(["write:accounts"])