diff options
| -rw-r--r-- | lib/pleroma/notification.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 24 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 11 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 39 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 7 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/twitter_api.ex | 5 | ||||
| -rw-r--r-- | test/notification_test.exs | 11 | ||||
| -rw-r--r-- | test/user_test.exs | 36 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 29 | ||||
| -rw-r--r-- | test/web/mastodon_api/account_view_test.exs | 3 | ||||
| -rw-r--r-- | test/web/mastodon_api/mastodon_api_controller_test.exs | 36 | 
12 files changed, 190 insertions, 21 deletions
| diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 35f817d1d..00a382f31 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -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 diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 5f1750035..771c54e81 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -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 diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 71e52cb46..a62be2511 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -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 diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 19e0be3a1..b1a54a4f1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -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 diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index ff02587d6..cf97ab746 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -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 diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 1fb5eadf6..f96ec7213 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -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 diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index d5c5cf5cf..912d5e278 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -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 diff --git a/test/notification_test.exs b/test/notification_test.exs index f50b3cb24..77fdb532f 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -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 diff --git a/test/user_test.exs b/test/user_test.exs index ae9a48e74..151b9afc0 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -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 diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index a088e97be..a02740d5d 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -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        %{public: public} = ActivityBuilder.public_and_non_public diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index aa74ed966..c62cb4f36 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -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 diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index cf09bc4b8..d118026eb 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -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) | 
