Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into develop
authorRoger Braun <roger@rogerbraun.net>
Sun, 5 Nov 2017 11:12:19 +0000 (12:12 +0100)
committerRoger Braun <roger@rogerbraun.net>
Sun, 5 Nov 2017 11:12:19 +0000 (12:12 +0100)
12 files changed:
lib/pleroma/notification.ex
lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
lib/pleroma/web/mastodon_api/views/account_view.ex
lib/pleroma/web/router.ex
lib/pleroma/web/twitter_api/twitter_api.ex
test/notification_test.exs
test/user_test.exs
test/web/activity_pub/activity_pub_test.exs
test/web/mastodon_api/account_view_test.exs
test/web/mastodon_api/mastodon_api_controller_test.exs

index 35f817d1d48ade6734a52f4546942ca04fe39e8c..00a382f3184fe65e9106659cfe5a6e9f17970bb5 100644 (file)
@@ -46,9 +46,11 @@ defmodule Pleroma.Notification do
 
   # TODO move to sql, too.
   def create_notification(%Activity{} = activity, %User{} = user) do
-    notification = %Notification{user_id: user.id, activity_id: activity.id}
-    {:ok, notification} = Repo.insert(notification)
-    notification
+    unless User.blocks?(user, %{ap_id: activity.data["actor"]}) do
+      notification = %Notification{user_id: user.id, activity_id: activity.id}
+      {:ok, notification} = Repo.insert(notification)
+      notification
+    end
   end
 end
 
index 5f1750035127b77ff9867af0bd145bf2a6a07daf..771c54e813e51f73bce54d0acde84d379698393a 100644 (file)
@@ -293,4 +293,28 @@ defmodule Pleroma.User do
       limit: 20
     Repo.all(q)
   end
+
+  def block(user, %{ap_id: ap_id}) do
+    blocks = user.info["blocks"] || []
+    new_blocks = Enum.uniq([ap_id | blocks])
+    new_info = Map.put(user.info, "blocks", new_blocks)
+
+    cs = User.info_changeset(user, %{info: new_info})
+    Repo.update(cs)
+  end
+
+  def unblock(user, %{ap_id: ap_id}) do
+    blocks = user.info["blocks"] || []
+    new_blocks = List.delete(blocks, ap_id)
+    new_info = Map.put(user.info, "blocks", new_blocks)
+
+    cs = User.info_changeset(user, %{info: new_info})
+    Repo.update(cs)
+  end
+
+  def blocks?(user, %{ap_id: ap_id}) do
+    blocks = user.info["blocks"] || []
+    Enum.member?(blocks, ap_id)
+  end
+
 end
index d4eb503234cf86105e34e25f517bb5db1db21610..4f7be4293332cb09bc75e86e337fe8a1589e7d62 100644 (file)
@@ -93,10 +93,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
-  def fetch_activities_for_context(context) do
+  def fetch_activities_for_context(context, opts \\ %{}) do
     query = from activity in Activity,
       where: fragment("?->>'type' = ? and ?->>'context' = ?", activity.data, "Create", activity.data, ^context),
       order_by: [desc: :id]
+    query = restrict_blocked(query, opts)
     Repo.all(query)
   end
 
@@ -163,6 +164,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       where: activity.id > ^since
   end
 
+  defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
+    blocks = info["blocks"] || []
+    from activity in query,
+      where: fragment("not (?->>'actor' = ANY(?))", activity.data, ^blocks)
+  end
+  defp restrict_blocked(query, _), do: query
+
   def fetch_activities(recipients, opts \\ %{}) do
     base_query = from activity in Activity,
       limit: 20,
@@ -178,6 +186,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> restrict_type(opts)
     |> restrict_favorited_by(opts)
     |> restrict_recent(opts)
+    |> restrict_blocked(opts)
     |> Repo.all
     |> Enum.reverse
   end
index 19e0be3a154240d8aa95c9b1752659394dc77c08..b1a54a4f1ef89ee55ccec6a9560aba4b7a87ee36 100644 (file)
@@ -79,6 +79,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   def home_timeline(%{assigns: %{user: user}} = conn, params) do
     params = params
     |> Map.put("type", ["Create", "Announce"])
+    |> Map.put("blocking_user", user)
 
     activities = ActivityPub.fetch_activities([user.ap_id | user.following], params)
     |> Enum.reverse
@@ -92,6 +93,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     params = params
     |> Map.put("type", ["Create", "Announce"])
     |> Map.put("local_only", !!params["local"])
+    |> Map.put("blocking_user", user)
 
     activities = ActivityPub.fetch_public_activities(params)
     |> Enum.reverse
@@ -123,7 +125,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 
   def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
     with %Activity{} = activity <- Repo.get(Activity, id),
-         activities <- ActivityPub.fetch_activities_for_context(activity.data["object"]["context"]),
+         activities <- ActivityPub.fetch_activities_for_context(activity.data["object"]["context"], %{"blocking_user" => user}),
          activities <- activities |> Enum.filter(fn (%{id: aid}) -> to_string(aid) != to_string(id) end),
          grouped_activities <- Enum.group_by(activities, fn (%{id: id}) -> id < activity.id end) do
       result = %{
@@ -246,6 +248,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     params = params
     |> Map.put("type", "Create")
     |> Map.put("local_only", !!params["local"])
+    |> Map.put("blocking_user", user)
 
     activities = ActivityPub.fetch_public_activities(params)
     |> Enum.reverse
@@ -308,6 +311,39 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
+  def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
+    with %User{} = blocked <- Repo.get(User, id),
+         {:ok, blocker} <- User.block(blocker, blocked) do
+      render conn, AccountView, "relationship.json", %{user: blocker, target: blocked}
+    else
+      {:error, message} = err ->
+        conn
+        |> put_resp_content_type("application/json")
+        |> send_resp(403, Poison.encode!(%{"error" => message}))
+    end
+  end
+
+  def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
+    with %User{} = blocked <- Repo.get(User, id),
+         {:ok, blocker} <- User.unblock(blocker, blocked) do
+      render conn, AccountView, "relationship.json", %{user: blocker, target: blocked}
+    else
+      {:error, message} = err ->
+        conn
+        |> put_resp_content_type("application/json")
+        |> send_resp(403, Poison.encode!(%{"error" => message}))
+    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)
+      json(conn, res)
+    end
+  end
+
   def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
     accounts = User.search(query, params["resolve"] == "true")
 
@@ -338,6 +374,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     params = conn
     |> Map.put("type", "Create")
     |> Map.put("favorited_by", user.ap_id)
+    |> Map.put("blocking_user", user)
 
     activities = ActivityPub.fetch_activities([], params)
     |> Enum.reverse
index ff02587d66d6fbe9428d5444c33c0e4166db6e5b..cf97ab746858900880060f6fd2f6b197fbdcd004 100644 (file)
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       id: target.id,
       following: User.following?(user, target),
       followed_by: User.following?(target, user),
-      blocking: false,
+      blocking: User.blocks?(user, target),
       muting: false,
       requested: false,
       domain_blocking: false
index 1fb5eadf68eb1fcbd4acd8a6468c21344be892f7..f96ec72138de2ef7effbd8354bc4b3d5eba3a679 100644 (file)
@@ -58,14 +58,15 @@ defmodule Pleroma.Web.Router do
     get "/accounts/search", MastodonAPIController, :account_search
     post "/accounts/:id/follow", MastodonAPIController, :follow
     post "/accounts/:id/unfollow", MastodonAPIController, :unfollow
-    post "/accounts/:id/block", MastodonAPIController, :relationship_noop
-    post "/accounts/:id/unblock", MastodonAPIController, :relationship_noop
+    post "/accounts/:id/block", MastodonAPIController, :block
+    post "/accounts/:id/unblock", MastodonAPIController, :unblock
     post "/accounts/:id/mute", MastodonAPIController, :relationship_noop
     post "/accounts/:id/unmute", MastodonAPIController, :relationship_noop
 
     post "/follows", MastodonAPIController, :follow
 
-    get "/blocks", MastodonAPIController, :empty_array
+    get "/blocks", MastodonAPIController, :blocks
+
     get "/domain_blocks", MastodonAPIController, :empty_array
     get "/follow_requests", MastodonAPIController, :empty_array
     get "/mutes", MastodonAPIController, :empty_array
index d5c5cf5cfd31b4f986433ec2ba2e9b9b050dd318..912d5e278b01676eef4e97e3d979b79505c929cf 100644 (file)
@@ -14,17 +14,20 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
   end
 
   def fetch_friend_statuses(user, opts \\ %{}) do
+    opts = Map.put(opts, "blocking_user", user)
     ActivityPub.fetch_activities([user.ap_id | user.following], opts)
     |> activities_to_statuses(%{for: user})
   end
 
   def fetch_public_statuses(user, opts \\ %{}) do
     opts = Map.put(opts, "local_only", true)
+    opts = Map.put(opts, "blocking_user", user)
     ActivityPub.fetch_public_activities(opts)
     |> activities_to_statuses(%{for: user})
   end
 
   def fetch_public_and_external_statuses(user, opts \\ %{}) do
+    opts = Map.put(opts, "blocking_user", user)
     ActivityPub.fetch_public_activities(opts)
     |> activities_to_statuses(%{for: user})
   end
@@ -41,7 +44,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
 
   def fetch_conversation(user, id) do
     with context when is_binary(context) <- conversation_id_to_context(id),
-         activities <- ActivityPub.fetch_activities_for_context(context),
+         activities <- ActivityPub.fetch_activities_for_context(context, %{"blocking_user" => user}),
          statuses <- activities |> activities_to_statuses(%{for: user})
     do
       statuses
index f50b3cb24d299880cf968334553e0c659b346102..77fdb532fe9e854f74799ecf33d8994e5cda09cf 100644 (file)
@@ -20,4 +20,15 @@ defmodule Pleroma.NotificationTest do
       assert other_notification.activity_id == activity.id
     end
   end
+
+  describe "create_notification" do
+    test "it doesn't create a notification for user if the user blocks the activity author" do
+      activity = insert(:note_activity)
+      author = User.get_by_ap_id(activity.data["actor"])
+      user = insert(:user)
+      {:ok, user} = User.block(user, author)
+
+      assert nil == Notification.create_notification(activity, user)
+    end
+  end
 end
index ae9a48e743cc8ddc36a82ffbb0b9c3e96f25f06b..151b9afc04d482c732ef208b7be37e49db5e8e8c 100644 (file)
@@ -9,11 +9,6 @@ defmodule Pleroma.UserTest do
   import Ecto.Query
 
   test "ap_id returns the activity pub id for the user" do
-    host =
-      Application.get_env(:pleroma, Pleroma.Web.Endpoint)
-      |> Keyword.fetch!(:url)
-      |> Keyword.fetch!(:host)
-
     user = UserBuilder.build
 
     expected_ap_id = "#{Pleroma.Web.base_url}/users/#{user.nickname}"
@@ -213,7 +208,9 @@ defmodule Pleroma.UserTest do
 
       {:ok, res} = User.get_followers(user)
 
-      assert res == [follower_one, follower_two]
+      assert Enum.member?(res, follower_one)
+      assert Enum.member?(res, follower_two)
+      refute Enum.member?(res, not_follower)
     end
 
     test "gets all friends (followed users) for a given user" do
@@ -229,7 +226,9 @@ defmodule Pleroma.UserTest do
 
       followed_one = User.get_by_ap_id(followed_one.ap_id)
       followed_two = User.get_by_ap_id(followed_two.ap_id)
-      assert res == [followed_one, followed_two]
+      assert Enum.member?(res, followed_one)
+      assert Enum.member?(res, followed_two)
+      refute Enum.member?(res, not_followed)
     end
   end
 
@@ -274,5 +273,28 @@ defmodule Pleroma.UserTest do
       assert user.info["follower_count"] == 1
     end
   end
+
+  describe "blocks" do
+    test "it blocks people" do
+      user = insert(:user)
+      blocked_user = insert(:user)
+
+      refute User.blocks?(user, blocked_user)
+
+      {:ok, user} = User.block(user, blocked_user)
+
+      assert User.blocks?(user, blocked_user)
+    end
+
+    test "it unblocks users" do
+      user = insert(:user)
+      blocked_user = insert(:user)
+
+      {:ok, user} = User.block(user, blocked_user)
+      {:ok, user} = User.unblock(user, blocked_user)
+
+      refute User.blocks?(user, blocked_user)
+    end
+  end
 end
 
index 48597f5fbcd55e834beb45916f1e0fb153c0f410..2cd33d623ee42a7c29b2df54494ce7e91ea91900 100644 (file)
@@ -73,13 +73,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
       {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
       {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"})
+      activity_five = insert(:note_activity)
+      user = insert(:user)
 
-      activities = ActivityPub.fetch_activities_for_context("2hu")
+      {:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]})
 
+      activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
       assert activities == [activity_two, activity]
     end
   end
 
+  test "doesn't return blocked activities" do
+    activity_one = insert(:note_activity)
+    activity_two = insert(:note_activity)
+    user = insert(:user)
+    {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]})
+
+    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
+
+    assert Enum.member?(activities, activity_two)
+    refute Enum.member?(activities, activity_one)
+
+    {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
+
+    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
+
+    assert Enum.member?(activities, activity_two)
+    assert Enum.member?(activities, activity_one)
+
+    activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil})
+
+    assert Enum.member?(activities, activity_two)
+    assert Enum.member?(activities, activity_one)
+  end
+
   describe "public fetch activities" do
     test "retrieves public activities" do
       activities = ActivityPub.fetch_public_activities
index aa74ed9668a8d940ed794c904c8139715b0c0af5..c62cb4f36265c9f47e172d28f09d65bc31149f3d 100644 (file)
@@ -51,12 +51,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
     other_user = insert(:user)
 
     {:ok, user} = User.follow(user, other_user)
+    {:ok, user} = User.block(user, other_user)
 
     expected = %{
       id: other_user.id,
       following: true,
       followed_by: false,
-      blocking: false,
+      blocking: true,
       muting: false,
       requested: false,
       domain_blocking: false
index cf09bc4b8d94a11f938c2e77d851f51955405ebf..d118026eb3b4d521c1d8bf59fd98e13912d1c6fc 100644 (file)
@@ -291,11 +291,43 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     assert id == other_user.id
   end
 
-  test "unimplemented block/mute endpoints" do
+  test "blocking / unblocking a user", %{conn: conn} do
     user = insert(:user)
     other_user = insert(:user)
 
-    ["block", "unblock", "mute", "unmute"]
+    conn = conn
+    |> assign(:user, user)
+    |> post("/api/v1/accounts/#{other_user.id}/block")
+
+    assert %{"id" => id, "blocking" => true} = json_response(conn, 200)
+
+    user = Repo.get(User, user.id)
+    conn = build_conn()
+    |> assign(:user, user)
+    |> post("/api/v1/accounts/#{other_user.id}/unblock")
+
+    assert %{"id" => id, "blocking" => false} = json_response(conn, 200)
+  end
+
+  test "getting a list of blocks", %{conn: conn} do
+    user = insert(:user)
+    other_user = insert(:user)
+
+    {:ok, user} = User.block(user, other_user)
+
+    conn = conn
+    |> assign(:user, user)
+    |> get("/api/v1/blocks")
+
+    other_user_id = other_user.id
+    assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
+  end
+
+  test "unimplemented mute endpoints" do
+    user = insert(:user)
+    other_user = insert(:user)
+
+    ["mute", "unmute"]
     |> Enum.each(fn(endpoint) ->
       conn = build_conn()
       |> assign(:user, user)