[#483] Blocked users list import & export Closes #483 See merge request pleroma/pleroma!603tags/v0.9.9
@@ -13,6 +13,8 @@ defmodule Pleroma.User do | |||
alias Pleroma.Web.{OStatus, Websub, OAuth} | |||
alias Pleroma.Web.ActivityPub.{Utils, ActivityPub} | |||
require Logger | |||
@type t :: %__MODULE__{} | |||
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ | |||
@@ -339,6 +341,24 @@ defmodule Pleroma.User do | |||
Enum.member?(follower.following, followed.follower_address) | |||
end | |||
def follow_import(%User{} = follower, followed_identifiers) | |||
when is_list(followed_identifiers) do | |||
Enum.map( | |||
followed_identifiers, | |||
fn followed_identifier -> | |||
with %User{} = followed <- get_or_fetch(followed_identifier), | |||
{:ok, follower} <- maybe_direct_follow(follower, followed), | |||
{:ok, _} <- ActivityPub.follow(follower, followed) do | |||
followed | |||
else | |||
err -> | |||
Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}") | |||
err | |||
end | |||
end | |||
) | |||
end | |||
def locked?(%User{} = user) do | |||
user.info.locked || false | |||
end | |||
@@ -375,7 +395,11 @@ defmodule Pleroma.User do | |||
end | |||
def get_by_nickname(nickname) do | |||
Repo.get_by(User, nickname: nickname) | |||
Repo.get_by(User, nickname: nickname) || | |||
if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do | |||
[local_nickname, _] = String.split(nickname, "@") | |||
Repo.get_by(User, nickname: local_nickname) | |||
end | |||
end | |||
def get_by_nickname_or_email(nickname_or_email) do | |||
@@ -604,6 +628,23 @@ defmodule Pleroma.User do | |||
Repo.all(q) | |||
end | |||
def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do | |||
Enum.map( | |||
blocked_identifiers, | |||
fn blocked_identifier -> | |||
with %User{} = blocked <- get_or_fetch(blocked_identifier), | |||
{:ok, blocker} <- block(blocker, blocked), | |||
{:ok, _} <- ActivityPub.block(blocker, blocked) do | |||
blocked | |||
else | |||
err -> | |||
Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}") | |||
err | |||
end | |||
end | |||
) | |||
end | |||
def block(blocker, %User{ap_id: ap_id} = blocked) do | |||
# sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213) | |||
blocker = | |||
@@ -657,6 +698,9 @@ defmodule Pleroma.User do | |||
end) | |||
end | |||
def blocked_users(user), | |||
do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) | |||
def block_domain(user, domain) do | |||
info_cng = | |||
user.info | |||
@@ -704,11 +704,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do | |||
end | |||
end | |||
# TODO: Use proper query | |||
def blocks(%{assigns: %{user: user}} = conn, _) do | |||
with blocked_users <- user.info.blocks || [], | |||
accounts <- Enum.map(blocked_users, fn ap_id -> User.get_cached_by_ap_id(ap_id) end) do | |||
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user) | |||
with blocked_accounts <- User.blocked_users(user) do | |||
res = AccountView.render("accounts.json", users: blocked_accounts, for: user, as: :user) | |||
json(conn, res) | |||
end | |||
end | |||
@@ -137,6 +137,7 @@ defmodule Pleroma.Web.Router do | |||
scope "/api/pleroma", Pleroma.Web.TwitterAPI do | |||
pipe_through(:authenticated_api) | |||
post("/blocks_import", UtilController, :blocks_import) | |||
post("/follow_import", UtilController, :follow_import) | |||
post("/change_password", UtilController, :change_password) | |||
post("/delete_account", UtilController, :delete_account) | |||
@@ -281,6 +282,7 @@ defmodule Pleroma.Web.Router do | |||
get("/statuses/followers", TwitterAPI.Controller, :followers) | |||
get("/statuses/friends", TwitterAPI.Controller, :friends) | |||
get("/statuses/blocks", TwitterAPI.Controller, :blocks) | |||
get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status) | |||
get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation) | |||
@@ -240,21 +240,22 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do | |||
follow_import(conn, %{"list" => File.read!(listfile.path)}) | |||
end | |||
def follow_import(%{assigns: %{user: user}} = conn, %{"list" => list}) do | |||
Task.start(fn -> | |||
String.split(list) | |||
|> Enum.map(fn account -> | |||
with %User{} = follower <- User.get_cached_by_ap_id(user.ap_id), | |||
%User{} = followed <- User.get_or_fetch(account), | |||
{:ok, follower} <- User.maybe_direct_follow(follower, followed) do | |||
ActivityPub.follow(follower, followed) | |||
else | |||
err -> Logger.debug("follow_import: following #{account} failed with #{inspect(err)}") | |||
end | |||
end) | |||
end) | |||
def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do | |||
with followed_identifiers <- String.split(list), | |||
{:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do | |||
json(conn, "job started") | |||
end | |||
end | |||
json(conn, "job started") | |||
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 | |||
with blocked_identifiers <- String.split(list), | |||
{:ok, _} = Task.start(fn -> User.blocks_import(blocker, blocked_identifiers) end) do | |||
json(conn, "job started") | |||
end | |||
end | |||
def change_password(%{assigns: %{user: user}} = conn, params) do | |||
@@ -507,6 +507,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do | |||
end | |||
end | |||
def blocks(%{assigns: %{user: user}} = conn, _params) do | |||
with blocked_users <- User.blocked_users(user) do | |||
conn | |||
|> put_view(UserView) | |||
|> render("index.json", %{users: blocked_users, for: user}) | |||
end | |||
end | |||
def friend_requests(conn, params) do | |||
with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params), | |||
{:ok, friend_requests} <- User.get_follow_requests(user) do | |||
@@ -278,6 +278,24 @@ defmodule Pleroma.UserTest do | |||
assert user == fetched_user | |||
end | |||
test "gets an existing user by fully qualified nickname" do | |||
user = insert(:user) | |||
fetched_user = | |||
User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host()) | |||
assert user == fetched_user | |||
end | |||
test "gets an existing user by fully qualified nickname, case insensitive" do | |||
user = insert(:user, nickname: "nick") | |||
casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host()) | |||
fetched_user = User.get_or_fetch_by_nickname(casing_altered_fqn) | |||
assert user == fetched_user | |||
end | |||
test "fetches an external user via ostatus if no user exists" do | |||
fetched_user = User.get_or_fetch_by_nickname("shp@social.heldscal.la") | |||
assert fetched_user.nickname == "shp@social.heldscal.la" | |||
@@ -485,6 +503,21 @@ 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 | |||
] | |||
result = User.follow_import(user1, identifiers) | |||
assert is_list(result) | |||
assert result == [user2, user3] | |||
end | |||
end | |||
describe "blocks" do | |||
test "it blocks people" do | |||
user = insert(:user) | |||
@@ -584,6 +617,21 @@ 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 | |||
] | |||
result = User.blocks_import(user1, identifiers) | |||
assert is_list(result) | |||
assert result == [user2, user3] | |||
end | |||
end | |||
test "get recipients from activity" do | |||
actor = insert(:user) | |||
user = insert(:user, local: true) | |||
@@ -1145,6 +1145,24 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do | |||
end | |||
end | |||
describe "GET /api/statuses/blocks" do | |||
test "it returns the list of users blocked by requester", %{conn: conn} do | |||
user = insert(:user) | |||
other_user = insert(:user) | |||
{:ok, user} = User.block(user, other_user) | |||
conn = | |||
conn | |||
|> assign(:user, user) | |||
|> get("/api/statuses/blocks") | |||
expected = UserView.render("index.json", %{users: [other_user], for: user}) | |||
result = json_response(conn, 200) | |||
assert Enum.sort(expected) == Enum.sort(result) | |||
end | |||
end | |||
describe "GET /api/statuses/friends" do | |||
test "it returns the logged in user's friends", %{conn: conn} do | |||
user = insert(:user) | |||
@@ -0,0 +1,35 @@ | |||
defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do | |||
use Pleroma.Web.ConnCase | |||
import Pleroma.Factory | |||
describe "POST /api/pleroma/follow_import" do | |||
test "it returns HTTP 200", %{conn: conn} do | |||
user1 = insert(:user) | |||
user2 = insert(:user) | |||
response = | |||
conn | |||
|> assign(:user, user1) | |||
|> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"}) | |||
|> json_response(:ok) | |||
assert response == "job started" | |||
end | |||
end | |||
describe "POST /api/pleroma/blocks_import" do | |||
test "it returns HTTP 200", %{conn: conn} do | |||
user1 = insert(:user) | |||
user2 = insert(:user) | |||
response = | |||
conn | |||
|> assign(:user, user1) | |||
|> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"}) | |||
|> json_response(:ok) | |||
assert response == "job started" | |||
end | |||
end | |||
end |