diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3010fe87f..6a34a39d8 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -79,6 +79,7 @@ defmodule Pleroma.User do field(:muted_reblogs, {:array, :string}, default: []) field(:muted_notifications, {:array, :string}, default: []) field(:subscribers, {:array, :string}, default: []) + field(:whitelist, {:array, :string}, default: []) field(:deactivated, :boolean, default: false) field(:no_rich_text, :boolean, default: false) field(:ap_enabled, :boolean, default: false) @@ -1019,6 +1020,14 @@ defmodule Pleroma.User do blocker end + blocker = + if whitelists?(blocker, blocked) do + {:ok, blocker} = unwhitelist(blocker, blocked) + blocker + else + blocker + end + if following?(blocked, blocker), do: unfollow(blocked, blocker) {:ok, blocker} = update_follower_count(blocker) @@ -1035,6 +1044,22 @@ defmodule Pleroma.User do remove_from_block(blocker, ap_id) end + def whitelist(whitelister, %User{ap_id: ap_id} = whitelisted) do + whitelister = + if blocks?(whitelister, whitelisted) do + {:ok, whitelister} = unblock(whitelister, whitelisted) + whitelister + else + whitelister + end + + add_to_whitelist(whitelister, ap_id) + end + + def unwhitelist(whitelister, %{ap_id: ap_id}) do + remove_from_whitelist(whitelister, ap_id) + end + def mutes?(nil, _), do: false def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.mutes, ap_id) @@ -1045,7 +1070,8 @@ defmodule Pleroma.User do do: Enum.member?(user.muted_notifications, ap_id) def blocks?(%User{} = user, %User{} = target) do - blocks_ap_id?(user, target) || blocks_domain?(user, target) + blocks_ap_id?(user, target) || + (blocks_domain?(user, target) && !whitelists?(user, target)) end def blocks?(nil, _), do: false @@ -1064,6 +1090,12 @@ defmodule Pleroma.User do def blocks_domain?(_, _), do: false + def whitelists?(%User{} = user, %User{} = target) do + Enum.member?(user.whitelist, target.ap_id) + end + + def whitelists?(_, _), do: false + def subscribed_to?(user, %{ap_id: ap_id}) do with %User{} = target <- get_cached_by_ap_id(ap_id) do Enum.member?(target.subscribers, user.ap_id) @@ -1846,6 +1878,14 @@ defmodule Pleroma.User do set_subscribers(user, List.delete(user.subscribers, subscribed)) end + def add_to_whitelist(user, whitelisted) do + set_whitelist(user, Enum.uniq([whitelisted | user.whitelist])) + end + + def remove_from_whitelist(user, whitelisted) do + set_whitelist(user, List.delete(user.whitelist, whitelisted)) + end + defp set_domain_blocks(user, domain_blocks) do params = %{domain_blocks: domain_blocks} @@ -1872,6 +1912,15 @@ defmodule Pleroma.User do |> update_and_set_cache() end + defp set_whitelist(user, whitelist) do + params = %{whitelist: whitelist} + + user + |> cast(params, [:whitelist]) + |> validate_required([:whitelist]) + |> update_and_set_cache() + end + def add_to_block(user, blocked) do set_blocks(user, Enum.uniq([blocked | user.blocks])) end diff --git a/priv/repo/migrations/20191126174757_add_user_whitelisted_column.exs b/priv/repo/migrations/20191126174757_add_user_whitelisted_column.exs new file mode 100644 index 000000000..d07f874eb --- /dev/null +++ b/priv/repo/migrations/20191126174757_add_user_whitelisted_column.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddUserWhitelistedColumn do + use Ecto.Migration + + def change do + alter table(:users) do + add_if_not_exists(:whitelist, {:array, :text}, default: []) + end + end +end diff --git a/test/user_test.exs b/test/user_test.exs index e6302b525..57e4e35da 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -816,6 +816,19 @@ defmodule Pleroma.UserTest do refute User.subscribed_to?(blocker, blocked) refute User.subscribed_to?(blocked, blocker) end + + test "blocks tear down whitelister->whitelisted relationship" do + blocker = insert(:user) + blocked = insert(:user) + + {:ok, blocker} = User.whitelist(blocker, blocked) + assert User.whitelists?(blocker, blocked) + refute User.whitelists?(blocked, blocker) + + {:ok, blocker} = User.block(blocker, blocked) + assert User.blocks?(blocker, blocked) + refute User.whitelists?(blocker, blocked) + end end describe "domain blocking" do @@ -881,6 +894,49 @@ defmodule Pleroma.UserTest do end end + describe "whitelists" do + test "whitelists user" do + user = insert(:user) + good_eggo = insert(:user) + + {:ok, user} = User.whitelist(user, good_eggo) + + assert User.whitelists?(user, good_eggo) + end + + test "unwhitelists user" do + user = insert(:user) + good_eggo = insert(:user) + + {:ok, user} = User.whitelist(user, good_eggo) + {:ok, user} = User.unwhitelist(user, good_eggo) + + refute User.whitelists?(user, good_eggo) + end + + test "undoes any block" do + user = insert(:user) + good_eggo = insert(:user) + + {:ok, user} = User.block(user, good_eggo) + {:ok, user} = User.whitelist(user, good_eggo) + + assert User.whitelists?(user, good_eggo) + refute User.blocks?(user, good_eggo) + end + + test "takes precidence over domain blocks" do + user = insert(:user) + good_eggo = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/cuteposter"}) + + {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com") + {:ok, user} = User.whitelist(user, good_eggo) + + assert User.whitelists?(user, good_eggo) + refute User.blocks?(user, good_eggo) + end + end + describe "blocks_import" do test "it imports user blocks from list" do [user1, user2, user3] = insert_list(3, :user)