User: Don't error out when following a user that's already followed.
This leads to a few situations where it is impossible to follow a user.
This commit is contained in:
		
							parent
							
								
									e4babb1c9f
								
							
						
					
					
						commit
						8b9a0dd4a7
					
				
					 4 changed files with 119 additions and 60 deletions
				
			
		| 
						 | 
				
			
			@ -370,8 +370,8 @@ def follow(%User{} = follower, %User{info: info} = followed) do
 | 
			
		|||
    ap_followers = followed.follower_address
 | 
			
		||||
 | 
			
		||||
    cond do
 | 
			
		||||
      following?(follower, followed) or info.deactivated ->
 | 
			
		||||
        {:error, "Could not follow user: #{followed.nickname} is already on your list."}
 | 
			
		||||
      info.deactivated ->
 | 
			
		||||
        {:error, "Could not follow user: You are deactivatedt."}
 | 
			
		||||
 | 
			
		||||
      deny_follow_blocked and blocks?(followed, follower) ->
 | 
			
		||||
        {:error, "Could not follow user: #{followed.nickname} blocked you."}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										115
									
								
								test/web/activity_pub/transmogrifier/follow_handling_test.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								test/web/activity_pub/transmogrifier/follow_handling_test.exs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,115 @@
 | 
			
		|||
# Pleroma: A lightweight social networking server
 | 
			
		||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
 | 
			
		||||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 | 
			
		||||
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
 | 
			
		||||
  use Pleroma.DataCase
 | 
			
		||||
  alias Pleroma.Activity
 | 
			
		||||
  alias Pleroma.Repo
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Transmogrifier
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Utils
 | 
			
		||||
 | 
			
		||||
  import Pleroma.Factory
 | 
			
		||||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  setup_all do
 | 
			
		||||
    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
 | 
			
		||||
    :ok
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "handle_incoming" do
 | 
			
		||||
    test "it works for incoming follow requests" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/mastodon-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      assert data["actor"] == "http://mastodon.example.org/users/admin"
 | 
			
		||||
      assert data["type"] == "Follow"
 | 
			
		||||
      assert data["id"] == "http://mastodon.example.org/users/admin#follows/2"
 | 
			
		||||
      assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it works for follow requests when you are already followed, creating a new accept activity" do
 | 
			
		||||
      # This is important because the remote might have the wrong idea about the current follow status.
 | 
			
		||||
      # This can lead to instance A thinking that x@A is followed by y@B, but B thinks they are not. In
 | 
			
		||||
      # this case, the follow can never go through again because it will never get an Accept.
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/mastodon-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      accepts =
 | 
			
		||||
        from(
 | 
			
		||||
          a in Activity,
 | 
			
		||||
          where: fragment("?->>'type' = ?", a.data, "Accept")
 | 
			
		||||
        )
 | 
			
		||||
        |> Repo.all()
 | 
			
		||||
 | 
			
		||||
      assert length(accepts) == 1
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/mastodon-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("id", String.replace(data["id"], "2", "3"))
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      accepts =
 | 
			
		||||
        from(
 | 
			
		||||
          a in Activity,
 | 
			
		||||
          where: fragment("?->>'type' = ?", a.data, "Accept")
 | 
			
		||||
        )
 | 
			
		||||
        |> Repo.all()
 | 
			
		||||
 | 
			
		||||
      assert length(accepts) == 2
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do
 | 
			
		||||
      Pleroma.Config.put([:user, :deny_follow_blocked], true)
 | 
			
		||||
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      {:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
 | 
			
		||||
 | 
			
		||||
      {:ok, user} = User.block(user, target)
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/mastodon-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      %Activity{} = activity = Activity.get_by_ap_id(id)
 | 
			
		||||
 | 
			
		||||
      assert activity.data["state"] == "reject"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it works for incoming follow requests from hubzilla" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/hubzilla-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
        |> Utils.normalize_params()
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"
 | 
			
		||||
      assert data["type"] == "Follow"
 | 
			
		||||
      assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
 | 
			
		||||
      assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 | 
			
		|||
  alias Pleroma.User
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.ActivityPub
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Transmogrifier
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Utils
 | 
			
		||||
  alias Pleroma.Web.OStatus
 | 
			
		||||
  alias Pleroma.Web.Websub.WebsubClientSubscription
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -248,59 +247,6 @@ test "it cleans up incoming notices which are not really DMs" do
 | 
			
		|||
      assert object_data["cc"] == to
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it works for incoming follow requests" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/mastodon-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      assert data["actor"] == "http://mastodon.example.org/users/admin"
 | 
			
		||||
      assert data["type"] == "Follow"
 | 
			
		||||
      assert data["id"] == "http://mastodon.example.org/users/admin#follows/2"
 | 
			
		||||
      assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do
 | 
			
		||||
      Pleroma.Config.put([:user, :deny_follow_blocked], true)
 | 
			
		||||
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      {:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
 | 
			
		||||
 | 
			
		||||
      {:ok, user} = User.block(user, target)
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/mastodon-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      %Activity{} = activity = Activity.get_by_ap_id(id)
 | 
			
		||||
 | 
			
		||||
      assert activity.data["state"] == "reject"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it works for incoming follow requests from hubzilla" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      data =
 | 
			
		||||
        File.read!("test/fixtures/hubzilla-follow-activity.json")
 | 
			
		||||
        |> Poison.decode!()
 | 
			
		||||
        |> Map.put("object", user.ap_id)
 | 
			
		||||
        |> Utils.normalize_params()
 | 
			
		||||
 | 
			
		||||
      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
 | 
			
		||||
 | 
			
		||||
      assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"
 | 
			
		||||
      assert data["type"] == "Follow"
 | 
			
		||||
      assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
 | 
			
		||||
      assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "it works for incoming likes" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,8 +116,7 @@ test "Follow another user using user_id" do
 | 
			
		|||
    {:ok, user, followed, _activity} = TwitterAPI.follow(user, %{"user_id" => followed.id})
 | 
			
		||||
    assert User.ap_followers(followed) in user.following
 | 
			
		||||
 | 
			
		||||
    {:error, msg} = TwitterAPI.follow(user, %{"user_id" => followed.id})
 | 
			
		||||
    assert msg == "Could not follow user: #{followed.nickname} is already on your list."
 | 
			
		||||
    {:ok, _, _, _} = TwitterAPI.follow(user, %{"user_id" => followed.id})
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "Follow another user using screen_name" do
 | 
			
		||||
| 
						 | 
				
			
			@ -132,8 +131,7 @@ test "Follow another user using screen_name" do
 | 
			
		|||
    followed = User.get_cached_by_ap_id(followed.ap_id)
 | 
			
		||||
    assert followed.info.follower_count == 1
 | 
			
		||||
 | 
			
		||||
    {:error, msg} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
 | 
			
		||||
    assert msg == "Could not follow user: #{followed.nickname} is already on your list."
 | 
			
		||||
    {:ok, _, _, _} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "Unfollow another user using user_id" do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue