diff options
| -rw-r--r-- | config/config.exs | 4 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/user.ex | 7 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/operations/account_operation.ex | 16 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 22 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 1 | ||||
| -rw-r--r-- | mix.exs | 6 | ||||
| -rw-r--r-- | mix.lock | 4 | ||||
| -rw-r--r-- | test/pleroma/integration/mastodon_websocket_test.exs | 18 | ||||
| -rw-r--r-- | test/pleroma/user_test.exs | 6 | ||||
| -rw-r--r-- | test/pleroma/web/activity_pub/activity_pub_test.exs | 2 | ||||
| -rw-r--r-- | test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs | 2 | ||||
| -rw-r--r-- | test/pleroma/web/mastodon_api/controllers/account_controller_test.exs | 44 | ||||
| -rw-r--r-- | test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs | 2 | ||||
| -rw-r--r-- | test/pleroma/web/media_proxy/invalidation/script_test.exs | 13 | ||||
| -rw-r--r-- | test/support/websocket_client.ex | 28 | 
15 files changed, 129 insertions, 46 deletions
diff --git a/config/config.exs b/config/config.exs index e07c3c779..4e21ce457 100644 --- a/config/config.exs +++ b/config/config.exs @@ -559,8 +559,8 @@ config :pleroma, Oban,      token_expiration: 5,      filter_expiration: 1,      backup: 1, -    federator_incoming: 50, -    federator_outgoing: 50, +    federator_incoming: 5, +    federator_outgoing: 5,      ingestion_queue: 50,      web_push: 50,      mailer: 10, diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 50ffb7f27..929fa1717 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -112,9 +112,10 @@ defmodule Mix.Tasks.Pleroma.User do           {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do        shell_info("Generated password reset token for #{user.nickname}") -      IO.puts("URL: #{Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, -      :reset, -      token.token)}") +      url = +        Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, :reset, token.token) + +      IO.puts("URL: #{url}")      else        _ ->          shell_error("No local user #{nickname}") diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 97616f5e7..aed59293c 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -376,6 +376,22 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do      }    end +  def remove_from_followers_operation do +    %Operation{ +      tags: ["Account actions"], +      summary: "Remove from followers", +      operationId: "AccountController.remove_from_followers", +      security: [%{"oAuth" => ["follow", "write:follows"]}], +      description: "Remove the given account from followers", +      parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}], +      responses: %{ +        200 => Operation.response("Relationship", "application/json", AccountRelationship), +        400 => Operation.response("Error", "application/json", ApiError), +        404 => Operation.response("Error", "application/json", ApiError) +      } +    } +  end +    def note_operation do      %Operation{        tags: ["Account actions"], diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index bf931dc6b..7c24c35d2 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -76,16 +76,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do    plug(      OAuthScopesPlug, -    %{scopes: ["follow", "write:follows"]} when action in [:follow_by_uri, :follow, :unfollow] +    %{scopes: ["follow", "write:follows"]} +    when action in [:follow_by_uri, :follow, :unfollow, :remove_from_followers]    )    plug(OAuthScopesPlug, %{scopes: ["follow", "read:mutes"]} when action == :mutes)    plug(OAuthScopesPlug, %{scopes: ["follow", "write:mutes"]} when action in [:mute, :unmute]) -  @relationship_actions [:follow, :unfollow] +  @relationship_actions [:follow, :unfollow, :remove_from_followers]    @needs_account ~W( -    followers following lists follow unfollow mute unmute block unblock note endorse unendorse +    followers following lists follow unfollow mute unmute block unblock +    note endorse unendorse remove_from_followers    )a    plug( @@ -477,6 +479,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do      end    end +  @doc "POST /api/v1/accounts/:id/remove_from_followers" +  def remove_from_followers(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do +    {:error, "Can not unfollow yourself"} +  end + +  def remove_from_followers(%{assigns: %{user: followed, account: follower}} = conn, _params) do +    with {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do +      render(conn, "relationship.json", user: followed, target: follower) +    else +      nil -> +        render_error(conn, :not_found, "Record not found") +    end +  end +    @doc "POST /api/v1/follows"    def follow_by_uri(%{body_params: %{uri: uri}} = conn, _) do      case User.get_cached_by_nickname(uri) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b2c7d147c..2ea3ea7c1 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -510,6 +510,7 @@ defmodule Pleroma.Web.Router do      post("/accounts/:id/note", AccountController, :note)      post("/accounts/:id/pin", AccountController, :endorse)      post("/accounts/:id/unpin", AccountController, :unendorse) +    post("/accounts/:id/remove_from_followers", AccountController, :remove_from_followers)      get("/conversations", ConversationController, :index)      post("/conversations/:id/read", ConversationController, :mark_as_read) @@ -167,8 +167,8 @@ defmodule Pleroma.Mixfile do        {:poolboy, "~> 1.5"},        {:prometheus, "~> 4.6"},        {:prometheus_ex, -       git: "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git", -       ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5", +       git: "https://github.com/lanodan/prometheus.ex.git", +       branch: "fix/elixir-1.14",         override: true},        {:prometheus_plugs, "~> 1.1"},        {:prometheus_phoenix, "~> 1.3"}, @@ -212,7 +212,7 @@ defmodule Pleroma.Mixfile do        {:excoveralls, "0.12.3", only: :test},        {:hackney, "~> 1.18.0", override: true},        {:mox, "~> 1.0", only: :test}, -      {:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test} +      {:websockex, "~> 0.4.3", only: :test}      ] ++ oauth_deps()    end @@ -110,7 +110,7 @@    "pot": {:hex, :pot, "1.0.1", "81b511b1fa7c3123171c265cb7065a1528cebd7277b0cbc94257c50a8b2e4c17", [:rebar3], [], "hexpm", "ed87f5976531d91528452faa1138a5328db7f9f20d8feaae15f5051f79bcfb6d"},    "prometheus": {:hex, :prometheus, "4.8.0", "1ce1e1002b173c336d61f186b56263346536e76814edd9a142e12aeb2d6c1ad2", [:mix, :rebar3], [], "hexpm", "0fc2e17103073edb3758a46a5d44b006191bf25b73cbaa2b779109de396afcb5"},    "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"}, -  "prometheus_ex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git", "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5", [ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5"]}, +  "prometheus_ex": {:git, "https://github.com/lanodan/prometheus.ex.git", "31f7fbe4b71b79ba27efc2a5085746c4011ceb8f", [branch: "fix/elixir-1.14"]},    "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"},    "prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]},    "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"}, @@ -134,5 +134,5 @@    "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},    "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},    "web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"}, -  "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []}, +  "websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"},  } diff --git a/test/pleroma/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs index 2d4c7f63b..0226b2a5d 100644 --- a/test/pleroma/integration/mastodon_websocket_test.exs +++ b/test/pleroma/integration/mastodon_websocket_test.exs @@ -33,16 +33,18 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do    test "refuses invalid requests" do      capture_log(fn -> -      assert {:error, {404, _}} = start_socket() -      assert {:error, {404, _}} = start_socket("?stream=ncjdk") +      assert {:error, %WebSockex.RequestError{code: 404}} = start_socket() +      assert {:error, %WebSockex.RequestError{code: 404}} = start_socket("?stream=ncjdk")        Process.sleep(30)      end)    end    test "requires authentication and a valid token for protected streams" do      capture_log(fn -> -      assert {:error, {401, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa") -      assert {:error, {401, _}} = start_socket("?stream=user") +      assert {:error, %WebSockex.RequestError{code: 401}} = +               start_socket("?stream=user&access_token=aaaaaaaaaaaa") + +      assert {:error, %WebSockex.RequestError{code: 401}} = start_socket("?stream=user")        Process.sleep(30)      end)    end @@ -102,7 +104,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do        assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}")        capture_log(fn -> -        assert {:error, {401, _}} = start_socket("?stream=user") +        assert {:error, %WebSockex.RequestError{code: 401}} = start_socket("?stream=user")          Process.sleep(30)        end)      end @@ -111,7 +113,9 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do        assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}")        capture_log(fn -> -        assert {:error, {401, _}} = start_socket("?stream=user:notification") +        assert {:error, %WebSockex.RequestError{code: 401}} = +                 start_socket("?stream=user:notification") +          Process.sleep(30)        end)      end @@ -120,7 +124,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do        assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])        capture_log(fn -> -        assert {:error, {401, _}} = +        assert {:error, %WebSockex.RequestError{code: 401}} =                   start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])          Process.sleep(30) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 0dc45beb9..11789b64d 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -311,7 +311,7 @@ defmodule Pleroma.UserTest do    describe "unfollow/2" do      setup do: clear_config([:instance, :external_user_synchronization]) -    test "unfollow with syncronizes external user" do +    test "unfollow with synchronizes external user" do        clear_config([:instance, :external_user_synchronization], true)        followed = @@ -2265,7 +2265,7 @@ defmodule Pleroma.UserTest do        assert other_user.follower_count == 1      end -    test "syncronizes the counters with the remote instance for the followed when enabled" do +    test "synchronizes the counters with the remote instance for the followed when enabled" do        clear_config([:instance, :external_user_synchronization], false)        user = insert(:user) @@ -2287,7 +2287,7 @@ defmodule Pleroma.UserTest do        assert other_user.follower_count == 437      end -    test "syncronizes the counters with the remote instance for the follower when enabled" do +    test "synchronizes the counters with the remote instance for the follower when enabled" do        clear_config([:instance, :external_user_synchronization], false)        user = insert(:user) diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index b8d73ea10..13f3d93b8 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -1662,7 +1662,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do    end    describe "fetch_follow_information_for_user" do -    test "syncronizes following/followers counters" do +    test "synchronizes following/followers counters" do        user =          insert(:user,            local: false, diff --git a/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs index 2601a026f..9511dccea 100644 --- a/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs @@ -3,7 +3,7 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.AdminAPI.InstanceDocumentControllerTest do -  use Pleroma.Web.ConnCase, async: true +  use Pleroma.Web.ConnCase    import Pleroma.Factory    @dir "test/tmp/instance_static" diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index ba7293d36..2bf4edb70 100644 --- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -2119,4 +2119,48 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do                 |> json_response_and_validate_schema(400)      end    end + +  describe "remove from followers" do +    setup do: oauth_access(["follow"]) + +    test "removing user from followers", %{conn: conn, user: user} do +      %{id: other_user_id} = other_user = insert(:user) + +      CommonAPI.follow(other_user, user) + +      assert %{"id" => ^other_user_id, "followed_by" => false} = +               conn +               |> post("/api/v1/accounts/#{other_user_id}/remove_from_followers") +               |> json_response_and_validate_schema(200) + +      refute User.following?(other_user, user) +    end + +    test "removing remote user from followers", %{conn: conn, user: user} do +      %{id: other_user_id} = other_user = insert(:user, local: false) + +      CommonAPI.follow(other_user, user) + +      assert User.following?(other_user, user) + +      assert %{"id" => ^other_user_id, "followed_by" => false} = +               conn +               |> post("/api/v1/accounts/#{other_user_id}/remove_from_followers") +               |> json_response_and_validate_schema(200) + +      refute User.following?(other_user, user) +    end + +    test "removing user from followers errors", %{user: user, conn: conn} do +      # self remove +      conn_res = post(conn, "/api/v1/accounts/#{user.id}/remove_from_followers") + +      assert %{"error" => "Can not unfollow yourself"} = +               json_response_and_validate_schema(conn_res, 400) + +      # remove non existing user +      conn_res = post(conn, "/api/v1/accounts/doesntexist/remove_from_followers") +      assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404) +    end +  end  end diff --git a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs index 1328b42c9..b13a8033b 100644 --- a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs @@ -944,7 +944,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do      end    end -  describe "hashtag timeline handling of :restrict_unauthenticated setting" do +  describe "hashtag timeline handling of restrict_unauthenticated setting" do      setup do        user = insert(:user)        {:ok, activity1} = CommonAPI.post(user, %{status: "test #tag1"}) diff --git a/test/pleroma/web/media_proxy/invalidation/script_test.exs b/test/pleroma/web/media_proxy/invalidation/script_test.exs index 39ef365f4..3e8fd751d 100644 --- a/test/pleroma/web/media_proxy/invalidation/script_test.exs +++ b/test/pleroma/web/media_proxy/invalidation/script_test.exs @@ -10,11 +10,14 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do    test "it logs error when script is not found" do      assert capture_log(fn -> -             assert Invalidation.Script.purge( -                      ["http://example.com/media/example.jpg"], -                      script_path: "./example" -                    ) == {:error, "%ErlangError{original: :enoent}"} -           end) =~ "Error while cache purge: %ErlangError{original: :enoent}" +             assert {:error, msg} = +                      Invalidation.Script.purge( +                        ["http://example.com/media/example.jpg"], +                        script_path: "./example" +                      ) + +             assert msg =~ ~r/%ErlangError{original: :enoent(, reason: nil)?}/ +           end) =~ ~r/Error while cache purge: %ErlangError{original: :enoent(, reason: nil)?}/      capture_log(fn ->        assert Invalidation.Script.purge( diff --git a/test/support/websocket_client.ex b/test/support/websocket_client.ex index d149b324e..cf2972c38 100644 --- a/test/support/websocket_client.ex +++ b/test/support/websocket_client.ex @@ -5,18 +5,17 @@  defmodule Pleroma.Integration.WebsocketClient do    # https://github.com/phoenixframework/phoenix/blob/master/test/support/websocket_client.exs +  use WebSockex +    @doc """    Starts the WebSocket server for given ws URL. Received Socket.Message's    are forwarded to the sender pid    """    def start_link(sender, url, headers \\ []) do -    :crypto.start() -    :ssl.start() - -    :websocket_client.start_link( -      String.to_charlist(url), +    WebSockex.start_link( +      url,        __MODULE__, -      [sender], +      %{sender: sender},        extra_headers: headers      )    end @@ -36,27 +35,26 @@ defmodule Pleroma.Integration.WebsocketClient do    end    @doc false -  def init([sender], _conn_state) do -    {:ok, %{sender: sender}} -  end - -  @doc false -  def websocket_handle(frame, _conn_state, state) do +  @impl true +  def handle_frame(frame, state) do      send(state.sender, frame)      {:ok, state}    end    @doc false -  def websocket_info({:text, msg}, _conn_state, state) do +  @impl true +  def handle_info({:text, msg}, state) do      {:reply, {:text, msg}, state}    end -  def websocket_info(:close, _conn_state, _state) do +  @impl true +  def handle_info(:close, _state) do      {:close, <<>>, "done"}    end    @doc false -  def websocket_terminate(_reason, _conn_state, _state) do +  @impl true +  def terminate(_reason, _state) do      :ok    end  end  | 
